xref: /onnv-gate/usr/src/lib/libsmbfs/smb/rq.c (revision 11332:ed3411181494)
16007Sthurlow /*
26007Sthurlow  * Copyright (c) 2000, Boris Popov
36007Sthurlow  * All rights reserved.
46007Sthurlow  *
56007Sthurlow  * Redistribution and use in source and binary forms, with or without
66007Sthurlow  * modification, are permitted provided that the following conditions
76007Sthurlow  * are met:
86007Sthurlow  * 1. Redistributions of source code must retain the above copyright
96007Sthurlow  *    notice, this list of conditions and the following disclaimer.
106007Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
116007Sthurlow  *    notice, this list of conditions and the following disclaimer in the
126007Sthurlow  *    documentation and/or other materials provided with the distribution.
136007Sthurlow  * 3. All advertising materials mentioning features or use of this software
146007Sthurlow  *    must display the following acknowledgement:
156007Sthurlow  *    This product includes software developed by Boris Popov.
166007Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
176007Sthurlow  *    may be used to endorse or promote products derived from this software
186007Sthurlow  *    without specific prior written permission.
196007Sthurlow  *
206007Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
216007Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
226007Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
236007Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
246007Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
256007Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
266007Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
276007Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
286007Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
296007Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
306007Sthurlow  * SUCH DAMAGE.
316007Sthurlow  *
326007Sthurlow  * $Id: rq.c,v 1.4 2004/12/13 00:25:23 lindak Exp $
336007Sthurlow  */
346007Sthurlow 
356007Sthurlow #include <sys/types.h>
366007Sthurlow #include <sys/param.h>
376007Sthurlow #include <sys/ioctl.h>
386007Sthurlow #include <sys/errno.h>
396007Sthurlow #include <sys/stat.h>
406007Sthurlow 
416007Sthurlow #include <ctype.h>
426007Sthurlow #include <errno.h>
436007Sthurlow #include <stdio.h>
446007Sthurlow #include <unistd.h>
456007Sthurlow #include <strings.h>
466007Sthurlow #include <stdlib.h>
476007Sthurlow #include <sysexits.h>
486007Sthurlow #include <libintl.h>
496007Sthurlow 
5010023SGordon.Ross@Sun.COM #include <netsmb/smb.h>
516007Sthurlow #include <netsmb/smb_lib.h>
528271SGordon.Ross@Sun.COM #include "private.h"
536007Sthurlow 
54*11332SGordon.Ross@Sun.COM #define	MIN_REPLY_SIZE 4096
55*11332SGordon.Ross@Sun.COM 
5610023SGordon.Ross@Sun.COM static uint32_t smb_map_doserr(uint8_t, uint16_t);
576007Sthurlow 
5810023SGordon.Ross@Sun.COM /*
5910023SGordon.Ross@Sun.COM  * Create and initialize a request structure, for either an
6010023SGordon.Ross@Sun.COM  * "internal" request (one that does not use the driver) or
6110023SGordon.Ross@Sun.COM  * a regular "driver" request, that uses driver ioctls.
6210023SGordon.Ross@Sun.COM  *
6310023SGordon.Ross@Sun.COM  * The two kinds are built a little differently:
6410023SGordon.Ross@Sun.COM  * Driver requests are composed starting with the
6510023SGordon.Ross@Sun.COM  * first word of the "variable word vector" section.
6610023SGordon.Ross@Sun.COM  * The driver prepends the SMB header and word count.
6710023SGordon.Ross@Sun.COM  * The driver also needs an output buffer to receive
6810023SGordon.Ross@Sun.COM  * the response, filled in via copyout in the ioctl.
6910023SGordon.Ross@Sun.COM  *
7010023SGordon.Ross@Sun.COM  * Internal requests are composed entirely in this library.
7110023SGordon.Ross@Sun.COM  * Space for the SMB header is reserved here, and later
7210023SGordon.Ross@Sun.COM  * filled in by smb_rq_internal before the send/receive.
7310023SGordon.Ross@Sun.COM  */
746007Sthurlow int
smb_rq_init(struct smb_ctx * ctx,uchar_t cmd,struct smb_rq ** rqpp)7510023SGordon.Ross@Sun.COM smb_rq_init(struct smb_ctx *ctx, uchar_t cmd, struct smb_rq **rqpp)
766007Sthurlow {
776007Sthurlow 	struct smb_rq *rqp;
786007Sthurlow 
796007Sthurlow 	rqp = malloc(sizeof (*rqp));
806007Sthurlow 	if (rqp == NULL)
8110023SGordon.Ross@Sun.COM 		goto errout;
826007Sthurlow 	bzero(rqp, sizeof (*rqp));
836007Sthurlow 	rqp->rq_cmd = cmd;
846007Sthurlow 	rqp->rq_ctx = ctx;
8510023SGordon.Ross@Sun.COM 
8610023SGordon.Ross@Sun.COM 	/*
8710023SGordon.Ross@Sun.COM 	 * Setup the request buffer.
8810023SGordon.Ross@Sun.COM 	 * Do the reply buffer later.
8910023SGordon.Ross@Sun.COM 	 */
90*11332SGordon.Ross@Sun.COM 	if (mb_init(&rqp->rq_rq))
9110023SGordon.Ross@Sun.COM 		goto errout;
9210023SGordon.Ross@Sun.COM 
9310023SGordon.Ross@Sun.COM 	/* Space for the SMB header. (filled in later) */
94*11332SGordon.Ross@Sun.COM 	mb_put_mem(&rqp->rq_rq, NULL, SMB_HDRLEN, MB_MSYSTEM);
9510023SGordon.Ross@Sun.COM 
9610023SGordon.Ross@Sun.COM 	/*
9710023SGordon.Ross@Sun.COM 	 * Copy the ctx flags here, so the caller can
9810023SGordon.Ross@Sun.COM 	 * update the req flags before the OTW call.
9910023SGordon.Ross@Sun.COM 	 */
10010023SGordon.Ross@Sun.COM 	rqp->rq_hflags = ctx->ct_hflags;
10110023SGordon.Ross@Sun.COM 	rqp->rq_hflags2 = ctx->ct_hflags2;
10210023SGordon.Ross@Sun.COM 
1036007Sthurlow 	*rqpp = rqp;
1046007Sthurlow 	return (0);
10510023SGordon.Ross@Sun.COM 
10610023SGordon.Ross@Sun.COM errout:
10710023SGordon.Ross@Sun.COM 	if (rqp) {
10810023SGordon.Ross@Sun.COM 		smb_rq_done(rqp);
10910023SGordon.Ross@Sun.COM 		free(rqp);
11010023SGordon.Ross@Sun.COM 	}
11110023SGordon.Ross@Sun.COM 	return (ENOMEM);
1126007Sthurlow }
1136007Sthurlow 
1146007Sthurlow void
smb_rq_done(struct smb_rq * rqp)1156007Sthurlow smb_rq_done(struct smb_rq *rqp)
1166007Sthurlow {
1176007Sthurlow 	mb_done(&rqp->rq_rp);
1186007Sthurlow 	mb_done(&rqp->rq_rq);
1196007Sthurlow 	free(rqp);
1206007Sthurlow }
1216007Sthurlow 
12210023SGordon.Ross@Sun.COM /*
12310023SGordon.Ross@Sun.COM  * Reserve space for the word count, which is filled in later by
12410023SGordon.Ross@Sun.COM  * smb_rq_wend().  Also initialize the counter that it uses
12510023SGordon.Ross@Sun.COM  * to figure out what value to fill in.
12610023SGordon.Ross@Sun.COM  *
12710023SGordon.Ross@Sun.COM  * Note that the word count happens to be 8-bits,
12810023SGordon.Ross@Sun.COM  * which can lead to confusion.
12910023SGordon.Ross@Sun.COM  */
13010023SGordon.Ross@Sun.COM void
smb_rq_wstart(struct smb_rq * rqp)13110023SGordon.Ross@Sun.COM smb_rq_wstart(struct smb_rq *rqp)
13210023SGordon.Ross@Sun.COM {
13310023SGordon.Ross@Sun.COM 	struct mbdata *mbp = &rqp->rq_rq;
13410023SGordon.Ross@Sun.COM 
135*11332SGordon.Ross@Sun.COM 	(void) mb_fit(mbp, 1, &rqp->rq_wcntp);
13610023SGordon.Ross@Sun.COM 	rqp->rq_wcbase = mbp->mb_count;
13710023SGordon.Ross@Sun.COM }
13810023SGordon.Ross@Sun.COM 
13910023SGordon.Ross@Sun.COM /*
14010023SGordon.Ross@Sun.COM  * Fill in the word count, in the space reserved by
14110023SGordon.Ross@Sun.COM  * smb_rq_wstart().
14210023SGordon.Ross@Sun.COM  */
1436007Sthurlow void
smb_rq_wend(struct smb_rq * rqp)1446007Sthurlow smb_rq_wend(struct smb_rq *rqp)
1456007Sthurlow {
14610023SGordon.Ross@Sun.COM 	struct mbdata *mbp = &rqp->rq_rq;
14710023SGordon.Ross@Sun.COM 	int wcnt;
14810023SGordon.Ross@Sun.COM 
14910023SGordon.Ross@Sun.COM 	if (rqp->rq_wcntp == NULL) {
15010023SGordon.Ross@Sun.COM 		DPRINT("no wcount ptr\n");
15110023SGordon.Ross@Sun.COM 		return;
15210023SGordon.Ross@Sun.COM 	}
15310023SGordon.Ross@Sun.COM 	wcnt = mbp->mb_count - rqp->rq_wcbase;
15410023SGordon.Ross@Sun.COM 	if (wcnt > 0x1ff)
15510023SGordon.Ross@Sun.COM 		DPRINT("word count too large (%d)\n", wcnt);
15610023SGordon.Ross@Sun.COM 	if (wcnt & 1)
15710023SGordon.Ross@Sun.COM 		DPRINT("odd word count\n");
15810023SGordon.Ross@Sun.COM 	wcnt >>= 1;
15910023SGordon.Ross@Sun.COM 
16010023SGordon.Ross@Sun.COM 	/*
16110023SGordon.Ross@Sun.COM 	 * Fill in the word count (8-bits).
16210023SGordon.Ross@Sun.COM 	 * Also store it in the rq, in case
16310023SGordon.Ross@Sun.COM 	 * we're using the ioctl path.
16410023SGordon.Ross@Sun.COM 	 */
16510023SGordon.Ross@Sun.COM 	*rqp->rq_wcntp = (char)wcnt;
1666007Sthurlow }
1676007Sthurlow 
16810023SGordon.Ross@Sun.COM /*
16910023SGordon.Ross@Sun.COM  * Reserve space for the byte count, which is filled in later by
17010023SGordon.Ross@Sun.COM  * smb_rq_bend().  Also initialize the counter that it uses
17110023SGordon.Ross@Sun.COM  * to figure out what value to fill in.
17210023SGordon.Ross@Sun.COM  *
17310023SGordon.Ross@Sun.COM  * Note that the byte count happens to be 16-bits,
17410023SGordon.Ross@Sun.COM  * which can lead to confusion.
17510023SGordon.Ross@Sun.COM  */
17610023SGordon.Ross@Sun.COM void
smb_rq_bstart(struct smb_rq * rqp)17710023SGordon.Ross@Sun.COM smb_rq_bstart(struct smb_rq *rqp)
1786007Sthurlow {
17910023SGordon.Ross@Sun.COM 	struct mbdata *mbp = &rqp->rq_rq;
1806007Sthurlow 
181*11332SGordon.Ross@Sun.COM 	(void) mb_fit(mbp, 2, &rqp->rq_bcntp);
18210023SGordon.Ross@Sun.COM 	rqp->rq_bcbase = mbp->mb_count;
1836007Sthurlow }
1846007Sthurlow 
18510023SGordon.Ross@Sun.COM /*
18610023SGordon.Ross@Sun.COM  * Fill in the byte count, in the space reserved by
18710023SGordon.Ross@Sun.COM  * smb_rq_bstart().
18810023SGordon.Ross@Sun.COM  */
18910023SGordon.Ross@Sun.COM void
smb_rq_bend(struct smb_rq * rqp)19010023SGordon.Ross@Sun.COM smb_rq_bend(struct smb_rq *rqp)
1916007Sthurlow {
19210023SGordon.Ross@Sun.COM 	struct mbdata *mbp = &rqp->rq_rq;
19310023SGordon.Ross@Sun.COM 	int bcnt;
19410023SGordon.Ross@Sun.COM 
19510023SGordon.Ross@Sun.COM 	if (rqp->rq_bcntp == NULL) {
19610023SGordon.Ross@Sun.COM 		DPRINT("no bcount ptr\n");
19710023SGordon.Ross@Sun.COM 		return;
19810023SGordon.Ross@Sun.COM 	}
19910023SGordon.Ross@Sun.COM 	bcnt = mbp->mb_count - rqp->rq_bcbase;
20010023SGordon.Ross@Sun.COM 	if (bcnt > 0xffff)
20110023SGordon.Ross@Sun.COM 		DPRINT("byte count too large (%d)\n", bcnt);
20210023SGordon.Ross@Sun.COM 	/*
20310023SGordon.Ross@Sun.COM 	 * Fill in the byte count (16-bits).
20410023SGordon.Ross@Sun.COM 	 * Also store it in the rq, in case
20510023SGordon.Ross@Sun.COM 	 * we're using the ioctl path.
20610023SGordon.Ross@Sun.COM 	 *
20710023SGordon.Ross@Sun.COM 	 * The pointer is char * type due to
20810023SGordon.Ross@Sun.COM 	 * typical off-by-one alignment.
20910023SGordon.Ross@Sun.COM 	 */
21010023SGordon.Ross@Sun.COM 	rqp->rq_bcntp[0] = bcnt & 0xFF;
21110023SGordon.Ross@Sun.COM 	rqp->rq_bcntp[1] = (bcnt >> 8);
2126007Sthurlow }
2136007Sthurlow 
2146007Sthurlow int
smb_rq_simple(struct smb_rq * rqp)2156007Sthurlow smb_rq_simple(struct smb_rq *rqp)
2166007Sthurlow {
2176007Sthurlow 	struct smbioc_rq krq;
2186007Sthurlow 	struct mbdata *mbp;
219*11332SGordon.Ross@Sun.COM 	mbuf_t *m;
2206007Sthurlow 	char *data;
22110023SGordon.Ross@Sun.COM 	uint32_t len;
22210023SGordon.Ross@Sun.COM 	size_t rpbufsz;
223*11332SGordon.Ross@Sun.COM 	int error;
2246007Sthurlow 
22510023SGordon.Ross@Sun.COM 	bzero(&krq, sizeof (krq));
22610023SGordon.Ross@Sun.COM 	krq.ioc_cmd = rqp->rq_cmd;
22710023SGordon.Ross@Sun.COM 
22810023SGordon.Ross@Sun.COM 	/*
22910023SGordon.Ross@Sun.COM 	 * Make the SMB request body contiguous,
23010023SGordon.Ross@Sun.COM 	 * and fill in the ioctl request.
23110023SGordon.Ross@Sun.COM 	 */
2326007Sthurlow 	mbp = smb_rq_getrequest(rqp);
233*11332SGordon.Ross@Sun.COM 	error = m_lineup(mbp->mb_top, &mbp->mb_top);
234*11332SGordon.Ross@Sun.COM 	if (error)
235*11332SGordon.Ross@Sun.COM 		return (error);
236*11332SGordon.Ross@Sun.COM 
2376007Sthurlow 	data = mtod(mbp->mb_top, char *);
23810023SGordon.Ross@Sun.COM 	len = m_totlen(mbp->mb_top);
2396007Sthurlow 
24010023SGordon.Ross@Sun.COM 	/*
24110023SGordon.Ross@Sun.COM 	 * _rq_init left space for the SMB header,
24210023SGordon.Ross@Sun.COM 	 * which makes mb_count the offset from
24310023SGordon.Ross@Sun.COM 	 * the beginning of the header (useful).
24410023SGordon.Ross@Sun.COM 	 * However, in this code path the driver
24510023SGordon.Ross@Sun.COM 	 * prepends the header, so we skip it.
24610023SGordon.Ross@Sun.COM 	 */
24710023SGordon.Ross@Sun.COM 	krq.ioc_tbufsz = len - SMB_HDRLEN;
24810023SGordon.Ross@Sun.COM 	krq.ioc_tbuf  = data + SMB_HDRLEN;
24910023SGordon.Ross@Sun.COM 
25010023SGordon.Ross@Sun.COM 	/*
251*11332SGordon.Ross@Sun.COM 	 * Setup a buffer to hold the reply,
252*11332SGordon.Ross@Sun.COM 	 * at least MIN_REPLY_SIZE, or larger
253*11332SGordon.Ross@Sun.COM 	 * if the caller increased rq_rpbufsz.
25410023SGordon.Ross@Sun.COM 	 */
2556007Sthurlow 	mbp = smb_rq_getreply(rqp);
25610023SGordon.Ross@Sun.COM 	rpbufsz = rqp->rq_rpbufsz;
257*11332SGordon.Ross@Sun.COM 	if (rpbufsz < MIN_REPLY_SIZE)
258*11332SGordon.Ross@Sun.COM 		rpbufsz = MIN_REPLY_SIZE;
259*11332SGordon.Ross@Sun.COM 	if ((error = m_get(rpbufsz, &m)) != 0)
260*11332SGordon.Ross@Sun.COM 		return (error);
261*11332SGordon.Ross@Sun.COM 	mb_initm(mbp, m);
26210023SGordon.Ross@Sun.COM 	krq.ioc_rbufsz = rpbufsz;
263*11332SGordon.Ross@Sun.COM 	krq.ioc_rbuf = mtod(m, char *);
26410023SGordon.Ross@Sun.COM 
26510023SGordon.Ross@Sun.COM 	/*
26610023SGordon.Ross@Sun.COM 	 * Call the driver
26710023SGordon.Ross@Sun.COM 	 */
26810023SGordon.Ross@Sun.COM 	if (ioctl(rqp->rq_ctx->ct_dev_fd, SMBIOC_REQUEST, &krq) == -1)
2696007Sthurlow 		return (errno);
27010023SGordon.Ross@Sun.COM 
27110023SGordon.Ross@Sun.COM 	/*
27210023SGordon.Ross@Sun.COM 	 * Initialize returned mbdata.
27310023SGordon.Ross@Sun.COM 	 * SMB header already parsed.
27410023SGordon.Ross@Sun.COM 	 */
275*11332SGordon.Ross@Sun.COM 	m->m_len = krq.ioc_rbufsz;
27610023SGordon.Ross@Sun.COM 
2776007Sthurlow 	return (0);
2786007Sthurlow }
2796007Sthurlow 
2806007Sthurlow 
2816007Sthurlow int
smb_t2_request(struct smb_ctx * ctx,int setupcount,uint16_t * setup,const char * name,int tparamcnt,void * tparam,int tdatacnt,void * tdata,int * rparamcnt,void * rparam,int * rdatacnt,void * rdata,int * buffer_oflow)2826007Sthurlow smb_t2_request(struct smb_ctx *ctx, int setupcount, uint16_t *setup,
2836007Sthurlow 	const char *name,
2846007Sthurlow 	int tparamcnt, void *tparam,
2856007Sthurlow 	int tdatacnt, void *tdata,
2866007Sthurlow 	int *rparamcnt, void *rparam,
2876007Sthurlow 	int *rdatacnt, void *rdata,
2886007Sthurlow 	int *buffer_oflow)
2896007Sthurlow {
2906007Sthurlow 	smbioc_t2rq_t *krq;
2916007Sthurlow 	int i;
2926007Sthurlow 
2936007Sthurlow 	krq = (smbioc_t2rq_t *)malloc(sizeof (smbioc_t2rq_t));
2946007Sthurlow 	bzero(krq, sizeof (*krq));
2956007Sthurlow 
29610023SGordon.Ross@Sun.COM 	if (setupcount < 0 || setupcount >= SMBIOC_T2RQ_MAXSETUP) {
2976007Sthurlow 		/* Bogus setup count, or too many setup words */
2986007Sthurlow 		return (EINVAL);
2996007Sthurlow 	}
3006007Sthurlow 	for (i = 0; i < setupcount; i++)
3016007Sthurlow 		krq->ioc_setup[i] = setup[i];
3026007Sthurlow 	krq->ioc_setupcnt = setupcount;
3036007Sthurlow 	strcpy(krq->ioc_name, name);
3046007Sthurlow 	krq->ioc_tparamcnt = tparamcnt;
3056007Sthurlow 	krq->ioc_tparam = tparam;
3066007Sthurlow 	krq->ioc_tdatacnt = tdatacnt;
3076007Sthurlow 	krq->ioc_tdata = tdata;
3086007Sthurlow 
3096007Sthurlow 	krq->ioc_rparamcnt = *rparamcnt;
3106007Sthurlow 	krq->ioc_rdatacnt = *rdatacnt;
3116007Sthurlow 	krq->ioc_rparam = rparam;
3126007Sthurlow 	krq->ioc_rdata  = rdata;
3136007Sthurlow 
31410023SGordon.Ross@Sun.COM 	if (ioctl(ctx->ct_dev_fd, SMBIOC_T2RQ, krq) == -1) {
3156007Sthurlow 		return (errno);
3166007Sthurlow 	}
3176007Sthurlow 
3186007Sthurlow 	*rparamcnt = krq->ioc_rparamcnt;
3196007Sthurlow 	*rdatacnt = krq->ioc_rdatacnt;
3206007Sthurlow 	*buffer_oflow = (krq->ioc_rpflags2 & SMB_FLAGS2_ERR_STATUS) &&
3216007Sthurlow 	    (krq->ioc_error == NT_STATUS_BUFFER_OVERFLOW);
3226007Sthurlow 	free(krq);
32310023SGordon.Ross@Sun.COM 
3246007Sthurlow 	return (0);
3256007Sthurlow }
32610023SGordon.Ross@Sun.COM 
32710023SGordon.Ross@Sun.COM 
32810023SGordon.Ross@Sun.COM /*
32910023SGordon.Ross@Sun.COM  * Do an over-the-wire call without using the nsmb driver.
33010023SGordon.Ross@Sun.COM  * This is all "internal" to this library, and used only
33110023SGordon.Ross@Sun.COM  * for connection setup (negotiate protocol, etc.)
33210023SGordon.Ross@Sun.COM  */
33310023SGordon.Ross@Sun.COM int
smb_rq_internal(struct smb_ctx * ctx,struct smb_rq * rqp)33410023SGordon.Ross@Sun.COM smb_rq_internal(struct smb_ctx *ctx, struct smb_rq *rqp)
33510023SGordon.Ross@Sun.COM {
33610023SGordon.Ross@Sun.COM 	static const uint8_t ffsmb[4] = SMB_SIGNATURE;
33710023SGordon.Ross@Sun.COM 	struct smb_iods *is = &ctx->ct_iods;
33810023SGordon.Ross@Sun.COM 	uint32_t sigbuf[2];
33910023SGordon.Ross@Sun.COM 	struct mbdata mbtmp, *mbp;
34010023SGordon.Ross@Sun.COM 	int err, save_mlen;
34110023SGordon.Ross@Sun.COM 	uint8_t ctmp;
34210023SGordon.Ross@Sun.COM 
34310023SGordon.Ross@Sun.COM 	rqp->rq_uid = is->is_smbuid;
34410023SGordon.Ross@Sun.COM 	rqp->rq_tid = SMB_TID_UNKNOWN;
34510023SGordon.Ross@Sun.COM 	rqp->rq_mid = is->is_next_mid++;
34610023SGordon.Ross@Sun.COM 
34710023SGordon.Ross@Sun.COM 	/*
34810023SGordon.Ross@Sun.COM 	 * Fill in the NBT and SMB headers
34910023SGordon.Ross@Sun.COM 	 * Using mbtmp so we can rewind without
35010023SGordon.Ross@Sun.COM 	 * affecting the passed request mbdata.
35110023SGordon.Ross@Sun.COM 	 */
35210023SGordon.Ross@Sun.COM 	bcopy(&rqp->rq_rq, &mbtmp, sizeof (mbtmp));
35310023SGordon.Ross@Sun.COM 	mbp = &mbtmp;
35410023SGordon.Ross@Sun.COM 	mbp->mb_cur = mbp->mb_top;
35510023SGordon.Ross@Sun.COM 	mbp->mb_pos = mbp->mb_cur->m_data;
35610023SGordon.Ross@Sun.COM 	mbp->mb_count = 0;
35710023SGordon.Ross@Sun.COM 	/* Have to save and restore m_len */
35810023SGordon.Ross@Sun.COM 	save_mlen = mbp->mb_cur->m_len;
35910023SGordon.Ross@Sun.COM 	mbp->mb_cur->m_len = 0;
36010023SGordon.Ross@Sun.COM 
36110023SGordon.Ross@Sun.COM 	/*
36210023SGordon.Ross@Sun.COM 	 * rewind done; fill it in
36310023SGordon.Ross@Sun.COM 	 */
364*11332SGordon.Ross@Sun.COM 	mb_put_mem(mbp, ffsmb, SMB_SIGLEN, MB_MSYSTEM);
36510023SGordon.Ross@Sun.COM 	mb_put_uint8(mbp, rqp->rq_cmd);
366*11332SGordon.Ross@Sun.COM 	mb_put_uint32le(mbp, 0);	/* status */
36710023SGordon.Ross@Sun.COM 	mb_put_uint8(mbp, rqp->rq_hflags);
36810023SGordon.Ross@Sun.COM 	mb_put_uint16le(mbp, rqp->rq_hflags2);
369*11332SGordon.Ross@Sun.COM 	/* pid_hi(2), signature(8), reserved(2) */
370*11332SGordon.Ross@Sun.COM 	mb_put_mem(mbp, NULL, 12, MB_MZERO);
37110023SGordon.Ross@Sun.COM 	mb_put_uint16le(mbp, rqp->rq_tid);
37210023SGordon.Ross@Sun.COM 	mb_put_uint16le(mbp, 0);	/* pid_lo */
37310023SGordon.Ross@Sun.COM 	mb_put_uint16le(mbp, rqp->rq_uid);
37410023SGordon.Ross@Sun.COM 	mb_put_uint16le(mbp, rqp->rq_mid);
37510023SGordon.Ross@Sun.COM 
37610023SGordon.Ross@Sun.COM 	/* Restore original m_len */
37710023SGordon.Ross@Sun.COM 	mbp->mb_cur->m_len = save_mlen;
37810023SGordon.Ross@Sun.COM 
37910023SGordon.Ross@Sun.COM 	/*
38010023SGordon.Ross@Sun.COM 	 * Sign the message, if flags2 indicates.
38110023SGordon.Ross@Sun.COM 	 */
38210023SGordon.Ross@Sun.COM 	if (rqp->rq_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
38310023SGordon.Ross@Sun.COM 		smb_rq_sign(rqp);
38410023SGordon.Ross@Sun.COM 	}
38510023SGordon.Ross@Sun.COM 
38610023SGordon.Ross@Sun.COM 	/*
38710023SGordon.Ross@Sun.COM 	 * Send it, wait for the reply.
38810023SGordon.Ross@Sun.COM 	 */
38910023SGordon.Ross@Sun.COM 	if ((err = smb_ssn_send(ctx, &rqp->rq_rq)) != 0)
39010023SGordon.Ross@Sun.COM 		return (err);
39110023SGordon.Ross@Sun.COM 
39210023SGordon.Ross@Sun.COM 	if ((err = smb_ssn_recv(ctx, &rqp->rq_rp)) != 0)
39310023SGordon.Ross@Sun.COM 		return (err);
39410023SGordon.Ross@Sun.COM 
39510023SGordon.Ross@Sun.COM 	/*
39610023SGordon.Ross@Sun.COM 	 * Should have an SMB header, at least.
39710023SGordon.Ross@Sun.COM 	 */
39810023SGordon.Ross@Sun.COM 	mbp = &rqp->rq_rp;
39910023SGordon.Ross@Sun.COM 	if (mbp->mb_cur->m_len < SMB_HDRLEN) {
40010023SGordon.Ross@Sun.COM 		DPRINT("len < 32");
40110023SGordon.Ross@Sun.COM 		return (EBADRPC);
40210023SGordon.Ross@Sun.COM 	}
40310023SGordon.Ross@Sun.COM 
40410023SGordon.Ross@Sun.COM 	/*
40510023SGordon.Ross@Sun.COM 	 * If the request was signed, validate the
40610023SGordon.Ross@Sun.COM 	 * signature on the response.
40710023SGordon.Ross@Sun.COM 	 */
40810023SGordon.Ross@Sun.COM 	if (rqp->rq_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
40910023SGordon.Ross@Sun.COM 		err = smb_rq_verify(rqp);
41010023SGordon.Ross@Sun.COM 		if (err) {
41110023SGordon.Ross@Sun.COM 			DPRINT("bad signature");
41210023SGordon.Ross@Sun.COM 			return (err);
41310023SGordon.Ross@Sun.COM 		}
41410023SGordon.Ross@Sun.COM 	}
41510023SGordon.Ross@Sun.COM 
41610023SGordon.Ross@Sun.COM 	/*
41710023SGordon.Ross@Sun.COM 	 * Decode the SMB header.
41810023SGordon.Ross@Sun.COM 	 */
419*11332SGordon.Ross@Sun.COM 	md_get_mem(mbp, (char *)sigbuf, 4, MB_MSYSTEM);
42010023SGordon.Ross@Sun.COM 	if (0 != bcmp(sigbuf, ffsmb, 4)) {
42110023SGordon.Ross@Sun.COM 		DPRINT("not SMB");
42210023SGordon.Ross@Sun.COM 		return (EBADRPC);
42310023SGordon.Ross@Sun.COM 	}
424*11332SGordon.Ross@Sun.COM 	md_get_uint8(mbp, &ctmp);	/* SMB cmd */
425*11332SGordon.Ross@Sun.COM 	md_get_uint32le(mbp, &rqp->rq_status);
426*11332SGordon.Ross@Sun.COM 	md_get_uint8(mbp, &rqp->rq_hflags);
427*11332SGordon.Ross@Sun.COM 	md_get_uint16le(mbp, &rqp->rq_hflags2);
428*11332SGordon.Ross@Sun.COM 	/* pid_hi(2), signature(8), reserved(2) */
429*11332SGordon.Ross@Sun.COM 	md_get_mem(mbp, NULL, 12, MB_MSYSTEM);
430*11332SGordon.Ross@Sun.COM 	md_get_uint16le(mbp, &rqp->rq_tid);
431*11332SGordon.Ross@Sun.COM 	md_get_uint16le(mbp, NULL);	/* pid_lo */
432*11332SGordon.Ross@Sun.COM 	md_get_uint16le(mbp, &rqp->rq_uid);
433*11332SGordon.Ross@Sun.COM 	md_get_uint16le(mbp, &rqp->rq_mid);
43410023SGordon.Ross@Sun.COM 
43510023SGordon.Ross@Sun.COM 	/*
43610023SGordon.Ross@Sun.COM 	 * Figure out the status return.
43710023SGordon.Ross@Sun.COM 	 * Caller looks at rq_status.
43810023SGordon.Ross@Sun.COM 	 */
43910023SGordon.Ross@Sun.COM 	if ((rqp->rq_hflags2 & SMB_FLAGS2_ERR_STATUS) == 0) {
44010023SGordon.Ross@Sun.COM 		uint16_t	serr;
44110023SGordon.Ross@Sun.COM 		uint8_t		class;
44210023SGordon.Ross@Sun.COM 
44310023SGordon.Ross@Sun.COM 		class = rqp->rq_status & 0xff;
44410023SGordon.Ross@Sun.COM 		serr  = rqp->rq_status >> 16;
44510023SGordon.Ross@Sun.COM 		rqp->rq_status = smb_map_doserr(class, serr);
44610023SGordon.Ross@Sun.COM 	}
44710023SGordon.Ross@Sun.COM 
44810023SGordon.Ross@Sun.COM 	return (0);
44910023SGordon.Ross@Sun.COM }
45010023SGordon.Ross@Sun.COM 
45110023SGordon.Ross@Sun.COM /*
45210023SGordon.Ross@Sun.COM  * Map old DOS errors (etc.) to NT status codes.
45310023SGordon.Ross@Sun.COM  * We probably don't need this anymore, since
45410023SGordon.Ross@Sun.COM  * the oldest server we talk to is NT.  But if
45510023SGordon.Ross@Sun.COM  * later find we do need this, add support here
45610023SGordon.Ross@Sun.COM  * for the DOS errors we care about.
45710023SGordon.Ross@Sun.COM  */
45810023SGordon.Ross@Sun.COM static uint32_t
smb_map_doserr(uint8_t class,uint16_t serr)45910023SGordon.Ross@Sun.COM smb_map_doserr(uint8_t class, uint16_t serr)
46010023SGordon.Ross@Sun.COM {
46110023SGordon.Ross@Sun.COM 	if (class == 0 && serr == 0)
46210023SGordon.Ross@Sun.COM 		return (0);
46310023SGordon.Ross@Sun.COM 
46410023SGordon.Ross@Sun.COM 	DPRINT("class 0x%x serr 0x%x", (int)class, (int)serr);
46510023SGordon.Ross@Sun.COM 	return (NT_STATUS_UNSUCCESSFUL);
46610023SGordon.Ross@Sun.COM }
467