/*
* 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 2013 Nexenta Systems, Inc. All rights reserved.
*/
#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_vops.h>
#include <smbsrv/smb_fsops.h>
/*
*
* SMB_INFO_STANDARD
* SMB_INFO_QUERY_EA_SIZE
* SMB_INFO_QUERY_EAS_FROM_LIST
* SMB_INFO_QUERY_ALL_EAS - not valid for pipes
* SMB_INFO_IS_NAME_VALID - only valid when query is by path
*
* SMB_QUERY_FILE_BASIC_INFO
* SMB_QUERY_FILE_STANDARD_INFO
* SMB_QUERY_FILE_EA_INFO
* SMB_QUERY_FILE_NAME_INFO
* SMB_QUERY_FILE_ALL_INFO
* SMB_QUERY_FILE_ALT_NAME_INFO - not valid for pipes
* SMB_QUERY_FILE_STREAM_INFO - not valid for pipes
* SMB_QUERY_FILE_COMPRESSION_INFO - not valid for pipes
*
* Supported Passthrough levels:
* SMB_FILE_BASIC_INFORMATION
* SMB_FILE_STANDARD_INFORMATION
* SMB_FILE_INTERNAL_INFORMATION
* SMB_FILE_EA_INFORMATION
* SMB_FILE_ACCESS_INFORMATION - not yet supported when query by path
* SMB_FILE_NAME_INFORMATION
* SMB_FILE_ALL_INFORMATION
* SMB_FILE_ALT_NAME_INFORMATION - not valid for pipes
* SMB_FILE_STREAM_INFORMATION - not valid for pipes
* SMB_FILE_COMPRESSION_INFORMATION - not valid for pipes
* SMB_FILE_NETWORK_OPEN_INFORMATION - not valid for pipes
* SMB_FILE_ATTR_TAG_INFORMATION - not valid for pipes
*
* Internal levels representing non trans2 requests
* SMB_QUERY_INFORMATION
* SMB_QUERY_INFORMATION2
*/
/*
* SMB_STREAM_ENCODE_FIXED_SIZE:
* 2 dwords + 2 quadwords => 4 + 4 + 8 + 8 => 24
*/
/* See smb_queryinfo_t in smb_ktypes.h */
uint16_t, smb_queryinfo_t *);
uint16_t, smb_queryinfo_t *);
uint16_t, smb_queryinfo_t *);
char *, uint32_t);
smb_queryinfo_t *);
int smb_query_passthru;
/*
* smb_com_trans2_query_file_information
*/
{
return (SDRC_ERROR);
return (SDRC_ERROR);
return (SDRC_SUCCESS);
}
/*
* smb_com_trans2_query_path_information
*/
{
return (SDRC_ERROR);
}
return (SDRC_ERROR);
return (SDRC_ERROR);
return (SDRC_SUCCESS);
}
/*
* smb_com_query_information (aka getattr)
*/
{
int rc;
}
void
{
}
{
return (SDRC_ERROR);
}
return (SDRC_ERROR);
return (SDRC_SUCCESS);
}
/*
* smb_com_query_information2 (aka getattre)
*/
{
int rc;
}
void
{
}
{
return (SDRC_ERROR);
return (SDRC_SUCCESS);
}
/*
* smb_query_by_fid
*
* Common code for querying file information by open file (or pipe) id.
* Use the id to identify the node / pipe object and request the
* smb_queryinfo_t data for that object.
*/
static int
{
int rc;
return (-1);
}
if (infolev == SMB_INFO_IS_NAME_VALID) {
return (-1);
}
return (-1);
}
case SMB_FTYPE_DISK:
break;
case SMB_FTYPE_MESG_PIPE:
break;
default:
rc = -1;
break;
}
if (rc == 0)
return (rc);
}
/*
* smb_query_by_path
*
* Common code for querying file information by file name.
* Use the file name to identify the node object and request the
* smb_queryinfo_t data for that node.
*
* Path should be set in sr->arg.dirop.fqi.fq_path prior to
* calling smb_query_by_path.
*
* Querying attributes on a named pipe by name is an error and
* is handled in the calling functions so that they can return
* the appropriate error status code (which differs by caller).
*/
static int
{
int rc;
/*
* The function smb_query_fileinfo is used here and in
* smb_query_by_fid. That common function needs this
* one to call it with a NULL fid_ofile, so check here.
* Note: smb_query_by_fid enforces the opposite.
*
* In theory we could ASSERT this, but whether we have
* fid_ofile set here depends on what sequence of SMB
* commands the client has sent in this message, so
* let's be cautious and handle it as an error.
*/
return (-1);
/* VALID, but not yet supported */
if (infolev == SMB_FILE_ACCESS_INFORMATION) {
return (-1);
}
return (-1);
if (rc == 0) {
}
if (rc != 0) {
else
return (-1);
}
return (-1);
}
if (rc != 0) {
return (rc);
}
/* If delete_on_close - NT_STATUS_DELETE_PENDING */
if (qinfo->qi_delete_on_close) {
return (-1);
}
return (rc);
}
/*
* smb_size32
* Some responses only support 32 bit file sizes. If the file size
* exceeds UINT_MAX (32 bit) we return UINT_MAX in the response.
*/
static uint32_t
{
}
/*
* smb_query_encode_response
*
* Encode the data from smb_queryinfo_t into client response
*/
int
{
switch (infolev) {
case SMB_QUERY_INFORMATION:
10,
0);
break;
case SMB_QUERY_INFORMATION2:
11,
break;
break;
case SMB_INFO_STANDARD:
"YYYllw" : "yyyllw"),
break;
case SMB_INFO_QUERY_EA_SIZE:
"YYYllwl" : "yyyllwl"),
break;
case SMB_INFO_QUERY_ALL_EAS:
break;
case SMB_INFO_IS_NAME_VALID:
break;
/*
* NT includes 6 bytes (spec says 4) at the end of this
* response, which are required by NetBench 5.01.
*/
dattr);
break;
/* 2-byte pad at end */
break;
case SMB_QUERY_FILE_EA_INFO:
case SMB_FILE_EA_INFORMATION:
break;
case SMB_QUERY_FILE_NAME_INFO:
break;
case SMB_QUERY_FILE_ALL_INFO:
case SMB_FILE_ALL_INFORMATION:
/*
* There is a 6-byte pad between Attributes and AllocationSize,
* and a 2-byte pad after the Directory field.
*/
0);
break;
break;
if (status)
break;
datasz, 0, 0, 0, 0);
break;
break;
break;
/*
* If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the
* second dword should be the reparse tag. Otherwise
* the tag value should be set to zero.
* We don't support reparse points, so we set the tag
* to zero.
*/
break;
default:
else
return (-1);
}
return (0);
}
/*
* smb_encode_stream_info
*
* This function encodes the streams information.
* The following rules about how have been derived from observed NT
* behaviour.
*
* If the target is a file:
* 1. If there are no named streams, the response should still contain
* an entry for the unnamed stream.
* 2. If there are named streams, the response should contain an entry
* for the unnamed stream followed by the entries for the named
* streams.
*
* If the target is a directory:
* 1. If there are no streams, the response is complete. Directories
* do not report the unnamed stream.
* 2. If there are streams, the response should contain entries for
* those streams but there should not be an entry for the unnamed
* stream.
*
* Note that the stream name lengths exclude the null terminator but
* the field lengths (i.e. next offset calculations) need to include
* the null terminator and be padded to a multiple of 8 bytes. The
* last entry does not seem to need any padding.
*
* If an error is encountered when trying to read the stream entries
* (smb_odir_read_streaminfo) it is treated as if there are no [more]
* entries. The entries that have been read so far are returned and
* no error is reported.
*
* If the response buffer is not large enough to return all of the
* named stream entries, the entries that do fit are returned and
* a warning code is set (NT_STATUS_BUFFER_OVERFLOW). The next_offset
* value in the last returned entry must be 0.
*/
{
char *stream_name;
int rc = 0;
if (SMB_IS_STREAM(fnode)) {
}
switch (status) {
case 0:
break;
case NT_STATUS_NO_SUCH_FILE:
case NT_STATUS_NOT_SUPPORTED:
/* No streams. */
break;
default:
return (status);
}
if (!done) {
}
/* If not a directory, encode an entry for the unnamed stream. */
stream_name = "::$DATA";
/* Can unnamed stream fit in response buffer? */
} else {
/* Can first named stream fit in rsp buffer? */
next_offset)) {
}
if (done)
next_offset = 0;
}
}
/*
* If there is no next entry, or there is not enough space in
* the response buffer for the next entry, the next_offset and
* padding are 0.
*/
while (!done) {
sinfo_next->si_name[0] = 0;
} else {
next_offset += pad;
/* Can next named stream fit in response buffer? */
next_offset)) {
}
}
if (done) {
next_offset = 0;
pad = 0;
}
}
if (od) {
}
return (status);
}
/*
* smb_stream_fits
*
* Check if the named stream entry can fit in the response buffer.
*
* Required space =
* offset (size of current entry)
* + SMB_STREAM_ENCODE_FIXED_SIZE
* + length of encoded stream name
* + length of null terminator
* + alignment padding
*/
static boolean_t
{
}
/*
* smb_query_fileinfo
*
* Populate smb_queryinfo_t structure for SMB_FTYPE_DISK
* (This should become an smb_ofile / smb_node function.)
*/
int
{
int rc = 0;
/* If shortname required but not supported -> OBJECT_NAME_NOT_FOUND */
if ((infolev == SMB_QUERY_FILE_ALT_NAME_INFO) ||
(infolev == SMB_FILE_ALT_NAME_INFORMATION)) {
return (-1);
}
}
/* See: smb_query_encode_response */
if (rc != 0) {
return (-1);
}
/*
* The number of links reported should be the number of
* non-deleted links. Thus if delete_on_close is set,
* decrement the link count.
*/
if (qinfo->qi_delete_on_close &&
}
/*
* populate name, namelen and shortname ONLY for the information
* levels that require these fields
*/
switch (infolev) {
case SMB_QUERY_FILE_ALL_INFO:
case SMB_FILE_ALL_INFORMATION:
break;
case SMB_QUERY_FILE_NAME_INFO:
break;
break;
default:
break;
}
if (rc != 0) {
return (-1);
}
return (0);
}
/*
* smb_query_pathname
*
* Determine the absolute pathname of 'node' within the share.
* For some levels (e.g. ALL_INFO) the pathname should include the
* sharename for others (e.g. NAME_INFO) the pathname should be
* relative to the share.
* For example if the node represents file "test1.txt" in directory
* "dir1" on share "share1"
* - if include_share is TRUE the pathname would be: \share1\dir1\test1.txt
* - if include_share is FALSE the pathname would be: \dir1\test1.txt
*
* For some reason NT will not show the security tab in the root
* directory of a mapped drive unless the filename length is greater
* than one. So if the length is 1 we set it to 2 to persuade NT to
* show the tab. It should be safe because of the null terminator.
*/
static int
{
int rc;
if (include_share) {
return (ENAMETOOLONG);
}
if (!include_share)
return (0);
}
if (rc == 0) {
qinfo->qi_namelen =
}
return (rc);
}
/*
* smb_query_shortname
*
* If the node is a named stream, use its associated
* unnamed stream name to determine the shortname.
* If a shortname is required (smb_needs_mangle()), generate it
* using smb_mangle(), otherwise, convert the original name to
* upper-case and return it as the alternative name.
*/
void
{
char *namep;
if (SMB_IS_STREAM(node))
else
if (smb_needs_mangled(namep)) {
} else {
}
}
/*
* smb_query_pipeinfo
*
* Populate smb_queryinfo_t structure for SMB_FTYPE_MESG_PIPE
* (This should become an smb_opipe function.)
*/
static int
{
if ((infolev == SMB_INFO_STANDARD) ||
(infolev == SMB_INFO_QUERY_EA_SIZE) ||
(infolev == SMB_QUERY_INFORMATION2)) {
} else {
}
/* If the leading \ is missing from the pipe name, add it. */
if (*namep != '\\')
else
return (0);
}
/*
* smb_query_pipe_valid_infolev
*
* If the infolev is not valid for a message pipe, the error
* information is set in sr and B_FALSE is returned.
* Otherwise, returns B_TRUE.
*/
static boolean_t
{
switch (infolev) {
case SMB_INFO_QUERY_ALL_EAS:
return (B_FALSE);
return (B_FALSE);
}
return (B_TRUE);
}