Print this page
NEX-19375 SMB2 durable handle create response missing timeout
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15578 SMB2 durable handle redesign
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@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-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15578 SMB2 durable handle redesign
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@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-5672 SMB2_create dtrace probe
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-3553 SMB2/3 durable handles
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-5586 SMB2 ofiles need real Persistent IDs
NEX-5313 SMB2 oplock break notification should use TID=0
Reviewed by: Gordon Ross <gwr@nexenta.com>
NEX-4836 WBC: export and destroy may hang due to faulty wrc migration termination
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
NEX-3733 Want SMB2 Apple extensions (allow disable)
NEX-3733 Want SMB2 Apple extensions
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@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>
NEX-1635 Codenomicon: SMB2 TC: 157974 Panic in smb2_create/smb_decode_sd
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-136 Snapshots not visible in Windows previous versions
SMB-138 memory leak in smb2_create
SMB-122 smbd core dumps in smbd_dc_update / smb_log
SMB-117 Win7 fails to open security properties
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)

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/smbsrv/smb2_create.c
          +++ new/usr/src/uts/common/fs/smbsrv/smb2_create.c
↓ open down ↓ 2 lines elided ↑ open up ↑
   3    3   * Common Development and Distribution License ("CDDL"), version 1.0.
   4    4   * You may only use this file in accordance with the terms of version
   5    5   * 1.0 of the CDDL.
   6    6   *
   7    7   * A full copy of the text of the CDDL should have accompanied this
   8    8   * source.  A copy of the CDDL is also available via the Internet at
   9    9   * http://www.illumos.org/license/CDDL.
  10   10   */
  11   11  
  12   12  /*
  13      - * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
       13 + * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  14   14   */
  15   15  
  16   16  /*
  17   17   * Dispatch function for SMB2_CREATE
  18   18   * [MS-SMB2] 2.2.13
  19   19   */
  20   20  
  21   21  #include <smbsrv/smb2_kproto.h>
  22   22  #include <smbsrv/smb_fsops.h>
  23   23  
       24 +#define DH_PERSISTENT   SMB2_DHANDLE_FLAG_PERSISTENT
       25 +
  24   26  /*
       27 + * Compile-time check that the SMB2_LEASE_... definitions
       28 + * match the (internal) equivalents from ntifs.h
       29 + */
       30 +#if SMB2_LEASE_NONE != OPLOCK_LEVEL_NONE
       31 +#error "SMB2_LEASE_NONE"
       32 +#endif
       33 +#if SMB2_LEASE_READ_CACHING != OPLOCK_LEVEL_CACHE_READ
       34 +#error "SMB2_LEASE_READ_CACHING"
       35 +#endif
       36 +#if SMB2_LEASE_HANDLE_CACHING != OPLOCK_LEVEL_CACHE_HANDLE
       37 +#error "SMB2_LEASE_HANDLE_CACHING"
       38 +#endif
       39 +#if SMB2_LEASE_WRITE_CACHING != OPLOCK_LEVEL_CACHE_WRITE
       40 +#error "SMB2_LEASE_WRITE_CACHING"
       41 +#endif
       42 +
       43 +/*
  25   44   * Some flags used locally to keep track of which Create Context
  26   45   * names have been provided and/or requested.
  27   46   */
  28   47  #define CCTX_EA_BUFFER                  1
  29   48  #define CCTX_SD_BUFFER                  2
  30   49  #define CCTX_DH_REQUEST                 4
  31   50  #define CCTX_DH_RECONNECT               8
  32   51  #define CCTX_ALLOCATION_SIZE            0x10
  33   52  #define CCTX_QUERY_MAX_ACCESS           0x20
  34   53  #define CCTX_TIMEWARP_TOKEN             0x40
  35   54  #define CCTX_QUERY_ON_DISK_ID           0x80
  36   55  #define CCTX_REQUEST_LEASE              0x100
       56 +#define CCTX_AAPL_EXT                   0x200
       57 +#define CCTX_DH_REQUEST_V2              0x400
       58 +#define CCTX_DH_RECONNECT_V2            0x800
  37   59  
  38      -
  39   60  typedef struct smb2_create_ctx_elem {
  40   61          uint32_t cce_len;
  41   62          mbuf_chain_t cce_mbc;
  42   63  } smb2_create_ctx_elem_t;
  43   64  
  44   65  typedef struct smb2_create_ctx {
       66 +        mbuf_chain_t cc_in_mbc;
  45   67          uint_t  cc_in_flags;    /* CCTX_... */
  46   68          uint_t  cc_out_flags;   /* CCTX_... */
  47   69          /* Elements we may see in the request. */
  48   70          smb2_create_ctx_elem_t cc_in_ext_attr;
  49   71          smb2_create_ctx_elem_t cc_in_sec_desc;
  50   72          smb2_create_ctx_elem_t cc_in_dh_request;
  51   73          smb2_create_ctx_elem_t cc_in_dh_reconnect;
  52   74          smb2_create_ctx_elem_t cc_in_alloc_size;
  53   75          smb2_create_ctx_elem_t cc_in_time_warp;
  54   76          smb2_create_ctx_elem_t cc_in_req_lease;
       77 +        smb2_create_ctx_elem_t cc_in_aapl;
       78 +        smb2_create_ctx_elem_t cc_in_dh_request_v2;
       79 +        smb2_create_ctx_elem_t cc_in_dh_reconnect_v2;
  55   80          /* Elements we my place in the response */
  56   81          smb2_create_ctx_elem_t cc_out_max_access;
  57   82          smb2_create_ctx_elem_t cc_out_file_id;
       83 +        smb2_create_ctx_elem_t cc_out_aapl;
       84 +        smb2_create_ctx_elem_t cc_out_req_lease;
       85 +        smb2_create_ctx_elem_t cc_out_dh_request;
       86 +        smb2_create_ctx_elem_t cc_out_dh_request_v2;
  58   87  } smb2_create_ctx_t;
  59   88  
  60   89  static uint32_t smb2_decode_create_ctx(
  61      -        mbuf_chain_t *, smb2_create_ctx_t *);
       90 +        smb_request_t *, smb2_create_ctx_t *);
  62   91  static uint32_t smb2_encode_create_ctx(
  63      -        mbuf_chain_t *, smb2_create_ctx_t *);
       92 +        smb_request_t *, smb2_create_ctx_t *);
  64   93  static int smb2_encode_create_ctx_elem(
  65   94          mbuf_chain_t *, smb2_create_ctx_elem_t *, uint32_t);
  66   95  static void smb2_free_create_ctx(smb2_create_ctx_t *);
  67   96  
       97 +int smb2_enable_dh = 1;
       98 +
  68   99  smb_sdrc_t
  69  100  smb2_create(smb_request_t *sr)
  70  101  {
  71  102          smb_attr_t *attr;
  72  103          smb2_create_ctx_elem_t *cce;
  73  104          smb2_create_ctx_t cctx;
  74      -        mbuf_chain_t cc_mbc;
  75  105          smb_arg_open_t *op = &sr->arg.open;
  76  106          smb_ofile_t *of = NULL;
  77  107          uint16_t StructSize;
  78  108          uint8_t SecurityFlags;
  79      -        uint8_t OplockLevel;
  80  109          uint32_t ImpersonationLevel;
  81  110          uint64_t SmbCreateFlags;
  82  111          uint64_t Reserved4;
  83  112          uint16_t NameOffset;
  84  113          uint16_t NameLength;
  85  114          uint32_t CreateCtxOffset;
  86  115          uint32_t CreateCtxLength;
  87      -        smb2fid_t smb2fid;
      116 +        smb2fid_t smb2fid = { 0, 0 };
  88  117          uint32_t status;
      118 +        int dh_flags;
  89  119          int skip;
  90  120          int rc = 0;
  91  121  
  92  122          bzero(&cctx, sizeof (cctx));
  93      -        bzero(&cc_mbc, sizeof (cc_mbc));
      123 +        op->create_ctx = &cctx; /* for debugging */
  94  124  
  95  125          /*
  96  126           * Paranoia.  This will set sr->fid_ofile, so
  97  127           * if we already have one, release it now.
  98  128           */
  99  129          if (sr->fid_ofile != NULL) {
 100      -                smb_ofile_request_complete(sr->fid_ofile);
 101  130                  smb_ofile_release(sr->fid_ofile);
 102  131                  sr->fid_ofile = NULL;
 103  132          }
 104  133  
 105  134          /*
 106      -         * SMB2 Create request
      135 +         * Decode the SMB2 Create request
      136 +         *
      137 +         * Most decode errors return SDRC_ERROR, but
      138 +         * for some we give a more specific error.
      139 +         *
      140 +         * In the "decode section" (starts here) any
      141 +         * errors should either return SDRC_ERROR, or
      142 +         * if any cleanup is needed, goto errout.
 107  143           */
 108  144          rc = smb_mbc_decodef(
 109  145              &sr->smb_data, "wbblqqlllllwwll",
 110  146              &StructSize,                /* w */
 111  147              &SecurityFlags,             /* b */
 112      -            &OplockLevel,               /* b */
      148 +            &op->op_oplock_level,       /* b */
 113  149              &ImpersonationLevel,        /* l */
 114  150              &SmbCreateFlags,            /* q */
 115  151              &Reserved4,                 /* q */
 116  152              &op->desired_access,        /* l */
 117  153              &op->dattr,                 /* l */
 118  154              &op->share_access,          /* l */
 119  155              &op->create_disposition,    /* l */
 120  156              &op->create_options,        /* l */
 121  157              &NameOffset,                /* w */
 122  158              &NameLength,                /* w */
↓ open down ↓ 1 lines elided ↑ open up ↑
 124  160              &CreateCtxLength);          /* l */
 125  161          if (rc != 0 || StructSize != 57)
 126  162                  return (SDRC_ERROR);
 127  163  
 128  164          /*
 129  165           * We're normally positioned at the path name now,
 130  166           * but there could be some padding before it.
 131  167           */
 132  168          skip = (NameOffset + sr->smb2_cmd_hdr) -
 133  169              sr->smb_data.chain_offset;
 134      -        if (skip < 0) {
 135      -                status = NT_STATUS_OBJECT_PATH_INVALID;
 136      -                goto errout;
 137      -        }
      170 +        if (skip < 0)
      171 +                return (SDRC_ERROR);
 138  172          if (skip > 0)
 139  173                  (void) smb_mbc_decodef(&sr->smb_data, "#.", skip);
 140  174  
 141  175          /*
 142  176           * Get the path name
      177 +         *
      178 +         * Name too long is not technically a decode error,
      179 +         * but it's very rare, so we'll just skip the
      180 +         * dtrace probes for this error case.
 143  181           */
 144  182          if (NameLength >= SMB_MAXPATHLEN) {
 145  183                  status = NT_STATUS_OBJECT_PATH_INVALID;
 146  184                  goto errout;
 147  185          }
 148  186          if (NameLength == 0) {
 149  187                  op->fqi.fq_path.pn_path = "\\";
 150  188          } else {
 151  189                  rc = smb_mbc_decodef(&sr->smb_data, "%#U", sr,
 152  190                      NameLength, &op->fqi.fq_path.pn_path);
 153  191                  if (rc) {
 154  192                          status = NT_STATUS_OBJECT_PATH_INVALID;
 155  193                          goto errout;
 156  194                  }
 157  195          }
 158  196          op->fqi.fq_dnode = sr->tid_tree->t_snode;
 159  197  
 160      -        switch (OplockLevel) {
 161      -        case SMB2_OPLOCK_LEVEL_NONE:
 162      -                op->op_oplock_level = SMB_OPLOCK_NONE;
 163      -                break;
 164      -        case SMB2_OPLOCK_LEVEL_II:
 165      -                op->op_oplock_level = SMB_OPLOCK_LEVEL_II;
 166      -                break;
 167      -        case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
 168      -                op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
 169      -                break;
 170      -        case SMB2_OPLOCK_LEVEL_BATCH:
 171      -                op->op_oplock_level = SMB_OPLOCK_BATCH;
 172      -                break;
 173      -        case SMB2_OPLOCK_LEVEL_LEASE:
 174      -                status = NT_STATUS_INVALID_PARAMETER;
 175      -                goto errout;
 176      -        }
 177      -        op->op_oplock_levelII = B_TRUE;
 178      -
 179  198          /*
 180      -         * ImpersonationLevel (spec. says ignore)
 181      -         * SmbCreateFlags (spec. says ignore)
 182      -         */
 183      -
 184      -        if ((op->create_options & FILE_DELETE_ON_CLOSE) &&
 185      -            !(op->desired_access & DELETE)) {
 186      -                status = NT_STATUS_INVALID_PARAMETER;
 187      -                goto errout;
 188      -        }
 189      -        if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) {
 190      -                status = NT_STATUS_INVALID_PARAMETER;
 191      -                goto errout;
 192      -        }
 193      -
 194      -        if (op->dattr & FILE_FLAG_WRITE_THROUGH)
 195      -                op->create_options |= FILE_WRITE_THROUGH;
 196      -        if (op->dattr & FILE_FLAG_DELETE_ON_CLOSE)
 197      -                op->create_options |= FILE_DELETE_ON_CLOSE;
 198      -        if (op->dattr & FILE_FLAG_BACKUP_SEMANTICS)
 199      -                op->create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
 200      -        if (op->create_options & FILE_OPEN_FOR_BACKUP_INTENT)
 201      -                sr->user_cr = smb_user_getprivcred(sr->uid_user);
 202      -
 203      -        /*
 204  199           * If there is a "Create Context" payload, decode it.
 205  200           * This may carry things like a security descriptor,
 206  201           * extended attributes, etc. to be used in create.
 207  202           *
 208  203           * The create ctx buffer must start after the headers
 209  204           * and file name, and must be 8-byte aligned.
 210  205           */
 211  206          if (CreateCtxLength != 0) {
 212  207                  if ((CreateCtxOffset & 7) != 0 ||
 213  208                      (CreateCtxOffset + sr->smb2_cmd_hdr) <
 214  209                      sr->smb_data.chain_offset) {
 215  210                          status = NT_STATUS_INVALID_PARAMETER;
 216  211                          goto errout;
 217  212                  }
 218  213  
 219      -                rc = MBC_SHADOW_CHAIN(&cc_mbc, &sr->smb_data,
      214 +                rc = MBC_SHADOW_CHAIN(&cctx.cc_in_mbc, &sr->smb_data,
 220  215                      sr->smb2_cmd_hdr + CreateCtxOffset, CreateCtxLength);
 221  216                  if (rc) {
 222  217                          status = NT_STATUS_INVALID_PARAMETER;
 223  218                          goto errout;
 224  219                  }
 225      -                status = smb2_decode_create_ctx(&cc_mbc, &cctx);
      220 +                status = smb2_decode_create_ctx(sr, &cctx);
 226  221                  if (status)
 227  222                          goto errout;
      223 +        }
 228  224  
 229      -                if (cctx.cc_in_flags & CCTX_EA_BUFFER) {
 230      -                        status = NT_STATUS_EAS_NOT_SUPPORTED;
 231      -                        goto errout;
 232      -                }
      225 +        /*
      226 +         * Everything is decoded into some internal form, so
      227 +         * in this probe one can look at sr->arg.open etc.
      228 +         *
      229 +         * This marks the end of the "decode" section and the
      230 +         * beginning of the "body" section.  Any errors in
      231 +         * this section should use: goto cmd_done (which is
      232 +         * just before the dtrace "done" probe).
      233 +         */
      234 +        DTRACE_SMB2_START(op__Create, smb_request_t *, sr); /* arg.open */
 233  235  
 234      -                if (cctx.cc_in_flags & CCTX_SD_BUFFER) {
 235      -                        smb_sd_t sd;
 236      -                        cce = &cctx.cc_in_sec_desc;
 237      -                        status = smb_decode_sd(
 238      -                            &cce->cce_mbc, &sd);
 239      -                        if (status)
 240      -                                goto errout;
 241      -                        op->sd = kmem_alloc(sizeof (sd), KM_SLEEP);
 242      -                        *op->sd = sd;
 243      -                }
      236 +        /*
      237 +         * Process the incoming create contexts (already decoded),
      238 +         * that need action before the open, starting with the
      239 +         * Durable Handle ones, which may override others.
      240 +         */
 244  241  
 245      -                if (cctx.cc_in_flags & CCTX_ALLOCATION_SIZE) {
 246      -                        cce = &cctx.cc_in_alloc_size;
 247      -                        rc = smb_mbc_decodef(&cce->cce_mbc, "q", &op->dsize);
 248      -                        if (rc) {
 249      -                                status = NT_STATUS_INVALID_PARAMETER;
 250      -                                goto errout;
      242 +        /*
      243 +         * Only disk trees get durable handles.
      244 +         */
      245 +        if (smb2_enable_dh == 0 ||
      246 +            (sr->tid_tree->t_res_type & STYPE_MASK) != STYPE_DISKTREE) {
      247 +                cctx.cc_in_flags &=
      248 +                    ~(CCTX_DH_REQUEST | CCTX_DH_REQUEST_V2 |
      249 +                    CCTX_DH_RECONNECT | CCTX_DH_RECONNECT_V2);
      250 +        }
      251 +
      252 +        /*
      253 +         * DH v2 is only valid in SMB3.0 and later.
      254 +         * If seen in earlier dialects, ignore.
      255 +         */
      256 +        if (sr->session->dialect < SMB_VERS_3_0) {
      257 +                cctx.cc_in_flags &=
      258 +                    ~(CCTX_DH_REQUEST_V2|CCTX_DH_RECONNECT_V2);
      259 +        }
      260 +
      261 +        /*
      262 +         * It is an error to specify more than one Durable Handle
      263 +         * operation in a single create, except when only the v1
      264 +         * REQUEST and RECONNECT operations are specified. In that
      265 +         * case, the v1 REQUEST is ignored.
      266 +         */
      267 +        dh_flags = cctx.cc_in_flags &
      268 +            (CCTX_DH_REQUEST | CCTX_DH_REQUEST_V2 |
      269 +            CCTX_DH_RECONNECT | CCTX_DH_RECONNECT_V2);
      270 +        if ((dh_flags & (dh_flags - 1)) != 0 &&
      271 +            dh_flags != (CCTX_DH_REQUEST|CCTX_DH_RECONNECT)) {
      272 +                status = NT_STATUS_INVALID_PARAMETER;
      273 +                goto cmd_done;
      274 +        }
      275 +
      276 +        /*
      277 +         * Reconnect is special in MANY ways, including the
      278 +         * somewhat surprising (specified) behavior that
      279 +         * most other creat parameters are ignored, and
      280 +         * many create context types are ignored too.
      281 +         */
      282 +        op->dh_vers = SMB2_NOT_DURABLE;
      283 +        if ((cctx.cc_in_flags &
      284 +            (CCTX_DH_RECONNECT|CCTX_DH_RECONNECT_V2)) != 0) {
      285 +
      286 +                if ((cctx.cc_in_flags & CCTX_DH_RECONNECT_V2) != 0)
      287 +                        op->dh_vers = SMB2_DURABLE_V2;
      288 +                else
      289 +                        op->dh_vers = SMB2_DURABLE_V1;
      290 +
      291 +                /* Ignore these create contexts. */
      292 +                cctx.cc_in_flags &=
      293 +                    ~(CCTX_DH_REQUEST |
      294 +                    CCTX_DH_REQUEST_V2 |
      295 +                    CCTX_EA_BUFFER |
      296 +                    CCTX_SD_BUFFER |
      297 +                    CCTX_ALLOCATION_SIZE |
      298 +                    CCTX_TIMEWARP_TOKEN |
      299 +                    CCTX_QUERY_ON_DISK_ID);
      300 +
      301 +                /*
      302 +                 * Reconnect check needs to know if a lease was requested.
      303 +                 * The requested oplock level is ignored in reconnect, so
      304 +                 * using op_oplock_level to convey this info.
      305 +                 */
      306 +                if (cctx.cc_in_flags & CCTX_REQUEST_LEASE)
      307 +                        op->op_oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
      308 +                else
      309 +                        op->op_oplock_level = 0;
      310 +
      311 +                status = smb2_dh_reconnect(sr);
      312 +                if (status != NT_STATUS_SUCCESS)
      313 +                        goto cmd_done;
      314 +
      315 +                /*
      316 +                 * Skip most open execution during reconnect,
      317 +                 * but need (reclaimed) oplock state in *op.
      318 +                 */
      319 +                of = sr->fid_ofile;
      320 +
      321 +                op->op_oplock_state = of->f_oplock.og_state;
      322 +                if (of->f_lease != NULL) {
      323 +                        smb_lease_t *ls = of->f_lease;
      324 +
      325 +                        op->op_oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
      326 +                        op->lease_state = ls->ls_state &
      327 +                            OPLOCK_LEVEL_CACHE_MASK;
      328 +                        op->lease_flags = (ls->ls_breaking != 0) ?
      329 +                            SMB2_LEASE_FLAG_BREAK_IN_PROGRESS : 0;
      330 +                        op->lease_epoch = ls->ls_epoch;
      331 +                        op->lease_version = ls->ls_version;
      332 +                } else {
      333 +                        switch (op->op_oplock_state & OPLOCK_LEVEL_TYPE_MASK) {
      334 +                        default:
      335 +                        case OPLOCK_LEVEL_NONE:
      336 +                                op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
      337 +                                break;
      338 +                        case OPLOCK_LEVEL_TWO:
      339 +                                op->op_oplock_level = SMB2_OPLOCK_LEVEL_II;
      340 +                                break;
      341 +                        case OPLOCK_LEVEL_ONE:
      342 +                                op->op_oplock_level =
      343 +                                    SMB2_OPLOCK_LEVEL_EXCLUSIVE;
      344 +                                break;
      345 +                        case OPLOCK_LEVEL_BATCH:
      346 +                                op->op_oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
      347 +                                break;
 251  348                          }
 252  349                  }
 253  350  
      351 +                goto reconnect_done;
      352 +        }
      353 +
      354 +        /*
      355 +         * Real create (of a new handle, not reconnect)
      356 +         */
      357 +
      358 +        /*
      359 +         * Validate the requested oplock level.
      360 +         * Conversion to internal form is in smb2_oplock_acquire()
      361 +         */
      362 +        switch (op->op_oplock_level) {
      363 +        case SMB2_OPLOCK_LEVEL_NONE:            /* OPLOCK_LEVEL_NONE */
      364 +        case SMB2_OPLOCK_LEVEL_II:              /* OPLOCK_LEVEL_TWO */
      365 +        case SMB2_OPLOCK_LEVEL_EXCLUSIVE:       /* OPLOCK_LEVEL_ONE */
      366 +        case SMB2_OPLOCK_LEVEL_BATCH:           /* OPLOCK_LEVEL_BATCH */
 254  367                  /*
 255      -                 * Support for opening "Previous Versions".
 256      -                 * [MS-SMB2] 2.2.13.2.7  Data is an NT time.
      368 +                 * Ignore lease create context (if any)
 257  369                   */
 258      -                if (cctx.cc_in_flags & CCTX_TIMEWARP_TOKEN) {
 259      -                        uint64_t timewarp;
 260      -                        cce = &cctx.cc_in_time_warp;
 261      -                        status = smb_mbc_decodef(&cce->cce_mbc,
 262      -                            "q", &timewarp);
 263      -                        if (status)
 264      -                                goto errout;
 265      -                        smb_time_nt_to_unix(timewarp, &op->timewarp);
 266      -                        op->create_timewarp = B_TRUE;
      370 +                cctx.cc_in_flags &= ~CCTX_REQUEST_LEASE;
      371 +                break;
      372 +
      373 +        case SMB2_OPLOCK_LEVEL_LEASE:           /* OPLOCK_LEVEL_GRANULAR */
      374 +                /*
      375 +                 * Require a lease create context.
      376 +                 */
      377 +                if ((cctx.cc_in_flags & CCTX_REQUEST_LEASE) == 0) {
      378 +                        cmn_err(CE_NOTE, "smb2:create, oplock=ff and no lease");
      379 +                        status = NT_STATUS_INVALID_PARAMETER;
      380 +                        goto cmd_done;
 267  381                  }
      382 +
      383 +                /*
      384 +                 * Validate lease request state
      385 +                 * Only a few valid combinations.
      386 +                 */
      387 +                switch (op->lease_state) {
      388 +                case SMB2_LEASE_NONE:
      389 +                case SMB2_LEASE_READ_CACHING:
      390 +                case SMB2_LEASE_READ_CACHING | SMB2_LEASE_HANDLE_CACHING:
      391 +                case SMB2_LEASE_READ_CACHING | SMB2_LEASE_WRITE_CACHING:
      392 +                case SMB2_LEASE_READ_CACHING | SMB2_LEASE_WRITE_CACHING |
      393 +                    SMB2_LEASE_HANDLE_CACHING:
      394 +                        break;
      395 +
      396 +                default:
      397 +                        /*
      398 +                         * Invalid lease state flags
      399 +                         * Just force to "none".
      400 +                         */
      401 +                        op->lease_state = SMB2_LEASE_NONE;
      402 +                        break;
      403 +                }
      404 +                break;
      405 +
      406 +        default:
      407 +                /* Unknown SMB2 oplock level. */
      408 +                status = NT_STATUS_INVALID_PARAMETER;
      409 +                goto cmd_done;
 268  410          }
 269  411  
 270  412          /*
      413 +         * Only disk trees get oplocks or leases.
      414 +         */
      415 +        if ((sr->tid_tree->t_res_type & STYPE_MASK) != STYPE_DISKTREE) {
      416 +                op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
      417 +                cctx.cc_in_flags &= ~CCTX_REQUEST_LEASE;
      418 +        }
      419 +
      420 +        if ((sr->tid_tree->t_flags & SMB_TREE_CA) == 0)
      421 +                op->dh_v2_flags &= ~DH_PERSISTENT;
      422 +
      423 +        if ((cctx.cc_in_flags &
      424 +            (CCTX_DH_REQUEST|CCTX_DH_REQUEST_V2)) != 0) {
      425 +                if ((cctx.cc_in_flags & CCTX_DH_REQUEST_V2) != 0)
      426 +                        op->dh_vers = SMB2_DURABLE_V2;
      427 +                else
      428 +                        op->dh_vers = SMB2_DURABLE_V1;
      429 +        }
      430 +
      431 +        if (cctx.cc_in_flags & CCTX_EA_BUFFER) {
      432 +                status = NT_STATUS_EAS_NOT_SUPPORTED;
      433 +                goto cmd_done;
      434 +        }
      435 +
      436 +        /*
      437 +         * ImpersonationLevel (spec. says validate + ignore)
      438 +         * SmbCreateFlags (spec. says ignore)
      439 +         */
      440 +
      441 +        if ((op->create_options & FILE_DELETE_ON_CLOSE) &&
      442 +            !(op->desired_access & DELETE)) {
      443 +                status = NT_STATUS_INVALID_PARAMETER;
      444 +                goto cmd_done;
      445 +        }
      446 +
      447 +        if (op->dattr & FILE_FLAG_WRITE_THROUGH)
      448 +                op->create_options |= FILE_WRITE_THROUGH;
      449 +        if (op->dattr & FILE_FLAG_DELETE_ON_CLOSE)
      450 +                op->create_options |= FILE_DELETE_ON_CLOSE;
      451 +        if (op->dattr & FILE_FLAG_BACKUP_SEMANTICS)
      452 +                op->create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
      453 +        if (op->create_options & FILE_OPEN_FOR_BACKUP_INTENT)
      454 +                sr->user_cr = smb_user_getprivcred(sr->uid_user);
      455 +        if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) {
      456 +                status = NT_STATUS_INVALID_PARAMETER;
      457 +                goto cmd_done;
      458 +        }
      459 +
      460 +        /*
 271  461           * The real open call.   Note: this gets attributes into
 272  462           * op->fqi.fq_fattr (SMB_AT_ALL).  We need those below.
      463 +         * When of != NULL, goto errout closes it.
 273  464           */
 274  465          status = smb_common_open(sr);
 275  466          if (status != NT_STATUS_SUCCESS)
 276      -                goto errout;
 277      -        attr = &op->fqi.fq_fattr;
      467 +                goto cmd_done;
      468 +        of = sr->fid_ofile;
 278  469  
 279  470          /*
 280      -         * Convert the negotiate Oplock level back into
 281      -         * SMB2 encoding form.
      471 +         * Set the "persistent" part of the file ID
      472 +         * (only for DISK shares).  Need this even for
      473 +         * non-durable handles in case we get the ioctl
      474 +         * to set "resiliency" on this handle.
 282  475           */
 283      -        switch (op->op_oplock_level) {
 284      -        default:
 285      -        case SMB_OPLOCK_NONE:
 286      -                OplockLevel = SMB2_OPLOCK_LEVEL_NONE;
 287      -                break;
 288      -        case SMB_OPLOCK_LEVEL_II:
 289      -                OplockLevel = SMB2_OPLOCK_LEVEL_II;
 290      -                break;
 291      -        case SMB_OPLOCK_EXCLUSIVE:
 292      -                OplockLevel = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
 293      -                break;
 294      -        case SMB_OPLOCK_BATCH:
 295      -                OplockLevel = SMB2_OPLOCK_LEVEL_BATCH;
 296      -                break;
      476 +        if (of->f_ftype == SMB_FTYPE_DISK) {
      477 +                if ((op->dh_v2_flags & DH_PERSISTENT) != 0)
      478 +                        smb_ofile_set_persistid_ph(of);
      479 +                else
      480 +                        smb_ofile_set_persistid_dh(of);
 297  481          }
 298  482  
 299  483          /*
      484 +         * [MS-SMB2] 3.3.5.9.8
      485 +         * Handling the SMB2_CREATE_REQUEST_LEASE Create Context
      486 +         */
      487 +        if ((cctx.cc_in_flags & CCTX_REQUEST_LEASE) != 0) {
      488 +                status = smb2_lease_create(sr, sr->session->clnt_uuid);
      489 +                if (status != NT_STATUS_SUCCESS) {
      490 +                        if (op->action_taken == SMB_OACT_CREATED) {
      491 +                                smb_ofile_set_delete_on_close(sr, of);
      492 +                        }
      493 +                        goto cmd_done;
      494 +                }
      495 +        }
      496 +        if (op->op_oplock_level == SMB2_OPLOCK_LEVEL_LEASE) {
      497 +                smb2_lease_acquire(sr);
      498 +        } else if (op->op_oplock_level != SMB2_OPLOCK_LEVEL_NONE) {
      499 +                smb2_oplock_acquire(sr);
      500 +        }
      501 +
      502 +        /*
      503 +         * Make this a durable open, but only if:
      504 +         * (durable handle requested and...)
      505 +         *
      506 +         * 1. op_oplock_level == SMB2_OPLOCK_LEVEL_BATCH
      507 +         * 2. A lease is requested with handle caching
      508 +         *    - for v1, the lease must not be on a directory
      509 +         * 3. For v2, flags has "persistent" && tree->is_CA
      510 +         *    (when tree not CA, turned off persist above)
      511 +         *
      512 +         * Otherwise, DH requests are ignored, so we set
      513 +         * dh_vers = not durable
      514 +         */
      515 +        if ((cctx.cc_in_flags &
      516 +            (CCTX_DH_REQUEST|CCTX_DH_REQUEST_V2)) != 0 &&
      517 +            smb_node_is_file(of->f_node) &&
      518 +            ((op->dh_v2_flags & DH_PERSISTENT) != 0 ||
      519 +            (op->op_oplock_level == SMB2_OPLOCK_LEVEL_BATCH) ||
      520 +            (op->op_oplock_level == SMB2_OPLOCK_LEVEL_LEASE &&
      521 +            (op->lease_state & OPLOCK_LEVEL_CACHE_HANDLE) != 0))) {
      522 +                /*
      523 +                 * OK, make this handle "durable"
      524 +                 */
      525 +                if (op->dh_vers == SMB2_DURABLE_V2) {
      526 +                        (void) memcpy(of->dh_create_guid,
      527 +                            op->create_guid, UUID_LEN);
      528 +
      529 +                        if ((op->dh_v2_flags & DH_PERSISTENT) != 0) {
      530 +                                if (smb2_dh_make_persistent(sr, of) == 0) {
      531 +                                        of->dh_persist = B_TRUE;
      532 +                                } else {
      533 +                                        op->dh_v2_flags = 0;
      534 +                                }
      535 +                        }
      536 +                }
      537 +                if (op->dh_vers != SMB2_NOT_DURABLE) {
      538 +                        uint32_t msto;
      539 +
      540 +                        of->dh_vers = op->dh_vers;
      541 +                        of->dh_expire_time = 0;
      542 +
      543 +                        /*
      544 +                         * Client may provide timeout=0 to request
      545 +                         * the default timeout (in mSec.)
      546 +                         */
      547 +                        msto = op->dh_timeout;
      548 +                        if (msto == 0) {
      549 +                                msto = (of->dh_persist) ?
      550 +                                    smb2_persist_timeout :
      551 +                                    smb2_dh_def_timeout;
      552 +                        }
      553 +                        if (msto > smb2_dh_max_timeout)
      554 +                                msto = smb2_dh_max_timeout;
      555 +                        op->dh_timeout = msto;
      556 +                        of->dh_timeout_offset = MSEC2NSEC(msto);
      557 +                }
      558 +        } else {
      559 +                op->dh_vers = SMB2_NOT_DURABLE;
      560 +                op->dh_v2_flags = 0;
      561 +        }
      562 +
      563 +        /*
 300  564           * NB: after the above smb_common_open() success,
 301  565           * we have a handle allocated (sr->fid_ofile).
 302  566           * If we don't return success, we must close it.
 303  567           *
 304  568           * Using sr->smb_fid as the file handle for now,
 305  569           * though it could later be something larger,
 306  570           * (16 bytes) similar to an NFSv4 open handle.
 307  571           */
 308      -        of = sr->fid_ofile;
 309      -        smb2fid.persistent = 0;
      572 +reconnect_done:
      573 +        smb2fid.persistent = of->f_persistid;
 310  574          smb2fid.temporal = sr->smb_fid;
 311  575  
 312  576          switch (sr->tid_tree->t_res_type & STYPE_MASK) {
 313  577          case STYPE_DISKTREE:
 314  578          case STYPE_PRINTQ:
 315  579                  if (op->create_options & FILE_DELETE_ON_CLOSE)
 316      -                        smb_ofile_set_delete_on_close(of);
      580 +                        smb_ofile_set_delete_on_close(sr, of);
 317  581                  break;
 318  582          }
 319  583  
 320  584          /*
 321      -         * Build the Create Context to return; first the
 322      -         * per-element parts, then the aggregated buffer.
 323      -         *
 324      -         * No response for these:
 325      -         *      CCTX_EA_BUFFER
 326      -         *      CCTX_SD_BUFFER
 327      -         *      CCTX_ALLOCATION_SIZE
 328      -         *      CCTX_TIMEWARP_TOKEN
 329      -         *
 330      -         * We don't handle these yet.
 331      -         *      CCTX_DH_REQUEST
 332      -         *      CCTX_DH_RECONNECT
 333      -         *      CCTX_REQUEST_LEASE
      585 +         * Process any outgoing create contexts that need work
      586 +         * after the open succeeds.  Encode happens later.
 334  587           */
 335  588          if (cctx.cc_in_flags & CCTX_QUERY_MAX_ACCESS) {
 336      -                cce = &cctx.cc_out_max_access;
 337      -                uint32_t MaxAccess = 0;
      589 +                op->maximum_access = 0;
 338  590                  if (of->f_node != NULL) {
 339      -                        smb_fsop_eaccess(sr, of->f_cr, of->f_node, &MaxAccess);
      591 +                        smb_fsop_eaccess(sr, of->f_cr, of->f_node,
      592 +                            &op->maximum_access);
 340  593                  }
 341      -                MaxAccess |= of->f_granted_access;
 342      -                cce->cce_len = 8;
 343      -                cce->cce_mbc.max_bytes = 8;
 344      -                (void) smb_mbc_encodef(&cce->cce_mbc,
 345      -                    "ll", 0, MaxAccess);
      594 +                op->maximum_access |= of->f_granted_access;
 346  595                  cctx.cc_out_flags |= CCTX_QUERY_MAX_ACCESS;
 347  596          }
      597 +
 348  598          if ((cctx.cc_in_flags & CCTX_QUERY_ON_DISK_ID) != 0 &&
 349  599              of->f_node != NULL) {
 350      -                cce = &cctx.cc_out_file_id;
 351      -                fsid_t fsid;
      600 +                op->op_fsid = SMB_NODE_FSID(of->f_node);
      601 +                cctx.cc_out_flags |= CCTX_QUERY_ON_DISK_ID;
      602 +        }
 352  603  
 353      -                fsid = SMB_NODE_FSID(of->f_node);
      604 +        if ((cctx.cc_in_flags & CCTX_AAPL_EXT) != 0) {
      605 +                cce = &cctx.cc_out_aapl;
      606 +                /*
      607 +                 * smb2_aapl_crctx has a variable response depending on
      608 +                 * what the incoming context looks like, so it does all
      609 +                 * the work of building cc_out_aapl, including setting
      610 +                 * cce_len, cce_mbc.max_bytes, and smb_mbc_encode.
      611 +                 * If we see errors getting this, simply omit it from
      612 +                 * the collection of returned create contexts.
      613 +                 */
      614 +                status = smb2_aapl_crctx(sr,
      615 +                    &cctx.cc_in_aapl.cce_mbc, &cce->cce_mbc);
      616 +                if (status == 0) {
      617 +                        cce->cce_len = cce->cce_mbc.chain_offset;
      618 +                        cctx.cc_out_flags |= CCTX_AAPL_EXT;
      619 +                }
      620 +                status = 0;
      621 +        }
 354  622  
 355      -                cce->cce_len = 32;
 356      -                cce->cce_mbc.max_bytes = 32;
 357      -                (void) smb_mbc_encodef(
 358      -                    &cce->cce_mbc, "qll.15.",
 359      -                    op->fileid,         /* q */
 360      -                    fsid.val[0],        /* l */
 361      -                    fsid.val[1]);       /* l */
 362      -                /* reserved (16 bytes)  .15. */
 363      -                cctx.cc_out_flags |= CCTX_QUERY_ON_DISK_ID;
      623 +        /*
      624 +         * If a lease was requested, and we got one...
      625 +         */
      626 +        if ((cctx.cc_in_flags & CCTX_REQUEST_LEASE) != 0 &&
      627 +            op->op_oplock_level == SMB2_OPLOCK_LEVEL_LEASE)
      628 +                cctx.cc_out_flags |= CCTX_REQUEST_LEASE;
      629 +
      630 +        /*
      631 +         * If a durable handle was requested and we got one...
      632 +         */
      633 +        if ((cctx.cc_in_flags & CCTX_DH_REQUEST) != 0 &&
      634 +            of->dh_vers == SMB2_DURABLE_V1) {
      635 +                cctx.cc_out_flags |= CCTX_DH_REQUEST;
 364  636          }
      637 +        if ((cctx.cc_in_flags & CCTX_DH_REQUEST_V2) != 0 &&
      638 +            of->dh_vers == SMB2_DURABLE_V2) {
      639 +                cctx.cc_out_flags |= CCTX_DH_REQUEST_V2;
      640 +        }
      641 +
      642 +        /*
      643 +         * This marks the end of the "body" section and the
      644 +         * beginning of the "encode" section.  Any errors
      645 +         * encoding the response should use: goto errout
      646 +         */
      647 +cmd_done:
      648 +        /* Want status visible in the done probe. */
      649 +        sr->smb2_status = status;
      650 +        DTRACE_SMB2_DONE(op__Create, smb_request_t *, sr);
      651 +        if (status != NT_STATUS_SUCCESS)
      652 +                goto errout;
      653 +
      654 +        /*
      655 +         * Encode all the create contexts to return.
      656 +         */
 365  657          if (cctx.cc_out_flags) {
 366  658                  sr->raw_data.max_bytes = smb2_max_trans;
 367      -                status = smb2_encode_create_ctx(&sr->raw_data, &cctx);
      659 +                status = smb2_encode_create_ctx(sr, &cctx);
 368  660                  if (status)
 369  661                          goto errout;
 370  662          }
 371  663  
 372  664          /*
 373      -         * SMB2 Create reply
      665 +         * Encode the SMB2 Create reply
 374  666           */
      667 +        attr = &op->fqi.fq_fattr;
 375  668          rc = smb_mbc_encodef(
 376  669              &sr->reply,
 377  670              "wb.lTTTTqqllqqll",
 378  671              89, /* StructSize */        /* w */
 379      -            OplockLevel,                /* b */
      672 +            op->op_oplock_level,        /* b */
 380  673              op->action_taken,           /* l */
 381  674              &attr->sa_crtime,           /* T */
 382  675              &attr->sa_vattr.va_atime,   /* T */
 383  676              &attr->sa_vattr.va_mtime,   /* T */
 384  677              &attr->sa_vattr.va_ctime,   /* T */
 385  678              attr->sa_allocsz,           /* q */
 386  679              attr->sa_vattr.va_size,     /* q */
 387  680              attr->sa_dosattr,           /* l */
 388  681              0, /* reserved2 */          /* l */
 389  682              smb2fid.persistent,         /* q */
↓ open down ↓ 19 lines elided ↑ open up ↑
 409  702                      CreateCtxLength,    /* l */
 410  703                      CreateCtxLength,    /* # */
 411  704                      &sr->raw_data);     /* C */
 412  705                  if (rc != 0) {
 413  706                          status = NT_STATUS_UNSUCCESSFUL;
 414  707                          goto errout;
 415  708                  }
 416  709          } else {
 417  710                  (void) smb_mbc_encodef(&sr->reply, ".");
 418  711          }
 419      -        return (SDRC_SUCCESS);
 420  712  
 421      -errout:
 422      -        if (of != NULL)
 423      -                smb_ofile_close(of, 0);
      713 +        if (status != 0) {
      714 +        errout:
      715 +                if (of != NULL)
      716 +                        smb_ofile_close(of, 0);
      717 +                smb2sr_put_error(sr, status);
      718 +        }
      719 +        if (op->sd != NULL) {
      720 +                smb_sd_term(op->sd);
      721 +                kmem_free(op->sd, sizeof (*op->sd));
      722 +        }
 424  723          if (cctx.cc_out_flags)
 425  724                  smb2_free_create_ctx(&cctx);
 426      -        smb2sr_put_error(sr, status);
      725 +
 427  726          return (SDRC_SUCCESS);
 428  727  }
 429  728  
 430  729  /*
 431  730   * Decode an SMB2 Create Context buffer into our internal form.
 432      - * No policy decisions about what's supported here, just decode.
      731 + * Avoid policy decisions about what's supported here, just decode.
 433  732   */
 434  733  static uint32_t
 435      -smb2_decode_create_ctx(mbuf_chain_t *in_mbc, smb2_create_ctx_t *cc)
      734 +smb2_decode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc)
 436  735  {
      736 +        smb_arg_open_t *op = &sr->arg.open;
 437  737          smb2_create_ctx_elem_t *cce;
      738 +        mbuf_chain_t *in_mbc = &cc->cc_in_mbc;
 438  739          mbuf_chain_t name_mbc;
 439  740          union {
 440  741                  uint32_t i;
 441  742                  char ch[4];
 442  743          } cc_name;
 443  744          uint32_t status;
 444  745          int32_t next_off;
 445  746          uint32_t data_len;
 446  747          uint16_t data_off;
 447  748          uint16_t name_off;
 448  749          uint16_t name_len;
 449  750          int top_offset;
 450  751          int rc;
 451  752  
      753 +        /*
      754 +         * Any break from the loop below before we've decoded
      755 +         * the entire create context means it was malformatted,
      756 +         * so we should return INVALID_PARAMETER.
      757 +         */
 452  758          status = NT_STATUS_INVALID_PARAMETER;
 453  759          for (;;) {
 454  760                  cce = NULL;
 455  761                  top_offset = in_mbc->chain_offset;
 456  762                  rc = smb_mbc_decodef(
 457  763                      in_mbc,
 458  764                      "lww..wl",
 459  765                      &next_off,  /* l */
 460  766                      &name_off,  /* w */
 461  767                      &name_len,  /* w */
↓ open down ↓ 51 lines elided ↑ open up ↑
 513  819                          cce = &cc->cc_in_time_warp;
 514  820                          break;
 515  821                  case SMB2_CREATE_QUERY_ON_DISK_ID:      /* ("QFid") */
 516  822                          cc->cc_in_flags |= CCTX_QUERY_ON_DISK_ID;
 517  823                          /* no input data for this */
 518  824                          break;
 519  825                  case SMB2_CREATE_REQUEST_LEASE:         /* ("RqLs") */
 520  826                          cc->cc_in_flags |= CCTX_REQUEST_LEASE;
 521  827                          cce = &cc->cc_in_req_lease;
 522  828                          break;
      829 +                case SMB2_CREATE_CTX_AAPL:              /* ("AAPL") */
      830 +                        cc->cc_in_flags |= CCTX_AAPL_EXT;
      831 +                        cce = &cc->cc_in_aapl;
      832 +                        break;
      833 +                case SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2: /* ("DH2Q") */
      834 +                        cc->cc_in_flags |= CCTX_DH_REQUEST_V2;
      835 +                        cce = &cc->cc_in_dh_request_v2;
      836 +                        break;
      837 +                case SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2: /* ("DH2C") */
      838 +                        cc->cc_in_flags |= CCTX_DH_RECONNECT_V2;
      839 +                        cce = &cc->cc_in_dh_reconnect_v2;
      840 +                        break;
      841 +                case 0x9ccbcf9e: /* SVHDX_OPEN_DEVICE_CONTEXT */
      842 +                        /* 9ccbcf9e 04c1e643 980e158d a1f6ec83 */
      843 +                        /* silently ignore */
      844 +                        break;
 523  845                  default:
 524  846                          /*
 525  847                           * Unknown create context values are normal, and
 526  848                           * should be ignored.  However, in debug mode,
 527  849                           * let's log them so we know which ones we're
 528  850                           * not handling (and may want to add).
 529  851                           */
 530  852  #ifdef  DEBUG
 531  853                          cmn_err(CE_NOTE, "unknown create context ID 0x%x",
 532  854                              cc_name.i);
 533  855  #endif
 534  856                          cce = NULL;
 535  857                          break;
 536  858                  }
 537  859  
 538      -                if (cce != NULL && data_len != 0) {
 539      -                        if ((data_off & 7) != 0)
 540      -                                break;
 541      -                        if ((top_offset + data_off) < in_mbc->chain_offset)
 542      -                                break;
 543      -                        rc = MBC_SHADOW_CHAIN(&cce->cce_mbc, in_mbc,
 544      -                            top_offset + data_off, data_len);
 545      -                        if (rc)
 546      -                                break;
 547      -                        cce->cce_len = data_len;
      860 +                if (cce == NULL || data_len == 0)
      861 +                        goto next_cc;
      862 +
      863 +                if ((data_off & 7) != 0)
      864 +                        break;
      865 +                if ((top_offset + data_off) < in_mbc->chain_offset)
      866 +                        break;
      867 +                rc = MBC_SHADOW_CHAIN(&cce->cce_mbc, in_mbc,
      868 +                    top_offset + data_off, data_len);
      869 +                if (rc)
      870 +                        break;
      871 +                cce->cce_len = data_len;
      872 +
      873 +                /*
      874 +                 * Additonal decoding for some create contexts.
      875 +                 */
      876 +                switch (cc_name.i) {
      877 +                        uint64_t nttime;
      878 +
      879 +                case SMB2_CREATE_SD_BUFFER:             /* ("SecD") */
      880 +                        op->sd = kmem_alloc(sizeof (smb_sd_t), KM_SLEEP);
      881 +                        if (smb_decode_sd(&cce->cce_mbc, op->sd) != 0)
      882 +                                goto errout;
      883 +                        break;
      884 +
      885 +                case SMB2_CREATE_ALLOCATION_SIZE:       /* ("AISi") */
      886 +                        rc = smb_mbc_decodef(&cce->cce_mbc, "q", &op->dsize);
      887 +                        if (rc != 0)
      888 +                                goto errout;
      889 +                        break;
      890 +
      891 +                case SMB2_CREATE_TIMEWARP_TOKEN:        /* ("TWrp") */
      892 +                        /*
      893 +                         * Support for opening "Previous Versions".
      894 +                         * [MS-SMB2] 2.2.13.2.7  Data is an NT time.
      895 +                         */
      896 +                        rc = smb_mbc_decodef(&cce->cce_mbc,
      897 +                            "q", &nttime);
      898 +                        if (rc != 0)
      899 +                                goto errout;
      900 +                        smb_time_nt_to_unix(nttime, &op->timewarp);
      901 +                        op->create_timewarp = B_TRUE;
      902 +                        break;
      903 +
      904 +                /*
      905 +                 * Note: This handles both V1 and V2 leases,
      906 +                 * which differ only by their length.
      907 +                 */
      908 +                case SMB2_CREATE_REQUEST_LEASE:         /* ("RqLs") */
      909 +                        if (data_len == 52) {
      910 +                                op->lease_version = 2;
      911 +                        } else if (data_len == 32) {
      912 +                                op->lease_version = 1;
      913 +                        } else {
      914 +                                cmn_err(CE_NOTE, "Cctx RqLs bad len=0x%x",
      915 +                                    data_len);
      916 +                        }
      917 +                        rc = smb_mbc_decodef(&cce->cce_mbc, "#cllq",
      918 +                            UUID_LEN,                   /* # */
      919 +                            op->lease_key,              /* c */
      920 +                            &op->lease_state,           /* l */
      921 +                            &op->lease_flags,           /* l */
      922 +                            &nttime);   /* (ignored)       q */
      923 +                        if (rc != 0)
      924 +                                goto errout;
      925 +                        if (op->lease_version == 2) {
      926 +                                rc = smb_mbc_decodef(&cce->cce_mbc,
      927 +                                    "#cw..",
      928 +                                    UUID_LEN,
      929 +                                    op->parent_lease_key,
      930 +                                    &op->lease_epoch);
      931 +                                if (rc != 0)
      932 +                                        goto errout;
      933 +                        } else {
      934 +                                bzero(op->parent_lease_key, UUID_LEN);
      935 +                        }
      936 +                        break;
      937 +
      938 +                case SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2: /* ("DH2C") */
      939 +                        rc = smb_mbc_decodef(&cce->cce_mbc, "qq#cl",
      940 +                            &op->dh_fileid.persistent,  /* q */
      941 +                            &op->dh_fileid.temporal,    /* q */
      942 +                            UUID_LEN,                   /* # */
      943 +                            op->create_guid,            /* c */
      944 +                            &op->dh_v2_flags);          /* l */
      945 +                        if (rc != 0)
      946 +                                goto errout;
      947 +                        break;
      948 +
      949 +                case SMB2_CREATE_DURABLE_HANDLE_RECONNECT: /* ("DHnC") */
      950 +                        rc = smb_mbc_decodef(&cce->cce_mbc, "qq",
      951 +                            &op->dh_fileid.persistent, /* q */
      952 +                            &op->dh_fileid.temporal); /* q */
      953 +                        if (rc != 0)
      954 +                                goto errout;
      955 +                        bzero(op->create_guid, UUID_LEN);
      956 +                        op->dh_v2_flags = 0;
      957 +                        break;
      958 +
      959 +                case SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2: /* ("DH2Q") */
      960 +                        rc = smb_mbc_decodef(&cce->cce_mbc,
      961 +                            "ll8.#c",
      962 +                            &op->dh_timeout,    /* l */
      963 +                            &op->dh_v2_flags,   /* l */
      964 +                            /* reserved */      /* 8. */
      965 +                            UUID_LEN, /* # */
      966 +                            op->create_guid); /* c */
      967 +                        if (rc != 0)
      968 +                                goto errout;
      969 +                        break;
      970 +
      971 +                case SMB2_CREATE_DURABLE_HANDLE_REQUEST: /* ("DHnQ") */
      972 +                        rc = smb_mbc_decodef(&cce->cce_mbc,
      973 +                            "16."); /* reserved */
      974 +                        if (rc != 0)
      975 +                                goto errout;
      976 +                        op->dh_timeout = 0;     /* default */
      977 +                        op->dh_v2_flags = 0;
      978 +                        break;
 548  979                  }
 549  980  
      981 +        next_cc:
 550  982                  if (next_off == 0) {
 551  983                          /* Normal loop termination */
 552  984                          status = 0;
 553  985                          break;
 554  986                  }
 555  987  
 556  988                  if ((next_off & 7) != 0)
 557  989                          break;
 558  990                  if ((top_offset + next_off) < in_mbc->chain_offset)
 559  991                          break;
 560  992                  if ((top_offset + next_off) > in_mbc->max_bytes)
 561  993                          break;
 562  994                  in_mbc->chain_offset = top_offset + next_off;
 563  995          }
 564  996  
      997 +errout:
 565  998          return (status);
 566  999  }
 567 1000  
 568 1001  /*
 569 1002   * Encode an SMB2 Create Context buffer from our internal form.
     1003 + *
     1004 + * Build the Create Context to return; first the
     1005 + * per-element parts, then the aggregated buffer.
     1006 + *
     1007 + * No response for these:
     1008 + *      CCTX_EA_BUFFER
     1009 + *      CCTX_SD_BUFFER
     1010 + *      CCTX_ALLOCATION_SIZE
     1011 + *      CCTX_TIMEWARP_TOKEN
     1012 + *
     1013 + * Remember to add code sections to smb2_free_create_ctx()
     1014 + * for each section here that encodes a context element.
 570 1015   */
 571      -/* ARGSUSED */
 572 1016  static uint32_t
 573      -smb2_encode_create_ctx(mbuf_chain_t *mbc, smb2_create_ctx_t *cc)
     1017 +smb2_encode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc)
 574 1018  {
     1019 +        smb_arg_open_t *op = &sr->arg.open;
 575 1020          smb2_create_ctx_elem_t *cce;
     1021 +        mbuf_chain_t *mbc = &sr->raw_data;
 576 1022          int last_top = -1;
 577 1023          int rc;
 578 1024  
 579 1025          if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) {
 580 1026                  cce = &cc->cc_out_max_access;
     1027 +
     1028 +                cce->cce_mbc.max_bytes = cce->cce_len = 8;
     1029 +                (void) smb_mbc_encodef(&cce->cce_mbc,
     1030 +                    "ll", 0, op->maximum_access);
     1031 +
 581 1032                  last_top = mbc->chain_offset;
 582 1033                  rc = smb2_encode_create_ctx_elem(mbc, cce,
 583 1034                      SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ);
 584 1035                  if (rc)
 585 1036                          return (NT_STATUS_INTERNAL_ERROR);
 586 1037                  (void) smb_mbc_poke(mbc, last_top, "l",
 587 1038                      mbc->chain_offset - last_top);
 588 1039          }
 589 1040  
 590 1041          if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) {
 591 1042                  cce = &cc->cc_out_file_id;
     1043 +
     1044 +                cce->cce_mbc.max_bytes = cce->cce_len = 32;
     1045 +                (void) smb_mbc_encodef(
     1046 +                    &cce->cce_mbc, "qll.15.",
     1047 +                    op->fileid,                 /* q */
     1048 +                    op->op_fsid.val[0],         /* l */
     1049 +                    op->op_fsid.val[1]);        /* l */
     1050 +                    /* reserved (16 bytes)      .15. */
     1051 +
 592 1052                  last_top = mbc->chain_offset;
 593 1053                  rc = smb2_encode_create_ctx_elem(mbc, cce,
 594 1054                      SMB2_CREATE_QUERY_ON_DISK_ID);
 595 1055                  if (rc)
 596 1056                          return (NT_STATUS_INTERNAL_ERROR);
 597 1057                  (void) smb_mbc_poke(mbc, last_top, "l",
 598 1058                      mbc->chain_offset - last_top);
 599 1059          }
 600 1060  
     1061 +        if (cc->cc_out_flags & CCTX_AAPL_EXT) {
     1062 +                cce = &cc->cc_out_aapl;
     1063 +                /* cc_out_aapl already encoded */
     1064 +
     1065 +                last_top = mbc->chain_offset;
     1066 +                rc = smb2_encode_create_ctx_elem(mbc, cce,
     1067 +                    SMB2_CREATE_CTX_AAPL);
     1068 +                if (rc)
     1069 +                        return (NT_STATUS_INTERNAL_ERROR);
     1070 +                (void) smb_mbc_poke(mbc, last_top, "l",
     1071 +                    mbc->chain_offset - last_top);
     1072 +        }
     1073 +
     1074 +        if (cc->cc_out_flags & CCTX_REQUEST_LEASE) {
     1075 +                cce = &cc->cc_out_req_lease;
     1076 +
     1077 +                cce->cce_mbc.max_bytes = cce->cce_len = 32;
     1078 +                (void) smb_mbc_encodef(&cce->cce_mbc, "#cllq",
     1079 +                    UUID_LEN,                   /* # */
     1080 +                    op->lease_key,              /* c */
     1081 +                    op->lease_state,            /* l */
     1082 +                    op->lease_flags,            /* l */
     1083 +                    0LL);                       /* q */
     1084 +                if (op->lease_version == 2) {
     1085 +                        cce->cce_mbc.max_bytes = cce->cce_len = 52;
     1086 +                        (void) smb_mbc_encodef(&cce->cce_mbc,
     1087 +                            "#cw..",
     1088 +                            UUID_LEN,
     1089 +                            op->parent_lease_key,
     1090 +                            op->lease_epoch);
     1091 +                }
     1092 +
     1093 +                last_top = mbc->chain_offset;
     1094 +                rc = smb2_encode_create_ctx_elem(mbc, cce,
     1095 +                    SMB2_CREATE_REQUEST_LEASE);
     1096 +                if (rc)
     1097 +                        return (NT_STATUS_INTERNAL_ERROR);
     1098 +                (void) smb_mbc_poke(mbc, last_top, "l",
     1099 +                    mbc->chain_offset - last_top);
     1100 +        }
     1101 +
     1102 +        if (cc->cc_out_flags & CCTX_DH_REQUEST) {
     1103 +                cce = &cc->cc_out_dh_request;
     1104 +
     1105 +                cce->cce_mbc.max_bytes = cce->cce_len = 8;
     1106 +                (void) smb_mbc_encodef(&cce->cce_mbc, "q", 0LL);
     1107 +
     1108 +                last_top = mbc->chain_offset;
     1109 +                rc = smb2_encode_create_ctx_elem(mbc, cce,
     1110 +                    SMB2_CREATE_DURABLE_HANDLE_REQUEST);
     1111 +                if (rc)
     1112 +                        return (NT_STATUS_INTERNAL_ERROR);
     1113 +                (void) smb_mbc_poke(mbc, last_top, "l",
     1114 +                    mbc->chain_offset - last_top);
     1115 +        }
     1116 +
     1117 +        if (cc->cc_out_flags & CCTX_DH_REQUEST_V2) {
     1118 +                cce = &cc->cc_out_dh_request_v2;
     1119 +
     1120 +                cce->cce_mbc.max_bytes = cce->cce_len = 8;
     1121 +                (void) smb_mbc_encodef(&cce->cce_mbc, "ll",
     1122 +                    op->dh_timeout, op->dh_v2_flags);
     1123 +
     1124 +                last_top = mbc->chain_offset;
     1125 +                rc = smb2_encode_create_ctx_elem(mbc, cce,
     1126 +                    SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2);
     1127 +                if (rc)
     1128 +                        return (NT_STATUS_INTERNAL_ERROR);
     1129 +                (void) smb_mbc_poke(mbc, last_top, "l",
     1130 +                    mbc->chain_offset - last_top);
     1131 +        }
     1132 +
 601 1133          if (last_top >= 0)
 602 1134                  (void) smb_mbc_poke(mbc, last_top, "l", 0);
 603 1135  
 604 1136          return (0);
 605 1137  }
 606 1138  
 607 1139  static int
 608 1140  smb2_encode_create_ctx_elem(mbuf_chain_t *out_mbc,
 609      -        smb2_create_ctx_elem_t *cce, uint32_t id)
     1141 +    smb2_create_ctx_elem_t *cce, uint32_t id)
 610 1142  {
 611 1143          union {
 612 1144                  uint32_t i;
 613 1145                  char ch[4];
 614 1146          } cc_name;
 615 1147          int rc;
 616 1148  
 617 1149          /* as above */
 618 1150          cc_name.i = htonl(id);
 619 1151  
 620 1152          /*
 621 1153           * This is the header, per [MS-SMB2] 2.2.13.2
 622 1154           * Sorry about the fixed offsets.  We know we'll
 623 1155           * layout the data part as [name, payload] and
 624 1156           * name is a fixed length, so this easy.
 625 1157           * The final layout looks like this:
 626      -         *      a: this header (16 bytes)
     1158 +         *      a: this header (16 bytes)
 627 1159           *      b: the name (4 bytes, 4 pad)
 628 1160           *      c: the payload (variable)
     1161 +         *      d: padding (to align 8)
 629 1162           *
 630 1163           * Note that "Next elem." is filled in later.
 631 1164           */
 632 1165          rc = smb_mbc_encodef(
 633 1166              out_mbc, "lwwwwl",
 634 1167              0,          /* Next offset  l */
 635 1168              16,         /* NameOffset   w */
 636 1169              4,          /* NameLength   w */
 637 1170              0,          /* Reserved     w */
 638 1171              24,         /* DataOffset   w */
 639      -            cce->cce_len);      /*      l */
     1172 +            cce->cce_len); /* DataLen   l */
 640 1173          if (rc)
 641 1174                  return (rc);
 642 1175  
 643 1176          /*
 644 1177           * Now the "name" and payload.
 645 1178           */
 646 1179          rc = smb_mbc_encodef(
 647 1180              out_mbc, "4c4.#C",
 648 1181              cc_name.ch,         /* 4c4. */
 649 1182              cce->cce_len,       /* # */
 650 1183              &cce->cce_mbc);     /* C */
 651 1184  
     1185 +        (void) smb_mbc_put_align(out_mbc, 8);
     1186 +
 652 1187          return (rc);
 653 1188  }
 654 1189  
 655 1190  static void
 656 1191  smb2_free_create_ctx(smb2_create_ctx_t *cc)
 657 1192  {
 658 1193          smb2_create_ctx_elem_t *cce;
 659 1194  
 660 1195          if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) {
 661 1196                  cce = &cc->cc_out_max_access;
 662 1197                  MBC_FLUSH(&cce->cce_mbc);
 663 1198          }
 664 1199          if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) {
 665 1200                  cce = &cc->cc_out_file_id;
 666 1201                  MBC_FLUSH(&cce->cce_mbc);
 667 1202          }
     1203 +        if (cc->cc_out_flags & CCTX_AAPL_EXT) {
     1204 +                cce = &cc->cc_out_aapl;
     1205 +                MBC_FLUSH(&cce->cce_mbc);
     1206 +        }
     1207 +        if (cc->cc_out_flags & CCTX_REQUEST_LEASE) {
     1208 +                cce = &cc->cc_out_req_lease;
     1209 +                MBC_FLUSH(&cce->cce_mbc);
     1210 +        }
     1211 +        if (cc->cc_out_flags & CCTX_DH_REQUEST) {
     1212 +                cce = &cc->cc_out_dh_request;
     1213 +                MBC_FLUSH(&cce->cce_mbc);
     1214 +        }
     1215 +        if (cc->cc_out_flags & CCTX_DH_REQUEST_V2) {
     1216 +                cce = &cc->cc_out_dh_request_v2;
     1217 +                MBC_FLUSH(&cce->cce_mbc);
     1218 +        }
 668 1219  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX