Print this page
NEX-15069 smtorture smb2.create.blob is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15069 smtorture smb2.create.blob is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-1643 dtrace provider for smbsrv
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-4458 Incorrect directory listing response for non-UNICODE clients
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-4540 SMB server declines EA support incorrectly
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-4053 Customer DIR command hangs with smb2 enabled
NEX-4080 SMB_ODIR_FLAG_WILDCARDS can be incorrectly inherited
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
SMB-11 SMB2 message parse & dispatch
SMB-12 SMB2 Negotiate Protocol
SMB-13 SMB2 Session Setup
SMB-14 SMB2 Logoff
SMB-15 SMB2 Tree Connect
SMB-16 SMB2 Tree Disconnect
SMB-17 SMB2 Create
SMB-18 SMB2 Close
SMB-19 SMB2 Flush
SMB-20 SMB2 Read
SMB-21 SMB2 Write
SMB-22 SMB2 Lock/Unlock
SMB-23 SMB2 Ioctl
SMB-24 SMB2 Cancel
SMB-25 SMB2 Echo
SMB-26 SMB2 Query Dir
SMB-27 SMB2 Change Notify
SMB-28 SMB2 Query Info
SMB-29 SMB2 Set Info
SMB-30 SMB2 Oplocks
SMB-53 SMB2 Create Context options
(SMB2 code review cleanup 1, 2, 3)
SMB-50 User-mode SMB server
 Includes work by these authors:
 Thomas Keiser <thomas.keiser@nexenta.com>
 Albert Lee <trisk@nexenta.com>
