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 33 /* 34 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 35 * Use is subject to license terms. 36 * 37 * Copyright (c) 2011 - 2013 Apple Inc. All rights reserved. 38 * Copyright 2018 Nexenta Systems, Inc. All rights reserved. 39 */ 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/inttypes.h> 44 #include <sys/time.h> 45 #include <sys/vnode.h> 46 #include <sys/sunddi.h> 47 #include <sys/cmn_err.h> 48 49 #include <netsmb/smb_osdep.h> 50 51 #include <netsmb/smb.h> 52 #include <netsmb/smb2.h> 53 #include <netsmb/smb_conn.h> 54 #include <netsmb/smb_subr.h> 55 #include <netsmb/smb_rq.h> 56 #include <netsmb/smb2_rq.h> 57 58 #include <smbfs/smbfs.h> 59 #include <smbfs/smbfs_node.h> 60 #include <smbfs/smbfs_subr.h> 61 62 63 /* 64 * Todo: locking over-the-wire 65 */ 66 #if 0 // todo 67 68 int 69 smbfs_smb2_locking(struct smbnode *np, int op, uint32_t pid, 70 offset_t start, uint64_t len, int largelock, 71 struct smb_cred *scrp, uint32_t timeout) 72 { 73 return (ENOTSUP); 74 } 75 76 #endif // todo 77 78 /* 79 * Helper for smbfs_getattr_otw 80 * used when we don't have an open FID 81 * 82 * For SMB2 we need to do an attribute-only open. The 83 * data returned by open gets us everything we need, so 84 * just close the handle and we're done. 85 */ 86 int 87 smbfs_smb2_getpattr( 88 struct smbnode *np, 89 struct smbfattr *fap, 90 struct smb_cred *scrp) 91 { 92 smb_fh_t tmp_fh; 93 struct smb_share *ssp = np->n_mount->smi_share; 94 uint32_t rights = (STD_RIGHT_READ_CONTROL_ACCESS | 95 SA_RIGHT_FILE_READ_ATTRIBUTES); 96 int error; 97 98 bzero(&tmp_fh, sizeof (tmp_fh)); 99 error = smbfs_smb_ntcreatex(np, 100 NULL, 0, 0, /* name nmlen xattr */ 101 rights, SMB_EFA_NORMAL, 102 NTCREATEX_SHARE_ACCESS_ALL, 103 NTCREATEX_DISP_OPEN, 104 0, /* create options */ 105 scrp, &tmp_fh, 106 NULL, fap); 107 if (error == 0) { 108 (void) smb_smb_close(ssp, &tmp_fh, scrp); 109 } 110 111 return (error); 112 } 113 114 /* 115 * Common SMB2 query file info 116 */ 117 static int 118 smbfs_smb2_query_info(struct smb_share *ssp, smb2fid_t *fid, 119 struct mdchain *info_mdp, uint32_t *iolen, 120 uint8_t type, uint8_t level, uint32_t addl_info, 121 struct smb_cred *scrp) 122 { 123 struct smb_rq *rqp = NULL; 124 struct mbchain *mbp; 125 struct mdchain *mdp; 126 uint32_t dlen = 0; 127 uint16_t doff = 0; 128 uint16_t ssize = 0; 129 int error; 130 131 error = smb_rq_alloc(SSTOCP(ssp), SMB2_QUERY_INFO, scrp, &rqp); 132 if (error) 133 goto out; 134 135 /* 136 * Build the SMB 2 Query Info req. 137 */ 138 smb_rq_getrequest(rqp, &mbp); 139 mb_put_uint16le(mbp, 41); // struct size 140 mb_put_uint8(mbp, type); 141 mb_put_uint8(mbp, level); 142 mb_put_uint32le(mbp, *iolen); // out buf len 143 mb_put_uint16le(mbp, 0); // in buf off 144 mb_put_uint16le(mbp, 0); // reserved 145 mb_put_uint32le(mbp, 0); // in buf len 146 mb_put_uint32le(mbp, addl_info); 147 mb_put_uint32le(mbp, 0); // flags 148 mb_put_uint64le(mbp, fid->fid_persistent); 149 mb_put_uint64le(mbp, fid->fid_volatile); 150 151 error = smb2_rq_simple(rqp); 152 if (error) { 153 if (rqp->sr_error == NT_STATUS_INVALID_PARAMETER) 154 error = ENOTSUP; 155 goto out; 156 } 157 158 /* 159 * Parse SMB 2 Query Info response 160 */ 161 smb_rq_getreply(rqp, &mdp); 162 163 /* Check structure size is 9 */ 164 md_get_uint16le(mdp, &ssize); 165 if (ssize != 9) { 166 error = EBADRPC; 167 goto out; 168 } 169 170 /* Get data off, len */ 171 md_get_uint16le(mdp, &doff); 172 md_get_uint32le(mdp, &dlen); 173 *iolen = dlen; 174 175 /* 176 * Skip ahead to the payload, as needed. 177 * Current offset is SMB2_HDRLEN + 8. 178 */ 179 if (dlen != 0) { 180 mblk_t *m = NULL; 181 int skip = (int)doff - (SMB2_HDRLEN + 8); 182 if (skip < 0) { 183 error = EBADRPC; 184 goto out; 185 } 186 if (skip > 0) { 187 md_get_mem(mdp, NULL, skip, MB_MSYSTEM); 188 } 189 error = md_get_mbuf(mdp, dlen, &m); 190 if (error) 191 goto out; 192 md_initm(info_mdp, m); 193 } 194 195 out: 196 smb_rq_done(rqp); 197 198 return (error); 199 } 200 201 202 /* 203 * Get FileAllInformation for an open file 204 * and parse into *fap 205 */ 206 int 207 smbfs_smb2_qfileinfo(struct smb_share *ssp, smb2fid_t *fid, 208 struct smbfattr *fap, struct smb_cred *scrp) 209 { 210 struct mdchain info_mdc, *mdp = &info_mdc; 211 uint32_t iolen = 1024; 212 int error; 213 214 bzero(mdp, sizeof (*mdp)); 215 216 error = smbfs_smb2_query_info(ssp, fid, mdp, &iolen, 217 SMB2_0_INFO_FILE, FileAllInformation, 0, scrp); 218 if (error) 219 goto out; 220 221 error = smbfs_decode_file_all_info(ssp, mdp, fap); 222 223 out: 224 md_done(mdp); 225 226 return (error); 227 } 228 229 /* 230 * Get some SMB2_0_INFO_FILESYSTEM info 231 * 232 * Note: This can be called during mount. We don't have any 233 * smbfs_node_t or pathname, so do our own attr. open on 234 * the root of the share to get a handle for this request. 235 */ 236 static int 237 smbfs_smb2_query_fs_info(struct smb_share *ssp, struct mdchain *mdp, 238 uint8_t level, struct smb_cred *scrp) 239 { 240 smb2fid_t fid; 241 uint32_t iolen = 1024; 242 boolean_t opened = B_FALSE; 243 int error; 244 245 /* 246 * Need a FID for smb2, and this is called during mount 247 * so "go behind" the usual open/close functions. 248 */ 249 error = smb2_smb_ntcreate( 250 ssp, NULL, // name 251 NULL, NULL, // create ctx in, out 252 0, /* NTCREATEX_FLAGS... */ 253 SA_RIGHT_FILE_READ_ATTRIBUTES, 254 SMB_EFA_NORMAL, 255 NTCREATEX_SHARE_ACCESS_ALL, 256 NTCREATEX_DISP_OPEN, 257 0, /* create options */ 258 NTCREATEX_IMPERSONATION_IMPERSONATION, 259 scrp, &fid, NULL, NULL); 260 if (error != 0) 261 goto out; 262 opened = B_TRUE; 263 264 error = smbfs_smb2_query_info(ssp, &fid, mdp, &iolen, 265 SMB2_0_INFO_FILESYSTEM, level, 0, scrp); 266 267 out: 268 if (opened) 269 (void) smb2_smb_close(ssp, &fid, scrp); 270 271 return (error); 272 } 273 274 /* 275 * Get FileFsAttributeInformation and 276 * parse into *info 277 */ 278 int 279 smbfs_smb2_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *info, 280 struct smb_cred *scrp) 281 { 282 struct mdchain info_mdc, *mdp = &info_mdc; 283 int error; 284 285 bzero(mdp, sizeof (*mdp)); 286 287 error = smbfs_smb2_query_fs_info(ssp, mdp, 288 FileFsAttributeInformation, scrp); 289 if (error) 290 goto out; 291 error = smbfs_decode_fs_attr_info(ssp, mdp, info); 292 293 out: 294 md_done(mdp); 295 296 return (error); 297 } 298 299 /* 300 * Get FileFsFullSizeInformation and 301 * parse into *info 302 */ 303 int 304 smbfs_smb2_statfs(struct smb_share *ssp, 305 struct smb_fs_size_info *info, 306 struct smb_cred *scrp) 307 { 308 struct mdchain info_mdc, *mdp = &info_mdc; 309 int error; 310 311 bzero(mdp, sizeof (*mdp)); 312 313 error = smbfs_smb2_query_fs_info(ssp, mdp, 314 FileFsFullSizeInformation, scrp); 315 if (error) 316 goto out; 317 318 md_get_uint64le(mdp, &info->total_units); 319 md_get_uint64le(mdp, &info->caller_avail); 320 md_get_uint64le(mdp, &info->actual_avail); 321 322 md_get_uint32le(mdp, &info->sect_per_unit); 323 error = md_get_uint32le(mdp, &info->bytes_per_sect); 324 325 out: 326 md_done(mdp); 327 328 return (error); 329 } 330 331 int 332 smbfs_smb2_flush(struct smb_share *ssp, smb2fid_t *fid, 333 struct smb_cred *scrp) 334 { 335 struct smb_rq *rqp; 336 struct mbchain *mbp; 337 int error; 338 339 error = smb_rq_alloc(SSTOCP(ssp), SMB2_FLUSH, scrp, &rqp); 340 if (error) 341 return (error); 342 343 /* 344 * Build the SMB 2 Flush Request 345 */ 346 smb_rq_getrequest(rqp, &mbp); 347 mb_put_uint16le(mbp, 24); /* struct size */ 348 mb_put_uint16le(mbp, 0); /* reserved */ 349 mb_put_uint32le(mbp, 0); /* reserved */ 350 351 mb_put_uint64le(mbp, fid->fid_persistent); 352 mb_put_uint64le(mbp, fid->fid_volatile); 353 354 rqp->sr_flags |= SMBR_NORECONNECT; 355 error = smb2_rq_simple(rqp); 356 smb_rq_done(rqp); 357 358 return (error); 359 } 360 361 /* 362 * Set file info via an open handle. 363 * Caller provides payload, info level. 364 */ 365 static int 366 smbfs_smb2_set_info(struct smb_share *ssp, smb2fid_t *fid, 367 struct mbchain *info_mbp, uint8_t type, uint8_t level, 368 uint32_t addl_info, struct smb_cred *scrp) 369 { 370 struct smb_rq *rqp = NULL; 371 struct mbchain *mbp; 372 uint32_t *buffer_lenp; 373 int base, len; 374 int error; 375 376 error = smb_rq_alloc(SSTOCP(ssp), SMB2_SET_INFO, scrp, &rqp); 377 if (error) 378 goto out; 379 380 /* 381 * Build the SMB 2 Set Info req. 382 */ 383 smb_rq_getrequest(rqp, &mbp); 384 mb_put_uint16le(mbp, 33); // struct size 385 mb_put_uint8(mbp, type); 386 mb_put_uint8(mbp, level); 387 buffer_lenp = mb_reserve(mbp, sizeof (uint32_t)); 388 mb_put_uint16le(mbp, SMB2_HDRLEN + 32); // Buffer Offset 389 mb_put_uint16le(mbp, 0); // Reserved 390 mb_put_uint32le(mbp, addl_info); // Additional Info 391 392 mb_put_uint64le(mbp, fid->fid_persistent); 393 mb_put_uint64le(mbp, fid->fid_volatile); 394 395 /* 396 * Now the payload 397 */ 398 base = mbp->mb_count; 399 error = mb_put_mbchain(mbp, info_mbp); 400 if (error) 401 goto out; 402 len = mbp->mb_count - base; 403 *buffer_lenp = htolel(len); 404 if (error) 405 goto out; 406 407 /* 408 * Run the request. 409 * Don't care about the (empty) reply. 410 */ 411 error = smb2_rq_simple(rqp); 412 413 out: 414 smb_rq_done(rqp); 415 416 return (error); 417 } 418 419 int 420 smbfs_smb2_seteof(struct smb_share *ssp, smb2fid_t *fid, 421 uint64_t newsize, struct smb_cred *scrp) 422 { 423 struct mbchain data_mb, *mbp = &data_mb; 424 uint8_t level = FileEndOfFileInformation; 425 int error; 426 427 mb_init(mbp); 428 mb_put_uint64le(mbp, newsize); 429 error = smbfs_smb2_set_info(ssp, fid, mbp, 430 SMB2_0_INFO_FILE, level, 0, scrp); 431 mb_done(mbp); 432 433 return (error); 434 } 435 436 int 437 smbfs_smb2_setdisp(struct smb_share *ssp, smb2fid_t *fid, 438 uint8_t newdisp, struct smb_cred *scrp) 439 { 440 struct mbchain data_mb, *mbp = &data_mb; 441 uint8_t level = FileDispositionInformation; 442 int error; 443 444 mb_init(mbp); 445 mb_put_uint8(mbp, newdisp); 446 error = smbfs_smb2_set_info(ssp, fid, mbp, 447 SMB2_0_INFO_FILE, level, 0, scrp); 448 mb_done(mbp); 449 450 return (error); 451 } 452 453 /* 454 * Set FileBasicInformation on an open handle 455 * Caller builds the mbchain. 456 */ 457 int 458 smbfs_smb2_setfattr(struct smb_share *ssp, smb2fid_t *fid, 459 struct mbchain *mbp, struct smb_cred *scrp) 460 { 461 uint8_t level = FileBasicInformation; 462 int error; 463 464 error = smbfs_smb2_set_info(ssp, fid, mbp, 465 SMB2_0_INFO_FILE, level, 0, scrp); 466 return (error); 467 } 468 469 /* 470 * Build a FileRenameInformation and call setinfo 471 */ 472 int 473 smbfs_smb2_rename(struct smbnode *np, struct smbnode *tdnp, 474 const char *tname, int tnlen, int overwrite, 475 smb2fid_t *fid, struct smb_cred *scrp) 476 { 477 struct smb_share *ssp = np->n_mount->smi_share; 478 struct mbchain data_mb, *mbp = &data_mb; 479 uint32_t *name_lenp; 480 uint8_t level = FileRenameInformation; 481 int base, len; 482 int error; 483 484 mb_init(mbp); 485 486 mb_put_uint32le(mbp, (overwrite & 1)); 487 mb_put_uint32le(mbp, 0); // reserved 488 mb_put_uint64le(mbp, 0); // Root Dir 489 name_lenp = mb_reserve(mbp, 4); 490 491 /* Target name (full path) */ 492 base = mbp->mb_count; 493 if (tnlen > 0) { 494 error = smbfs_fullpath(mbp, SSTOVC(ssp), 495 tdnp, tname, tnlen, '\\'); 496 if (error) 497 goto out; 498 } 499 len = mbp->mb_count - base; 500 *name_lenp = htolel(len); 501 502 error = smbfs_smb2_set_info(ssp, fid, mbp, 503 SMB2_0_INFO_FILE, level, 0, scrp); 504 505 out: 506 mb_done(mbp); 507 508 return (error); 509 } 510 511 /* 512 * Later servers have maxtransact at a megabyte or more, 513 * but we don't want to buffer up that much data, so use 514 * the lesser of that or 64k. 515 */ 516 #define SMBFS_QDIR_MAX_BUF (1<<16) 517 518 /* 519 * SMB2 query directory 520 */ 521 static int 522 smbfs_smb2_qdir(struct smbfs_fctx *ctx) 523 { 524 smb_fh_t *fhp = ctx->f_fhp; 525 smb_share_t *ssp = ctx->f_ssp; 526 smb_vc_t *vcp = SSTOVC(ssp); 527 struct smb_rq *rqp; 528 struct mbchain *mbp; 529 struct mdchain *mdp; 530 uint16_t *name_lenp; 531 uint8_t level, flags; 532 uint16_t ssize = 0; 533 uint16_t obuf_off = 0; 534 uint32_t obuf_len = 0; 535 uint32_t obuf_req; 536 int error; 537 538 level = (uint8_t)ctx->f_infolevel; 539 flags = 0; 540 if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) 541 flags |= SMB2_QDIR_FLAG_SINGLE; 542 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) 543 ctx->f_rkey = 0; 544 else 545 flags |= SMB2_QDIR_FLAG_INDEX; 546 547 obuf_req = SMBFS_QDIR_MAX_BUF; 548 if (obuf_req > vcp->vc_sopt.sv2_maxtransact) 549 obuf_req = vcp->vc_sopt.sv2_maxtransact; 550 551 if (ctx->f_rq) { 552 smb_rq_done(ctx->f_rq); 553 ctx->f_rq = NULL; 554 } 555 error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB2_QUERY_DIRECTORY, 556 ctx->f_scred, &rqp); 557 if (error) 558 return (error); 559 ctx->f_rq = rqp; 560 561 /* 562 * Build an SMB2 Query Dir req. 563 */ 564 smb_rq_getrequest(rqp, &mbp); 565 566 mb_put_uint16le(mbp, 33); /* Struct size */ 567 mb_put_uint8(mbp, level); 568 mb_put_uint8(mbp, flags); 569 mb_put_uint32le(mbp, ctx->f_rkey); /* FileIndex */ 570 571 mb_put_uint64le(mbp, fhp->fh_fid2.fid_persistent); 572 mb_put_uint64le(mbp, fhp->fh_fid2.fid_volatile); 573 574 mb_put_uint16le(mbp, 96); 575 name_lenp = mb_reserve(mbp, sizeof (uint16_t)); /* FileNameLen */ 576 mb_put_uint32le(mbp, obuf_req); /* Output Buf Len */ 577 578 /* Add in the name if any */ 579 if (ctx->f_wclen > 0) { 580 int base, len; 581 582 /* Put the match pattern. */ 583 base = mbp->mb_count; 584 error = smb_put_dmem(mbp, vcp, 585 ctx->f_wildcard, ctx->f_wclen, 586 SMB_CS_NONE, NULL); 587 if (error) 588 return (error); 589 590 /* Update the FileNameLen */ 591 len = mbp->mb_count - base; 592 *name_lenp = htoles(len); 593 } else { 594 /* Empty string */ 595 mb_put_uint16le(mbp, 0); 596 *name_lenp = 0; 597 } 598 599 error = smb2_rq_simple(rqp); 600 if (error != 0) 601 goto out; 602 603 /* 604 * Parse the SMB2 Query Dir response 605 */ 606 smb_rq_getreply(rqp, &mdp); 607 608 /* Check structure size is 9 */ 609 md_get_uint16le(mdp, &ssize); 610 if (ssize != 9) { 611 error = EBADRPC; 612 goto out; 613 } 614 615 /* Get output buffer offset, length */ 616 md_get_uint16le(mdp, &obuf_off); 617 md_get_uint32le(mdp, &obuf_len); 618 619 /* 620 * After read at EOF we'll have just one word: 621 * NextEntryOffset == 0 Allow some padding. 622 */ 623 if (obuf_len < 8) { 624 error = ENOENT; 625 goto out; 626 } 627 628 /* 629 * If this reply is shorter than requested by 1k 630 * or more, we must have reached EOF. 631 */ 632 if ((obuf_len + 1024) < obuf_req) 633 ctx->f_flags |= SMBFS_RDD_EOF; 634 635 /* 636 * Have data. Put the payload in ctx->f_mdchain 637 * Current offset is SMB2_HDRLEN + 8. 638 */ 639 { 640 mblk_t *m = NULL; 641 int skip = (int)obuf_off - (SMB2_HDRLEN + 8); 642 if (skip < 0) { 643 error = EBADRPC; 644 goto out; 645 } 646 if (skip > 0) { 647 md_get_mem(mdp, NULL, skip, MB_MSYSTEM); 648 } 649 error = md_get_mbuf(mdp, obuf_len, &m); 650 if (error) 651 goto out; 652 md_done(&ctx->f_mdchain); 653 md_initm(&ctx->f_mdchain, m); 654 } 655 656 /* 657 * SMB2 Query Directory does not provie an EntryCount. 658 * Instead, we'll advance f_eofs (entry offset) 659 * through the range [0..f_left] 660 */ 661 ctx->f_left = obuf_len; 662 ctx->f_eofs = 0; 663 return (0); 664 665 out: 666 if (error != 0) { 667 /* 668 * Failed parsing the FindFirst or FindNext response. 669 * Force this directory listing closed, otherwise the 670 * calling process may hang in an infinite loop. 671 */ 672 ctx->f_left = 0; 673 ctx->f_eofs = 0; 674 ctx->f_flags |= SMBFS_RDD_EOF; 675 } 676 677 return (error); 678 } 679 680 int 681 smbfs_smb2_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp, 682 const char *wildcard, int wclen, uint32_t attr) 683 { 684 smb_fh_t *fhp = NULL; 685 uint32_t rights = 686 STD_RIGHT_READ_CONTROL_ACCESS | 687 SA_RIGHT_FILE_READ_ATTRIBUTES | 688 SA_RIGHT_FILE_READ_DATA; 689 int error; 690 691 /* 692 * Set f_type no matter what, so cleanup will call 693 * smbfs_smb2_findclose, error or not. 694 */ 695 ctx->f_type = ft_SMB2; 696 ASSERT(ctx->f_dnp == dnp); 697 698 /* 699 * Get a file handle on the directory 700 */ 701 error = smb_fh_create(ctx->f_ssp, &fhp); 702 if (error != 0) 703 goto errout; 704 705 error = smbfs_smb_ntcreatex(dnp, 706 NULL, 0, 0, /* name nmlen xattr */ 707 rights, SMB_EFA_NORMAL, 708 NTCREATEX_SHARE_ACCESS_ALL, 709 NTCREATEX_DISP_OPEN, 710 0, /* create options */ 711 ctx->f_scred, fhp, 712 NULL, NULL); /* cr_act_p fa_p */ 713 if (error != 0) 714 goto errout; 715 716 fhp->fh_rights = rights; 717 smb_fh_opened(fhp); 718 ctx->f_fhp = fhp; 719 720 ctx->f_namesz = SMB_MAXFNAMELEN + 1; 721 ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP); 722 ctx->f_infolevel = FileFullDirectoryInformation; 723 ctx->f_attrmask = attr; 724 ctx->f_wildcard = wildcard; 725 ctx->f_wclen = wclen; 726 727 return (0); 728 729 errout: 730 if (fhp != NULL) 731 smb_fh_rele(fhp); 732 return (error); 733 } 734 735 int 736 smbfs_smb2_findclose(struct smbfs_fctx *ctx) 737 { 738 smb_fh_t *fhp = NULL; 739 740 if ((fhp = ctx->f_fhp) != NULL) { 741 ctx->f_fhp = NULL; 742 smb_fh_rele(fhp); 743 } 744 if (ctx->f_name) 745 kmem_free(ctx->f_name, ctx->f_namesz); 746 if (ctx->f_rq) 747 smb_rq_done(ctx->f_rq); 748 md_done(&ctx->f_mdchain); 749 750 return (0); 751 } 752 753 /* 754 * Get a buffer of directory entries (if we don't already have 755 * some remaining in the current buffer) then decode one. 756 */ 757 int 758 smbfs_smb2_findnext(struct smbfs_fctx *ctx, uint16_t limit) 759 { 760 int error; 761 762 /* 763 * If we've scanned to the end of the current buffer 764 * try to read anohther buffer of dir entries. 765 * Treat anything less than 8 bytes as an "empty" 766 * buffer to ensure we can read something. 767 * (There may be up to 8 bytes of padding.) 768 */ 769 if ((ctx->f_eofs + 8) > ctx->f_left) { 770 /* Scanned the whole buffer. */ 771 if (ctx->f_flags & SMBFS_RDD_EOF) 772 return (ENOENT); 773 ctx->f_limit = limit; 774 error = smbfs_smb2_qdir(ctx); 775 if (error) 776 return (error); 777 ctx->f_otws++; 778 } 779 780 /* 781 * Decode one entry 782 */ 783 error = smbfs_decode_dirent(ctx); 784 785 return (error); 786 } 787 788 789 /* 790 * Helper for smbfs_xa_get_streaminfo 791 * Query stream info 792 */ 793 int 794 smbfs_smb2_get_streaminfo(smbnode_t *np, struct mdchain *mdp, 795 struct smb_cred *scrp) 796 { 797 smb_share_t *ssp = np->n_mount->smi_share; 798 smb_fh_t *fhp = NULL; 799 uint32_t rights = 800 STD_RIGHT_READ_CONTROL_ACCESS | 801 SA_RIGHT_FILE_READ_ATTRIBUTES; 802 uint32_t iolen = INT16_MAX; 803 int error; 804 805 /* 806 * Get a file handle on the object 807 * with read attr. rights. 808 */ 809 error = smb_fh_create(ssp, &fhp); 810 if (error != 0) 811 goto out; 812 error = smbfs_smb_ntcreatex(np, 813 NULL, 0, 0, /* name nmlen xattr */ 814 rights, SMB_EFA_NORMAL, 815 NTCREATEX_SHARE_ACCESS_ALL, 816 NTCREATEX_DISP_OPEN, 817 0, /* create options */ 818 scrp, fhp, NULL, NULL); 819 if (error != 0) 820 goto out; 821 822 smb_fh_opened(fhp); 823 824 /* 825 * Query stream info 826 */ 827 error = smbfs_smb2_query_info(ssp, &fhp->fh_fid2, mdp, &iolen, 828 SMB2_0_INFO_FILE, FileStreamInformation, 0, scrp); 829 830 out: 831 if (fhp != NULL) 832 smb_fh_rele(fhp); 833 return (error); 834 } 835 836 837 /* 838 * OTW function to Get a security descriptor (SD). 839 * 840 * The *reslen param is bufsize(in) / length(out) 841 * Note: On success, this fills in mdp->md_top, 842 * which the caller should free. 843 */ 844 int 845 smbfs_smb2_getsec(struct smb_share *ssp, smb2fid_t *fid, 846 uint32_t selector, mblk_t **res, uint32_t *reslen, 847 struct smb_cred *scrp) 848 { 849 struct mdchain info_mdc, *mdp = &info_mdc; 850 int error; 851 852 bzero(mdp, sizeof (*mdp)); 853 854 error = smbfs_smb2_query_info(ssp, fid, mdp, reslen, 855 SMB2_0_INFO_SECURITY, 0, selector, scrp); 856 if (error) 857 goto out; 858 859 if (mdp->md_top == NULL) { 860 error = EBADRPC; 861 goto out; 862 } 863 *res = mdp->md_top; 864 mdp->md_top = NULL; 865 866 out: 867 md_done(mdp); 868 return (error); 869 } 870 871 872 /* 873 * OTW function to Set a security descriptor (SD). 874 * Caller data are carried in an mbchain_t. 875 * 876 * Note: This normally consumes mbp->mb_top, and clears 877 * that pointer when it does. 878 */ 879 int 880 smbfs_smb2_setsec(struct smb_share *ssp, smb2fid_t *fid, 881 uint32_t selector, mblk_t **mp, struct smb_cred *scrp) 882 { 883 struct mbchain info_mbp, *mbp = &info_mbp; 884 int error; 885 886 ASSERT(*mp != NULL); 887 mb_initm(mbp, *mp); 888 *mp = NULL; /* consumed */ 889 890 error = smbfs_smb2_set_info(ssp, fid, mbp, 891 SMB2_0_INFO_SECURITY, 0, selector, scrp); 892 893 mb_done(mbp); 894 895 return (error); 896 } 897