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)
   1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  14  */
  15 
  16 /*
  17  * Dispatch function for SMB2_CREATE
  18  * [MS-SMB2] 2.2.13
  19  */
  20 
  21 #include <smbsrv/smb2_kproto.h>
  22 #include <smbsrv/smb_fsops.h>
  23 


  24 /*

















  25  * Some flags used locally to keep track of which Create Context
  26  * names have been provided and/or requested.
  27  */
  28 #define CCTX_EA_BUFFER                  1
  29 #define CCTX_SD_BUFFER                  2
  30 #define CCTX_DH_REQUEST                 4
  31 #define CCTX_DH_RECONNECT               8
  32 #define CCTX_ALLOCATION_SIZE            0x10
  33 #define CCTX_QUERY_MAX_ACCESS           0x20
  34 #define CCTX_TIMEWARP_TOKEN             0x40
  35 #define CCTX_QUERY_ON_DISK_ID           0x80
  36 #define CCTX_REQUEST_LEASE              0x100



  37 
  38 
  39 typedef struct smb2_create_ctx_elem {
  40         uint32_t cce_len;
  41         mbuf_chain_t cce_mbc;
  42 } smb2_create_ctx_elem_t;
  43 
  44 typedef struct smb2_create_ctx {

  45         uint_t  cc_in_flags;    /* CCTX_... */
  46         uint_t  cc_out_flags;   /* CCTX_... */
  47         /* Elements we may see in the request. */
  48         smb2_create_ctx_elem_t cc_in_ext_attr;
  49         smb2_create_ctx_elem_t cc_in_sec_desc;
  50         smb2_create_ctx_elem_t cc_in_dh_request;
  51         smb2_create_ctx_elem_t cc_in_dh_reconnect;
  52         smb2_create_ctx_elem_t cc_in_alloc_size;
  53         smb2_create_ctx_elem_t cc_in_time_warp;
  54         smb2_create_ctx_elem_t cc_in_req_lease;



  55         /* Elements we my place in the response */
  56         smb2_create_ctx_elem_t cc_out_max_access;
  57         smb2_create_ctx_elem_t cc_out_file_id;




  58 } smb2_create_ctx_t;
  59 
  60 static uint32_t smb2_decode_create_ctx(
  61         mbuf_chain_t *, smb2_create_ctx_t *);
  62 static uint32_t smb2_encode_create_ctx(
  63         mbuf_chain_t *, smb2_create_ctx_t *);
  64 static int smb2_encode_create_ctx_elem(
  65         mbuf_chain_t *, smb2_create_ctx_elem_t *, uint32_t);
  66 static void smb2_free_create_ctx(smb2_create_ctx_t *);
  67 


  68 smb_sdrc_t
  69 smb2_create(smb_request_t *sr)
  70 {
  71         smb_attr_t *attr;
  72         smb2_create_ctx_elem_t *cce;
  73         smb2_create_ctx_t cctx;
  74         mbuf_chain_t cc_mbc;
  75         smb_arg_open_t *op = &sr->arg.open;
  76         smb_ofile_t *of = NULL;
  77         uint16_t StructSize;
  78         uint8_t SecurityFlags;
  79         uint8_t OplockLevel;
  80         uint32_t ImpersonationLevel;
  81         uint64_t SmbCreateFlags;
  82         uint64_t Reserved4;
  83         uint16_t NameOffset;
  84         uint16_t NameLength;
  85         uint32_t CreateCtxOffset;
  86         uint32_t CreateCtxLength;
  87         smb2fid_t smb2fid;
  88         uint32_t status;

  89         int skip;
  90         int rc = 0;
  91 
  92         bzero(&cctx, sizeof (cctx));
  93         bzero(&cc_mbc, sizeof (cc_mbc));
  94 
  95         /*
  96          * Paranoia.  This will set sr->fid_ofile, so
  97          * if we already have one, release it now.
  98          */
  99         if (sr->fid_ofile != NULL) {
 100                 smb_ofile_request_complete(sr->fid_ofile);
 101                 smb_ofile_release(sr->fid_ofile);
 102                 sr->fid_ofile = NULL;
 103         }
 104 
 105         /*
 106          * SMB2 Create request







 107          */
 108         rc = smb_mbc_decodef(
 109             &sr->smb_data, "wbblqqlllllwwll",
 110             &StructSize,            /* w */
 111             &SecurityFlags,         /* b */
 112             &OplockLevel,           /* b */
 113             &ImpersonationLevel,    /* l */
 114             &SmbCreateFlags,                /* q */
 115             &Reserved4,                     /* q */
 116             &op->desired_access, /* l */
 117             &op->dattr,                  /* l */
 118             &op->share_access,           /* l */
 119             &op->create_disposition,     /* l */
 120             &op->create_options, /* l */
 121             &NameOffset,            /* w */
 122             &NameLength,            /* w */
 123             &CreateCtxOffset,               /* l */
 124             &CreateCtxLength);              /* l */
 125         if (rc != 0 || StructSize != 57)
 126                 return (SDRC_ERROR);
 127 
 128         /*
 129          * We're normally positioned at the path name now,
 130          * but there could be some padding before it.
 131          */
 132         skip = (NameOffset + sr->smb2_cmd_hdr) -
 133             sr->smb_data.chain_offset;
 134         if (skip < 0) {
 135                 status = NT_STATUS_OBJECT_PATH_INVALID;
 136                 goto errout;
 137         }
 138         if (skip > 0)
 139                 (void) smb_mbc_decodef(&sr->smb_data, "#.", skip);
 140 
 141         /*
 142          * Get the path name




 143          */
 144         if (NameLength >= SMB_MAXPATHLEN) {
 145                 status = NT_STATUS_OBJECT_PATH_INVALID;
 146                 goto errout;
 147         }
 148         if (NameLength == 0) {
 149                 op->fqi.fq_path.pn_path = "\\";
 150         } else {
 151                 rc = smb_mbc_decodef(&sr->smb_data, "%#U", sr,
 152                     NameLength, &op->fqi.fq_path.pn_path);
 153                 if (rc) {
 154                         status = NT_STATUS_OBJECT_PATH_INVALID;
 155                         goto errout;
 156                 }
 157         }
 158         op->fqi.fq_dnode = sr->tid_tree->t_snode;
 159 
 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         /*
 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          * If there is a "Create Context" payload, decode it.
 205          * This may carry things like a security descriptor,
 206          * extended attributes, etc. to be used in create.
 207          *
 208          * The create ctx buffer must start after the headers
 209          * and file name, and must be 8-byte aligned.
 210          */
 211         if (CreateCtxLength != 0) {
 212                 if ((CreateCtxOffset & 7) != 0 ||
 213                     (CreateCtxOffset + sr->smb2_cmd_hdr) <
 214                     sr->smb_data.chain_offset) {
 215                         status = NT_STATUS_INVALID_PARAMETER;
 216                         goto errout;
 217                 }
 218 
 219                 rc = MBC_SHADOW_CHAIN(&cc_mbc, &sr->smb_data,
 220                     sr->smb2_cmd_hdr + CreateCtxOffset, CreateCtxLength);
 221                 if (rc) {
 222                         status = NT_STATUS_INVALID_PARAMETER;
 223                         goto errout;
 224                 }
 225                 status = smb2_decode_create_ctx(&cc_mbc, &cctx);
 226                 if (status)
 227                         goto errout;

 228 
 229                 if (cctx.cc_in_flags & CCTX_EA_BUFFER) {
 230                         status = NT_STATUS_EAS_NOT_SUPPORTED;
 231                         goto errout;






















 232                 }
 233 
 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                 }
 244 
 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;
 251                         }
 252                 }
 253 
 254                 /*
 255                  * Support for opening "Previous Versions".
 256                  * [MS-SMB2] 2.2.13.2.7  Data is an NT time.


 257                  */
 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;

























































 267                 }
 268         }
 269 



 270         /*
 271          * The real open call.   Note: this gets attributes into
 272          * op->fqi.fq_fattr (SMB_AT_ALL).  We need those below.
 273          */
 274         status = smb_common_open(sr);
 275         if (status != NT_STATUS_SUCCESS)
 276                 goto errout;
 277         attr = &op->fqi.fq_fattr;
 278 
 279         /*
 280          * Convert the negotiate Oplock level back into
 281          * SMB2 encoding form.
 282          */
 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;





 297         }
 298 
 299         /*























































































































































 300          * NB: after the above smb_common_open() success,
 301          * we have a handle allocated (sr->fid_ofile).
 302          * If we don't return success, we must close it.
 303          *
 304          * Using sr->smb_fid as the file handle for now,
 305          * though it could later be something larger,
 306          * (16 bytes) similar to an NFSv4 open handle.
 307          */
 308         of = sr->fid_ofile;
 309         smb2fid.persistent = 0;
 310         smb2fid.temporal = sr->smb_fid;
 311 
 312         switch (sr->tid_tree->t_res_type & STYPE_MASK) {
 313         case STYPE_DISKTREE:
 314         case STYPE_PRINTQ:
 315                 if (op->create_options & FILE_DELETE_ON_CLOSE)
 316                         smb_ofile_set_delete_on_close(of);
 317                 break;
 318         }
 319 
 320         /*
 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
 334          */
 335         if (cctx.cc_in_flags & CCTX_QUERY_MAX_ACCESS) {
 336                 cce = &cctx.cc_out_max_access;
 337                 uint32_t MaxAccess = 0;
 338                 if (of->f_node != NULL) {
 339                         smb_fsop_eaccess(sr, of->f_cr, of->f_node, &MaxAccess);

 340                 }
 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);
 346                 cctx.cc_out_flags |= CCTX_QUERY_MAX_ACCESS;
 347         }

 348         if ((cctx.cc_in_flags & CCTX_QUERY_ON_DISK_ID) != 0 &&
 349             of->f_node != NULL) {
 350                 cce = &cctx.cc_out_file_id;
 351                 fsid_t fsid;

 352 
 353                 fsid = SMB_NODE_FSID(of->f_node);

















 354 
 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;




 364         }




















 365         if (cctx.cc_out_flags) {
 366                 sr->raw_data.max_bytes = smb2_max_trans;
 367                 status = smb2_encode_create_ctx(&sr->raw_data, &cctx);
 368                 if (status)
 369                         goto errout;
 370         }
 371 
 372         /*
 373          * SMB2 Create reply
 374          */

 375         rc = smb_mbc_encodef(
 376             &sr->reply,
 377             "wb.lTTTTqqllqqll",
 378             89, /* StructSize */        /* w */
 379             OplockLevel,                /* b */
 380             op->action_taken,                /* l */
 381             &attr->sa_crtime,            /* T */
 382             &attr->sa_vattr.va_atime,    /* T */
 383             &attr->sa_vattr.va_mtime,    /* T */
 384             &attr->sa_vattr.va_ctime,    /* T */
 385             attr->sa_allocsz,                /* q */
 386             attr->sa_vattr.va_size,  /* q */
 387             attr->sa_dosattr,                /* l */
 388             0, /* reserved2 */          /* l */
 389             smb2fid.persistent,         /* q */
 390             smb2fid.temporal,           /* q */
 391             0,  /* CreateCtxOffset         l */
 392             0); /* CreateCtxLength         l */
 393         if (rc != 0) {
 394                 status = NT_STATUS_UNSUCCESSFUL;
 395                 goto errout;
 396         }
 397 
 398         CreateCtxOffset = sr->reply.chain_offset - sr->smb2_reply_hdr;
 399         CreateCtxLength = MBC_LENGTH(&sr->raw_data);
 400         if (CreateCtxLength != 0) {
 401                 /*
 402                  * Overwrite CreateCtxOffset, CreateCtxLength, pad
 403                  */
 404                 sr->reply.chain_offset -= 8;
 405                 rc = smb_mbc_encodef(
 406                     &sr->reply,
 407                     "ll#C",
 408                     CreateCtxOffset,    /* l */
 409                     CreateCtxLength,    /* l */
 410                     CreateCtxLength,    /* # */
 411                     &sr->raw_data);      /* C */
 412                 if (rc != 0) {
 413                         status = NT_STATUS_UNSUCCESSFUL;
 414                         goto errout;
 415                 }
 416         } else {
 417                 (void) smb_mbc_encodef(&sr->reply, ".");
 418         }
 419         return (SDRC_SUCCESS);
 420 
 421 errout:

 422         if (of != NULL)
 423                 smb_ofile_close(of, 0);






 424         if (cctx.cc_out_flags)
 425                 smb2_free_create_ctx(&cctx);
 426         smb2sr_put_error(sr, status);
 427         return (SDRC_SUCCESS);
 428 }
 429 
 430 /*
 431  * Decode an SMB2 Create Context buffer into our internal form.
 432  * No policy decisions about what's supported here, just decode.
 433  */
 434 static uint32_t
 435 smb2_decode_create_ctx(mbuf_chain_t *in_mbc, smb2_create_ctx_t *cc)
 436 {

 437         smb2_create_ctx_elem_t *cce;

 438         mbuf_chain_t name_mbc;
 439         union {
 440                 uint32_t i;
 441                 char ch[4];
 442         } cc_name;
 443         uint32_t status;
 444         int32_t next_off;
 445         uint32_t data_len;
 446         uint16_t data_off;
 447         uint16_t name_off;
 448         uint16_t name_len;
 449         int top_offset;
 450         int rc;
 451 





 452         status = NT_STATUS_INVALID_PARAMETER;
 453         for (;;) {
 454                 cce = NULL;
 455                 top_offset = in_mbc->chain_offset;
 456                 rc = smb_mbc_decodef(
 457                     in_mbc,
 458                     "lww..wl",
 459                     &next_off,      /* l */
 460                     &name_off,      /* w */
 461                     &name_len,      /* w */
 462                     /* reserved   .. */
 463                     &data_off,      /* w */
 464                     &data_len); /* l */
 465                 if (rc)
 466                         break;
 467 
 468                 /*
 469                  * The Create Context "name", per [MS-SMB] 2.2.13.2
 470                  * They're defined as network-order integers for our
 471                  * switch below.  We don't have routines to decode


 503                 case SMB2_CREATE_ALLOCATION_SIZE:       /* ("AISi") */
 504                         cc->cc_in_flags |= CCTX_ALLOCATION_SIZE;
 505                         cce = &cc->cc_in_alloc_size;
 506                         break;
 507                 case SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ: /* ("MxAc") */
 508                         cc->cc_in_flags |= CCTX_QUERY_MAX_ACCESS;
 509                         /* no input data for this */
 510                         break;
 511                 case SMB2_CREATE_TIMEWARP_TOKEN:        /* ("TWrp") */
 512                         cc->cc_in_flags |= CCTX_TIMEWARP_TOKEN;
 513                         cce = &cc->cc_in_time_warp;
 514                         break;
 515                 case SMB2_CREATE_QUERY_ON_DISK_ID:      /* ("QFid") */
 516                         cc->cc_in_flags |= CCTX_QUERY_ON_DISK_ID;
 517                         /* no input data for this */
 518                         break;
 519                 case SMB2_CREATE_REQUEST_LEASE:         /* ("RqLs") */
 520                         cc->cc_in_flags |= CCTX_REQUEST_LEASE;
 521                         cce = &cc->cc_in_req_lease;
 522                         break;
















 523                 default:
 524                         /*
 525                          * Unknown create context values are normal, and
 526                          * should be ignored.  However, in debug mode,
 527                          * let's log them so we know which ones we're
 528                          * not handling (and may want to add).
 529                          */
 530 #ifdef  DEBUG
 531                         cmn_err(CE_NOTE, "unknown create context ID 0x%x",
 532                             cc_name.i);
 533 #endif
 534                         cce = NULL;
 535                         break;
 536                 }
 537 
 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;












































 548                 }




















 549 












































 550                 if (next_off == 0) {
 551                         /* Normal loop termination */
 552                         status = 0;
 553                         break;
 554                 }
 555 
 556                 if ((next_off & 7) != 0)
 557                         break;
 558                 if ((top_offset + next_off) < in_mbc->chain_offset)
 559                         break;
 560                 if ((top_offset + next_off) > in_mbc->max_bytes)
 561                         break;
 562                 in_mbc->chain_offset = top_offset + next_off;
 563         }
 564 

 565         return (status);
 566 }
 567 
 568 /*
 569  * Encode an SMB2 Create Context buffer from our internal form.












 570  */
 571 /* ARGSUSED */
 572 static uint32_t
 573 smb2_encode_create_ctx(mbuf_chain_t *mbc, smb2_create_ctx_t *cc)
 574 {

 575         smb2_create_ctx_elem_t *cce;

 576         int last_top = -1;
 577         int rc;
 578 
 579         if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) {
 580                 cce = &cc->cc_out_max_access;





 581                 last_top = mbc->chain_offset;
 582                 rc = smb2_encode_create_ctx_elem(mbc, cce,
 583                     SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ);
 584                 if (rc)
 585                         return (NT_STATUS_INTERNAL_ERROR);
 586                 (void) smb_mbc_poke(mbc, last_top, "l",
 587                     mbc->chain_offset - last_top);
 588         }
 589 
 590         if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) {
 591                 cce = &cc->cc_out_file_id;









 592                 last_top = mbc->chain_offset;
 593                 rc = smb2_encode_create_ctx_elem(mbc, cce,
 594                     SMB2_CREATE_QUERY_ON_DISK_ID);
 595                 if (rc)
 596                         return (NT_STATUS_INTERNAL_ERROR);
 597                 (void) smb_mbc_poke(mbc, last_top, "l",
 598                     mbc->chain_offset - last_top);
 599         }
 600 








































































 601         if (last_top >= 0)
 602                 (void) smb_mbc_poke(mbc, last_top, "l", 0);
 603 
 604         return (0);
 605 }
 606 
 607 static int
 608 smb2_encode_create_ctx_elem(mbuf_chain_t *out_mbc,
 609         smb2_create_ctx_elem_t *cce, uint32_t id)
 610 {
 611         union {
 612                 uint32_t i;
 613                 char ch[4];
 614         } cc_name;
 615         int rc;
 616 
 617         /* as above */
 618         cc_name.i = htonl(id);
 619 
 620         /*
 621          * This is the header, per [MS-SMB2] 2.2.13.2
 622          * Sorry about the fixed offsets.  We know we'll
 623          * layout the data part as [name, payload] and
 624          * name is a fixed length, so this easy.
 625          * The final layout looks like this:
 626          *      a: this header (16 bytes)
 627          *      b: the name (4 bytes, 4 pad)
 628          *      c: the payload (variable)

 629          *
 630          * Note that "Next elem." is filled in later.
 631          */
 632         rc = smb_mbc_encodef(
 633             out_mbc, "lwwwwl",
 634             0,          /* Next offset  l */
 635             16,         /* NameOffset   w */
 636             4,          /* NameLength   w */
 637             0,          /* Reserved     w */
 638             24,         /* DataOffset   w */
 639             cce->cce_len);   /*      l */
 640         if (rc)
 641                 return (rc);
 642 
 643         /*
 644          * Now the "name" and payload.
 645          */
 646         rc = smb_mbc_encodef(
 647             out_mbc, "4c4.#C",
 648             cc_name.ch,         /* 4c4. */
 649             cce->cce_len,    /* # */
 650             &cce->cce_mbc);      /* C */
 651 


 652         return (rc);
 653 }
 654 
 655 static void
 656 smb2_free_create_ctx(smb2_create_ctx_t *cc)
 657 {
 658         smb2_create_ctx_elem_t *cce;
 659 
 660         if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) {
 661                 cce = &cc->cc_out_max_access;
 662                 MBC_FLUSH(&cce->cce_mbc);
 663         }
 664         if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) {
 665                 cce = &cc->cc_out_file_id;
 666                 MBC_FLUSH(&cce->cce_mbc);
 667         }
















 668 }
   1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  14  */
  15 
  16 /*
  17  * Dispatch function for SMB2_CREATE
  18  * [MS-SMB2] 2.2.13
  19  */
  20 
  21 #include <smbsrv/smb2_kproto.h>
  22 #include <smbsrv/smb_fsops.h>
  23 
  24 #define DH_PERSISTENT   SMB2_DHANDLE_FLAG_PERSISTENT
  25 
  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 /*
  44  * Some flags used locally to keep track of which Create Context
  45  * names have been provided and/or requested.
  46  */
  47 #define CCTX_EA_BUFFER                  1
  48 #define CCTX_SD_BUFFER                  2
  49 #define CCTX_DH_REQUEST                 4
  50 #define CCTX_DH_RECONNECT               8
  51 #define CCTX_ALLOCATION_SIZE            0x10
  52 #define CCTX_QUERY_MAX_ACCESS           0x20
  53 #define CCTX_TIMEWARP_TOKEN             0x40
  54 #define CCTX_QUERY_ON_DISK_ID           0x80
  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
  59 

  60 typedef struct smb2_create_ctx_elem {
  61         uint32_t cce_len;
  62         mbuf_chain_t cce_mbc;
  63 } smb2_create_ctx_elem_t;
  64 
  65 typedef struct smb2_create_ctx {
  66         mbuf_chain_t cc_in_mbc;
  67         uint_t  cc_in_flags;    /* CCTX_... */
  68         uint_t  cc_out_flags;   /* CCTX_... */
  69         /* Elements we may see in the request. */
  70         smb2_create_ctx_elem_t cc_in_ext_attr;
  71         smb2_create_ctx_elem_t cc_in_sec_desc;
  72         smb2_create_ctx_elem_t cc_in_dh_request;
  73         smb2_create_ctx_elem_t cc_in_dh_reconnect;
  74         smb2_create_ctx_elem_t cc_in_alloc_size;
  75         smb2_create_ctx_elem_t cc_in_time_warp;
  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;
  80         /* Elements we my place in the response */
  81         smb2_create_ctx_elem_t cc_out_max_access;
  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;
  87 } smb2_create_ctx_t;
  88 
  89 static uint32_t smb2_decode_create_ctx(
  90         smb_request_t *, smb2_create_ctx_t *);
  91 static uint32_t smb2_encode_create_ctx(
  92         smb_request_t *, smb2_create_ctx_t *);
  93 static int smb2_encode_create_ctx_elem(
  94         mbuf_chain_t *, smb2_create_ctx_elem_t *, uint32_t);
  95 static void smb2_free_create_ctx(smb2_create_ctx_t *);
  96 
  97 int smb2_enable_dh = 1;
  98 
  99 smb_sdrc_t
 100 smb2_create(smb_request_t *sr)
 101 {
 102         smb_attr_t *attr;
 103         smb2_create_ctx_elem_t *cce;
 104         smb2_create_ctx_t cctx;

 105         smb_arg_open_t *op = &sr->arg.open;
 106         smb_ofile_t *of = NULL;
 107         uint16_t StructSize;
 108         uint8_t SecurityFlags;

 109         uint32_t ImpersonationLevel;
 110         uint64_t SmbCreateFlags;
 111         uint64_t Reserved4;
 112         uint16_t NameOffset;
 113         uint16_t NameLength;
 114         uint32_t CreateCtxOffset;
 115         uint32_t CreateCtxLength;
 116         smb2fid_t smb2fid = { 0, 0 };
 117         uint32_t status;
 118         int dh_flags;
 119         int skip;
 120         int rc = 0;
 121 
 122         bzero(&cctx, sizeof (cctx));
 123         op->create_ctx = &cctx;  /* for debugging */
 124 
 125         /*
 126          * Paranoia.  This will set sr->fid_ofile, so
 127          * if we already have one, release it now.
 128          */
 129         if (sr->fid_ofile != NULL) {

 130                 smb_ofile_release(sr->fid_ofile);
 131                 sr->fid_ofile = NULL;
 132         }
 133 
 134         /*
 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.
 143          */
 144         rc = smb_mbc_decodef(
 145             &sr->smb_data, "wbblqqlllllwwll",
 146             &StructSize,            /* w */
 147             &SecurityFlags,         /* b */
 148             &op->op_oplock_level,        /* b */
 149             &ImpersonationLevel,    /* l */
 150             &SmbCreateFlags,                /* q */
 151             &Reserved4,                     /* q */
 152             &op->desired_access, /* l */
 153             &op->dattr,                  /* l */
 154             &op->share_access,           /* l */
 155             &op->create_disposition,     /* l */
 156             &op->create_options, /* l */
 157             &NameOffset,            /* w */
 158             &NameLength,            /* w */
 159             &CreateCtxOffset,               /* l */
 160             &CreateCtxLength);              /* l */
 161         if (rc != 0 || StructSize != 57)
 162                 return (SDRC_ERROR);
 163 
 164         /*
 165          * We're normally positioned at the path name now,
 166          * but there could be some padding before it.
 167          */
 168         skip = (NameOffset + sr->smb2_cmd_hdr) -
 169             sr->smb_data.chain_offset;
 170         if (skip < 0)
 171                 return (SDRC_ERROR);


 172         if (skip > 0)
 173                 (void) smb_mbc_decodef(&sr->smb_data, "#.", skip);
 174 
 175         /*
 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.
 181          */
 182         if (NameLength >= SMB_MAXPATHLEN) {
 183                 status = NT_STATUS_OBJECT_PATH_INVALID;
 184                 goto errout;
 185         }
 186         if (NameLength == 0) {
 187                 op->fqi.fq_path.pn_path = "\\";
 188         } else {
 189                 rc = smb_mbc_decodef(&sr->smb_data, "%#U", sr,
 190                     NameLength, &op->fqi.fq_path.pn_path);
 191                 if (rc) {
 192                         status = NT_STATUS_OBJECT_PATH_INVALID;
 193                         goto errout;
 194                 }
 195         }
 196         op->fqi.fq_dnode = sr->tid_tree->t_snode;
 197 



















 198         /*
























 199          * If there is a "Create Context" payload, decode it.
 200          * This may carry things like a security descriptor,
 201          * extended attributes, etc. to be used in create.
 202          *
 203          * The create ctx buffer must start after the headers
 204          * and file name, and must be 8-byte aligned.
 205          */
 206         if (CreateCtxLength != 0) {
 207                 if ((CreateCtxOffset & 7) != 0 ||
 208                     (CreateCtxOffset + sr->smb2_cmd_hdr) <
 209                     sr->smb_data.chain_offset) {
 210                         status = NT_STATUS_INVALID_PARAMETER;
 211                         goto errout;
 212                 }
 213 
 214                 rc = MBC_SHADOW_CHAIN(&cctx.cc_in_mbc, &sr->smb_data,
 215                     sr->smb2_cmd_hdr + CreateCtxOffset, CreateCtxLength);
 216                 if (rc) {
 217                         status = NT_STATUS_INVALID_PARAMETER;
 218                         goto errout;
 219                 }
 220                 status = smb2_decode_create_ctx(sr, &cctx);
 221                 if (status)
 222                         goto errout;
 223         }
 224 
 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 */
 235 
 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          */
 241 
 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;
 348                         }
 349                 }
 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 */
 367                 /*
 368                  * Ignore lease create context (if any)
 369                  */
 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;
 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;
 410         }
 411 
 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         /*
 461          * The real open call.   Note: this gets attributes into
 462          * op->fqi.fq_fattr (SMB_AT_ALL).  We need those below.
 463          * When of != NULL, goto errout closes it.
 464          */
 465         status = smb_common_open(sr);
 466         if (status != NT_STATUS_SUCCESS)
 467                 goto cmd_done;
 468         of = sr->fid_ofile;
 469 
 470         /*
 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.
 475          */
 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);
 481         }
 482 
 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         /*
 564          * NB: after the above smb_common_open() success,
 565          * we have a handle allocated (sr->fid_ofile).
 566          * If we don't return success, we must close it.
 567          *
 568          * Using sr->smb_fid as the file handle for now,
 569          * though it could later be something larger,
 570          * (16 bytes) similar to an NFSv4 open handle.
 571          */
 572 reconnect_done:
 573         smb2fid.persistent = of->f_persistid;
 574         smb2fid.temporal = sr->smb_fid;
 575 
 576         switch (sr->tid_tree->t_res_type & STYPE_MASK) {
 577         case STYPE_DISKTREE:
 578         case STYPE_PRINTQ:
 579                 if (op->create_options & FILE_DELETE_ON_CLOSE)
 580                         smb_ofile_set_delete_on_close(sr, of);
 581                 break;
 582         }
 583 
 584         /*
 585          * Process any outgoing create contexts that need work
 586          * after the open succeeds.  Encode happens later.











 587          */
 588         if (cctx.cc_in_flags & CCTX_QUERY_MAX_ACCESS) {
 589                 op->maximum_access = 0;

 590                 if (of->f_node != NULL) {
 591                         smb_fsop_eaccess(sr, of->f_cr, of->f_node,
 592                             &op->maximum_access);
 593                 }
 594                 op->maximum_access |= of->f_granted_access;




 595                 cctx.cc_out_flags |= CCTX_QUERY_MAX_ACCESS;
 596         }
 597 
 598         if ((cctx.cc_in_flags & CCTX_QUERY_ON_DISK_ID) != 0 &&
 599             of->f_node != NULL) {
 600                 op->op_fsid = SMB_NODE_FSID(of->f_node);
 601                 cctx.cc_out_flags |= CCTX_QUERY_ON_DISK_ID;
 602         }
 603 
 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         }
 622 
 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;
 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          */
 657         if (cctx.cc_out_flags) {
 658                 sr->raw_data.max_bytes = smb2_max_trans;
 659                 status = smb2_encode_create_ctx(sr, &cctx);
 660                 if (status)
 661                         goto errout;
 662         }
 663 
 664         /*
 665          * Encode the SMB2 Create reply
 666          */
 667         attr = &op->fqi.fq_fattr;
 668         rc = smb_mbc_encodef(
 669             &sr->reply,
 670             "wb.lTTTTqqllqqll",
 671             89, /* StructSize */        /* w */
 672             op->op_oplock_level,     /* b */
 673             op->action_taken,                /* l */
 674             &attr->sa_crtime,            /* T */
 675             &attr->sa_vattr.va_atime,    /* T */
 676             &attr->sa_vattr.va_mtime,    /* T */
 677             &attr->sa_vattr.va_ctime,    /* T */
 678             attr->sa_allocsz,                /* q */
 679             attr->sa_vattr.va_size,  /* q */
 680             attr->sa_dosattr,                /* l */
 681             0, /* reserved2 */          /* l */
 682             smb2fid.persistent,         /* q */
 683             smb2fid.temporal,           /* q */
 684             0,  /* CreateCtxOffset         l */
 685             0); /* CreateCtxLength         l */
 686         if (rc != 0) {
 687                 status = NT_STATUS_UNSUCCESSFUL;
 688                 goto errout;
 689         }
 690 
 691         CreateCtxOffset = sr->reply.chain_offset - sr->smb2_reply_hdr;
 692         CreateCtxLength = MBC_LENGTH(&sr->raw_data);
 693         if (CreateCtxLength != 0) {
 694                 /*
 695                  * Overwrite CreateCtxOffset, CreateCtxLength, pad
 696                  */
 697                 sr->reply.chain_offset -= 8;
 698                 rc = smb_mbc_encodef(
 699                     &sr->reply,
 700                     "ll#C",
 701                     CreateCtxOffset,    /* l */
 702                     CreateCtxLength,    /* l */
 703                     CreateCtxLength,    /* # */
 704                     &sr->raw_data);      /* C */
 705                 if (rc != 0) {
 706                         status = NT_STATUS_UNSUCCESSFUL;
 707                         goto errout;
 708                 }
 709         } else {
 710                 (void) smb_mbc_encodef(&sr->reply, ".");
 711         }

 712 
 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         }
 723         if (cctx.cc_out_flags)
 724                 smb2_free_create_ctx(&cctx);
 725 
 726         return (SDRC_SUCCESS);
 727 }
 728 
 729 /*
 730  * Decode an SMB2 Create Context buffer into our internal form.
 731  * Avoid policy decisions about what's supported here, just decode.
 732  */
 733 static uint32_t
 734 smb2_decode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc)
 735 {
 736         smb_arg_open_t *op = &sr->arg.open;
 737         smb2_create_ctx_elem_t *cce;
 738         mbuf_chain_t *in_mbc = &cc->cc_in_mbc;
 739         mbuf_chain_t name_mbc;
 740         union {
 741                 uint32_t i;
 742                 char ch[4];
 743         } cc_name;
 744         uint32_t status;
 745         int32_t next_off;
 746         uint32_t data_len;
 747         uint16_t data_off;
 748         uint16_t name_off;
 749         uint16_t name_len;
 750         int top_offset;
 751         int rc;
 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          */
 758         status = NT_STATUS_INVALID_PARAMETER;
 759         for (;;) {
 760                 cce = NULL;
 761                 top_offset = in_mbc->chain_offset;
 762                 rc = smb_mbc_decodef(
 763                     in_mbc,
 764                     "lww..wl",
 765                     &next_off,      /* l */
 766                     &name_off,      /* w */
 767                     &name_len,      /* w */
 768                     /* reserved   .. */
 769                     &data_off,      /* w */
 770                     &data_len); /* l */
 771                 if (rc)
 772                         break;
 773 
 774                 /*
 775                  * The Create Context "name", per [MS-SMB] 2.2.13.2
 776                  * They're defined as network-order integers for our
 777                  * switch below.  We don't have routines to decode


 809                 case SMB2_CREATE_ALLOCATION_SIZE:       /* ("AISi") */
 810                         cc->cc_in_flags |= CCTX_ALLOCATION_SIZE;
 811                         cce = &cc->cc_in_alloc_size;
 812                         break;
 813                 case SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ: /* ("MxAc") */
 814                         cc->cc_in_flags |= CCTX_QUERY_MAX_ACCESS;
 815                         /* no input data for this */
 816                         break;
 817                 case SMB2_CREATE_TIMEWARP_TOKEN:        /* ("TWrp") */
 818                         cc->cc_in_flags |= CCTX_TIMEWARP_TOKEN;
 819                         cce = &cc->cc_in_time_warp;
 820                         break;
 821                 case SMB2_CREATE_QUERY_ON_DISK_ID:      /* ("QFid") */
 822                         cc->cc_in_flags |= CCTX_QUERY_ON_DISK_ID;
 823                         /* no input data for this */
 824                         break;
 825                 case SMB2_CREATE_REQUEST_LEASE:         /* ("RqLs") */
 826                         cc->cc_in_flags |= CCTX_REQUEST_LEASE;
 827                         cce = &cc->cc_in_req_lease;
 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;
 845                 default:
 846                         /*
 847                          * Unknown create context values are normal, and
 848                          * should be ignored.  However, in debug mode,
 849                          * let's log them so we know which ones we're
 850                          * not handling (and may want to add).
 851                          */
 852 #ifdef  DEBUG
 853                         cmn_err(CE_NOTE, "unknown create context ID 0x%x",
 854                             cc_name.i);
 855 #endif
 856                         cce = NULL;
 857                         break;
 858                 }
 859 
 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;
 979                 }
 980 
 981         next_cc:
 982                 if (next_off == 0) {
 983                         /* Normal loop termination */
 984                         status = 0;
 985                         break;
 986                 }
 987 
 988                 if ((next_off & 7) != 0)
 989                         break;
 990                 if ((top_offset + next_off) < in_mbc->chain_offset)
 991                         break;
 992                 if ((top_offset + next_off) > in_mbc->max_bytes)
 993                         break;
 994                 in_mbc->chain_offset = top_offset + next_off;
 995         }
 996 
 997 errout:
 998         return (status);
 999 }
