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 
354bff34e3Sthurlow #pragma ident	"%Z%%M%	%I%	%E% SMI"
364bff34e3Sthurlow 
374bff34e3Sthurlow #include <sys/param.h>
384bff34e3Sthurlow #include <sys/kmem.h>
394bff34e3Sthurlow #include <sys/systm.h>
404bff34e3Sthurlow #include <sys/policy.h>
414bff34e3Sthurlow #include <sys/conf.h>
424bff34e3Sthurlow #include <sys/proc.h>
434bff34e3Sthurlow #include <sys/fcntl.h>
444bff34e3Sthurlow #include <sys/socket.h>
454bff34e3Sthurlow #include <sys/cmn_err.h>
464bff34e3Sthurlow 
474bff34e3Sthurlow #ifdef APPLE
484bff34e3Sthurlow #include <sys/smb_apple.h>
494bff34e3Sthurlow #include <sys/smb_iconv.h>
504bff34e3Sthurlow #else
514bff34e3Sthurlow #include <netsmb/smb_osdep.h>
524bff34e3Sthurlow #endif
534bff34e3Sthurlow 
544bff34e3Sthurlow #include <netsmb/smb.h>
554bff34e3Sthurlow #include <netsmb/smb_conn.h>
564bff34e3Sthurlow #include <netsmb/smb_rq.h>
574bff34e3Sthurlow #include <netsmb/smb_subr.h>
584bff34e3Sthurlow #include <netsmb/smb_dev.h>
594bff34e3Sthurlow 
604bff34e3Sthurlow /*
614bff34e3Sthurlow  * helpers for nsmb device. Can be moved to the smb_dev.c file.
624bff34e3Sthurlow  */
634bff34e3Sthurlow static void smb_usr_vcspec_free(struct smb_vcspec *spec);
644bff34e3Sthurlow 
654bff34e3Sthurlow /*
664bff34e3Sthurlow  * Moved the access checks here, just becuase
674bff34e3Sthurlow  * this was a more convenient place to do it
684bff34e3Sthurlow  * than in every function calling this.
694bff34e3Sthurlow  */
704bff34e3Sthurlow static int
714bff34e3Sthurlow smb_usr_ioc2vcspec(struct smbioc_ossn *dp, struct smb_vcspec *spec)
724bff34e3Sthurlow {
734bff34e3Sthurlow 	cred_t *cr = CRED();
744bff34e3Sthurlow 	uid_t realuid;
754bff34e3Sthurlow 
764bff34e3Sthurlow 	/*
774bff34e3Sthurlow 	 * Only superuser can specify a UID or GID.
784bff34e3Sthurlow 	 */
794bff34e3Sthurlow 	realuid = crgetruid(cr);
804bff34e3Sthurlow 	if (dp->ioc_owner == SMBM_ANY_OWNER)
814bff34e3Sthurlow 		spec->owner = realuid;
824bff34e3Sthurlow 	else {
834bff34e3Sthurlow 		/*
844bff34e3Sthurlow 		 * Do we have the privilege to create with the
854bff34e3Sthurlow 		 * specified uid?  (does uid == cr->cr_uid, etc.)
864bff34e3Sthurlow 		 * MacOS would want suser(), or similar here.
874bff34e3Sthurlow 		 */
884bff34e3Sthurlow 		if (secpolicy_vnode_owner(cr, dp->ioc_owner))
894bff34e3Sthurlow 			return (EPERM);
904bff34e3Sthurlow 		spec->owner = dp->ioc_owner;
914bff34e3Sthurlow 	}
924bff34e3Sthurlow 	if (dp->ioc_group == SMBM_ANY_GROUP)
934bff34e3Sthurlow 		spec->group = crgetgid(cr);
944bff34e3Sthurlow 	else {
954bff34e3Sthurlow 		/*
964bff34e3Sthurlow 		 * Do we have the privilege to create with the
974bff34e3Sthurlow 		 * specified gid?  (one of our groups?)
984bff34e3Sthurlow 		 */
994bff34e3Sthurlow 		if (groupmember(dp->ioc_group, cr) ||
1004bff34e3Sthurlow 		    secpolicy_vnode_create_gid(cr) == 0)
1014bff34e3Sthurlow 			spec->group = dp->ioc_group;
1024bff34e3Sthurlow 		else
1034bff34e3Sthurlow 			return (EPERM);
1044bff34e3Sthurlow 	}
1054bff34e3Sthurlow 
1064bff34e3Sthurlow 	/*
1074bff34e3Sthurlow 	 * Valid codesets?  XXX
1084bff34e3Sthurlow 	 */
1094bff34e3Sthurlow 	if (dp->ioc_localcs[0] == 0) {
1104bff34e3Sthurlow 		spec->localcs = "ISO8859-1";
1114bff34e3Sthurlow #ifdef NOTYETRESOLVED
1124bff34e3Sthurlow 		SMBERROR("no local charset ? dp->ioc_localcs[0]: %d\n",
1134bff34e3Sthurlow 		    dp->ioc_localcs[0]);
1144bff34e3Sthurlow 		return (EINVAL);
1154bff34e3Sthurlow #endif
1164bff34e3Sthurlow 	} else
1174bff34e3Sthurlow 		spec->localcs = spec->localcs;
1184bff34e3Sthurlow 
1194bff34e3Sthurlow 	/*
1204bff34e3Sthurlow 	 * Check for valid sa_family.
1214bff34e3Sthurlow 	 * XXX: Just NetBIOS for now.
1224bff34e3Sthurlow 	 */
1234bff34e3Sthurlow 	if (dp->ioc_server.sa.sa_family != AF_NETBIOS)
1244bff34e3Sthurlow 		return (EINVAL);
1254bff34e3Sthurlow 	spec->sap = &dp->ioc_server.sa;
1264bff34e3Sthurlow 
1274bff34e3Sthurlow 	if (dp->ioc_local.sa.sa_family) {
1284bff34e3Sthurlow 		/* If specified, local AF must be the same. */
1294bff34e3Sthurlow 		if (dp->ioc_local.sa.sa_family !=
1304bff34e3Sthurlow 		    dp->ioc_server.sa.sa_family)
1314bff34e3Sthurlow 			return (EINVAL);
1324bff34e3Sthurlow 		spec->lap = &dp->ioc_local.sa;
1334bff34e3Sthurlow 	}
1344bff34e3Sthurlow 
1354bff34e3Sthurlow 	if (dp->ioc_intok) {
1364bff34e3Sthurlow 		spec->tok = smb_memdupin(dp->ioc_intok, dp->ioc_intoklen);
1374bff34e3Sthurlow 		if (spec->tok == NULL)
1384bff34e3Sthurlow 			return (EFAULT);
1394bff34e3Sthurlow 		spec->toklen = dp->ioc_intoklen;
1404bff34e3Sthurlow 	}
1414bff34e3Sthurlow 
1424bff34e3Sthurlow 	spec->srvname = dp->ioc_srvname;
1434bff34e3Sthurlow 	spec->pass = dp->ioc_password;
1444bff34e3Sthurlow 	spec->domain = dp->ioc_workgroup;
1454bff34e3Sthurlow 	spec->username = dp->ioc_user;
1464bff34e3Sthurlow 	spec->mode = dp->ioc_mode;
1474bff34e3Sthurlow 	spec->rights = dp->ioc_rights;
1484bff34e3Sthurlow 	spec->servercs = dp->ioc_servercs;
1494bff34e3Sthurlow 	spec->optflags = dp->ioc_opt;
1504bff34e3Sthurlow 
1514bff34e3Sthurlow 	return (0);
1524bff34e3Sthurlow }
1534bff34e3Sthurlow 
1544bff34e3Sthurlow static void
1554bff34e3Sthurlow smb_usr_shspec_free(struct smb_sharespec *sspec)
1564bff34e3Sthurlow {
1574bff34e3Sthurlow 	kmem_free(sspec, sizeof (struct smb_sharespec));
1584bff34e3Sthurlow }
1594bff34e3Sthurlow 
1604bff34e3Sthurlow static void
1614bff34e3Sthurlow smb_usr_vcspec_free(struct smb_vcspec *spec)
1624bff34e3Sthurlow {
1634bff34e3Sthurlow 
1644bff34e3Sthurlow 	if (spec->tok) {
1654bff34e3Sthurlow 		kmem_free(spec->tok, spec->toklen);
1664bff34e3Sthurlow 	}
1674bff34e3Sthurlow 	kmem_free(spec, sizeof (*spec));
1684bff34e3Sthurlow }
1694bff34e3Sthurlow 
1704bff34e3Sthurlow static int
1714bff34e3Sthurlow smb_usr_ioc2sharespec(struct smbioc_oshare *dp, struct smb_sharespec *spec)
1724bff34e3Sthurlow {
1734bff34e3Sthurlow 	bzero(spec, sizeof (*spec));
1744bff34e3Sthurlow 	spec->name = dp->ioc_share;
1754bff34e3Sthurlow 	spec->pass = dp->ioc_password;
1764bff34e3Sthurlow 	spec->mode = dp->ioc_mode;
1774bff34e3Sthurlow 	spec->rights = dp->ioc_rights;
1784bff34e3Sthurlow 	spec->owner = dp->ioc_owner;
1794bff34e3Sthurlow 	spec->group = dp->ioc_group;
1804bff34e3Sthurlow 	spec->stype = dp->ioc_stype;
1814bff34e3Sthurlow 	spec->optflags = dp->ioc_opt;
1824bff34e3Sthurlow 	return (0);
1834bff34e3Sthurlow }
1844bff34e3Sthurlow 
185*1b34bc4aSbs int
186*1b34bc4aSbs smb_usr_findvc(struct smbioc_lookup *dp, struct smb_cred *scred,
187*1b34bc4aSbs 	struct smb_vc **vcpp)
188*1b34bc4aSbs {
189*1b34bc4aSbs 	struct smb_vc *vcp = NULL;
190*1b34bc4aSbs 	struct smb_vcspec *vspec = NULL;
191*1b34bc4aSbs 	int error = 0;
192*1b34bc4aSbs 
193*1b34bc4aSbs 	if (dp->ioc_flags & SMBLK_CREATE)
194*1b34bc4aSbs 		return (EINVAL);
195*1b34bc4aSbs 	if (dp->ioc_level != SMBL_VC)
196*1b34bc4aSbs 		return (EINVAL);
197*1b34bc4aSbs 	vspec = kmem_zalloc(sizeof (struct smb_vcspec), KM_SLEEP);
198*1b34bc4aSbs 	error = smb_usr_ioc2vcspec(&dp->ioc_ssn, vspec);
199*1b34bc4aSbs 	if (error)
200*1b34bc4aSbs 		goto out;
201*1b34bc4aSbs 	error = smb_sm_findvc(vspec, scred, &vcp);
202*1b34bc4aSbs 	if (error == 0)
203*1b34bc4aSbs 		*vcpp =  vcp;
204*1b34bc4aSbs out:
205*1b34bc4aSbs 	smb_usr_vcspec_free(vspec);
206*1b34bc4aSbs 	return (error);
207*1b34bc4aSbs }
208*1b34bc4aSbs 
2094bff34e3Sthurlow int
2104bff34e3Sthurlow smb_usr_negotiate(struct smbioc_lookup *dp, struct smb_cred *scred,
2114bff34e3Sthurlow 	struct smb_vc **vcpp)
2124bff34e3Sthurlow {
2134bff34e3Sthurlow 	struct smb_vc *vcp = NULL;
2144bff34e3Sthurlow 	struct smb_vcspec *vspec = NULL;
2154bff34e3Sthurlow 	struct smb_sharespec *sspecp = NULL;
2164bff34e3Sthurlow 	int error = 0;
2174bff34e3Sthurlow 
2184bff34e3Sthurlow 	if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE)
2194bff34e3Sthurlow 		return (EINVAL);
2204bff34e3Sthurlow 	vspec = kmem_zalloc(sizeof (struct smb_vcspec), KM_SLEEP);
2214bff34e3Sthurlow 	error = smb_usr_ioc2vcspec(&dp->ioc_ssn, vspec);
2224bff34e3Sthurlow 	if (error)
2234bff34e3Sthurlow 		return (error);
2244bff34e3Sthurlow 	if (dp->ioc_flags & SMBLK_CREATE)
2254bff34e3Sthurlow 		vspec->optflags |= SMBVOPT_CREATE;
2264bff34e3Sthurlow 	if (dp->ioc_level >= SMBL_SHARE) {
2274bff34e3Sthurlow 		sspecp = kmem_alloc(sizeof (*sspecp), KM_SLEEP);
2284bff34e3Sthurlow 		error = smb_usr_ioc2sharespec(&dp->ioc_sh, sspecp);
2294bff34e3Sthurlow 		if (error)
2304bff34e3Sthurlow 			goto out;
2314bff34e3Sthurlow 	}
2324bff34e3Sthurlow 	error = smb_sm_negotiate(vspec, scred, &vcp);
2334bff34e3Sthurlow 	if (error == 0) {
2344bff34e3Sthurlow 		*vcpp =  vcp;
2354bff34e3Sthurlow 		/*
2364bff34e3Sthurlow 		 * Used to copyout ioc_outtok, outtoklen here,
2374bff34e3Sthurlow 		 * but that's now in smb_dev. (our caller)
2384bff34e3Sthurlow 		 *
2394bff34e3Sthurlow 		 * If this call asked for extended security and
2404bff34e3Sthurlow 		 * the server does not support it, clear the
2414bff34e3Sthurlow 		 * flag so the caller knows this.
2424bff34e3Sthurlow 		 *
2434bff34e3Sthurlow 		 * XXX: Should just add sv_caps to ioc_ssn,
2444bff34e3Sthurlow 		 * set the new sv_caps field here, and let
2454bff34e3Sthurlow 		 * let the copyout of ioc_ssn handle it.
2464bff34e3Sthurlow 		 */
2474bff34e3Sthurlow 		if (!(vcp->vc_sopt.sv_caps & SMB_CAP_EXT_SECURITY) &&
2484bff34e3Sthurlow 		    (dp->ioc_ssn.ioc_opt & SMBVOPT_EXT_SEC)) {
2494bff34e3Sthurlow 			dp->ioc_ssn.ioc_opt &= ~SMBVOPT_EXT_SEC;
2504bff34e3Sthurlow 			SMBSDEBUG("turned off extended security");
2514bff34e3Sthurlow 		}
2524bff34e3Sthurlow 	}
2534bff34e3Sthurlow out:
2544bff34e3Sthurlow 	smb_usr_vcspec_free(vspec);
2554bff34e3Sthurlow 	smb_usr_shspec_free(sspecp);
2564bff34e3Sthurlow 	return (error);
2574bff34e3Sthurlow }
2584bff34e3Sthurlow 
2594bff34e3Sthurlow int
2604bff34e3Sthurlow smb_usr_ssnsetup(struct smbioc_lookup *dp, struct smb_cred *scred,
2614bff34e3Sthurlow 	struct smb_vc *vcp)
2624bff34e3Sthurlow {
2634bff34e3Sthurlow 	struct smb_vcspec *vspec = NULL;
2644bff34e3Sthurlow 	int error;
2654bff34e3Sthurlow 
2664bff34e3Sthurlow 	if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE)
2674bff34e3Sthurlow 		return (EINVAL);
2684bff34e3Sthurlow 
2694bff34e3Sthurlow 	vspec = kmem_zalloc(sizeof (struct smb_vcspec), KM_SLEEP);
2704bff34e3Sthurlow 	error = smb_usr_ioc2vcspec(&dp->ioc_ssn, vspec);
2714bff34e3Sthurlow 	if (error)
2724bff34e3Sthurlow 		goto out;
2734bff34e3Sthurlow 
2744bff34e3Sthurlow 	error = smb_sm_ssnsetup(vspec, scred, vcp);
2754bff34e3Sthurlow 	/*
2764bff34e3Sthurlow 	 * Moved the copyout of ioc_outtok to
2774bff34e3Sthurlow 	 * smb_dev.c (our caller)
2784bff34e3Sthurlow 	 */
2794bff34e3Sthurlow 
2804bff34e3Sthurlow out:
2814bff34e3Sthurlow 	smb_usr_vcspec_free(vspec);
2824bff34e3Sthurlow 	return (error);
2834bff34e3Sthurlow }
2844bff34e3Sthurlow 
2854bff34e3Sthurlow 
2864bff34e3Sthurlow int
2874bff34e3Sthurlow smb_usr_tcon(struct smbioc_lookup *dp, struct smb_cred *scred,
2884bff34e3Sthurlow 	struct smb_vc *vcp, struct smb_share **sspp)
2894bff34e3Sthurlow {
2904bff34e3Sthurlow 	struct smb_sharespec *sspecp = NULL;
2914bff34e3Sthurlow 	int error;
2924bff34e3Sthurlow 
2934bff34e3Sthurlow 	if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE)
2944bff34e3Sthurlow 		return (EINVAL);
2954bff34e3Sthurlow 
2964bff34e3Sthurlow 	if (dp->ioc_level >= SMBL_SHARE) {
2974bff34e3Sthurlow 		sspecp = kmem_alloc(sizeof (*sspecp), KM_SLEEP);
2984bff34e3Sthurlow 		error = smb_usr_ioc2sharespec(&dp->ioc_sh, sspecp);
2994bff34e3Sthurlow 		if (error)
3004bff34e3Sthurlow 			goto out;
3014bff34e3Sthurlow 	}
3024bff34e3Sthurlow 	error = smb_sm_tcon(sspecp, scred, vcp, sspp);
3034bff34e3Sthurlow 
3044bff34e3Sthurlow out:
3054bff34e3Sthurlow 	if (sspecp)
3064bff34e3Sthurlow 		smb_usr_shspec_free(sspecp);
3074bff34e3Sthurlow 
3084bff34e3Sthurlow 	return (error);
3094bff34e3Sthurlow }
3104bff34e3Sthurlow 
3114bff34e3Sthurlow /*
3124bff34e3Sthurlow  * Connect to the resource specified by smbioc_ossn structure.
3134bff34e3Sthurlow  * It may either find an existing connection or try to establish a new one.
3144bff34e3Sthurlow  * If no errors occured smb_vc returned locked and referenced.
3154bff34e3Sthurlow  */
3164bff34e3Sthurlow 
3174bff34e3Sthurlow int
3184bff34e3Sthurlow smb_usr_simplerequest(struct smb_share *ssp, struct smbioc_rq *dp,
3194bff34e3Sthurlow 	struct smb_cred *scred)
3204bff34e3Sthurlow {
3214bff34e3Sthurlow 	struct smb_rq rq, *rqp = &rq;
3224bff34e3Sthurlow 	struct mbchain *mbp;
3234bff34e3Sthurlow 	struct mdchain *mdp;
3244bff34e3Sthurlow 	char *p;
3254bff34e3Sthurlow 	size_t wc2;
3264bff34e3Sthurlow 	u_int8_t wc;
3274bff34e3Sthurlow 	u_int16_t bc;
3284bff34e3Sthurlow 	int error;
3294bff34e3Sthurlow 
3304bff34e3Sthurlow 	switch (dp->ioc_cmd) {
3314bff34e3Sthurlow 	case SMB_COM_TRANSACTION2:
3324bff34e3Sthurlow 	case SMB_COM_TRANSACTION2_SECONDARY:
3334bff34e3Sthurlow 	case SMB_COM_CLOSE_AND_TREE_DISC:
3344bff34e3Sthurlow 	case SMB_COM_TREE_CONNECT:
3354bff34e3Sthurlow 	case SMB_COM_TREE_DISCONNECT:
3364bff34e3Sthurlow 	case SMB_COM_NEGOTIATE:
3374bff34e3Sthurlow 	case SMB_COM_SESSION_SETUP_ANDX:
3384bff34e3Sthurlow 	case SMB_COM_LOGOFF_ANDX:
3394bff34e3Sthurlow 	case SMB_COM_TREE_CONNECT_ANDX:
3404bff34e3Sthurlow 		return (EPERM);
3414bff34e3Sthurlow 	}
3424bff34e3Sthurlow 	error = smb_rq_init(rqp, SSTOCP(ssp), dp->ioc_cmd, scred);
3434bff34e3Sthurlow 	if (error)
3444bff34e3Sthurlow 		return (error);
3454bff34e3Sthurlow 	mbp = &rqp->sr_rq;
3464bff34e3Sthurlow 	smb_rq_wstart(rqp);
3474bff34e3Sthurlow 	error = mb_put_mem(mbp, dp->ioc_twords,
3484bff34e3Sthurlow 	    dp->ioc_twc * 2, MB_MUSER);
3494bff34e3Sthurlow 	if (error)
3504bff34e3Sthurlow 		goto bad;
3514bff34e3Sthurlow 	smb_rq_wend(rqp);
3524bff34e3Sthurlow 	smb_rq_bstart(rqp);
3534bff34e3Sthurlow 	error = mb_put_mem(mbp, dp->ioc_tbytes,
3544bff34e3Sthurlow 	    dp->ioc_tbc, MB_MUSER);
3554bff34e3Sthurlow 	if (error)
3564bff34e3Sthurlow 		goto bad;
3574bff34e3Sthurlow 	smb_rq_bend(rqp);
3584bff34e3Sthurlow 	error = smb_rq_simple(rqp);
3594bff34e3Sthurlow 	if (error)
3604bff34e3Sthurlow 		goto bad;
3614bff34e3Sthurlow 	mdp = &rqp->sr_rp;
3624bff34e3Sthurlow 	md_get_uint8(mdp, &wc);
3634bff34e3Sthurlow 	dp->ioc_rwc = wc;
3644bff34e3Sthurlow 	wc2 = wc * 2;
3654bff34e3Sthurlow 	if (wc2 > dp->ioc_rpbufsz) {
3664bff34e3Sthurlow 		error = EBADRPC;
3674bff34e3Sthurlow 		goto bad;
3684bff34e3Sthurlow 	}
3694bff34e3Sthurlow 	error = md_get_mem(mdp, dp->ioc_rpbuf, wc2, MB_MUSER);
3704bff34e3Sthurlow 	if (error)
3714bff34e3Sthurlow 		goto bad;
3724bff34e3Sthurlow 	md_get_uint16le(mdp, &bc);
3734bff34e3Sthurlow 	if ((wc2 + bc) > dp->ioc_rpbufsz) {
3744bff34e3Sthurlow 		error = EBADRPC;
3754bff34e3Sthurlow 		goto bad;
3764bff34e3Sthurlow 	}
3774bff34e3Sthurlow 	dp->ioc_rbc = bc;
3784bff34e3Sthurlow 	p = dp->ioc_rpbuf;
3794bff34e3Sthurlow 	error = md_get_mem(mdp, p + wc2, bc, MB_MUSER);
3804bff34e3Sthurlow bad:
3814bff34e3Sthurlow 	dp->ioc_errclass = rqp->sr_errclass;
3824bff34e3Sthurlow 	dp->ioc_serror = rqp->sr_serror;
3834bff34e3Sthurlow 	dp->ioc_error = rqp->sr_error;
3844bff34e3Sthurlow 	smb_rq_done(rqp);
3854bff34e3Sthurlow 	return (error);
3864bff34e3Sthurlow 
3874bff34e3Sthurlow }
3884bff34e3Sthurlow 
3894bff34e3Sthurlow static int
3904bff34e3Sthurlow smb_cpdatain(struct mbchain *mbp, int len, char *data)
3914bff34e3Sthurlow {
3924bff34e3Sthurlow 	int error;
3934bff34e3Sthurlow 
3944bff34e3Sthurlow 	if (len == 0)
3954bff34e3Sthurlow 		return (0);
3964bff34e3Sthurlow 	error = mb_init(mbp);
3974bff34e3Sthurlow 	if (error)
3984bff34e3Sthurlow 		return (error);
3994bff34e3Sthurlow 	return (mb_put_mem(mbp, data, len, MB_MUSER));
4004bff34e3Sthurlow }
4014bff34e3Sthurlow 
4024bff34e3Sthurlow int
4034bff34e3Sthurlow smb_usr_t2request(struct smb_share *ssp, smbioc_t2rq_t *dp,
4044bff34e3Sthurlow 	struct smb_cred *scred)
4054bff34e3Sthurlow {
4064bff34e3Sthurlow 	struct smb_t2rq t2, *t2p = &t2;
4074bff34e3Sthurlow 	struct mdchain *mdp;
4084bff34e3Sthurlow 	int error, len;
4094bff34e3Sthurlow 
4104bff34e3Sthurlow 	if (dp->ioc_setupcnt > SMB_MAXSETUPWORDS)
4114bff34e3Sthurlow 		return (EINVAL);
4124bff34e3Sthurlow 
4134bff34e3Sthurlow 	t2p = (struct smb_t2rq *)kmem_alloc(sizeof (struct smb_t2rq), KM_SLEEP);
4144bff34e3Sthurlow 	if (t2p == NULL)
4154bff34e3Sthurlow 		return (ENOMEM);
4164bff34e3Sthurlow 	error = smb_t2_init(t2p, SSTOCP(ssp), dp->ioc_setup, dp->ioc_setupcnt,
4174bff34e3Sthurlow 	    scred);
4184bff34e3Sthurlow 	if (error)
4194bff34e3Sthurlow 		return (error);
4204bff34e3Sthurlow 	len = t2p->t2_setupcount = dp->ioc_setupcnt;
4214bff34e3Sthurlow 	if (len > 1)
4224bff34e3Sthurlow 		t2p->t2_setupdata = dp->ioc_setup;
4234bff34e3Sthurlow 	if (dp->ioc_name) {
4244bff34e3Sthurlow 		bcopy(dp->ioc_name, t2p->t_name, 128);
4254bff34e3Sthurlow 		if (t2p->t_name == NULL) {
4264bff34e3Sthurlow 			error = ENOMEM;
4274bff34e3Sthurlow 			goto bad;
4284bff34e3Sthurlow 		}
4294bff34e3Sthurlow 	}
4304bff34e3Sthurlow 	t2p->t2_maxscount = 0;
4314bff34e3Sthurlow 	t2p->t2_maxpcount = dp->ioc_rparamcnt;
4324bff34e3Sthurlow 	t2p->t2_maxdcount = dp->ioc_rdatacnt;
4334bff34e3Sthurlow 	error = smb_cpdatain(&t2p->t2_tparam, dp->ioc_tparamcnt,
4344bff34e3Sthurlow 	    dp->ioc_tparam);
4354bff34e3Sthurlow 	if (error)
4364bff34e3Sthurlow 		goto bad;
4374bff34e3Sthurlow 	error = smb_cpdatain(&t2p->t2_tdata,
4384bff34e3Sthurlow 	    dp->ioc_tdatacnt, dp->ioc_tdata);
4394bff34e3Sthurlow 	if (error)
4404bff34e3Sthurlow 		goto bad;
4414bff34e3Sthurlow 	error = smb_t2_request(t2p);
4424bff34e3Sthurlow 	dp->ioc_errclass = t2p->t2_sr_errclass;
4434bff34e3Sthurlow 	dp->ioc_serror = t2p->t2_sr_serror;
4444bff34e3Sthurlow 	dp->ioc_error = t2p->t2_sr_error;
4454bff34e3Sthurlow 	dp->ioc_rpflags2 = t2p->t2_sr_rpflags2;
4464bff34e3Sthurlow 	if (error)
4474bff34e3Sthurlow 		goto bad;
4484bff34e3Sthurlow 	mdp = &t2p->t2_rparam;
4494bff34e3Sthurlow 	if (mdp->md_top) {
4504bff34e3Sthurlow 		mblk_t *m = mdp->md_top;
4514bff34e3Sthurlow #ifdef lint
4524bff34e3Sthurlow 		m = m;
4534bff34e3Sthurlow #endif
4544bff34e3Sthurlow 		len = m_fixhdr(mdp->md_top);
4554bff34e3Sthurlow 		if (len > dp->ioc_rparamcnt) {
4564bff34e3Sthurlow 			error = EMSGSIZE;
4574bff34e3Sthurlow 			goto bad;
4584bff34e3Sthurlow 		}
4594bff34e3Sthurlow 		dp->ioc_rparamcnt = (ushort_t)len;
4604bff34e3Sthurlow 		error = md_get_mem(mdp, dp->ioc_rparam,
4614bff34e3Sthurlow 		    len, MB_MUSER);
4624bff34e3Sthurlow 		if (error) {
4634bff34e3Sthurlow 			goto bad;
4644bff34e3Sthurlow 		}
4654bff34e3Sthurlow 	} else
4664bff34e3Sthurlow 		dp->ioc_rparamcnt = 0;
4674bff34e3Sthurlow 	mdp = &t2p->t2_rdata;
4684bff34e3Sthurlow 	if (mdp->md_top) {
4694bff34e3Sthurlow 		mblk_t *m = mdp->md_top;
4704bff34e3Sthurlow #ifdef lint
4714bff34e3Sthurlow 		m = m;
4724bff34e3Sthurlow #endif
4734bff34e3Sthurlow 		len = m_fixhdr(mdp->md_top);
4744bff34e3Sthurlow 		if (len > dp->ioc_rdatacnt) {
4754bff34e3Sthurlow 			error = EMSGSIZE;
4764bff34e3Sthurlow 			goto bad;
4774bff34e3Sthurlow 		}
4784bff34e3Sthurlow 		dp->ioc_rdatacnt = (ushort_t)len;
4794bff34e3Sthurlow 		error = md_get_mem(mdp, dp->ioc_rdata,
4804bff34e3Sthurlow 		    len, MB_MUSER);
4814bff34e3Sthurlow 		if (error) {
4824bff34e3Sthurlow 			goto bad;
4834bff34e3Sthurlow 		}
4844bff34e3Sthurlow 	} else
4854bff34e3Sthurlow 		dp->ioc_rdatacnt = 0;
4864bff34e3Sthurlow bad:
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