xref: /titanic_51/usr/src/lib/libsmbfs/smb/rq.c (revision 613a2f6ba31e891e3d947a356daf5e563d43c1ce)
14bff34e3Sthurlow /*
24bff34e3Sthurlow  * Copyright (c) 2000, 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: rq.c,v 1.4 2004/12/13 00:25:23 lindak Exp $
334bff34e3Sthurlow  */
344bff34e3Sthurlow 
354bff34e3Sthurlow #include <sys/types.h>
364bff34e3Sthurlow #include <sys/param.h>
374bff34e3Sthurlow #include <sys/ioctl.h>
384bff34e3Sthurlow #include <sys/errno.h>
394bff34e3Sthurlow #include <sys/stat.h>
404bff34e3Sthurlow 
414bff34e3Sthurlow #include <ctype.h>
424bff34e3Sthurlow #include <errno.h>
434bff34e3Sthurlow #include <stdio.h>
444bff34e3Sthurlow #include <unistd.h>
454bff34e3Sthurlow #include <strings.h>
464bff34e3Sthurlow #include <stdlib.h>
474bff34e3Sthurlow #include <sysexits.h>
484bff34e3Sthurlow #include <libintl.h>
494bff34e3Sthurlow 
50*613a2f6bSGordon Ross #include <netsmb/smb.h>
514bff34e3Sthurlow #include <netsmb/smb_lib.h>
529c9af259SGordon Ross #include "private.h"
534bff34e3Sthurlow 
54*613a2f6bSGordon Ross static uint32_t smb_map_doserr(uint8_t, uint16_t);
554bff34e3Sthurlow 
56*613a2f6bSGordon Ross /*
57*613a2f6bSGordon Ross  * Create and initialize a request structure, for either an
58*613a2f6bSGordon Ross  * "internal" request (one that does not use the driver) or
59*613a2f6bSGordon Ross  * a regular "driver" request, that uses driver ioctls.
60*613a2f6bSGordon Ross  *
61*613a2f6bSGordon Ross  * The two kinds are built a little differently:
62*613a2f6bSGordon Ross  * Driver requests are composed starting with the
63*613a2f6bSGordon Ross  * first word of the "variable word vector" section.
64*613a2f6bSGordon Ross  * The driver prepends the SMB header and word count.
65*613a2f6bSGordon Ross  * The driver also needs an output buffer to receive
66*613a2f6bSGordon Ross  * the response, filled in via copyout in the ioctl.
67*613a2f6bSGordon Ross  *
68*613a2f6bSGordon Ross  * Internal requests are composed entirely in this library.
69*613a2f6bSGordon Ross  * Space for the SMB header is reserved here, and later
70*613a2f6bSGordon Ross  * filled in by smb_rq_internal before the send/receive.
71*613a2f6bSGordon Ross  */
724bff34e3Sthurlow int
73*613a2f6bSGordon Ross smb_rq_init(struct smb_ctx *ctx, uchar_t cmd, struct smb_rq **rqpp)
744bff34e3Sthurlow {
754bff34e3Sthurlow 	struct smb_rq *rqp;
764bff34e3Sthurlow 
774bff34e3Sthurlow 	rqp = malloc(sizeof (*rqp));
784bff34e3Sthurlow 	if (rqp == NULL)
79*613a2f6bSGordon Ross 		goto errout;
804bff34e3Sthurlow 	bzero(rqp, sizeof (*rqp));
814bff34e3Sthurlow 	rqp->rq_cmd = cmd;
824bff34e3Sthurlow 	rqp->rq_ctx = ctx;
83*613a2f6bSGordon Ross 
84*613a2f6bSGordon Ross 	/*
85*613a2f6bSGordon Ross 	 * Setup the request buffer.
86*613a2f6bSGordon Ross 	 * Do the reply buffer later.
87*613a2f6bSGordon Ross 	 */
88*613a2f6bSGordon Ross 	if (mb_init(&rqp->rq_rq, M_MINSIZE))
89*613a2f6bSGordon Ross 		goto errout;
90*613a2f6bSGordon Ross 
91*613a2f6bSGordon Ross 	/* Space for the SMB header. (filled in later) */
92*613a2f6bSGordon Ross 	mb_put_mem(&rqp->rq_rq, NULL, SMB_HDRLEN);
93*613a2f6bSGordon Ross 
94*613a2f6bSGordon Ross 	/*
95*613a2f6bSGordon Ross 	 * Copy the ctx flags here, so the caller can
96*613a2f6bSGordon Ross 	 * update the req flags before the OTW call.
97*613a2f6bSGordon Ross 	 */
98*613a2f6bSGordon Ross 	rqp->rq_hflags = ctx->ct_hflags;
99*613a2f6bSGordon Ross 	rqp->rq_hflags2 = ctx->ct_hflags2;
100*613a2f6bSGordon Ross 
1014bff34e3Sthurlow 	*rqpp = rqp;
1024bff34e3Sthurlow 	return (0);
103*613a2f6bSGordon Ross 
104*613a2f6bSGordon Ross errout:
105*613a2f6bSGordon Ross 	if (rqp) {
106*613a2f6bSGordon Ross 		smb_rq_done(rqp);
107*613a2f6bSGordon Ross 		free(rqp);
108*613a2f6bSGordon Ross 	}
109*613a2f6bSGordon Ross 	return (ENOMEM);
1104bff34e3Sthurlow }
1114bff34e3Sthurlow 
1124bff34e3Sthurlow void
1134bff34e3Sthurlow smb_rq_done(struct smb_rq *rqp)
1144bff34e3Sthurlow {
1154bff34e3Sthurlow 	mb_done(&rqp->rq_rp);
1164bff34e3Sthurlow 	mb_done(&rqp->rq_rq);
1174bff34e3Sthurlow 	free(rqp);
1184bff34e3Sthurlow }
1194bff34e3Sthurlow 
120*613a2f6bSGordon Ross /*
121*613a2f6bSGordon Ross  * Reserve space for the word count, which is filled in later by
122*613a2f6bSGordon Ross  * smb_rq_wend().  Also initialize the counter that it uses
123*613a2f6bSGordon Ross  * to figure out what value to fill in.
124*613a2f6bSGordon Ross  *
125*613a2f6bSGordon Ross  * Note that the word count happens to be 8-bits,
126*613a2f6bSGordon Ross  * which can lead to confusion.
127*613a2f6bSGordon Ross  */
128*613a2f6bSGordon Ross void
129*613a2f6bSGordon Ross smb_rq_wstart(struct smb_rq *rqp)
130*613a2f6bSGordon Ross {
131*613a2f6bSGordon Ross 	struct mbdata *mbp = &rqp->rq_rq;
132*613a2f6bSGordon Ross 
133*613a2f6bSGordon Ross 	mb_fit(mbp, 1, &rqp->rq_wcntp);
134*613a2f6bSGordon Ross 	rqp->rq_wcbase = mbp->mb_count;
135*613a2f6bSGordon Ross }
136*613a2f6bSGordon Ross 
137*613a2f6bSGordon Ross /*
138*613a2f6bSGordon Ross  * Fill in the word count, in the space reserved by
139*613a2f6bSGordon Ross  * smb_rq_wstart().
140*613a2f6bSGordon Ross  */
1414bff34e3Sthurlow void
1424bff34e3Sthurlow smb_rq_wend(struct smb_rq *rqp)
1434bff34e3Sthurlow {
144*613a2f6bSGordon Ross 	struct mbdata *mbp = &rqp->rq_rq;
145*613a2f6bSGordon Ross 	int wcnt;
146*613a2f6bSGordon Ross 
147*613a2f6bSGordon Ross 	if (rqp->rq_wcntp == NULL) {
148*613a2f6bSGordon Ross 		DPRINT("no wcount ptr\n");
149*613a2f6bSGordon Ross 		return;
150*613a2f6bSGordon Ross 	}
151*613a2f6bSGordon Ross 	wcnt = mbp->mb_count - rqp->rq_wcbase;
152*613a2f6bSGordon Ross 	if (wcnt > 0x1ff)
153*613a2f6bSGordon Ross 		DPRINT("word count too large (%d)\n", wcnt);
154*613a2f6bSGordon Ross 	if (wcnt & 1)
155*613a2f6bSGordon Ross 		DPRINT("odd word count\n");
156*613a2f6bSGordon Ross 	wcnt >>= 1;
157*613a2f6bSGordon Ross 
158*613a2f6bSGordon Ross 	/*
159*613a2f6bSGordon Ross 	 * Fill in the word count (8-bits).
160*613a2f6bSGordon Ross 	 * Also store it in the rq, in case
161*613a2f6bSGordon Ross 	 * we're using the ioctl path.
162*613a2f6bSGordon Ross 	 */
163*613a2f6bSGordon Ross 	*rqp->rq_wcntp = (char)wcnt;
1644bff34e3Sthurlow }
1654bff34e3Sthurlow 
166*613a2f6bSGordon Ross /*
167*613a2f6bSGordon Ross  * Reserve space for the byte count, which is filled in later by
168*613a2f6bSGordon Ross  * smb_rq_bend().  Also initialize the counter that it uses
169*613a2f6bSGordon Ross  * to figure out what value to fill in.
170*613a2f6bSGordon Ross  *
171*613a2f6bSGordon Ross  * Note that the byte count happens to be 16-bits,
172*613a2f6bSGordon Ross  * which can lead to confusion.
173*613a2f6bSGordon Ross  */
174*613a2f6bSGordon Ross void
175*613a2f6bSGordon Ross smb_rq_bstart(struct smb_rq *rqp)
1764bff34e3Sthurlow {
177*613a2f6bSGordon Ross 	struct mbdata *mbp = &rqp->rq_rq;
1784bff34e3Sthurlow 
179*613a2f6bSGordon Ross 	mb_fit(mbp, 2, &rqp->rq_bcntp);
180*613a2f6bSGordon Ross 	rqp->rq_bcbase = mbp->mb_count;
1814bff34e3Sthurlow }
1824bff34e3Sthurlow 
183*613a2f6bSGordon Ross /*
184*613a2f6bSGordon Ross  * Fill in the byte count, in the space reserved by
185*613a2f6bSGordon Ross  * smb_rq_bstart().
186*613a2f6bSGordon Ross  */
187*613a2f6bSGordon Ross void
188*613a2f6bSGordon Ross smb_rq_bend(struct smb_rq *rqp)
1894bff34e3Sthurlow {
190*613a2f6bSGordon Ross 	struct mbdata *mbp = &rqp->rq_rq;
191*613a2f6bSGordon Ross 	int bcnt;
192*613a2f6bSGordon Ross 
193*613a2f6bSGordon Ross 	if (rqp->rq_bcntp == NULL) {
194*613a2f6bSGordon Ross 		DPRINT("no bcount ptr\n");
195*613a2f6bSGordon Ross 		return;
1964bff34e3Sthurlow 	}
197*613a2f6bSGordon Ross 	bcnt = mbp->mb_count - rqp->rq_bcbase;
198*613a2f6bSGordon Ross 	if (bcnt > 0xffff)
199*613a2f6bSGordon Ross 		DPRINT("byte count too large (%d)\n", bcnt);
200*613a2f6bSGordon Ross 	/*
201*613a2f6bSGordon Ross 	 * Fill in the byte count (16-bits).
202*613a2f6bSGordon Ross 	 * Also store it in the rq, in case
203*613a2f6bSGordon Ross 	 * we're using the ioctl path.
204*613a2f6bSGordon Ross 	 *
205*613a2f6bSGordon Ross 	 * The pointer is char * type due to
206*613a2f6bSGordon Ross 	 * typical off-by-one alignment.
207*613a2f6bSGordon Ross 	 */
208*613a2f6bSGordon Ross 	rqp->rq_bcntp[0] = bcnt & 0xFF;
209*613a2f6bSGordon Ross 	rqp->rq_bcntp[1] = (bcnt >> 8);
210*613a2f6bSGordon Ross }
211*613a2f6bSGordon Ross 
212*613a2f6bSGordon Ross /*
213*613a2f6bSGordon Ross  * Removed: smb_rq_dmem
214*613a2f6bSGordon Ross  * which was mostly like: mb_put_mem
215*613a2f6bSGordon Ross  */
2164bff34e3Sthurlow 
2174bff34e3Sthurlow int
2184bff34e3Sthurlow smb_rq_simple(struct smb_rq *rqp)
2194bff34e3Sthurlow {
2204bff34e3Sthurlow 	struct smbioc_rq krq;
2214bff34e3Sthurlow 	struct mbdata *mbp;
2224bff34e3Sthurlow 	char *data;
223*613a2f6bSGordon Ross 	uint32_t len;
224*613a2f6bSGordon Ross 	size_t rpbufsz;
2254bff34e3Sthurlow 
226*613a2f6bSGordon Ross 	bzero(&krq, sizeof (krq));
227*613a2f6bSGordon Ross 	krq.ioc_cmd = rqp->rq_cmd;
228*613a2f6bSGordon Ross 
229*613a2f6bSGordon Ross 	/*
230*613a2f6bSGordon Ross 	 * Make the SMB request body contiguous,
231*613a2f6bSGordon Ross 	 * and fill in the ioctl request.
232*613a2f6bSGordon Ross 	 */
2334bff34e3Sthurlow 	mbp = smb_rq_getrequest(rqp);
2344bff34e3Sthurlow 	m_lineup(mbp->mb_top, &mbp->mb_top);
2354bff34e3Sthurlow 	data = mtod(mbp->mb_top, char *);
236*613a2f6bSGordon Ross 	len = m_totlen(mbp->mb_top);
2374bff34e3Sthurlow 
238*613a2f6bSGordon Ross 	/*
239*613a2f6bSGordon Ross 	 * _rq_init left space for the SMB header,
240*613a2f6bSGordon Ross 	 * which makes mb_count the offset from
241*613a2f6bSGordon Ross 	 * the beginning of the header (useful).
242*613a2f6bSGordon Ross 	 * However, in this code path the driver
243*613a2f6bSGordon Ross 	 * prepends the header, so we skip it.
244*613a2f6bSGordon Ross 	 */
245*613a2f6bSGordon Ross 	krq.ioc_tbufsz = len - SMB_HDRLEN;
246*613a2f6bSGordon Ross 	krq.ioc_tbuf  = data + SMB_HDRLEN;
247*613a2f6bSGordon Ross 
248*613a2f6bSGordon Ross 	/*
249*613a2f6bSGordon Ross 	 * Setup a buffer to hold the reply.
250*613a2f6bSGordon Ross 	 *
251*613a2f6bSGordon Ross 	 * Default size is M_MINSIZE, but the
252*613a2f6bSGordon Ross 	 * caller may increase rq_rpbufsz
253*613a2f6bSGordon Ross 	 * before calling this.
254*613a2f6bSGordon Ross 	 */
2554bff34e3Sthurlow 	mbp = smb_rq_getreply(rqp);
256*613a2f6bSGordon Ross 	rpbufsz = rqp->rq_rpbufsz;
257*613a2f6bSGordon Ross 	if (rpbufsz < M_MINSIZE)
258*613a2f6bSGordon Ross 		rpbufsz = M_MINSIZE;
259*613a2f6bSGordon Ross 	if (mb_init(mbp, rpbufsz))
260*613a2f6bSGordon Ross 		return (ENOMEM);
261*613a2f6bSGordon Ross 	krq.ioc_rbufsz = rpbufsz;
262*613a2f6bSGordon Ross 	krq.ioc_rbuf = mtod(mbp->mb_top, char *);
263*613a2f6bSGordon Ross 
264*613a2f6bSGordon Ross 	/*
265*613a2f6bSGordon Ross 	 * Call the driver
266*613a2f6bSGordon Ross 	 */
267*613a2f6bSGordon Ross 	if (ioctl(rqp->rq_ctx->ct_dev_fd, SMBIOC_REQUEST, &krq) == -1)
2684bff34e3Sthurlow 		return (errno);
269*613a2f6bSGordon Ross 
270*613a2f6bSGordon Ross 	/*
271*613a2f6bSGordon Ross 	 * Initialize returned mbdata.
272*613a2f6bSGordon Ross 	 * SMB header already parsed.
273*613a2f6bSGordon Ross 	 */
274*613a2f6bSGordon Ross 	mbp->mb_top->m_len = krq.ioc_rbufsz;
275*613a2f6bSGordon Ross 
2764bff34e3Sthurlow 	return (0);
2774bff34e3Sthurlow }
2784bff34e3Sthurlow 
2794bff34e3Sthurlow 
2804bff34e3Sthurlow int
2814bff34e3Sthurlow smb_t2_request(struct smb_ctx *ctx, int setupcount, uint16_t *setup,
2824bff34e3Sthurlow 	const char *name,
2834bff34e3Sthurlow 	int tparamcnt, void *tparam,
2844bff34e3Sthurlow 	int tdatacnt, void *tdata,
2854bff34e3Sthurlow 	int *rparamcnt, void *rparam,
2864bff34e3Sthurlow 	int *rdatacnt, void *rdata,
2874bff34e3Sthurlow 	int *buffer_oflow)
2884bff34e3Sthurlow {
2894bff34e3Sthurlow 	smbioc_t2rq_t *krq;
2904bff34e3Sthurlow 	int i;
2914bff34e3Sthurlow 
2924bff34e3Sthurlow 	krq = (smbioc_t2rq_t *)malloc(sizeof (smbioc_t2rq_t));
2934bff34e3Sthurlow 	bzero(krq, sizeof (*krq));
2944bff34e3Sthurlow 
295*613a2f6bSGordon Ross 	if (setupcount < 0 || setupcount >= SMBIOC_T2RQ_MAXSETUP) {
2964bff34e3Sthurlow 		/* Bogus setup count, or too many setup words */
2974bff34e3Sthurlow 		return (EINVAL);
2984bff34e3Sthurlow 	}
2994bff34e3Sthurlow 	for (i = 0; i < setupcount; i++)
3004bff34e3Sthurlow 		krq->ioc_setup[i] = setup[i];
3014bff34e3Sthurlow 	krq->ioc_setupcnt = setupcount;
3024bff34e3Sthurlow 	strcpy(krq->ioc_name, name);
3034bff34e3Sthurlow 	krq->ioc_tparamcnt = tparamcnt;
3044bff34e3Sthurlow 	krq->ioc_tparam = tparam;
3054bff34e3Sthurlow 	krq->ioc_tdatacnt = tdatacnt;
3064bff34e3Sthurlow 	krq->ioc_tdata = tdata;
3074bff34e3Sthurlow 
3084bff34e3Sthurlow 	krq->ioc_rparamcnt = *rparamcnt;
3094bff34e3Sthurlow 	krq->ioc_rdatacnt = *rdatacnt;
3104bff34e3Sthurlow 	krq->ioc_rparam = rparam;
3114bff34e3Sthurlow 	krq->ioc_rdata  = rdata;
3124bff34e3Sthurlow 
313*613a2f6bSGordon Ross 	if (ioctl(ctx->ct_dev_fd, SMBIOC_T2RQ, krq) == -1) {
3144bff34e3Sthurlow 		return (errno);
3154bff34e3Sthurlow 	}
3164bff34e3Sthurlow 
3174bff34e3Sthurlow 	*rparamcnt = krq->ioc_rparamcnt;
3184bff34e3Sthurlow 	*rdatacnt = krq->ioc_rdatacnt;
3194bff34e3Sthurlow 	*buffer_oflow = (krq->ioc_rpflags2 & SMB_FLAGS2_ERR_STATUS) &&
3204bff34e3Sthurlow 	    (krq->ioc_error == NT_STATUS_BUFFER_OVERFLOW);
3214bff34e3Sthurlow 	free(krq);
322*613a2f6bSGordon Ross 
3234bff34e3Sthurlow 	return (0);
3244bff34e3Sthurlow }
325*613a2f6bSGordon Ross 
326*613a2f6bSGordon Ross 
327*613a2f6bSGordon Ross /*
328*613a2f6bSGordon Ross  * Do an over-the-wire call without using the nsmb driver.
329*613a2f6bSGordon Ross  * This is all "internal" to this library, and used only
330*613a2f6bSGordon Ross  * for connection setup (negotiate protocol, etc.)
331*613a2f6bSGordon Ross  */
332*613a2f6bSGordon Ross int
333*613a2f6bSGordon Ross smb_rq_internal(struct smb_ctx *ctx, struct smb_rq *rqp)
334*613a2f6bSGordon Ross {
335*613a2f6bSGordon Ross 	static const uint8_t ffsmb[4] = SMB_SIGNATURE;
336*613a2f6bSGordon Ross 	struct smb_iods *is = &ctx->ct_iods;
337*613a2f6bSGordon Ross 	uint32_t sigbuf[2];
338*613a2f6bSGordon Ross 	struct mbdata mbtmp, *mbp;
339*613a2f6bSGordon Ross 	int err, save_mlen;
340*613a2f6bSGordon Ross 	uint8_t ctmp;
341*613a2f6bSGordon Ross 
342*613a2f6bSGordon Ross 	rqp->rq_uid = is->is_smbuid;
343*613a2f6bSGordon Ross 	rqp->rq_tid = SMB_TID_UNKNOWN;
344*613a2f6bSGordon Ross 	rqp->rq_mid = is->is_next_mid++;
345*613a2f6bSGordon Ross 
346*613a2f6bSGordon Ross 	/*
347*613a2f6bSGordon Ross 	 * Fill in the NBT and SMB headers
348*613a2f6bSGordon Ross 	 * Using mbtmp so we can rewind without
349*613a2f6bSGordon Ross 	 * affecting the passed request mbdata.
350*613a2f6bSGordon Ross 	 */
351*613a2f6bSGordon Ross 	bcopy(&rqp->rq_rq, &mbtmp, sizeof (mbtmp));
352*613a2f6bSGordon Ross 	mbp = &mbtmp;
353*613a2f6bSGordon Ross 	mbp->mb_cur = mbp->mb_top;
354*613a2f6bSGordon Ross 	mbp->mb_pos = mbp->mb_cur->m_data;
355*613a2f6bSGordon Ross 	mbp->mb_count = 0;
356*613a2f6bSGordon Ross 	/* Have to save and restore m_len */
357*613a2f6bSGordon Ross 	save_mlen = mbp->mb_cur->m_len;
358*613a2f6bSGordon Ross 	mbp->mb_cur->m_len = 0;
359*613a2f6bSGordon Ross 
360*613a2f6bSGordon Ross 	/*
361*613a2f6bSGordon Ross 	 * rewind done; fill it in
362*613a2f6bSGordon Ross 	 */
363*613a2f6bSGordon Ross 	mb_put_mem(mbp, (char *)SMB_SIGNATURE, SMB_SIGLEN);
364*613a2f6bSGordon Ross 	mb_put_uint8(mbp, rqp->rq_cmd);
365*613a2f6bSGordon Ross 	mb_put_mem(mbp, NULL, 4);	/* status */
366*613a2f6bSGordon Ross 	mb_put_uint8(mbp, rqp->rq_hflags);
367*613a2f6bSGordon Ross 	mb_put_uint16le(mbp, rqp->rq_hflags2);
368*613a2f6bSGordon Ross 	mb_put_uint16le(mbp, 0);	/* pid_hi */
369*613a2f6bSGordon Ross 	mb_put_mem(mbp, NULL, 8);	/* signature */
370*613a2f6bSGordon Ross 	mb_put_uint16le(mbp, 0);	/* reserved */
371*613a2f6bSGordon Ross 	mb_put_uint16le(mbp, rqp->rq_tid);
372*613a2f6bSGordon Ross 	mb_put_uint16le(mbp, 0);	/* pid_lo */
373*613a2f6bSGordon Ross 	mb_put_uint16le(mbp, rqp->rq_uid);
374*613a2f6bSGordon Ross 	mb_put_uint16le(mbp, rqp->rq_mid);
375*613a2f6bSGordon Ross 
376*613a2f6bSGordon Ross 	/* Restore original m_len */
377*613a2f6bSGordon Ross 	mbp->mb_cur->m_len = save_mlen;
378*613a2f6bSGordon Ross 
379*613a2f6bSGordon Ross 	/*
380*613a2f6bSGordon Ross 	 * Sign the message, if flags2 indicates.
381*613a2f6bSGordon Ross 	 */
382*613a2f6bSGordon Ross 	if (rqp->rq_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
383*613a2f6bSGordon Ross 		smb_rq_sign(rqp);
384*613a2f6bSGordon Ross 	}
385*613a2f6bSGordon Ross 
386*613a2f6bSGordon Ross 	/*
387*613a2f6bSGordon Ross 	 * Send it, wait for the reply.
388*613a2f6bSGordon Ross 	 */
389*613a2f6bSGordon Ross 	if ((err = smb_ssn_send(ctx, &rqp->rq_rq)) != 0)
390*613a2f6bSGordon Ross 		return (err);
391*613a2f6bSGordon Ross 
392*613a2f6bSGordon Ross 	if ((err = smb_ssn_recv(ctx, &rqp->rq_rp)) != 0)
393*613a2f6bSGordon Ross 		return (err);
394*613a2f6bSGordon Ross 
395*613a2f6bSGordon Ross 	/*
396*613a2f6bSGordon Ross 	 * Should have an SMB header, at least.
397*613a2f6bSGordon Ross 	 */
398*613a2f6bSGordon Ross 	mbp = &rqp->rq_rp;
399*613a2f6bSGordon Ross 	if (mbp->mb_cur->m_len < SMB_HDRLEN) {
400*613a2f6bSGordon Ross 		DPRINT("len < 32");
401*613a2f6bSGordon Ross 		return (EBADRPC);
402*613a2f6bSGordon Ross 	}
403*613a2f6bSGordon Ross 
404*613a2f6bSGordon Ross 	/*
405*613a2f6bSGordon Ross 	 * If the request was signed, validate the
406*613a2f6bSGordon Ross 	 * signature on the response.
407*613a2f6bSGordon Ross 	 */
408*613a2f6bSGordon Ross 	if (rqp->rq_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
409*613a2f6bSGordon Ross 		err = smb_rq_verify(rqp);
410*613a2f6bSGordon Ross 		if (err) {
411*613a2f6bSGordon Ross 			DPRINT("bad signature");
412*613a2f6bSGordon Ross 			return (err);
413*613a2f6bSGordon Ross 		}
414*613a2f6bSGordon Ross 	}
415*613a2f6bSGordon Ross 
416*613a2f6bSGordon Ross 	/*
417*613a2f6bSGordon Ross 	 * Decode the SMB header.
418*613a2f6bSGordon Ross 	 */
419*613a2f6bSGordon Ross 	mb_get_mem(mbp, (char *)sigbuf, 4);
420*613a2f6bSGordon Ross 	if (0 != bcmp(sigbuf, ffsmb, 4)) {
421*613a2f6bSGordon Ross 		DPRINT("not SMB");
422*613a2f6bSGordon Ross 		return (EBADRPC);
423*613a2f6bSGordon Ross 	}
424*613a2f6bSGordon Ross 	mb_get_uint8(mbp, &ctmp);	/* SMB cmd */
425*613a2f6bSGordon Ross 	mb_get_uint32le(mbp, &rqp->rq_status);
426*613a2f6bSGordon Ross 	mb_get_uint8(mbp, &rqp->rq_hflags);
427*613a2f6bSGordon Ross 	mb_get_uint16le(mbp, &rqp->rq_hflags2);
428*613a2f6bSGordon Ross 	mb_get_uint16le(mbp, NULL);	/* pid_hi */
429*613a2f6bSGordon Ross 	mb_get_mem(mbp, NULL, 8); /* signature */
430*613a2f6bSGordon Ross 	mb_get_uint16le(mbp, NULL);	/* reserved */
431*613a2f6bSGordon Ross 	mb_get_uint16le(mbp, &rqp->rq_tid);
432*613a2f6bSGordon Ross 	mb_get_uint16le(mbp, NULL);	/* pid_lo */
433*613a2f6bSGordon Ross 	mb_get_uint16le(mbp, &rqp->rq_uid);
434*613a2f6bSGordon Ross 	mb_get_uint16le(mbp, &rqp->rq_mid);
435*613a2f6bSGordon Ross 
436*613a2f6bSGordon Ross 	/*
437*613a2f6bSGordon Ross 	 * Figure out the status return.
438*613a2f6bSGordon Ross 	 * Caller looks at rq_status.
439*613a2f6bSGordon Ross 	 */
440*613a2f6bSGordon Ross 	if ((rqp->rq_hflags2 & SMB_FLAGS2_ERR_STATUS) == 0) {
441*613a2f6bSGordon Ross 		uint16_t	serr;
442*613a2f6bSGordon Ross 		uint8_t		class;
443*613a2f6bSGordon Ross 
444*613a2f6bSGordon Ross 		class = rqp->rq_status & 0xff;
445*613a2f6bSGordon Ross 		serr  = rqp->rq_status >> 16;
446*613a2f6bSGordon Ross 		rqp->rq_status = smb_map_doserr(class, serr);
447*613a2f6bSGordon Ross 	}
448*613a2f6bSGordon Ross 
449*613a2f6bSGordon Ross 	return (0);
450*613a2f6bSGordon Ross }
451*613a2f6bSGordon Ross 
452*613a2f6bSGordon Ross /*
453*613a2f6bSGordon Ross  * Map old DOS errors (etc.) to NT status codes.
454*613a2f6bSGordon Ross  * We probably don't need this anymore, since
455*613a2f6bSGordon Ross  * the oldest server we talk to is NT.  But if
456*613a2f6bSGordon Ross  * later find we do need this, add support here
457*613a2f6bSGordon Ross  * for the DOS errors we care about.
458*613a2f6bSGordon Ross  */
459*613a2f6bSGordon Ross static uint32_t
460*613a2f6bSGordon Ross smb_map_doserr(uint8_t class, uint16_t serr)
461*613a2f6bSGordon Ross {
462*613a2f6bSGordon Ross 	if (class == 0 && serr == 0)
463*613a2f6bSGordon Ross 		return (0);
464*613a2f6bSGordon Ross 
465*613a2f6bSGordon Ross 	DPRINT("class 0x%x serr 0x%x", (int)class, (int)serr);
466*613a2f6bSGordon Ross 	return (NT_STATUS_UNSUCCESSFUL);
467*613a2f6bSGordon Ross }
468