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 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 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 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 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 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 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 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 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 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 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