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