a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * CDDL HEADER START
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * The contents of this file are subject to the terms of the
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Common Development and Distribution License (the "License").
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * You may not use this file except in compliance with the License.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * See the License for the specific language governing permissions
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * and limitations under the License.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * When distributing Covered Code, include this CDDL HEADER in each
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * If applicable, add the following below this CDDL HEADER, with the
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * fields enclosed by brackets "[]" replaced with your own identifying
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * information: Portions Copyright [yyyy] [name of copyright owner]
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * CDDL HEADER END
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Use is subject to license terms.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Dispatch function for SMB2_QUERY_DIRECTORY
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Similar to smb_trans2_find.c (from SMB1)
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Args (and other state) that we carry around among the
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * various functions involved in SMB2 Query Directory.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross uint16_t fa_fixedsize; /* size of fixed part of a returned entry */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Rossstatic uint32_t smb2_find_entries(smb_request_t *,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Rossstatic uint32_t smb2_find_mbc_encode(smb_request_t *,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Tunable parameter to limit the maximum
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * number of entries to be returned.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * SMB2 Query Directory request
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * If there's an input buffer (search pattern), decode it.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Two times MAXNAMELEN because it represents the UNICODE string
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * length in bytes.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * We're normally positioned at the pattern now,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * but there could be some padding before it.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross (void) smb_mbc_decodef(&sr->smb_data, "#.", skip);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Setup the output buffer.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Get the mininum size of entries we will return, which
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * lets us estimate the number of entries we'll need.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * This should be the size with a one character name.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Compare w/ smb2_find_get_maxdata().
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Also use this opportunity to validate fa_infoclass.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross args.fa_maxcount = args.fa_maxdata / (args.fa_fixedsize + 4);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross if ((smb2_find_max != 0) && (args.fa_maxcount > smb2_find_max))
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * If this ofile does not have an odir yet, get one.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross status = smb_odir_openfh(sr, pattern, sattr, &od);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * "Reopen" sets a new pattern and restart.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Set the correct position in the directory.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross } else if (args.fa_fflags & SMB2_QDIR_FLAG_INDEX) {
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * The real work of readdir and format conversion.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * This is not an error, but a warning that can be
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * used to tell the client that this data return
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * is the last of the enumeration. Returning this
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * warning now (with the data) saves the client a
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * round trip that would otherwise be needed to
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * find out it's at the end.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * SMB2 Query Directory reply
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * smb2_find_entries
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Find and encode up to args->fa_maxcount directory entries.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Rosssmb2_find_entries(smb_request_t *sr, smb_odir_t *od, smb2_find_args_t *args)
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Let's stop when the remaining space will not hold a
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * minimum size entry. That's the fixed part plus the
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * storage size of a 1 char unicode string.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &args->fa_eos);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /* The readdir call hit the end. */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross status = smb2_find_mbc_encode(sr, &fileinfo, args);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * We read a directory entry but failed to
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * copy it into the output buffer. Rewind
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * the directory pointer so this will be
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * the first entry read next time.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Save the offset of the next entry we'll read.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * If we fail copying, we'll need this offset.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * We copied some directory entries, but stopped for
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * NT_STATUS_NO_MORE_FILES, or something.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Per [MS-FSCC] sec. 2.4, the last entry in the
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * enumeration MUST have its NextEntryOffset value
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * set to zero. Overwrite that in the last entry.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * smb2_mbc_encode
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * This function encodes the mbc for one directory entry.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * The function returns -1 when the max data requested by client
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * is reached. If the entry is valid and successful encoded, 0
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * will be returned; otherwise, 1 will be returned.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * We always null terminate the filename. The space for the null
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * is included in the maxdata calculation and is therefore included
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * in the next_entry_offset. namelen is the unterminated length of
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * the filename. For levels except STANDARD and EA_SIZE, if the
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * filename is ascii the name length returned to the client should
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * include the null terminator. Otherwise the length returned to
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * the client should not include the terminator.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Returns: 0 - data successfully encoded
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Rosssmb2_find_mbc_encode(smb_request_t *sr, smb_fileinfo_t *fileinfo,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross namelen = smb_wcequiv_strlen(fileinfo->fi_name);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Keep track of where the last entry starts so we can
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * come back and poke the NextEntryOffset field. Also,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * after enumeration finishes, the caller uses this to
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * poke the last entry again with zero to mark it as
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * the end of the enumeration.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Technically (per MS-SMB2) resume keys are optional.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Windows doesn't need them, but MacOS does.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * This switch handles all the "information levels" (formats)
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * that we support. Note that all formats have the file name
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * placed after some fixed-size data, and the code to write
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * the file name is factored out at the end of this switch.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /* See also: SMB_FIND_FILE_DIRECTORY_INFO */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross 0, /* NextEntryOffset (set later) */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /* See also: SMB_FIND_FILE_FULL_DIRECTORY_INFO */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross 0, /* NextEntryOffset (set later) */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross 0L); /* EaSize */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /* See also: SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross 0, /* NextEntryOffset (set later) */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross 0L, /* EaSize */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross 0L, /* reserved */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /* See also: SMB_FIND_FILE_BOTH_DIRECTORY_INFO */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross smb_msgbuf_init(&mb, buf83, sizeof (buf83), mb_flags);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross if (!smb_msgbuf_encode(&mb, "U", fileinfo->fi_shortname))
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross shortlen = smb_wcequiv_strlen(fileinfo->fi_shortname);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross 0, /* NextEntryOffset (set later) */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross 0L, /* EaSize */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /* See also: SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross smb_msgbuf_init(&mb, buf83, sizeof (buf83), mb_flags);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross if (!smb_msgbuf_encode(&mb, "U", fileinfo->fi_shortname))
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross shortlen = smb_wcequiv_strlen(fileinfo->fi_shortname);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross 0, /* NextEntryOffset (set later) */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross 0L, /* EaSize l */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /* reserved .. */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /* See also: SMB_FIND_FILE_NAMES_INFO */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross 0, /* NextEntryOffset (set later) */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * At this point we have written all the fixed-size data
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * for the specified info. class. Now put the name and
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * alignment padding, and then patch the NextEntryOffset.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Also store this offset for the caller so they can
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * patch this (again) to zero on the very last entry.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /* Next entry needs to be 8-byte aligned. */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross (void) smb_mbc_encodef(&sr->raw_data, "#.", padsz);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross next_entry_offset = sr->raw_data.chain_offset - starting_offset;