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 2017 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 op->dh_v2_flags = 0; 284 if ((cctx.cc_in_flags & 285 (CCTX_DH_RECONNECT|CCTX_DH_RECONNECT_V2)) != 0) { 286 287 if ((cctx.cc_in_flags & CCTX_DH_RECONNECT_V2) != 0) 288 op->dh_vers = SMB2_DURABLE_V2; 289 else 290 op->dh_vers = SMB2_DURABLE_V1; 291 292 /* Ignore these create contexts. */ 293 cctx.cc_in_flags &= 294 ~(CCTX_DH_REQUEST | 295 CCTX_DH_REQUEST_V2 | 296 CCTX_EA_BUFFER | 297 CCTX_SD_BUFFER | 298 CCTX_ALLOCATION_SIZE | 299 CCTX_TIMEWARP_TOKEN | 300 CCTX_QUERY_ON_DISK_ID); 301 302 /* 303 * Reconnect check needs to know if a lease was requested. 304 * The requested oplock level is ignored in reconnect, so 305 * using op_oplock_level to convey this info. 306 */ 307 if (cctx.cc_in_flags & CCTX_REQUEST_LEASE) 308 op->op_oplock_level = SMB2_OPLOCK_LEVEL_LEASE; 309 else 310 op->op_oplock_level = 0; 311 312 status = smb2_dh_reconnect(sr); 313 if (status != NT_STATUS_SUCCESS) 314 goto cmd_done; 315 316 /* 317 * Skip most open execution during reconnect, 318 * but need (reclaimed) oplock state in *op. 319 */ 320 of = sr->fid_ofile; 321 smb2_oplock_reconnect(sr); 322 goto reconnect_done; 323 } 324 325 /* 326 * Real create (of a new handle, not reconnect) 327 */ 328 329 /* 330 * Validate the requested oplock level. 331 * Conversion to internal form is in smb2_oplock_acquire() 332 */ 333 switch (op->op_oplock_level) { 334 case SMB2_OPLOCK_LEVEL_NONE: /* OPLOCK_LEVEL_NONE */ 335 case SMB2_OPLOCK_LEVEL_II: /* OPLOCK_LEVEL_TWO */ 336 case SMB2_OPLOCK_LEVEL_EXCLUSIVE: /* OPLOCK_LEVEL_ONE */ 337 case SMB2_OPLOCK_LEVEL_BATCH: /* OPLOCK_LEVEL_BATCH */ 338 /* 339 * Ignore lease create context (if any) 340 */ 341 cctx.cc_in_flags &= ~CCTX_REQUEST_LEASE; 342 break; 343 344 case SMB2_OPLOCK_LEVEL_LEASE: /* OPLOCK_LEVEL_GRANULAR */ 345 /* 346 * Require a lease create context. 347 */ 348 if ((cctx.cc_in_flags & CCTX_REQUEST_LEASE) == 0) { 349 cmn_err(CE_NOTE, "smb2:create, oplock=ff and no lease"); 350 status = NT_STATUS_INVALID_PARAMETER; 351 goto cmd_done; 352 } 353 354 /* 355 * Validate lease request state 356 * Only a few valid combinations. 357 */ 358 switch (op->lease_state) { 359 case SMB2_LEASE_NONE: 360 case SMB2_LEASE_READ_CACHING: 361 case SMB2_LEASE_READ_CACHING | SMB2_LEASE_HANDLE_CACHING: 362 case SMB2_LEASE_READ_CACHING | SMB2_LEASE_WRITE_CACHING: 363 case SMB2_LEASE_READ_CACHING | SMB2_LEASE_WRITE_CACHING | 364 SMB2_LEASE_HANDLE_CACHING: 365 break; 366 367 default: 368 /* 369 * Invalid lease state flags 370 * Just force to "none". 371 */ 372 op->lease_state = SMB2_LEASE_NONE; 373 break; 374 } 375 break; 376 377 default: 378 /* Unknown SMB2 oplock level. */ 379 status = NT_STATUS_INVALID_PARAMETER; 380 goto cmd_done; 381 } 382 383 /* 384 * Only disk trees get oplocks or leases. 385 */ 386 if ((sr->tid_tree->t_res_type & STYPE_MASK) != STYPE_DISKTREE) { 387 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE; 388 cctx.cc_in_flags &= ~CCTX_REQUEST_LEASE; 389 } 390 391 if ((cctx.cc_in_flags & 392 (CCTX_DH_REQUEST|CCTX_DH_REQUEST_V2)) != 0) { 393 if ((cctx.cc_in_flags & CCTX_DH_REQUEST_V2) != 0) 394 op->dh_vers = SMB2_DURABLE_V2; 395 else 396 op->dh_vers = SMB2_DURABLE_V1; 397 } 398 399 if (cctx.cc_in_flags & CCTX_EA_BUFFER) { 400 status = NT_STATUS_EAS_NOT_SUPPORTED; 401 goto cmd_done; 402 } 403 404 /* 405 * ImpersonationLevel (spec. says validate + ignore) 406 * SmbCreateFlags (spec. says ignore) 407 */ 408 409 if ((op->create_options & FILE_DELETE_ON_CLOSE) && 410 !(op->desired_access & DELETE)) { 411 status = NT_STATUS_INVALID_PARAMETER; 412 goto cmd_done; 413 } 414 415 if (op->dattr & FILE_FLAG_WRITE_THROUGH) 416 op->create_options |= FILE_WRITE_THROUGH; 417 if (op->dattr & FILE_FLAG_DELETE_ON_CLOSE) 418 op->create_options |= FILE_DELETE_ON_CLOSE; 419 if (op->dattr & FILE_FLAG_BACKUP_SEMANTICS) 420 op->create_options |= FILE_OPEN_FOR_BACKUP_INTENT; 421 if (op->create_options & FILE_OPEN_FOR_BACKUP_INTENT) 422 sr->user_cr = smb_user_getprivcred(sr->uid_user); 423 if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) { 424 status = NT_STATUS_INVALID_PARAMETER; 425 goto cmd_done; 426 } 427 428 /* 429 * The real open call. Note: this gets attributes into 430 * op->fqi.fq_fattr (SMB_AT_ALL). We need those below. 431 * When of != NULL, goto errout closes it. 432 */ 433 status = smb_common_open(sr); 434 if (status != NT_STATUS_SUCCESS) 435 goto cmd_done; 436 of = sr->fid_ofile; 437 438 /* 439 * Set the "persistent" part of the file ID 440 * (only for DISK shares). Need this even for 441 * non-durable handles in case we get the ioctl 442 * to set "resiliency" on this handle. 443 */ 444 if (of->f_ftype == SMB_FTYPE_DISK) 445 smb_ofile_set_persistid(of); 446 447 /* 448 * [MS-SMB2] 3.3.5.9.8 449 * Handling the SMB2_CREATE_REQUEST_LEASE Create Context 450 */ 451 if ((cctx.cc_in_flags & CCTX_REQUEST_LEASE) != 0) { 452 status = smb2_lease_create(sr); 453 if (status != NT_STATUS_SUCCESS) { 454 if (op->action_taken == SMB_OACT_CREATED) { 455 smb_ofile_set_delete_on_close(sr, of); 456 } 457 goto cmd_done; 458 } 459 } 460 if (op->op_oplock_level == SMB2_OPLOCK_LEVEL_LEASE) { 461 smb2_lease_acquire(sr); 462 } else if (op->op_oplock_level != SMB2_OPLOCK_LEVEL_NONE) { 463 smb2_oplock_acquire(sr); 464 } 465 466 /* 467 * Make this a durable open, but only if: 468 * (durable handle requested and...) 469 * 470 * 1. op_oplock_level == SMB2_OPLOCK_LEVEL_BATCH 471 * 2. A lease is requested with handle caching 472 * - for v1, the lease must not be on a directory 473 * 3. For v2, flags has "persistent" (tree is CA) 474 * (when tree not CA, turned off persist above) 475 * 476 * Otherwise, DH requests are ignored, so we set 477 * dh_vers = not durable 478 */ 479 if ((cctx.cc_in_flags & 480 (CCTX_DH_REQUEST|CCTX_DH_REQUEST_V2)) != 0 && 481 smb_node_is_file(of->f_node) && 482 ((op->op_oplock_level == SMB2_OPLOCK_LEVEL_BATCH) || 483 (op->op_oplock_level == SMB2_OPLOCK_LEVEL_LEASE && 484 (op->lease_state & OPLOCK_LEVEL_CACHE_HANDLE) != 0))) { 485 /* 486 * OK, make this handle "durable" 487 */ 488 if (op->dh_vers == SMB2_DURABLE_V2) { 489 (void) memcpy(of->dh_create_guid, 490 op->create_guid, UUID_LEN); 491 492 /* no persistent handles yet */ 493 of->dh_persist = B_FALSE; 494 } 495 if (op->dh_vers != SMB2_NOT_DURABLE) { 496 uint32_t msto; 497 498 of->dh_vers = op->dh_vers; 499 of->dh_expire_time = 0; 500 501 /* 502 * Client may provide timeout=0 to request 503 * the default timeout (in mSec.) 504 */ 505 msto = op->dh_timeout; 506 if (msto == 0) 507 msto = smb2_dh_def_timeout; 508 if (msto > smb2_dh_max_timeout) 509 msto = smb2_dh_max_timeout; 510 op->dh_timeout = msto; 511 of->dh_timeout_offset = MSEC2NSEC(msto); 512 } 513 } else { 514 op->dh_vers = SMB2_NOT_DURABLE; 515 } 516 517 /* 518 * NB: after the above smb_common_open() success, 519 * we have a handle allocated (sr->fid_ofile). 520 * If we don't return success, we must close it. 521 * 522 * Using sr->smb_fid as the file handle for now, 523 * though it could later be something larger, 524 * (16 bytes) similar to an NFSv4 open handle. 525 */ 526 reconnect_done: 527 smb2fid.persistent = of->f_persistid; 528 smb2fid.temporal = sr->smb_fid; 529 530 switch (sr->tid_tree->t_res_type & STYPE_MASK) { 531 case STYPE_DISKTREE: 532 case STYPE_PRINTQ: 533 if (op->create_options & FILE_DELETE_ON_CLOSE) 534 smb_ofile_set_delete_on_close(sr, of); 535 break; 536 } 537 538 /* 539 * Process any outgoing create contexts that need work 540 * after the open succeeds. Encode happens later. 541 */ 542 if (cctx.cc_in_flags & CCTX_QUERY_MAX_ACCESS) { 543 op->maximum_access = 0; 544 if (of->f_node != NULL) { 545 smb_fsop_eaccess(sr, of->f_cr, of->f_node, 546 &op->maximum_access); 547 } 548 op->maximum_access |= of->f_granted_access; 549 cctx.cc_out_flags |= CCTX_QUERY_MAX_ACCESS; 550 } 551 552 if ((cctx.cc_in_flags & CCTX_QUERY_ON_DISK_ID) != 0 && 553 of->f_node != NULL) { 554 op->op_fsid = SMB_NODE_FSID(of->f_node); 555 cctx.cc_out_flags |= CCTX_QUERY_ON_DISK_ID; 556 } 557 558 if ((cctx.cc_in_flags & CCTX_AAPL_EXT) != 0) { 559 cce = &cctx.cc_out_aapl; 560 /* 561 * smb2_aapl_crctx has a variable response depending on 562 * what the incoming context looks like, so it does all 563 * the work of building cc_out_aapl, including setting 564 * cce_len, cce_mbc.max_bytes, and smb_mbc_encode. 565 * If we see errors getting this, simply omit it from 566 * the collection of returned create contexts. 567 */ 568 status = smb2_aapl_crctx(sr, 569 &cctx.cc_in_aapl.cce_mbc, &cce->cce_mbc); 570 if (status == 0) { 571 cce->cce_len = cce->cce_mbc.chain_offset; 572 cctx.cc_out_flags |= CCTX_AAPL_EXT; 573 } 574 status = 0; 575 } 576 577 /* 578 * If a lease was requested, and we got one... 579 */ 580 if ((cctx.cc_in_flags & CCTX_REQUEST_LEASE) != 0 && 581 op->op_oplock_level == SMB2_OPLOCK_LEVEL_LEASE) 582 cctx.cc_out_flags |= CCTX_REQUEST_LEASE; 583 584 /* 585 * If a durable handle was requested and we got one... 586 */ 587 if ((cctx.cc_in_flags & CCTX_DH_REQUEST) != 0 && 588 of->dh_vers == SMB2_DURABLE_V1) { 589 cctx.cc_out_flags |= CCTX_DH_REQUEST; 590 } 591 if ((cctx.cc_in_flags & CCTX_DH_REQUEST_V2) != 0 && 592 of->dh_vers == SMB2_DURABLE_V2) { 593 cctx.cc_out_flags |= CCTX_DH_REQUEST_V2; 594 } 595 596 /* 597 * This marks the end of the "body" section and the 598 * beginning of the "encode" section. Any errors 599 * encoding the response should use: goto errout 600 */ 601 cmd_done: 602 /* Want status visible in the done probe. */ 603 sr->smb2_status = status; 604 DTRACE_SMB2_DONE(op__Create, smb_request_t *, sr); 605 if (status != NT_STATUS_SUCCESS) 606 goto errout; 607 608 /* 609 * Encode all the create contexts to return. 610 */ 611 if (cctx.cc_out_flags) { 612 sr->raw_data.max_bytes = smb2_max_trans; 613 status = smb2_encode_create_ctx(sr, &cctx); 614 if (status) 615 goto errout; 616 } 617 618 /* 619 * Encode the SMB2 Create reply 620 */ 621 attr = &op->fqi.fq_fattr; 622 rc = smb_mbc_encodef( 623 &sr->reply, 624 "wb.lTTTTqqllqqll", 625 89, /* StructSize */ /* w */ 626 op->op_oplock_level, /* b */ 627 op->action_taken, /* l */ 628 &attr->sa_crtime, /* T */ 629 &attr->sa_vattr.va_atime, /* T */ 630 &attr->sa_vattr.va_mtime, /* T */ 631 &attr->sa_vattr.va_ctime, /* T */ 632 attr->sa_allocsz, /* q */ 633 attr->sa_vattr.va_size, /* q */ 634 attr->sa_dosattr, /* l */ 635 0, /* reserved2 */ /* l */ 636 smb2fid.persistent, /* q */ 637 smb2fid.temporal, /* q */ 638 0, /* CreateCtxOffset l */ 639 0); /* CreateCtxLength l */ 640 if (rc != 0) { 641 status = NT_STATUS_UNSUCCESSFUL; 642 goto errout; 643 } 644 645 CreateCtxOffset = sr->reply.chain_offset - sr->smb2_reply_hdr; 646 CreateCtxLength = MBC_LENGTH(&sr->raw_data); 647 if (CreateCtxLength != 0) { 648 /* 649 * Overwrite CreateCtxOffset, CreateCtxLength, pad 650 */ 651 sr->reply.chain_offset -= 8; 652 rc = smb_mbc_encodef( 653 &sr->reply, 654 "ll#C", 655 CreateCtxOffset, /* l */ 656 CreateCtxLength, /* l */ 657 CreateCtxLength, /* # */ 658 &sr->raw_data); /* C */ 659 if (rc != 0) { 660 status = NT_STATUS_UNSUCCESSFUL; 661 goto errout; 662 } 663 } else { 664 (void) smb_mbc_encodef(&sr->reply, "."); 665 } 666 667 if (status != 0) { 668 errout: 669 if (of != NULL) 670 smb_ofile_close(of, 0); 671 smb2sr_put_error(sr, status); 672 } 673 if (op->sd != NULL) { 674 smb_sd_term(op->sd); 675 kmem_free(op->sd, sizeof (*op->sd)); 676 } 677 if (cctx.cc_out_flags) 678 smb2_free_create_ctx(&cctx); 679 680 return (SDRC_SUCCESS); 681 } 682 683 /* 684 * Decode an SMB2 Create Context buffer into our internal form. 685 * Avoid policy decisions about what's supported here, just decode. 686 */ 687 static uint32_t 688 smb2_decode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc) 689 { 690 smb_arg_open_t *op = &sr->arg.open; 691 smb2_create_ctx_elem_t *cce; 692 mbuf_chain_t *in_mbc = &cc->cc_in_mbc; 693 mbuf_chain_t name_mbc; 694 union { 695 uint32_t i; 696 char ch[4]; 697 } cc_name; 698 uint32_t status; 699 int32_t next_off; 700 uint32_t data_len; 701 uint16_t data_off; 702 uint16_t name_off; 703 uint16_t name_len; 704 int top_offset; 705 int rc; 706 707 /* 708 * Any break from the loop below before we've decoded 709 * the entire create context means it was malformatted, 710 * so we should return INVALID_PARAMETER. 711 */ 712 status = NT_STATUS_INVALID_PARAMETER; 713 for (;;) { 714 cce = NULL; 715 top_offset = in_mbc->chain_offset; 716 rc = smb_mbc_decodef( 717 in_mbc, 718 "lww..wl", 719 &next_off, /* l */ 720 &name_off, /* w */ 721 &name_len, /* w */ 722 /* reserved .. */ 723 &data_off, /* w */ 724 &data_len); /* l */ 725 if (rc) 726 break; 727 728 /* 729 * The Create Context "name", per [MS-SMB] 2.2.13.2 730 * They're defined as network-order integers for our 731 * switch below. We don't have routines to decode 732 * native order, so read as char[4] then ntohl. 733 * NB: in SMB3, some of these are 8 bytes. 734 */ 735 if ((top_offset + name_off) < in_mbc->chain_offset) 736 break; 737 rc = MBC_SHADOW_CHAIN(&name_mbc, in_mbc, 738 top_offset + name_off, name_len); 739 if (rc) 740 break; 741 rc = smb_mbc_decodef(&name_mbc, "4c", &cc_name); 742 if (rc) 743 break; 744 cc_name.i = ntohl(cc_name.i); 745 746 switch (cc_name.i) { 747 case SMB2_CREATE_EA_BUFFER: /* ("ExtA") */ 748 cc->cc_in_flags |= CCTX_EA_BUFFER; 749 cce = &cc->cc_in_ext_attr; 750 break; 751 case SMB2_CREATE_SD_BUFFER: /* ("SecD") */ 752 cc->cc_in_flags |= CCTX_SD_BUFFER; 753 cce = &cc->cc_in_sec_desc; 754 break; 755 case SMB2_CREATE_DURABLE_HANDLE_REQUEST: /* ("DHnQ") */ 756 cc->cc_in_flags |= CCTX_DH_REQUEST; 757 cce = &cc->cc_in_dh_request; 758 break; 759 case SMB2_CREATE_DURABLE_HANDLE_RECONNECT: /* ("DHnC") */ 760 cc->cc_in_flags |= CCTX_DH_RECONNECT; 761 cce = &cc->cc_in_dh_reconnect; 762 break; 763 case SMB2_CREATE_ALLOCATION_SIZE: /* ("AISi") */ 764 cc->cc_in_flags |= CCTX_ALLOCATION_SIZE; 765 cce = &cc->cc_in_alloc_size; 766 break; 767 case SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ: /* ("MxAc") */ 768 cc->cc_in_flags |= CCTX_QUERY_MAX_ACCESS; 769 /* no input data for this */ 770 break; 771 case SMB2_CREATE_TIMEWARP_TOKEN: /* ("TWrp") */ 772 cc->cc_in_flags |= CCTX_TIMEWARP_TOKEN; 773 cce = &cc->cc_in_time_warp; 774 break; 775 case SMB2_CREATE_QUERY_ON_DISK_ID: /* ("QFid") */ 776 cc->cc_in_flags |= CCTX_QUERY_ON_DISK_ID; 777 /* no input data for this */ 778 break; 779 case SMB2_CREATE_REQUEST_LEASE: /* ("RqLs") */ 780 cc->cc_in_flags |= CCTX_REQUEST_LEASE; 781 cce = &cc->cc_in_req_lease; 782 break; 783 case SMB2_CREATE_CTX_AAPL: /* ("AAPL") */ 784 cc->cc_in_flags |= CCTX_AAPL_EXT; 785 cce = &cc->cc_in_aapl; 786 break; 787 case SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2: /* ("DH2Q") */ 788 cc->cc_in_flags |= CCTX_DH_REQUEST_V2; 789 cce = &cc->cc_in_dh_request_v2; 790 break; 791 case SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2: /* ("DH2C") */ 792 cc->cc_in_flags |= CCTX_DH_RECONNECT_V2; 793 cce = &cc->cc_in_dh_reconnect_v2; 794 break; 795 case 0x9ccbcf9e: /* SVHDX_OPEN_DEVICE_CONTEXT */ 796 /* 9ccbcf9e 04c1e643 980e158d a1f6ec83 */ 797 /* silently ignore */ 798 break; 799 default: 800 /* 801 * Unknown create context values are normal, and 802 * should be ignored. However, in debug mode, 803 * let's log them so we know which ones we're 804 * not handling (and may want to add). 805 */ 806 #ifdef DEBUG 807 cmn_err(CE_NOTE, "unknown create context ID 0x%x", 808 cc_name.i); 809 #endif 810 cce = NULL; 811 break; 812 } 813 814 if (cce == NULL || data_len == 0) 815 goto next_cc; 816 817 if ((data_off & 7) != 0) 818 break; 819 if ((top_offset + data_off) < in_mbc->chain_offset) 820 break; 821 rc = MBC_SHADOW_CHAIN(&cce->cce_mbc, in_mbc, 822 top_offset + data_off, data_len); 823 if (rc) 824 break; 825 cce->cce_len = data_len; 826 827 /* 828 * Additonal decoding for some create contexts. 829 */ 830 switch (cc_name.i) { 831 uint64_t nttime; 832 833 case SMB2_CREATE_SD_BUFFER: /* ("SecD") */ 834 op->sd = kmem_alloc(sizeof (smb_sd_t), KM_SLEEP); 835 if (smb_decode_sd(&cce->cce_mbc, op->sd) != 0) 836 goto errout; 837 break; 838 839 case SMB2_CREATE_ALLOCATION_SIZE: /* ("AISi") */ 840 rc = smb_mbc_decodef(&cce->cce_mbc, "q", &op->dsize); 841 if (rc != 0) 842 goto errout; 843 break; 844 845 case SMB2_CREATE_TIMEWARP_TOKEN: /* ("TWrp") */ 846 /* 847 * Support for opening "Previous Versions". 848 * [MS-SMB2] 2.2.13.2.7 Data is an NT time. 849 */ 850 rc = smb_mbc_decodef(&cce->cce_mbc, 851 "q", &nttime); 852 if (rc != 0) 853 goto errout; 854 smb_time_nt_to_unix(nttime, &op->timewarp); 855 op->create_timewarp = B_TRUE; 856 break; 857 858 /* 859 * Note: This handles both V1 and V2 leases, 860 * which differ only by their length. 861 */ 862 case SMB2_CREATE_REQUEST_LEASE: /* ("RqLs") */ 863 if (data_len == 52) { 864 op->lease_version = 2; 865 } else if (data_len == 32) { 866 op->lease_version = 1; 867 } else { 868 cmn_err(CE_NOTE, "Cctx RqLs bad len=0x%x", 869 data_len); 870 } 871 rc = smb_mbc_decodef(&cce->cce_mbc, "#cllq", 872 UUID_LEN, /* # */ 873 op->lease_key, /* c */ 874 &op->lease_state, /* l */ 875 &op->lease_flags, /* l */ 876 &nttime); /* (ignored) q */ 877 if (rc != 0) 878 goto errout; 879 if (op->lease_version == 2) { 880 rc = smb_mbc_decodef(&cce->cce_mbc, 881 "#cw..", 882 UUID_LEN, 883 op->parent_lease_key, 884 &op->lease_epoch); 885 if (rc != 0) 886 goto errout; 887 } else { 888 bzero(op->parent_lease_key, UUID_LEN); 889 } 890 break; 891 892 case SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2: /* ("DH2C") */ 893 rc = smb_mbc_decodef(&cce->cce_mbc, "qq#cl", 894 &op->dh_fileid.persistent, /* q */ 895 &op->dh_fileid.temporal, /* q */ 896 UUID_LEN, /* # */ 897 op->create_guid, /* c */ 898 &op->dh_v2_flags); /* l */ 899 if (rc != 0) 900 goto errout; 901 break; 902 903 case SMB2_CREATE_DURABLE_HANDLE_RECONNECT: /* ("DHnC") */ 904 rc = smb_mbc_decodef(&cce->cce_mbc, "qq", 905 &op->dh_fileid.persistent, /* q */ 906 &op->dh_fileid.temporal); /* q */ 907 if (rc != 0) 908 goto errout; 909 bzero(op->create_guid, UUID_LEN); 910 op->dh_v2_flags = 0; 911 break; 912 913 case SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2: /* ("DH2Q") */ 914 rc = smb_mbc_decodef(&cce->cce_mbc, 915 "ll8.#c", 916 &op->dh_timeout, /* l */ 917 &op->dh_v2_flags, /* l */ 918 /* reserved */ /* 8. */ 919 UUID_LEN, /* # */ 920 op->create_guid); /* c */ 921 if (rc != 0) 922 goto errout; 923 break; 924 925 case SMB2_CREATE_DURABLE_HANDLE_REQUEST: /* ("DHnQ") */ 926 rc = smb_mbc_decodef(&cce->cce_mbc, 927 "16."); /* reserved */ 928 if (rc != 0) 929 goto errout; 930 op->dh_timeout = 0; /* default */ 931 op->dh_v2_flags = 0; 932 break; 933 } 934 935 next_cc: 936 if (next_off == 0) { 937 /* Normal loop termination */ 938 status = 0; 939 break; 940 } 941 942 if ((next_off & 7) != 0) 943 break; 944 if ((top_offset + next_off) < in_mbc->chain_offset) 945 break; 946 if ((top_offset + next_off) > in_mbc->max_bytes) 947 break; 948 in_mbc->chain_offset = top_offset + next_off; 949 } 950 951 errout: 952 return (status); 953 } 954 955 /* 956 * Encode an SMB2 Create Context buffer from our internal form. 957 * 958 * Build the Create Context to return; first the 959 * per-element parts, then the aggregated buffer. 960 * 961 * No response for these: 962 * CCTX_EA_BUFFER 963 * CCTX_SD_BUFFER 964 * CCTX_ALLOCATION_SIZE 965 * CCTX_TIMEWARP_TOKEN 966 * 967 * Remember to add code sections to smb2_free_create_ctx() 968 * for each section here that encodes a context element. 969 */ 970 static uint32_t 971 smb2_encode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc) 972 { 973 smb_arg_open_t *op = &sr->arg.open; 974 smb2_create_ctx_elem_t *cce; 975 mbuf_chain_t *mbc = &sr->raw_data; 976 int last_top = -1; 977 int rc; 978 979 if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) { 980 cce = &cc->cc_out_max_access; 981 982 cce->cce_mbc.max_bytes = cce->cce_len = 8; 983 (void) smb_mbc_encodef(&cce->cce_mbc, 984 "ll", 0, op->maximum_access); 985 986 last_top = mbc->chain_offset; 987 rc = smb2_encode_create_ctx_elem(mbc, cce, 988 SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ); 989 if (rc) 990 return (NT_STATUS_INTERNAL_ERROR); 991 (void) smb_mbc_poke(mbc, last_top, "l", 992 mbc->chain_offset - last_top); 993 } 994 995 if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) { 996 cce = &cc->cc_out_file_id; 997 998 cce->cce_mbc.max_bytes = cce->cce_len = 32; 999 (void) smb_mbc_encodef( 1000 &cce->cce_mbc, "qll.15.", 1001 op->fileid, /* q */ 1002 op->op_fsid.val[0], /* l */ 1003 op->op_fsid.val[1]); /* l */ 1004 /* reserved (16 bytes) .15. */ 1005 1006 last_top = mbc->chain_offset; 1007 rc = smb2_encode_create_ctx_elem(mbc, cce, 1008 SMB2_CREATE_QUERY_ON_DISK_ID); 1009 if (rc) 1010 return (NT_STATUS_INTERNAL_ERROR); 1011 (void) smb_mbc_poke(mbc, last_top, "l", 1012 mbc->chain_offset - last_top); 1013 } 1014 1015 if (cc->cc_out_flags & CCTX_AAPL_EXT) { 1016 cce = &cc->cc_out_aapl; 1017 /* cc_out_aapl already encoded */ 1018 1019 last_top = mbc->chain_offset; 1020 rc = smb2_encode_create_ctx_elem(mbc, cce, 1021 SMB2_CREATE_CTX_AAPL); 1022 if (rc) 1023 return (NT_STATUS_INTERNAL_ERROR); 1024 (void) smb_mbc_poke(mbc, last_top, "l", 1025 mbc->chain_offset - last_top); 1026 } 1027 1028 if (cc->cc_out_flags & CCTX_REQUEST_LEASE) { 1029 cce = &cc->cc_out_req_lease; 1030 1031 cce->cce_mbc.max_bytes = cce->cce_len = 32; 1032 (void) smb_mbc_encodef(&cce->cce_mbc, "#cllq", 1033 UUID_LEN, /* # */ 1034 op->lease_key, /* c */ 1035 op->lease_state, /* l */ 1036 op->lease_flags, /* l */ 1037 0LL); /* q */ 1038 if (op->lease_version == 2) { 1039 cce->cce_mbc.max_bytes = cce->cce_len = 52; 1040 (void) smb_mbc_encodef(&cce->cce_mbc, 1041 "#cw..", 1042 UUID_LEN, 1043 op->parent_lease_key, 1044 op->lease_epoch); 1045 } 1046 1047 last_top = mbc->chain_offset; 1048 rc = smb2_encode_create_ctx_elem(mbc, cce, 1049 SMB2_CREATE_REQUEST_LEASE); 1050 if (rc) 1051 return (NT_STATUS_INTERNAL_ERROR); 1052 (void) smb_mbc_poke(mbc, last_top, "l", 1053 mbc->chain_offset - last_top); 1054 } 1055 1056 if (cc->cc_out_flags & CCTX_DH_REQUEST) { 1057 cce = &cc->cc_out_dh_request; 1058 1059 cce->cce_mbc.max_bytes = cce->cce_len = 8; 1060 (void) smb_mbc_encodef(&cce->cce_mbc, "q", 0LL); 1061 1062 last_top = mbc->chain_offset; 1063 rc = smb2_encode_create_ctx_elem(mbc, cce, 1064 SMB2_CREATE_DURABLE_HANDLE_REQUEST); 1065 if (rc) 1066 return (NT_STATUS_INTERNAL_ERROR); 1067 (void) smb_mbc_poke(mbc, last_top, "l", 1068 mbc->chain_offset - last_top); 1069 } 1070 1071 if (cc->cc_out_flags & CCTX_DH_REQUEST_V2) { 1072 cce = &cc->cc_out_dh_request_v2; 1073 1074 cce->cce_mbc.max_bytes = cce->cce_len = 8; 1075 (void) smb_mbc_encodef(&cce->cce_mbc, "ll", 1076 op->dh_timeout, op->dh_v2_flags); 1077 1078 last_top = mbc->chain_offset; 1079 rc = smb2_encode_create_ctx_elem(mbc, cce, 1080 SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2); 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 (last_top >= 0) 1088 (void) smb_mbc_poke(mbc, last_top, "l", 0); 1089 1090 return (0); 1091 } 1092 1093 static int 1094 smb2_encode_create_ctx_elem(mbuf_chain_t *out_mbc, 1095 smb2_create_ctx_elem_t *cce, uint32_t id) 1096 { 1097 union { 1098 uint32_t i; 1099 char ch[4]; 1100 } cc_name; 1101 int rc; 1102 1103 /* as above */ 1104 cc_name.i = htonl(id); 1105 1106 /* 1107 * This is the header, per [MS-SMB2] 2.2.13.2 1108 * Sorry about the fixed offsets. We know we'll 1109 * layout the data part as [name, payload] and 1110 * name is a fixed length, so this easy. 1111 * The final layout looks like this: 1112 * a: this header (16 bytes) 1113 * b: the name (4 bytes, 4 pad) 1114 * c: the payload (variable) 1115 * d: padding (to align 8) 1116 * 1117 * Note that "Next elem." is filled in later. 1118 */ 1119 rc = smb_mbc_encodef( 1120 out_mbc, "lwwwwl", 1121 0, /* Next offset l */ 1122 16, /* NameOffset w */ 1123 4, /* NameLength w */ 1124 0, /* Reserved w */ 1125 24, /* DataOffset w */ 1126 cce->cce_len); /* DataLen l */ 1127 if (rc) 1128 return (rc); 1129 1130 /* 1131 * Now the "name" and payload. 1132 */ 1133 rc = smb_mbc_encodef( 1134 out_mbc, "4c4.#C", 1135 cc_name.ch, /* 4c4. */ 1136 cce->cce_len, /* # */ 1137 &cce->cce_mbc); /* C */ 1138 1139 (void) smb_mbc_put_align(out_mbc, 8); 1140 1141 return (rc); 1142 } 1143 1144 static void 1145 smb2_free_create_ctx(smb2_create_ctx_t *cc) 1146 { 1147 smb2_create_ctx_elem_t *cce; 1148 1149 if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) { 1150 cce = &cc->cc_out_max_access; 1151 MBC_FLUSH(&cce->cce_mbc); 1152 } 1153 if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) { 1154 cce = &cc->cc_out_file_id; 1155 MBC_FLUSH(&cce->cce_mbc); 1156 } 1157 if (cc->cc_out_flags & CCTX_AAPL_EXT) { 1158 cce = &cc->cc_out_aapl; 1159 MBC_FLUSH(&cce->cce_mbc); 1160 } 1161 if (cc->cc_out_flags & CCTX_REQUEST_LEASE) { 1162 cce = &cc->cc_out_req_lease; 1163 MBC_FLUSH(&cce->cce_mbc); 1164 } 1165 if (cc->cc_out_flags & CCTX_DH_REQUEST) { 1166 cce = &cc->cc_out_dh_request; 1167 MBC_FLUSH(&cce->cce_mbc); 1168 } 1169 if (cc->cc_out_flags & CCTX_DH_REQUEST_V2) { 1170 cce = &cc->cc_out_dh_request_v2; 1171 MBC_FLUSH(&cce->cce_mbc); 1172 } 1173 } 1174