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,30 **** */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * ! * Copyright 2015 Nexenta Systems, Inc. All rights reserved. */ /* * This module provides functions for TRANS2_FIND_FIRST2 and --- 20,30 ---- */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * ! * Copyright 2017 Nexenta Systems, Inc. All rights reserved. */ /* * This module provides functions for TRANS2_FIND_FIRST2 and
*** 211,221 **** /* * 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; 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 */ --- 211,221 ---- /* * Args (and other state) that we carry around among the * various functions involved in FindFirst, FindNext. */ typedef struct smb_find_args { ! 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,233 **** 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_mbc_encode(smb_request_t *, smb_xa_t *, smb_fileinfo_t *, smb_find_args_t *); /* * Tunable parameter to limit the maximum --- 223,233 ---- 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_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,330 **** 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) return (SDRC_ERROR); status = smb_odir_openpath(sr, pn->pn_path, sattr, odir_flags, &od); if (status != 0) { smbsr_error(sr, status, 0, 0); --- 318,330 ---- 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_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,352 **** } if (count == 0) { smb_odir_close(od); smb_odir_release(od); ! smbsr_errno(sr, ENOENT); return (SDRC_ERROR); } if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) || (args.fa_eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) { --- 342,353 ---- } if (count == 0) { smb_odir_close(od); smb_odir_release(od); ! 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,465 **** } 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) return (SDRC_ERROR); od = smb_tree_lookup_odir(sr, odid); if (od == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, --- 454,466 ---- } if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT) sr->user_cr = smb_user_getprivcred(sr->uid_user); ! 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,545 **** --- 535,562 ---- { 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,557 **** --- 565,575 ---- 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,576 **** --- 585,603 ---- ++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,636 **** return (count); } /* ! * smb_trans2_find_get_maxdata * ! * Calculate the minimum response space required for the specified ! * information level. * ! * A non-zero return value provides the minimum space required. * 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) { ! int maxdata; - 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: if (fflag & SMB_FIND_RETURN_RESUME_KEYS) maxdata += sizeof (int32_t); maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 4 + 1; break; --- 631,663 ---- return (count); } /* ! * smb_trans2_find_get_fixedsize * ! * Calculate the sizeof the fixed part of the response for the ! * specified information level. * ! * 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_fixedsize(smb_request_t *sr, uint16_t infolev, ! uint16_t fflag) { ! int maxdata = 0; 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,748 **** uint32_t dsize32, asize32; uint32_t mb_flags = 0; uint32_t resume_key; char buf83[26]; smb_msgbuf_t mb; namelen = smb_ascii_or_unicode_strlen(sr, fileinfo->fi_name); if (namelen == -1) return (-1); /* ! * If ascii the filename length returned to the client should ! * include the null terminator for levels except STANDARD and ! * EASIZE. */ ! if (!(sr->smb_flg2 & SMB_FLAGS2_UNICODE)) { ! if ((args->fa_infolev != SMB_INFO_STANDARD) && ! (args->fa_infolev != SMB_INFO_QUERY_EA_SIZE)) namelen += 1; } - 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; --- 745,801 ---- 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) { /* ! * 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) != 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; } + } 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,781 **** --- 825,835 ---- 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,948 **** 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); 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); return (SDRC_SUCCESS); } void smb_post_find_close2(smb_request_t *sr) { ! DTRACE_SMB_1(op__FindClose2__done, smb_request_t *, sr); } smb_sdrc_t smb_com_find_close2(smb_request_t *sr) { --- 973,1005 ---- 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, ! 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_START(op__FindClose2, smb_request_t *, sr); return (SDRC_SUCCESS); } void smb_post_find_close2(smb_request_t *sr) { ! DTRACE_SMB_DONE(op__FindClose2, smb_request_t *, sr); } smb_sdrc_t smb_com_find_close2(smb_request_t *sr) {