Print this page
NEX-15069 smtorture smb2.create.blob is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15069 smtorture smb2.create.blob is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-1643 dtrace provider for smbsrv
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-4458 Incorrect directory listing response for non-UNICODE clients
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-4540 SMB server declines EA support incorrectly
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-4053 Customer DIR command hangs with smb2 enabled
NEX-4080 SMB_ODIR_FLAG_WILDCARDS can be incorrectly inherited
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
SMB-11 SMB2 message parse & dispatch
SMB-12 SMB2 Negotiate Protocol
SMB-13 SMB2 Session Setup
SMB-14 SMB2 Logoff
SMB-15 SMB2 Tree Connect
SMB-16 SMB2 Tree Disconnect
SMB-17 SMB2 Create
SMB-18 SMB2 Close
SMB-19 SMB2 Flush
SMB-20 SMB2 Read
SMB-21 SMB2 Write
SMB-22 SMB2 Lock/Unlock
SMB-23 SMB2 Ioctl
SMB-24 SMB2 Cancel
SMB-25 SMB2 Echo
SMB-26 SMB2 Query Dir
SMB-27 SMB2 Change Notify
SMB-28 SMB2 Query Info
SMB-29 SMB2 Set Info
SMB-30 SMB2 Oplocks
SMB-53 SMB2 Create Context options
(SMB2 code review cleanup 1, 2, 3)
SMB-50 User-mode SMB server
Includes work by these authors:
Thomas Keiser <thomas.keiser@nexenta.com>
Albert Lee <trisk@nexenta.com>
SMB-63 taskq_create_proc ... TQ_DYNAMIC puts tasks in p0
re #11974 CIFS Share - Tree connect fails from Windows 7 Clients
re #10733 Windows 7 directory listing keeps restarting (fix lint)
re #10733 Windows 7 directory listing keeps restarting
@@ -20,11 +20,11 @@
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
/*
* This module provides functions for TRANS2_FIND_FIRST2 and
@@ -211,11 +211,11 @@
/*
* Args (and other state) that we carry around among the
* various functions involved in FindFirst, FindNext.
*/
typedef struct smb_find_args {
- uint32_t fa_maxdata;
+ uint32_t fa_fixedsize;
uint16_t fa_infolev;
uint16_t fa_maxcount;
uint16_t fa_fflag;
uint16_t fa_eos; /* End Of Search */
uint16_t fa_lno; /* Last Name Offset */
@@ -223,11 +223,11 @@
char fa_lastname[MAXNAMELEN]; /* and name */
} smb_find_args_t;
static int smb_trans2_find_entries(smb_request_t *, smb_xa_t *,
smb_odir_t *, smb_find_args_t *);
-static int smb_trans2_find_get_maxdata(smb_request_t *, uint16_t, uint16_t);
+static int smb_trans2_find_get_fixedsize(smb_request_t *, uint16_t, uint16_t);
static int smb_trans2_find_mbc_encode(smb_request_t *, smb_xa_t *,
smb_fileinfo_t *, smb_find_args_t *);
/*
* Tunable parameter to limit the maximum
@@ -318,13 +318,13 @@
if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT) {
sr->user_cr = smb_user_getprivcred(sr->uid_user);
odir_flags = SMB_ODIR_OPENF_BACKUP_INTENT;
}
- args.fa_maxdata =
- smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag);
- if (args.fa_maxdata == 0)
+ args.fa_fixedsize =
+ smb_trans2_find_get_fixedsize(sr, args.fa_infolev, args.fa_fflag);
+ if (args.fa_fixedsize == 0)
return (SDRC_ERROR);
status = smb_odir_openpath(sr, pn->pn_path, sattr, odir_flags, &od);
if (status != 0) {
smbsr_error(sr, status, 0, 0);
@@ -342,11 +342,12 @@
}
if (count == 0) {
smb_odir_close(od);
smb_odir_release(od);
- smbsr_errno(sr, ENOENT);
+ smbsr_status(sr, NT_STATUS_NO_SUCH_FILE,
+ ERRDOS, ERROR_FILE_NOT_FOUND);
return (SDRC_ERROR);
}
if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) ||
(args.fa_eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) {
@@ -453,13 +454,13 @@
}
if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT)
sr->user_cr = smb_user_getprivcred(sr->uid_user);
- args.fa_maxdata =
- smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag);
- if (args.fa_maxdata == 0)
+ args.fa_fixedsize =
+ smb_trans2_find_get_fixedsize(sr, args.fa_infolev, args.fa_fflag);
+ if (args.fa_fixedsize == 0)
return (SDRC_ERROR);
od = smb_tree_lookup_odir(sr, odid);
if (od == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
@@ -534,12 +535,28 @@
{
smb_fileinfo_t fileinfo;
smb_odir_resume_t odir_resume;
uint16_t count, maxcount;
int rc = -1;
+ int LastEntryOffset = 0;
boolean_t need_rewind = B_FALSE;
+ /*
+ * EAs are not current supported, so a search for level
+ * SMB_INFO_QUERY_EAS_FROM_LIST should always return an
+ * empty list. Returning zero for this case gives the
+ * client an empty response, which is better than an
+ * NT_STATUS_INVALID_LEVEL return (and test failures).
+ *
+ * If and when we do support EAs, this level will modify
+ * the search here, and then return results just like
+ * SMB_INFO_QUERY_EA_SIZE, but only including files
+ * that have an EA in the provided list.
+ */
+ if (args->fa_infolev == SMB_INFO_QUERY_EAS_FROM_LIST)
+ return (0);
+
if ((maxcount = args->fa_maxcount) == 0)
maxcount = 1;
if ((smb_trans2_find_max != 0) && (maxcount > smb_trans2_find_max))
maxcount = smb_trans2_find_max;
@@ -548,10 +565,11 @@
while (count < maxcount) {
rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &args->fa_eos);
if (rc != 0 || args->fa_eos != 0)
break;
+ LastEntryOffset = xa->rep_data_mb.chain_offset;
rc = smb_trans2_find_mbc_encode(sr, xa, &fileinfo, args);
if (rc == -1)
return (-1); /* fatal encoding error */
if (rc == 1) {
need_rewind = B_TRUE;
@@ -567,10 +585,19 @@
++count;
}
if (args->fa_eos != 0 && rc == ENOENT)
rc = 0;
+ /*
+ * All but the ancient info levels start with NextEntryOffset.
+ * That's supposed to be zero in the last entry returned.
+ */
+ if (args->fa_infolev >= SMB_FIND_FILE_DIRECTORY_INFO) {
+ (void) smb_mbc_poke(&xa->rep_data_mb,
+ LastEntryOffset, "l", 0);
+ }
+
/* save the last cookie returned to client */
if (count != 0)
smb_odir_save_fname(od, args->fa_lastkey, args->fa_lastname);
/*
@@ -604,33 +631,33 @@
return (count);
}
/*
- * smb_trans2_find_get_maxdata
+ * smb_trans2_find_get_fixedsize
*
- * Calculate the minimum response space required for the specified
- * information level.
+ * Calculate the sizeof the fixed part of the response for the
+ * specified information level.
*
- * A non-zero return value provides the minimum space required.
+ * A non-zero return value provides the fixed size.
* A return value of zero indicates an unknown information level.
*/
static int
-smb_trans2_find_get_maxdata(smb_request_t *sr, uint16_t infolev, uint16_t fflag)
+smb_trans2_find_get_fixedsize(smb_request_t *sr, uint16_t infolev,
+ uint16_t fflag)
{
- int maxdata;
+ int maxdata = 0;
- maxdata = smb_ascii_or_unicode_null_len(sr);
-
switch (infolev) {
case SMB_INFO_STANDARD :
if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
maxdata += sizeof (int32_t);
maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 1;
break;
case SMB_INFO_QUERY_EA_SIZE:
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
maxdata += sizeof (int32_t);
maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 4 + 1;
break;
@@ -718,31 +745,57 @@
uint32_t dsize32, asize32;
uint32_t mb_flags = 0;
uint32_t resume_key;
char buf83[26];
smb_msgbuf_t mb;
+ int pad = 0;
namelen = smb_ascii_or_unicode_strlen(sr, fileinfo->fi_name);
if (namelen == -1)
return (-1);
+ if (args->fa_infolev < SMB_FIND_FILE_DIRECTORY_INFO) {
/*
- * If ascii the filename length returned to the client should
- * include the null terminator for levels except STANDARD and
- * EASIZE.
+ * Ancient info levels don't have a NextEntryOffset
+ * field, so there's no padding for alignment.
+ * The client expects a null after the file name,
+ * and then the next entry. The namelength field
+ * never includes the null for these old levels.
+ * Using the pad value to write the null because
+ * we don't want to add that to namelen.
+ * [MS-CIFS] sec. 2.8.1.{1-3}
*/
- if (!(sr->smb_flg2 & SMB_FLAGS2_UNICODE)) {
- if ((args->fa_infolev != SMB_INFO_STANDARD) &&
- (args->fa_infolev != SMB_INFO_QUERY_EA_SIZE))
+ if ((sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0)
+ pad = 2; /* Unicode null */
+ else
+ pad = 1; /* ascii null */
+ next_entry_offset = args->fa_fixedsize + namelen + pad;
+ if (!MBC_ROOM_FOR(&xa->rep_data_mb, next_entry_offset))
+ return (1);
+ } else {
+ /*
+ * Later info levels: The file name is written WITH
+ * null termination, and the size of that null _is_
+ * included in the namelen field. There may also
+ * be padding, and we pad to align(4) like Windows.
+ * Don't include the padding in the "room for" test
+ * because we want to ignore any error writing the
+ * pad bytes after the last element.
+ */
+ if ((sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0)
+ namelen += 2;
+ else
namelen += 1;
+ next_entry_offset = args->fa_fixedsize + namelen;
+ if (!MBC_ROOM_FOR(&xa->rep_data_mb, next_entry_offset))
+ return (1);
+ if ((next_entry_offset & 3) != 0) {
+ pad = 4 - (next_entry_offset & 3);
+ next_entry_offset += pad;
}
+ }
- next_entry_offset = args->fa_maxdata + namelen;
-
- if (MBC_ROOM_FOR(&xa->rep_data_mb, (args->fa_maxdata + namelen)) == 0)
- return (1);
-
mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE) ? SMB_MSGBUF_UNICODE : 0;
dsize32 = (fileinfo->fi_size > UINT_MAX) ?
UINT_MAX : (uint32_t)fileinfo->fi_size;
asize32 = (fileinfo->fi_alloc_size > UINT_MAX) ?
UINT_MAX : (uint32_t)fileinfo->fi_alloc_size;
@@ -772,10 +825,11 @@
fileinfo->fi_dosattr,
namelen);
break;
case SMB_INFO_QUERY_EA_SIZE:
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS)
(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
resume_key);
(void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwlb", sr,
@@ -919,30 +973,33 @@
args->fa_lno = xa->rep_data_mb.chain_offset;
if ((sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0 &&
(args->fa_lno & 1) != 0)
args->fa_lno++;
- (void) smb_mbc_encodef(&xa->rep_data_mb, "%u", sr,
- fileinfo->fi_name);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "%#u", sr,
+ namelen, fileinfo->fi_name);
+ if (pad)
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "#.", pad);
+
return (0);
}
/*
* Close a search started by a Trans2FindFirst2 request.
*/
smb_sdrc_t
smb_pre_find_close2(smb_request_t *sr)
{
- DTRACE_SMB_1(op__FindClose2__start, smb_request_t *, sr);
+ DTRACE_SMB_START(op__FindClose2, smb_request_t *, sr);
return (SDRC_SUCCESS);
}
void
smb_post_find_close2(smb_request_t *sr)
{
- DTRACE_SMB_1(op__FindClose2__done, smb_request_t *, sr);
+ DTRACE_SMB_DONE(op__FindClose2, smb_request_t *, sr);
}
smb_sdrc_t
smb_com_find_close2(smb_request_t *sr)
{