Print this page
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@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-4538 SMB1 create file should support extended_response format (2)
NEX-6116 Failures in smbtorture raw.open
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Include this commit if upstreaming/backporting any of:
NEX-4540 SMB server declines EA support incorrectly
NEX-4239 smbtorture create failures re. allocation size
(illumos) 6398 SMB should support path names longer than 1024
NEX-4538 SMB1 create file should support extended_response format
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
NEX-4239 smbtorture create failures re. allocation size
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@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)
re #14152 Race between ipmi_submit_driver_request() and kcs_loop() (sync with illumos fix 3902)
SMB-46 File handle leaks exposed by mtime fixes (rm 7815)
re #7815 SMB server delivers old modification time...

*** 18,31 **** * * CDDL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2015 Nexenta Systems, Inc. All rights reserved. */ #include <smbsrv/smb_kproto.h> #include <smbsrv/smb_vops.h> int smb_open_dsize_check = 0; /* --- 18,32 ---- * * CDDL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2017 Nexenta Systems, Inc. All rights reserved. */ #include <smbsrv/smb_kproto.h> + #include <smbsrv/smb_fsops.h> #include <smbsrv/smb_vops.h> int smb_open_dsize_check = 0; /*
*** 224,251 **** rc = smbsr_decode_vwv(sr, "ww", &op->omode, &op->fqi.fq_sattr); if (rc == 0) rc = smbsr_decode_data(sr, "%S", sr, &op->fqi.fq_path.pn_path); ! DTRACE_SMB_2(op__Open__start, smb_request_t *, sr, ! struct open_param *, op); return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); } void smb_post_open(smb_request_t *sr) { ! DTRACE_SMB_1(op__Open__done, smb_request_t *, sr); } smb_sdrc_t smb_com_open(smb_request_t *sr) { struct open_param *op = &sr->arg.open; smb_ofile_t *of; ! smb_attr_t attr; uint32_t status; uint16_t file_attr; int rc; op->desired_access = smb_omode_to_amask(op->omode); --- 225,251 ---- rc = smbsr_decode_vwv(sr, "ww", &op->omode, &op->fqi.fq_sattr); if (rc == 0) rc = smbsr_decode_data(sr, "%S", sr, &op->fqi.fq_path.pn_path); ! DTRACE_SMB_START(op__Open, smb_request_t *, sr); /* arg.open */ return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); } void smb_post_open(smb_request_t *sr) { ! DTRACE_SMB_DONE(op__Open, smb_request_t *, sr); } smb_sdrc_t smb_com_open(smb_request_t *sr) { struct open_param *op = &sr->arg.open; smb_ofile_t *of; ! uint32_t mtime_sec; uint32_t status; uint16_t file_attr; int rc; op->desired_access = smb_omode_to_amask(op->omode);
*** 263,284 **** else op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE; } else { op->op_oplock_level = SMB_OPLOCK_NONE; } - op->op_oplock_levelII = B_FALSE; if (smb_open_dsize_check && op->dsize > UINT_MAX) { smbsr_error(sr, 0, ERRDOS, ERRbadaccess); return (SDRC_ERROR); } status = smb_common_open(sr); if (status != NT_STATUS_SUCCESS) { smbsr_status(sr, status, 0, 0); return (SDRC_ERROR); } /* * NB: after the above smb_common_open() success, * we have a handle allocated (sr->fid_ofile). * If we don't return success, we must close it. --- 263,291 ---- else op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE; } else { op->op_oplock_level = SMB_OPLOCK_NONE; } if (smb_open_dsize_check && op->dsize > UINT_MAX) { smbsr_error(sr, 0, ERRDOS, ERRbadaccess); return (SDRC_ERROR); } + /* + * The real open call. Note: this gets attributes into + * op->fqi.fq_fattr (SMB_AT_ALL). We need those below. + */ status = smb_common_open(sr); if (status != NT_STATUS_SUCCESS) { smbsr_status(sr, status, 0, 0); return (SDRC_ERROR); } + if (op->op_oplock_level != SMB_OPLOCK_NONE) { + /* Oplock req. in op->op_oplock_level etc. */ + smb1_oplock_acquire(sr, B_FALSE); + } /* * NB: after the above smb_common_open() success, * we have a handle allocated (sr->fid_ofile). * If we don't return success, we must close it.
*** 289,385 **** sr->smb_flg &= ~(SMB_FLAGS_OPLOCK | SMB_FLAGS_OPLOCK_NOTIFY_ANY); } file_attr = op->dattr & FILE_ATTRIBUTE_MASK; ! bzero(&attr, sizeof (attr)); ! attr.sa_mask = SMB_AT_MTIME; ! rc = smb_node_getattr(sr, of->f_node, of->f_cr, of, &attr); ! if (rc != 0) { ! smbsr_errno(sr, rc); ! goto errout; ! } rc = smbsr_encode_result(sr, 7, 0, "bwwllww", 7, sr->smb_fid, file_attr, ! smb_time_gmt_to_local(sr, attr.sa_vattr.va_mtime.tv_sec), (uint32_t)op->dsize, op->omode, (uint16_t)0); /* bcc */ if (rc == 0) return (SDRC_SUCCESS); - errout: smb_ofile_close(of, 0); return (SDRC_ERROR); } /* * smb_pre_open_andx * For compatibility with windows servers, the search attributes * specified in the request are ignored. */ smb_sdrc_t smb_pre_open_andx(smb_request_t *sr) { struct open_param *op = &sr->arg.open; ! uint16_t flags; uint32_t alloc_size; uint32_t creation_time; uint16_t file_attr, sattr; int rc; bzero(op, sizeof (sr->arg.open)); rc = smbsr_decode_vwv(sr, "b.wwwwwlwll4.", &sr->andx_com, ! &sr->andx_off, &flags, &op->omode, &sattr, &file_attr, &creation_time, &op->ofun, &alloc_size, &op->timeo); if (rc == 0) { rc = smbsr_decode_data(sr, "%u", sr, &op->fqi.fq_path.pn_path); op->dattr = file_attr; op->dsize = alloc_size; ! if (flags & 2) ! op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE; ! else if (flags & 4) op->op_oplock_level = SMB_OPLOCK_BATCH; else op->op_oplock_level = SMB_OPLOCK_NONE; if ((creation_time != 0) && (creation_time != UINT_MAX)) op->crtime.tv_sec = smb_time_local_to_gmt(sr, creation_time); op->crtime.tv_nsec = 0; op->create_disposition = smb_ofun_to_crdisposition(op->ofun); } ! DTRACE_SMB_2(op__OpenX__start, smb_request_t *, sr, ! struct open_param *, op); return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); } void smb_post_open_andx(smb_request_t *sr) { ! DTRACE_SMB_1(op__OpenX__done, smb_request_t *, sr); } smb_sdrc_t smb_com_open_andx(smb_request_t *sr) { struct open_param *op = &sr->arg.open; smb_ofile_t *of; uint32_t status; uint16_t file_attr; - smb_attr_t attr; int rc; op->desired_access = smb_omode_to_amask(op->omode); op->share_access = smb_denymode_to_sharemode(op->omode, op->fqi.fq_path.pn_path); --- 296,394 ---- sr->smb_flg &= ~(SMB_FLAGS_OPLOCK | SMB_FLAGS_OPLOCK_NOTIFY_ANY); } file_attr = op->dattr & FILE_ATTRIBUTE_MASK; ! mtime_sec = smb_time_gmt_to_local(sr, ! op->fqi.fq_fattr.sa_vattr.va_mtime.tv_sec); rc = smbsr_encode_result(sr, 7, 0, "bwwllww", 7, sr->smb_fid, file_attr, ! mtime_sec, (uint32_t)op->dsize, op->omode, (uint16_t)0); /* bcc */ if (rc == 0) return (SDRC_SUCCESS); smb_ofile_close(of, 0); return (SDRC_ERROR); } + int smb_openx_enable_extended_response = 1; + /* * smb_pre_open_andx * For compatibility with windows servers, the search attributes * specified in the request are ignored. */ smb_sdrc_t smb_pre_open_andx(smb_request_t *sr) { struct open_param *op = &sr->arg.open; ! uint16_t openx_flags; uint32_t alloc_size; uint32_t creation_time; uint16_t file_attr, sattr; int rc; bzero(op, sizeof (sr->arg.open)); rc = smbsr_decode_vwv(sr, "b.wwwwwlwll4.", &sr->andx_com, ! &sr->andx_off, &openx_flags, &op->omode, &sattr, &file_attr, &creation_time, &op->ofun, &alloc_size, &op->timeo); if (rc == 0) { rc = smbsr_decode_data(sr, "%u", sr, &op->fqi.fq_path.pn_path); op->dattr = file_attr; op->dsize = alloc_size; ! /* ! * The openx_flags use some "extended" flags that ! * happen to match some of the NtCreateX flags. ! */ ! if (openx_flags & NT_CREATE_FLAG_REQUEST_OPBATCH) op->op_oplock_level = SMB_OPLOCK_BATCH; + else if (openx_flags & NT_CREATE_FLAG_REQUEST_OPLOCK) + op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE; else op->op_oplock_level = SMB_OPLOCK_NONE; + if (openx_flags & NT_CREATE_FLAG_EXTENDED_RESPONSE) + op->nt_flags |= NT_CREATE_FLAG_EXTENDED_RESPONSE; if ((creation_time != 0) && (creation_time != UINT_MAX)) op->crtime.tv_sec = smb_time_local_to_gmt(sr, creation_time); op->crtime.tv_nsec = 0; op->create_disposition = smb_ofun_to_crdisposition(op->ofun); } ! DTRACE_SMB_START(op__OpenX, smb_request_t *, sr); /* arg.open */ return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); } void smb_post_open_andx(smb_request_t *sr) { ! DTRACE_SMB_DONE(op__OpenX, smb_request_t *, sr); } smb_sdrc_t smb_com_open_andx(smb_request_t *sr) { struct open_param *op = &sr->arg.open; + smb_attr_t *ap = &op->fqi.fq_fattr; smb_ofile_t *of; uint32_t status; + uint32_t mtime_sec; uint16_t file_attr; int rc; op->desired_access = smb_omode_to_amask(op->omode); op->share_access = smb_denymode_to_sharemode(op->omode, op->fqi.fq_path.pn_path);
*** 391,402 **** op->create_options = FILE_NON_DIRECTORY_FILE; if (op->omode & SMB_DA_WRITE_THROUGH) op->create_options |= FILE_WRITE_THROUGH; - op->op_oplock_levelII = B_FALSE; - if (smb_open_dsize_check && op->dsize > UINT_MAX) { smbsr_error(sr, 0, ERRDOS, ERRbadaccess); return (SDRC_ERROR); } --- 400,409 ----
*** 403,473 **** status = smb_common_open(sr); if (status != NT_STATUS_SUCCESS) { smbsr_status(sr, status, 0, 0); return (SDRC_ERROR); } /* * NB: after the above smb_common_open() success, * we have a handle allocated (sr->fid_ofile). * If we don't return success, we must close it. */ of = sr->fid_ofile; if (op->op_oplock_level != SMB_OPLOCK_NONE) ! op->action_taken |= SMB_OACT_LOCK; else ! op->action_taken &= ~SMB_OACT_LOCK; file_attr = op->dattr & FILE_ATTRIBUTE_MASK; ! bzero(&attr, sizeof (attr)); switch (sr->tid_tree->t_res_type & STYPE_MASK) { case STYPE_DISKTREE: case STYPE_PRINTQ: - attr.sa_mask = SMB_AT_MTIME; - rc = smb_node_getattr(sr, of->f_node, of->f_cr, of, &attr); - if (rc != 0) { - smbsr_errno(sr, rc); - goto errout; - } - - rc = smbsr_encode_result(sr, 15, 0, - "bb.wwwllwwwwl2.w", - 15, - sr->andx_com, VAR_BCC, - sr->smb_fid, - file_attr, - smb_time_gmt_to_local(sr, attr.sa_vattr.va_mtime.tv_sec), - (uint32_t)op->dsize, - op->omode, op->ftype, - op->devstate, - op->action_taken, op->fileid, - 0); break; case STYPE_IPC: ! rc = smbsr_encode_result(sr, 15, 0, ! "bb.wwwllwwwwl2.w", ! 15, ! sr->andx_com, VAR_BCC, ! sr->smb_fid, ! file_attr, ! 0L, ! 0L, ! op->omode, op->ftype, ! op->devstate, ! op->action_taken, op->fileid, ! 0); break; default: smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST, ERRDOS, ERROR_INVALID_FUNCTION); goto errout; } if (rc == 0) return (SDRC_SUCCESS); errout: smb_ofile_close(of, 0); --- 410,500 ---- status = smb_common_open(sr); if (status != NT_STATUS_SUCCESS) { smbsr_status(sr, status, 0, 0); return (SDRC_ERROR); } + if (op->op_oplock_level != SMB_OPLOCK_NONE) { + /* Oplock req. in op->op_oplock_level etc. */ + smb1_oplock_acquire(sr, B_FALSE); + } /* * NB: after the above smb_common_open() success, * we have a handle allocated (sr->fid_ofile). * If we don't return success, we must close it. */ of = sr->fid_ofile; if (op->op_oplock_level != SMB_OPLOCK_NONE) ! op->action_taken |= SMB_OACT_OPLOCK; else ! op->action_taken &= ~SMB_OACT_OPLOCK; file_attr = op->dattr & FILE_ATTRIBUTE_MASK; ! mtime_sec = smb_time_gmt_to_local(sr, ap->sa_vattr.va_mtime.tv_sec); switch (sr->tid_tree->t_res_type & STYPE_MASK) { case STYPE_DISKTREE: case STYPE_PRINTQ: break; case STYPE_IPC: ! mtime_sec = 0; break; default: smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST, ERRDOS, ERROR_INVALID_FUNCTION); goto errout; } + if ((op->nt_flags & NT_CREATE_FLAG_EXTENDED_RESPONSE) != 0 && + smb_openx_enable_extended_response != 0) { + uint32_t MaxAccess = 0; + if (of->f_node != NULL) { + smb_fsop_eaccess(sr, of->f_cr, of->f_node, &MaxAccess); + } + MaxAccess |= of->f_granted_access; + + rc = smbsr_encode_result( + sr, 19, 0, "bb.wwwllwwwwl2.llw", + 19, /* word count (b) */ + sr->andx_com, /* (b.) */ + VAR_BCC, /* andx offset (w) */ + sr->smb_fid, /* (w) */ + file_attr, /* (w) */ + mtime_sec, /* (l) */ + (uint32_t)op->dsize, /* (l) */ + op->omode, /* (w) */ + op->ftype, /* (w) */ + op->devstate, /* (w) */ + op->action_taken, /* (w) */ + 0, /* legacy fileid (l) */ + /* reserved (2.) */ + MaxAccess, /* (l) */ + 0, /* guest access (l) */ + 0); /* byte count (w) */ + + } else { + rc = smbsr_encode_result( + sr, 15, 0, "bb.wwwllwwwwl2.w", + 15, /* word count (b) */ + sr->andx_com, /* (b.) */ + VAR_BCC, /* andx offset (w) */ + sr->smb_fid, /* (w) */ + file_attr, /* (w) */ + mtime_sec, /* (l) */ + (uint32_t)op->dsize, /* (l) */ + op->omode, /* (w) */ + op->ftype, /* (w) */ + op->devstate, /* (w) */ + op->action_taken, /* (w) */ + 0, /* legacy fileid (l) */ + /* reserved (2.) */ + 0); /* byte count (w) */ + } + if (rc == 0) return (SDRC_SUCCESS); errout: smb_ofile_close(of, 0);
*** 478,487 **** --- 505,515 ---- smb_com_trans2_open2(smb_request_t *sr, smb_xa_t *xa) { struct open_param *op = &sr->arg.open; uint32_t creation_time; uint32_t alloc_size; + uint32_t ea_list_size; uint16_t flags; uint16_t file_attr; uint32_t status; int rc;
*** 491,500 **** --- 519,546 ---- sr, &flags, &op->omode, &op->fqi.fq_sattr, &file_attr, &creation_time, &op->ofun, &alloc_size, &op->fqi.fq_path.pn_path); if (rc != 0) return (SDRC_ERROR); + /* + * The data part of this transaction may contain an EA list. + * See: SMB_FEA_LIST ExtendedAttributeList + * + * If we find a non-empty EA list payload, return the special + * error that tells the caller this FS does not suport EAs. + * + * Note: the first word is the size of the whole data segment, + * INCLUDING the size of that length word. That means if + * the length word specifies a size less than four, it's + * invalid (and probably a client trying something fishy). + */ + rc = smb_mbc_decodef(&xa->req_data_mb, "l", &ea_list_size); + if (rc == 0 && ea_list_size > 4) { + smbsr_status(sr, NT_STATUS_EAS_NOT_SUPPORTED, 0, 0); + return (SDRC_ERROR); + } + if ((creation_time != 0) && (creation_time != UINT_MAX)) op->crtime.tv_sec = smb_time_local_to_gmt(sr, creation_time); op->crtime.tv_nsec = 0; op->dattr = file_attr;
*** 518,539 **** else op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE; } else { op->op_oplock_level = SMB_OPLOCK_NONE; } - op->op_oplock_levelII = B_FALSE; status = smb_common_open(sr); if (status != NT_STATUS_SUCCESS) { smbsr_status(sr, status, 0, 0); return (SDRC_ERROR); } if (op->op_oplock_level != SMB_OPLOCK_NONE) ! op->action_taken |= SMB_OACT_LOCK; else ! op->action_taken &= ~SMB_OACT_LOCK; file_attr = op->dattr & FILE_ATTRIBUTE_MASK; if (STYPE_ISIPC(sr->tid_tree->t_res_type)) op->dsize = 0; --- 564,588 ---- else op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE; } else { op->op_oplock_level = SMB_OPLOCK_NONE; } status = smb_common_open(sr); if (status != NT_STATUS_SUCCESS) { smbsr_status(sr, status, 0, 0); return (SDRC_ERROR); } + if (op->op_oplock_level != SMB_OPLOCK_NONE) { + /* Oplock req. in op->op_oplock_level etc. */ + smb1_oplock_acquire(sr, B_FALSE); + } if (op->op_oplock_level != SMB_OPLOCK_NONE) ! op->action_taken |= SMB_OACT_OPLOCK; else ! op->action_taken &= ~SMB_OACT_OPLOCK; file_attr = op->dattr & FILE_ATTRIBUTE_MASK; if (STYPE_ISIPC(sr->tid_tree->t_res_type)) op->dsize = 0;