14bff34e3Sthurlow /*
24bff34e3Sthurlow  * Copyright (c) 2000-2001 Boris Popov
34bff34e3Sthurlow  * All rights reserved.
44bff34e3Sthurlow  *
54bff34e3Sthurlow  * Redistribution and use in source and binary forms, with or without
64bff34e3Sthurlow  * modification, are permitted provided that the following conditions
74bff34e3Sthurlow  * are met:
84bff34e3Sthurlow  * 1. Redistributions of source code must retain the above copyright
94bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer.
104bff34e3Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
114bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer in the
124bff34e3Sthurlow  *    documentation and/or other materials provided with the distribution.
134bff34e3Sthurlow  * 3. All advertising materials mentioning features or use of this software
144bff34e3Sthurlow  *    must display the following acknowledgement:
154bff34e3Sthurlow  *    This product includes software developed by Boris Popov.
164bff34e3Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
174bff34e3Sthurlow  *    may be used to endorse or promote products derived from this software
184bff34e3Sthurlow  *    without specific prior written permission.
194bff34e3Sthurlow  *
204bff34e3Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
214bff34e3Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
224bff34e3Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234bff34e3Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
244bff34e3Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
254bff34e3Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
264bff34e3Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
274bff34e3Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
284bff34e3Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
294bff34e3Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
304bff34e3Sthurlow  * SUCH DAMAGE.
314bff34e3Sthurlow  *
324bff34e3Sthurlow  * $Id: smb_usr.c,v 1.15 2004/12/13 00:25:18 lindak Exp $
334bff34e3Sthurlow  */
344bff34e3Sthurlow 
35*9c9af259SGordon Ross /*
36*9c9af259SGordon Ross  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
37*9c9af259SGordon Ross  * Use is subject to license terms.
38*9c9af259SGordon Ross  */
394bff34e3Sthurlow 
404bff34e3Sthurlow #include <sys/param.h>
414bff34e3Sthurlow #include <sys/kmem.h>
424bff34e3Sthurlow #include <sys/systm.h>
434bff34e3Sthurlow #include <sys/policy.h>
444bff34e3Sthurlow #include <sys/conf.h>
454bff34e3Sthurlow #include <sys/proc.h>
464bff34e3Sthurlow #include <sys/fcntl.h>
474bff34e3Sthurlow #include <sys/socket.h>
484bff34e3Sthurlow #include <sys/cmn_err.h>
494bff34e3Sthurlow 
504bff34e3Sthurlow #include <netsmb/smb_osdep.h>
514bff34e3Sthurlow 
524bff34e3Sthurlow #include <netsmb/smb.h>
534bff34e3Sthurlow #include <netsmb/smb_conn.h>
544bff34e3Sthurlow #include <netsmb/smb_rq.h>
554bff34e3Sthurlow #include <netsmb/smb_subr.h>
564bff34e3Sthurlow #include <netsmb/smb_dev.h>
574bff34e3Sthurlow 
584bff34e3Sthurlow /*
594bff34e3Sthurlow  * helpers for nsmb device. Can be moved to the smb_dev.c file.
604bff34e3Sthurlow  */
614bff34e3Sthurlow static void smb_usr_vcspec_free(struct smb_vcspec *spec);
624bff34e3Sthurlow 
634bff34e3Sthurlow /*
644bff34e3Sthurlow  * Moved the access checks here, just becuase
654bff34e3Sthurlow  * this was a more convenient place to do it
664bff34e3Sthurlow  * than in every function calling this.
674bff34e3Sthurlow  */
684bff34e3Sthurlow static int
694bff34e3Sthurlow smb_usr_ioc2vcspec(struct smbioc_ossn *dp, struct smb_vcspec *spec)
704bff34e3Sthurlow {
714bff34e3Sthurlow 	cred_t *cr = CRED();
724bff34e3Sthurlow 	uid_t realuid;
734bff34e3Sthurlow 
744bff34e3Sthurlow 	/*
754bff34e3Sthurlow 	 * Only superuser can specify a UID or GID.
764bff34e3Sthurlow 	 */
774bff34e3Sthurlow 	realuid = crgetruid(cr);
784bff34e3Sthurlow 	if (dp->ioc_owner == SMBM_ANY_OWNER)
794bff34e3Sthurlow 		spec->owner = realuid;
804bff34e3Sthurlow 	else {
814bff34e3Sthurlow 		/*
824bff34e3Sthurlow 		 * Do we have the privilege to create with the
834bff34e3Sthurlow 		 * specified uid?  (does uid == cr->cr_uid, etc.)
844bff34e3Sthurlow 		 * MacOS would want suser(), or similar here.
854bff34e3Sthurlow 		 */
864bff34e3Sthurlow 		if (secpolicy_vnode_owner(cr, dp->ioc_owner))
874bff34e3Sthurlow 			return (EPERM);
884bff34e3Sthurlow 		spec->owner = dp->ioc_owner;
894bff34e3Sthurlow 	}
904bff34e3Sthurlow 	if (dp->ioc_group == SMBM_ANY_GROUP)
914bff34e3Sthurlow 		spec->group = crgetgid(cr);
924bff34e3Sthurlow 	else {
934bff34e3Sthurlow 		/*
944bff34e3Sthurlow 		 * Do we have the privilege to create with the
954bff34e3Sthurlow 		 * specified gid?  (one of our groups?)
964bff34e3Sthurlow 		 */
974bff34e3Sthurlow 		if (groupmember(dp->ioc_group, cr) ||
984bff34e3Sthurlow 		    secpolicy_vnode_create_gid(cr) == 0)
994bff34e3Sthurlow 			spec->group = dp->ioc_group;
1004bff34e3Sthurlow 		else
1014bff34e3Sthurlow 			return (EPERM);
1024bff34e3Sthurlow 	}
1034bff34e3Sthurlow 
1044bff34e3Sthurlow 	/*
1054bff34e3Sthurlow 	 * Valid codesets?  XXX
1064bff34e3Sthurlow 	 */
1074bff34e3Sthurlow 	if (dp->ioc_localcs[0] == 0) {
1084bff34e3Sthurlow 		spec->localcs = "ISO8859-1";
1094bff34e3Sthurlow #ifdef NOTYETRESOLVED
1104bff34e3Sthurlow 		SMBERROR("no local charset ? dp->ioc_localcs[0]: %d\n",
1114bff34e3Sthurlow 		    dp->ioc_localcs[0]);
1124bff34e3Sthurlow 		return (EINVAL);
1134bff34e3Sthurlow #endif
1144bff34e3Sthurlow 	} else
1154bff34e3Sthurlow 		spec->localcs = spec->localcs;
1164bff34e3Sthurlow 
1174bff34e3Sthurlow 	/*
1184bff34e3Sthurlow 	 * Check for valid sa_family.
1194bff34e3Sthurlow 	 * XXX: Just NetBIOS for now.
1204bff34e3Sthurlow 	 */
1214bff34e3Sthurlow 	if (dp->ioc_server.sa.sa_family != AF_NETBIOS)
1224bff34e3Sthurlow 		return (EINVAL);
1234bff34e3Sthurlow 	spec->sap = &dp->ioc_server.sa;
1244bff34e3Sthurlow 
1254bff34e3Sthurlow 	if (dp->ioc_local.sa.sa_family) {
1264bff34e3Sthurlow 		/* If specified, local AF must be the same. */
1274bff34e3Sthurlow 		if (dp->ioc_local.sa.sa_family !=
1284bff34e3Sthurlow 		    dp->ioc_server.sa.sa_family)
1294bff34e3Sthurlow 			return (EINVAL);
1304bff34e3Sthurlow 		spec->lap = &dp->ioc_local.sa;
1314bff34e3Sthurlow 	}
1324bff34e3Sthurlow 
1334bff34e3Sthurlow 	if (dp->ioc_intok) {
1344bff34e3Sthurlow 		spec->tok = smb_memdupin(dp->ioc_intok, dp->ioc_intoklen);
1354bff34e3Sthurlow 		if (spec->tok == NULL)
1364bff34e3Sthurlow 			return (EFAULT);
1374bff34e3Sthurlow 		spec->toklen = dp->ioc_intoklen;
1384bff34e3Sthurlow 	}
1394bff34e3Sthurlow 
1404bff34e3Sthurlow 	spec->srvname = dp->ioc_srvname;
1414bff34e3Sthurlow 	spec->pass = dp->ioc_password;
1424bff34e3Sthurlow 	spec->domain = dp->ioc_workgroup;
1434bff34e3Sthurlow 	spec->username = dp->ioc_user;
1444bff34e3Sthurlow 	spec->mode = dp->ioc_mode;
1454bff34e3Sthurlow 	spec->rights = dp->ioc_rights;
1464bff34e3Sthurlow 	spec->servercs = dp->ioc_servercs;
1474bff34e3Sthurlow 	spec->optflags = dp->ioc_opt;
1484bff34e3Sthurlow 
1494bff34e3Sthurlow 	return (0);
1504bff34e3Sthurlow }
1514bff34e3Sthurlow 
1524bff34e3Sthurlow static void
1534bff34e3Sthurlow smb_usr_shspec_free(struct smb_sharespec *sspec)
1544bff34e3Sthurlow {
1554bff34e3Sthurlow 	kmem_free(sspec, sizeof (struct smb_sharespec));
1564bff34e3Sthurlow }
1574bff34e3Sthurlow 
1584bff34e3Sthurlow static void
1594bff34e3Sthurlow smb_usr_vcspec_free(struct smb_vcspec *spec)
1604bff34e3Sthurlow {
1614bff34e3Sthurlow 
1624bff34e3Sthurlow 	if (spec->tok) {
1634bff34e3Sthurlow 		kmem_free(spec->tok, spec->toklen);
1644bff34e3Sthurlow 	}
1654bff34e3Sthurlow 	kmem_free(spec, sizeof (*spec));
1664bff34e3Sthurlow }
1674bff34e3Sthurlow 
1684bff34e3Sthurlow static int
1694bff34e3Sthurlow smb_usr_ioc2sharespec(struct smbioc_oshare *dp, struct smb_sharespec *spec)
1704bff34e3Sthurlow {
1714bff34e3Sthurlow 	bzero(spec, sizeof (*spec));
1724bff34e3Sthurlow 	spec->name = dp->ioc_share;
1734bff34e3Sthurlow 	spec->pass = dp->ioc_password;
1744bff34e3Sthurlow 	spec->mode = dp->ioc_mode;
1754bff34e3Sthurlow 	spec->rights = dp->ioc_rights;
1764bff34e3Sthurlow 	spec->owner = dp->ioc_owner;
1774bff34e3Sthurlow 	spec->group = dp->ioc_group;
1784bff34e3Sthurlow 	spec->stype = dp->ioc_stype;
1794bff34e3Sthurlow 	spec->optflags = dp->ioc_opt;
1804bff34e3Sthurlow 	return (0);
1814bff34e3Sthurlow }
1824bff34e3Sthurlow 
1831b34bc4aSbs int
1841b34bc4aSbs smb_usr_findvc(struct smbioc_lookup *dp, struct smb_cred *scred,
1851b34bc4aSbs 	struct smb_vc **vcpp)
1861b34bc4aSbs {
1871b34bc4aSbs 	struct smb_vc *vcp = NULL;
1881b34bc4aSbs 	struct smb_vcspec *vspec = NULL;
1891b34bc4aSbs 	int error = 0;
1901b34bc4aSbs 
1911b34bc4aSbs 	if (dp->ioc_flags & SMBLK_CREATE)
1921b34bc4aSbs 		return (EINVAL);
1931b34bc4aSbs 	if (dp->ioc_level != SMBL_VC)
1941b34bc4aSbs 		return (EINVAL);
1951b34bc4aSbs 	vspec = kmem_zalloc(sizeof (struct smb_vcspec), KM_SLEEP);
1961b34bc4aSbs 	error = smb_usr_ioc2vcspec(&dp->ioc_ssn, vspec);
1971b34bc4aSbs 	if (error)
1981b34bc4aSbs 		goto out;
1991b34bc4aSbs 	error = smb_sm_findvc(vspec, scred, &vcp);
2001b34bc4aSbs 	if (error == 0)
2011b34bc4aSbs 		*vcpp =  vcp;
2021b34bc4aSbs out:
2031b34bc4aSbs 	smb_usr_vcspec_free(vspec);
2041b34bc4aSbs 	return (error);
2051b34bc4aSbs }
2061b34bc4aSbs 
2074bff34e3Sthurlow int
2084bff34e3Sthurlow smb_usr_negotiate(struct smbioc_lookup *dp, struct smb_cred *scred,
2094bff34e3Sthurlow 	struct smb_vc **vcpp)
2104bff34e3Sthurlow {
2114bff34e3Sthurlow 	struct smb_vc *vcp = NULL;
2124bff34e3Sthurlow 	struct smb_vcspec *vspec = NULL;
2134bff34e3Sthurlow 	struct smb_sharespec *sspecp = NULL;
2144bff34e3Sthurlow 	int error = 0;
2154bff34e3Sthurlow 
2164bff34e3Sthurlow 	if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE)
2174bff34e3Sthurlow 		return (EINVAL);
2184bff34e3Sthurlow 	vspec = kmem_zalloc(sizeof (struct smb_vcspec), KM_SLEEP);
2194bff34e3Sthurlow 	error = smb_usr_ioc2vcspec(&dp->ioc_ssn, vspec);
2204bff34e3Sthurlow 	if (error)
2214bff34e3Sthurlow 		return (error);
2224bff34e3Sthurlow 	if (dp->ioc_flags & SMBLK_CREATE)
2234bff34e3Sthurlow 		vspec->optflags |= SMBVOPT_CREATE;
2244bff34e3Sthurlow 	if (dp->ioc_level >= SMBL_SHARE) {
2254bff34e3Sthurlow 		sspecp = kmem_alloc(sizeof (*sspecp), KM_SLEEP);
2264bff34e3Sthurlow 		error = smb_usr_ioc2sharespec(&dp->ioc_sh, sspecp);
2274bff34e3Sthurlow 		if (error)
2284bff34e3Sthurlow 			goto out;
2294bff34e3Sthurlow 	}
2304bff34e3Sthurlow 	error = smb_sm_negotiate(vspec, scred, &vcp);
2314bff34e3Sthurlow 	if (error == 0) {
2324bff34e3Sthurlow 		*vcpp =  vcp;
2334bff34e3Sthurlow 		/*
2344bff34e3Sthurlow 		 * Used to copyout ioc_outtok, outtoklen here,
2354bff34e3Sthurlow 		 * but that's now in smb_dev. (our caller)
2364bff34e3Sthurlow 		 *
2374bff34e3Sthurlow 		 * If this call asked for extended security and
2384bff34e3Sthurlow 		 * the server does not support it, clear the
2394bff34e3Sthurlow 		 * flag so the caller knows this.
2404bff34e3Sthurlow 		 *
2414bff34e3Sthurlow 		 * XXX: Should just add sv_caps to ioc_ssn,
2424bff34e3Sthurlow 		 * set the new sv_caps field here, and let
2434bff34e3Sthurlow 		 * let the copyout of ioc_ssn handle it.
2444bff34e3Sthurlow 		 */
2454bff34e3Sthurlow 		if (!(vcp->vc_sopt.sv_caps & SMB_CAP_EXT_SECURITY) &&
2464bff34e3Sthurlow 		    (dp->ioc_ssn.ioc_opt & SMBVOPT_EXT_SEC)) {
2474bff34e3Sthurlow 			dp->ioc_ssn.ioc_opt &= ~SMBVOPT_EXT_SEC;
2484bff34e3Sthurlow 			SMBSDEBUG("turned off extended security");
2494bff34e3Sthurlow 		}
2504bff34e3Sthurlow 	}
2514bff34e3Sthurlow out:
2524bff34e3Sthurlow 	smb_usr_vcspec_free(vspec);
2534bff34e3Sthurlow 	smb_usr_shspec_free(sspecp);
2544bff34e3Sthurlow 	return (error);
2554bff34e3Sthurlow }
2564bff34e3Sthurlow 
2574bff34e3Sthurlow int
2584bff34e3Sthurlow smb_usr_ssnsetup(struct smbioc_lookup *dp, struct smb_cred *scred,
2594bff34e3Sthurlow 	struct smb_vc *vcp)
2604bff34e3Sthurlow {
2614bff34e3Sthurlow 	struct smb_vcspec *vspec = NULL;
2624bff34e3Sthurlow 	int error;
2634bff34e3Sthurlow 
2644bff34e3Sthurlow 	if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE)
2654bff34e3Sthurlow 		return (EINVAL);
2664bff34e3Sthurlow 
2674bff34e3Sthurlow 	vspec = kmem_zalloc(sizeof (struct smb_vcspec), KM_SLEEP);
2684bff34e3Sthurlow 	error = smb_usr_ioc2vcspec(&dp->ioc_ssn, vspec);
2694bff34e3Sthurlow 	if (error)
2704bff34e3Sthurlow 		goto out;
2714bff34e3Sthurlow 
2724bff34e3Sthurlow 	error = smb_sm_ssnsetup(vspec, scred, vcp);
2734bff34e3Sthurlow 	/*
2744bff34e3Sthurlow 	 * Moved the copyout of ioc_outtok to
2754bff34e3Sthurlow 	 * smb_dev.c (our caller)
2764bff34e3Sthurlow 	 */
2774bff34e3Sthurlow 
2784bff34e3Sthurlow out:
2794bff34e3Sthurlow 	smb_usr_vcspec_free(vspec);
2804bff34e3Sthurlow 	return (error);
2814bff34e3Sthurlow }
2824bff34e3Sthurlow 
2834bff34e3Sthurlow 
2844bff34e3Sthurlow int
2854bff34e3Sthurlow smb_usr_tcon(struct smbioc_lookup *dp, struct smb_cred *scred,
2864bff34e3Sthurlow 	struct smb_vc *vcp, struct smb_share **sspp)
2874bff34e3Sthurlow {
2884bff34e3Sthurlow 	struct smb_sharespec *sspecp = NULL;
2894bff34e3Sthurlow 	int error;
2904bff34e3Sthurlow 
2914bff34e3Sthurlow 	if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE)
2924bff34e3Sthurlow 		return (EINVAL);
2934bff34e3Sthurlow 
2944bff34e3Sthurlow 	if (dp->ioc_level >= SMBL_SHARE) {
2954bff34e3Sthurlow 		sspecp = kmem_alloc(sizeof (*sspecp), KM_SLEEP);
2964bff34e3Sthurlow 		error = smb_usr_ioc2sharespec(&dp->ioc_sh, sspecp);
2974bff34e3Sthurlow 		if (error)
2984bff34e3Sthurlow 			goto out;
2994bff34e3Sthurlow 	}
3004bff34e3Sthurlow 	error = smb_sm_tcon(sspecp, scred, vcp, sspp);
3014bff34e3Sthurlow 
3024bff34e3Sthurlow out:
3034bff34e3Sthurlow 	if (sspecp)
3044bff34e3Sthurlow 		smb_usr_shspec_free(sspecp);
3054bff34e3Sthurlow 
3064bff34e3Sthurlow 	return (error);
3074bff34e3Sthurlow }
3084bff34e3Sthurlow 
3094bff34e3Sthurlow /*
3104bff34e3Sthurlow  * Connect to the resource specified by smbioc_ossn structure.
3114bff34e3Sthurlow  * It may either find an existing connection or try to establish a new one.
3124bff34e3Sthurlow  * If no errors occured smb_vc returned locked and referenced.
3134bff34e3Sthurlow  */
3144bff34e3Sthurlow 
3154bff34e3Sthurlow int
3164bff34e3Sthurlow smb_usr_simplerequest(struct smb_share *ssp, struct smbioc_rq *dp,
3174bff34e3Sthurlow 	struct smb_cred *scred)
3184bff34e3Sthurlow {
3194bff34e3Sthurlow 	struct smb_rq rq, *rqp = &rq;
3204bff34e3Sthurlow 	struct mbchain *mbp;
3214bff34e3Sthurlow 	struct mdchain *mdp;
3224bff34e3Sthurlow 	char *p;
3234bff34e3Sthurlow 	size_t wc2;
3244bff34e3Sthurlow 	u_int8_t wc;
3254bff34e3Sthurlow 	u_int16_t bc;
3264bff34e3Sthurlow 	int error;
3274bff34e3Sthurlow 
3284bff34e3Sthurlow 	switch (dp->ioc_cmd) {
3294bff34e3Sthurlow 	case SMB_COM_TRANSACTION2:
3304bff34e3Sthurlow 	case SMB_COM_TRANSACTION2_SECONDARY:
3314bff34e3Sthurlow 	case SMB_COM_CLOSE_AND_TREE_DISC:
3324bff34e3Sthurlow 	case SMB_COM_TREE_CONNECT:
3334bff34e3Sthurlow 	case SMB_COM_TREE_DISCONNECT:
3344bff34e3Sthurlow 	case SMB_COM_NEGOTIATE:
3354bff34e3Sthurlow 	case SMB_COM_SESSION_SETUP_ANDX:
3364bff34e3Sthurlow 	case SMB_COM_LOGOFF_ANDX:
3374bff34e3Sthurlow 	case SMB_COM_TREE_CONNECT_ANDX:
3384bff34e3Sthurlow 		return (EPERM);
3394bff34e3Sthurlow 	}
3404bff34e3Sthurlow 	error = smb_rq_init(rqp, SSTOCP(ssp), dp->ioc_cmd, scred);
3414bff34e3Sthurlow 	if (error)
3424bff34e3Sthurlow 		return (error);
3434bff34e3Sthurlow 	mbp = &rqp->sr_rq;
3444bff34e3Sthurlow 	smb_rq_wstart(rqp);
3454bff34e3Sthurlow 	error = mb_put_mem(mbp, dp->ioc_twords,
3464bff34e3Sthurlow 	    dp->ioc_twc * 2, MB_MUSER);
3474bff34e3Sthurlow 	if (error)
3484bff34e3Sthurlow 		goto bad;
3494bff34e3Sthurlow 	smb_rq_wend(rqp);
3504bff34e3Sthurlow 	smb_rq_bstart(rqp);
3514bff34e3Sthurlow 	error = mb_put_mem(mbp, dp->ioc_tbytes,
3524bff34e3Sthurlow 	    dp->ioc_tbc, MB_MUSER);
3534bff34e3Sthurlow 	if (error)
3544bff34e3Sthurlow 		goto bad;
3554bff34e3Sthurlow 	smb_rq_bend(rqp);
3564bff34e3Sthurlow 	error = smb_rq_simple(rqp);
3574bff34e3Sthurlow 	if (error)
3584bff34e3Sthurlow 		goto bad;
3594bff34e3Sthurlow 	mdp = &rqp->sr_rp;
3604bff34e3Sthurlow 	md_get_uint8(mdp, &wc);
3614bff34e3Sthurlow 	dp->ioc_rwc = wc;
3624bff34e3Sthurlow 	wc2 = wc * 2;
3634bff34e3Sthurlow 	if (wc2 > dp->ioc_rpbufsz) {
3644bff34e3Sthurlow 		error = EBADRPC;
3654bff34e3Sthurlow 		goto bad;
3664bff34e3Sthurlow 	}
3674bff34e3Sthurlow 	error = md_get_mem(mdp, dp->ioc_rpbuf, wc2, MB_MUSER);
3684bff34e3Sthurlow 	if (error)
3694bff34e3Sthurlow 		goto bad;
3704bff34e3Sthurlow 	md_get_uint16le(mdp, &bc);
3714bff34e3Sthurlow 	if ((wc2 + bc) > dp->ioc_rpbufsz) {
3724bff34e3Sthurlow 		error = EBADRPC;
3734bff34e3Sthurlow 		goto bad;
3744bff34e3Sthurlow 	}
3754bff34e3Sthurlow 	dp->ioc_rbc = bc;
3764bff34e3Sthurlow 	p = dp->ioc_rpbuf;
3774bff34e3Sthurlow 	error = md_get_mem(mdp, p + wc2, bc, MB_MUSER);
3784bff34e3Sthurlow bad:
3794bff34e3Sthurlow 	dp->ioc_errclass = rqp->sr_errclass;
3804bff34e3Sthurlow 	dp->ioc_serror = rqp->sr_serror;
3814bff34e3Sthurlow 	dp->ioc_error = rqp->sr_error;
3824bff34e3Sthurlow 	smb_rq_done(rqp);
3834bff34e3Sthurlow 	return (error);
3844bff34e3Sthurlow 
3854bff34e3Sthurlow }
3864bff34e3Sthurlow 
3874bff34e3Sthurlow static int
3884bff34e3Sthurlow smb_cpdatain(struct mbchain *mbp, int len, char *data)
3894bff34e3Sthurlow {
3904bff34e3Sthurlow 	int error;
3914bff34e3Sthurlow 
3924bff34e3Sthurlow 	if (len == 0)
3934bff34e3Sthurlow 		return (0);
3944bff34e3Sthurlow 	error = mb_init(mbp);
3954bff34e3Sthurlow 	if (error)
3964bff34e3Sthurlow 		return (error);
3974bff34e3Sthurlow 	return (mb_put_mem(mbp, data, len, MB_MUSER));
3984bff34e3Sthurlow }
3994bff34e3Sthurlow 
4004bff34e3Sthurlow int
4014bff34e3Sthurlow smb_usr_t2request(struct smb_share *ssp, smbioc_t2rq_t *dp,
4024bff34e3Sthurlow 	struct smb_cred *scred)
4034bff34e3Sthurlow {
4044bff34e3Sthurlow 	struct smb_t2rq t2, *t2p = &t2;
4054bff34e3Sthurlow 	struct mdchain *mdp;
4064bff34e3Sthurlow 	int error, len;
4074bff34e3Sthurlow 
4084bff34e3Sthurlow 	if (dp->ioc_setupcnt > SMB_MAXSETUPWORDS)
4094bff34e3Sthurlow 		return (EINVAL);
4104bff34e3Sthurlow 	error = smb_t2_init(t2p, SSTOCP(ssp), dp->ioc_setup, dp->ioc_setupcnt,
4114bff34e3Sthurlow 	    scred);
4124bff34e3Sthurlow 	if (error)
4134bff34e3Sthurlow 		return (error);
4144bff34e3Sthurlow 	len = t2p->t2_setupcount = dp->ioc_setupcnt;
4154bff34e3Sthurlow 	if (len > 1)
4164bff34e3Sthurlow 		t2p->t2_setupdata = dp->ioc_setup;
417*9c9af259SGordon Ross 	/* This ioc member is a fixed-size array. */
418*9c9af259SGordon Ross 	if (dp->ioc_name[0]) {
419*9c9af259SGordon Ross 		t2p->t_name_maxlen = SMBIOC_T2RQ_MAXNAME;
420*9c9af259SGordon Ross 		t2p->t_name = kmem_alloc(t2p->t_name_maxlen, KM_SLEEP);
421*9c9af259SGordon Ross 		bcopy(dp->ioc_name, t2p->t_name, t2p->t_name_maxlen);
422*9c9af259SGordon Ross 		/* Get the string length - carefully! */
423*9c9af259SGordon Ross 		t2p->t_name[t2p->t_name_maxlen - 1] = '\0';
424*9c9af259SGordon Ross 		t2p->t_name_len = strlen(t2p->t_name);
4254bff34e3Sthurlow 	}
4264bff34e3Sthurlow 	t2p->t2_maxscount = 0;
4274bff34e3Sthurlow 	t2p->t2_maxpcount = dp->ioc_rparamcnt;
4284bff34e3Sthurlow 	t2p->t2_maxdcount = dp->ioc_rdatacnt;
4294bff34e3Sthurlow 	error = smb_cpdatain(&t2p->t2_tparam, dp->ioc_tparamcnt,
4304bff34e3Sthurlow 	    dp->ioc_tparam);
4314bff34e3Sthurlow 	if (error)
4324bff34e3Sthurlow 		goto bad;
4334bff34e3Sthurlow 	error = smb_cpdatain(&t2p->t2_tdata,
4344bff34e3Sthurlow 	    dp->ioc_tdatacnt, dp->ioc_tdata);
4354bff34e3Sthurlow 	if (error)
4364bff34e3Sthurlow 		goto bad;
4374bff34e3Sthurlow 	error = smb_t2_request(t2p);
4384bff34e3Sthurlow 	dp->ioc_errclass = t2p->t2_sr_errclass;
4394bff34e3Sthurlow 	dp->ioc_serror = t2p->t2_sr_serror;
4404bff34e3Sthurlow 	dp->ioc_error = t2p->t2_sr_error;
4414bff34e3Sthurlow 	dp->ioc_rpflags2 = t2p->t2_sr_rpflags2;
4424bff34e3Sthurlow 	if (error)
4434bff34e3Sthurlow 		goto bad;
4444bff34e3Sthurlow 	mdp = &t2p->t2_rparam;
4454bff34e3Sthurlow 	if (mdp->md_top) {
4464bff34e3Sthurlow 		mblk_t *m = mdp->md_top;
4474bff34e3Sthurlow #ifdef lint
4484bff34e3Sthurlow 		m = m;
4494bff34e3Sthurlow #endif
4504bff34e3Sthurlow 		len = m_fixhdr(mdp->md_top);
4514bff34e3Sthurlow 		if (len > dp->ioc_rparamcnt) {
4524bff34e3Sthurlow 			error = EMSGSIZE;
4534bff34e3Sthurlow 			goto bad;
4544bff34e3Sthurlow 		}
4554bff34e3Sthurlow 		dp->ioc_rparamcnt = (ushort_t)len;
4564bff34e3Sthurlow 		error = md_get_mem(mdp, dp->ioc_rparam,
4574bff34e3Sthurlow 		    len, MB_MUSER);
4584bff34e3Sthurlow 		if (error) {
4594bff34e3Sthurlow 			goto bad;
4604bff34e3Sthurlow 		}
4614bff34e3Sthurlow 	} else
4624bff34e3Sthurlow 		dp->ioc_rparamcnt = 0;
4634bff34e3Sthurlow 	mdp = &t2p->t2_rdata;
4644bff34e3Sthurlow 	if (mdp->md_top) {
4654bff34e3Sthurlow 		mblk_t *m = mdp->md_top;
4664bff34e3Sthurlow #ifdef lint
4674bff34e3Sthurlow 		m = m;
4684bff34e3Sthurlow #endif
4694bff34e3Sthurlow 		len = m_fixhdr(mdp->md_top);
4704bff34e3Sthurlow 		if (len > dp->ioc_rdatacnt) {
4714bff34e3Sthurlow 			error = EMSGSIZE;
4724bff34e3Sthurlow 			goto bad;
4734bff34e3Sthurlow 		}
4744bff34e3Sthurlow 		dp->ioc_rdatacnt = (ushort_t)len;
4754bff34e3Sthurlow 		error = md_get_mem(mdp, dp->ioc_rdata,
4764bff34e3Sthurlow 		    len, MB_MUSER);
4774bff34e3Sthurlow 		if (error) {
4784bff34e3Sthurlow 			goto bad;
4794bff34e3Sthurlow 		}
4804bff34e3Sthurlow 	} else
4814bff34e3Sthurlow 		dp->ioc_rdatacnt = 0;
4824bff34e3Sthurlow bad:
483*9c9af259SGordon Ross 	if (t2p->t_name) {
484*9c9af259SGordon Ross 		kmem_free(t2p->t_name, t2p->t_name_maxlen);
485*9c9af259SGordon Ross 		t2p->t_name = NULL;
486*9c9af259SGordon Ross 	}
4874bff34e3Sthurlow 	smb_t2_done(t2p);
4884bff34e3Sthurlow 	return (error);
4894bff34e3Sthurlow }
4904bff34e3Sthurlow 
4914bff34e3Sthurlow /*
4924bff34e3Sthurlow  * Helper for nsmb_ioctl cases
4934bff34e3Sthurlow  * SMBIOC_READ, SMBIOC_WRITE
4944bff34e3Sthurlow  */
4954bff34e3Sthurlow int
4964bff34e3Sthurlow smb_usr_rw(struct smb_share *ssp, smbioc_rw_t *rwrq,
4974bff34e3Sthurlow     int cmd, struct smb_cred *scred)
4984bff34e3Sthurlow {
4994bff34e3Sthurlow 	struct iovec aiov[1];
5004bff34e3Sthurlow 	struct uio  auio;
5014bff34e3Sthurlow 	u_int16_t fh;
5024bff34e3Sthurlow 	int error;
5034bff34e3Sthurlow 	uio_rw_t rw;
5044bff34e3Sthurlow 
5054bff34e3Sthurlow 	switch (cmd) {
5064bff34e3Sthurlow 	case SMBIOC_READ:
5074bff34e3Sthurlow 		rw = UIO_READ;
5084bff34e3Sthurlow 		break;
5094bff34e3Sthurlow 	case SMBIOC_WRITE:
5104bff34e3Sthurlow 		rw = UIO_WRITE;
5114bff34e3Sthurlow 		break;
5124bff34e3Sthurlow 	default:
5134bff34e3Sthurlow 		return (ENODEV);
5144bff34e3Sthurlow 	}
5154bff34e3Sthurlow 
5164bff34e3Sthurlow 	fh = htoles(rwrq->ioc_fh);
5174bff34e3Sthurlow 
5184bff34e3Sthurlow 	aiov[0].iov_base = rwrq->ioc_base;
5194bff34e3Sthurlow 	aiov[0].iov_len = (size_t)rwrq->ioc_cnt;
5204bff34e3Sthurlow 
5214bff34e3Sthurlow 	auio.uio_iov = aiov;
5224bff34e3Sthurlow 	auio.uio_iovcnt = 1;
5234bff34e3Sthurlow 	auio.uio_loffset = rwrq->ioc_offset;
5244bff34e3Sthurlow 	auio.uio_segflg = UIO_USERSPACE;
5254bff34e3Sthurlow 	auio.uio_fmode = 0;
5264bff34e3Sthurlow 	auio.uio_resid = (size_t)rwrq->ioc_cnt;
5274bff34e3Sthurlow 
5284bff34e3Sthurlow 	error = smb_rwuio(ssp, fh, rw, &auio, scred, 0);
5294bff34e3Sthurlow 
5304bff34e3Sthurlow 	/*
5314bff34e3Sthurlow 	 * On return ioc_cnt holds the
5324bff34e3Sthurlow 	 * number of bytes transferred.
5334bff34e3Sthurlow 	 */
5344bff34e3Sthurlow 	rwrq->ioc_cnt -= auio.uio_resid;
5354bff34e3Sthurlow 
5364bff34e3Sthurlow 	return (error);
5374bff34e3Sthurlow }
538