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 2022-2024 RackTop Systems, Inc. 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 * Ignore lease or oplock requests for anything other than 474 * plain files. The share type was checked above, but the 475 * node pointer of->f_node is only valid for "disk" files. 476 */ 477 if (of->f_ftype != SMB_FTYPE_DISK || 478 !smb_node_is_file(of->f_node)) { 479 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE; 480 cctx.cc_in_flags &= ~CCTX_REQUEST_LEASE; 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 * If requested and allowed, make this a durable open; 504 * see comment above smb_dh_create_allowed() for more detail. 505 * 506 * Otherwise, DH requests are ignored, so we set 507 * dh_vers = not durable 508 */ 509 if ((cctx.cc_in_flags & 510 (CCTX_DH_REQUEST|CCTX_DH_REQUEST_V2)) != 0 && 511 smb_dh_create_allowed(sr, of)) { 512 /* 513 * OK, make this handle "durable" 514 */ 515 if (op->dh_vers == SMB2_DURABLE_V2) { 516 (void) memcpy(of->dh_create_guid, 517 op->create_guid, UUID_LEN); 518 519 if ((op->dh_v2_flags & DH_PERSISTENT) != 0) { 520 if (smb2_dh_make_persistent(sr, of) == 0) { 521 of->dh_persist = B_TRUE; 522 } else { 523 op->dh_v2_flags = 0; 524 } 525 } 526 } 527 if (op->dh_vers != SMB2_NOT_DURABLE) { 528 uint32_t msto; 529 530 of->dh_vers = op->dh_vers; 531 of->dh_expire_time = 0; 532 533 /* 534 * Client may provide timeout=0 to request 535 * the default timeout (in mSec.) 536 */ 537 msto = op->dh_timeout; 538 if (msto == 0) { 539 msto = (of->dh_persist) ? 540 smb2_persist_timeout : 541 smb2_dh_def_timeout; 542 } 543 if (msto > smb2_dh_max_timeout) 544 msto = smb2_dh_max_timeout; 545 op->dh_timeout = msto; 546 of->dh_timeout_offset = MSEC2NSEC(msto); 547 } 548 } else { 549 op->dh_vers = SMB2_NOT_DURABLE; 550 op->dh_v2_flags = 0; 551 } 552 553 /* 554 * NB: after the above smb_common_open() success, 555 * we have a handle allocated (sr->fid_ofile). 556 * If we don't return success, we must close it. 557 * 558 * Using sr->smb_fid as the file handle for now, 559 * though it could later be something larger, 560 * (16 bytes) similar to an NFSv4 open handle. 561 */ 562 reconnect_done: 563 smb2fid.persistent = of->f_persistid; 564 smb2fid.temporal = sr->smb_fid; 565 566 switch (sr->tid_tree->t_res_type & STYPE_MASK) { 567 case STYPE_DISKTREE: 568 case STYPE_PRINTQ: 569 if (op->create_options & FILE_DELETE_ON_CLOSE) 570 smb_ofile_set_delete_on_close(sr, of); 571 break; 572 } 573 574 /* 575 * Process any outgoing create contexts that need work 576 * after the open succeeds. Encode happens later. 577 */ 578 if (cctx.cc_in_flags & CCTX_QUERY_MAX_ACCESS) { 579 op->maximum_access = 0; 580 if (of->f_node != NULL) { 581 smb_fsop_eaccess(sr, of->f_cr, of->f_node, 582 &op->maximum_access); 583 } 584 op->maximum_access |= of->f_granted_access; 585 cctx.cc_out_flags |= CCTX_QUERY_MAX_ACCESS; 586 } 587 588 if ((cctx.cc_in_flags & CCTX_QUERY_ON_DISK_ID) != 0 && 589 of->f_node != NULL) { 590 op->op_fsid = SMB_NODE_FSID(of->f_node); 591 cctx.cc_out_flags |= CCTX_QUERY_ON_DISK_ID; 592 } 593 594 if ((cctx.cc_in_flags & CCTX_AAPL_EXT) != 0) { 595 cce = &cctx.cc_out_aapl; 596 /* 597 * smb2_aapl_crctx has a variable response depending on 598 * what the incoming context looks like, so it does all 599 * the work of building cc_out_aapl, including setting 600 * cce_len, cce_mbc.max_bytes, and smb_mbc_encode. 601 * If we see errors getting this, simply omit it from 602 * the collection of returned create contexts. 603 */ 604 status = smb2_aapl_crctx(sr, 605 &cctx.cc_in_aapl.cce_mbc, &cce->cce_mbc); 606 if (status == 0) { 607 cce->cce_len = cce->cce_mbc.chain_offset; 608 cctx.cc_out_flags |= CCTX_AAPL_EXT; 609 } 610 status = 0; 611 } 612 613 /* 614 * If a lease was requested, and we got one... 615 */ 616 if ((cctx.cc_in_flags & CCTX_REQUEST_LEASE) != 0 && 617 op->op_oplock_level == SMB2_OPLOCK_LEVEL_LEASE) 618 cctx.cc_out_flags |= CCTX_REQUEST_LEASE; 619 620 /* 621 * If a durable handle was requested and we got one... 622 */ 623 if ((cctx.cc_in_flags & CCTX_DH_REQUEST) != 0 && 624 of->dh_vers == SMB2_DURABLE_V1) { 625 cctx.cc_out_flags |= CCTX_DH_REQUEST; 626 } 627 if ((cctx.cc_in_flags & CCTX_DH_REQUEST_V2) != 0 && 628 of->dh_vers == SMB2_DURABLE_V2) { 629 cctx.cc_out_flags |= CCTX_DH_REQUEST_V2; 630 } 631 632 /* 633 * This marks the end of the "body" section and the 634 * beginning of the "encode" section. Any errors 635 * encoding the response should use: goto errout 636 */ 637 cmd_done: 638 /* Want status visible in the done probe. */ 639 sr->smb2_status = status; 640 DTRACE_SMB2_DONE(op__Create, smb_request_t *, sr); 641 if (status != NT_STATUS_SUCCESS) 642 goto errout; 643 644 /* 645 * Encode all the create contexts to return. 646 */ 647 if (cctx.cc_out_flags) { 648 sr->raw_data.max_bytes = smb2_max_trans; 649 status = smb2_encode_create_ctx(sr, &cctx); 650 if (status) 651 goto errout; 652 } 653 654 /* 655 * Encode the SMB2 Create reply 656 */ 657 attr = &op->fqi.fq_fattr; 658 rc = smb_mbc_encodef( 659 &sr->reply, 660 "wb.lTTTTqqllqqll", 661 89, /* StructSize */ /* w */ 662 op->op_oplock_level, /* b */ 663 op->action_taken, /* l */ 664 &attr->sa_crtime, /* T */ 665 &attr->sa_vattr.va_atime, /* T */ 666 &attr->sa_vattr.va_mtime, /* T */ 667 &attr->sa_vattr.va_ctime, /* T */ 668 attr->sa_allocsz, /* q */ 669 attr->sa_vattr.va_size, /* q */ 670 attr->sa_dosattr, /* l */ 671 0, /* reserved2 */ /* l */ 672 smb2fid.persistent, /* q */ 673 smb2fid.temporal, /* q */ 674 0, /* CreateCtxOffset l */ 675 0); /* CreateCtxLength l */ 676 if (rc != 0) { 677 status = NT_STATUS_UNSUCCESSFUL; 678 goto errout; 679 } 680 681 CreateCtxOffset = sr->reply.chain_offset - sr->smb2_reply_hdr; 682 CreateCtxLength = MBC_LENGTH(&sr->raw_data); 683 if (CreateCtxLength != 0) { 684 /* 685 * Overwrite CreateCtxOffset, CreateCtxLength, pad 686 */ 687 sr->reply.chain_offset -= 8; 688 rc = smb_mbc_encodef( 689 &sr->reply, 690 "ll#C", 691 CreateCtxOffset, /* l */ 692 CreateCtxLength, /* l */ 693 CreateCtxLength, /* # */ 694 &sr->raw_data); /* C */ 695 if (rc != 0) { 696 status = NT_STATUS_UNSUCCESSFUL; 697 goto errout; 698 } 699 } else { 700 (void) smb_mbc_encodef(&sr->reply, "."); 701 } 702 703 if (status != 0) { 704 errout: 705 if (of != NULL) 706 smb_ofile_close(of, 0); 707 smb2sr_put_error(sr, status); 708 } 709 if (op->sd != NULL) { 710 smb_sd_term(op->sd); 711 kmem_free(op->sd, sizeof (*op->sd)); 712 } 713 if (cctx.cc_out_flags) 714 smb2_free_create_ctx(&cctx); 715 716 return (SDRC_SUCCESS); 717 } 718 719 /* 720 * Decode an SMB2 Create Context buffer into our internal form. 721 * Avoid policy decisions about what's supported here, just decode. 722 */ 723 static uint32_t 724 smb2_decode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc) 725 { 726 smb_arg_open_t *op = &sr->arg.open; 727 smb2_create_ctx_elem_t *cce; 728 mbuf_chain_t *in_mbc = &cc->cc_in_mbc; 729 mbuf_chain_t name_mbc; 730 union { 731 uint32_t i; 732 char ch[4]; 733 } cc_name; 734 uint32_t status; 735 int32_t next_off; 736 uint32_t data_len; 737 uint16_t data_off; 738 uint16_t name_off; 739 uint16_t name_len; 740 int top_offset; 741 int rc; 742 743 /* 744 * Any break from the loop below before we've decoded 745 * the entire create context means it was malformatted, 746 * so we should return INVALID_PARAMETER. 747 */ 748 status = NT_STATUS_INVALID_PARAMETER; 749 for (;;) { 750 cce = NULL; 751 top_offset = in_mbc->chain_offset; 752 rc = smb_mbc_decodef( 753 in_mbc, 754 "lww..wl", 755 &next_off, /* l */ 756 &name_off, /* w */ 757 &name_len, /* w */ 758 /* reserved .. */ 759 &data_off, /* w */ 760 &data_len); /* l */ 761 if (rc) 762 break; 763 764 /* 765 * The Create Context "name", per [MS-SMB] 2.2.13.2 766 * They're defined as network-order integers for our 767 * switch below. We don't have routines to decode 768 * native order, so read as char[4] then ntohl. 769 * NB: in SMB3, some of these are 8 bytes. 770 */ 771 if ((top_offset + name_off) < in_mbc->chain_offset) 772 break; 773 rc = MBC_SHADOW_CHAIN(&name_mbc, in_mbc, 774 top_offset + name_off, name_len); 775 if (rc) 776 break; 777 rc = smb_mbc_decodef(&name_mbc, "4c", &cc_name); 778 if (rc) 779 break; 780 cc_name.i = ntohl(cc_name.i); 781 782 switch (cc_name.i) { 783 case SMB2_CREATE_EA_BUFFER: /* ("ExtA") */ 784 cc->cc_in_flags |= CCTX_EA_BUFFER; 785 cce = &cc->cc_in_ext_attr; 786 break; 787 case SMB2_CREATE_SD_BUFFER: /* ("SecD") */ 788 cc->cc_in_flags |= CCTX_SD_BUFFER; 789 cce = &cc->cc_in_sec_desc; 790 break; 791 case SMB2_CREATE_DURABLE_HANDLE_REQUEST: /* ("DHnQ") */ 792 cc->cc_in_flags |= CCTX_DH_REQUEST; 793 cce = &cc->cc_in_dh_request; 794 break; 795 case SMB2_CREATE_DURABLE_HANDLE_RECONNECT: /* ("DHnC") */ 796 cc->cc_in_flags |= CCTX_DH_RECONNECT; 797 cce = &cc->cc_in_dh_reconnect; 798 break; 799 case SMB2_CREATE_ALLOCATION_SIZE: /* ("AISi") */ 800 cc->cc_in_flags |= CCTX_ALLOCATION_SIZE; 801 cce = &cc->cc_in_alloc_size; 802 break; 803 case SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ: /* ("MxAc") */ 804 cc->cc_in_flags |= CCTX_QUERY_MAX_ACCESS; 805 /* Optional input data for this CC. See below. */ 806 cce = &cc->cc_in_max_access; 807 break; 808 case SMB2_CREATE_TIMEWARP_TOKEN: /* ("TWrp") */ 809 cc->cc_in_flags |= CCTX_TIMEWARP_TOKEN; 810 cce = &cc->cc_in_time_warp; 811 break; 812 case SMB2_CREATE_QUERY_ON_DISK_ID: /* ("QFid") */ 813 cc->cc_in_flags |= CCTX_QUERY_ON_DISK_ID; 814 /* no input data for this */ 815 break; 816 case SMB2_CREATE_REQUEST_LEASE: /* ("RqLs") */ 817 cc->cc_in_flags |= CCTX_REQUEST_LEASE; 818 cce = &cc->cc_in_req_lease; 819 break; 820 case SMB2_CREATE_CTX_AAPL: /* ("AAPL") */ 821 cc->cc_in_flags |= CCTX_AAPL_EXT; 822 cce = &cc->cc_in_aapl; 823 break; 824 case SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2: /* ("DH2Q") */ 825 cc->cc_in_flags |= CCTX_DH_REQUEST_V2; 826 cce = &cc->cc_in_dh_request_v2; 827 break; 828 case SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2: /* ("DH2C") */ 829 cc->cc_in_flags |= CCTX_DH_RECONNECT_V2; 830 cce = &cc->cc_in_dh_reconnect_v2; 831 break; 832 833 /* 834 * Known but not implemented context IDs. 835 * Here just to silence the debug below. 836 * 837 * Note: all three of these IDs are actually longer, 838 * but we start by decoding just the first 4 bytes. 839 * If/when we recognize these, do another match on 840 * the full ID after we take this switch case. 841 */ 842 case 0x45bca66a: /* SMB2_CREATE_APP_INSTANCE_ID */ 843 case 0xB982D0B7: /* SMB2_CREATE_APP_INSTANCE_VERSION */ 844 case 0x9ccbcf9e: /* SVHDX_OPEN_DEVICE_CONTEXT */ 845 cce = NULL; 846 break; 847 848 default: 849 /* 850 * Unknown create context values are normal, and 851 * should be ignored. However, in debug mode, 852 * let's log them so we know which ones we're 853 * not handling (and may want to add). 854 */ 855 #ifdef DEBUG 856 cmn_err(CE_NOTE, "unknown create context ID 0x%x", 857 cc_name.i); 858 #endif 859 cce = NULL; 860 break; 861 } 862 863 if (cce == NULL || data_len == 0) 864 goto next_cc; 865 866 if ((data_off & 7) != 0) 867 break; 868 if ((top_offset + data_off) < in_mbc->chain_offset) 869 break; 870 rc = MBC_SHADOW_CHAIN(&cce->cce_mbc, in_mbc, 871 top_offset + data_off, data_len); 872 if (rc) 873 break; 874 cce->cce_len = data_len; 875 876 /* 877 * Additonal decoding for some create contexts. 878 */ 879 switch (cc_name.i) { 880 uint64_t nttime; 881 882 case SMB2_CREATE_SD_BUFFER: /* ("SecD") */ 883 op->sd = kmem_alloc(sizeof (smb_sd_t), KM_SLEEP); 884 if (smb_decode_sd(&cce->cce_mbc, op->sd) != 0) 885 goto errout; 886 break; 887 888 case SMB2_CREATE_ALLOCATION_SIZE: /* ("AISi") */ 889 rc = smb_mbc_decodef(&cce->cce_mbc, "q", &op->dsize); 890 if (rc != 0) 891 goto errout; 892 break; 893 894 case SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ: /* ("MxAc") */ 895 /* 896 * The SMB spec says this can be either 0 bytes 897 * (handled above) or an 8 byte timestamp value 898 * but does not say what its purpose is. 899 * 900 * Note: The WPTS expects us to validate that it 901 * is at least 8 bytes so we read it and discard 902 * it. If it was too short the decode will fail. 903 */ 904 rc = smb_mbc_decodef(&cce->cce_mbc, "q", &nttime); 905 if (rc != 0) 906 goto errout; 907 break; 908 909 case SMB2_CREATE_TIMEWARP_TOKEN: /* ("TWrp") */ 910 /* 911 * Support for opening "Previous Versions". 912 * [MS-SMB2] 2.2.13.2.7 Data is an NT time. 913 */ 914 rc = smb_mbc_decodef(&cce->cce_mbc, 915 "q", &nttime); 916 if (rc != 0) 917 goto errout; 918 smb_time_nt_to_unix(nttime, &op->timewarp); 919 op->create_timewarp = B_TRUE; 920 break; 921 922 /* 923 * Note: This handles both V1 and V2 leases, 924 * which differ only by their length. 925 */ 926 case SMB2_CREATE_REQUEST_LEASE: /* ("RqLs") */ 927 if (data_len == 52) { 928 op->lease_version = 2; 929 } else if (data_len == 32) { 930 op->lease_version = 1; 931 } else { 932 cmn_err(CE_NOTE, "Cctx RqLs bad len=0x%x", 933 data_len); 934 } 935 rc = smb_mbc_decodef(&cce->cce_mbc, "#cllq", 936 UUID_LEN, /* # */ 937 op->lease_key, /* c */ 938 &op->lease_state, /* l */ 939 &op->lease_flags, /* l */ 940 &nttime); /* (ignored) q */ 941 if (rc != 0) 942 goto errout; 943 if (op->lease_version == 2) { 944 rc = smb_mbc_decodef(&cce->cce_mbc, 945 "#cw..", 946 UUID_LEN, 947 op->parent_lease_key, 948 &op->lease_epoch); 949 if (rc != 0) 950 goto errout; 951 } else { 952 bzero(op->parent_lease_key, UUID_LEN); 953 } 954 break; 955 956 case SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2: /* ("DH2C") */ 957 rc = smb_mbc_decodef(&cce->cce_mbc, "qq#cl", 958 &op->dh_fileid.persistent, /* q */ 959 &op->dh_fileid.temporal, /* q */ 960 UUID_LEN, /* # */ 961 op->create_guid, /* c */ 962 &op->dh_v2_flags); /* l */ 963 if (rc != 0) 964 goto errout; 965 break; 966 967 case SMB2_CREATE_DURABLE_HANDLE_RECONNECT: /* ("DHnC") */ 968 rc = smb_mbc_decodef(&cce->cce_mbc, "qq", 969 &op->dh_fileid.persistent, /* q */ 970 &op->dh_fileid.temporal); /* q */ 971 if (rc != 0) 972 goto errout; 973 bzero(op->create_guid, UUID_LEN); 974 op->dh_v2_flags = 0; 975 break; 976 977 case SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2: /* ("DH2Q") */ 978 rc = smb_mbc_decodef(&cce->cce_mbc, 979 "ll8.#c", 980 &op->dh_timeout, /* l */ 981 &op->dh_v2_flags, /* l */ 982 /* reserved */ /* 8. */ 983 UUID_LEN, /* # */ 984 op->create_guid); /* c */ 985 if (rc != 0) 986 goto errout; 987 break; 988 989 case SMB2_CREATE_DURABLE_HANDLE_REQUEST: /* ("DHnQ") */ 990 rc = smb_mbc_decodef(&cce->cce_mbc, 991 "16."); /* reserved */ 992 if (rc != 0) 993 goto errout; 994 op->dh_timeout = 0; /* default */ 995 op->dh_v2_flags = 0; 996 break; 997 } 998 999 next_cc: 1000 if (next_off == 0) { 1001 /* Normal loop termination */ 1002 status = 0; 1003 break; 1004 } 1005 1006 if ((next_off & 7) != 0) 1007 break; 1008 if ((top_offset + next_off) < in_mbc->chain_offset) 1009 break; 1010 if ((top_offset + next_off) > in_mbc->max_bytes) 1011 break; 1012 in_mbc->chain_offset = top_offset + next_off; 1013 } 1014 1015 errout: 1016 return (status); 1017 } 1018 1019 /* 1020 * Encode an SMB2 Create Context buffer from our internal form. 1021 * 1022 * Build the Create Context to return; first the 1023 * per-element parts, then the aggregated buffer. 1024 * 1025 * No response for these: 1026 * CCTX_EA_BUFFER 1027 * CCTX_SD_BUFFER 1028 * CCTX_ALLOCATION_SIZE 1029 * CCTX_TIMEWARP_TOKEN 1030 * 1031 * Remember to add code sections to smb2_free_create_ctx() 1032 * for each section here that encodes a context element. 1033 */ 1034 static uint32_t 1035 smb2_encode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc) 1036 { 1037 smb_arg_open_t *op = &sr->arg.open; 1038 smb2_create_ctx_elem_t *cce; 1039 mbuf_chain_t *mbc = &sr->raw_data; 1040 int last_top = -1; 1041 int rc; 1042 1043 if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) { 1044 cce = &cc->cc_out_max_access; 1045 1046 cce->cce_mbc.max_bytes = cce->cce_len = 8; 1047 (void) smb_mbc_encodef(&cce->cce_mbc, 1048 "ll", 0, op->maximum_access); 1049 1050 last_top = mbc->chain_offset; 1051 rc = smb2_encode_create_ctx_elem(mbc, cce, 1052 SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ); 1053 if (rc) 1054 return (NT_STATUS_INTERNAL_ERROR); 1055 (void) smb_mbc_poke(mbc, last_top, "l", 1056 mbc->chain_offset - last_top); 1057 } 1058 1059 if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) { 1060 cce = &cc->cc_out_file_id; 1061 1062 cce->cce_mbc.max_bytes = cce->cce_len = 32; 1063 (void) smb_mbc_encodef( 1064 &cce->cce_mbc, "qll.15.", 1065 op->fileid, /* q */ 1066 op->op_fsid.val[0], /* l */ 1067 op->op_fsid.val[1]); /* l */ 1068 /* reserved (16 bytes) .15. */ 1069 1070 last_top = mbc->chain_offset; 1071 rc = smb2_encode_create_ctx_elem(mbc, cce, 1072 SMB2_CREATE_QUERY_ON_DISK_ID); 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_AAPL_EXT) { 1080 cce = &cc->cc_out_aapl; 1081 /* cc_out_aapl already encoded */ 1082 1083 last_top = mbc->chain_offset; 1084 rc = smb2_encode_create_ctx_elem(mbc, cce, 1085 SMB2_CREATE_CTX_AAPL); 1086 if (rc) 1087 return (NT_STATUS_INTERNAL_ERROR); 1088 (void) smb_mbc_poke(mbc, last_top, "l", 1089 mbc->chain_offset - last_top); 1090 } 1091 1092 if (cc->cc_out_flags & CCTX_REQUEST_LEASE) { 1093 cce = &cc->cc_out_req_lease; 1094 1095 cce->cce_mbc.max_bytes = cce->cce_len = 32; 1096 (void) smb_mbc_encodef(&cce->cce_mbc, "#cllq", 1097 UUID_LEN, /* # */ 1098 op->lease_key, /* c */ 1099 op->lease_state, /* l */ 1100 op->lease_flags, /* l */ 1101 0LL); /* q */ 1102 if (op->lease_version == 2) { 1103 cce->cce_mbc.max_bytes = cce->cce_len = 52; 1104 (void) smb_mbc_encodef(&cce->cce_mbc, 1105 "#cw..", 1106 UUID_LEN, 1107 op->parent_lease_key, 1108 op->lease_epoch); 1109 } 1110 1111 last_top = mbc->chain_offset; 1112 rc = smb2_encode_create_ctx_elem(mbc, cce, 1113 SMB2_CREATE_REQUEST_LEASE); 1114 if (rc) 1115 return (NT_STATUS_INTERNAL_ERROR); 1116 (void) smb_mbc_poke(mbc, last_top, "l", 1117 mbc->chain_offset - last_top); 1118 } 1119 1120 if (cc->cc_out_flags & CCTX_DH_REQUEST) { 1121 cce = &cc->cc_out_dh_request; 1122 1123 cce->cce_mbc.max_bytes = cce->cce_len = 8; 1124 (void) smb_mbc_encodef(&cce->cce_mbc, "q", 0LL); 1125 1126 last_top = mbc->chain_offset; 1127 rc = smb2_encode_create_ctx_elem(mbc, cce, 1128 SMB2_CREATE_DURABLE_HANDLE_REQUEST); 1129 if (rc) 1130 return (NT_STATUS_INTERNAL_ERROR); 1131 (void) smb_mbc_poke(mbc, last_top, "l", 1132 mbc->chain_offset - last_top); 1133 } 1134 1135 if (cc->cc_out_flags & CCTX_DH_REQUEST_V2) { 1136 cce = &cc->cc_out_dh_request_v2; 1137 1138 cce->cce_mbc.max_bytes = cce->cce_len = 8; 1139 (void) smb_mbc_encodef(&cce->cce_mbc, "ll", 1140 op->dh_timeout, op->dh_v2_flags); 1141 1142 last_top = mbc->chain_offset; 1143 rc = smb2_encode_create_ctx_elem(mbc, cce, 1144 SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2); 1145 if (rc) 1146 return (NT_STATUS_INTERNAL_ERROR); 1147 (void) smb_mbc_poke(mbc, last_top, "l", 1148 mbc->chain_offset - last_top); 1149 } 1150 1151 if (last_top >= 0) 1152 (void) smb_mbc_poke(mbc, last_top, "l", 0); 1153 1154 return (0); 1155 } 1156 1157 static int 1158 smb2_encode_create_ctx_elem(mbuf_chain_t *out_mbc, 1159 smb2_create_ctx_elem_t *cce, uint32_t id) 1160 { 1161 union { 1162 uint32_t i; 1163 char ch[4]; 1164 } cc_name; 1165 int rc; 1166 1167 /* as above */ 1168 cc_name.i = htonl(id); 1169 1170 /* 1171 * This is the header, per [MS-SMB2] 2.2.13.2 1172 * Sorry about the fixed offsets. We know we'll 1173 * layout the data part as [name, payload] and 1174 * name is a fixed length, so this easy. 1175 * The final layout looks like this: 1176 * a: this header (16 bytes) 1177 * b: the name (4 bytes, 4 pad) 1178 * c: the payload (variable) 1179 * d: padding (to align 8) 1180 * 1181 * Note that "Next elem." is filled in later. 1182 */ 1183 rc = smb_mbc_encodef( 1184 out_mbc, "lwwwwl", 1185 0, /* Next offset l */ 1186 16, /* NameOffset w */ 1187 4, /* NameLength w */ 1188 0, /* Reserved w */ 1189 24, /* DataOffset w */ 1190 cce->cce_len); /* DataLen l */ 1191 if (rc) 1192 return (rc); 1193 1194 /* 1195 * Now the "name" and payload. 1196 */ 1197 rc = smb_mbc_encodef( 1198 out_mbc, "4c4.#C", 1199 cc_name.ch, /* 4c4. */ 1200 cce->cce_len, /* # */ 1201 &cce->cce_mbc); /* C */ 1202 1203 (void) smb_mbc_put_align(out_mbc, 8); 1204 1205 return (rc); 1206 } 1207 1208 static void 1209 smb2_free_create_ctx(smb2_create_ctx_t *cc) 1210 { 1211 smb2_create_ctx_elem_t *cce; 1212 1213 if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) { 1214 cce = &cc->cc_out_max_access; 1215 MBC_FLUSH(&cce->cce_mbc); 1216 } 1217 if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) { 1218 cce = &cc->cc_out_file_id; 1219 MBC_FLUSH(&cce->cce_mbc); 1220 } 1221 if (cc->cc_out_flags & CCTX_AAPL_EXT) { 1222 cce = &cc->cc_out_aapl; 1223 MBC_FLUSH(&cce->cce_mbc); 1224 } 1225 if (cc->cc_out_flags & CCTX_REQUEST_LEASE) { 1226 cce = &cc->cc_out_req_lease; 1227 MBC_FLUSH(&cce->cce_mbc); 1228 } 1229 if (cc->cc_out_flags & CCTX_DH_REQUEST) { 1230 cce = &cc->cc_out_dh_request; 1231 MBC_FLUSH(&cce->cce_mbc); 1232 } 1233 if (cc->cc_out_flags & CCTX_DH_REQUEST_V2) { 1234 cce = &cc->cc_out_dh_request_v2; 1235 MBC_FLUSH(&cce->cce_mbc); 1236 } 1237 } 1238