SMB-63 taskq_create_proc ... TQ_DYNAMIC puts tasks in p0
re #11974 CIFS Share - Tree connect fails from Windows 7 Clients
re #10733 Windows 7 directory listing keeps restarting (fix lint)
re #10733 Windows 7 directory listing keeps restarting


   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  *
  25  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  26  */
  27 
  28 
  29 /*
  30  * This module provides functions for TRANS2_FIND_FIRST2 and
  31  * TRANS2_FIND_NEXT2 requests. The requests allow the client to search
  32  * for the file(s) which match the file specification.  The search is
  33  * started with TRANS2_FIND_FIRST2 and can be continued if necessary with
  34  * TRANS2_FIND_NEXT2. There are numerous levels of information which may be
  35  * obtained for the returned files, the desired level is specified in the
  36  * InformationLevel field of the requests.
  37  *
  38  *  InformationLevel Name              Value
  39  *  =================================  ================
  40  *
  41  *  SMB_INFO_STANDARD                  1
  42  *  SMB_INFO_QUERY_EA_SIZE             2
  43  *  SMB_INFO_QUERY_EAS_FROM_LIST       3
  44  *  SMB_FIND_FILE_DIRECTORY_INFO       0x101
  45  *  SMB_FIND_FILE_FULL_DIRECTORY_INFO  0x102


 196  *
 197  *  Response Field                     Description
 198  *  =================================  ==================================
 199  *
 200  *  ULONG NextEntryOffset;             Offset from this structure to
 201  *                                     beginning of next one
 202  *  ULONG FileIndex;
 203  *  ULONG FileNameLength;              Length of FileName in bytes
 204  *  STRING FileName;                   Files full length name
 205  */
 206 
 207 #include <smbsrv/smb_kproto.h>
 208 #include <smbsrv/msgbuf.h>
 209 #include <smbsrv/smb_fsops.h>
 210 
 211 /*
 212  * Args (and other state) that we carry around among the
 213  * various functions involved in FindFirst, FindNext.
 214  */
 215 typedef struct smb_find_args {
 216         uint32_t fa_maxdata;
 217         uint16_t fa_infolev;
 218         uint16_t fa_maxcount;
 219         uint16_t fa_fflag;
 220         uint16_t fa_eos;        /* End Of Search */
 221         uint16_t fa_lno;        /* Last Name Offset */
 222         uint32_t fa_lastkey;    /* Last resume key */
 223         char fa_lastname[MAXNAMELEN]; /* and name */
 224 } smb_find_args_t;
 225 
 226 static int smb_trans2_find_entries(smb_request_t *, smb_xa_t *,
 227     smb_odir_t *, smb_find_args_t *);
 228 static int smb_trans2_find_get_maxdata(smb_request_t *, uint16_t, uint16_t);
 229 static int smb_trans2_find_mbc_encode(smb_request_t *, smb_xa_t *,
 230     smb_fileinfo_t *, smb_find_args_t *);
 231 
 232 /*
 233  * Tunable parameter to limit the maximum
 234  * number of entries to be returned.
 235  */
 236 uint16_t smb_trans2_find_max = 128;
 237 
 238 /*
 239  * smb_com_trans2_find_first2
 240  *
 241  *  Client Request                Value
 242  *  ============================  ==================================
 243  *
 244  *  UCHAR  WordCount              15
 245  *  UCHAR  TotalDataCount         Total size of extended attribute list
 246  *  UCHAR  SetupCount             1
 247  *  UCHAR  Setup[0]               TRANS2_FIND_FIRST2
 248  *


 303             &args.fa_maxcount, &args.fa_fflag, &args.fa_infolev,
 304             &pn->pn_path) != 0) {
 305                 return (SDRC_ERROR);
 306         }
 307 
 308         smb_pathname_init(sr, pn, pn->pn_path);
 309         if (!smb_pathname_validate(sr, pn))
 310                 return (-1);
 311 
 312         if (smb_is_stream_name(pn->pn_path)) {
 313                 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
 314                     ERRDOS, ERROR_INVALID_NAME);
 315                 return (SDRC_ERROR);
 316         }
 317 
 318         if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT) {
 319                 sr->user_cr = smb_user_getprivcred(sr->uid_user);
 320                 odir_flags = SMB_ODIR_OPENF_BACKUP_INTENT;
 321         }
 322 
 323         args.fa_maxdata =
 324             smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag);
 325         if (args.fa_maxdata == 0)
 326                 return (SDRC_ERROR);
 327 
 328         status = smb_odir_openpath(sr, pn->pn_path, sattr, odir_flags, &od);
 329         if (status != 0) {
 330                 smbsr_error(sr, status, 0, 0);
 331                 return (SDRC_ERROR);
 332         }
 333         if (od == NULL)
 334                 return (SDRC_ERROR);
 335 
 336         count = smb_trans2_find_entries(sr, xa, od, &args);
 337 
 338         if (count == -1) {
 339                 smb_odir_close(od);
 340                 smb_odir_release(od);
 341                 return (SDRC_ERROR);
 342         }
 343 
 344         if (count == 0) {
 345                 smb_odir_close(od);
 346                 smb_odir_release(od);
 347                 smbsr_errno(sr, ENOENT);

 348                 return (SDRC_ERROR);
 349         }
 350 
 351         if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) ||
 352             (args.fa_eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) {
 353                 smb_odir_close(od);
 354         } /* else leave odir open for trans2_find_next2 */
 355 
 356         (void) smb_mbc_encodef(&xa->rep_param_mb, "wwwww",
 357             od->d_odid,      /* Search ID */
 358             count,      /* Search Count */
 359             args.fa_eos, /* End Of Search */
 360             0,          /* EA Error Offset */
 361             args.fa_lno); /* Last Name Offset */
 362 
 363         smb_odir_release(od);
 364 
 365         return (SDRC_SUCCESS);
 366 }
 367 


 438 
 439         bzero(&args, sizeof (args));
 440         bzero(&odir_resume, sizeof (odir_resume));
 441 
 442         if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
 443                 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
 444                     ERRDOS, ERROR_ACCESS_DENIED);
 445                 return (SDRC_ERROR);
 446         }
 447 
 448         if (smb_mbc_decodef(&xa->req_param_mb, "%wwwlwu", sr,
 449             &odid, &args.fa_maxcount, &args.fa_infolev,
 450             &odir_resume.or_cookie, &args.fa_fflag,
 451             &odir_resume.or_fname) != 0) {
 452                 return (SDRC_ERROR);
 453         }
 454 
 455         if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT)
 456                 sr->user_cr = smb_user_getprivcred(sr->uid_user);
 457 
 458         args.fa_maxdata =
 459             smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag);
 460         if (args.fa_maxdata == 0)
 461                 return (SDRC_ERROR);
 462 
 463         od = smb_tree_lookup_odir(sr, odid);
 464         if (od == NULL) {
 465                 smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
 466                     ERRDOS, ERROR_INVALID_HANDLE);
 467                 return (SDRC_ERROR);
 468         }
 469 
 470         /*
 471          * Set the correct position in the directory.
 472          *
 473          * "Continue from last" is easy, but due to a history of
 474          * buggy server implementations, most clients don't use
 475          * that method.  The most widely used (and reliable) is
 476          * resume by file name.  Unfortunately, that can't really
 477          * be fully supported unless your file system stores all
 478          * directory entries in some sorted order (like NTFS).
 479          * We can partially support resume by name, where the only
 480          * name we're ever asked to resume on is the same as the


 519 
 520 /*
 521  * smb_trans2_find_entries
 522  *
 523  * Find and encode up to args->fa_maxcount directory entries.
 524  * For compatibilty with Windows, if args->fa_maxcount is zero treat it as 1.
 525  *
 526  * Returns:
 527  *   count - count of entries encoded
 528  *           *eos = B_TRUE if no more directory entries
 529  *      -1 - error
 530  */
 531 static int
 532 smb_trans2_find_entries(smb_request_t *sr, smb_xa_t *xa, smb_odir_t *od,
 533     smb_find_args_t *args)
 534 {
 535         smb_fileinfo_t  fileinfo;
 536         smb_odir_resume_t odir_resume;
 537         uint16_t        count, maxcount;
 538         int             rc = -1;

 539         boolean_t       need_rewind = B_FALSE;
 540 















 541         if ((maxcount = args->fa_maxcount) == 0)
 542                 maxcount = 1;
 543 
 544         if ((smb_trans2_find_max != 0) && (maxcount > smb_trans2_find_max))
 545                 maxcount = smb_trans2_find_max;
 546 
 547         count = 0;
 548         while (count < maxcount) {
 549                 rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &args->fa_eos);
 550                 if (rc != 0 || args->fa_eos != 0)
 551                         break;
 552 

 553                 rc = smb_trans2_find_mbc_encode(sr, xa, &fileinfo, args);
 554                 if (rc == -1)
 555                         return (-1); /* fatal encoding error */
 556                 if (rc == 1) {
 557                         need_rewind = B_TRUE;
 558                         break; /* output space exhausted */
 559                 }
 560 
 561                 /*
 562                  * Save the info about the last file returned.
 563                  */
 564                 args->fa_lastkey = fileinfo.fi_cookie;
 565                 bcopy(fileinfo.fi_name, args->fa_lastname, MAXNAMELEN);
 566 
 567                 ++count;
 568         }
 569         if (args->fa_eos != 0 && rc == ENOENT)
 570                 rc = 0;
 571 









 572         /* save the last cookie returned to client */
 573         if (count != 0)
 574                 smb_odir_save_fname(od, args->fa_lastkey, args->fa_lastname);
 575 
 576         /*
 577          * If all retrieved entries have been successfully encoded
 578          * and eos has not already been detected, check if there are
 579          * any more entries. eos will be set if there are no more.
 580          */
 581         if ((rc == 0) && (args->fa_eos == 0)) {
 582                 rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &args->fa_eos);
 583                 /*
 584                  * If rc == ENOENT, we did not read any additional data.
 585                  * if rc != 0, there's no need to rewind.
 586                  */
 587                 if (rc == 0)
 588                         need_rewind = B_TRUE;
 589         }
 590 
 591         /*
 592          * When the last entry we read from the directory did not
 593          * fit in the return buffer, we will have read one entry
 594          * that will not be returned in this call.  That, and the
 595          * check for EOS just above both can leave the directory
 596          * position incorrect for the next call.  Fix that now.
 597          */
 598         if (need_rewind) {
 599                 bzero(&odir_resume, sizeof (odir_resume));
 600                 odir_resume.or_type = SMB_ODIR_RESUME_COOKIE;
 601                 odir_resume.or_cookie = args->fa_lastkey;
 602                 smb_odir_resume_at(od, &odir_resume);
 603         }
 604 
 605         return (count);
 606 }
 607 
 608 /*
 609  * smb_trans2_find_get_maxdata
 610  *
 611  * Calculate the minimum response space required for the specified
 612  * information level.
 613  *
 614  * A non-zero return value provides the minimum space required.
 615  * A return value of zero indicates an unknown information level.
 616  */
 617 static int
 618 smb_trans2_find_get_maxdata(smb_request_t *sr, uint16_t infolev, uint16_t fflag)

 619 {
 620         int maxdata;
 621 
 622         maxdata = smb_ascii_or_unicode_null_len(sr);
 623 
 624         switch (infolev) {
 625         case SMB_INFO_STANDARD :
 626                 if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
 627                         maxdata += sizeof (int32_t);
 628                 maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 1;
 629                 break;
 630 
 631         case SMB_INFO_QUERY_EA_SIZE:

 632                 if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
 633                         maxdata += sizeof (int32_t);
 634                 maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 4 + 1;
 635                 break;
 636 
 637         case SMB_FIND_FILE_DIRECTORY_INFO:
 638                 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4;
 639                 break;
 640 
 641         case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
 642                 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4;
 643                 break;
 644 
 645         case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO:
 646                 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4 + 8;
 647                 break;
 648 
 649         case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
 650                 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24;
 651                 break;


 703  * the filename. For levels except STANDARD and EA_SIZE, if the
 704  * filename is ascii the name length returned to the client should
 705  * include the null terminator. Otherwise the length returned to
 706  * the client should not include the terminator.
 707  *
 708  * Returns: 0 - data successfully encoded
 709  *          1 - client request's maxdata limit reached
 710  *         -1 - error
 711  */
 712 static int
 713 smb_trans2_find_mbc_encode(smb_request_t *sr, smb_xa_t *xa,
 714     smb_fileinfo_t *fileinfo, smb_find_args_t *args)
 715 {
 716         int             namelen, shortlen;
 717         uint32_t        next_entry_offset;
 718         uint32_t        dsize32, asize32;
 719         uint32_t        mb_flags = 0;
 720         uint32_t        resume_key;
 721         char            buf83[26];
 722         smb_msgbuf_t    mb;

 723 
 724         namelen = smb_ascii_or_unicode_strlen(sr, fileinfo->fi_name);
 725         if (namelen == -1)
 726                 return (-1);
 727 

 728         /*
 729          * If ascii the filename length returned to the client should
 730          * include the null terminator for levels except STANDARD and
 731          * EASIZE.





 732          */
 733         if (!(sr->smb_flg2 & SMB_FLAGS2_UNICODE)) {
 734                 if ((args->fa_infolev != SMB_INFO_STANDARD) &&
 735                     (args->fa_infolev != SMB_INFO_QUERY_EA_SIZE))

















 736                         namelen += 1;






 737         }

 738 
 739         next_entry_offset = args->fa_maxdata + namelen;
 740 
 741         if (MBC_ROOM_FOR(&xa->rep_data_mb, (args->fa_maxdata + namelen)) == 0)
 742                 return (1);
 743 
 744         mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE) ? SMB_MSGBUF_UNICODE : 0;
 745         dsize32 = (fileinfo->fi_size > UINT_MAX) ?
 746             UINT_MAX : (uint32_t)fileinfo->fi_size;
 747         asize32 = (fileinfo->fi_alloc_size > UINT_MAX) ?
 748             UINT_MAX : (uint32_t)fileinfo->fi_alloc_size;
 749 
 750         resume_key = fileinfo->fi_cookie;
 751         if (smbd_use_resume_keys == 0)
 752                 resume_key = 0;
 753 
 754         /*
 755          * This switch handles all the "information levels" (formats)
 756          * that we support.  Note that all formats have the file name
 757          * placed after some fixed-size data, and the code to write
 758          * the file name is factored out at the end of this switch.
 759          */
 760         switch (args->fa_infolev) {
 761         case SMB_INFO_STANDARD:
 762                 if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS)
 763                         (void) smb_mbc_encodef(&xa->rep_data_mb, "l",
 764                             resume_key);
 765 
 766                 (void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwb", sr,
 767                     smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec),
 768                     smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec),
 769                     smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec),
 770                     dsize32,
 771                     asize32,
 772                     fileinfo->fi_dosattr,
 773                     namelen);
 774                 break;
 775 
 776         case SMB_INFO_QUERY_EA_SIZE:

 777                 if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS)
 778                         (void) smb_mbc_encodef(&xa->rep_data_mb, "l",
 779                             resume_key);
 780 
 781                 (void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwlb", sr,
 782                     smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec),
 783                     smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec),
 784                     smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec),
 785                     dsize32,
 786                     asize32,
 787                     fileinfo->fi_dosattr,
 788                     0L,         /* EA Size */
 789                     namelen);
 790                 break;
 791 
 792         case SMB_FIND_FILE_DIRECTORY_INFO:
 793                 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqll", sr,
 794                     next_entry_offset,
 795                     resume_key,
 796                     &fileinfo->fi_crtime,


 904 
 905         default:
 906                 /* invalid info. level */
 907                 return (-1);
 908         }
 909 
 910         /*
 911          * At this point we have written all the fixed-size data
 912          * for the specified info. level, and we're about to put
 913          * the file name string in the message.  We may later
 914          * need the offset in the trans2 data where this string
 915          * is placed, so save the message position now.  Note:
 916          * We also need to account for the alignment padding
 917          * that may precede the unicode string.
 918          */
 919         args->fa_lno = xa->rep_data_mb.chain_offset;
 920         if ((sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0 &&
 921             (args->fa_lno & 1) != 0)
 922                 args->fa_lno++;
 923 
 924         (void) smb_mbc_encodef(&xa->rep_data_mb, "%u", sr,
 925             fileinfo->fi_name);
 926 



 927         return (0);
 928 }
 929 
 930 /*
 931  * Close a search started by a Trans2FindFirst2 request.
 932  */
 933 smb_sdrc_t
 934 smb_pre_find_close2(smb_request_t *sr)
 935 {
 936         DTRACE_SMB_1(op__FindClose2__start, smb_request_t *, sr);
 937         return (SDRC_SUCCESS);
 938 }
 939 
 940 void
 941 smb_post_find_close2(smb_request_t *sr)
 942 {
 943         DTRACE_SMB_1(op__FindClose2__done, smb_request_t *, sr);
 944 }
 945 
 946 smb_sdrc_t
 947 smb_com_find_close2(smb_request_t *sr)
 948 {
 949         uint16_t        odid;
 950         smb_odir_t      *od;
 951 
 952         if (smbsr_decode_vwv(sr, "w", &odid) != 0)
 953                 return (SDRC_ERROR);
 954 
 955         od = smb_tree_lookup_odir(sr, odid);
 956         if (od == NULL) {
 957                 smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
 958                     ERRDOS, ERROR_INVALID_HANDLE);
 959                 return (SDRC_ERROR);
 960         }
 961 
 962         smb_odir_close(od);
 963         smb_odir_release(od);


   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  *
  25  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  26  */
  27 
  28 
  29 /*
  30  * This module provides functions for TRANS2_FIND_FIRST2 and
  31  * TRANS2_FIND_NEXT2 requests. The requests allow the client to search
  32  * for the file(s) which match the file specification.  The search is
  33  * started with TRANS2_FIND_FIRST2 and can be continued if necessary with
  34  * TRANS2_FIND_NEXT2. There are numerous levels of information which may be
  35  * obtained for the returned files, the desired level is specified in the
  36  * InformationLevel field of the requests.
  37  *
  38  *  InformationLevel Name              Value
  39  *  =================================  ================
  40  *
  41  *  SMB_INFO_STANDARD                  1
  42  *  SMB_INFO_QUERY_EA_SIZE             2
  43  *  SMB_INFO_QUERY_EAS_FROM_LIST       3
  44  *  SMB_FIND_FILE_DIRECTORY_INFO       0x101
  45  *  SMB_FIND_FILE_FULL_DIRECTORY_INFO  0x102


 196  *
 197  *  Response Field                     Description
 198  *  =================================  ==================================
 199  *
 200  *  ULONG NextEntryOffset;             Offset from this structure to
 201  *                                     beginning of next one
 202  *  ULONG FileIndex;
 203  *  ULONG FileNameLength;              Length of FileName in bytes
 204  *  STRING FileName;                   Files full length name
 205  */
 206 
 207 #include <smbsrv/smb_kproto.h>
 208 #include <smbsrv/msgbuf.h>
 209 #include <smbsrv/smb_fsops.h>
 210 
 211 /*
 212  * Args (and other state) that we carry around among the
 213  * various functions involved in FindFirst, FindNext.
 214  */
 215 typedef struct smb_find_args {
 216         uint32_t fa_fixedsize;
 217         uint16_t fa_infolev;
 218         uint16_t fa_maxcount;
 219         uint16_t fa_fflag;
 220         uint16_t fa_eos;        /* End Of Search */
 221         uint16_t fa_lno;        /* Last Name Offset */
 222         uint32_t fa_lastkey;    /* Last resume key */
 223         char fa_lastname[MAXNAMELEN]; /* and name */
 224 } smb_find_args_t;
 225 
 226 static int smb_trans2_find_entries(smb_request_t *, smb_xa_t *,
 227     smb_odir_t *, smb_find_args_t *);
 228 static int smb_trans2_find_get_fixedsize(smb_request_t *, uint16_t, uint16_t);
 229 static int smb_trans2_find_mbc_encode(smb_request_t *, smb_xa_t *,
 230     smb_fileinfo_t *, smb_find_args_t *);
 231 
 232 /*
 233  * Tunable parameter to limit the maximum
 234  * number of entries to be returned.
 235  */
 236 uint16_t smb_trans2_find_max = 128;
 237 
 238 /*
 239  * smb_com_trans2_find_first2
 240  *
 241  *  Client Request                Value
 242  *  ============================  ==================================
 243  *
 244  *  UCHAR  WordCount              15
 245  *  UCHAR  TotalDataCount         Total size of extended attribute list
 246  *  UCHAR  SetupCount             1
 247  *  UCHAR  Setup[0]               TRANS2_FIND_FIRST2
 248  *


 303             &args.fa_maxcount, &args.fa_fflag, &args.fa_infolev,
 304             &pn->pn_path) != 0) {
 305                 return (SDRC_ERROR);
 306         }
 307 
 308         smb_pathname_init(sr, pn, pn->pn_path);
 309         if (!smb_pathname_validate(sr, pn))
 310                 return (-1);
 311 
 312         if (smb_is_stream_name(pn->pn_path)) {
 313                 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
 314                     ERRDOS, ERROR_INVALID_NAME);
 315                 return (SDRC_ERROR);
 316         }
 317 
 318         if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT) {
 319                 sr->user_cr = smb_user_getprivcred(sr->uid_user);
 320                 odir_flags = SMB_ODIR_OPENF_BACKUP_INTENT;
 321         }
 322 
 323         args.fa_fixedsize =
 324             smb_trans2_find_get_fixedsize(sr, args.fa_infolev, args.fa_fflag);
 325         if (args.fa_fixedsize == 0)
 326                 return (SDRC_ERROR);
 327 
 328         status = smb_odir_openpath(sr, pn->pn_path, sattr, odir_flags, &od);
 329         if (status != 0) {
 330                 smbsr_error(sr, status, 0, 0);
 331                 return (SDRC_ERROR);
 332         }
 333         if (od == NULL)
 334                 return (SDRC_ERROR);
 335 
 336         count = smb_trans2_find_entries(sr, xa, od, &args);
 337 
 338         if (count == -1) {
 339                 smb_odir_close(od);
 340                 smb_odir_release(od);
 341                 return (SDRC_ERROR);
 342         }
 343 
 344         if (count == 0) {
 345                 smb_odir_close(od);
 346                 smb_odir_release(od);
 347                 smbsr_status(sr, NT_STATUS_NO_SUCH_FILE,
 348                     ERRDOS, ERROR_FILE_NOT_FOUND);
 349                 return (SDRC_ERROR);
 350         }
 351 
 352         if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) ||
 353             (args.fa_eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) {
 354                 smb_odir_close(od);
 355         } /* else leave odir open for trans2_find_next2 */
 356 
 357         (void) smb_mbc_encodef(&xa->rep_param_mb, "wwwww",
 358             od->d_odid,      /* Search ID */
 359             count,      /* Search Count */
 360             args.fa_eos, /* End Of Search */
 361             0,          /* EA Error Offset */
 362             args.fa_lno); /* Last Name Offset */
 363 
 364         smb_odir_release(od);
 365 
 366         return (SDRC_SUCCESS);
 367 }
 368 


 439 
 440         bzero(&args, sizeof (args));
 441         bzero(&odir_resume, sizeof (odir_resume));
 442 
 443         if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
 444                 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
 445                     ERRDOS, ERROR_ACCESS_DENIED);
 446                 return (SDRC_ERROR);
 447         }
 448 
 449         if (smb_mbc_decodef(&xa->req_param_mb, "%wwwlwu", sr,
 450             &odid, &args.fa_maxcount, &args.fa_infolev,
 451             &odir_resume.or_cookie, &args.fa_fflag,
 452             &odir_resume.or_fname) != 0) {
 453                 return (SDRC_ERROR);
 454         }
 455 
 456         if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT)
 457                 sr->user_cr = smb_user_getprivcred(sr->uid_user);
 458 
 459         args.fa_fixedsize =
 460             smb_trans2_find_get_fixedsize(sr, args.fa_infolev, args.fa_fflag);
 461         if (args.fa_fixedsize == 0)
 462                 return (SDRC_ERROR);
 463 
 464         od = smb_tree_lookup_odir(sr, odid);
 465         if (od == NULL) {
 466                 smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
 467                     ERRDOS, ERROR_INVALID_HANDLE);
 468                 return (SDRC_ERROR);
 469         }
 470 
 471         /*
 472          * Set the correct position in the directory.
 473          *
 474          * "Continue from last" is easy, but due to a history of
 475          * buggy server implementations, most clients don't use
 476          * that method.  The most widely used (and reliable) is
 477          * resume by file name.  Unfortunately, that can't really
 478          * be fully supported unless your file system stores all
 479          * directory entries in some sorted order (like NTFS).
 480          * We can partially support resume by name, where the only
 481          * name we're ever asked to resume on is the same as the


 520 
 521 /*
 522  * smb_trans2_find_entries
 523  *
 524  * Find and encode up to args->fa_maxcount directory entries.
 525  * For compatibilty with Windows, if args->fa_maxcount is zero treat it as 1.
 526  *
 527  * Returns:
 528  *   count - count of entries encoded
 529  *           *eos = B_TRUE if no more directory entries
 530  *      -1 - error
 531  */
 532 static int
 533 smb_trans2_find_entries(smb_request_t *sr, smb_xa_t *xa, smb_odir_t *od,
 534     smb_find_args_t *args)
 535 {
 536         smb_fileinfo_t  fileinfo;
 537         smb_odir_resume_t odir_resume;
 538         uint16_t        count, maxcount;
 539         int             rc = -1;
 540         int             LastEntryOffset = 0;
 541         boolean_t       need_rewind = B_FALSE;
 542 
 543         /*
 544          * EAs are not current supported, so a search for level
 545          * SMB_INFO_QUERY_EAS_FROM_LIST should always return an
 546          * empty list.  Returning zero for this case gives the
 547          * client an empty response, which is better than an
 548          * NT_STATUS_INVALID_LEVEL return (and test failures).
 549          *
 550          * If and when we do support EAs, this level will modify
 551          * the search here, and then return results just like
 552          * SMB_INFO_QUERY_EA_SIZE, but only including files
 553          * that have an EA in the provided list.
 554          */
 555         if (args->fa_infolev == SMB_INFO_QUERY_EAS_FROM_LIST)
 556                 return (0);
 557 
 558         if ((maxcount = args->fa_maxcount) == 0)
 559                 maxcount = 1;
 560 
 561         if ((smb_trans2_find_max != 0) && (maxcount > smb_trans2_find_max))
 562                 maxcount = smb_trans2_find_max;
 563 
 564         count = 0;
 565         while (count < maxcount) {
 566                 rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &args->fa_eos);
 567                 if (rc != 0 || args->fa_eos != 0)
 568                         break;
 569 
 570                 LastEntryOffset = xa->rep_data_mb.chain_offset;
 571                 rc = smb_trans2_find_mbc_encode(sr, xa, &fileinfo, args);
 572                 if (rc == -1)
 573                         return (-1); /* fatal encoding error */
 574                 if (rc == 1) {
 575                         need_rewind = B_TRUE;
 576                         break; /* output space exhausted */
 577                 }
 578 
 579                 /*
 580                  * Save the info about the last file returned.
 581                  */
 582                 args->fa_lastkey = fileinfo.fi_cookie;
 583                 bcopy(fileinfo.fi_name, args->fa_lastname, MAXNAMELEN);
 584 
 585                 ++count;
 586         }
 587         if (args->fa_eos != 0 && rc == ENOENT)
 588                 rc = 0;
 589 
 590         /*
 591          * All but the ancient info levels start with NextEntryOffset.
 592          * That's supposed to be zero in the last entry returned.
 593          */
 594         if (args->fa_infolev >= SMB_FIND_FILE_DIRECTORY_INFO) {
 595                 (void) smb_mbc_poke(&xa->rep_data_mb,
 596                     LastEntryOffset, "l", 0);
 597         }
 598 
 599         /* save the last cookie returned to client */
 600         if (count != 0)
 601                 smb_odir_save_fname(od, args->fa_lastkey, args->fa_lastname);
 602 
 603         /*
 604          * If all retrieved entries have been successfully encoded
 605          * and eos has not already been detected, check if there are
 606          * any more entries. eos will be set if there are no more.
 607          */
 608         if ((rc == 0) && (args->fa_eos == 0)) {
 609                 rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &args->fa_eos);
 610                 /*
 611                  * If rc == ENOENT, we did not read any additional data.
 612                  * if rc != 0, there's no need to rewind.
 613                  */
 614                 if (rc == 0)
 615                         need_rewind = B_TRUE;
 616         }
 617 
 618         /*
 619          * When the last entry we read from the directory did not
 620          * fit in the return buffer, we will have read one entry
 621          * that will not be returned in this call.  That, and the
 622          * check for EOS just above both can leave the directory
 623          * position incorrect for the next call.  Fix that now.
 624          */
 625         if (need_rewind) {
 626                 bzero(&odir_resume, sizeof (odir_resume));
 627                 odir_resume.or_type = SMB_ODIR_RESUME_COOKIE;
 628                 odir_resume.or_cookie = args->fa_lastkey;
 629                 smb_odir_resume_at(od, &odir_resume);
 630         }
 631 
 632         return (count);
 633 }
 634 
 635 /*
 636  * smb_trans2_find_get_fixedsize
 637  *
 638  * Calculate the sizeof the fixed part of the response for the
 639  * specified information level.
 640  *
 641  * A non-zero return value provides the fixed size.
 642  * A return value of zero indicates an unknown information level.
 643  */
 644 static int
 645 smb_trans2_find_get_fixedsize(smb_request_t *sr, uint16_t infolev,
 646         uint16_t fflag)
 647 {
 648         int maxdata = 0;
 649 


 650         switch (infolev) {
 651         case SMB_INFO_STANDARD :
 652                 if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
 653                         maxdata += sizeof (int32_t);
 654                 maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 1;
 655                 break;
 656 
 657         case SMB_INFO_QUERY_EA_SIZE:
 658         case SMB_INFO_QUERY_EAS_FROM_LIST:
 659                 if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
 660                         maxdata += sizeof (int32_t);
 661                 maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 4 + 1;
 662                 break;
 663 
 664         case SMB_FIND_FILE_DIRECTORY_INFO:
 665                 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4;
 666                 break;
 667 
 668         case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
 669                 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4;
 670                 break;
 671 
 672         case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO:
 673                 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4 + 8;
 674                 break;
 675 
 676         case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
 677                 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24;
 678                 break;


 730  * the filename. For levels except STANDARD and EA_SIZE, if the
 731  * filename is ascii the name length returned to the client should
 732  * include the null terminator. Otherwise the length returned to
 733  * the client should not include the terminator.
 734  *
 735  * Returns: 0 - data successfully encoded
 736  *          1 - client request's maxdata limit reached
 737  *         -1 - error
 738  */
 739 static int
 740 smb_trans2_find_mbc_encode(smb_request_t *sr, smb_xa_t *xa,
 741     smb_fileinfo_t *fileinfo, smb_find_args_t *args)
 742 {
 743         int             namelen, shortlen;
 744         uint32_t        next_entry_offset;
 745         uint32_t        dsize32, asize32;
 746         uint32_t        mb_flags = 0;
 747         uint32_t        resume_key;
 748         char            buf83[26];
 749         smb_msgbuf_t    mb;
 750         int             pad = 0;
 751 
 752         namelen = smb_ascii_or_unicode_strlen(sr, fileinfo->fi_name);
 753         if (namelen == -1)
 754                 return (-1);
 755 
 756         if (args->fa_infolev < SMB_FIND_FILE_DIRECTORY_INFO) {
 757                 /*
 758                  * Ancient info levels don't have a NextEntryOffset
 759                  * field, so there's no padding for alignment.
 760                  * The client expects a null after the file name,
 761                  * and then the next entry.  The namelength field
 762                  * never includes the null for these old levels.
 763                  * Using the pad value to write the null because
 764                  * we don't want to add that to namelen.
 765                  * [MS-CIFS] sec. 2.8.1.{1-3}
 766                  */
 767                 if ((sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0)
 768                         pad = 2; /* Unicode null */
 769                 else
 770                         pad = 1; /* ascii null */
 771                 next_entry_offset = args->fa_fixedsize + namelen + pad;
 772                 if (!MBC_ROOM_FOR(&xa->rep_data_mb, next_entry_offset))
 773                         return (1);
 774         } else {
 775                 /*
 776                  * Later info levels: The file name is written WITH
 777                  * null termination, and the size of that null _is_
 778                  * included in the namelen field.  There may also
 779                  * be padding, and we pad to align(4) like Windows.
 780                  * Don't include the padding in the "room for" test
 781                  * because we want to ignore any error writing the
 782                  * pad bytes after the last element.
 783                  */
 784                 if ((sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0)
 785                         namelen += 2;
 786                 else
 787                         namelen += 1;
 788                 next_entry_offset = args->fa_fixedsize + namelen;
 789                 if (!MBC_ROOM_FOR(&xa->rep_data_mb, next_entry_offset))
 790                         return (1);
 791                 if ((next_entry_offset & 3) != 0) {
 792                         pad = 4 - (next_entry_offset & 3);
 793                         next_entry_offset += pad;
 794                 }
 795         }
 796 





 797         mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE) ? SMB_MSGBUF_UNICODE : 0;
 798         dsize32 = (fileinfo->fi_size > UINT_MAX) ?
 799             UINT_MAX : (uint32_t)fileinfo->fi_size;
 800         asize32 = (fileinfo->fi_alloc_size > UINT_MAX) ?
 801             UINT_MAX : (uint32_t)fileinfo->fi_alloc_size;
 802 
 803         resume_key = fileinfo->fi_cookie;
 804         if (smbd_use_resume_keys == 0)
 805                 resume_key = 0;
 806 
 807         /*
 808          * This switch handles all the "information levels" (formats)
 809          * that we support.  Note that all formats have the file name
 810          * placed after some fixed-size data, and the code to write
 811          * the file name is factored out at the end of this switch.
 812          */
 813         switch (args->fa_infolev) {
 814         case SMB_INFO_STANDARD:
 815                 if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS)
 816                         (void) smb_mbc_encodef(&xa->rep_data_mb, "l",
 817                             resume_key);
 818 
 819                 (void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwb", sr,
 820                     smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec),
 821                     smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec),
 822                     smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec),
 823                     dsize32,
 824                     asize32,
 825                     fileinfo->fi_dosattr,
 826                     namelen);
 827                 break;
 828 
 829         case SMB_INFO_QUERY_EA_SIZE:
 830         case SMB_INFO_QUERY_EAS_FROM_LIST:
 831                 if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS)
 832                         (void) smb_mbc_encodef(&xa->rep_data_mb, "l",
 833                             resume_key);
 834 
 835                 (void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwlb", sr,
 836                     smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec),
 837                     smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec),
 838                     smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec),
 839                     dsize32,
 840                     asize32,
 841                     fileinfo->fi_dosattr,
 842                     0L,         /* EA Size */
 843                     namelen);
 844                 break;
 845 
 846         case SMB_FIND_FILE_DIRECTORY_INFO:
 847                 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqll", sr,
 848                     next_entry_offset,
 849                     resume_key,
 850                     &fileinfo->fi_crtime,


 958 
 959         default:
 960                 /* invalid info. level */
 961                 return (-1);
 962         }
 963 
 964         /*
 965          * At this point we have written all the fixed-size data
 966          * for the specified info. level, and we're about to put
 967          * the file name string in the message.  We may later
 968          * need the offset in the trans2 data where this string
 969          * is placed, so save the message position now.  Note:
 970          * We also need to account for the alignment padding
 971          * that may precede the unicode string.
 972          */
 973         args->fa_lno = xa->rep_data_mb.chain_offset;
 974         if ((sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0 &&
 975             (args->fa_lno & 1) != 0)
 976                 args->fa_lno++;
 977 
 978         (void) smb_mbc_encodef(&xa->rep_data_mb, "%#u", sr,
 979             namelen, fileinfo->fi_name);
 980 
 981         if (pad)
 982                 (void) smb_mbc_encodef(&xa->rep_data_mb, "#.", pad);
 983 
 984         return (0);
 985 }
 986 
 987 /*
 988  * Close a search started by a Trans2FindFirst2 request.
 989  */
 990 smb_sdrc_t
 991 smb_pre_find_close2(smb_request_t *sr)
 992 {
 993         DTRACE_SMB_START(op__FindClose2, smb_request_t *, sr);
 994         return (SDRC_SUCCESS);
 995 }
 996 
 997 void
 998 smb_post_find_close2(smb_request_t *sr)
 999 {
1000         DTRACE_SMB_DONE(op__FindClose2, smb_request_t *, sr);
1001 }
1002 
1003 smb_sdrc_t
1004 smb_com_find_close2(smb_request_t *sr)
1005 {
1006         uint16_t        odid;
1007         smb_odir_t      *od;
1008 
1009         if (smbsr_decode_vwv(sr, "w", &odid) != 0)
1010                 return (SDRC_ERROR);
1011 
1012         od = smb_tree_lookup_odir(sr, odid);
1013         if (od == NULL) {
1014                 smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
1015                     ERRDOS, ERROR_INVALID_HANDLE);
1016                 return (SDRC_ERROR);
1017         }
1018 
1019         smb_odir_close(od);
1020         smb_odir_release(od);