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