Home | History | Annotate | Download | only in smbsrv
      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 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 
     27 /*
     28  * This module provides functions for TRANS2_FIND_FIRST2 and
     29  * TRANS2_FIND_NEXT2 requests. The requests allow the client to search
     30  * for the file(s) which match the file specification.  The search is
     31  * started with TRANS2_FIND_FIRST2 and can be continued if necessary with
     32  * TRANS2_FIND_NEXT2. There are numerous levels of information which may be
     33  * obtained for the returned files, the desired level is specified in the
     34  * InformationLevel field of the requests.
     35  *
     36  *  InformationLevel Name              Value
     37  *  =================================  ================
     38  *
     39  *  SMB_INFO_STANDARD                  1
     40  *  SMB_INFO_QUERY_EA_SIZE             2
     41  *  SMB_INFO_QUERY_EAS_FROM_LIST       3
     42  *  SMB_FIND_FILE_DIRECTORY_INFO       0x101
     43  *  SMB_FIND_FILE_FULL_DIRECTORY_INFO  0x102
     44  *  SMB_FIND_FILE_NAMES_INFO           0x103
     45  *  SMB_FIND_FILE_BOTH_DIRECTORY_INFO  0x104
     46  *  SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO  0x105
     47  *  SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO  0x106
     48  *
     49  * The following sections detail the data returned for each
     50  * InformationLevel. The requested information is placed in the Data
     51  * portion of the transaction response. Note: a client which does not
     52  * support long names can only request SMB_INFO_STANDARD.
     53  *
     54  * A four-byte resume key precedes each data item (described below) if bit
     55  * 2 in the Flags field is set, i.e. if the request indicates the server
     56  * should return resume keys. Note: it is not always the case. If the
     57  * data item already includes the resume key, the resume key should not be
     58  * added again.
     59  *
     60  * 4.3.4.1   SMB_INFO_STANDARD
     61  *
     62  *  Response Field                    Description
     63  *  ================================  ==================================
     64  *
     65  *  SMB_DATE CreationDate;            Date when file was created
     66  *  SMB_TIME CreationTime;            Time when file was created
     67  *  SMB_DATE LastAccessDate;          Date of last file access
     68  *  SMB_TIME LastAccessTime;          Time of last file access
     69  *  SMB_DATE LastWriteDate;           Date of last write to the file
     70  *  SMB_TIME LastWriteTime;           Time of last write to the file
     71  *  ULONG  DataSize;                  File Size
     72  *  ULONG AllocationSize;             Size of filesystem allocation unit
     73  *  USHORT Attributes;                File Attributes
     74  *  UCHAR FileNameLength;             Length of filename in bytes
     75  *  STRING FileName;                  Name of found file
     76  *
     77  * 4.3.4.2   SMB_INFO_QUERY_EA_SIZE
     78  *
     79  *  Response Field                     Description
     80  *  =================================  ==================================
     81  *
     82  *   SMB_DATE CreationDate;            Date when file was created
     83  *   SMB_TIME CreationTime;            Time when file was created
     84  *   SMB_DATE LastAccessDate;          Date of last file access
     85  *   SMB_TIME LastAccessTime;          Time of last file access
     86  *   SMB_DATE LastWriteDate;           Date of last write to the file
     87  *   SMB_TIME LastWriteTime;           Time of last write to the file
     88  *   ULONG DataSize;                   File Size
     89  *   ULONG AllocationSize;             Size of filesystem allocation unit
     90  *   USHORT Attributes;                File Attributes
     91  *   ULONG EaSize;                     Size of file's EA information
     92  *   UCHAR FileNameLength;             Length of filename in bytes
     93  *   STRING FileName;                  Name of found file
     94  *
     95  * 4.3.4.3   SMB_INFO_QUERY_EAS_FROM_LIST
     96  *
     97  * This request returns the same information as SMB_INFO_QUERY_EA_SIZE, but
     98  * only for files which have an EA list which match the EA information in
     99  * the Data part of the request.
    100  *
    101  * 4.3.4.4   SMB_FIND_FILE_DIRECTORY_INFO
    102  *
    103  *  Response Field                     Description
    104  *  =================================  ==================================
    105  *
    106  *  ULONG NextEntryOffset;             Offset from this structure to
    107  *					beginning of next one
    108  *  ULONG FileIndex;
    109  *  LARGE_INTEGER CreationTime;        file creation time
    110  *  LARGE_INTEGER LastAccessTime;      last access time
    111  *  LARGE_INTEGER LastWriteTime;       last write time
    112  *  LARGE_INTEGER ChangeTime;          last attribute change time
    113  *  LARGE_INTEGER EndOfFile;           file size
    114  *  LARGE_INTEGER AllocationSize;      size of filesystem allocation information
    115  *  ULONG ExtFileAttributes;           Extended file attributes
    116  *					(see section 3.11)
    117  *  ULONG FileNameLength;              Length of filename in bytes
    118  *  STRING FileName;                   Name of the file
    119  *
    120  * 4.3.4.5   SMB_FIND_FILE_FULL_DIRECTORY_INFO
    121  *
    122  *  Response Field                     Description
    123  *  =================================  ==================================
    124  *
    125  *  ULONG NextEntryOffset;             Offset from this structure to
    126  *					beginning of next one
    127  *  ULONG FileIndex;
    128  *  LARGE_INTEGER CreationTime;        file creation time
    129  *  LARGE_INTEGER LastAccessTime;      last access time
    130  *  LARGE_INTEGER LastWriteTime;       last write time
    131  *  LARGE_INTEGER ChangeTime;          last attribute change time
    132  *  LARGE_INTEGER EndOfFile;           file size
    133  *  LARGE_INTEGER AllocationSize;      size of filesystem allocation information
    134  *  ULONG ExtFileAttributes;           Extended file attributes
    135  *					(see section 3.11)
    136  *  ULONG FileNameLength;              Length of filename in bytes
    137  *  ULONG EaSize;                      Size of file's extended attributes
    138  *  STRING FileName;                   Name of the file
    139  *
    140  *
    141  *  SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO
    142  *
    143  *  This is the same as SMB_FIND_FILE_FULL_DIRECTORY_INFO but with
    144  *  FileId inserted after EaSize. FileId is preceded by a 4 byte
    145  *  alignment padding.
    146  *
    147  *  Response Field                     Description
    148  *  =================================  ==================================
    149  *  ...
    150  *  ULONG EaSize;                      Size of file's extended attributes
    151  *  UCHAR Reserved[4]
    152  *  LARGE_INTEGER FileId               Internal file system unique id.
    153  *  STRING FileName;                   Name of the file
    154  *
    155  * 4.3.4.6   SMB_FIND_FILE_BOTH_DIRECTORY_INFO
    156  *
    157  *  Response Field                     Description
    158  *  =================================  ==================================
    159  *
    160  *  ULONG NextEntryOffset;             Offset from this structure to
    161  *					beginning of next one
    162  *  ULONG FileIndex;
    163  *  LARGE_INTEGER CreationTime;        file creation time
    164  *  LARGE_INTEGER LastAccessTime;      last access time
    165  *  LARGE_INTEGER LastWriteTime;       last write time
    166  *  LARGE_INTEGER ChangeTime;          last attribute change time
    167  *  LARGE_INTEGER EndOfFile;           file size
    168  *  LARGE_INTEGER AllocationSize;      size of filesystem allocation information
    169  *  ULONG ExtFileAttributes;           Extended file attributes
    170  *					(see section 3.11)
    171  *  ULONG FileNameLength;              Length of FileName in bytes
    172  *  ULONG EaSize;                      Size of file's extended attributes
    173  *  UCHAR ShortNameLength;             Length of file's short name in bytes
    174  *  UCHAR Reserved
    175  *  WCHAR ShortName[12];               File's 8.3 conformant name in Unicode
    176  *  STRING FileName;                   Files full length name
    177  *
    178  *
    179  *  SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO
    180  *
    181  *  This is the same as SMB_FIND_FILE_BOTH_DIRECTORY_INFO but with
    182  *  FileId inserted after ShortName. FileId is preceded by a 2 byte
    183  *  alignment pad.
    184  *
    185  *  Response Field                     Description
    186  *  =================================  ==================================
    187  *  ...
    188  *  WCHAR ShortName[12];               File's 8.3 conformant name in Unicode
    189  *  UCHAR Reserved[2]
    190  *  LARGE_INTEGER FileId               Internal file system unique id.
    191  *  STRING FileName;                   Files full length name
    192  *
    193  * 4.3.4.7   SMB_FIND_FILE_NAMES_INFO
    194  *
    195  *  Response Field                     Description
    196  *  =================================  ==================================
    197  *
    198  *  ULONG NextEntryOffset;             Offset from this structure to
    199  *                                     beginning of next one
    200  *  ULONG FileIndex;
    201  *  ULONG FileNameLength;              Length of FileName in bytes
    202  *  STRING FileName;                   Files full length name
    203  */
    204 
    205 #include <smbsrv/smb_kproto.h>
    206 #include <smbsrv/msgbuf.h>
    207 #include <smbsrv/smb_fsops.h>
    208 
    209 typedef struct smb_find_args {
    210 	uint16_t fa_infolev;
    211 	uint16_t fa_maxcount;
    212 	uint16_t fa_fflag;
    213 	uint32_t fa_maxdata;
    214 } smb_find_args_t;
    215 
    216 static int smb_trans2_find_entries(smb_request_t *, smb_xa_t *,
    217     smb_odir_t *, smb_find_args_t *, boolean_t *);
    218 static int smb_trans2_find_get_maxdata(smb_request_t *, uint16_t, uint16_t);
    219 static int smb_trans2_find_mbc_encode(smb_request_t *, smb_xa_t *,
    220     smb_fileinfo_t *, smb_find_args_t *);
    221 
    222 /*
    223  * Tunable parameter to limit the maximum
    224  * number of entries to be returned.
    225  */
    226 uint16_t smb_trans2_find_max = 128;
    227 
    228 /*
    229  * smb_com_trans2_find_first2
    230  *
    231  *  Client Request                Value
    232  *  ============================  ==================================
    233  *
    234  *  UCHAR  WordCount              15
    235  *  UCHAR  TotalDataCount         Total size of extended attribute list
    236  *  UCHAR  SetupCount             1
    237  *  UCHAR  Setup[0]               TRANS2_FIND_FIRST2
    238  *
    239  *  Parameter Block Encoding      Description
    240  *  ============================  ==================================
    241  *  USHORT SearchAttributes;
    242  *  USHORT SearchCount;           Maximum number of entries to return
    243  *  USHORT Flags;                 Additional information:
    244  *                                Bit 0 - close search after this request
    245  *                                Bit 1 - close search if end of search
    246  *                                reached
    247  *                                Bit 2 - return resume keys for each
    248  *                                entry found
    249  *                                Bit 3 - continue search from previous
    250  *                                ending place
    251  *                                Bit 4 - find with backup intent
    252  *  USHORT InformationLevel;      See below
    253  *  ULONG SearchStorageType;
    254  *  STRING FileName;              Pattern for the search
    255  *  UCHAR Data[ TotalDataCount ]  FEAList if InformationLevel is
    256  *                                QUERY_EAS_FROM_LIST
    257  *
    258  *  Response Parameter Block      Description
    259  *  ============================  ==================================
    260  *
    261  *  USHORT Sid;                   Search handle
    262  *  USHORT SearchCount;           Number of entries returned
    263  *  USHORT EndOfSearch;           Was last entry returned?
    264  *  USHORT EaErrorOffset;         Offset into EA list if EA error
    265  *  USHORT LastNameOffset;        Offset into data to file name of last
    266  *                                entry, if server needs it to resume
    267  *                                search; else 0
    268  *  UCHAR Data[ TotalDataCount ]  Level dependent info about the matches
    269  *                                found in the search
    270  */
    271 smb_sdrc_t
    272 smb_com_trans2_find_first2(smb_request_t *sr, smb_xa_t *xa)
    273 {
    274 	int		count;
    275 	uint16_t	sattr, odid;
    276 	char		*path;
    277 	smb_odir_t	*od;
    278 	smb_find_args_t	args;
    279 	boolean_t	eos;
    280 	uint32_t	odir_flags = 0;
    281 
    282 	bzero(&args, sizeof (smb_find_args_t));
    283 
    284 	if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
    285 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
    286 		    ERRDOS, ERROR_ACCESS_DENIED);
    287 		return (SDRC_ERROR);
    288 	}
    289 
    290 	if (smb_mbc_decodef(&xa->req_param_mb, "%wwww4.u", sr, &sattr,
    291 	    &args.fa_maxcount, &args.fa_fflag, &args.fa_infolev, &path) != 0) {
    292 		return (SDRC_ERROR);
    293 	}
    294 
    295 	if (smb_is_stream_name(path)) {
    296 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
    297 		    ERRDOS, ERROR_INVALID_NAME);
    298 		return (SDRC_ERROR);
    299 	}
    300 
    301 	if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT) {
    302 		sr->user_cr = smb_user_getprivcred(sr->uid_user);
    303 		odir_flags = SMB_ODIR_OPENF_BACKUP_INTENT;
    304 	}
    305 
    306 	args.fa_maxdata =
    307 	    smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag);
    308 	if (args.fa_maxdata == 0)
    309 		return (SDRC_ERROR);
    310 
    311 	if (sr->smb_flg2 & SMB_FLAGS2_UNICODE)
    312 		(void) smb_convert_wildcards(path);
    313 
    314 	odid = smb_odir_open(sr, path, sattr, odir_flags);
    315 	if (odid == 0)
    316 		return (SDRC_ERROR);
    317 
    318 	od = smb_tree_lookup_odir(sr->tid_tree, odid);
    319 	if (od == NULL)
    320 		return (SDRC_ERROR);
    321 	count = smb_trans2_find_entries(sr, xa, od, &args, &eos);
    322 
    323 	if (count == -1) {
    324 		smb_odir_close(od);
    325 		smb_odir_release(od);
    326 		return (SDRC_ERROR);
    327 	}
    328 
    329 	if (count == 0) {
    330 		smb_odir_close(od);
    331 		smb_odir_release(od);
    332 		smbsr_errno(sr, ENOENT);
    333 		return (SDRC_ERROR);
    334 	}
    335 
    336 	if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) ||
    337 	    (eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) {
    338 		smb_odir_close(od);
    339 	} /* else leave odir open for trans2_find_next2 */
    340 
    341 	smb_odir_release(od);
    342 
    343 	(void) smb_mbc_encodef(&xa->rep_param_mb, "wwwww",
    344 	    odid, count, (eos) ? 1 : 0, 0, 0);
    345 
    346 	return (SDRC_SUCCESS);
    347 }
    348 
    349 /*
    350  * smb_com_trans2_find_next2
    351  *
    352  *  Client Request                     Value
    353  *  ================================== =================================
    354  *
    355  *  WordCount                          15
    356  *  SetupCount                         1
    357  *  Setup[0]                           TRANS2_FIND_NEXT2
    358  *
    359  *  Parameter Block Encoding           Description
    360  *  ================================== =================================
    361  *
    362  *  USHORT Sid;                        Search handle
    363  *  USHORT SearchCount;                Maximum number of entries to
    364  *                                      return
    365  *  USHORT InformationLevel;           Levels described in
    366  *                                      TRANS2_FIND_FIRST2 request
    367  *  ULONG ResumeKey;                   Value returned by previous find2
    368  *                                      call
    369  *  USHORT Flags;                      Additional information: bit set-
    370  *                                      0 - close search after this
    371  *                                      request
    372  *                                      1 - close search if end of search
    373  *                                      reached
    374  *                                      2 - return resume keys for each
    375  *                                      entry found
    376  *                                      3 - resume/continue from previous
    377  *                                      ending place
    378  *                                      4 - find with backup intent
    379  *  STRING FileName;                   Resume file name
    380  *
    381  * Sid is the value returned by a previous successful TRANS2_FIND_FIRST2
    382  * call.  If Bit3 of Flags is set, then FileName may be the NULL string,
    383  * since the search is continued from the previous TRANS2_FIND request.
    384  * Otherwise, FileName must not be more than 256 characters long.
    385  *
    386  *  Response Field                     Description
    387  *  ================================== =================================
    388  *
    389  *  USHORT SearchCount;                Number of entries returned
    390  *  USHORT EndOfSearch;                Was last entry returned?
    391  *  USHORT EaErrorOffset;              Offset into EA list if EA error
    392  *  USHORT LastNameOffset;             Offset into data to file name of
    393  *                                      last entry, if server needs it to
    394  *                                      resume search; else 0
    395  *  UCHAR Data[TotalDataCount]         Level dependent info about the
    396  *                                      matches found in the search
    397  *
    398  *
    399  * The last parameter in the request is a filename, which is a
    400  * null-terminated unicode string.
    401  *
    402  * smb_mbc_decodef(&xa->req_param_mb, "%www lwu", sr,
    403  *    &odid, &fa_maxcount, &fa_infolev, &cookie, &fa_fflag, &fname)
    404  *
    405  * The filename parameter is not currently decoded because we
    406  * expect a 2-byte null but Mac OS 10 clients send a 1-byte null,
    407  * which leads to a decode error.
    408  * Thus, we do not support resume by filename.  We treat a request
    409  * to resume by filename as SMB_FIND_CONTINUE_FROM_LAST.
    410  */
    411 smb_sdrc_t
    412 smb_com_trans2_find_next2(smb_request_t *sr, smb_xa_t *xa)
    413 {
    414 	int			count;
    415 	uint16_t		odid;
    416 	uint32_t		cookie;
    417 	smb_odir_t		*od;
    418 	smb_find_args_t		args;
    419 	boolean_t		eos;
    420 	smb_odir_resume_t	odir_resume;
    421 
    422 	bzero(&args, sizeof (smb_find_args_t));
    423 
    424 	if (smb_mbc_decodef(&xa->req_param_mb, "%wwwlw", sr, &odid,
    425 	    &args.fa_maxcount, &args.fa_infolev, &cookie, &args.fa_fflag)
    426 	    != 0) {
    427 		return (SDRC_ERROR);
    428 	}
    429 
    430 	/* continuation by filename not supported */
    431 	if ((args.fa_fflag & SMB_FIND_CONTINUE_FROM_LAST) || (cookie == 0)) {
    432 		odir_resume.or_type = SMB_ODIR_RESUME_IDX;
    433 		odir_resume.or_idx = 0;
    434 	} else {
    435 		odir_resume.or_type = SMB_ODIR_RESUME_COOKIE;
    436 		odir_resume.or_cookie = cookie;
    437 	}
    438 
    439 	if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT)
    440 		sr->user_cr = smb_user_getprivcred(sr->uid_user);
    441 
    442 	args.fa_maxdata =
    443 	    smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag);
    444 	if (args.fa_maxdata == 0)
    445 		return (SDRC_ERROR);
    446 
    447 	od = smb_tree_lookup_odir(sr->tid_tree, odid);
    448 	if (od == NULL) {
    449 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
    450 		    ERRDOS, ERROR_INVALID_HANDLE);
    451 		return (SDRC_ERROR);
    452 	}
    453 	smb_odir_resume_at(od, &odir_resume);
    454 	count = smb_trans2_find_entries(sr, xa, od, &args, &eos);
    455 
    456 	if (count == -1) {
    457 		smb_odir_close(od);
    458 		smb_odir_release(od);
    459 		return (SDRC_ERROR);
    460 	}
    461 
    462 	if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) ||
    463 	    (eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) {
    464 		smb_odir_close(od);
    465 	} /* else leave odir open for trans2_find_next2 */
    466 
    467 	smb_odir_release(od);
    468 	(void) smb_mbc_encodef(&xa->rep_param_mb, "wwww",
    469 	    count, (eos) ? 1 : 0, 0, 0);
    470 
    471 	return (SDRC_SUCCESS);
    472 }
    473 
    474 
    475 /*
    476  * smb_trans2_find_entries
    477  *
    478  * Find and encode up to args->fa_maxcount directory entries.
    479  * For compatibilty with Windows, if args->fa_maxcount is zero treat it as 1.
    480  *
    481  * Returns:
    482  *   count - count of entries encoded
    483  *           *eos = B_TRUE if no more directory entries
    484  *      -1 - error
    485  */
    486 static int
    487 smb_trans2_find_entries(smb_request_t *sr, smb_xa_t *xa, smb_odir_t *od,
    488     smb_find_args_t *args, boolean_t *eos)
    489 {
    490 	int		rc;
    491 	uint16_t	count, maxcount;
    492 	uint32_t	cookie;
    493 	smb_fileinfo_t	fileinfo;
    494 
    495 	if ((maxcount = args->fa_maxcount) == 0)
    496 		maxcount = 1;
    497 
    498 	if ((smb_trans2_find_max != 0) && (maxcount > smb_trans2_find_max))
    499 		maxcount = smb_trans2_find_max;
    500 
    501 	count = 0;
    502 	while (count < maxcount) {
    503 		if (smb_odir_read_fileinfo(sr, od, &fileinfo, eos) != 0)
    504 			return (-1);
    505 		if (*eos == B_TRUE)
    506 			break;
    507 
    508 		rc = smb_trans2_find_mbc_encode(sr, xa, &fileinfo, args);
    509 		if (rc == -1)
    510 			return (-1);
    511 		if (rc == 1)
    512 			break;
    513 
    514 		cookie = fileinfo.fi_cookie;
    515 		++count;
    516 	}
    517 
    518 	/* save the last cookie returned to client */
    519 	if (count != 0)
    520 		smb_odir_save_cookie(od, 0, cookie);
    521 
    522 	/*
    523 	 * If all retrieved entries have been successfully encoded
    524 	 * and eos has not already been detected, check if there are
    525 	 * any more entries. eos will be set if there are no more.
    526 	 */
    527 	if ((rc == 0) && (!*eos))
    528 		(void) smb_odir_read_fileinfo(sr, od, &fileinfo, eos);
    529 
    530 	return (count);
    531 }
    532 
    533 /*
    534  * smb_trans2_find_get_maxdata
    535  *
    536  * Calculate the minimum response space required for the specified
    537  * information level.
    538  *
    539  * A non-zero return value provides the minimum space required.
    540  * A return value of zero indicates an unknown information level.
    541  */
    542 static int
    543 smb_trans2_find_get_maxdata(smb_request_t *sr, uint16_t infolev, uint16_t fflag)
    544 {
    545 	int maxdata;
    546 
    547 	maxdata = smb_ascii_or_unicode_null_len(sr);
    548 
    549 	switch (infolev) {
    550 	case SMB_INFO_STANDARD :
    551 		if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
    552 			maxdata += sizeof (int32_t);
    553 		maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 1;
    554 		break;
    555 
    556 	case SMB_INFO_QUERY_EA_SIZE:
    557 		if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
    558 			maxdata += sizeof (int32_t);
    559 		maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 4 + 1;
    560 		break;
    561 
    562 	case SMB_FIND_FILE_DIRECTORY_INFO:
    563 		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4;
    564 		break;
    565 
    566 	case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
    567 		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4;
    568 		break;
    569 
    570 	case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO:
    571 		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4 + 8;
    572 		break;
    573 
    574 	case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
    575 		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24;
    576 		break;
    577 
    578 	case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO:
    579 		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24
    580 		    + 2 + 8;
    581 		break;
    582 
    583 	case SMB_FIND_FILE_NAMES_INFO:
    584 		maxdata += 4 + 4 + 4;
    585 		break;
    586 
    587 	case SMB_MAC_FIND_BOTH_HFS_INFO:
    588 		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 1 + 1 + 2 +
    589 		    4 + 32 + 4 + 1 + 1 + 24 + 4;
    590 		break;
    591 
    592 	default:
    593 		maxdata = 0;
    594 		smbsr_error(sr, NT_STATUS_INVALID_LEVEL,
    595 		    ERRDOS, ERROR_INVALID_LEVEL);
    596 	}
    597 
    598 	return (maxdata);
    599 }
    600 
    601 /*
    602  * smb_trans2_mbc_encode
    603  *
    604  * This function encodes the mbc for one directory entry.
    605  *
    606  * The function returns -1 when the max data requested by client
    607  * is reached. If the entry is valid and successful encoded, 0
    608  * will be returned; otherwise, 1 will be returned.
    609  *
    610  * We always null terminate the filename. The space for the null
    611  * is included in the maxdata calculation and is therefore included
    612  * in the next_entry_offset. namelen is the unterminated length of
    613  * the filename. For levels except STANDARD and EA_SIZE, if the
    614  * filename is ascii the name length returned to the client should
    615  * include the null terminator. Otherwise the length returned to
    616  * the client should not include the terminator.
    617  *
    618  * Returns: 0 - data successfully encoded
    619  *          1 - client request's maxdata limit reached
    620  *	   -1 - error
    621  */
    622 static int
    623 smb_trans2_find_mbc_encode(smb_request_t *sr, smb_xa_t *xa,
    624     smb_fileinfo_t *fileinfo, smb_find_args_t *args)
    625 {
    626 	int		namelen, shortlen, buflen;
    627 	uint32_t	next_entry_offset;
    628 	uint32_t	dsize32, asize32;
    629 	uint32_t	mb_flags = 0;
    630 	char		buf83[26];
    631 	char		*tmpbuf;
    632 	smb_msgbuf_t	mb;
    633 
    634 	namelen = smb_ascii_or_unicode_strlen(sr, fileinfo->fi_name);
    635 	if (namelen == -1)
    636 		return (-1);
    637 
    638 	next_entry_offset = args->fa_maxdata + namelen;
    639 
    640 	if (MBC_ROOM_FOR(&xa->rep_data_mb, (args->fa_maxdata + namelen)) == 0)
    641 		return (1);
    642 
    643 	/*
    644 	 * If ascii the filename length returned to the client should
    645 	 * include the null terminator for levels except STANDARD and
    646 	 * EASIZE.
    647 	 */
    648 	if (!(sr->smb_flg2 & SMB_FLAGS2_UNICODE)) {
    649 		if ((args->fa_infolev != SMB_INFO_STANDARD) &&
    650 		    (args->fa_infolev != SMB_INFO_QUERY_EA_SIZE))
    651 			namelen += 1;
    652 	}
    653 
    654 	mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE) ? SMB_MSGBUF_UNICODE : 0;
    655 	dsize32 = (fileinfo->fi_size > UINT_MAX) ?
    656 	    UINT_MAX : (uint32_t)fileinfo->fi_size;
    657 	asize32 = (fileinfo->fi_alloc_size > UINT_MAX) ?
    658 	    UINT_MAX : (uint32_t)fileinfo->fi_alloc_size;
    659 
    660 	switch (args->fa_infolev) {
    661 	case SMB_INFO_STANDARD:
    662 		if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS)
    663 			(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
    664 			    fileinfo->fi_cookie);
    665 
    666 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwbu", sr,
    667 		    smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec),
    668 		    smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec),
    669 		    smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec),
    670 		    dsize32,
    671 		    asize32,
    672 		    fileinfo->fi_dosattr,
    673 		    namelen,
    674 		    fileinfo->fi_name);
    675 		break;
    676 
    677 	case SMB_INFO_QUERY_EA_SIZE:
    678 		if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS)
    679 			(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
    680 			    fileinfo->fi_cookie);
    681 
    682 		/*
    683 		 * Unicode filename should NOT be aligned. Encode ('u')
    684 		 * into a temporary buffer, then encode buffer as a
    685 		 * byte stream ('#c').
    686 		 * Regardless of whether unicode or ascii, a single
    687 		 * termination byte is used.
    688 		 */
    689 		buflen = namelen + sizeof (smb_wchar_t);
    690 		tmpbuf = kmem_zalloc(buflen, KM_SLEEP);
    691 		smb_msgbuf_init(&mb, (uint8_t *)tmpbuf, buflen, mb_flags);
    692 		if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_name) < 0) {
    693 			smb_msgbuf_term(&mb);
    694 			kmem_free(tmpbuf, buflen);
    695 			return (-1);
    696 		}
    697 		tmpbuf[namelen] = '\0';
    698 
    699 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwlb#c", sr,
    700 		    smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec),
    701 		    smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec),
    702 		    smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec),
    703 		    dsize32,
    704 		    asize32,
    705 		    fileinfo->fi_dosattr,
    706 		    0L,		/* EA Size */
    707 		    namelen,
    708 		    namelen + 1,
    709 		    tmpbuf);
    710 
    711 		smb_msgbuf_term(&mb);
    712 		kmem_free(tmpbuf, buflen);
    713 		break;
    714 
    715 	case SMB_FIND_FILE_DIRECTORY_INFO:
    716 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqllu", sr,
    717 		    next_entry_offset,
    718 		    fileinfo->fi_cookie,
    719 		    &fileinfo->fi_crtime,
    720 		    &fileinfo->fi_atime,
    721 		    &fileinfo->fi_mtime,
    722 		    &fileinfo->fi_ctime,
    723 		    fileinfo->fi_size,
    724 		    fileinfo->fi_alloc_size,
    725 		    fileinfo->fi_dosattr,
    726 		    namelen,
    727 		    fileinfo->fi_name);
    728 		break;
    729 
    730 	case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
    731 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllu", sr,
    732 		    next_entry_offset,
    733 		    fileinfo->fi_cookie,
    734 		    &fileinfo->fi_crtime,
    735 		    &fileinfo->fi_atime,
    736 		    &fileinfo->fi_mtime,
    737 		    &fileinfo->fi_ctime,
    738 		    fileinfo->fi_size,
    739 		    fileinfo->fi_alloc_size,
    740 		    fileinfo->fi_dosattr,
    741 		    namelen,
    742 		    0L,
    743 		    fileinfo->fi_name);
    744 		break;
    745 
    746 	case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO:
    747 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll4.qu", sr,
    748 		    next_entry_offset,
    749 		    fileinfo->fi_cookie,
    750 		    &fileinfo->fi_crtime,
    751 		    &fileinfo->fi_atime,
    752 		    &fileinfo->fi_mtime,
    753 		    &fileinfo->fi_ctime,
    754 		    fileinfo->fi_size,
    755 		    fileinfo->fi_alloc_size,
    756 		    fileinfo->fi_dosattr,
    757 		    namelen,
    758 		    0L,
    759 		    fileinfo->fi_nodeid,
    760 		    fileinfo->fi_name);
    761 		break;
    762 
    763 	case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
    764 		bzero(buf83, sizeof (buf83));
    765 		smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83),
    766 		    mb_flags);
    767 		if (smb_msgbuf_encode(&mb, "U", fileinfo->fi_shortname) < 0) {
    768 			smb_msgbuf_term(&mb);
    769 			return (-1);
    770 		}
    771 		shortlen = smb_wcequiv_strlen(fileinfo->fi_shortname);
    772 
    773 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllb.24cu",
    774 		    sr,
    775 		    next_entry_offset,
    776 		    fileinfo->fi_cookie,
    777 		    &fileinfo->fi_crtime,
    778 		    &fileinfo->fi_atime,
    779 		    &fileinfo->fi_mtime,
    780 		    &fileinfo->fi_ctime,
    781 		    fileinfo->fi_size,
    782 		    fileinfo->fi_alloc_size,
    783 		    fileinfo->fi_dosattr,
    784 		    namelen,
    785 		    0L,
    786 		    shortlen,
    787 		    buf83,
    788 		    fileinfo->fi_name);
    789 
    790 		smb_msgbuf_term(&mb);
    791 		break;
    792 
    793 	case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO:
    794 		bzero(buf83, sizeof (buf83));
    795 		smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83),
    796 		    mb_flags);
    797 		if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_shortname) < 0) {
    798 			smb_msgbuf_term(&mb);
    799 			return (-1);
    800 		}
    801 		shortlen = smb_ascii_or_unicode_strlen(sr,
    802 		    fileinfo->fi_shortname);
    803 
    804 		(void) smb_mbc_encodef(&xa->rep_data_mb,
    805 		    "%llTTTTqqlllb.24c2.qu",
    806 		    sr,
    807 		    next_entry_offset,
    808 		    fileinfo->fi_cookie,
    809 		    &fileinfo->fi_crtime,
    810 		    &fileinfo->fi_atime,
    811 		    &fileinfo->fi_mtime,
    812 		    &fileinfo->fi_ctime,
    813 		    fileinfo->fi_size,
    814 		    fileinfo->fi_alloc_size,
    815 		    fileinfo->fi_dosattr,
    816 		    namelen,
    817 		    0L,
    818 		    shortlen,
    819 		    buf83,
    820 		    fileinfo->fi_nodeid,
    821 		    fileinfo->fi_name);
    822 
    823 		smb_msgbuf_term(&mb);
    824 		break;
    825 
    826 	case SMB_FIND_FILE_NAMES_INFO:
    827 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lllu", sr,
    828 		    next_entry_offset,
    829 		    fileinfo->fi_cookie,
    830 		    namelen,
    831 		    fileinfo->fi_name);
    832 		break;
    833 	}
    834 
    835 	return (0);
    836 }
    837 
    838 /*
    839  * Close a search started by a Trans2FindFirst2 request.
    840  */
    841 smb_sdrc_t
    842 smb_pre_find_close2(smb_request_t *sr)
    843 {
    844 	DTRACE_SMB_1(op__FindClose2__start, smb_request_t *, sr);
    845 	return (SDRC_SUCCESS);
    846 }
    847 
    848 void
    849 smb_post_find_close2(smb_request_t *sr)
    850 {
    851 	DTRACE_SMB_1(op__FindClose2__done, smb_request_t *, sr);
    852 }
    853 
    854 smb_sdrc_t
    855 smb_com_find_close2(smb_request_t *sr)
    856 {
    857 	uint16_t	odid;
    858 	smb_odir_t	*od;
    859 
    860 	if (smbsr_decode_vwv(sr, "w", &odid) != 0)
    861 		return (SDRC_ERROR);
    862 
    863 	od = smb_tree_lookup_odir(sr->tid_tree, odid);
    864 	if (od == NULL) {
    865 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
    866 		    ERRDOS, ERROR_INVALID_HANDLE);
    867 		return (SDRC_ERROR);
    868 	}
    869 
    870 	smb_odir_close(od);
    871 	smb_odir_release(od);
    872 
    873 	if (smbsr_encode_empty_result(sr))
    874 		return (SDRC_ERROR);
    875 
    876 	return (SDRC_SUCCESS);
    877 }
    878