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 /* 25 * Some flags used locally to keep track of which Create Context 26 * names have been provided and/or requested. 27 */ 28 #define CCTX_EA_BUFFER 1 29 #define CCTX_SD_BUFFER 2 30 #define CCTX_DH_REQUEST 4 31 #define CCTX_DH_RECONNECT 8 32 #define CCTX_ALLOCATION_SIZE 0x10 33 #define CCTX_QUERY_MAX_ACCESS 0x20 34 #define CCTX_TIMEWARP_TOKEN 0x40 35 #define CCTX_QUERY_ON_DISK_ID 0x80 36 #define CCTX_REQUEST_LEASE 0x100 37 #define CCTX_AAPL_EXT 0x200 38 39 typedef struct smb2_create_ctx_elem { 40 uint32_t cce_len; 41 mbuf_chain_t cce_mbc; 42 } smb2_create_ctx_elem_t; 43 44 typedef struct smb2_create_ctx { 45 mbuf_chain_t cc_in_mbc; 46 uint_t cc_in_flags; /* CCTX_... */ 47 uint_t cc_out_flags; /* CCTX_... */ 48 /* Elements we may see in the request. */ 49 smb2_create_ctx_elem_t cc_in_ext_attr; 50 smb2_create_ctx_elem_t cc_in_sec_desc; 51 smb2_create_ctx_elem_t cc_in_dh_request; 52 smb2_create_ctx_elem_t cc_in_dh_reconnect; 53 smb2_create_ctx_elem_t cc_in_alloc_size; 54 smb2_create_ctx_elem_t cc_in_time_warp; 55 smb2_create_ctx_elem_t cc_in_req_lease; 56 smb2_create_ctx_elem_t cc_in_aapl; 57 /* Elements we my place in the response */ 58 smb2_create_ctx_elem_t cc_out_max_access; 59 smb2_create_ctx_elem_t cc_out_file_id; 60 smb2_create_ctx_elem_t cc_out_aapl; 61 } smb2_create_ctx_t; 62 63 static uint32_t smb2_decode_create_ctx( 64 smb_request_t *, smb2_create_ctx_t *); 65 static uint32_t smb2_encode_create_ctx( 66 smb_request_t *, smb2_create_ctx_t *); 67 static int smb2_encode_create_ctx_elem( 68 mbuf_chain_t *, smb2_create_ctx_elem_t *, uint32_t); 69 static void smb2_free_create_ctx(smb2_create_ctx_t *); 70 71 smb_sdrc_t 72 smb2_create(smb_request_t *sr) 73 { 74 smb_attr_t *attr; 75 smb2_create_ctx_elem_t *cce; 76 smb2_create_ctx_t cctx; 77 smb_arg_open_t *op = &sr->arg.open; 78 smb_ofile_t *of = NULL; 79 uint16_t StructSize; 80 uint8_t SecurityFlags; 81 uint8_t OplockLevel; 82 uint32_t ImpersonationLevel; 83 uint64_t SmbCreateFlags; 84 uint64_t Reserved4; 85 uint16_t NameOffset; 86 uint16_t NameLength; 87 uint32_t CreateCtxOffset; 88 uint32_t CreateCtxLength; 89 smb2fid_t smb2fid; 90 uint32_t status; 91 int skip; 92 int rc = 0; 93 94 bzero(&cctx, sizeof (cctx)); 95 op->create_ctx = &cctx; /* for debugging */ 96 97 /* 98 * Paranoia. This will set sr->fid_ofile, so 99 * if we already have one, release it now. 100 */ 101 if (sr->fid_ofile != NULL) { 102 smb_ofile_request_complete(sr->fid_ofile); 103 smb_ofile_release(sr->fid_ofile); 104 sr->fid_ofile = NULL; 105 } 106 107 /* 108 * Decode the SMB2 Create request 109 * 110 * Most decode errors return SDRC_ERROR, but 111 * for some we give a more specific error. 112 * 113 * In the "decode section" (starts here) any 114 * errors should either return SDRC_ERROR, or 115 * if any cleanup is needed, goto errout. 116 */ 117 rc = smb_mbc_decodef( 118 &sr->smb_data, "wbblqqlllllwwll", 119 &StructSize, /* w */ 120 &SecurityFlags, /* b */ 121 &op->op_oplock_level, /* b */ 122 &ImpersonationLevel, /* l */ 123 &SmbCreateFlags, /* q */ 124 &Reserved4, /* q */ 125 &op->desired_access, /* l */ 126 &op->dattr, /* l */ 127 &op->share_access, /* l */ 128 &op->create_disposition, /* l */ 129 &op->create_options, /* l */ 130 &NameOffset, /* w */ 131 &NameLength, /* w */ 132 &CreateCtxOffset, /* l */ 133 &CreateCtxLength); /* l */ 134 if (rc != 0 || StructSize != 57) 135 return (SDRC_ERROR); 136 137 /* 138 * We're normally positioned at the path name now, 139 * but there could be some padding before it. 140 */ 141 skip = (NameOffset + sr->smb2_cmd_hdr) - 142 sr->smb_data.chain_offset; 143 if (skip < 0) 144 return (SDRC_ERROR); 145 if (skip > 0) 146 (void) smb_mbc_decodef(&sr->smb_data, "#.", skip); 147 148 /* 149 * Get the path name 150 * 151 * Name too long is not technically a decode error, 152 * but it's very rare, so we'll just skip the 153 * dtrace probes for this error case. 154 */ 155 if (NameLength >= SMB_MAXPATHLEN) { 156 status = NT_STATUS_OBJECT_PATH_INVALID; 157 goto errout; 158 } 159 if (NameLength == 0) { 160 op->fqi.fq_path.pn_path = "\\"; 161 } else { 162 rc = smb_mbc_decodef(&sr->smb_data, "%#U", sr, 163 NameLength, &op->fqi.fq_path.pn_path); 164 if (rc) { 165 status = NT_STATUS_OBJECT_PATH_INVALID; 166 goto errout; 167 } 168 } 169 op->fqi.fq_dnode = sr->tid_tree->t_snode; 170 171 /* 172 * If there is a "Create Context" payload, decode it. 173 * This may carry things like a security descriptor, 174 * extended attributes, etc. to be used in create. 175 * 176 * The create ctx buffer must start after the headers 177 * and file name, and must be 8-byte aligned. 178 */ 179 if (CreateCtxLength != 0) { 180 if ((CreateCtxOffset & 7) != 0 || 181 (CreateCtxOffset + sr->smb2_cmd_hdr) < 182 sr->smb_data.chain_offset) { 183 status = NT_STATUS_INVALID_PARAMETER; 184 goto errout; 185 } 186 187 rc = MBC_SHADOW_CHAIN(&cctx.cc_in_mbc, &sr->smb_data, 188 sr->smb2_cmd_hdr + CreateCtxOffset, CreateCtxLength); 189 if (rc) { 190 status = NT_STATUS_INVALID_PARAMETER; 191 goto errout; 192 } 193 status = smb2_decode_create_ctx(sr, &cctx); 194 if (status) 195 goto errout; 196 } 197 198 /* 199 * Everything is decoded into some internal form, so 200 * in this probe one can look at sr->arg.open etc. 201 * 202 * This marks the end of the "decode" section and the 203 * beginning of the "body" section. Any errors in 204 * this section should use: goto cmd_done (which is 205 * just before the dtrace "done" probe). 206 */ 207 DTRACE_SMB2_START(op__Create, smb_request_t *, sr); /* arg.open */ 208 209 /* 210 * Process the incoming create contexts (already decoded), 211 * that need action before the open, starting with the 212 * Durable Handle ones, which may override others. 213 */ 214 215 /* 216 * Validate the requested oplock level. 217 * Convert the SMB2 oplock level into SMB1 form. 218 */ 219 switch (op->op_oplock_level) { 220 case SMB2_OPLOCK_LEVEL_NONE: 221 op->op_oplock_level = SMB_OPLOCK_NONE; 222 break; 223 case SMB2_OPLOCK_LEVEL_II: 224 op->op_oplock_level = SMB_OPLOCK_LEVEL_II; 225 break; 226 case SMB2_OPLOCK_LEVEL_EXCLUSIVE: 227 op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE; 228 break; 229 case SMB2_OPLOCK_LEVEL_BATCH: 230 op->op_oplock_level = SMB_OPLOCK_BATCH; 231 break; 232 case SMB2_OPLOCK_LEVEL_LEASE: /* not yet */ 233 default: 234 /* Unknown SMB2 oplock level. */ 235 status = NT_STATUS_INVALID_PARAMETER; 236 goto cmd_done; 237 } 238 op->op_oplock_levelII = B_TRUE; 239 240 /* 241 * Only disk trees get oplocks or leases. 242 */ 243 if ((sr->tid_tree->t_res_type & STYPE_MASK) != STYPE_DISKTREE) { 244 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE; 245 cctx.cc_in_flags &= ~CCTX_REQUEST_LEASE; 246 } 247 248 if (cctx.cc_in_flags & CCTX_EA_BUFFER) { 249 status = NT_STATUS_EAS_NOT_SUPPORTED; 250 goto cmd_done; 251 } 252 253 /* 254 * ImpersonationLevel (spec. says validate + ignore) 255 * SmbCreateFlags (spec. says ignore) 256 */ 257 258 if ((op->create_options & FILE_DELETE_ON_CLOSE) && 259 !(op->desired_access & DELETE)) { 260 status = NT_STATUS_INVALID_PARAMETER; 261 goto cmd_done; 262 } 263 264 if (op->dattr & FILE_FLAG_WRITE_THROUGH) 265 op->create_options |= FILE_WRITE_THROUGH; 266 if (op->dattr & FILE_FLAG_DELETE_ON_CLOSE) 267 op->create_options |= FILE_DELETE_ON_CLOSE; 268 if (op->dattr & FILE_FLAG_BACKUP_SEMANTICS) 269 op->create_options |= FILE_OPEN_FOR_BACKUP_INTENT; 270 if (op->create_options & FILE_OPEN_FOR_BACKUP_INTENT) 271 sr->user_cr = smb_user_getprivcred(sr->uid_user); 272 if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) { 273 status = NT_STATUS_INVALID_PARAMETER; 274 goto cmd_done; 275 } 276 277 /* 278 * The real open call. Note: this gets attributes into 279 * op->fqi.fq_fattr (SMB_AT_ALL). We need those below. 280 * When of != NULL, goto errout closes it. 281 */ 282 status = smb_common_open(sr); 283 if (status != NT_STATUS_SUCCESS) 284 goto cmd_done; 285 of = sr->fid_ofile; 286 287 /* 288 * NB: after the above smb_common_open() success, 289 * we have a handle allocated (sr->fid_ofile). 290 * If we don't return success, we must close it. 291 * 292 * Using sr->smb_fid as the file handle for now, 293 * though it could later be something larger, 294 * (16 bytes) similar to an NFSv4 open handle. 295 */ 296 smb2fid.persistent = 0; 297 smb2fid.temporal = sr->smb_fid; 298 299 switch (sr->tid_tree->t_res_type & STYPE_MASK) { 300 case STYPE_DISKTREE: 301 case STYPE_PRINTQ: 302 if (op->create_options & FILE_DELETE_ON_CLOSE) 303 smb_ofile_set_delete_on_close(of); 304 break; 305 } 306 307 /* 308 * Process any outgoing create contexts that need work 309 * after the open succeeds. Encode happens later. 310 */ 311 if (cctx.cc_in_flags & CCTX_QUERY_MAX_ACCESS) { 312 op->maximum_access = 0; 313 if (of->f_node != NULL) { 314 smb_fsop_eaccess(sr, of->f_cr, of->f_node, 315 &op->maximum_access); 316 } 317 op->maximum_access |= of->f_granted_access; 318 cctx.cc_out_flags |= CCTX_QUERY_MAX_ACCESS; 319 } 320 321 if ((cctx.cc_in_flags & CCTX_QUERY_ON_DISK_ID) != 0 && 322 of->f_node != NULL) { 323 op->op_fsid = SMB_NODE_FSID(of->f_node); 324 cctx.cc_out_flags |= CCTX_QUERY_ON_DISK_ID; 325 } 326 327 if ((cctx.cc_in_flags & CCTX_AAPL_EXT) != 0) { 328 cce = &cctx.cc_out_aapl; 329 /* 330 * smb2_aapl_crctx has a variable response depending on 331 * what the incoming context looks like, so it does all 332 * the work of building cc_out_aapl, including setting 333 * cce_len, cce_mbc.max_bytes, and smb_mbc_encode. 334 * If we see errors getting this, simply omit it from 335 * the collection of returned create contexts. 336 */ 337 status = smb2_aapl_crctx(sr, 338 &cctx.cc_in_aapl.cce_mbc, &cce->cce_mbc); 339 if (status == 0) { 340 cce->cce_len = cce->cce_mbc.chain_offset; 341 cctx.cc_out_flags |= CCTX_AAPL_EXT; 342 } 343 status = 0; 344 } 345 346 /* 347 * This marks the end of the "body" section and the 348 * beginning of the "encode" section. Any errors 349 * encoding the response should use: goto errout 350 */ 351 cmd_done: 352 /* Want status visible in the done probe. */ 353 sr->smb2_status = status; 354 DTRACE_SMB2_DONE(op__Create, smb_request_t *, sr); 355 if (status != NT_STATUS_SUCCESS) 356 goto errout; 357 358 /* 359 * Encode all the create contexts to return. 360 */ 361 if (cctx.cc_out_flags) { 362 sr->raw_data.max_bytes = smb2_max_trans; 363 status = smb2_encode_create_ctx(sr, &cctx); 364 if (status) 365 goto errout; 366 } 367 368 /* 369 * Convert the negotiated Oplock level back into 370 * SMB2 encoding form. 371 */ 372 switch (op->op_oplock_level) { 373 default: 374 case SMB_OPLOCK_NONE: 375 OplockLevel = SMB2_OPLOCK_LEVEL_NONE; 376 break; 377 case SMB_OPLOCK_LEVEL_II: 378 OplockLevel = SMB2_OPLOCK_LEVEL_II; 379 break; 380 case SMB_OPLOCK_EXCLUSIVE: 381 OplockLevel = SMB2_OPLOCK_LEVEL_EXCLUSIVE; 382 break; 383 case SMB_OPLOCK_BATCH: 384 OplockLevel = SMB2_OPLOCK_LEVEL_BATCH; 385 break; 386 } 387 388 /* 389 * Encode the SMB2 Create reply 390 */ 391 attr = &op->fqi.fq_fattr; 392 rc = smb_mbc_encodef( 393 &sr->reply, 394 "wb.lTTTTqqllqqll", 395 89, /* StructSize */ /* w */ 396 OplockLevel, /* b */ 397 op->action_taken, /* l */ 398 &attr->sa_crtime, /* T */ 399 &attr->sa_vattr.va_atime, /* T */ 400 &attr->sa_vattr.va_mtime, /* T */ 401 &attr->sa_vattr.va_ctime, /* T */ 402 attr->sa_allocsz, /* q */ 403 attr->sa_vattr.va_size, /* q */ 404 attr->sa_dosattr, /* l */ 405 0, /* reserved2 */ /* l */ 406 smb2fid.persistent, /* q */ 407 smb2fid.temporal, /* q */ 408 0, /* CreateCtxOffset l */ 409 0); /* CreateCtxLength l */ 410 if (rc != 0) { 411 status = NT_STATUS_UNSUCCESSFUL; 412 goto errout; 413 } 414 415 CreateCtxOffset = sr->reply.chain_offset - sr->smb2_reply_hdr; 416 CreateCtxLength = MBC_LENGTH(&sr->raw_data); 417 if (CreateCtxLength != 0) { 418 /* 419 * Overwrite CreateCtxOffset, CreateCtxLength, pad 420 */ 421 sr->reply.chain_offset -= 8; 422 rc = smb_mbc_encodef( 423 &sr->reply, 424 "ll#C", 425 CreateCtxOffset, /* l */ 426 CreateCtxLength, /* l */ 427 CreateCtxLength, /* # */ 428 &sr->raw_data); /* C */ 429 if (rc != 0) { 430 status = NT_STATUS_UNSUCCESSFUL; 431 goto errout; 432 } 433 } else { 434 (void) smb_mbc_encodef(&sr->reply, "."); 435 } 436 437 if (status != 0) { 438 errout: 439 if (of != NULL) 440 smb_ofile_close(of, 0); 441 smb2sr_put_error(sr, status); 442 } 443 if (op->sd != NULL) { 444 smb_sd_term(op->sd); 445 kmem_free(op->sd, sizeof (*op->sd)); 446 } 447 if (cctx.cc_out_flags) 448 smb2_free_create_ctx(&cctx); 449 450 return (SDRC_SUCCESS); 451 } 452 453 /* 454 * Decode an SMB2 Create Context buffer into our internal form. 455 * Avoid policy decisions about what's supported here, just decode. 456 */ 457 static uint32_t 458 smb2_decode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc) 459 { 460 smb_arg_open_t *op = &sr->arg.open; 461 smb2_create_ctx_elem_t *cce; 462 mbuf_chain_t *in_mbc = &cc->cc_in_mbc; 463 mbuf_chain_t name_mbc; 464 union { 465 uint32_t i; 466 char ch[4]; 467 } cc_name; 468 uint32_t status; 469 int32_t next_off; 470 uint32_t data_len; 471 uint16_t data_off; 472 uint16_t name_off; 473 uint16_t name_len; 474 int top_offset; 475 int rc; 476 477 /* 478 * Any break from the loop below before we've decoded 479 * the entire create context means it was malformatted, 480 * so we should return INVALID_PARAMETER. 481 */ 482 status = NT_STATUS_INVALID_PARAMETER; 483 for (;;) { 484 cce = NULL; 485 top_offset = in_mbc->chain_offset; 486 rc = smb_mbc_decodef( 487 in_mbc, 488 "lww..wl", 489 &next_off, /* l */ 490 &name_off, /* w */ 491 &name_len, /* w */ 492 /* reserved .. */ 493 &data_off, /* w */ 494 &data_len); /* l */ 495 if (rc) 496 break; 497 498 /* 499 * The Create Context "name", per [MS-SMB] 2.2.13.2 500 * They're defined as network-order integers for our 501 * switch below. We don't have routines to decode 502 * native order, so read as char[4] then ntohl. 503 * NB: in SMB3, some of these are 8 bytes. 504 */ 505 if ((top_offset + name_off) < in_mbc->chain_offset) 506 break; 507 rc = MBC_SHADOW_CHAIN(&name_mbc, in_mbc, 508 top_offset + name_off, name_len); 509 if (rc) 510 break; 511 rc = smb_mbc_decodef(&name_mbc, "4c", &cc_name); 512 if (rc) 513 break; 514 cc_name.i = ntohl(cc_name.i); 515 516 switch (cc_name.i) { 517 case SMB2_CREATE_EA_BUFFER: /* ("ExtA") */ 518 cc->cc_in_flags |= CCTX_EA_BUFFER; 519 cce = &cc->cc_in_ext_attr; 520 break; 521 case SMB2_CREATE_SD_BUFFER: /* ("SecD") */ 522 cc->cc_in_flags |= CCTX_SD_BUFFER; 523 cce = &cc->cc_in_sec_desc; 524 break; 525 case SMB2_CREATE_DURABLE_HANDLE_REQUEST: /* ("DHnQ") */ 526 cc->cc_in_flags |= CCTX_DH_REQUEST; 527 cce = &cc->cc_in_dh_request; 528 break; 529 case SMB2_CREATE_DURABLE_HANDLE_RECONNECT: /* ("DHnC") */ 530 cc->cc_in_flags |= CCTX_DH_RECONNECT; 531 cce = &cc->cc_in_dh_reconnect; 532 break; 533 case SMB2_CREATE_ALLOCATION_SIZE: /* ("AISi") */ 534 cc->cc_in_flags |= CCTX_ALLOCATION_SIZE; 535 cce = &cc->cc_in_alloc_size; 536 break; 537 case SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ: /* ("MxAc") */ 538 cc->cc_in_flags |= CCTX_QUERY_MAX_ACCESS; 539 /* no input data for this */ 540 break; 541 case SMB2_CREATE_TIMEWARP_TOKEN: /* ("TWrp") */ 542 cc->cc_in_flags |= CCTX_TIMEWARP_TOKEN; 543 cce = &cc->cc_in_time_warp; 544 break; 545 case SMB2_CREATE_QUERY_ON_DISK_ID: /* ("QFid") */ 546 cc->cc_in_flags |= CCTX_QUERY_ON_DISK_ID; 547 /* no input data for this */ 548 break; 549 case SMB2_CREATE_REQUEST_LEASE: /* ("RqLs") */ 550 cc->cc_in_flags |= CCTX_REQUEST_LEASE; 551 cce = &cc->cc_in_req_lease; 552 break; 553 case SMB2_CREATE_CTX_AAPL: /* ("AAPL") */ 554 cc->cc_in_flags |= CCTX_AAPL_EXT; 555 cce = &cc->cc_in_aapl; 556 break; 557 default: 558 /* 559 * Unknown create context values are normal, and 560 * should be ignored. However, in debug mode, 561 * let's log them so we know which ones we're 562 * not handling (and may want to add). 563 */ 564 #ifdef DEBUG 565 cmn_err(CE_NOTE, "unknown create context ID 0x%x", 566 cc_name.i); 567 #endif 568 cce = NULL; 569 break; 570 } 571 572 if (cce == NULL || data_len == 0) 573 goto next_cc; 574 575 if ((data_off & 7) != 0) 576 break; 577 if ((top_offset + data_off) < in_mbc->chain_offset) 578 break; 579 rc = MBC_SHADOW_CHAIN(&cce->cce_mbc, in_mbc, 580 top_offset + data_off, data_len); 581 if (rc) 582 break; 583 cce->cce_len = data_len; 584 585 /* 586 * Additonal decoding for some create contexts. 587 */ 588 switch (cc_name.i) { 589 uint64_t nttime; 590 591 case SMB2_CREATE_SD_BUFFER: /* ("SecD") */ 592 op->sd = kmem_alloc(sizeof (smb_sd_t), KM_SLEEP); 593 if (smb_decode_sd(&cce->cce_mbc, op->sd) != 0) 594 goto errout; 595 break; 596 597 case SMB2_CREATE_ALLOCATION_SIZE: /* ("AISi") */ 598 rc = smb_mbc_decodef(&cce->cce_mbc, "q", &op->dsize); 599 if (rc != 0) 600 goto errout; 601 break; 602 603 case SMB2_CREATE_TIMEWARP_TOKEN: /* ("TWrp") */ 604 /* 605 * Support for opening "Previous Versions". 606 * [MS-SMB2] 2.2.13.2.7 Data is an NT time. 607 */ 608 rc = smb_mbc_decodef(&cce->cce_mbc, 609 "q", &nttime); 610 if (rc != 0) 611 goto errout; 612 smb_time_nt_to_unix(nttime, &op->timewarp); 613 op->create_timewarp = B_TRUE; 614 break; 615 616 } 617 618 next_cc: 619 if (next_off == 0) { 620 /* Normal loop termination */ 621 status = 0; 622 break; 623 } 624 625 if ((next_off & 7) != 0) 626 break; 627 if ((top_offset + next_off) < in_mbc->chain_offset) 628 break; 629 if ((top_offset + next_off) > in_mbc->max_bytes) 630 break; 631 in_mbc->chain_offset = top_offset + next_off; 632 } 633 634 errout: 635 return (status); 636 } 637 638 /* 639 * Encode an SMB2 Create Context buffer from our internal form. 640 * 641 * Build the Create Context to return; first the 642 * per-element parts, then the aggregated buffer. 643 * 644 * No response for these: 645 * CCTX_EA_BUFFER 646 * CCTX_SD_BUFFER 647 * CCTX_ALLOCATION_SIZE 648 * CCTX_TIMEWARP_TOKEN 649 * 650 * Remember to add code sections to smb2_free_create_ctx() 651 * for each section here that encodes a context element. 652 */ 653 static uint32_t 654 smb2_encode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc) 655 { 656 smb_arg_open_t *op = &sr->arg.open; 657 smb2_create_ctx_elem_t *cce; 658 mbuf_chain_t *mbc = &sr->raw_data; 659 int last_top = -1; 660 int rc; 661 662 if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) { 663 cce = &cc->cc_out_max_access; 664 665 cce->cce_mbc.max_bytes = cce->cce_len = 8; 666 (void) smb_mbc_encodef(&cce->cce_mbc, 667 "ll", 0, op->maximum_access); 668 669 last_top = mbc->chain_offset; 670 rc = smb2_encode_create_ctx_elem(mbc, cce, 671 SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ); 672 if (rc) 673 return (NT_STATUS_INTERNAL_ERROR); 674 (void) smb_mbc_poke(mbc, last_top, "l", 675 mbc->chain_offset - last_top); 676 } 677 678 if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) { 679 cce = &cc->cc_out_file_id; 680 681 cce->cce_mbc.max_bytes = cce->cce_len = 32; 682 (void) smb_mbc_encodef( 683 &cce->cce_mbc, "qll.15.", 684 op->fileid, /* q */ 685 op->op_fsid.val[0], /* l */ 686 op->op_fsid.val[1]); /* l */ 687 /* reserved (16 bytes) .15. */ 688 689 last_top = mbc->chain_offset; 690 rc = smb2_encode_create_ctx_elem(mbc, cce, 691 SMB2_CREATE_QUERY_ON_DISK_ID); 692 if (rc) 693 return (NT_STATUS_INTERNAL_ERROR); 694 (void) smb_mbc_poke(mbc, last_top, "l", 695 mbc->chain_offset - last_top); 696 } 697 698 if (cc->cc_out_flags & CCTX_AAPL_EXT) { 699 cce = &cc->cc_out_aapl; 700 /* cc_out_aapl already encoded */ 701 702 last_top = mbc->chain_offset; 703 rc = smb2_encode_create_ctx_elem(mbc, cce, 704 SMB2_CREATE_CTX_AAPL); 705 if (rc) 706 return (NT_STATUS_INTERNAL_ERROR); 707 (void) smb_mbc_poke(mbc, last_top, "l", 708 mbc->chain_offset - last_top); 709 } 710 711 if (last_top >= 0) 712 (void) smb_mbc_poke(mbc, last_top, "l", 0); 713 714 return (0); 715 } 716 717 static int 718 smb2_encode_create_ctx_elem(mbuf_chain_t *out_mbc, 719 smb2_create_ctx_elem_t *cce, uint32_t id) 720 { 721 union { 722 uint32_t i; 723 char ch[4]; 724 } cc_name; 725 int rc; 726 727 /* as above */ 728 cc_name.i = htonl(id); 729 730 /* 731 * This is the header, per [MS-SMB2] 2.2.13.2 732 * Sorry about the fixed offsets. We know we'll 733 * layout the data part as [name, payload] and 734 * name is a fixed length, so this easy. 735 * The final layout looks like this: 736 * a: this header (16 bytes) 737 * b: the name (4 bytes, 4 pad) 738 * c: the payload (variable) 739 * 740 * Note that "Next elem." is filled in later. 741 */ 742 rc = smb_mbc_encodef( 743 out_mbc, "lwwwwl", 744 0, /* Next offset l */ 745 16, /* NameOffset w */ 746 4, /* NameLength w */ 747 0, /* Reserved w */ 748 24, /* DataOffset w */ 749 cce->cce_len); /* DataLen l */ 750 if (rc) 751 return (rc); 752 753 /* 754 * Now the "name" and payload. 755 */ 756 rc = smb_mbc_encodef( 757 out_mbc, "4c4.#C", 758 cc_name.ch, /* 4c4. */ 759 cce->cce_len, /* # */ 760 &cce->cce_mbc); /* C */ 761 762 return (rc); 763 } 764 765 static void 766 smb2_free_create_ctx(smb2_create_ctx_t *cc) 767 { 768 smb2_create_ctx_elem_t *cce; 769 770 if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) { 771 cce = &cc->cc_out_max_access; 772 MBC_FLUSH(&cce->cce_mbc); 773 } 774 if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) { 775 cce = &cc->cc_out_file_id; 776 MBC_FLUSH(&cce->cce_mbc); 777 } 778 if (cc->cc_out_flags & CCTX_AAPL_EXT) { 779 cce = &cc->cc_out_aapl; 780 MBC_FLUSH(&cce->cce_mbc); 781 } 782 } 783