smb_trans2_query_path_info.c revision 1fcced4c370617db71610fecffd5451a5894ca5e
/*
* 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
* or http://www.opensolaris.org/os/licensing.
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* SMB: trans2_query_path_information
*
* This request is used to get information about a specific file or
* subdirectory.
*
* Client Request Value
* ========================== =========================================
*
* WordCount 15
* MaxSetupCount 0
* SetupCount 1
* Setup[0] TRANS2_QUERY_PATH_INFORMATION
*
* Parameter Block Encoding Description
* ========================== =========================================
*
* USHORT InformationLevel; Level of information requested
* ULONG Reserved; Must be zero
* STRING FileName; File or directory name
*
* The following InformationLevels may be requested:
*
* Information Level Value
*
* ================================ =====
*
* SMB_INFO_STANDARD 1
* SMB_INFO_QUERY_EA_SIZE 2
* SMB_INFO_QUERY_EAS_FROM_LIST 3
* SMB_INFO_QUERY_ALL_EAS 4
* SMB_INFO_IS_NAME_VALID 6
* SMB_QUERY_FILE_BASIC_INFO 0x101
* SMB_QUERY_FILE_STANDARD_INFO 0x102
* SMB_QUERY_FILE_EA_INFO 0x103
* SMB_QUERY_FILE_NAME_INFO 0x104
* SMB_QUERY_FILE_ALL_INFO 0x107
* SMB_QUERY_FILE_ALT_NAME_INFO 0x108
* SMB_QUERY_FILE_STREAM_INFO 0x109
* SMB_QUERY_FILE_COMPRESSION_INFO 0x10B
* SMB_FILE_INTERNAL_INFORMATION 1006
*
* The requested information is placed in the Data portion of the
* transaction response. For the information levels greater than 0x100,
* the transaction response has 1 parameter word which should be ignored by
* the client.
*
* The following sections describe the InformationLevel dependent encoding
* of the data part of the transaction response.
*
* 4.2.14.1 SMB_INFO_STANDARD & SMB_INFO_QUERY_EA_SIZE
*
* Data Block Encoding Description
* =============================== ====================================
*
* SMB_DATE CreationDate; Date when file was created
* SMB_TIME CreationTime; Time when file was created
* SMB_DATE LastAccessDate; Date of last file access
* SMB_TIME LastAccessTime; Time of last file access
* SMB_DATE LastWriteDate; Date of last write to the file
* SMB_TIME LastWriteTime; Time of last write to the file
* ULONG DataSize; File Size
* ULONG AllocationSize; Size of filesystem allocation unit
* USHORT Attributes; File Attributes
* ULONG EaSize; Size of file's EA information
* (SMB_INFO_QUERY_EA_SIZE)
*
* 4.2.14.2 SMB_INFO_QUERY_EAS_FROM_LIST & SMB_INFO_QUERY_ALL_EAS
*
* Response Field Value
* ==================== ===============================================
*
* MaxDataCount Length of EAlist found (minimum value is 4)
*
* Parameter Block Description
* Encoding ===============================================
* ====================
*
* USHORT EaErrorOffset Offset into EAList of EA error
*
* Data Block Encoding Description
* ==================== ===============================================
*
* ULONG ListLength; Length of the remaining data
* UCHAR EaList[] The extended attributes list
*
* 4.2.14.3 SMB_INFO_IS_NAME_VALID
*
* This requests checks to see if the name of the file contained in the
* request's Data field has a valid path syntax. No parameters or data are
* returned on this information request. An error is returned if the syntax
* of the name is incorrect. Success indicates the server accepts the path
* syntax, but it does not ensure the file or directory actually exists.
*
* 4.2.14.4 SMB_QUERY_FILE_BASIC_INFO
*
* Data Block Encoding Description
* =============================== ====================================
*
* LARGE_INTEGER CreationTime; Time when file was created
* LARGE_INTEGER LastAccessTime; Time of last file access
* LARGE_INTEGER LastWriteTime; Time of last write to the file
* LARGE_INTEGER ChangeTime Time when file was last changed
* USHORT Attributes; File Attributes
*
* 4.2.14.5 SMB_QUERY_FILE_STANDARD_INFO
*
* Data Block Encoding Description
* =============================== ====================================
*
* LARGE_INTEGER AllocationSize Allocated size of the file in number
* of bytes
* LARGE_INTEGER EndofFile; Offset to the first free byte in the
* file
* ULONG NumberOfLinks Number of hard links to the file
* BOOLEAN DeletePending Indicates whether the file is marked
* for deletion
* BOOLEAN Directory Indicates whether the file is a
* directory
*
* 4.2.14.6 SMB_QUERY_FILE_EA_INFO
*
* Data Block Encoding Description
* =============================== ====================================
*
* ULONG EASize Size of the file's extended
* attributes in number of bytes
*
* 4.2.14.7 SMB_QUERY_FILE_NAME_INFO
*
* Data Block Encoding Description
* =============================== ====================================
*
* ULONG FileNameLength Length of the file name in number of
* bytes
* STRING FileName Name of the file
*
* 4.2.14.8 SMB_QUERY_FILE_ALL_INFO
*
* Data Block Encoding Description
* =============================== ====================================
*
* LARGE_INTEGER CreationTime; Time when file was created
* LARGE_INTEGER LastAccessTime; Time of last file access
* LARGE_INTEGER LastWriteTime; Time of last write to the file
* LARGE_INTEGER ChangeTime Time when file was last changed
* USHORT Attributes; File Attributes
* LARGE_INTEGER AllocationSize Allocated size of the file in number
* of bytes
* LARGE_INTEGER EndofFile; Offset to the first free byte in the
* file
* ULONG NumberOfLinks Number of hard links to the file
* BOOLEAN DeletePending Indicates whether the file is marked
* for deletion
* BOOLEAN Directory Indicates whether the file is a
* directory
* LARGE_INTEGER Index Number A file system unique identifier
* ULONG EASize Size of the file's extended
* attributes in number of bytes
* ULONG AccessFlags Access that a caller has to the
* file; Possible values and meanings
* are specified below
* LARGE_INTEGER Index Number A file system unique identifier
* LARGE_INTEGER CurrentByteOffset Current byte offset within the file
* ULONG Mode Current Open mode of the file handle
* to the file; possible values and
* meanings are detailed below
* ULONG AlignmentRequirement Buffer Alignment required by device;
* possible values detailed below
* ULONG FileNameLength Length of the file name in number of
* bytes
* STRING FileName Name of the file
*
* The AccessFlags specifies the access permissions a caller has to the
* file and can have any suitable combination of the following values:
*
* Value Meaning
*
* ILE_READ_DATA 0x00000001 Data can be read from the file
* ILE_WRITE_DATA 0x00000002 Data can be written to the file
* ILE_APPEND_DATA 0x00000004 Data can be appended to the file
* ILE_READ_EA 0x00000008 Extended attributes associated
* with the file can be read
* ILE_WRITE_EA 0x00000010 Extended attributes associated
* with the file can be written
* ILE_EXECUTE 0x00000020 Data can be read into memory from
* the file using system paging I/O
* ILE_READ_ATTRIBUTES 0x00000080 Attributes associated with the
* file can be read
* ILE_WRITE_ATTRIBUTES 0x00000100 Attributes associated with the
* file can be written
* ELETE 0x00010000 The file can be deleted
* EAD_CONTROL 0x00020000 The access control list and
* ownership associated with the
* file can be read
* RITE_DAC 0x00040000 The access control list and
* ownership associated with the
* file can be written.
* RITE_OWNER 0x00080000 Ownership information associated
* with the file can be written
* YNCHRONIZE 0x00100000 The file handle can waited on to
* synchronize with the completion
* of an input/output request
*
* The Mode field specifies the mode in which the file is currently opened.
* The possible values may be a suitable and logical combination of the
* following:
*
* Value Meaning
*
* FILE_WRITE_THROUGH 0x00000002 File is opened in mode
* where data is written to
* file before the driver
* completes a write request
* FILE_SEQUENTIAL_ONLY 0x00000004 All access to the file is
* sequential
* FILE_SYNCHRONOUS_IO_ALERT 0x00000010 All operations on the
* file are performed
* synchronously
* FILE_SYNCHRONOUS_IO_NONALER 0x00000020 All operations on the
* T file are to be performed
* synchronously. Waits in
* the system to synchronize
* I/O queuing and
* completion are not
* subject to alerts.
*
* The AlignmentRequirement field specifies buffer alignment required by
* the device and can have any one of the following values:
*
* Value Meaning
*
* FILE_BYTE_ALIGNMENT 0x00000000 The buffer needs to be aligned
* on a byte boundary
* FILE_WORD_ALIGNMENT 0x00000001 The buffer needs to be aligned
* on a word boundary
* FILE_LONG_ALIGNMENT 0x00000003 The buffer needs to be aligned
* on a 4 byte boundary
* FILE_QUAD_ALIGNMENT 0x00000007 The buffer needs to be aligned
* on an 8 byte boundary
* FILE_OCTA_ALIGNMENT 0x0000000f The buffer needs to be aligned
* on a 16 byte boundary
* FILE_32_BYTE_ALIGNMENT 0x0000001f The buffer needs to be aligned
* on a 32 byte boundary
* FILE_64_BYTE_ALIGNMENT 0x0000003f The buffer needs to be aligned
* on a 64 byte boundary
* FILE_128_BYTE_ALIGNMENT 0x0000007f The buffer needs to be aligned
* on a 128 byte boundary
* FILE_256_BYTE_ALIGNMENT 0x000000ff The buffer needs to be aligned
* on a 256 byte boundary
* FILE_512_BYTE_ALIGNMENT 0x000001ff The buffer needs to be aligned
* on a 512 byte boundary
*
* 4.2.14.9 SMB_QUERY_FILE_ALT_NAME_INFO
*
* Data Block Encoding Description
* ===================== =================================
* ULONG FileNameLength Length of the file name in number of bytes
* STRING FileName Name of the file
*
* 4.2.14.10 SMB_QUERY_FILE_STREAM_INFO
*
* Data Block Encoding Description
* =============================== ====================================
* ULONG NextEntryOffset Offset to the next entry (in bytes)
* ULONG StreamNameLength Length of the stream name in # of bytes
* LARGE_INTEGER StreamSize Size of the stream in number of bytes
* LARGE_INTEGER AllocationSize Allocated size of stream in bytes
* STRING FileName Name of the stream
*
* 4.2.14.11 SMB_QUERY_FILE_COMPRESSION_INFO
*
* Data Block Encoding Description
* =============================== ====================================
* LARGE_INTEGER Size of the compressed file in
* CompressedFileSize number of bytes
* USHORT CompressionFormat compression algorithm used
* UCHAR CompressionUnitShift Size of the stream in number of bytes
* UCHAR ChunkShift Allocated size of the stream in # of bytes
* UCHAR ClusterShift Allocated size of the stream in # of bytes
* UCHAR Reserved[3] Name of the stream
*
* typedef struct {
* LARGE_INTEGER CompressedFileSize;
* USHORT CompressionFormat;
* UCHAR CompressionUnitShift;
* UCHAR ChunkShift;
* UCHAR ClusterShift;
* UCHAR Reserved[3];
* } FILE_COMPRESSION_INFORMATION;
*/
#include <smbsrv/smb_incl.h>
#include <smbsrv/msgbuf.h>
#include <smbsrv/smb_vops.h>
#include <smbsrv/smb_fsops.h>
int smb_query_all_info_filename(smb_tree_t *, smb_node_t *, char *, size_t);
extern void smb_encode_smb_datetimes(smb_request_t *, smb_xa_t *, smb_attr_t *);
extern void smb_encode_nt_times(smb_request_t *, smb_xa_t *, smb_attr_t *);
/*
* Function: int smb_com_trans2_query_path_information(struct smb_request *)
*/
smb_sdrc_t
smb_com_trans2_query_path_information(struct smb_request *sr, struct smb_xa *xa)
{
char *path, *alt_nm_ptr;
int rc;
u_offset_t datasz, allocsz;
unsigned short infolev, dattr;
smb_attr_t *ap, ret_attr;
struct smb_node *dir_node;
struct smb_node *node;
char *name, *namep;
char short_name[SMB_SHORTNAMELEN];
char name83[SMB_SHORTNAMELEN];
unsigned char is_dir;
unsigned char delete_on_close;
int len;
if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST, ERRDOS,
ERROR_INVALID_FUNCTION);
return (SDRC_ERROR);
}
if (smb_mbc_decodef(&xa->req_param_mb, "%w4.u", sr,
&infolev, &path) != 0) {
return (SDRC_ERROR);
}
/*
* Some MS clients pass NULL file names
* NT interprets this as "\"
*/
if ((len = strlen(path)) == 0)
path = "\\";
else {
if ((len > 1) && (path[len - 1] == '\\')) {
/*
* Remove the terminating slash to prevent
* sending back '.' instead of path name.
*/
path[len - 1] = 0;
}
}
ap = &ret_attr;
name = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
if ((rc = smb_pathname_reduce(sr, sr->user_cr, path,
sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dir_node, name))
!= 0) {
kmem_free(name, MAXPATHLEN);
if (rc == ENOENT)
smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
ERRDOS, ERROR_FILE_NOT_FOUND);
else
smbsr_errno(sr, rc);
return (SDRC_ERROR);
}
if ((rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
sr->tid_tree->t_snode, dir_node, name, &node)) != 0) {
smb_node_release(dir_node);
kmem_free(name, MAXPATHLEN);
if (rc == ENOENT)
smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
ERRDOS, ERROR_FILE_NOT_FOUND);
else
smbsr_errno(sr, rc);
return (SDRC_ERROR);
}
smb_node_release(dir_node);
if (smb_node_getattr(sr, node, ap) != 0) {
smb_node_release(node);
kmem_free(name, MAXPATHLEN);
smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
ERRDOS, ERROR_INTERNAL_ERROR);
return (SDRC_ERROR);
}
(void) strcpy(name, node->od_name);
namep = node->od_name;
dattr = ap->sa_dosattr;
if (smb_node_is_dir(node)) {
is_dir = 1;
/* Win2K and NT reply with the size of directory file */
datasz = allocsz = 0;
} else {
is_dir = 0;
datasz = ap->sa_vattr.va_size;
allocsz = ap->sa_vattr.va_nblocks * DEV_BSIZE;
}
delete_on_close =
(node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0;
/*
* 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 (delete_on_close && ap->sa_vattr.va_nlink > 0)
--(ap->sa_vattr.va_nlink);
switch (infolev) {
case SMB_INFO_STANDARD:
if (datasz > UINT_MAX)
datasz = UINT_MAX;
if (allocsz > UINT_MAX)
allocsz = UINT_MAX;
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
smb_encode_smb_datetimes(sr, xa, ap);
(void) smb_mbc_encodef(&xa->rep_data_mb, "llw",
(uint32_t)datasz, (uint32_t)allocsz, dattr);
break;
case SMB_INFO_QUERY_EA_SIZE:
if (datasz > UINT_MAX)
datasz = UINT_MAX;
if (allocsz > UINT_MAX)
allocsz = UINT_MAX;
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
smb_encode_smb_datetimes(sr, xa, ap);
(void) smb_mbc_encodef(&xa->rep_data_mb, "llwl",
(uint32_t)datasz, (uint32_t)allocsz, dattr, 0);
break;
case SMB_INFO_QUERY_EAS_FROM_LIST:
case SMB_INFO_QUERY_ALL_EAS:
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
break;
case SMB_INFO_IS_NAME_VALID:
break;
case SMB_QUERY_FILE_BASIC_INFO:
case SMB_FILE_BASIC_INFORMATION:
/*
* NT includes 6 undocumented bytes at the end of this
* response, which are required by NetBench 5.01.
* Similar change in smb_trans2_query_file_information.c.
*/
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
smb_encode_nt_times(sr, xa, ap);
(void) smb_mbc_encodef(&xa->rep_data_mb, "w6.", dattr);
break;
case SMB_QUERY_FILE_STANDARD_INFO:
case SMB_FILE_STANDARD_INFORMATION:
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
/*
* Add 2 bytes to pad data to long. It is
* necessary because Win2k expects the padded bytes.
*/
(void) smb_mbc_encodef(&xa->rep_data_mb, "qqlbb2.",
(uint64_t)allocsz,
(uint64_t)datasz,
ap->sa_vattr.va_nlink,
delete_on_close,
(char)(ap->sa_vattr.va_type == VDIR));
break;
case SMB_QUERY_FILE_EA_INFO:
case SMB_FILE_EA_INFORMATION:
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
break;
case SMB_QUERY_FILE_NAME_INFO:
case SMB_FILE_NAME_INFORMATION:
/* If the leading \ is missing, add it. */
if (*namep != '\\') {
(void) snprintf(name, MAXNAMELEN, "\\%s", namep);
namep = name;
}
len = smb_ascii_or_unicode_strlen(sr, namep);
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
(void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr, len, namep);
break;
case SMB_QUERY_FILE_ALL_INFO:
case SMB_FILE_ALL_INFORMATION:
rc = smb_query_all_info_filename(sr->tid_tree, node,
name, MAXPATHLEN);
if (rc != 0) {
smbsr_errno(sr, rc);
smb_node_release(node);
kmem_free(name, MAXPATHLEN);
return (SDRC_ERROR);
}
/*
* There is a 6-byte pad between Attributes and AllocationSize,
* and a 2-byte pad after the Directory field.
*/
rc = smb_query_all_info_filename(sr->tid_tree, node,
name, MAXPATHLEN);
if (rc != 0) {
smbsr_errno(sr, rc);
smb_node_release(node);
kmem_free(name, MAXPATHLEN);
return (SDRC_ERROR);
}
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
smb_encode_nt_times(sr, xa, ap);
(void) smb_mbc_encodef(&xa->rep_data_mb, "w6.qqlbb2.l",
dattr,
(uint64_t)allocsz,
(uint64_t)datasz,
ap->sa_vattr.va_nlink,
0,
is_dir,
0);
(void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr,
smb_ascii_or_unicode_strlen(sr, name), name);
break;
case SMB_QUERY_FILE_ALT_NAME_INFO:
case SMB_FILE_ALT_NAME_INFORMATION:
/*
* If the shortname is generated by smb_mangle_name()
* it will be returned as the alternative name.
* Otherwise, convert the original name to upper-case
* and return it as the alternative name.
*/
(void) smb_mangle_name(ap->sa_vattr.va_nodeid,
name, short_name, name83, 0);
alt_nm_ptr = ((*short_name == 0) ?
utf8_strupr(name) : short_name);
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
(void) smb_mbc_encodef(&xa->rep_data_mb, "%lU", sr,
mts_wcequiv_strlen(alt_nm_ptr), alt_nm_ptr);
break;
case SMB_QUERY_FILE_STREAM_INFO:
case SMB_FILE_STREAM_INFORMATION:
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
smb_encode_stream_info(sr, xa, node, ap);
break;
case SMB_QUERY_FILE_COMPRESSION_INFO:
case SMB_FILE_COMPRESSION_INFORMATION:
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
(void) smb_mbc_encodef(&xa->rep_data_mb,
"qwbbb3.", datasz, 0, 0, 0, 0);
break;
case SMB_FILE_INTERNAL_INFORMATION:
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
(void) smb_mbc_encodef(&xa->rep_data_mb, "q",
ap->sa_vattr.va_nodeid);
break;
case SMB_FILE_ATTR_TAG_INFORMATION:
/*
* 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.
*/
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
(void) smb_mbc_encodef(&xa->rep_data_mb, "ll",
(uint32_t)dattr, 0);
break;
default:
smb_node_release(node);
kmem_free(name, MAXPATHLEN);
smbsr_error(sr, 0, ERRDOS, ERRunknownlevel);
return (SDRC_ERROR);
}
smb_node_release(node);
kmem_free(name, MAXPATHLEN);
return (SDRC_SUCCESS);
}
/*
* smb_query_all_info_filename
*
* This format of filename is only used by the ALL_INFO level.
*
* Determine the absolute pathname of 'node' within the share.
* For example if the node represents file "test1.txt" in directory
* "dir1" on share "share1", the path would be: \share1\dir1\test1.txt
*
* If node represents a named stream, construct the pathname for the
* associated unnamed stream then append the stream name.
*/
int
smb_query_all_info_filename(smb_tree_t *tree, smb_node_t *node,
char *buf, size_t buflen)
{
char *sharename = tree->t_sharename;
int rc;
size_t len;
vnode_t *vp;
len = snprintf(buf, buflen, "\\%s", sharename);
if (len == (buflen - 1))
return (ENAMETOOLONG);
buf += len;
buflen -= len;
if (SMB_IS_STREAM(node))
vp = node->n_unode->vp;
else
vp = node->vp;
rc = vnodetopath(tree->t_snode->vp, vp, buf, buflen, kcred);
if (rc == 0) {
(void) strsubst(buf, '/', '\\');
if (SMB_IS_STREAM(node))
(void) strlcat(buf, node->od_name, buflen);
}
return (rc);
}