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