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;