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