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,41 **** */ /* * 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 { uint32_t fa_maxdata; --- 20,49 ---- */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * ! * 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,59 **** 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 */ } 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 *); /* * Tunable parameter to limit the maximum * number of entries to be returned. */ --- 52,72 ---- 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 *, smb2_find_args_t *); /* * Tunable parameter to limit the maximum * number of entries to be returned. */
*** 97,109 **** &args.fa_maxdata); /* l */ if (rc || StructSize != 33) return (SDRC_ERROR); status = smb2sr_lookup_fid(sr, &smb2fid); 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. --- 110,125 ---- &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; /* * If there's an input buffer (search pattern), decode it. * Two times MAXNAMELEN because it represents the UNICODE string * length in bytes.
*** 140,153 **** 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 * 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) { --- 156,167 ---- if (args.fa_maxdata > smb2_max_trans) args.fa_maxdata = smb2_max_trans; sr->raw_data.max_bytes = args.fa_maxdata; /* ! * Get the fixed size of entries we will return, which * lets us estimate the number of entries we'll need. * * Also use this opportunity to validate fa_infoclass. */ switch (args.fa_infoclass) {
*** 172,181 **** --- 186,208 ---- 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,251 **** */ 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) { status = NT_STATUS_NO_SUCH_FILE; - 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. */ ! sr->smb2_status = status; ! status = 0; } - if (status) - goto errout; /* * SMB2 Query Directory reply */ StructSize = 9; --- 251,282 ---- */ status = smb2_find_entries(sr, od, &args); of->f_seek_pos = od->d_offset; ! if ((args.fa_fflags & SMB2_QDIR_FLAG_SINGLE) && ! status == NT_STATUS_NO_MORE_FILES) { status = NT_STATUS_NO_SUCH_FILE; } + + errout: + sr->smb2_status = status; + DTRACE_SMB2_DONE(op__QueryDirectory, smb_request_t *, sr); + /* ! * 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. */ ! if (status != 0 && ! status != NT_STATUS_NO_MORE_FILES) { ! smb2sr_put_error(sr, status); ! return (SDRC_SUCCESS); } /* * SMB2 Query Directory reply */ StructSize = 9;
*** 257,272 **** 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); return (SDRC_SUCCESS); } /* * smb2_find_entries --- 288,301 ---- DataOff, /* w */ DataLen, /* l */ &sr->raw_data); /* C */ if (DataLen == 0) (void) smb_mbc_encodef(&sr->reply, "."); ! if (rc) ! sr->smb2_status = NT_STATUS_INTERNAL_ERROR; ! return (SDRC_SUCCESS); } /* * smb2_find_entries
*** 277,288 **** * 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; uint16_t count; uint16_t minsize; uint32_t status = 0; int rc = -1; --- 306,318 ---- * NT status */ static uint32_t smb2_find_entries(smb_request_t *sr, smb_odir_t *od, smb2_find_args_t *args) { 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,309 **** * minimum size entry. That's the fixed part plus the * storage size of a 1 char unicode string. */ minsize = args->fa_fixedsize + 2; 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); if (rc == ENOENT) { status = NT_STATUS_NO_MORE_FILES; break; } if (rc != 0) { --- 321,350 ---- * 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, ! &args->fa_fi, &args->fa_eos); if (rc == ENOENT) { status = NT_STATUS_NO_MORE_FILES; break; } if (rc != 0) {
*** 314,324 **** /* The readdir call hit the end. */ status = NT_STATUS_NO_MORE_FILES; break; } ! status = smb2_find_mbc_encode(sr, &fileinfo, 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 --- 355,373 ---- /* The readdir call hit the end. */ status = NT_STATUS_NO_MORE_FILES; break; } ! 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,343 **** /* * 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; ++count; } if (count == 0) { ASSERT(status != 0); --- 382,392 ---- /* * Save the offset of the next entry we'll read. * If we fail copying, we'll need this offset. */ ! args->fa_lastkey = args->fa_fi.fi_cookie; ++count; } if (count == 0) { ASSERT(status != 0);
*** 353,362 **** --- 402,414 ---- (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,392 **** * * 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) { uint8_t buf83[26]; smb_msgbuf_t mb; ! int namelen, padsz; int shortlen = 0; int rc, starting_offset; uint32_t next_entry_offset; uint32_t mb_flags = SMB_MSGBUF_UNICODE; uint32_t resume_key; --- 429,445 ---- * * Returns: 0 - data successfully encoded * NT status */ static uint32_t ! 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; int shortlen = 0; int rc, starting_offset; uint32_t next_entry_offset; uint32_t mb_flags = SMB_MSGBUF_UNICODE; uint32_t resume_key;
*** 522,531 **** --- 575,625 ---- 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,565 **** 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); ! } 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; --- 645,656 ---- fileinfo->fi_name); if (rc) return (NT_STATUS_BUFFER_OVERFLOW); /* Next entry needs to be 8-byte aligned. */ ! (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;