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-14982 smbtorture raw tests fail after NEX-4538
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
corrects:
 NEX-4538 SMB1 create file should support extended_response format
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-4909 SMB1: getting "RPC struct is bad" trying to mkdir on OS X
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
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>
SMB-115 Support SMB path names with length > 1024
SMB-100 Internal error if filename is too long
Approved by: Gordon Ross <gwr@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-63 taskq_create_proc ... TQ_DYNAMIC puts tasks in p0
re #11974 CIFS Share - Tree connect fails from Windows 7 Clients
SUS-172 Excel 2003 warning dialog when re-saving a file
SUS-173 Open fails if the client does not ask for read_attribute permission
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,28 ****
   *
   * CDDL HEADER END
   */
  /*
   * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
!  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
   */
  
  /*
   * This command is used to create or open a file or directory.
   */
--- 18,28 ----
   *
   * CDDL HEADER END
   */
  /*
   * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
!  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
   */
  
  /*
   * This command is used to create or open a file or directory.
   */
*** 30,39 ****
--- 30,41 ----
  
  #include <smbsrv/smb_kproto.h>
  #include <smbsrv/smb_fsops.h>
  #include <smbsrv/smb_vops.h>
  
+ int smb_nt_create_enable_extended_response = 1;
+ 
  /*
   * smb_com_nt_create_andx
   *
   * This command is used to create or open a file or directory.
   *
*** 208,244 ****
                          op->op_oplock_level = SMB_OPLOCK_BATCH;
                  else
                          op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
          }
  
!         DTRACE_SMB_2(op__NtCreateX__start, smb_request_t *, sr,
!             struct open_param *, op);
  
          return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
  }
  
  void
  smb_post_nt_create_andx(smb_request_t *sr)
  {
!         DTRACE_SMB_1(op__NtCreateX__done, smb_request_t *, sr);
  
          if (sr->arg.open.dir != NULL) {
                  smb_ofile_release(sr->arg.open.dir);
                  sr->arg.open.dir = NULL;
          }
  }
  
  smb_sdrc_t
  smb_com_nt_create_andx(struct smb_request *sr)
  {
          struct open_param       *op = &sr->arg.open;
          smb_attr_t              *ap = &op->fqi.fq_fattr;
          smb_ofile_t             *of;
          int                     rc;
!         unsigned char           DirFlag;
          uint32_t                status;
  
          if ((op->create_options & FILE_DELETE_ON_CLOSE) &&
              !(op->desired_access & DELETE)) {
                  smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
                      ERRDOS, ERRbadaccess);
                  return (SDRC_ERROR);
--- 210,260 ----
                          op->op_oplock_level = SMB_OPLOCK_BATCH;
                  else
                          op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
          }
  
!         DTRACE_SMB_START(op__NtCreateX, smb_request_t *, sr); /* arg.open */
  
          return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
  }
  
  void
  smb_post_nt_create_andx(smb_request_t *sr)
  {
!         DTRACE_SMB_DONE(op__NtCreateX, smb_request_t *, sr);
  
          if (sr->arg.open.dir != NULL) {
                  smb_ofile_release(sr->arg.open.dir);
                  sr->arg.open.dir = NULL;
          }
  }
  
+ /*
+  * A lot like smb_nt_transact_create
+  */
  smb_sdrc_t
  smb_com_nt_create_andx(struct smb_request *sr)
  {
          struct open_param       *op = &sr->arg.open;
          smb_attr_t              *ap = &op->fqi.fq_fattr;
          smb_ofile_t             *of;
          int                     rc;
!         uint8_t                 DirFlag;
          uint32_t                status;
  
+         if (op->create_options & ~SMB_NTCREATE_VALID_OPTIONS) {
+                 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
+                     ERRDOS, ERROR_INVALID_PARAMETER);
+                 return (SDRC_ERROR);
+         }
+ 
+         if (op->create_options & FILE_OPEN_BY_FILE_ID) {
+                 smbsr_error(sr, NT_STATUS_NOT_SUPPORTED,
+                     ERRDOS, ERROR_NOT_SUPPORTED);
+                 return (SDRC_ERROR);
+         }
+ 
          if ((op->create_options & FILE_DELETE_ON_CLOSE) &&
              !(op->desired_access & DELETE)) {
                  smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
                      ERRDOS, ERRbadaccess);
                  return (SDRC_ERROR);
*** 272,288 ****
                          return (SDRC_ERROR);
                  }
                  op->fqi.fq_dnode = op->dir->f_node;
          }
  
-         op->op_oplock_levelII = B_TRUE;
- 
          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.
--- 288,306 ----
                          return (SDRC_ERROR);
                  }
                  op->fqi.fq_dnode = op->dir->f_node;
          }
  
          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_TRUE);
