xref: /illumos-gate/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c (revision 4bff34e37def8a90f9194d81bc345c52ba20086a)
1*4bff34e3Sthurlow /*
2*4bff34e3Sthurlow  * Copyright (c) 2000-2001 Boris Popov
3*4bff34e3Sthurlow  * All rights reserved.
4*4bff34e3Sthurlow  *
5*4bff34e3Sthurlow  * Redistribution and use in source and binary forms, with or without
6*4bff34e3Sthurlow  * modification, are permitted provided that the following conditions
7*4bff34e3Sthurlow  * are met:
8*4bff34e3Sthurlow  * 1. Redistributions of source code must retain the above copyright
9*4bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer.
10*4bff34e3Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
11*4bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer in the
12*4bff34e3Sthurlow  *    documentation and/or other materials provided with the distribution.
13*4bff34e3Sthurlow  * 3. All advertising materials mentioning features or use of this software
14*4bff34e3Sthurlow  *    must display the following acknowledgement:
15*4bff34e3Sthurlow  *    This product includes software developed by Boris Popov.
16*4bff34e3Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
17*4bff34e3Sthurlow  *    may be used to endorse or promote products derived from this software
18*4bff34e3Sthurlow  *    without specific prior written permission.
19*4bff34e3Sthurlow  *
20*4bff34e3Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21*4bff34e3Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22*4bff34e3Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23*4bff34e3Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24*4bff34e3Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25*4bff34e3Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26*4bff34e3Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27*4bff34e3Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28*4bff34e3Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29*4bff34e3Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30*4bff34e3Sthurlow  * SUCH DAMAGE.
31*4bff34e3Sthurlow  *
32*4bff34e3Sthurlow  * $Id: smb_usr.c,v 1.15 2004/12/13 00:25:18 lindak Exp $
33*4bff34e3Sthurlow  */
34*4bff34e3Sthurlow 
35*4bff34e3Sthurlow #pragma ident	"%Z%%M%	%I%	%E% SMI"
36*4bff34e3Sthurlow 
37*4bff34e3Sthurlow #include <sys/param.h>
38*4bff34e3Sthurlow #include <sys/kmem.h>
39*4bff34e3Sthurlow #include <sys/systm.h>
40*4bff34e3Sthurlow #include <sys/policy.h>
41*4bff34e3Sthurlow #include <sys/conf.h>
42*4bff34e3Sthurlow #include <sys/proc.h>
43*4bff34e3Sthurlow #include <sys/fcntl.h>
44*4bff34e3Sthurlow #include <sys/socket.h>
45*4bff34e3Sthurlow #include <sys/cmn_err.h>
46*4bff34e3Sthurlow 
47*4bff34e3Sthurlow #ifdef APPLE
48*4bff34e3Sthurlow #include <sys/smb_apple.h>
49*4bff34e3Sthurlow #include <sys/smb_iconv.h>
50*4bff34e3Sthurlow #else
51*4bff34e3Sthurlow #include <netsmb/smb_osdep.h>
52*4bff34e3Sthurlow #endif
53*4bff34e3Sthurlow 
54*4bff34e3Sthurlow #include <netsmb/smb.h>
55*4bff34e3Sthurlow #include <netsmb/smb_conn.h>
56*4bff34e3Sthurlow #include <netsmb/smb_rq.h>
57*4bff34e3Sthurlow #include <netsmb/smb_subr.h>
58*4bff34e3Sthurlow #include <netsmb/smb_dev.h>
59*4bff34e3Sthurlow 
60*4bff34e3Sthurlow /*
61*4bff34e3Sthurlow  * helpers for nsmb device. Can be moved to the smb_dev.c file.
62*4bff34e3Sthurlow  */
63*4bff34e3Sthurlow static void smb_usr_vcspec_free(struct smb_vcspec *spec);
64*4bff34e3Sthurlow 
65*4bff34e3Sthurlow /*
66*4bff34e3Sthurlow  * Moved the access checks here, just becuase
67*4bff34e3Sthurlow  * this was a more convenient place to do it
68*4bff34e3Sthurlow  * than in every function calling this.
69*4bff34e3Sthurlow  */
70*4bff34e3Sthurlow static int
71*4bff34e3Sthurlow smb_usr_ioc2vcspec(struct smbioc_ossn *dp, struct smb_vcspec *spec)
72*4bff34e3Sthurlow {
73*4bff34e3Sthurlow 	cred_t *cr = CRED();
74*4bff34e3Sthurlow 	uid_t realuid;
75*4bff34e3Sthurlow 
76*4bff34e3Sthurlow 	/*
77*4bff34e3Sthurlow 	 * Only superuser can specify a UID or GID.
78*4bff34e3Sthurlow 	 */
79*4bff34e3Sthurlow 	realuid = crgetruid(cr);
80*4bff34e3Sthurlow 	if (dp->ioc_owner == SMBM_ANY_OWNER)
81*4bff34e3Sthurlow 		spec->owner = realuid;
82*4bff34e3Sthurlow 	else {
83*4bff34e3Sthurlow 		/*
84*4bff34e3Sthurlow 		 * Do we have the privilege to create with the
85*4bff34e3Sthurlow 		 * specified uid?  (does uid == cr->cr_uid, etc.)
86*4bff34e3Sthurlow 		 * MacOS would want suser(), or similar here.
87*4bff34e3Sthurlow 		 */
88*4bff34e3Sthurlow 		if (secpolicy_vnode_owner(cr, dp->ioc_owner))
89*4bff34e3Sthurlow 			return (EPERM);
90*4bff34e3Sthurlow 		spec->owner = dp->ioc_owner;
91*4bff34e3Sthurlow 	}
92*4bff34e3Sthurlow 	if (dp->ioc_group == SMBM_ANY_GROUP)
93*4bff34e3Sthurlow 		spec->group = crgetgid(cr);
94*4bff34e3Sthurlow 	else {
95*4bff34e3Sthurlow 		/*
96*4bff34e3Sthurlow 		 * Do we have the privilege to create with the
97*4bff34e3Sthurlow 		 * specified gid?  (one of our groups?)
98*4bff34e3Sthurlow 		 */
99*4bff34e3Sthurlow 		if (groupmember(dp->ioc_group, cr) ||
100*4bff34e3Sthurlow 		    secpolicy_vnode_create_gid(cr) == 0)
101*4bff34e3Sthurlow 			spec->group = dp->ioc_group;
102*4bff34e3Sthurlow 		else
103*4bff34e3Sthurlow 			return (EPERM);
104*4bff34e3Sthurlow 	}
105*4bff34e3Sthurlow 
106*4bff34e3Sthurlow 	/*
107*4bff34e3Sthurlow 	 * Valid codesets?  XXX
108*4bff34e3Sthurlow 	 */
109*4bff34e3Sthurlow 	if (dp->ioc_localcs[0] == 0) {
110*4bff34e3Sthurlow 		spec->localcs = "ISO8859-1";
111*4bff34e3Sthurlow #ifdef NOTYETRESOLVED
112*4bff34e3Sthurlow 		SMBERROR("no local charset ? dp->ioc_localcs[0]: %d\n",
113*4bff34e3Sthurlow 		    dp->ioc_localcs[0]);
114*4bff34e3Sthurlow 		return (EINVAL);
115*4bff34e3Sthurlow #endif
116*4bff34e3Sthurlow 	} else
117*4bff34e3Sthurlow 		spec->localcs = spec->localcs;
118*4bff34e3Sthurlow 
119*4bff34e3Sthurlow 	/*
120*4bff34e3Sthurlow 	 * Check for valid sa_family.
121*4bff34e3Sthurlow 	 * XXX: Just NetBIOS for now.
122*4bff34e3Sthurlow 	 */
123*4bff34e3Sthurlow 	if (dp->ioc_server.sa.sa_family != AF_NETBIOS)
124*4bff34e3Sthurlow 		return (EINVAL);
125*4bff34e3Sthurlow 	spec->sap = &dp->ioc_server.sa;
126*4bff34e3Sthurlow 
127*4bff34e3Sthurlow 	if (dp->ioc_local.sa.sa_family) {
128*4bff34e3Sthurlow 		/* If specified, local AF must be the same. */
129*4bff34e3Sthurlow 		if (dp->ioc_local.sa.sa_family !=
130*4bff34e3Sthurlow 		    dp->ioc_server.sa.sa_family)
131*4bff34e3Sthurlow 			return (EINVAL);
132*4bff34e3Sthurlow 		spec->lap = &dp->ioc_local.sa;
133*4bff34e3Sthurlow 	}
134*4bff34e3Sthurlow 
135*4bff34e3Sthurlow 	if (dp->ioc_intok) {
136*4bff34e3Sthurlow 		spec->tok = smb_memdupin(dp->ioc_intok, dp->ioc_intoklen);
137*4bff34e3Sthurlow 		if (spec->tok == NULL)
138*4bff34e3Sthurlow 			return (EFAULT);
139*4bff34e3Sthurlow 		spec->toklen = dp->ioc_intoklen;
140*4bff34e3Sthurlow 	}
141*4bff34e3Sthurlow 
142*4bff34e3Sthurlow 	spec->srvname = dp->ioc_srvname;
143*4bff34e3Sthurlow 	spec->pass = dp->ioc_password;
144*4bff34e3Sthurlow 	spec->domain = dp->ioc_workgroup;
145*4bff34e3Sthurlow 	spec->username = dp->ioc_user;
146*4bff34e3Sthurlow 	spec->mode = dp->ioc_mode;
147*4bff34e3Sthurlow 	spec->rights = dp->ioc_rights;
148*4bff34e3Sthurlow 	spec->servercs = dp->ioc_servercs;
149*4bff34e3Sthurlow 	spec->optflags = dp->ioc_opt;
150*4bff34e3Sthurlow 
151*4bff34e3Sthurlow 	return (0);
152*4bff34e3Sthurlow }
153*4bff34e3Sthurlow 
154*4bff34e3Sthurlow static void
155*4bff34e3Sthurlow smb_usr_shspec_free(struct smb_sharespec *sspec)
156*4bff34e3Sthurlow {
157*4bff34e3Sthurlow 	kmem_free(sspec, sizeof (struct smb_sharespec));
158*4bff34e3Sthurlow }
159*4bff34e3Sthurlow 
160*4bff34e3Sthurlow static void
161*4bff34e3Sthurlow smb_usr_vcspec_free(struct smb_vcspec *spec)
162*4bff34e3Sthurlow {
163*4bff34e3Sthurlow 
164*4bff34e3Sthurlow 	if (spec->tok) {
165*4bff34e3Sthurlow 		kmem_free(spec->tok, spec->toklen);
166*4bff34e3Sthurlow 	}
167*4bff34e3Sthurlow 	kmem_free(spec, sizeof (*spec));
168*4bff34e3Sthurlow }
169*4bff34e3Sthurlow 
170*4bff34e3Sthurlow static int
171*4bff34e3Sthurlow smb_usr_ioc2sharespec(struct smbioc_oshare *dp, struct smb_sharespec *spec)
172*4bff34e3Sthurlow {
173*4bff34e3Sthurlow 	bzero(spec, sizeof (*spec));
174*4bff34e3Sthurlow 	spec->name = dp->ioc_share;
175*4bff34e3Sthurlow 	spec->pass = dp->ioc_password;
176*4bff34e3Sthurlow 	spec->mode = dp->ioc_mode;
177*4bff34e3Sthurlow 	spec->rights = dp->ioc_rights;
178*4bff34e3Sthurlow 	spec->owner = dp->ioc_owner;
179*4bff34e3Sthurlow 	spec->group = dp->ioc_group;
180*4bff34e3Sthurlow 	spec->stype = dp->ioc_stype;
181*4bff34e3Sthurlow 	spec->optflags = dp->ioc_opt;
182*4bff34e3Sthurlow 	return (0);
183*4bff34e3Sthurlow }
184*4bff34e3Sthurlow 
185*4bff34e3Sthurlow int
186*4bff34e3Sthurlow smb_usr_negotiate(struct smbioc_lookup *dp, struct smb_cred *scred,
187*4bff34e3Sthurlow 	struct smb_vc **vcpp)
188*4bff34e3Sthurlow {
189*4bff34e3Sthurlow 	struct smb_vc *vcp = NULL;
190*4bff34e3Sthurlow 	struct smb_vcspec *vspec = NULL;
191*4bff34e3Sthurlow 	struct smb_sharespec *sspecp = NULL;
192*4bff34e3Sthurlow 	int error = 0;
193*4bff34e3Sthurlow 
194*4bff34e3Sthurlow 	if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE)
195*4bff34e3Sthurlow 		return (EINVAL);
196*4bff34e3Sthurlow 	vspec = kmem_zalloc(sizeof (struct smb_vcspec), KM_SLEEP);
197*4bff34e3Sthurlow 	error = smb_usr_ioc2vcspec(&dp->ioc_ssn, vspec);
198*4bff34e3Sthurlow 	if (error)
199*4bff34e3Sthurlow 		return (error);
200*4bff34e3Sthurlow 	if (dp->ioc_flags & SMBLK_CREATE)
201*4bff34e3Sthurlow 		vspec->optflags |= SMBVOPT_CREATE;
202*4bff34e3Sthurlow 	if (dp->ioc_level >= SMBL_SHARE) {
203*4bff34e3Sthurlow 		sspecp = kmem_alloc(sizeof (*sspecp), KM_SLEEP);
204*4bff34e3Sthurlow 		error = smb_usr_ioc2sharespec(&dp->ioc_sh, sspecp);
205*4bff34e3Sthurlow 		if (error)
206*4bff34e3Sthurlow 			goto out;
207*4bff34e3Sthurlow 	}
208*4bff34e3Sthurlow 	error = smb_sm_negotiate(vspec, scred, &vcp);
209*4bff34e3Sthurlow 	if (error == 0) {
210*4bff34e3Sthurlow 		*vcpp =  vcp;
211*4bff34e3Sthurlow 		/*
212*4bff34e3Sthurlow 		 * Used to copyout ioc_outtok, outtoklen here,
213*4bff34e3Sthurlow 		 * but that's now in smb_dev. (our caller)
214*4bff34e3Sthurlow 		 *
215*4bff34e3Sthurlow 		 * If this call asked for extended security and
216*4bff34e3Sthurlow 		 * the server does not support it, clear the
217*4bff34e3Sthurlow 		 * flag so the caller knows this.
218*4bff34e3Sthurlow 		 *
219*4bff34e3Sthurlow 		 * XXX: Should just add sv_caps to ioc_ssn,
220*4bff34e3Sthurlow 		 * set the new sv_caps field here, and let
221*4bff34e3Sthurlow 		 * let the copyout of ioc_ssn handle it.
222*4bff34e3Sthurlow 		 */
223*4bff34e3Sthurlow 		if (!(vcp->vc_sopt.sv_caps & SMB_CAP_EXT_SECURITY) &&
224*4bff34e3Sthurlow 		    (dp->ioc_ssn.ioc_opt & SMBVOPT_EXT_SEC)) {
225*4bff34e3Sthurlow 			dp->ioc_ssn.ioc_opt &= ~SMBVOPT_EXT_SEC;
226*4bff34e3Sthurlow 			SMBSDEBUG("turned off extended security");
227*4bff34e3Sthurlow 		}
228*4bff34e3Sthurlow 	}
229*4bff34e3Sthurlow out:
230*4bff34e3Sthurlow 	smb_usr_vcspec_free(vspec);
231*4bff34e3Sthurlow 	smb_usr_shspec_free(sspecp);
232*4bff34e3Sthurlow 	return (error);
233*4bff34e3Sthurlow }
234*4bff34e3Sthurlow 
235*4bff34e3Sthurlow int
236*4bff34e3Sthurlow smb_usr_ssnsetup(struct smbioc_lookup *dp, struct smb_cred *scred,
237*4bff34e3Sthurlow 	struct smb_vc *vcp)
238*4bff34e3Sthurlow {
239*4bff34e3Sthurlow 	struct smb_vcspec *vspec = NULL;
240*4bff34e3Sthurlow 	int error;
241*4bff34e3Sthurlow 
242*4bff34e3Sthurlow 	if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE)
243*4bff34e3Sthurlow 		return (EINVAL);
244*4bff34e3Sthurlow 
245*4bff34e3Sthurlow 	vspec = kmem_zalloc(sizeof (struct smb_vcspec), KM_SLEEP);
246*4bff34e3Sthurlow 	error = smb_usr_ioc2vcspec(&dp->ioc_ssn, vspec);
247*4bff34e3Sthurlow 	if (error)
248*4bff34e3Sthurlow 		goto out;
249*4bff34e3Sthurlow 
250*4bff34e3Sthurlow 	error = smb_sm_ssnsetup(vspec, scred, vcp);
251*4bff34e3Sthurlow 	/*
252*4bff34e3Sthurlow 	 * Moved the copyout of ioc_outtok to
253*4bff34e3Sthurlow 	 * smb_dev.c (our caller)
254*4bff34e3Sthurlow 	 */
255*4bff34e3Sthurlow 
256*4bff34e3Sthurlow out:
257*4bff34e3Sthurlow 	smb_usr_vcspec_free(vspec);
258*4bff34e3Sthurlow 	return (error);
259*4bff34e3Sthurlow }
260*4bff34e3Sthurlow 
261*4bff34e3Sthurlow 
262*4bff34e3Sthurlow int
263*4bff34e3Sthurlow smb_usr_tcon(struct smbioc_lookup *dp, struct smb_cred *scred,
264*4bff34e3Sthurlow 	struct smb_vc *vcp, struct smb_share **sspp)
265*4bff34e3Sthurlow {
266*4bff34e3Sthurlow 	struct smb_sharespec *sspecp = NULL;
267*4bff34e3Sthurlow 	int error;
268*4bff34e3Sthurlow 
269*4bff34e3Sthurlow 	if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE)
270*4bff34e3Sthurlow 		return (EINVAL);
271*4bff34e3Sthurlow 
272*4bff34e3Sthurlow 	if (dp->ioc_level >= SMBL_SHARE) {
273*4bff34e3Sthurlow 		sspecp = kmem_alloc(sizeof (*sspecp), KM_SLEEP);
274*4bff34e3Sthurlow 		error = smb_usr_ioc2sharespec(&dp->ioc_sh, sspecp);
275*4bff34e3Sthurlow 		if (error)
276*4bff34e3Sthurlow 			goto out;
277*4bff34e3Sthurlow 	}
278*4bff34e3Sthurlow 	error = smb_sm_tcon(sspecp, scred, vcp, sspp);
279*4bff34e3Sthurlow 
280*4bff34e3Sthurlow out:
281*4bff34e3Sthurlow 	if (sspecp)
282*4bff34e3Sthurlow 		smb_usr_shspec_free(sspecp);
283*4bff34e3Sthurlow 
284*4bff34e3Sthurlow 	return (error);
285*4bff34e3Sthurlow }
286*4bff34e3Sthurlow 
287*4bff34e3Sthurlow /*
288*4bff34e3Sthurlow  * Connect to the resource specified by smbioc_ossn structure.
289*4bff34e3Sthurlow  * It may either find an existing connection or try to establish a new one.
290*4bff34e3Sthurlow  * If no errors occured smb_vc returned locked and referenced.
291*4bff34e3Sthurlow  */
292*4bff34e3Sthurlow 
293*4bff34e3Sthurlow int
294*4bff34e3Sthurlow smb_usr_simplerequest(struct smb_share *ssp, struct smbioc_rq *dp,
295*4bff34e3Sthurlow 	struct smb_cred *scred)
296*4bff34e3Sthurlow {
297*4bff34e3Sthurlow 	struct smb_rq rq, *rqp = &rq;
298*4bff34e3Sthurlow 	struct mbchain *mbp;
299*4bff34e3Sthurlow 	struct mdchain *mdp;
300*4bff34e3Sthurlow 	char *p;
301*4bff34e3Sthurlow 	size_t wc2;
302*4bff34e3Sthurlow 	u_int8_t wc;
303*4bff34e3Sthurlow 	u_int16_t bc;
304*4bff34e3Sthurlow 	int error;
305*4bff34e3Sthurlow 
306*4bff34e3Sthurlow 	switch (dp->ioc_cmd) {
307*4bff34e3Sthurlow 	case SMB_COM_TRANSACTION2:
308*4bff34e3Sthurlow 	case SMB_COM_TRANSACTION2_SECONDARY:
309*4bff34e3Sthurlow 	case SMB_COM_CLOSE_AND_TREE_DISC:
310*4bff34e3Sthurlow 	case SMB_COM_TREE_CONNECT:
311*4bff34e3Sthurlow 	case SMB_COM_TREE_DISCONNECT:
312*4bff34e3Sthurlow 	case SMB_COM_NEGOTIATE:
313*4bff34e3Sthurlow 	case SMB_COM_SESSION_SETUP_ANDX:
314*4bff34e3Sthurlow 	case SMB_COM_LOGOFF_ANDX:
315*4bff34e3Sthurlow 	case SMB_COM_TREE_CONNECT_ANDX:
316*4bff34e3Sthurlow 		return (EPERM);
317*4bff34e3Sthurlow 	}
318*4bff34e3Sthurlow 	error = smb_rq_init(rqp, SSTOCP(ssp), dp->ioc_cmd, scred);
319*4bff34e3Sthurlow 	if (error)
320*4bff34e3Sthurlow 		return (error);
321*4bff34e3Sthurlow 	mbp = &rqp->sr_rq;
322*4bff34e3Sthurlow 	smb_rq_wstart(rqp);
323*4bff34e3Sthurlow 	error = mb_put_mem(mbp, dp->ioc_twords,
324*4bff34e3Sthurlow 	    dp->ioc_twc * 2, MB_MUSER);
325*4bff34e3Sthurlow 	if (error)
326*4bff34e3Sthurlow 		goto bad;
327*4bff34e3Sthurlow 	smb_rq_wend(rqp);
328*4bff34e3Sthurlow 	smb_rq_bstart(rqp);
329*4bff34e3Sthurlow 	error = mb_put_mem(mbp, dp->ioc_tbytes,
330*4bff34e3Sthurlow 	    dp->ioc_tbc, MB_MUSER);
331*4bff34e3Sthurlow 	if (error)
332*4bff34e3Sthurlow 		goto bad;
333*4bff34e3Sthurlow 	smb_rq_bend(rqp);
334*4bff34e3Sthurlow 	error = smb_rq_simple(rqp);
335*4bff34e3Sthurlow 	if (error)
336*4bff34e3Sthurlow 		goto bad;
337*4bff34e3Sthurlow 	mdp = &rqp->sr_rp;
338*4bff34e3Sthurlow 	md_get_uint8(mdp, &wc);
339*4bff34e3Sthurlow 	dp->ioc_rwc = wc;
340*4bff34e3Sthurlow 	wc2 = wc * 2;
341*4bff34e3Sthurlow 	if (wc2 > dp->ioc_rpbufsz) {
342*4bff34e3Sthurlow 		error = EBADRPC;
343*4bff34e3Sthurlow 		goto bad;
344*4bff34e3Sthurlow 	}
345*4bff34e3Sthurlow 	error = md_get_mem(mdp, dp->ioc_rpbuf, wc2, MB_MUSER);
346*4bff34e3Sthurlow 	if (error)
347*4bff34e3Sthurlow 		goto bad;
348*4bff34e3Sthurlow 	md_get_uint16le(mdp, &bc);
349*4bff34e3Sthurlow 	if ((wc2 + bc) > dp->ioc_rpbufsz) {
350*4bff34e3Sthurlow 		error = EBADRPC;
351*4bff34e3Sthurlow 		goto bad;
352*4bff34e3Sthurlow 	}
353*4bff34e3Sthurlow 	dp->ioc_rbc = bc;
354*4bff34e3Sthurlow 	p = dp->ioc_rpbuf;
355*4bff34e3Sthurlow 	error = md_get_mem(mdp, p + wc2, bc, MB_MUSER);
356*4bff34e3Sthurlow bad:
357*4bff34e3Sthurlow 	dp->ioc_errclass = rqp->sr_errclass;
358*4bff34e3Sthurlow 	dp->ioc_serror = rqp->sr_serror;
359*4bff34e3Sthurlow 	dp->ioc_error = rqp->sr_error;
360*4bff34e3Sthurlow 	smb_rq_done(rqp);
361*4bff34e3Sthurlow 	return (error);
362*4bff34e3Sthurlow 
363*4bff34e3Sthurlow }
364*4bff34e3Sthurlow 
365*4bff34e3Sthurlow static int
366*4bff34e3Sthurlow smb_cpdatain(struct mbchain *mbp, int len, char *data)
367*4bff34e3Sthurlow {
368*4bff34e3Sthurlow 	int error;
369*4bff34e3Sthurlow 
370*4bff34e3Sthurlow 	if (len == 0)
371*4bff34e3Sthurlow 		return (0);
372*4bff34e3Sthurlow 	error = mb_init(mbp);
373*4bff34e3Sthurlow 	if (error)
374*4bff34e3Sthurlow 		return (error);
375*4bff34e3Sthurlow 	return (mb_put_mem(mbp, data, len, MB_MUSER));
376*4bff34e3Sthurlow }
377*4bff34e3Sthurlow 
378*4bff34e3Sthurlow int
379*4bff34e3Sthurlow smb_usr_t2request(struct smb_share *ssp, smbioc_t2rq_t *dp,
380*4bff34e3Sthurlow 	struct smb_cred *scred)
381*4bff34e3Sthurlow {
382*4bff34e3Sthurlow 	struct smb_t2rq t2, *t2p = &t2;
383*4bff34e3Sthurlow 	struct mdchain *mdp;
384*4bff34e3Sthurlow 	int error, len;
385*4bff34e3Sthurlow 
386*4bff34e3Sthurlow 	if (dp->ioc_setupcnt > SMB_MAXSETUPWORDS)
387*4bff34e3Sthurlow 		return (EINVAL);
388*4bff34e3Sthurlow 
389*4bff34e3Sthurlow 	t2p = (struct smb_t2rq *)kmem_alloc(sizeof (struct smb_t2rq), KM_SLEEP);
390*4bff34e3Sthurlow 	if (t2p == NULL)
391*4bff34e3Sthurlow 		return (ENOMEM);
392*4bff34e3Sthurlow 	error = smb_t2_init(t2p, SSTOCP(ssp), dp->ioc_setup, dp->ioc_setupcnt,
393*4bff34e3Sthurlow 	    scred);
394*4bff34e3Sthurlow 	if (error)
395*4bff34e3Sthurlow 		return (error);
396*4bff34e3Sthurlow 	len = t2p->t2_setupcount = dp->ioc_setupcnt;
397*4bff34e3Sthurlow 	if (len > 1)
398*4bff34e3Sthurlow 		t2p->t2_setupdata = dp->ioc_setup;
399*4bff34e3Sthurlow 	if (dp->ioc_name) {
400*4bff34e3Sthurlow 		bcopy(dp->ioc_name, t2p->t_name, 128);
401*4bff34e3Sthurlow 		if (t2p->t_name == NULL) {
402*4bff34e3Sthurlow 			error = ENOMEM;
403*4bff34e3Sthurlow 			goto bad;
404*4bff34e3Sthurlow 		}
405*4bff34e3Sthurlow 	}
406*4bff34e3Sthurlow 	t2p->t2_maxscount = 0;
407*4bff34e3Sthurlow 	t2p->t2_maxpcount = dp->ioc_rparamcnt;
408*4bff34e3Sthurlow 	t2p->t2_maxdcount = dp->ioc_rdatacnt;
409*4bff34e3Sthurlow 	error = smb_cpdatain(&t2p->t2_tparam, dp->ioc_tparamcnt,
410*4bff34e3Sthurlow 	    dp->ioc_tparam);
411*4bff34e3Sthurlow 	if (error)
412*4bff34e3Sthurlow 		goto bad;
413*4bff34e3Sthurlow 	error = smb_cpdatain(&t2p->t2_tdata,
414*4bff34e3Sthurlow 	    dp->ioc_tdatacnt, dp->ioc_tdata);
415*4bff34e3Sthurlow 	if (error)
416*4bff34e3Sthurlow 		goto bad;
417*4bff34e3Sthurlow 	error = smb_t2_request(t2p);
418*4bff34e3Sthurlow 	dp->ioc_errclass = t2p->t2_sr_errclass;
419*4bff34e3Sthurlow 	dp->ioc_serror = t2p->t2_sr_serror;
420*4bff34e3Sthurlow 	dp->ioc_error = t2p->t2_sr_error;
421*4bff34e3Sthurlow 	dp->ioc_rpflags2 = t2p->t2_sr_rpflags2;
422*4bff34e3Sthurlow 	if (error)
423*4bff34e3Sthurlow 		goto bad;
424*4bff34e3Sthurlow 	mdp = &t2p->t2_rparam;
425*4bff34e3Sthurlow 	if (mdp->md_top) {
426*4bff34e3Sthurlow 		mblk_t *m = mdp->md_top;
427*4bff34e3Sthurlow #ifdef lint
428*4bff34e3Sthurlow 		m = m;
429*4bff34e3Sthurlow #endif
430*4bff34e3Sthurlow 		len = m_fixhdr(mdp->md_top);
431*4bff34e3Sthurlow 		if (len > dp->ioc_rparamcnt) {
432*4bff34e3Sthurlow 			error = EMSGSIZE;
433*4bff34e3Sthurlow 			goto bad;
434*4bff34e3Sthurlow 		}
435*4bff34e3Sthurlow 		dp->ioc_rparamcnt = (ushort_t)len;
436*4bff34e3Sthurlow 		error = md_get_mem(mdp, dp->ioc_rparam,
437*4bff34e3Sthurlow 		    len, MB_MUSER);
438*4bff34e3Sthurlow 		if (error) {
439*4bff34e3Sthurlow 			goto bad;
440*4bff34e3Sthurlow 		}
441*4bff34e3Sthurlow 	} else
442*4bff34e3Sthurlow 		dp->ioc_rparamcnt = 0;
443*4bff34e3Sthurlow 	mdp = &t2p->t2_rdata;
444*4bff34e3Sthurlow 	if (mdp->md_top) {
445*4bff34e3Sthurlow 		mblk_t *m = mdp->md_top;
446*4bff34e3Sthurlow #ifdef lint
447*4bff34e3Sthurlow 		m = m;
448*4bff34e3Sthurlow #endif
449*4bff34e3Sthurlow 		len = m_fixhdr(mdp->md_top);
450*4bff34e3Sthurlow 		if (len > dp->ioc_rdatacnt) {
451*4bff34e3Sthurlow 			error = EMSGSIZE;
452*4bff34e3Sthurlow 			goto bad;
453*4bff34e3Sthurlow 		}
454*4bff34e3Sthurlow 		dp->ioc_rdatacnt = (ushort_t)len;
455*4bff34e3Sthurlow 		error = md_get_mem(mdp, dp->ioc_rdata,
456*4bff34e3Sthurlow 		    len, MB_MUSER);
457*4bff34e3Sthurlow 		if (error) {
458*4bff34e3Sthurlow 			goto bad;
459*4bff34e3Sthurlow 		}
460*4bff34e3Sthurlow 	} else
461*4bff34e3Sthurlow 		dp->ioc_rdatacnt = 0;
462*4bff34e3Sthurlow bad:
463*4bff34e3Sthurlow 	smb_t2_done(t2p);
464*4bff34e3Sthurlow 	return (error);
465*4bff34e3Sthurlow }
466*4bff34e3Sthurlow 
467*4bff34e3Sthurlow /*
468*4bff34e3Sthurlow  * Helper for nsmb_ioctl cases
469*4bff34e3Sthurlow  * SMBIOC_READ, SMBIOC_WRITE
470*4bff34e3Sthurlow  */
471*4bff34e3Sthurlow int
472*4bff34e3Sthurlow smb_usr_rw(struct smb_share *ssp, smbioc_rw_t *rwrq,
473*4bff34e3Sthurlow     int cmd, struct smb_cred *scred)
474*4bff34e3Sthurlow {
475*4bff34e3Sthurlow 	struct iovec aiov[1];
476*4bff34e3Sthurlow 	struct uio  auio;
477*4bff34e3Sthurlow 	u_int16_t fh;
478*4bff34e3Sthurlow 	int error;
479*4bff34e3Sthurlow 	uio_rw_t rw;
480*4bff34e3Sthurlow 
481*4bff34e3Sthurlow 	switch (cmd) {
482*4bff34e3Sthurlow 	case SMBIOC_READ:
483*4bff34e3Sthurlow 		rw = UIO_READ;
484*4bff34e3Sthurlow 		break;
485*4bff34e3Sthurlow 	case SMBIOC_WRITE:
486*4bff34e3Sthurlow 		rw = UIO_WRITE;
487*4bff34e3Sthurlow 		break;
488*4bff34e3Sthurlow 	default:
489*4bff34e3Sthurlow 		return (ENODEV);
490*4bff34e3Sthurlow 	}
491*4bff34e3Sthurlow 
492*4bff34e3Sthurlow 	fh = htoles(rwrq->ioc_fh);
493*4bff34e3Sthurlow 
494*4bff34e3Sthurlow 	aiov[0].iov_base = rwrq->ioc_base;
495*4bff34e3Sthurlow 	aiov[0].iov_len = (size_t)rwrq->ioc_cnt;
496*4bff34e3Sthurlow 
497*4bff34e3Sthurlow 	auio.uio_iov = aiov;
498*4bff34e3Sthurlow 	auio.uio_iovcnt = 1;
499*4bff34e3Sthurlow 	auio.uio_loffset = rwrq->ioc_offset;
500*4bff34e3Sthurlow 	auio.uio_segflg = UIO_USERSPACE;
501*4bff34e3Sthurlow 	auio.uio_fmode = 0;
502*4bff34e3Sthurlow 	auio.uio_resid = (size_t)rwrq->ioc_cnt;
503*4bff34e3Sthurlow 
504*4bff34e3Sthurlow 	error = smb_rwuio(ssp, fh, rw, &auio, scred, 0);
505*4bff34e3Sthurlow 
506*4bff34e3Sthurlow 	/*
507*4bff34e3Sthurlow 	 * On return ioc_cnt holds the
508*4bff34e3Sthurlow 	 * number of bytes transferred.
509*4bff34e3Sthurlow 	 */
510*4bff34e3Sthurlow 	rwrq->ioc_cnt -= auio.uio_resid;
511*4bff34e3Sthurlow 
512*4bff34e3Sthurlow 	return (error);
513*4bff34e3Sthurlow }
514