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