+         }
  
          /*
           * 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.
*** 291,349 ****
  
          switch (sr->tid_tree->t_res_type & STYPE_MASK) {
          case STYPE_DISKTREE:
          case STYPE_PRINTQ:
                  if (op->create_options & FILE_DELETE_ON_CLOSE)
!                         smb_ofile_set_delete_on_close(of);
! 
                  DirFlag = smb_node_is_dir(of->f_node) ? 1 : 0;
-                 rc = smbsr_encode_result(sr, 34, 0, "bb.wbwlTTTTlqqwwbw",
-                     34,
-                     sr->andx_com,
-                     0x67,
-                     op->op_oplock_level,
-                     sr->smb_fid,
-                     op->action_taken,
-                     &ap->sa_crtime,
-                     &ap->sa_vattr.va_atime,
-                     &ap->sa_vattr.va_mtime,
-                     &ap->sa_vattr.va_ctime,
-                     op->dattr & FILE_ATTRIBUTE_MASK,
-                     ap->sa_allocsz,
-                     ap->sa_vattr.va_size,
-                     op->ftype,
-                     op->devstate,
-                     DirFlag,
-                     0);
                  break;
  
          case STYPE_IPC:
!                 rc = smbsr_encode_result(sr, 34, 0, "bb.wbwlqqqqlqqwwbw",
!                     34,
!                     sr->andx_com,
!                     0x67,
!                     0,
!                     sr->smb_fid,
!                     op->action_taken,
!                     0LL,
!                     0LL,
!                     0LL,
!                     0LL,
!                     FILE_ATTRIBUTE_NORMAL,
!                     0x1000LL,
!                     0LL,
!                     op->ftype,
!                     op->devstate,
!                     0,
!                     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);
--- 309,408 ----
  
          switch (sr->tid_tree->t_res_type & STYPE_MASK) {
          case STYPE_DISKTREE:
          case STYPE_PRINTQ:
                  if (op->create_options & FILE_DELETE_ON_CLOSE)
!                         smb_ofile_set_delete_on_close(sr, of);
                  DirFlag = smb_node_is_dir(of->f_node) ? 1 : 0;
                  break;
  
          case STYPE_IPC:
!                 DirFlag = 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_nt_create_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;
+ 
+                 /*
+                  * Here is a really ugly protocol wart in SMB1:
+                  *
+                  * [MS-SMB] Sec. 2.2.4.9.2: Windows-based SMB servers
+                  * send 50 (0x32) words in the extended response although
+                  * they set the WordCount field to 0x2A.
+                  *
+                  * In other words, THEY LIE!  We really do need to encode
+                  * 50 words here, but lie and say we encoded 42 words.
+                  * This means we can't use smbsr_encode_result() to
+                  * build this response, because the rules it breaks
+                  * would cause errors in smbsr_check_result().
+                  *
+                  * And that's not all (it gets worse...)
+                  * Because of the bogus word count, some clients will
+                  * read the byte count from within what should be the
+                  * fileid field below.  Leave that zero, like Win7.
+                  *
+                  * Apparently the only really useful thing in this
+                  * extended response is MaxAccess.
+                  */
+                 sr->smb_wct = 50; /* real word count */
+                 sr->smb_bcc = 0;
+                 rc = smb_mbc_encodef(&sr->reply,
+                     "bb.wbwlTTTTlqqwwb16.qllw",
+                     42,         /* fake word count (b) */
+                     sr->andx_com,               /* (b.) */
+                     0x87,       /* andx offset     (w) */
+                     op->op_oplock_level,        /* (b) */
+                     sr->smb_fid,                /* (w) */
+                     op->action_taken,           /* (l) */
+                     &ap->sa_crtime,             /* (T) */
+                     &ap->sa_vattr.va_atime,     /* (T) */
+                     &ap->sa_vattr.va_mtime,     /* (T) */
+                     &ap->sa_vattr.va_ctime,     /* (T) */
+                     op->dattr & FILE_ATTRIBUTE_MASK, /* (l) */
+                     ap->sa_allocsz,             /* (q) */
+                     ap->sa_vattr.va_size,       /* (q) */
+                     op->ftype,                  /* (w) */
+                     op->devstate,               /* (w) */
+                     DirFlag,                    /* (b) */
+                     /* volume guid                (16.) */
+                     0,  /* file ID (see above)     (q) */
+                     MaxAccess,                  /* (l) */
+                     0,          /* guest access    (l) */
+                     0);         /* byte count      (w) */
+         } else {
+                 rc = smbsr_encode_result(
+                     sr, 34, 0, "bb.wbwlTTTTlqqwwbw",
+                     34,         /* word count      (b) */
+                     sr->andx_com,               /* (b.) */
+                     0x67,       /* andx offset     (w) */
+                     op->op_oplock_level,        /* (b) */
+                     sr->smb_fid,                /* (w) */
+                     op->action_taken,           /* (l) */
+                     &ap->sa_crtime,             /* (T) */
+                     &ap->sa_vattr.va_atime,     /* (T) */
+                     &ap->sa_vattr.va_mtime,     /* (T) */
+                     &ap->sa_vattr.va_ctime,     /* (T) */
+                     op->dattr & FILE_ATTRIBUTE_MASK, /* (l) */
+                     ap->sa_allocsz,             /* (q) */
+                     ap->sa_vattr.va_size,       /* (q) */
+                     op->ftype,                  /* (w) */
+                     op->devstate,               /* (w) */
+                     DirFlag,                    /* (b) */
+                     0);         /* byte count      (w) */
+         }
+ 
          if (rc == 0)
                  return (SDRC_SUCCESS);
  
  errout:
          smb_ofile_close(of, 0);