Home | History | Annotate | Download | only in smb
      1 /*
      2  * Copyright (c) 2000, Boris Popov
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *    This product includes software developed by Boris Popov.
     16  * 4. Neither the name of the author nor the names of any co-contributors
     17  *    may be used to endorse or promote products derived from this software
     18  *    without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     30  * SUCH DAMAGE.
     31  *
     32  * $Id: rq.c,v 1.4 2004/12/13 00:25:23 lindak Exp $
     33  */
     34 
     35 #include <sys/types.h>
     36 #include <sys/param.h>
     37 #include <sys/ioctl.h>
     38 #include <sys/errno.h>
     39 #include <sys/stat.h>
     40 
     41 #include <ctype.h>
     42 #include <errno.h>
     43 #include <stdio.h>
     44 #include <unistd.h>
     45 #include <strings.h>
     46 #include <stdlib.h>
     47 #include <sysexits.h>
     48 #include <libintl.h>
     49 
     50 #include <netsmb/smb.h>
     51 #include <netsmb/smb_lib.h>
     52 #include "private.h"
     53 
     54 #define	MIN_REPLY_SIZE 4096
     55 
     56 static uint32_t smb_map_doserr(uint8_t, uint16_t);
     57 
     58 /*
     59  * Create and initialize a request structure, for either an
     60  * "internal" request (one that does not use the driver) or
     61  * a regular "driver" request, that uses driver ioctls.
     62  *
     63  * The two kinds are built a little differently:
     64  * Driver requests are composed starting with the
     65  * first word of the "variable word vector" section.
     66  * The driver prepends the SMB header and word count.
     67  * The driver also needs an output buffer to receive
     68  * the response, filled in via copyout in the ioctl.
     69  *
     70  * Internal requests are composed entirely in this library.
     71  * Space for the SMB header is reserved here, and later
     72  * filled in by smb_rq_internal before the send/receive.
     73  */
     74 int
     75 smb_rq_init(struct smb_ctx *ctx, uchar_t cmd, struct smb_rq **rqpp)
     76 {
     77 	struct smb_rq *rqp;
     78 
     79 	rqp = malloc(sizeof (*rqp));
     80 	if (rqp == NULL)
     81 		goto errout;
     82 	bzero(rqp, sizeof (*rqp));
     83 	rqp->rq_cmd = cmd;
     84 	rqp->rq_ctx = ctx;
     85 
     86 	/*
     87 	 * Setup the request buffer.
     88 	 * Do the reply buffer later.
     89 	 */
     90 	if (mb_init(&rqp->rq_rq))
     91 		goto errout;
     92 
     93 	/* Space for the SMB header. (filled in later) */
     94 	mb_put_mem(&rqp->rq_rq, NULL, SMB_HDRLEN, MB_MSYSTEM);
     95 
     96 	/*
     97 	 * Copy the ctx flags here, so the caller can
     98 	 * update the req flags before the OTW call.
     99 	 */
    100 	rqp->rq_hflags = ctx->ct_hflags;
    101 	rqp->rq_hflags2 = ctx->ct_hflags2;
    102 
    103 	*rqpp = rqp;
    104 	return (0);
    105 
    106 errout:
    107 	if (rqp) {
    108 		smb_rq_done(rqp);
    109 		free(rqp);
    110 	}
    111 	return (ENOMEM);
    112 }
    113 
    114 void
    115 smb_rq_done(struct smb_rq *rqp)
    116 {
    117 	mb_done(&rqp->rq_rp);
    118 	mb_done(&rqp->rq_rq);
    119 	free(rqp);
    120 }
    121 
    122 /*
    123  * Reserve space for the word count, which is filled in later by
    124  * smb_rq_wend().  Also initialize the counter that it uses
    125  * to figure out what value to fill in.
    126  *
    127  * Note that the word count happens to be 8-bits,
    128  * which can lead to confusion.
    129  */
    130 void
    131 smb_rq_wstart(struct smb_rq *rqp)
    132 {
    133 	struct mbdata *mbp = &rqp->rq_rq;
    134 
    135 	(void) mb_fit(mbp, 1, &rqp->rq_wcntp);
    136 	rqp->rq_wcbase = mbp->mb_count;
    137 }
    138 
    139 /*
    140  * Fill in the word count, in the space reserved by
    141  * smb_rq_wstart().
    142  */
    143 void
    144 smb_rq_wend(struct smb_rq *rqp)
    145 {
    146 	struct mbdata *mbp = &rqp->rq_rq;
    147 	int wcnt;
    148 
    149 	if (rqp->rq_wcntp == NULL) {
    150 		DPRINT("no wcount ptr\n");
    151 		return;
    152 	}
    153 	wcnt = mbp->mb_count - rqp->rq_wcbase;
    154 	if (wcnt > 0x1ff)
    155 		DPRINT("word count too large (%d)\n", wcnt);
    156 	if (wcnt & 1)
    157 		DPRINT("odd word count\n");
    158 	wcnt >>= 1;
    159 
    160 	/*
    161 	 * Fill in the word count (8-bits).
    162 	 * Also store it in the rq, in case
    163 	 * we're using the ioctl path.
    164 	 */
    165 	*rqp->rq_wcntp = (char)wcnt;
    166 }
    167 
    168 /*
    169  * Reserve space for the byte count, which is filled in later by
    170  * smb_rq_bend().  Also initialize the counter that it uses
    171  * to figure out what value to fill in.
    172  *
    173  * Note that the byte count happens to be 16-bits,
    174  * which can lead to confusion.
    175  */
    176 void
    177 smb_rq_bstart(struct smb_rq *rqp)
    178 {
    179 	struct mbdata *mbp = &rqp->rq_rq;
    180 
    181 	(void) mb_fit(mbp, 2, &rqp->rq_bcntp);
    182 	rqp->rq_bcbase = mbp->mb_count;
    183 }
    184 
    185 /*
    186  * Fill in the byte count, in the space reserved by
    187  * smb_rq_bstart().
    188  */
    189 void
    190 smb_rq_bend(struct smb_rq *rqp)
    191 {
    192 	struct mbdata *mbp = &rqp->rq_rq;
    193 	int bcnt;
    194 
    195 	if (rqp->rq_bcntp == NULL) {
    196 		DPRINT("no bcount ptr\n");
    197 		return;
    198 	}
    199 	bcnt = mbp->mb_count - rqp->rq_bcbase;
    200 	if (bcnt > 0xffff)
    201 		DPRINT("byte count too large (%d)\n", bcnt);
    202 	/*
    203 	 * Fill in the byte count (16-bits).
    204 	 * Also store it in the rq, in case
    205 	 * we're using the ioctl path.
    206 	 *
    207 	 * The pointer is char * type due to
    208 	 * typical off-by-one alignment.
    209 	 */
    210 	rqp->rq_bcntp[0] = bcnt & 0xFF;
    211 	rqp->rq_bcntp[1] = (bcnt >> 8);
    212 }
    213 
    214 int
    215 smb_rq_simple(struct smb_rq *rqp)
    216 {
    217 	struct smbioc_rq krq;
    218 	struct mbdata *mbp;
    219 	mbuf_t *m;
    220 	char *data;
    221 	uint32_t len;
    222 	size_t rpbufsz;
    223 	int error;
    224 
    225 	bzero(&krq, sizeof (krq));
    226 	krq.ioc_cmd = rqp->rq_cmd;
    227 
    228 	/*
    229 	 * Make the SMB request body contiguous,
    230 	 * and fill in the ioctl request.
    231 	 */
    232 	mbp = smb_rq_getrequest(rqp);
    233 	error = m_lineup(mbp->mb_top, &mbp->mb_top);
    234 	if (error)
    235 		return (error);
    236 
    237 	data = mtod(mbp->mb_top, char *);
    238 	len = m_totlen(mbp->mb_top);
    239 
    240 	/*
    241 	 * _rq_init left space for the SMB header,
    242 	 * which makes mb_count the offset from
    243 	 * the beginning of the header (useful).
    244 	 * However, in this code path the driver
    245 	 * prepends the header, so we skip it.
    246 	 */
    247 	krq.ioc_tbufsz = len - SMB_HDRLEN;
    248 	krq.ioc_tbuf  = data + SMB_HDRLEN;
    249 
    250 	/*
    251 	 * Setup a buffer to hold the reply,
    252 	 * at least MIN_REPLY_SIZE, or larger
    253 	 * if the caller increased rq_rpbufsz.
    254 	 */
    255 	mbp = smb_rq_getreply(rqp);
    256 	rpbufsz = rqp->rq_rpbufsz;
    257 	if (rpbufsz < MIN_REPLY_SIZE)
    258 		rpbufsz = MIN_REPLY_SIZE;
    259 	if ((error = m_get(rpbufsz, &m)) != 0)
    260 		return (error);
    261 	mb_initm(mbp, m);
    262 	krq.ioc_rbufsz = rpbufsz;
    263 	krq.ioc_rbuf = mtod(m, char *);
    264 
    265 	/*
    266 	 * Call the driver
    267 	 */
    268 	if (ioctl(rqp->rq_ctx->ct_dev_fd, SMBIOC_REQUEST, &krq) == -1)
    269 		return (errno);
    270 
    271 	/*
    272 	 * Initialize returned mbdata.
    273 	 * SMB header already parsed.
    274 	 */
    275 	m->m_len = krq.ioc_rbufsz;
    276 
    277 	return (0);
    278 }
    279 
    280 
    281 int
    282 smb_t2_request(struct smb_ctx *ctx, int setupcount, uint16_t *setup,
    283 	const char *name,
    284 	int tparamcnt, void *tparam,
    285 	int tdatacnt, void *tdata,
    286 	int *rparamcnt, void *rparam,
    287 	int *rdatacnt, void *rdata,
    288 	int *buffer_oflow)
    289 {
    290 	smbioc_t2rq_t *krq;
    291 	int i;
    292 
    293 	krq = (smbioc_t2rq_t *)malloc(sizeof (smbioc_t2rq_t));
    294 	bzero(krq, sizeof (*krq));
    295 
    296 	if (setupcount < 0 || setupcount >= SMBIOC_T2RQ_MAXSETUP) {
    297 		/* Bogus setup count, or too many setup words */
    298 		return (EINVAL);
    299 	}
    300 	for (i = 0; i < setupcount; i++)
    301 		krq->ioc_setup[i] = setup[i];
    302 	krq->ioc_setupcnt = setupcount;
    303 	strcpy(krq->ioc_name, name);
    304 	krq->ioc_tparamcnt = tparamcnt;
    305 	krq->ioc_tparam = tparam;
    306 	krq->ioc_tdatacnt = tdatacnt;
    307 	krq->ioc_tdata = tdata;
    308 
    309 	krq->ioc_rparamcnt = *rparamcnt;
    310 	krq->ioc_rdatacnt = *rdatacnt;
    311 	krq->ioc_rparam = rparam;
    312 	krq->ioc_rdata  = rdata;
    313 
    314 	if (ioctl(ctx->ct_dev_fd, SMBIOC_T2RQ, krq) == -1) {
    315 		return (errno);
    316 	}
    317 
    318 	*rparamcnt = krq->ioc_rparamcnt;
    319 	*rdatacnt = krq->ioc_rdatacnt;
    320 	*buffer_oflow = (krq->ioc_rpflags2 & SMB_FLAGS2_ERR_STATUS) &&
    321 	    (krq->ioc_error == NT_STATUS_BUFFER_OVERFLOW);
    322 	free(krq);
    323 
    324 	return (0);
    325 }
    326 
    327 
    328 /*
    329  * Do an over-the-wire call without using the nsmb driver.
    330  * This is all "internal" to this library, and used only
    331  * for connection setup (negotiate protocol, etc.)
    332  */
    333 int
    334 smb_rq_internal(struct smb_ctx *ctx, struct smb_rq *rqp)
    335 {
    336 	static const uint8_t ffsmb[4] = SMB_SIGNATURE;
    337 	struct smb_iods *is = &ctx->ct_iods;
    338 	uint32_t sigbuf[2];
    339 	struct mbdata mbtmp, *mbp;
    340 	int err, save_mlen;
    341 	uint8_t ctmp;
    342 
    343 	rqp->rq_uid = is->is_smbuid;
    344 	rqp->rq_tid = SMB_TID_UNKNOWN;
    345 	rqp->rq_mid = is->is_next_mid++;
    346 
    347 	/*
    348 	 * Fill in the NBT and SMB headers
    349 	 * Using mbtmp so we can rewind without
    350 	 * affecting the passed request mbdata.
    351 	 */
    352 	bcopy(&rqp->rq_rq, &mbtmp, sizeof (mbtmp));
    353 	mbp = &mbtmp;
    354 	mbp->mb_cur = mbp->mb_top;
    355 	mbp->mb_pos = mbp->mb_cur->m_data;
    356 	mbp->mb_count = 0;
    357 	/* Have to save and restore m_len */
    358 	save_mlen = mbp->mb_cur->m_len;
    359 	mbp->mb_cur->m_len = 0;
    360 
    361 	/*
    362 	 * rewind done; fill it in
    363 	 */
    364 	mb_put_mem(mbp, ffsmb, SMB_SIGLEN, MB_MSYSTEM);
    365 	mb_put_uint8(mbp, rqp->rq_cmd);
    366 	mb_put_uint32le(mbp, 0);	/* status */
    367 	mb_put_uint8(mbp, rqp->rq_hflags);
    368 	mb_put_uint16le(mbp, rqp->rq_hflags2);
    369 	/* pid_hi(2), signature(8), reserved(2) */
    370 	mb_put_mem(mbp, NULL, 12, MB_MZERO);
    371 	mb_put_uint16le(mbp, rqp->rq_tid);
    372 	mb_put_uint16le(mbp, 0);	/* pid_lo */
    373 	mb_put_uint16le(mbp, rqp->rq_uid);
    374 	mb_put_uint16le(mbp, rqp->rq_mid);
    375 
    376 	/* Restore original m_len */
    377 	mbp->mb_cur->m_len = save_mlen;
    378 
    379 	/*
    380 	 * Sign the message, if flags2 indicates.
    381 	 */
    382 	if (rqp->rq_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
    383 		smb_rq_sign(rqp);
    384 	}
    385 
    386 	/*
    387 	 * Send it, wait for the reply.
    388 	 */
    389 	if ((err = smb_ssn_send(ctx, &rqp->rq_rq)) != 0)
    390 		return (err);
    391 
    392 	if ((err = smb_ssn_recv(ctx, &rqp->rq_rp)) != 0)
    393 		return (err);
    394 
    395 	/*
    396 	 * Should have an SMB header, at least.
    397 	 */
    398 	mbp = &rqp->rq_rp;
    399 	if (mbp->mb_cur->m_len < SMB_HDRLEN) {
    400 		DPRINT("len < 32");
    401 		return (EBADRPC);
    402 	}
    403 
    404 	/*
    405 	 * If the request was signed, validate the
    406 	 * signature on the response.
    407 	 */
    408 	if (rqp->rq_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
    409 		err = smb_rq_verify(rqp);
    410 		if (err) {
    411 			DPRINT("bad signature");
    412 			return (err);
    413 		}
    414 	}
    415 
    416 	/*
    417 	 * Decode the SMB header.
    418 	 */
    419 	md_get_mem(mbp, (char *)sigbuf, 4, MB_MSYSTEM);
    420 	if (0 != bcmp(sigbuf, ffsmb, 4)) {
    421 		DPRINT("not SMB");
    422 		return (EBADRPC);
    423 	}
    424 	md_get_uint8(mbp, &ctmp);	/* SMB cmd */
    425 	md_get_uint32le(mbp, &rqp->rq_status);
    426 	md_get_uint8(mbp, &rqp->rq_hflags);
    427 	md_get_uint16le(mbp, &rqp->rq_hflags2);
    428 	/* pid_hi(2), signature(8), reserved(2) */
    429 	md_get_mem(mbp, NULL, 12, MB_MSYSTEM);
    430 	md_get_uint16le(mbp, &rqp->rq_tid);
    431 	md_get_uint16le(mbp, NULL);	/* pid_lo */
    432 	md_get_uint16le(mbp, &rqp->rq_uid);
    433 	md_get_uint16le(mbp, &rqp->rq_mid);
    434 
    435 	/*
    436 	 * Figure out the status return.
    437 	 * Caller looks at rq_status.
    438 	 */
    439 	if ((rqp->rq_hflags2 & SMB_FLAGS2_ERR_STATUS) == 0) {
    440 		uint16_t	serr;
    441 		uint8_t		class;
    442 
    443 		class = rqp->rq_status & 0xff;
    444 		serr  = rqp->rq_status >> 16;
    445 		rqp->rq_status = smb_map_doserr(class, serr);
    446 	}
    447 
    448 	return (0);
    449 }
    450 
    451 /*
    452  * Map old DOS errors (etc.) to NT status codes.
    453  * We probably don't need this anymore, since
    454  * the oldest server we talk to is NT.  But if
    455  * later find we do need this, add support here
    456  * for the DOS errors we care about.
    457  */
    458 static uint32_t
    459 smb_map_doserr(uint8_t class, uint16_t serr)
    460 {
    461 	if (class == 0 && serr == 0)
    462 		return (0);
    463 
    464 	DPRINT("class 0x%x serr 0x%x", (int)class, (int)serr);
    465 	return (NT_STATUS_UNSUCCESSFUL);
    466 }
    467