1 /* 2 * Copyright (c) 2000-2001 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: smb_smb.c,v 1.35.100.2 2005/06/02 00:55:39 lindak Exp $ 33 */ 34 35 /* 36 * Copyright 2012 Nexenta Systems, Inc. All rights reserved. 37 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 38 */ 39 40 /* 41 * various SMB requests. Most of the routines merely packs data into mbufs. 42 */ 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/kmem.h> 46 #include <sys/proc.h> 47 #include <sys/lock.h> 48 #include <sys/socket.h> 49 #include <sys/uio.h> 50 #include <sys/random.h> 51 #include <sys/note.h> 52 #include <sys/cmn_err.h> 53 54 #include <netsmb/smb_osdep.h> 55 56 #include <netsmb/smb.h> 57 #include <netsmb/smb_conn.h> 58 #include <netsmb/smb_rq.h> 59 #include <netsmb/smb_subr.h> 60 #include <netsmb/smb_tran.h> 61 62 #define STYPE_LEN 8 /* share type strings */ 63 64 /* 65 * Largest size to use with LARGE_READ/LARGE_WRITE. 66 * Specs say up to 64k data bytes, but Windows traffic 67 * uses 60k... no doubt for some good reason. 68 * (Probably to keep 4k block alignment.) 69 * XXX: Move to smb.h maybe? 70 */ 71 #define SMB_MAX_LARGE_RW_SIZE (60*1024) 72 73 /* 74 * Default timeout values, all in seconds. 75 * Make these tunable (only via mdb for now). 76 */ 77 int smb_timo_notice = 15; 78 int smb_timo_default = 30; /* was SMB_DEFRQTIMO */ 79 int smb_timo_open = 45; 80 int smb_timo_read = 45; 81 int smb_timo_write = 60; /* was SMBWRTTIMO */ 82 int smb_timo_append = 90; 83 84 static int smb_smb_read(struct smb_share *ssp, uint16_t fid, 85 uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo); 86 static int smb_smb_write(struct smb_share *ssp, uint16_t fid, 87 uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo); 88 89 static int smb_smb_readx(struct smb_share *ssp, uint16_t fid, 90 uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo); 91 static int smb_smb_writex(struct smb_share *ssp, uint16_t fid, 92 uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo); 93 94 /* 95 * Get the string representation of a share "use" type, 96 * as needed for the "service" in tree connect. 97 */ 98 static const char * 99 smb_share_typename(uint32_t stype) 100 { 101 const char *p; 102 103 switch (stype) { 104 case STYPE_DISKTREE: 105 p = "A:"; 106 break; 107 case STYPE_PRINTQ: 108 p = "LPT1:"; 109 break; 110 case STYPE_DEVICE: 111 p = "COMM"; 112 break; 113 case STYPE_IPC: 114 p = "IPC"; 115 break; 116 case STYPE_UNKNOWN: 117 default: 118 p = "?????"; 119 break; 120 } 121 return (p); 122 } 123 124 /* 125 * Parse a share type name (inverse of above) 126 */ 127 static uint32_t 128 smb_share_parsetype(char *name) 129 { 130 int stype; 131 132 switch (*name) { 133 case 'A': /* A: */ 134 stype = STYPE_DISKTREE; 135 break; 136 case 'C': /* COMM */ 137 stype = STYPE_DEVICE; 138 break; 139 case 'I': /* IPC */ 140 stype = STYPE_IPC; 141 break; 142 case 'L': /* LPT: */ 143 stype = STYPE_PRINTQ; 144 break; 145 default: 146 stype = STYPE_UNKNOWN; 147 break; 148 } 149 return (stype); 150 } 151 152 int 153 smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred) 154 { 155 struct smb_vc *vcp; 156 struct smb_rq *rqp = NULL; 157 struct mbchain *mbp; 158 struct mdchain *mdp; 159 const char *tname; 160 char *pbuf, *unc_name = NULL; 161 int error, tlen, plen, unc_len; 162 uint16_t bcnt, options; 163 uint8_t wc; 164 char stype_str[STYPE_LEN]; 165 166 vcp = SSTOVC(ssp); 167 168 /* 169 * Make this a "VC-level" request, so it will have 170 * rqp->sr_share == NULL, and smb_iod_sendrq() 171 * will send it with TID = SMB_TID_UNKNOWN 172 * 173 * This also serves to bypass the wait for 174 * share state changes, which this call is 175 * trying to carry out. 176 */ 177 error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_TREE_CONNECT_ANDX, 178 scred, &rqp); 179 if (error) 180 return (error); 181 182 /* 183 * Build the UNC name, i.e. "//server/share" 184 * but with backslashes of course. 185 * size math: three slashes, one null. 186 */ 187 unc_len = 4 + strlen(vcp->vc_srvname) + strlen(ssp->ss_name); 188 unc_name = kmem_alloc(unc_len, KM_SLEEP); 189 (void) snprintf(unc_name, unc_len, "\\\\%s\\%s", 190 vcp->vc_srvname, ssp->ss_name); 191 SMBSDEBUG("unc_name: \"%s\"", unc_name); 192 193 194 /* 195 * Share-level password (pre-computed in user-space) 196 * MS-SMB 2.2.6 says this should be null terminated, 197 * and the pw length includes the null. 198 */ 199 pbuf = ssp->ss_pass; 200 plen = strlen(pbuf) + 1; 201 202 /* 203 * Build the request. 204 */ 205 mbp = &rqp->sr_rq; 206 smb_rq_wstart(rqp); 207 mb_put_uint8(mbp, 0xff); 208 mb_put_uint8(mbp, 0); 209 mb_put_uint16le(mbp, 0); 210 mb_put_uint16le(mbp, 0); /* Flags */ 211 mb_put_uint16le(mbp, plen); 212 smb_rq_wend(rqp); 213 smb_rq_bstart(rqp); 214 215 /* Tree connect password, if any */ 216 error = mb_put_mem(mbp, pbuf, plen, MB_MSYSTEM); 217 if (error) 218 goto out; 219 220 /* UNC resource name */ 221 error = smb_put_dstring(mbp, vcp, unc_name, SMB_CS_NONE); 222 if (error) 223 goto out; 224 225 /* 226 * Put the type string (always ASCII), 227 * including the null. 228 */ 229 tname = smb_share_typename(ssp->ss_use); 230 tlen = strlen(tname) + 1; 231 error = mb_put_mem(mbp, tname, tlen, MB_MSYSTEM); 232 if (error) 233 goto out; 234 235 smb_rq_bend(rqp); 236 237 /* 238 * Run the request. 239 * 240 * Using NOINTR_RECV because we don't want to risk 241 * missing a successful tree connect response, 242 * which would "leak" Tree IDs. 243 */ 244 rqp->sr_flags |= SMBR_NOINTR_RECV; 245 error = smb_rq_simple(rqp); 246 SMBSDEBUG("%d\n", error); 247 if (error) { 248 /* 249 * If we get the server name wrong, i.e. due to 250 * mis-configured name services, this will be 251 * NT_STATUS_DUPLICATE_NAME. Log this error. 252 */ 253 SMBERROR("(%s) failed, status=0x%x", 254 unc_name, rqp->sr_error); 255 goto out; 256 } 257 258 /* 259 * Parse the TCON response 260 */ 261 smb_rq_getreply(rqp, &mdp); 262 md_get_uint8(mdp, &wc); 263 if (wc != 3 && wc != 7) { 264 error = EBADRPC; 265 goto out; 266 } 267 md_get_uint16le(mdp, NULL); /* AndX cmd */ 268 md_get_uint16le(mdp, NULL); /* AndX off */ 269 md_get_uint16le(mdp, &options); /* option bits (DFS, search) */ 270 if (wc == 7) { 271 md_get_uint32le(mdp, NULL); /* MaximalShareAccessRights */ 272 md_get_uint32le(mdp, NULL); /* GuestMaximalShareAcc... */ 273 } 274 error = md_get_uint16le(mdp, &bcnt); /* byte count */ 275 if (error) 276 goto out; 277 278 /* 279 * Get the returned share type string, i.e. "IPC" or whatever. 280 * (See smb_share_typename, smb_share_parsetype). If we get 281 * an error reading the type, just say STYPE_UNKNOWN. 282 */ 283 tlen = STYPE_LEN; 284 bzero(stype_str, tlen--); 285 if (tlen > bcnt) 286 tlen = bcnt; 287 md_get_mem(mdp, stype_str, tlen, MB_MSYSTEM); 288 stype_str[tlen] = '\0'; 289 ssp->ss_type = smb_share_parsetype(stype_str); 290 291 /* Success! */ 292 SMB_SS_LOCK(ssp); 293 ssp->ss_tid = rqp->sr_rptid; 294 ssp->ss_vcgenid = vcp->vc_genid; 295 ssp->ss_options = options; 296 ssp->ss_flags |= SMBS_CONNECTED; 297 SMB_SS_UNLOCK(ssp); 298 299 out: 300 if (unc_name) 301 kmem_free(unc_name, unc_len); 302 smb_rq_done(rqp); 303 return (error); 304 } 305 306 int 307 smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred) 308 { 309 struct smb_vc *vcp; 310 struct smb_rq *rqp; 311 int error; 312 313 if (ssp->ss_tid == SMB_TID_UNKNOWN) 314 return (0); 315 316 /* 317 * Build this as a "VC-level" request, so it will 318 * avoid testing the _GONE flag on the share, 319 * which has already been set at this point. 320 * Add the share pointer "by hand" below, so 321 * smb_iod_sendrq will plug in the TID. 322 */ 323 vcp = SSTOVC(ssp); 324 error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_TREE_DISCONNECT, scred, &rqp); 325 if (error) 326 return (error); 327 rqp->sr_share = ssp; /* by hand */ 328 329 smb_rq_wstart(rqp); 330 smb_rq_wend(rqp); 331 smb_rq_bstart(rqp); 332 smb_rq_bend(rqp); 333 334 /* 335 * Run this with a relatively short timeout. (5 sec.) 336 * We don't really care about the result here, but we 337 * do need to make sure we send this out, or we could 338 * "leak" active tree IDs on interrupt or timeout. 339 * The NOINTR_SEND flag makes this request immune to 340 * interrupt or timeout until the send is done. 341 * Also, don't reconnect for this, of course! 342 */ 343 rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT); 344 error = smb_rq_simple_timed(rqp, 5); 345 SMBSDEBUG("%d\n", error); 346 smb_rq_done(rqp); 347 ssp->ss_tid = SMB_TID_UNKNOWN; 348 return (error); 349 } 350 351 /* 352 * Modern create/open of file or directory. 353 */ 354 int 355 smb_smb_ntcreate( 356 struct smb_share *ssp, 357 struct mbchain *name_mb, 358 uint32_t cr_flags, /* create flags */ 359 uint32_t req_acc, /* requested access */ 360 uint32_t efa, /* ext. file attrs (DOS attr +) */ 361 uint32_t share_acc, 362 uint32_t open_disp, /* open disposition */ 363 uint32_t createopt, /* NTCREATEX_OPTIONS_ */ 364 uint32_t impersonate, /* NTCREATEX_IMPERSONATION_... */ 365 struct smb_cred *scrp, 366 uint16_t *fidp, /* returned FID */ 367 uint32_t *cr_act_p, /* optional create action */ 368 struct smbfattr *fap) /* optional attributes */ 369 { 370 struct smb_rq rq, *rqp = &rq; 371 struct smb_vc *vcp = SSTOVC(ssp); 372 struct mbchain *mbp; 373 struct mdchain *mdp; 374 struct smbfattr fa; 375 uint64_t llongint; 376 uint32_t longint, createact; 377 uint16_t fid; 378 uint8_t wc; 379 int error; 380 381 bzero(&fa, sizeof (fa)); 382 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_NT_CREATE_ANDX, scrp); 383 if (error) 384 return (error); 385 smb_rq_getrequest(rqp, &mbp); 386 387 /* Word parameters */ 388 smb_rq_wstart(rqp); 389 mb_put_uint8(mbp, 0xff); /* secondary command */ 390 mb_put_uint8(mbp, 0); /* MBZ */ 391 mb_put_uint16le(mbp, 0); /* offset to next command (none) */ 392 mb_put_uint8(mbp, 0); /* MBZ */ 393 mb_put_uint16le(mbp, name_mb->mb_count); 394 mb_put_uint32le(mbp, cr_flags); /* NTCREATEX_FLAGS_* */ 395 mb_put_uint32le(mbp, 0); /* FID - basis for path if not root */ 396 mb_put_uint32le(mbp, req_acc); 397 mb_put_uint64le(mbp, 0); /* "initial allocation size" */ 398 mb_put_uint32le(mbp, efa); 399 mb_put_uint32le(mbp, share_acc); 400 mb_put_uint32le(mbp, open_disp); 401 mb_put_uint32le(mbp, createopt); 402 mb_put_uint32le(mbp, impersonate); 403 mb_put_uint8(mbp, 0); /* security flags (?) */ 404 smb_rq_wend(rqp); 405 406 /* 407 * Byte parameters: Just the path name, aligned. 408 * Note: mb_put_mbuf consumes mb_top, so clear it. 409 */ 410 smb_rq_bstart(rqp); 411 if (SMB_UNICODE_STRINGS(vcp)) 412 mb_put_padbyte(mbp); 413 mb_put_mbuf(mbp, name_mb->mb_top); 414 bzero(name_mb, sizeof (*name_mb)); 415 smb_rq_bend(rqp); 416 417 /* 418 * Don't want to risk missing a successful 419 * open response, or we could "leak" FIDs. 420 */ 421 rqp->sr_flags |= SMBR_NOINTR_RECV; 422 error = smb_rq_simple_timed(rqp, smb_timo_open); 423 if (error) 424 goto done; 425 smb_rq_getreply(rqp, &mdp); 426 /* 427 * spec says 26 for word count, but 34 words are defined 428 * and observed from win2000 429 */ 430 error = md_get_uint8(mdp, &wc); 431 if (error) 432 goto done; 433 if (wc != 26 && wc < 34) { 434 error = EBADRPC; 435 goto done; 436 } 437 md_get_uint8(mdp, NULL); /* secondary cmd */ 438 md_get_uint8(mdp, NULL); /* mbz */ 439 md_get_uint16le(mdp, NULL); /* andxoffset */ 440 md_get_uint8(mdp, NULL); /* oplock lvl granted */ 441 md_get_uint16le(mdp, &fid); /* file ID */ 442 md_get_uint32le(mdp, &createact); /* create_action */ 443 444 md_get_uint64le(mdp, &llongint); /* creation time */ 445 smb_time_NT2local(llongint, &fa.fa_createtime); 446 md_get_uint64le(mdp, &llongint); /* access time */ 447 smb_time_NT2local(llongint, &fa.fa_atime); 448 md_get_uint64le(mdp, &llongint); /* write time */ 449 smb_time_NT2local(llongint, &fa.fa_mtime); 450 md_get_uint64le(mdp, &llongint); /* change time */ 451 smb_time_NT2local(llongint, &fa.fa_ctime); 452 453 md_get_uint32le(mdp, &longint); /* attributes */ 454 fa.fa_attr = longint; 455 md_get_uint64le(mdp, &llongint); /* allocation size */ 456 fa.fa_allocsz = llongint; 457 md_get_uint64le(mdp, &llongint); /* EOF position */ 458 fa.fa_size = llongint; 459 460 error = md_get_uint16le(mdp, NULL); /* file type */ 461 /* other stuff we don't care about */ 462 463 done: 464 smb_rq_done(rqp); 465 if (error) 466 return (error); 467 468 *fidp = fid; 469 if (cr_act_p) 470 *cr_act_p = createact; 471 if (fap) 472 *fap = fa; /* struct copy */ 473 474 return (0); 475 } 476 477 int 478 smb_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime, 479 struct smb_cred *scrp) 480 { 481 struct smb_rq rq, *rqp = &rq; 482 struct mbchain *mbp; 483 long time; 484 int error; 485 486 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scrp); 487 if (error) 488 return (error); 489 smb_rq_getrequest(rqp, &mbp); 490 smb_rq_wstart(rqp); 491 mb_put_uint16le(mbp, fid); 492 if (mtime) { 493 int sv_tz = SSTOVC(ssp)->vc_sopt.sv_tz; 494 smb_time_local2server(mtime, sv_tz, &time); 495 } else { 496 time = 0; 497 } 498 mb_put_uint32le(mbp, time); 499 smb_rq_wend(rqp); 500 smb_rq_bstart(rqp); 501 smb_rq_bend(rqp); 502 503 /* Make sure we send, but only if already connected */ 504 rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT); 505 error = smb_rq_simple(rqp); 506 smb_rq_done(rqp); 507 return (error); 508 } 509 510 int 511 smb_smb_open_prjob( 512 struct smb_share *ssp, 513 char *title, 514 uint16_t setuplen, 515 uint16_t mode, 516 struct smb_cred *scrp, 517 uint16_t *fidp) 518 { 519 struct smb_rq rq, *rqp = &rq; 520 struct smb_vc *vcp = SSTOVC(ssp); 521 struct mbchain *mbp; 522 struct mdchain *mdp; 523 uint16_t fid; 524 uint8_t wc; 525 int error; 526 527 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN_PRINT_FILE, scrp); 528 if (error) 529 return (error); 530 smb_rq_getrequest(rqp, &mbp); 531 532 /* Word parameters */ 533 smb_rq_wstart(rqp); 534 mb_put_uint16le(mbp, setuplen); 535 mb_put_uint16le(mbp, mode); 536 smb_rq_wend(rqp); 537 538 /* 539 * Byte parameters: Just the title 540 */ 541 smb_rq_bstart(rqp); 542 mb_put_uint8(mbp, SMB_DT_ASCII); 543 error = smb_put_dstring(mbp, vcp, title, SMB_CS_NONE); 544 smb_rq_bend(rqp); 545 if (error) 546 goto done; 547 548 /* 549 * Don't want to risk missing a successful 550 * open response, or we could "leak" FIDs. 551 */ 552 rqp->sr_flags |= SMBR_NOINTR_RECV; 553 error = smb_rq_simple_timed(rqp, smb_timo_open); 554 if (error) 555 goto done; 556 557 smb_rq_getreply(rqp, &mdp); 558 error = md_get_uint8(mdp, &wc); 559 if (error || wc < 1) { 560 error = EBADRPC; 561 goto done; 562 } 563 error = md_get_uint16le(mdp, &fid); 564 565 done: 566 smb_rq_done(rqp); 567 if (error) 568 return (error); 569 570 *fidp = fid; 571 return (0); 572 } 573 574 /* 575 * Like smb_smb_close, but for print shares. 576 */ 577 int 578 smb_smb_close_prjob(struct smb_share *ssp, uint16_t fid, 579 struct smb_cred *scrp) 580 { 581 struct smb_rq rq, *rqp = &rq; 582 struct mbchain *mbp; 583 int error; 584 585 error = smb_rq_init(rqp, SSTOCP(ssp), 586 SMB_COM_CLOSE_PRINT_FILE, scrp); 587 if (error) 588 return (error); 589 smb_rq_getrequest(rqp, &mbp); 590 smb_rq_wstart(rqp); 591 mb_put_uint16le(mbp, fid); 592 smb_rq_wend(rqp); 593 smb_rq_bstart(rqp); 594 smb_rq_bend(rqp); 595 596 /* Make sure we send but only if already connected */ 597 rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT); 598 error = smb_rq_simple(rqp); 599 smb_rq_done(rqp); 600 return (error); 601 } 602 603 /* 604 * Common function for read/write with UIO. 605 * Called by netsmb smb_usr_rw, 606 * smbfs_readvnode, smbfs_writevnode 607 */ 608 int 609 smb_rwuio(struct smb_share *ssp, uint16_t fid, uio_rw_t rw, 610 uio_t *uiop, smb_cred_t *scred, int timo) 611 { 612 struct smb_vc *vcp = SSTOVC(ssp); 613 ssize_t save_resid; 614 uint32_t len, rlen, maxlen; 615 int error = 0; 616 int (*iofun)(struct smb_share *, uint16_t, uint32_t *, 617 uio_t *, smb_cred_t *, int); 618 619 /* 620 * Determine which function to use, 621 * and the transfer size per call. 622 */ 623 if (SMB_DIALECT(vcp) >= SMB_DIALECT_NTLM0_12) { 624 /* 625 * Using NT LM 0.12, so readx, writex. 626 * Make sure we can represent the offset. 627 */ 628 if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) == 0 && 629 (uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX) 630 return (EFBIG); 631 632 if (rw == UIO_READ) { 633 iofun = smb_smb_readx; 634 if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX) 635 maxlen = SMB_MAX_LARGE_RW_SIZE; 636 else 637 maxlen = vcp->vc_rxmax; 638 } else { /* UIO_WRITE */ 639 iofun = smb_smb_writex; 640 if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX) 641 maxlen = SMB_MAX_LARGE_RW_SIZE; 642 else 643 maxlen = vcp->vc_wxmax; 644 } 645 } else { 646 /* 647 * Using the old SMB_READ and SMB_WRITE so 648 * we're limited to 32-bit offsets, etc. 649 * XXX: Someday, punt the old dialects. 650 */ 651 if ((uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX) 652 return (EFBIG); 653 654 if (rw == UIO_READ) { 655 iofun = smb_smb_read; 656 maxlen = vcp->vc_rxmax; 657 } else { /* UIO_WRITE */ 658 iofun = smb_smb_write; 659 maxlen = vcp->vc_wxmax; 660 } 661 } 662 663 save_resid = uiop->uio_resid; 664 while (uiop->uio_resid > 0) { 665 /* Lint: uio_resid may be 64-bits */ 666 rlen = len = (uint32_t)min(maxlen, uiop->uio_resid); 667 error = (*iofun)(ssp, fid, &rlen, uiop, scred, timo); 668 669 /* 670 * Note: the iofun called uio_update, so 671 * not doing that here as one might expect. 672 * 673 * Quit the loop either on error, or if we 674 * transferred less then requested. 675 */ 676 if (error || (rlen < len)) 677 break; 678 679 timo = 0; /* only first I/O should wait */ 680 } 681 if (error && (save_resid != uiop->uio_resid)) { 682 /* 683 * Stopped on an error after having 684 * successfully transferred data. 685 * Suppress this error. 686 */ 687 SMBSDEBUG("error %d suppressed\n", error); 688 error = 0; 689 } 690 691 return (error); 692 } 693 694 static int 695 smb_smb_readx(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, 696 uio_t *uiop, smb_cred_t *scred, int timo) 697 { 698 struct smb_rq *rqp; 699 struct mbchain *mbp; 700 struct mdchain *mdp; 701 int error; 702 uint32_t offlo, offhi, rlen; 703 uint16_t lenhi, lenlo, off, doff; 704 uint8_t wc; 705 706 lenhi = (uint16_t)(*lenp >> 16); 707 lenlo = (uint16_t)*lenp; 708 offhi = (uint32_t)(uiop->uio_loffset >> 32); 709 offlo = (uint32_t)uiop->uio_loffset; 710 711 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp); 712 if (error) 713 return (error); 714 smb_rq_getrequest(rqp, &mbp); 715 smb_rq_wstart(rqp); 716 mb_put_uint8(mbp, 0xff); /* no secondary command */ 717 mb_put_uint8(mbp, 0); /* MBZ */ 718 mb_put_uint16le(mbp, 0); /* offset to secondary */ 719 mb_put_uint16le(mbp, fid); 720 mb_put_uint32le(mbp, offlo); /* offset (low part) */ 721 mb_put_uint16le(mbp, lenlo); /* MaxCount */ 722 mb_put_uint16le(mbp, 1); /* MinCount */ 723 /* (only indicates blocking) */ 724 mb_put_uint32le(mbp, lenhi); /* MaxCountHigh */ 725 mb_put_uint16le(mbp, lenlo); /* Remaining ("obsolete") */ 726 mb_put_uint32le(mbp, offhi); /* offset (high part) */ 727 smb_rq_wend(rqp); 728 smb_rq_bstart(rqp); 729 smb_rq_bend(rqp); 730 731 if (timo == 0) 732 timo = smb_timo_read; 733 error = smb_rq_simple_timed(rqp, timo); 734 if (error) 735 goto out; 736 737 smb_rq_getreply(rqp, &mdp); 738 error = md_get_uint8(mdp, &wc); 739 if (error) 740 goto out; 741 if (wc != 12) { 742 error = EBADRPC; 743 goto out; 744 } 745 md_get_uint8(mdp, NULL); 746 md_get_uint8(mdp, NULL); 747 md_get_uint16le(mdp, NULL); 748 md_get_uint16le(mdp, NULL); 749 md_get_uint16le(mdp, NULL); /* data compaction mode */ 750 md_get_uint16le(mdp, NULL); 751 md_get_uint16le(mdp, &lenlo); /* data len ret. */ 752 md_get_uint16le(mdp, &doff); /* data offset */ 753 md_get_uint16le(mdp, &lenhi); 754 rlen = (lenhi << 16) | lenlo; 755 md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); 756 error = md_get_uint16le(mdp, NULL); /* ByteCount */ 757 if (error) 758 goto out; 759 /* 760 * Does the data offset indicate padding? 761 * The current offset is a constant, found 762 * by counting the md_get_ calls above. 763 */ 764 off = SMB_HDRLEN + 3 + (12 * 2); /* =59 */ 765 if (doff > off) /* pad byte(s)? */ 766 md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM); 767 if (rlen == 0) { 768 *lenp = rlen; 769 goto out; 770 } 771 /* paranoid */ 772 if (rlen > *lenp) { 773 SMBSDEBUG("bad server! rlen %d, len %d\n", 774 rlen, *lenp); 775 rlen = *lenp; 776 } 777 error = md_get_uio(mdp, uiop, rlen); 778 if (error) 779 goto out; 780 781 /* Success */ 782 *lenp = rlen; 783 784 out: 785 smb_rq_done(rqp); 786 return (error); 787 } 788 789 static int 790 smb_smb_writex(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, 791 uio_t *uiop, smb_cred_t *scred, int timo) 792 { 793 struct smb_rq *rqp; 794 struct mbchain *mbp; 795 struct mdchain *mdp; 796 int error; 797 uint32_t offlo, offhi, rlen; 798 uint16_t lenhi, lenlo; 799 uint8_t wc; 800 801 lenhi = (uint16_t)(*lenp >> 16); 802 lenlo = (uint16_t)*lenp; 803 offhi = (uint32_t)(uiop->uio_loffset >> 32); 804 offlo = (uint32_t)uiop->uio_loffset; 805 806 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp); 807 if (error) 808 return (error); 809 smb_rq_getrequest(rqp, &mbp); 810 smb_rq_wstart(rqp); 811 mb_put_uint8(mbp, 0xff); /* no secondary command */ 812 mb_put_uint8(mbp, 0); /* MBZ */ 813 mb_put_uint16le(mbp, 0); /* offset to secondary */ 814 mb_put_uint16le(mbp, fid); 815 mb_put_uint32le(mbp, offlo); /* offset (low part) */ 816 mb_put_uint32le(mbp, 0); /* MBZ (timeout) */ 817 mb_put_uint16le(mbp, 0); /* !write-thru */ 818 mb_put_uint16le(mbp, 0); 819 mb_put_uint16le(mbp, lenhi); 820 mb_put_uint16le(mbp, lenlo); 821 mb_put_uint16le(mbp, 64); /* data offset from header start */ 822 mb_put_uint32le(mbp, offhi); /* offset (high part) */ 823 smb_rq_wend(rqp); 824 smb_rq_bstart(rqp); 825 826 mb_put_uint8(mbp, 0); /* pad byte */ 827 error = mb_put_uio(mbp, uiop, *lenp); 828 if (error) 829 goto out; 830 smb_rq_bend(rqp); 831 if (timo == 0) 832 timo = smb_timo_write; 833 error = smb_rq_simple_timed(rqp, timo); 834 if (error) 835 goto out; 836 smb_rq_getreply(rqp, &mdp); 837 error = md_get_uint8(mdp, &wc); 838 if (error) 839 goto out; 840 if (wc != 6) { 841 error = EBADRPC; 842 goto out; 843 } 844 md_get_uint8(mdp, NULL); /* andx cmd */ 845 md_get_uint8(mdp, NULL); /* reserved */ 846 md_get_uint16le(mdp, NULL); /* andx offset */ 847 md_get_uint16le(mdp, &lenlo); /* data len ret. */ 848 md_get_uint16le(mdp, NULL); /* remaining */ 849 error = md_get_uint16le(mdp, &lenhi); 850 if (error) 851 goto out; 852 853 /* Success */ 854 rlen = (lenhi << 16) | lenlo; 855 *lenp = rlen; 856 857 out: 858 smb_rq_done(rqp); 859 return (error); 860 } 861 862 static int 863 smb_smb_read(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, 864 uio_t *uiop, smb_cred_t *scred, int timo) 865 { 866 struct smb_rq *rqp; 867 struct mbchain *mbp; 868 struct mdchain *mdp; 869 int error; 870 uint32_t off32; 871 uint16_t bc, cnt, dlen, rcnt, todo; 872 uint8_t wc; 873 874 ASSERT(uiop->uio_loffset <= UINT32_MAX); 875 off32 = (uint32_t)uiop->uio_loffset; 876 ASSERT(*lenp <= UINT16_MAX); 877 cnt = (uint16_t)*lenp; 878 /* This next is an "estimate" of planned reads. */ 879 todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX); 880 881 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp); 882 if (error) 883 return (error); 884 smb_rq_getrequest(rqp, &mbp); 885 smb_rq_wstart(rqp); 886 mb_put_uint16le(mbp, fid); 887 mb_put_uint16le(mbp, cnt); 888 mb_put_uint32le(mbp, off32); 889 mb_put_uint16le(mbp, todo); 890 smb_rq_wend(rqp); 891 smb_rq_bstart(rqp); 892 smb_rq_bend(rqp); 893 894 if (timo == 0) 895 timo = smb_timo_read; 896 error = smb_rq_simple_timed(rqp, timo); 897 if (error) 898 goto out; 899 smb_rq_getreply(rqp, &mdp); 900 error = md_get_uint8(mdp, &wc); 901 if (error) 902 goto out; 903 if (wc != 5) { 904 error = EBADRPC; 905 goto out; 906 } 907 md_get_uint16le(mdp, &rcnt); /* ret. count */ 908 md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); /* res. */ 909 md_get_uint16le(mdp, &bc); /* byte count */ 910 md_get_uint8(mdp, NULL); /* buffer format */ 911 error = md_get_uint16le(mdp, &dlen); /* data len */ 912 if (error) 913 goto out; 914 if (dlen < rcnt) { 915 SMBSDEBUG("oops: dlen=%d rcnt=%d\n", 916 (int)dlen, (int)rcnt); 917 rcnt = dlen; 918 } 919 if (rcnt == 0) { 920 *lenp = 0; 921 goto out; 922 } 923 /* paranoid */ 924 if (rcnt > cnt) { 925 SMBSDEBUG("bad server! rcnt %d, cnt %d\n", 926 (int)rcnt, (int)cnt); 927 rcnt = cnt; 928 } 929 error = md_get_uio(mdp, uiop, (int)rcnt); 930 if (error) 931 goto out; 932 933 /* success */ 934 *lenp = (int)rcnt; 935 936 out: 937 smb_rq_done(rqp); 938 return (error); 939 } 940 941 static int 942 smb_smb_write(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, 943 uio_t *uiop, smb_cred_t *scred, int timo) 944 { 945 struct smb_rq *rqp; 946 struct mbchain *mbp; 947 struct mdchain *mdp; 948 int error; 949 uint32_t off32; 950 uint16_t cnt, rcnt, todo; 951 uint8_t wc; 952 953 ASSERT(uiop->uio_loffset <= UINT32_MAX); 954 off32 = (uint32_t)uiop->uio_loffset; 955 ASSERT(*lenp <= UINT16_MAX); 956 cnt = (uint16_t)*lenp; 957 /* This next is an "estimate" of planned writes. */ 958 todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX); 959 960 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp); 961 if (error) 962 return (error); 963 smb_rq_getrequest(rqp, &mbp); 964 smb_rq_wstart(rqp); 965 mb_put_uint16le(mbp, fid); 966 mb_put_uint16le(mbp, cnt); 967 mb_put_uint32le(mbp, off32); 968 mb_put_uint16le(mbp, todo); 969 smb_rq_wend(rqp); 970 smb_rq_bstart(rqp); 971 mb_put_uint8(mbp, SMB_DT_DATA); 972 mb_put_uint16le(mbp, cnt); 973 974 error = mb_put_uio(mbp, uiop, *lenp); 975 if (error) 976 goto out; 977 smb_rq_bend(rqp); 978 if (timo == 0) 979 timo = smb_timo_write; 980 error = smb_rq_simple_timed(rqp, timo); 981 if (error) 982 goto out; 983 smb_rq_getreply(rqp, &mdp); 984 error = md_get_uint8(mdp, &wc); 985 if (error) 986 goto out; 987 if (wc != 1) { 988 error = EBADRPC; 989 goto out; 990 } 991 error = md_get_uint16le(mdp, &rcnt); 992 if (error) 993 goto out; 994 *lenp = rcnt; 995 996 out: 997 smb_rq_done(rqp); 998 return (error); 999 } 1000 1001 1002 static u_int32_t smbechoes = 0; 1003 1004 int 1005 smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo) 1006 { 1007 struct smb_rq *rqp; 1008 struct mbchain *mbp; 1009 int error; 1010 1011 error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_ECHO, scred, &rqp); 1012 if (error) 1013 return (error); 1014 mbp = &rqp->sr_rq; 1015 smb_rq_wstart(rqp); 1016 mb_put_uint16le(mbp, 1); /* echo count */ 1017 smb_rq_wend(rqp); 1018 smb_rq_bstart(rqp); 1019 mb_put_uint32le(mbp, atomic_inc_32_nv(&smbechoes)); 1020 smb_rq_bend(rqp); 1021 /* 1022 * Note: the IOD calls this, so 1023 * this request must not wait for 1024 * connection state changes, etc. 1025 */ 1026 rqp->sr_flags |= SMBR_NORECONNECT; 1027 error = smb_rq_simple_timed(rqp, timo); 1028 SMBSDEBUG("%d\n", error); 1029 smb_rq_done(rqp); 1030 return (error); 1031 } 1032