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