14bff34e3Sthurlow /*
2*430b4c46SGordon Ross * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
34bff34e3Sthurlow * Copyright (c) 2000, Boris Popov
44bff34e3Sthurlow * All rights reserved.
54bff34e3Sthurlow *
64bff34e3Sthurlow * Redistribution and use in source and binary forms, with or without
74bff34e3Sthurlow * modification, are permitted provided that the following conditions
84bff34e3Sthurlow * are met:
94bff34e3Sthurlow * 1. Redistributions of source code must retain the above copyright
104bff34e3Sthurlow * notice, this list of conditions and the following disclaimer.
114bff34e3Sthurlow * 2. Redistributions in binary form must reproduce the above copyright
124bff34e3Sthurlow * notice, this list of conditions and the following disclaimer in the
134bff34e3Sthurlow * documentation and/or other materials provided with the distribution.
144bff34e3Sthurlow * 3. All advertising materials mentioning features or use of this software
154bff34e3Sthurlow * must display the following acknowledgement:
164bff34e3Sthurlow * This product includes software developed by Boris Popov.
174bff34e3Sthurlow * 4. Neither the name of the author nor the names of any co-contributors
184bff34e3Sthurlow * may be used to endorse or promote products derived from this software
194bff34e3Sthurlow * without specific prior written permission.
204bff34e3Sthurlow *
214bff34e3Sthurlow * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
224bff34e3Sthurlow * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
234bff34e3Sthurlow * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
244bff34e3Sthurlow * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
254bff34e3Sthurlow * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
264bff34e3Sthurlow * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
274bff34e3Sthurlow * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
284bff34e3Sthurlow * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
294bff34e3Sthurlow * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
304bff34e3Sthurlow * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
314bff34e3Sthurlow * SUCH DAMAGE.
324bff34e3Sthurlow *
334bff34e3Sthurlow * $Id: rq.c,v 1.4 2004/12/13 00:25:23 lindak Exp $
344bff34e3Sthurlow */
354bff34e3Sthurlow
364bff34e3Sthurlow #include <sys/types.h>
374bff34e3Sthurlow #include <sys/param.h>
384bff34e3Sthurlow #include <sys/ioctl.h>
394bff34e3Sthurlow #include <sys/errno.h>
404bff34e3Sthurlow #include <sys/stat.h>
414bff34e3Sthurlow
424bff34e3Sthurlow #include <ctype.h>
434bff34e3Sthurlow #include <errno.h>
444bff34e3Sthurlow #include <stdio.h>
454bff34e3Sthurlow #include <unistd.h>
464bff34e3Sthurlow #include <strings.h>
474bff34e3Sthurlow #include <stdlib.h>
484bff34e3Sthurlow #include <sysexits.h>
494bff34e3Sthurlow #include <libintl.h>
504bff34e3Sthurlow
51613a2f6bSGordon Ross #include <netsmb/smb.h>
524bff34e3Sthurlow #include <netsmb/smb_lib.h>
539c9af259SGordon Ross #include "private.h"
544bff34e3Sthurlow
5502d09e03SGordon Ross #define MIN_REPLY_SIZE 4096
5602d09e03SGordon Ross
57613a2f6bSGordon Ross static uint32_t smb_map_doserr(uint8_t, uint16_t);
584bff34e3Sthurlow
59613a2f6bSGordon Ross /*
60613a2f6bSGordon Ross * Create and initialize a request structure, for either an
61613a2f6bSGordon Ross * "internal" request (one that does not use the driver) or
62613a2f6bSGordon Ross * a regular "driver" request, that uses driver ioctls.
63613a2f6bSGordon Ross *
64613a2f6bSGordon Ross * The two kinds are built a little differently:
65613a2f6bSGordon Ross * Driver requests are composed starting with the
66613a2f6bSGordon Ross * first word of the "variable word vector" section.
67613a2f6bSGordon Ross * The driver prepends the SMB header and word count.
68613a2f6bSGordon Ross * The driver also needs an output buffer to receive
69613a2f6bSGordon Ross * the response, filled in via copyout in the ioctl.
70613a2f6bSGordon Ross *
71613a2f6bSGordon Ross * Internal requests are composed entirely in this library.
72613a2f6bSGordon Ross * Space for the SMB header is reserved here, and later
73613a2f6bSGordon Ross * filled in by smb_rq_internal before the send/receive.
74613a2f6bSGordon Ross */
754bff34e3Sthurlow int
smb_rq_init(struct smb_ctx * ctx,uchar_t cmd,struct smb_rq ** rqpp)76613a2f6bSGordon Ross smb_rq_init(struct smb_ctx *ctx, uchar_t cmd, struct smb_rq **rqpp)
774bff34e3Sthurlow {
784bff34e3Sthurlow struct smb_rq *rqp;
794bff34e3Sthurlow
804bff34e3Sthurlow rqp = malloc(sizeof (*rqp));
814bff34e3Sthurlow if (rqp == NULL)
82613a2f6bSGordon Ross goto errout;
834bff34e3Sthurlow bzero(rqp, sizeof (*rqp));
844bff34e3Sthurlow rqp->rq_cmd = cmd;
854bff34e3Sthurlow rqp->rq_ctx = ctx;
86613a2f6bSGordon Ross
87613a2f6bSGordon Ross /*
88613a2f6bSGordon Ross * Setup the request buffer.
89613a2f6bSGordon Ross * Do the reply buffer later.
90613a2f6bSGordon Ross */
9102d09e03SGordon Ross if (mb_init(&rqp->rq_rq))
92613a2f6bSGordon Ross goto errout;
93613a2f6bSGordon Ross
94613a2f6bSGordon Ross /* Space for the SMB header. (filled in later) */
9502d09e03SGordon Ross mb_put_mem(&rqp->rq_rq, NULL, SMB_HDRLEN, MB_MSYSTEM);
96613a2f6bSGordon Ross
97613a2f6bSGordon Ross /*
98613a2f6bSGordon Ross * Copy the ctx flags here, so the caller can
99613a2f6bSGordon Ross * update the req flags before the OTW call.
100613a2f6bSGordon Ross */
101613a2f6bSGordon Ross rqp->rq_hflags = ctx->ct_hflags;
102613a2f6bSGordon Ross rqp->rq_hflags2 = ctx->ct_hflags2;
103613a2f6bSGordon Ross
1044bff34e3Sthurlow *rqpp = rqp;
1054bff34e3Sthurlow return (0);
106613a2f6bSGordon Ross
107613a2f6bSGordon Ross errout:
108613a2f6bSGordon Ross if (rqp) {
109613a2f6bSGordon Ross smb_rq_done(rqp);
110613a2f6bSGordon Ross free(rqp);
111613a2f6bSGordon Ross }
112613a2f6bSGordon Ross return (ENOMEM);
1134bff34e3Sthurlow }
1144bff34e3Sthurlow
1154bff34e3Sthurlow void
smb_rq_done(struct smb_rq * rqp)1164bff34e3Sthurlow smb_rq_done(struct smb_rq *rqp)
1174bff34e3Sthurlow {
1184bff34e3Sthurlow mb_done(&rqp->rq_rp);
1194bff34e3Sthurlow mb_done(&rqp->rq_rq);
1204bff34e3Sthurlow free(rqp);
1214bff34e3Sthurlow }
1224bff34e3Sthurlow
123613a2f6bSGordon Ross /*
124613a2f6bSGordon Ross * Reserve space for the word count, which is filled in later by
125613a2f6bSGordon Ross * smb_rq_wend(). Also initialize the counter that it uses
126613a2f6bSGordon Ross * to figure out what value to fill in.
127613a2f6bSGordon Ross *
128613a2f6bSGordon Ross * Note that the word count happens to be 8-bits,
129613a2f6bSGordon Ross * which can lead to confusion.
130613a2f6bSGordon Ross */
131613a2f6bSGordon Ross void
smb_rq_wstart(struct smb_rq * rqp)132613a2f6bSGordon Ross smb_rq_wstart(struct smb_rq *rqp)
133613a2f6bSGordon Ross {
134613a2f6bSGordon Ross struct mbdata *mbp = &rqp->rq_rq;
135613a2f6bSGordon Ross
13602d09e03SGordon Ross (void) mb_fit(mbp, 1, &rqp->rq_wcntp);
137613a2f6bSGordon Ross rqp->rq_wcbase = mbp->mb_count;
138613a2f6bSGordon Ross }
139613a2f6bSGordon Ross
140613a2f6bSGordon Ross /*
141613a2f6bSGordon Ross * Fill in the word count, in the space reserved by
142613a2f6bSGordon Ross * smb_rq_wstart().
143613a2f6bSGordon Ross */
1444bff34e3Sthurlow void
smb_rq_wend(struct smb_rq * rqp)1454bff34e3Sthurlow smb_rq_wend(struct smb_rq *rqp)
1464bff34e3Sthurlow {
147613a2f6bSGordon Ross struct mbdata *mbp = &rqp->rq_rq;
148613a2f6bSGordon Ross int wcnt;
149613a2f6bSGordon Ross
150613a2f6bSGordon Ross if (rqp->rq_wcntp == NULL) {
151613a2f6bSGordon Ross DPRINT("no wcount ptr\n");
152613a2f6bSGordon Ross return;
153613a2f6bSGordon Ross }
154613a2f6bSGordon Ross wcnt = mbp->mb_count - rqp->rq_wcbase;
155613a2f6bSGordon Ross if (wcnt > 0x1ff)
156613a2f6bSGordon Ross DPRINT("word count too large (%d)\n", wcnt);
157613a2f6bSGordon Ross if (wcnt & 1)
158613a2f6bSGordon Ross DPRINT("odd word count\n");
159613a2f6bSGordon Ross wcnt >>= 1;
160613a2f6bSGordon Ross
161613a2f6bSGordon Ross /*
162613a2f6bSGordon Ross * Fill in the word count (8-bits).
163613a2f6bSGordon Ross * Also store it in the rq, in case
164613a2f6bSGordon Ross * we're using the ioctl path.
165613a2f6bSGordon Ross */
166613a2f6bSGordon Ross *rqp->rq_wcntp = (char)wcnt;
1674bff34e3Sthurlow }
1684bff34e3Sthurlow
169613a2f6bSGordon Ross /*
170613a2f6bSGordon Ross * Reserve space for the byte count, which is filled in later by
171613a2f6bSGordon Ross * smb_rq_bend(). Also initialize the counter that it uses
172613a2f6bSGordon Ross * to figure out what value to fill in.
173613a2f6bSGordon Ross *
174613a2f6bSGordon Ross * Note that the byte count happens to be 16-bits,
175613a2f6bSGordon Ross * which can lead to confusion.
176613a2f6bSGordon Ross */
177613a2f6bSGordon Ross void
smb_rq_bstart(struct smb_rq * rqp)178613a2f6bSGordon Ross smb_rq_bstart(struct smb_rq *rqp)
1794bff34e3Sthurlow {
180613a2f6bSGordon Ross struct mbdata *mbp = &rqp->rq_rq;
1814bff34e3Sthurlow
18202d09e03SGordon Ross (void) mb_fit(mbp, 2, &rqp->rq_bcntp);
183613a2f6bSGordon Ross rqp->rq_bcbase = mbp->mb_count;
1844bff34e3Sthurlow }
1854bff34e3Sthurlow
186613a2f6bSGordon Ross /*
187613a2f6bSGordon Ross * Fill in the byte count, in the space reserved by
188613a2f6bSGordon Ross * smb_rq_bstart().
189613a2f6bSGordon Ross */
190613a2f6bSGordon Ross void
smb_rq_bend(struct smb_rq * rqp)191613a2f6bSGordon Ross smb_rq_bend(struct smb_rq *rqp)
1924bff34e3Sthurlow {
193613a2f6bSGordon Ross struct mbdata *mbp = &rqp->rq_rq;
194613a2f6bSGordon Ross int bcnt;
195613a2f6bSGordon Ross
196613a2f6bSGordon Ross if (rqp->rq_bcntp == NULL) {
197613a2f6bSGordon Ross DPRINT("no bcount ptr\n");
198613a2f6bSGordon Ross return;
1994bff34e3Sthurlow }
200613a2f6bSGordon Ross bcnt = mbp->mb_count - rqp->rq_bcbase;
201613a2f6bSGordon Ross if (bcnt > 0xffff)
202613a2f6bSGordon Ross DPRINT("byte count too large (%d)\n", bcnt);
203613a2f6bSGordon Ross /*
204613a2f6bSGordon Ross * Fill in the byte count (16-bits).
205613a2f6bSGordon Ross * Also store it in the rq, in case
206613a2f6bSGordon Ross * we're using the ioctl path.
207613a2f6bSGordon Ross *
208613a2f6bSGordon Ross * The pointer is char * type due to
209613a2f6bSGordon Ross * typical off-by-one alignment.
210613a2f6bSGordon Ross */
211613a2f6bSGordon Ross rqp->rq_bcntp[0] = bcnt & 0xFF;
212613a2f6bSGordon Ross rqp->rq_bcntp[1] = (bcnt >> 8);
213613a2f6bSGordon Ross }
214613a2f6bSGordon Ross
2154bff34e3Sthurlow int
smb_rq_simple(struct smb_rq * rqp)2164bff34e3Sthurlow smb_rq_simple(struct smb_rq *rqp)
2174bff34e3Sthurlow {
2184bff34e3Sthurlow struct smbioc_rq krq;
2194bff34e3Sthurlow struct mbdata *mbp;
22002d09e03SGordon Ross mbuf_t *m;
2214bff34e3Sthurlow char *data;
222613a2f6bSGordon Ross uint32_t len;
223613a2f6bSGordon Ross size_t rpbufsz;
22402d09e03SGordon Ross int error;
2254bff34e3Sthurlow
226613a2f6bSGordon Ross bzero(&krq, sizeof (krq));
227613a2f6bSGordon Ross krq.ioc_cmd = rqp->rq_cmd;
228613a2f6bSGordon Ross
229613a2f6bSGordon Ross /*
230613a2f6bSGordon Ross * Make the SMB request body contiguous,
231613a2f6bSGordon Ross * and fill in the ioctl request.
232613a2f6bSGordon Ross */
2334bff34e3Sthurlow mbp = smb_rq_getrequest(rqp);
23402d09e03SGordon Ross error = m_lineup(mbp->mb_top, &mbp->mb_top);
23502d09e03SGordon Ross if (error)
23602d09e03SGordon Ross return (error);
23702d09e03SGordon Ross
2384bff34e3Sthurlow data = mtod(mbp->mb_top, char *);
239613a2f6bSGordon Ross len = m_totlen(mbp->mb_top);
2404bff34e3Sthurlow
241613a2f6bSGordon Ross /*
242613a2f6bSGordon Ross * _rq_init left space for the SMB header,
243613a2f6bSGordon Ross * which makes mb_count the offset from
244613a2f6bSGordon Ross * the beginning of the header (useful).
245613a2f6bSGordon Ross * However, in this code path the driver
246613a2f6bSGordon Ross * prepends the header, so we skip it.
247613a2f6bSGordon Ross */
248613a2f6bSGordon Ross krq.ioc_tbufsz = len - SMB_HDRLEN;
249613a2f6bSGordon Ross krq.ioc_tbuf = data + SMB_HDRLEN;
250613a2f6bSGordon Ross
251613a2f6bSGordon Ross /*
25202d09e03SGordon Ross * Setup a buffer to hold the reply,
25302d09e03SGordon Ross * at least MIN_REPLY_SIZE, or larger
25402d09e03SGordon Ross * if the caller increased rq_rpbufsz.
255613a2f6bSGordon Ross */
2564bff34e3Sthurlow mbp = smb_rq_getreply(rqp);
257613a2f6bSGordon Ross rpbufsz = rqp->rq_rpbufsz;
25802d09e03SGordon Ross if (rpbufsz < MIN_REPLY_SIZE)
25902d09e03SGordon Ross rpbufsz = MIN_REPLY_SIZE;
26002d09e03SGordon Ross if ((error = m_get(rpbufsz, &m)) != 0)
26102d09e03SGordon Ross return (error);
26202d09e03SGordon Ross mb_initm(mbp, m);
263613a2f6bSGordon Ross krq.ioc_rbufsz = rpbufsz;
26402d09e03SGordon Ross krq.ioc_rbuf = mtod(m, char *);
265613a2f6bSGordon Ross
266613a2f6bSGordon Ross /*
267613a2f6bSGordon Ross * Call the driver
268613a2f6bSGordon Ross */
269613a2f6bSGordon Ross if (ioctl(rqp->rq_ctx->ct_dev_fd, SMBIOC_REQUEST, &krq) == -1)
2704bff34e3Sthurlow return (errno);
271613a2f6bSGordon Ross
272613a2f6bSGordon Ross /*
273613a2f6bSGordon Ross * Initialize returned mbdata.
274613a2f6bSGordon Ross * SMB header already parsed.
275613a2f6bSGordon Ross */
27602d09e03SGordon Ross m->m_len = krq.ioc_rbufsz;
277613a2f6bSGordon Ross
2784bff34e3Sthurlow return (0);
2794bff34e3Sthurlow }
2804bff34e3Sthurlow
2814bff34e3Sthurlow
2824bff34e3Sthurlow int
smb_t2_request(int dev_fd,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)283*430b4c46SGordon Ross smb_t2_request(int dev_fd, int setupcount, uint16_t *setup,
2844bff34e3Sthurlow const char *name,
2854bff34e3Sthurlow int tparamcnt, void *tparam,
2864bff34e3Sthurlow int tdatacnt, void *tdata,
2874bff34e3Sthurlow int *rparamcnt, void *rparam,
2884bff34e3Sthurlow int *rdatacnt, void *rdata,
2894bff34e3Sthurlow int *buffer_oflow)
2904bff34e3Sthurlow {
2914bff34e3Sthurlow smbioc_t2rq_t *krq;
2924bff34e3Sthurlow int i;
2934bff34e3Sthurlow
2944bff34e3Sthurlow krq = (smbioc_t2rq_t *)malloc(sizeof (smbioc_t2rq_t));
2954bff34e3Sthurlow bzero(krq, sizeof (*krq));
2964bff34e3Sthurlow
297613a2f6bSGordon Ross if (setupcount < 0 || setupcount >= SMBIOC_T2RQ_MAXSETUP) {
2984bff34e3Sthurlow /* Bogus setup count, or too many setup words */
2994bff34e3Sthurlow return (EINVAL);
3004bff34e3Sthurlow }
3014bff34e3Sthurlow for (i = 0; i < setupcount; i++)
3024bff34e3Sthurlow krq->ioc_setup[i] = setup[i];
3034bff34e3Sthurlow krq->ioc_setupcnt = setupcount;
3044bff34e3Sthurlow strcpy(krq->ioc_name, name);
3054bff34e3Sthurlow krq->ioc_tparamcnt = tparamcnt;
3064bff34e3Sthurlow krq->ioc_tparam = tparam;
3074bff34e3Sthurlow krq->ioc_tdatacnt = tdatacnt;
3084bff34e3Sthurlow krq->ioc_tdata = tdata;
3094bff34e3Sthurlow
3104bff34e3Sthurlow krq->ioc_rparamcnt = *rparamcnt;
3114bff34e3Sthurlow krq->ioc_rdatacnt = *rdatacnt;
3124bff34e3Sthurlow krq->ioc_rparam = rparam;
3134bff34e3Sthurlow krq->ioc_rdata = rdata;
3144bff34e3Sthurlow
315*430b4c46SGordon Ross if (ioctl(dev_fd, SMBIOC_T2RQ, krq) == -1) {
3164bff34e3Sthurlow return (errno);
3174bff34e3Sthurlow }
3184bff34e3Sthurlow
3194bff34e3Sthurlow *rparamcnt = krq->ioc_rparamcnt;
3204bff34e3Sthurlow *rdatacnt = krq->ioc_rdatacnt;
3214bff34e3Sthurlow *buffer_oflow = (krq->ioc_rpflags2 & SMB_FLAGS2_ERR_STATUS) &&
3224bff34e3Sthurlow (krq->ioc_error == NT_STATUS_BUFFER_OVERFLOW);
3234bff34e3Sthurlow free(krq);
324613a2f6bSGordon Ross
3254bff34e3Sthurlow return (0);
3264bff34e3Sthurlow }
327613a2f6bSGordon Ross
328613a2f6bSGordon Ross
329613a2f6bSGordon Ross /*
330613a2f6bSGordon Ross * Do an over-the-wire call without using the nsmb driver.
331613a2f6bSGordon Ross * This is all "internal" to this library, and used only
332613a2f6bSGordon Ross * for connection setup (negotiate protocol, etc.)
333613a2f6bSGordon Ross */
334613a2f6bSGordon Ross int
smb_rq_internal(struct smb_ctx * ctx,struct smb_rq * rqp)335613a2f6bSGordon Ross smb_rq_internal(struct smb_ctx *ctx, struct smb_rq *rqp)
336613a2f6bSGordon Ross {
337613a2f6bSGordon Ross static const uint8_t ffsmb[4] = SMB_SIGNATURE;
338613a2f6bSGordon Ross struct smb_iods *is = &ctx->ct_iods;
339613a2f6bSGordon Ross uint32_t sigbuf[2];
340613a2f6bSGordon Ross struct mbdata mbtmp, *mbp;
341613a2f6bSGordon Ross int err, save_mlen;
342613a2f6bSGordon Ross uint8_t ctmp;
343613a2f6bSGordon Ross
344613a2f6bSGordon Ross rqp->rq_uid = is->is_smbuid;
345613a2f6bSGordon Ross rqp->rq_tid = SMB_TID_UNKNOWN;
346613a2f6bSGordon Ross rqp->rq_mid = is->is_next_mid++;
347613a2f6bSGordon Ross
348613a2f6bSGordon Ross /*
349613a2f6bSGordon Ross * Fill in the NBT and SMB headers
350613a2f6bSGordon Ross * Using mbtmp so we can rewind without
351613a2f6bSGordon Ross * affecting the passed request mbdata.
352613a2f6bSGordon Ross */
353613a2f6bSGordon Ross bcopy(&rqp->rq_rq, &mbtmp, sizeof (mbtmp));
354613a2f6bSGordon Ross mbp = &mbtmp;
355613a2f6bSGordon Ross mbp->mb_cur = mbp->mb_top;
356613a2f6bSGordon Ross mbp->mb_pos = mbp->mb_cur->m_data;
357613a2f6bSGordon Ross mbp->mb_count = 0;
358613a2f6bSGordon Ross /* Have to save and restore m_len */
359613a2f6bSGordon Ross save_mlen = mbp->mb_cur->m_len;
360613a2f6bSGordon Ross mbp->mb_cur->m_len = 0;
361613a2f6bSGordon Ross
362613a2f6bSGordon Ross /*
363613a2f6bSGordon Ross * rewind done; fill it in
364613a2f6bSGordon Ross */
36502d09e03SGordon Ross mb_put_mem(mbp, ffsmb, SMB_SIGLEN, MB_MSYSTEM);
366613a2f6bSGordon Ross mb_put_uint8(mbp, rqp->rq_cmd);
36702d09e03SGordon Ross mb_put_uint32le(mbp, 0); /* status */
368613a2f6bSGordon Ross mb_put_uint8(mbp, rqp->rq_hflags);
369613a2f6bSGordon Ross mb_put_uint16le(mbp, rqp->rq_hflags2);
37002d09e03SGordon Ross /* pid_hi(2), signature(8), reserved(2) */
37102d09e03SGordon Ross mb_put_mem(mbp, NULL, 12, MB_MZERO);
372613a2f6bSGordon Ross mb_put_uint16le(mbp, rqp->rq_tid);
373613a2f6bSGordon Ross mb_put_uint16le(mbp, 0); /* pid_lo */
374613a2f6bSGordon Ross mb_put_uint16le(mbp, rqp->rq_uid);
375613a2f6bSGordon Ross mb_put_uint16le(mbp, rqp->rq_mid);
376613a2f6bSGordon Ross
377613a2f6bSGordon Ross /* Restore original m_len */
378613a2f6bSGordon Ross mbp->mb_cur->m_len = save_mlen;
379613a2f6bSGordon Ross
380613a2f6bSGordon Ross /*
381613a2f6bSGordon Ross * Sign the message, if flags2 indicates.
382613a2f6bSGordon Ross */
383613a2f6bSGordon Ross if (rqp->rq_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
384613a2f6bSGordon Ross smb_rq_sign(rqp);
385613a2f6bSGordon Ross }
386613a2f6bSGordon Ross
387613a2f6bSGordon Ross /*
388613a2f6bSGordon Ross * Send it, wait for the reply.
389613a2f6bSGordon Ross */
390613a2f6bSGordon Ross if ((err = smb_ssn_send(ctx, &rqp->rq_rq)) != 0)
391613a2f6bSGordon Ross return (err);
392613a2f6bSGordon Ross
393613a2f6bSGordon Ross if ((err = smb_ssn_recv(ctx, &rqp->rq_rp)) != 0)
394613a2f6bSGordon Ross return (err);
395613a2f6bSGordon Ross
396613a2f6bSGordon Ross /*
397613a2f6bSGordon Ross * Should have an SMB header, at least.
398613a2f6bSGordon Ross */
399613a2f6bSGordon Ross mbp = &rqp->rq_rp;
400613a2f6bSGordon Ross if (mbp->mb_cur->m_len < SMB_HDRLEN) {
401613a2f6bSGordon Ross DPRINT("len < 32");
402613a2f6bSGordon Ross return (EBADRPC);
403613a2f6bSGordon Ross }
404613a2f6bSGordon Ross
405613a2f6bSGordon Ross /*
406613a2f6bSGordon Ross * If the request was signed, validate the
407613a2f6bSGordon Ross * signature on the response.
408613a2f6bSGordon Ross */
409613a2f6bSGordon Ross if (rqp->rq_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
410613a2f6bSGordon Ross err = smb_rq_verify(rqp);
411613a2f6bSGordon Ross if (err) {
412613a2f6bSGordon Ross DPRINT("bad signature");
413613a2f6bSGordon Ross return (err);
414613a2f6bSGordon Ross }
415613a2f6bSGordon Ross }
416613a2f6bSGordon Ross
417613a2f6bSGordon Ross /*
418613a2f6bSGordon Ross * Decode the SMB header.
419613a2f6bSGordon Ross */
42002d09e03SGordon Ross md_get_mem(mbp, (char *)sigbuf, 4, MB_MSYSTEM);
421613a2f6bSGordon Ross if (0 != bcmp(sigbuf, ffsmb, 4)) {
422613a2f6bSGordon Ross DPRINT("not SMB");
423613a2f6bSGordon Ross return (EBADRPC);
424613a2f6bSGordon Ross }
42502d09e03SGordon Ross md_get_uint8(mbp, &ctmp); /* SMB cmd */
42602d09e03SGordon Ross md_get_uint32le(mbp, &rqp->rq_status);
42702d09e03SGordon Ross md_get_uint8(mbp, &rqp->rq_hflags);
42802d09e03SGordon Ross md_get_uint16le(mbp, &rqp->rq_hflags2);
42902d09e03SGordon Ross /* pid_hi(2), signature(8), reserved(2) */
43002d09e03SGordon Ross md_get_mem(mbp, NULL, 12, MB_MSYSTEM);
43102d09e03SGordon Ross md_get_uint16le(mbp, &rqp->rq_tid);
43202d09e03SGordon Ross md_get_uint16le(mbp, NULL); /* pid_lo */
43302d09e03SGordon Ross md_get_uint16le(mbp, &rqp->rq_uid);
43402d09e03SGordon Ross md_get_uint16le(mbp, &rqp->rq_mid);
435613a2f6bSGordon Ross
436613a2f6bSGordon Ross /*
437613a2f6bSGordon Ross * Figure out the status return.
438613a2f6bSGordon Ross * Caller looks at rq_status.
439613a2f6bSGordon Ross */
440613a2f6bSGordon Ross if ((rqp->rq_hflags2 & SMB_FLAGS2_ERR_STATUS) == 0) {
441613a2f6bSGordon Ross uint16_t serr;
442613a2f6bSGordon Ross uint8_t class;
443613a2f6bSGordon Ross
444613a2f6bSGordon Ross class = rqp->rq_status & 0xff;
445613a2f6bSGordon Ross serr = rqp->rq_status >> 16;
446613a2f6bSGordon Ross rqp->rq_status = smb_map_doserr(class, serr);
447613a2f6bSGordon Ross }
448613a2f6bSGordon Ross
449613a2f6bSGordon Ross return (0);
450613a2f6bSGordon Ross }
451613a2f6bSGordon Ross
452613a2f6bSGordon Ross /*
453613a2f6bSGordon Ross * Map old DOS errors (etc.) to NT status codes.
454613a2f6bSGordon Ross * We probably don't need this anymore, since
455613a2f6bSGordon Ross * the oldest server we talk to is NT. But if
456613a2f6bSGordon Ross * later find we do need this, add support here
457613a2f6bSGordon Ross * for the DOS errors we care about.
458613a2f6bSGordon Ross */
459613a2f6bSGordon Ross static uint32_t
smb_map_doserr(uint8_t class,uint16_t serr)460613a2f6bSGordon Ross smb_map_doserr(uint8_t class, uint16_t serr)
461613a2f6bSGordon Ross {
462613a2f6bSGordon Ross if (class == 0 && serr == 0)
463613a2f6bSGordon Ross return (0);
464613a2f6bSGordon Ross
465613a2f6bSGordon Ross DPRINT("class 0x%x serr 0x%x", (int)class, (int)serr);
466613a2f6bSGordon Ross return (NT_STATUS_UNSUCCESSFUL);
467613a2f6bSGordon Ross }
468