1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   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
  46  *  SMB_FIND_FILE_NAMES_INFO           0x103
  47  *  SMB_FIND_FILE_BOTH_DIRECTORY_INFO  0x104
  48  *  SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO  0x105
  49  *  SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO  0x106
  50  *
  51  * The following sections detail the data returned for each
  52  * InformationLevel. The requested information is placed in the Data
  53  * portion of the transaction response. Note: a client which does not
  54  * support long names can only request SMB_INFO_STANDARD.
  55  *
  56  * A four-byte resume key precedes each data item (described below) if bit
  57  * 2 in the Flags field is set, i.e. if the request indicates the server
  58  * should return resume keys. Note: it is not always the case. If the
  59  * data item already includes the resume key, the resume key should not be
  60  * added again.
  61  *
  62  * 4.3.4.1   SMB_INFO_STANDARD
  63  *
  64  *  Response Field                    Description
  65  *  ================================  ==================================
  66  *
  67  *  SMB_DATE CreationDate;            Date when file was created
  68  *  SMB_TIME CreationTime;            Time when file was created
  69  *  SMB_DATE LastAccessDate;          Date of last file access
  70  *  SMB_TIME LastAccessTime;          Time of last file access
  71  *  SMB_DATE LastWriteDate;           Date of last write to the file
  72  *  SMB_TIME LastWriteTime;           Time of last write to the file
  73  *  ULONG  DataSize;                  File Size
  74  *  ULONG AllocationSize;             Size of filesystem allocation unit
  75  *  USHORT Attributes;                File Attributes
  76  *  UCHAR FileNameLength;             Length of filename in bytes
  77  *  STRING FileName;                  Name of found file
  78  *
  79  * 4.3.4.2   SMB_INFO_QUERY_EA_SIZE
  80  *
  81  *  Response Field                     Description
  82  *  =================================  ==================================
  83  *
  84  *   SMB_DATE CreationDate;            Date when file was created
  85  *   SMB_TIME CreationTime;            Time when file was created
  86  *   SMB_DATE LastAccessDate;          Date of last file access
  87  *   SMB_TIME LastAccessTime;          Time of last file access
  88  *   SMB_DATE LastWriteDate;           Date of last write to the file
  89  *   SMB_TIME LastWriteTime;           Time of last write to the file
  90  *   ULONG DataSize;                   File Size
  91  *   ULONG AllocationSize;             Size of filesystem allocation unit
  92  *   USHORT Attributes;                File Attributes
  93  *   ULONG EaSize;                     Size of file's EA information
  94  *   UCHAR FileNameLength;             Length of filename in bytes
  95  *   STRING FileName;                  Name of found file
  96  *
  97  * 4.3.4.3   SMB_INFO_QUERY_EAS_FROM_LIST
  98  *
  99  * This request returns the same information as SMB_INFO_QUERY_EA_SIZE, but
 100  * only for files which have an EA list which match the EA information in
 101  * the Data part of the request.
 102  *
 103  * 4.3.4.4   SMB_FIND_FILE_DIRECTORY_INFO
 104  *
 105  *  Response Field                     Description
 106  *  =================================  ==================================
 107  *
 108  *  ULONG NextEntryOffset;             Offset from this structure to
 109  *                                      beginning of next one
 110  *  ULONG FileIndex;
 111  *  LARGE_INTEGER CreationTime;        file creation time
 112  *  LARGE_INTEGER LastAccessTime;      last access time
 113  *  LARGE_INTEGER LastWriteTime;       last write time
 114  *  LARGE_INTEGER ChangeTime;          last attribute change time
 115  *  LARGE_INTEGER EndOfFile;           file size
 116  *  LARGE_INTEGER AllocationSize;      size of filesystem allocation information
 117  *  ULONG ExtFileAttributes;           Extended file attributes
 118  *                                      (see section 3.11)
 119  *  ULONG FileNameLength;              Length of filename in bytes
 120  *  STRING FileName;                   Name of the file
 121  *
 122  * 4.3.4.5   SMB_FIND_FILE_FULL_DIRECTORY_INFO
 123  *
 124  *  Response Field                     Description
 125  *  =================================  ==================================
 126  *
 127  *  ULONG NextEntryOffset;             Offset from this structure to
 128  *                                      beginning of next one
 129  *  ULONG FileIndex;
 130  *  LARGE_INTEGER CreationTime;        file creation time
 131  *  LARGE_INTEGER LastAccessTime;      last access time
 132  *  LARGE_INTEGER LastWriteTime;       last write time
 133  *  LARGE_INTEGER ChangeTime;          last attribute change time
 134  *  LARGE_INTEGER EndOfFile;           file size
 135  *  LARGE_INTEGER AllocationSize;      size of filesystem allocation information
 136  *  ULONG ExtFileAttributes;           Extended file attributes
 137  *                                      (see section 3.11)
 138  *  ULONG FileNameLength;              Length of filename in bytes
 139  *  ULONG EaSize;                      Size of file's extended attributes
 140  *  STRING FileName;                   Name of the file
 141  *
 142  *
 143  *  SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO
 144  *
 145  *  This is the same as SMB_FIND_FILE_FULL_DIRECTORY_INFO but with
 146  *  FileId inserted after EaSize. FileId is preceded by a 4 byte
 147  *  alignment padding.
 148  *
 149  *  Response Field                     Description
 150  *  =================================  ==================================
 151  *  ...
 152  *  ULONG EaSize;                      Size of file's extended attributes
 153  *  UCHAR Reserved[4]
 154  *  LARGE_INTEGER FileId               Internal file system unique id.
 155  *  STRING FileName;                   Name of the file
 156  *
 157  * 4.3.4.6   SMB_FIND_FILE_BOTH_DIRECTORY_INFO
 158  *
 159  *  Response Field                     Description
 160  *  =================================  ==================================
 161  *
 162  *  ULONG NextEntryOffset;             Offset from this structure to
 163  *                                      beginning of next one
 164  *  ULONG FileIndex;
 165  *  LARGE_INTEGER CreationTime;        file creation time
 166  *  LARGE_INTEGER LastAccessTime;      last access time
 167  *  LARGE_INTEGER LastWriteTime;       last write time
 168  *  LARGE_INTEGER ChangeTime;          last attribute change time
 169  *  LARGE_INTEGER EndOfFile;           file size
 170  *  LARGE_INTEGER AllocationSize;      size of filesystem allocation information
 171  *  ULONG ExtFileAttributes;           Extended file attributes
 172  *                                      (see section 3.11)
 173  *  ULONG FileNameLength;              Length of FileName in bytes
 174  *  ULONG EaSize;                      Size of file's extended attributes
 175  *  UCHAR ShortNameLength;             Length of file's short name in bytes
 176  *  UCHAR Reserved
 177  *  WCHAR ShortName[12];               File's 8.3 conformant name in Unicode
 178  *  STRING FileName;                   Files full length name
 179  *
 180  *
 181  *  SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO
 182  *
 183  *  This is the same as SMB_FIND_FILE_BOTH_DIRECTORY_INFO but with
 184  *  FileId inserted after ShortName. FileId is preceded by a 2 byte
 185  *  alignment pad.
 186  *
 187  *  Response Field                     Description
 188  *  =================================  ==================================
 189  *  ...
 190  *  WCHAR ShortName[12];               File's 8.3 conformant name in Unicode
 191  *  UCHAR Reserved[2]
 192  *  LARGE_INTEGER FileId               Internal file system unique id.
 193  *  STRING FileName;                   Files full length name
 194  *
 195  * 4.3.4.7   SMB_FIND_FILE_NAMES_INFO
 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  *
 249  *  Parameter Block Encoding      Description
 250  *  ============================  ==================================
 251  *  USHORT SearchAttributes;
 252  *  USHORT SearchCount;           Maximum number of entries to return
 253  *  USHORT Flags;                 Additional information:
 254  *                                Bit 0 - close search after this request
 255  *                                Bit 1 - close search if end of search
 256  *                                reached
 257  *                                Bit 2 - return resume keys for each
 258  *                                entry found
 259  *                                Bit 3 - continue search from previous
 260  *                                ending place
 261  *                                Bit 4 - find with backup intent
 262  *  USHORT InformationLevel;      See below
 263  *  ULONG SearchStorageType;
 264  *  STRING FileName;              Pattern for the search
 265  *  UCHAR Data[ TotalDataCount ]  FEAList if InformationLevel is
 266  *                                QUERY_EAS_FROM_LIST
 267  *
 268  *  Response Parameter Block      Description
 269  *  ============================  ==================================
 270  *
 271  *  USHORT Sid;                   Search handle
 272  *  USHORT SearchCount;           Number of entries returned
 273  *  USHORT EndOfSearch;           Was last entry returned?
 274  *  USHORT EaErrorOffset;         Offset into EA list if EA error
 275  *  USHORT LastNameOffset;        Offset into data to file name of last
 276  *                                entry, if server needs it to resume
 277  *                                search; else 0
 278  *  UCHAR Data[ TotalDataCount ]  Level dependent info about the matches
 279  *                                found in the search
 280  */
 281 smb_sdrc_t
 282 smb_com_trans2_find_first2(smb_request_t *sr, smb_xa_t *xa)
 283 {
 284         int             count;
 285         uint16_t        sattr;
 286         smb_pathname_t  *pn;
 287         smb_odir_t      *od;
 288         smb_find_args_t args;
 289         uint32_t        status;
 290         uint32_t        odir_flags = 0;
 291 
 292         bzero(&args, sizeof (smb_find_args_t));
 293 
 294         if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
 295                 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
 296                     ERRDOS, ERROR_ACCESS_DENIED);
 297                 return (SDRC_ERROR);
 298         }
 299 
 300         pn = &sr->arg.dirop.fqi.fq_path;
 301 
 302         if (smb_mbc_decodef(&xa->req_param_mb, "%wwww4.u", sr, &sattr,
 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 
 369 /*
 370  * smb_com_trans2_find_next2
 371  *
 372  *  Client Request                     Value
 373  *  ================================== =================================
 374  *
 375  *  WordCount                          15
 376  *  SetupCount                         1
 377  *  Setup[0]                           TRANS2_FIND_NEXT2
 378  *
 379  *  Parameter Block Encoding           Description
 380  *  ================================== =================================
 381  *
 382  *  USHORT Sid;                        Search handle
 383  *  USHORT SearchCount;                Maximum number of entries to
 384  *                                      return
 385  *  USHORT InformationLevel;           Levels described in
 386  *                                      TRANS2_FIND_FIRST2 request
 387  *  ULONG ResumeKey;                   Value returned by previous find2
 388  *                                      call
 389  *  USHORT Flags;                      Additional information: bit set-
 390  *                                      0 - close search after this
 391  *                                      request
 392  *                                      1 - close search if end of search
 393  *                                      reached
 394  *                                      2 - return resume keys for each
 395  *                                      entry found
 396  *                                      3 - resume/continue from previous
 397  *                                      ending place
 398  *                                      4 - find with backup intent
 399  *  STRING FileName;                   Resume file name
 400  *
 401  * Sid is the value returned by a previous successful TRANS2_FIND_FIRST2
 402  * call.  If Bit3 of Flags is set, then FileName may be the NULL string,
 403  * since the search is continued from the previous TRANS2_FIND request.
 404  * Otherwise, FileName must not be more than 256 characters long.
 405  *
 406  *  Response Field                     Description
 407  *  ================================== =================================
 408  *
 409  *  USHORT SearchCount;                Number of entries returned
 410  *  USHORT EndOfSearch;                Was last entry returned?
 411  *  USHORT EaErrorOffset;              Offset into EA list if EA error
 412  *  USHORT LastNameOffset;             Offset into data to file name of
 413  *                                      last entry, if server needs it to
 414  *                                      resume search; else 0
 415  *  UCHAR Data[TotalDataCount]         Level dependent info about the
 416  *                                      matches found in the search
 417  *
 418  *
 419  * The last parameter in the request is a filename, which is a
 420  * null-terminated unicode string.
 421  *
 422  * smb_mbc_decodef(&xa->req_param_mb, "%www lwu", sr,
 423  *    &odid, &fa_maxcount, &fa_infolev, &cookie, &fa_fflag, &fname)
 424  *
 425  * The filename parameter is not currently decoded because we
 426  * expect a 2-byte null but Mac OS 10 clients send a 1-byte null,
 427  * which leads to a decode error.
 428  * Thus, we do not support resume by filename.  We treat a request
 429  * to resume by filename as SMB_FIND_CONTINUE_FROM_LAST.
 430  */
 431 smb_sdrc_t
 432 smb_com_trans2_find_next2(smb_request_t *sr, smb_xa_t *xa)
 433 {
 434         int                     count;
 435         uint16_t                odid;
 436         smb_odir_t              *od;
 437         smb_find_args_t         args;
 438         smb_odir_resume_t       odir_resume;
 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
 482          * most recent we returned.  That's always what the client
 483          * gives us as the resume name, so we can simply remember
 484          * the last name/offset pair and use that to position on
 485          * the following FindNext call.  In the unlikely event
 486          * that the client asks to resume somewhere else, we'll
 487          * use the numeric resume key, and hope the client gives
 488          * correctly uses one of the resume keys we provided.
 489          */
 490         if (args.fa_fflag & SMB_FIND_CONTINUE_FROM_LAST) {
 491                 odir_resume.or_type = SMB_ODIR_RESUME_CONT;
 492         } else {
 493                 odir_resume.or_type = SMB_ODIR_RESUME_FNAME;
 494         }
 495         smb_odir_resume_at(od, &odir_resume);
 496 
 497         count = smb_trans2_find_entries(sr, xa, od, &args);
 498         if (count == -1) {
 499                 smb_odir_close(od);
 500                 smb_odir_release(od);
 501                 return (SDRC_ERROR);
 502         }
 503 
 504         if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) ||
 505             (args.fa_eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) {
 506                 smb_odir_close(od);
 507         } /* else leave odir open for trans2_find_next2 */
 508 
 509         smb_odir_release(od);
 510 
 511         (void) smb_mbc_encodef(&xa->rep_param_mb, "wwww",
 512             count,      /* Search Count */
 513             args.fa_eos, /* End Of Search */
 514             0,          /* EA Error Offset */
 515             args.fa_lno); /* Last Name Offset */
 516 
 517         return (SDRC_SUCCESS);
 518 }
 519 
 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;
 679 
 680         case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO:
 681                 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24
 682                     + 2 + 8;
 683                 break;
 684 
 685         case SMB_FIND_FILE_NAMES_INFO:
 686                 maxdata += 4 + 4 + 4;
 687                 break;
 688 
 689         case SMB_MAC_FIND_BOTH_HFS_INFO:
 690                 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 1 + 1 + 2 +
 691                     4 + 32 + 4 + 1 + 1 + 24 + 4;
 692                 break;
 693 
 694         default:
 695                 maxdata = 0;
 696                 smbsr_error(sr, NT_STATUS_INVALID_LEVEL,
 697                     ERRDOS, ERROR_INVALID_LEVEL);
 698         }
 699 
 700         return (maxdata);
 701 }
 702 
 703 /*
 704  * This is an experimental feature that allows us to return zero
 705  * for all numeric resume keys, to match Windows behavior with an
 706  * NTFS share.  Setting this variable to zero does that.
 707  *
 708  * It's possible we could remove this variable and always set
 709  * numeric resume keys to zero, but that would leave us unable
 710  * to handle a FindNext call with an arbitrary start position.
 711  * In practice we never see these, but in theory we could.
 712  *
 713  * See the long comment above smb_com_trans2_find_next2() for
 714  * more details about resume key / resume name handling.
 715  */
 716 int smbd_use_resume_keys = 1;
 717 
 718 /*
 719  * smb_trans2_mbc_encode
 720  *
 721  * This function encodes the mbc for one directory entry.
 722  *
 723  * The function returns -1 when the max data requested by client
 724  * is reached. If the entry is valid and successful encoded, 0
 725  * will be returned; otherwise, 1 will be returned.
 726  *
 727  * We always null terminate the filename. The space for the null
 728  * is included in the maxdata calculation and is therefore included
 729  * in the next_entry_offset. namelen is the unterminated length of
 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,
 851                     &fileinfo->fi_atime,
 852                     &fileinfo->fi_mtime,
 853                     &fileinfo->fi_ctime,
 854                     fileinfo->fi_size,
 855                     fileinfo->fi_alloc_size,
 856                     fileinfo->fi_dosattr,
 857                     namelen);
 858                 break;
 859 
 860         case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
 861                 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll", sr,
 862                     next_entry_offset,
 863                     resume_key,
 864                     &fileinfo->fi_crtime,
 865                     &fileinfo->fi_atime,
 866                     &fileinfo->fi_mtime,
 867                     &fileinfo->fi_ctime,
 868                     fileinfo->fi_size,
 869                     fileinfo->fi_alloc_size,
 870                     fileinfo->fi_dosattr,
 871                     namelen,
 872                     0L);
 873                 break;
 874 
 875         case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO:
 876                 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll4.q", sr,
 877                     next_entry_offset,
 878                     resume_key,
 879                     &fileinfo->fi_crtime,
 880                     &fileinfo->fi_atime,
 881                     &fileinfo->fi_mtime,
 882                     &fileinfo->fi_ctime,
 883                     fileinfo->fi_size,
 884                     fileinfo->fi_alloc_size,
 885                     fileinfo->fi_dosattr,
 886                     namelen,
 887                     0L,
 888                     fileinfo->fi_nodeid);
 889                 break;
 890 
 891         case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
 892                 bzero(buf83, sizeof (buf83));
 893                 smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83),
 894                     mb_flags);
 895                 if (smb_msgbuf_encode(&mb, "U", fileinfo->fi_shortname) < 0) {
 896                         smb_msgbuf_term(&mb);
 897                         return (-1);
 898                 }
 899                 shortlen = smb_wcequiv_strlen(fileinfo->fi_shortname);
 900 
 901                 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllb.24c",
 902                     sr,
 903                     next_entry_offset,
 904                     resume_key,
 905                     &fileinfo->fi_crtime,
 906                     &fileinfo->fi_atime,
 907                     &fileinfo->fi_mtime,
 908                     &fileinfo->fi_ctime,
 909                     fileinfo->fi_size,
 910                     fileinfo->fi_alloc_size,
 911                     fileinfo->fi_dosattr,
 912                     namelen,
 913                     0L,
 914                     shortlen,
 915                     buf83);
 916 
 917                 smb_msgbuf_term(&mb);
 918                 break;
 919 
 920         case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO:
 921                 bzero(buf83, sizeof (buf83));
 922                 smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83),
 923                     mb_flags);
 924                 if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_shortname) < 0) {
 925                         smb_msgbuf_term(&mb);
 926                         return (-1);
 927                 }
 928                 shortlen = smb_ascii_or_unicode_strlen(sr,
 929                     fileinfo->fi_shortname);
 930 
 931                 (void) smb_mbc_encodef(&xa->rep_data_mb,
 932                     "%llTTTTqqlllb.24c2.q",
 933                     sr,
 934                     next_entry_offset,
 935                     resume_key,
 936                     &fileinfo->fi_crtime,
 937                     &fileinfo->fi_atime,
 938                     &fileinfo->fi_mtime,
 939                     &fileinfo->fi_ctime,
 940                     fileinfo->fi_size,
 941                     fileinfo->fi_alloc_size,
 942                     fileinfo->fi_dosattr,
 943                     namelen,
 944                     0L,
 945                     shortlen,
 946                     buf83,
 947                     fileinfo->fi_nodeid);
 948 
 949                 smb_msgbuf_term(&mb);
 950                 break;
 951 
 952         case SMB_FIND_FILE_NAMES_INFO:
 953                 (void) smb_mbc_encodef(&xa->rep_data_mb, "%lll", sr,
 954                     next_entry_offset,
 955                     resume_key,
 956                     namelen);
 957                 break;
 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);
1021 
1022         if (smbsr_encode_empty_result(sr))
1023                 return (SDRC_ERROR);
1024 
1025         return (SDRC_SUCCESS);
1026 }