1000 
1001 /*
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.
1015  */

1016 static uint32_t
1017 smb2_encode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc)
1018 {
1019         smb_arg_open_t *op = &sr->arg.open;
1020         smb2_create_ctx_elem_t *cce;
1021         mbuf_chain_t *mbc = &sr->raw_data;
1022         int last_top = -1;
1023         int rc;
1024 
1025         if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) {
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 
1032                 last_top = mbc->chain_offset;
1033                 rc = smb2_encode_create_ctx_elem(mbc, cce,
1034                     SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ);
1035                 if (rc)
1036                         return (NT_STATUS_INTERNAL_ERROR);
1037                 (void) smb_mbc_poke(mbc, last_top, "l",
1038                     mbc->chain_offset - last_top);
1039         }
1040 
1041         if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) {
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 
1052                 last_top = mbc->chain_offset;
1053                 rc = smb2_encode_create_ctx_elem(mbc, cce,
1054                     SMB2_CREATE_QUERY_ON_DISK_ID);
1055                 if (rc)
1056                         return (NT_STATUS_INTERNAL_ERROR);
1057                 (void) smb_mbc_poke(mbc, last_top, "l",
1058                     mbc->chain_offset - last_top);
1059         }
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 
1133         if (last_top >= 0)
1134                 (void) smb_mbc_poke(mbc, last_top, "l", 0);
1135 
1136         return (0);
1137 }
1138 
1139 static int
1140 smb2_encode_create_ctx_elem(mbuf_chain_t *out_mbc,
1141     smb2_create_ctx_elem_t *cce, uint32_t id)
1142 {
1143         union {
1144                 uint32_t i;
1145                 char ch[4];
1146         } cc_name;
1147         int rc;
1148 
1149         /* as above */
1150         cc_name.i = htonl(id);
1151 
1152         /*
1153          * This is the header, per [MS-SMB2] 2.2.13.2
1154          * Sorry about the fixed offsets.  We know we'll
1155          * layout the data part as [name, payload] and
1156          * name is a fixed length, so this easy.
1157          * The final layout looks like this:
1158          *      a: this header (16 bytes)
1159          *      b: the name (4 bytes, 4 pad)
1160          *      c: the payload (variable)
1161          *      d: padding (to align 8)
1162          *
1163          * Note that "Next elem." is filled in later.
1164          */
1165         rc = smb_mbc_encodef(
1166             out_mbc, "lwwwwl",
1167             0,          /* Next offset  l */
1168             16,         /* NameOffset   w */
1169             4,          /* NameLength   w */
1170             0,          /* Reserved     w */
1171             24,         /* DataOffset   w */
1172             cce->cce_len); /* DataLen        l */
1173         if (rc)
1174                 return (rc);
1175 
1176         /*
1177          * Now the "name" and payload.
1178          */
1179         rc = smb_mbc_encodef(
1180             out_mbc, "4c4.#C",
1181             cc_name.ch,         /* 4c4. */
1182             cce->cce_len,    /* # */
1183             &cce->cce_mbc);      /* C */
1184 
1185         (void) smb_mbc_put_align(out_mbc, 8);
1186 
1187         return (rc);
1188 }
1189 
1190 static void
1191 smb2_free_create_ctx(smb2_create_ctx_t *cc)
1192 {
1193         smb2_create_ctx_elem_t *cce;
1194 
1195         if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) {
1196                 cce = &cc->cc_out_max_access;
1197                 MBC_FLUSH(&cce->cce_mbc);
1198         }
1199         if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) {
1200                 cce = &cc->cc_out_file_id;
1201                 MBC_FLUSH(&cce->cce_mbc);
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         }
1219 }