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