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-3409 SMB2: OSX - cannot display nested folders in finder
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-3733 Want SMB2 Apple extensions
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-2604 Windows Explorer Stops Working / Crashes when Security Tab is accessed
NEX-2593 SMB2: unable to create folder with long filename on 4.0.3
NEX-1409 bcmp(NULL, NULL, 0) panics in DEBUG kernel
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Josef Sipek <josef.sipek@nexenta.com>
SMB-143 OS X 10.9.2 not working with SMB2
SMB-122 smbd core dumps in smbd_dc_update / smb_log
SMB-117 Win7 fails to open security properties
SMB-105 Codenomicon: SMB2 TC: 384126: Panic in smb2_query_dir with null search pattern
SMB-110 panic mapping a share from Nexentastor to the windows 2012 R2 client
SMB-109 Codenomicon: SMB TC: 409480 - Panic with SMB2_FIND request
SMB-96 Codenomicon: SMB2 TC: 141500 - Panic in smb2_decode_create_ctx
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)
@@ -20,22 +20,30 @@
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
- * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 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>
+#include <smbsrv/smb2_aapl.h>
/*
+ * Internally defined info. level for MacOS support.
+ * Make sure this does not conflict with real values in
+ * FILE_INFORMATION_CLASS, and that it fits in 8-bits.
+ */
+#define FileIdMacOsDirectoryInformation (FileMaximumInformation + 10)
+
+/*
* Args (and other state) that we carry around among the
* various functions involved in SMB2 Query Directory.
*/
typedef struct smb2_find_args {
uint32_t fa_maxdata;
@@ -44,16 +52,21 @@
uint16_t fa_maxcount;
uint16_t fa_eos; /* End Of Search */
uint16_t fa_fixedsize; /* size of fixed part of a returned entry */
uint32_t fa_lastkey; /* Last resume key */
int fa_last_entry; /* offset of last entry */
+
+ /* Normal info, per dir. entry */
+ smb_fileinfo_t fa_fi;
+
+ /* MacOS AAPL extension stuff. */
+ smb_macinfo_t fa_mi;
} smb2_find_args_t;
static uint32_t smb2_find_entries(smb_request_t *,
smb_odir_t *, smb2_find_args_t *);
-static uint32_t smb2_find_mbc_encode(smb_request_t *,
- smb_fileinfo_t *, smb2_find_args_t *);
+static uint32_t smb2_find_mbc_encode(smb_request_t *, smb2_find_args_t *);
/*
* Tunable parameter to limit the maximum
* number of entries to be returned.
*/
@@ -97,13 +110,16 @@
&args.fa_maxdata); /* l */
if (rc || StructSize != 33)
return (SDRC_ERROR);
status = smb2sr_lookup_fid(sr, &smb2fid);
+ of = sr->fid_ofile;
+
+ DTRACE_SMB2_START(op__QueryDirectory, smb_request_t *, sr);
+
if (status)
goto errout;
- of = sr->fid_ofile;
/*
* If there's an input buffer (search pattern), decode it.
* Two times MAXNAMELEN because it represents the UNICODE string
* length in bytes.
@@ -140,14 +156,12 @@
if (args.fa_maxdata > smb2_max_trans)
args.fa_maxdata = smb2_max_trans;
sr->raw_data.max_bytes = args.fa_maxdata;
/*
- * Get the mininum size of entries we will return, which
+ * Get the fixed 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) {
@@ -172,10 +186,23 @@
default:
status = NT_STATUS_INVALID_INFO_CLASS;
goto errout;
}
+ /*
+ * MacOS, when using the AAPL CreateContext extensions
+ * and the "read dir attr" feature, uses a non-standard
+ * information format for directory entries. Internally
+ * we'll use a fake info level to represent this case.
+ * (Wish they had just defined a new info level.)
+ */
+ if ((sr->session->s_flags & SMB_SSN_AAPL_READDIR) != 0 &&
+ args.fa_infoclass == FileIdBothDirectoryInformation) {
+ args.fa_infoclass = FileIdMacOsDirectoryInformation;
+ args.fa_fixedsize = 96; /* yes, same size */
+ }
+
args.fa_maxcount = args.fa_maxdata / (args.fa_fixedsize + 4);
if (args.fa_maxcount == 0)
args.fa_maxcount = 1;
if ((smb2_find_max != 0) && (args.fa_maxcount > smb2_find_max))
args.fa_maxcount = smb2_find_max;
@@ -224,28 +251,32 @@
*/
status = smb2_find_entries(sr, od, &args);
of->f_seek_pos = od->d_offset;
- if (status == NT_STATUS_NO_MORE_FILES) {
- if (args.fa_fflags & SMB2_QDIR_FLAG_SINGLE) {
+ if ((args.fa_fflags & SMB2_QDIR_FLAG_SINGLE) &&
+ status == NT_STATUS_NO_MORE_FILES) {
status = NT_STATUS_NO_SUCH_FILE;
- goto errout;
}
+
+errout:
+ sr->smb2_status = status;
+ DTRACE_SMB2_DONE(op__QueryDirectory, smb_request_t *, sr);
+
/*
- * This is not an error, but a warning that can be
+ * Note: NT_STATUS_NO_MORE_FILES is a warning
* 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.
*/
- sr->smb2_status = status;
- status = 0;
+ if (status != 0 &&
+ status != NT_STATUS_NO_MORE_FILES) {
+ smb2sr_put_error(sr, status);
+ return (SDRC_SUCCESS);
}
- if (status)
- goto errout;
/*
* SMB2 Query Directory reply
*/
StructSize = 9;
@@ -257,16 +288,14 @@
DataOff, /* w */
DataLen, /* l */
&sr->raw_data); /* C */
if (DataLen == 0)
(void) smb_mbc_encodef(&sr->reply, ".");
- if (rc == 0)
- return (SDRC_SUCCESS);
- status = NT_STATUS_UNSUCCESSFUL;
-errout:
- smb2sr_put_error(sr, status);
+ if (rc)
+ sr->smb2_status = NT_STATUS_INTERNAL_ERROR;
+
return (SDRC_SUCCESS);
}
/*
* smb2_find_entries
@@ -277,12 +306,13 @@
* NT status
*/
static uint32_t
smb2_find_entries(smb_request_t *sr, smb_odir_t *od, smb2_find_args_t *args)
{
- smb_fileinfo_t fileinfo;
smb_odir_resume_t odir_resume;
+ char *tbuf = NULL;
+ size_t tbuflen = 0;
uint16_t count;
uint16_t minsize;
uint32_t status = 0;
int rc = -1;
@@ -291,19 +321,30 @@
* minimum size entry. That's the fixed part plus the
* storage size of a 1 char unicode string.
*/
minsize = args->fa_fixedsize + 2;
+ /*
+ * FileIdMacOsDirectoryInformation needs some buffer space
+ * for composing directory entry + stream name for lookup.
+ * Get the buffer now to avoid alloc/free per entry.
+ */
+ if (args->fa_infoclass == FileIdMacOsDirectoryInformation) {
+ tbuflen = 2 * MAXNAMELEN;
+ tbuf = kmem_alloc(tbuflen, KM_SLEEP);
+ }
+
count = 0;
while (count < args->fa_maxcount) {
if (!MBC_ROOM_FOR(&sr->raw_data, minsize)) {
status = NT_STATUS_BUFFER_OVERFLOW;
break;
}
- rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &args->fa_eos);
+ rc = smb_odir_read_fileinfo(sr, od,
+ &args->fa_fi, &args->fa_eos);
if (rc == ENOENT) {
status = NT_STATUS_NO_MORE_FILES;
break;
}
if (rc != 0) {
@@ -314,11 +355,19 @@
/* The readdir call hit the end. */
status = NT_STATUS_NO_MORE_FILES;
break;
}
- status = smb2_find_mbc_encode(sr, &fileinfo, args);
+ if (args->fa_infoclass == FileIdMacOsDirectoryInformation)
+ (void) smb2_aapl_get_macinfo(sr, od,
+ &args->fa_fi, &args->fa_mi, tbuf, tbuflen);
+
+ if (smb2_aapl_use_file_ids == 0 &&
+ (sr->session->s_flags & SMB_SSN_AAPL_CCEXT) != 0)
+ args->fa_fi.fi_nodeid = 0;
+
+ status = smb2_find_mbc_encode(sr, args);
if (status) {
/*
* We read a directory entry but failed to
* copy it into the output buffer. Rewind
* the directory pointer so this will be
@@ -333,11 +382,11 @@
/*
* Save the offset of the next entry we'll read.
* If we fail copying, we'll need this offset.
*/
- args->fa_lastkey = fileinfo.fi_cookie;
+ args->fa_lastkey = args->fa_fi.fi_cookie;
++count;
}
if (count == 0) {
ASSERT(status != 0);
@@ -353,10 +402,13 @@
(void) smb_mbc_poke(&sr->raw_data,
args->fa_last_entry, "l", 0);
status = 0;
}
+ if (tbuf != NULL)
+ kmem_free(tbuf, tbuflen);
+
return (status);
}
/*
* smb2_mbc_encode
@@ -377,16 +429,17 @@
*
* Returns: 0 - data successfully encoded
* NT status
*/
static uint32_t
-smb2_find_mbc_encode(smb_request_t *sr, smb_fileinfo_t *fileinfo,
- smb2_find_args_t *args)
+smb2_find_mbc_encode(smb_request_t *sr, smb2_find_args_t *args)
{
+ smb_fileinfo_t *fileinfo = &args->fa_fi;
+ smb_macinfo_t *macinfo = &args->fa_mi;
uint8_t buf83[26];
smb_msgbuf_t mb;
- int namelen, padsz;
+ int namelen;
int shortlen = 0;
int rc, starting_offset;
uint32_t next_entry_offset;
uint32_t mb_flags = SMB_MSGBUF_UNICODE;
uint32_t resume_key;
@@ -522,10 +575,51 @@
fileinfo->fi_nodeid); /* q */
smb_msgbuf_term(&mb);
break;
+ /*
+ * MacOS, when using the AAPL extensions (see smb2_create)
+ * uses modified directory listing responses where the
+ * "EA size" field is replaced with "maximum access".
+ * This avoids the need for MacOS Finder to come back
+ * N times to get the maximum access for every file.
+ */
+ case FileIdMacOsDirectoryInformation:
+ rc = smb_mbc_encodef(
+ &sr->raw_data, "llTTTTqqll",
+ 0, /* NextEntryOffset (set later) */
+ resume_key, /* a.k.a. file index */
+ &fileinfo->fi_crtime,
+ &fileinfo->fi_atime,
+ &fileinfo->fi_mtime,
+ &fileinfo->fi_ctime,
+ fileinfo->fi_size, /* q */
+ fileinfo->fi_alloc_size, /* q */
+ fileinfo->fi_dosattr, /* l */
+ namelen); /* l */
+ if (rc != 0)
+ break;
+ /*
+ * This where FileIdMacOsDirectoryInformation
+ * differs from FileIdBothDirectoryInformation
+ * Instead of: EaSize, ShortNameLen, ShortName;
+ * MacOS wants: MaxAccess, ResourceForkSize, and
+ * 16 bytes of "compressed finder info".
+ * mi_rforksize + mi_finderinfo falls where
+ * the 24 byte shortname would normally be.
+ */
+ rc = smb_mbc_encodef(
+ &sr->raw_data, "l..q16cwq",
+ macinfo->mi_maxaccess, /* l */
+ /* short_name_len, reserved (..) */
+ macinfo->mi_rforksize, /* q */
+ macinfo->mi_finderinfo, /* 16c */
+ macinfo->mi_unixmode, /* w */
+ fileinfo->fi_nodeid); /* q */
+ break;
+
/* See also: SMB_FIND_FILE_NAMES_INFO */
case FileNamesInformation: /* 12 */
rc = smb_mbc_encodef(
&sr->raw_data, "lll",
0, /* NextEntryOffset (set later) */
@@ -551,15 +645,12 @@
fileinfo->fi_name);
if (rc)
return (NT_STATUS_BUFFER_OVERFLOW);
/* Next entry needs to be 8-byte aligned. */
- padsz = sr->raw_data.chain_offset & 7;
- if (padsz) {
- padsz = 8 - padsz;
- (void) smb_mbc_encodef(&sr->raw_data, "#.", padsz);
- }
+ (void) smb_mbc_put_align(&sr->raw_data, 8);
+
next_entry_offset = sr->raw_data.chain_offset - starting_offset;
(void) smb_mbc_poke(&sr->raw_data, starting_offset, "l",
next_entry_offset);
args->fa_last_entry = starting_offset;