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 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 * [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 832 /* 833 * Known but not implemented context IDs. 834 * Here just to silence the debug below. 835 * 836 * Note: all three of these IDs are actually longer, 837 * but we start by decoding just the first 4 bytes. 838 * If/when we recognize these, do another match on 839 * the full ID after we take this switch case. 840 */ 841 case 0x45bca66a: /* SMB2_CREATE_APP_INSTANCE_ID */ 842 case 0xB982D0B7: /* SMB2_CREATE_APP_INSTANCE_VERSION */ 843 case 0x9ccbcf9e: /* SVHDX_OPEN_DEVICE_CONTEXT */ 844 cce = NULL; 845 break; 846 847 default: 848 /* 849 * Unknown create context values are normal, and 850 * should be ignored. However, in debug mode, 851 * let's log them so we know which ones we're 852 * not handling (and may want to add). 853 */ 854 #ifdef DEBUG 855 cmn_err(CE_NOTE, "unknown create context ID 0x%x", 856 cc_name.i); 857 #endif 858 cce = NULL; 859 break; 860 } 861 862 if (cce == NULL || data_len == 0) 863 goto next_cc; 864 865 if ((data_off & 7) != 0) 866 break; 867 if ((top_offset + data_off) < in_mbc->chain_offset) 868 break; 869 rc = MBC_SHADOW_CHAIN(&cce->cce_mbc, in_mbc, 870 top_offset + data_off, data_len); 871 if (rc) 872 break; 873 cce->cce_len = data_len; 874 875 /* 876 * Additonal decoding for some create contexts. 877 */ 878 switch (cc_name.i) { 879 uint64_t nttime; 880 881 case SMB2_CREATE_SD_BUFFER: /* ("SecD") */ 882 op->sd = kmem_alloc(sizeof (smb_sd_t), KM_SLEEP); 883 if (smb_decode_sd(&cce->cce_mbc, op->sd) != 0) 884 goto errout; 885 break; 886 887 case SMB2_CREATE_ALLOCATION_SIZE: /* ("AISi") */ 888 rc = smb_mbc_decodef(&cce->cce_mbc, "q", &op->dsize); 889 if (rc != 0) 890 goto errout; 891 break; 892 893 case SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ: /* ("MxAc") */ 894 /* 895 * The SMB spec says this can be either 0 bytes 896 * (handled above) or an 8 byte timestamp value 897 * but does not say what its purpose is. 898 * 899 * Note: The WPTS expects us to validate that it 900 * is at least 8 bytes so we read it and discard 901 * it. If it was too short the decode will fail. 902 */ 903 rc = smb_mbc_decodef(&cce->cce_mbc, "q", &nttime); 904 if (rc != 0) 905 goto errout; 906 break; 907 908 case SMB2_CREATE_TIMEWARP_TOKEN: /* ("TWrp") */ 909 /* 910 * Support for opening "Previous Versions". 911 * [MS-SMB2] 2.2.13.2.7 Data is an NT time. 912 */ 913 rc = smb_mbc_decodef(&cce->cce_mbc, 914 "q", &nttime); 915 if (rc != 0) 916 goto errout; 917 smb_time_nt_to_unix(nttime, &op->timewarp); 918 op->create_timewarp = B_TRUE; 919 break; 920 921 /* 922 * Note: This handles both V1 and V2 leases, 923 * which differ only by their length. 924 */ 925 case SMB2_CREATE_REQUEST_LEASE: /* ("RqLs") */ 926 if (data_len == 52) { 927 op->lease_version = 2; 928 } else if (data_len == 32) { 929 op->lease_version = 1; 930 } else { 931 cmn_err(CE_NOTE, "Cctx RqLs bad len=0x%x", 932 data_len); 933 } 934 rc = smb_mbc_decodef(&cce->cce_mbc, "#cllq", 935 UUID_LEN, /* # */ 936 op->lease_key, /* c */ 937 &op->lease_state, /* l */ 938 &op->lease_flags, /* l */ 939 &nttime); /* (ignored) q */ 940 if (rc != 0) 941 goto errout; 942 if (op->lease_version == 2) { 943 rc = smb_mbc_decodef(&cce->cce_mbc, 944 "#cw..", 945 UUID_LEN, 946 op->parent_lease_key, 947 &op->lease_epoch); 948 if (rc != 0) 949 goto errout; 950 } else { 951 bzero(op->parent_lease_key, UUID_LEN); 952 } 953 break; 954 955 case SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2: /* ("DH2C") */ 956 rc = smb_mbc_decodef(&cce->cce_mbc, "qq#cl", 957 &op->dh_fileid.persistent, /* q */ 958 &op->dh_fileid.temporal, /* q */ 959 UUID_LEN, /* # */ 960 op->create_guid, /* c */ 961 &op->dh_v2_flags); /* l */ 962 if (rc != 0) 963 goto errout; 964 break; 965 966 case SMB2_CREATE_DURABLE_HANDLE_RECONNECT: /* ("DHnC") */ 967 rc = smb_mbc_decodef(&cce->cce_mbc, "qq", 968 &op->dh_fileid.persistent, /* q */ 969 &op->dh_fileid.temporal); /* q */ 970 if (rc != 0) 971 goto errout; 972 bzero(op->create_guid, UUID_LEN); 973 op->dh_v2_flags = 0; 974 break; 975 976 case SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2: /* ("DH2Q") */ 977 rc = smb_mbc_decodef(&cce->cce_mbc, 978 "ll8.#c", 979 &op->dh_timeout, /* l */ 980 &op->dh_v2_flags, /* l */ 981 /* reserved */ /* 8. */ 982 UUID_LEN, /* # */ 983 op->create_guid); /* c */ 984 if (rc != 0) 985 goto errout; 986 break; 987 988 case SMB2_CREATE_DURABLE_HANDLE_REQUEST: /* ("DHnQ") */ 989 rc = smb_mbc_decodef(&cce->cce_mbc, 990 "16."); /* reserved */ 991 if (rc != 0) 992 goto errout; 993 op->dh_timeout = 0; /* default */ 994 op->dh_v2_flags = 0; 995 break; 996 } 997 998 next_cc: 999 if (next_off == 0) { 1000 /* Normal loop termination */ 1001 status = 0; 1002 break; 1003 } 1004 1005 if ((next_off & 7) != 0) 1006 break; 1007 if ((top_offset + next_off) < in_mbc->chain_offset) 1008 break; 1009 if ((top_offset + next_off) > in_mbc->max_bytes) 1010 break; 1011 in_mbc->chain_offset = top_offset + next_off; 1012 } 1013 1014 errout: 1015 return (status); 1016 } 1017 1018 /* 1019 * Encode an SMB2 Create Context buffer from our internal form. 1020 * 1021 * Build the Create Context to return; first the 1022 * per-element parts, then the aggregated buffer. 1023 * 1024 * No response for these: 1025 * CCTX_EA_BUFFER 1026 * CCTX_SD_BUFFER 1027 * CCTX_ALLOCATION_SIZE 1028 * CCTX_TIMEWARP_TOKEN 1029 * 1030 * Remember to add code sections to smb2_free_create_ctx() 1031 * for each section here that encodes a context element. 1032 */ 1033 static uint32_t 1034 smb2_encode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc) 1035 { 1036 smb_arg_open_t *op = &sr->arg.open; 1037 smb2_create_ctx_elem_t *cce; 1038 mbuf_chain_t *mbc = &sr->raw_data; 1039 int last_top = -1; 1040 int rc; 1041 1042 if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) { 1043 cce = &cc->cc_out_max_access; 1044 1045 cce->cce_mbc.max_bytes = cce->cce_len = 8; 1046 (void) smb_mbc_encodef(&cce->cce_mbc, 1047 "ll", 0, op->maximum_access); 1048 1049 last_top = mbc->chain_offset; 1050 rc = smb2_encode_create_ctx_elem(mbc, cce, 1051 SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ); 1052 if (rc) 1053 return (NT_STATUS_INTERNAL_ERROR); 1054 (void) smb_mbc_poke(mbc, last_top, "l", 1055 mbc->chain_offset - last_top); 1056 } 1057 1058 if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) { 1059 cce = &cc->cc_out_file_id; 1060 1061 cce->cce_mbc.max_bytes = cce->cce_len = 32; 1062 (void) smb_mbc_encodef( 1063 &cce->cce_mbc, "qll.15.", 1064 op->fileid, /* q */ 1065 op->op_fsid.val[0], /* l */ 1066 op->op_fsid.val[1]); /* l */ 1067 /* reserved (16 bytes) .15. */ 1068 1069 last_top = mbc->chain_offset; 1070 rc = smb2_encode_create_ctx_elem(mbc, cce, 1071 SMB2_CREATE_QUERY_ON_DISK_ID); 1072 if (rc) 1073 return (NT_STATUS_INTERNAL_ERROR); 1074 (void) smb_mbc_poke(mbc, last_top, "l", 1075 mbc->chain_offset - last_top); 1076 } 1077 1078 if (cc->cc_out_flags & CCTX_AAPL_EXT) { 1079 cce = &cc->cc_out_aapl; 1080 /* cc_out_aapl already encoded */ 1081 1082 last_top = mbc->chain_offset; 1083 rc = smb2_encode_create_ctx_elem(mbc, cce, 1084 SMB2_CREATE_CTX_AAPL); 1085 if (rc) 1086 return (NT_STATUS_INTERNAL_ERROR); 1087 (void) smb_mbc_poke(mbc, last_top, "l", 1088 mbc->chain_offset - last_top); 1089 } 1090 1091 if (cc->cc_out_flags & CCTX_REQUEST_LEASE) { 1092 cce = &cc->cc_out_req_lease; 1093 1094 cce->cce_mbc.max_bytes = cce->cce_len = 32; 1095 (void) smb_mbc_encodef(&cce->cce_mbc, "#cllq", 1096 UUID_LEN, /* # */ 1097 op->lease_key, /* c */ 1098 op->lease_state, /* l */ 1099 op->lease_flags, /* l */ 1100 0LL); /* q */ 1101 if (op->lease_version == 2) { 1102 cce->cce_mbc.max_bytes = cce->cce_len = 52; 1103 (void) smb_mbc_encodef(&cce->cce_mbc, 1104 "#cw..", 1105 UUID_LEN, 1106 op->parent_lease_key, 1107 op->lease_epoch); 1108 } 1109 1110 last_top = mbc->chain_offset; 1111 rc = smb2_encode_create_ctx_elem(mbc, cce, 1112 SMB2_CREATE_REQUEST_LEASE); 1113 if (rc) 1114 return (NT_STATUS_INTERNAL_ERROR); 1115 (void) smb_mbc_poke(mbc, last_top, "l", 1116 mbc->chain_offset - last_top); 1117 } 1118 1119 if (cc->cc_out_flags & CCTX_DH_REQUEST) { 1120 cce = &cc->cc_out_dh_request; 1121 1122 cce->cce_mbc.max_bytes = cce->cce_len = 8; 1123 (void) smb_mbc_encodef(&cce->cce_mbc, "q", 0LL); 1124 1125 last_top = mbc->chain_offset; 1126 rc = smb2_encode_create_ctx_elem(mbc, cce, 1127 SMB2_CREATE_DURABLE_HANDLE_REQUEST); 1128 if (rc) 1129 return (NT_STATUS_INTERNAL_ERROR); 1130 (void) smb_mbc_poke(mbc, last_top, "l", 1131 mbc->chain_offset - last_top); 1132 } 1133 1134 if (cc->cc_out_flags & CCTX_DH_REQUEST_V2) { 1135 cce = &cc->cc_out_dh_request_v2; 1136 1137 cce->cce_mbc.max_bytes = cce->cce_len = 8; 1138 (void) smb_mbc_encodef(&cce->cce_mbc, "ll", 1139 op->dh_timeout, op->dh_v2_flags); 1140 1141 last_top = mbc->chain_offset; 1142 rc = smb2_encode_create_ctx_elem(mbc, cce, 1143 SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2); 1144 if (rc) 1145 return (NT_STATUS_INTERNAL_ERROR); 1146 (void) smb_mbc_poke(mbc, last_top, "l", 1147 mbc->chain_offset - last_top); 1148 } 1149 1150 if (last_top >= 0) 1151 (void) smb_mbc_poke(mbc, last_top, "l", 0); 1152 1153 return (0); 1154 } 1155 1156 static int 1157 smb2_encode_create_ctx_elem(mbuf_chain_t *out_mbc, 1158 smb2_create_ctx_elem_t *cce, uint32_t id) 1159 { 1160 union { 1161 uint32_t i; 1162 char ch[4]; 1163 } cc_name; 1164 int rc; 1165 1166 /* as above */ 1167 cc_name.i = htonl(id); 1168 1169 /* 1170 * This is the header, per [MS-SMB2] 2.2.13.2 1171 * Sorry about the fixed offsets. We know we'll 1172 * layout the data part as [name, payload] and 1173 * name is a fixed length, so this easy. 1174 * The final layout looks like this: 1175 * a: this header (16 bytes) 1176 * b: the name (4 bytes, 4 pad) 1177 * c: the payload (variable) 1178 * d: padding (to align 8) 1179 * 1180 * Note that "Next elem." is filled in later. 1181 */ 1182 rc = smb_mbc_encodef( 1183 out_mbc, "lwwwwl", 1184 0, /* Next offset l */ 1185 16, /* NameOffset w */ 1186 4, /* NameLength w */ 1187 0, /* Reserved w */ 1188 24, /* DataOffset w */ 1189 cce->cce_len); /* DataLen l */ 1190 if (rc) 1191 return (rc); 1192 1193 /* 1194 * Now the "name" and payload. 1195 */ 1196 rc = smb_mbc_encodef( 1197 out_mbc, "4c4.#C", 1198 cc_name.ch, /* 4c4. */ 1199 cce->cce_len, /* # */ 1200 &cce->cce_mbc); /* C */ 1201 1202 (void) smb_mbc_put_align(out_mbc, 8); 1203 1204 return (rc); 1205 } 1206 1207 static void 1208 smb2_free_create_ctx(smb2_create_ctx_t *cc) 1209 { 1210 smb2_create_ctx_elem_t *cce; 1211 1212 if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) { 1213 cce = &cc->cc_out_max_access; 1214 MBC_FLUSH(&cce->cce_mbc); 1215 } 1216 if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) { 1217 cce = &cc->cc_out_file_id; 1218 MBC_FLUSH(&cce->cce_mbc); 1219 } 1220 if (cc->cc_out_flags & CCTX_AAPL_EXT) { 1221 cce = &cc->cc_out_aapl; 1222 MBC_FLUSH(&cce->cce_mbc); 1223 } 1224 if (cc->cc_out_flags & CCTX_REQUEST_LEASE) { 1225 cce = &cc->cc_out_req_lease; 1226 MBC_FLUSH(&cce->cce_mbc); 1227 } 1228 if (cc->cc_out_flags & CCTX_DH_REQUEST) { 1229 cce = &cc->cc_out_dh_request; 1230 MBC_FLUSH(&cce->cce_mbc); 1231 } 1232 if (cc->cc_out_flags & CCTX_DH_REQUEST_V2) { 1233 cce = &cc->cc_out_dh_request_v2; 1234 MBC_FLUSH(&cce->cce_mbc); 1235 } 1236 } 1237