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-2021 Tintri by DDN, Inc. All rights reserved. 14 * Copyright 2022 RackTop Systems, Inc. 15 */ 16 17 18 #include <smbsrv/smb2_kproto.h> 19 #include <smbsrv/smb_kstat.h> 20 #include <smbsrv/smb2.h> 21 22 #define SMB2_ASYNCID(sr) (sr->smb2_messageid ^ (1ULL << 62)) 23 24 smb_sdrc_t smb2_invalid_cmd(smb_request_t *); 25 static void smb2_tq_work(void *); 26 static void smb2sr_run_postwork(smb_request_t *); 27 static int smb3_decrypt_msg(smb_request_t *); 28 29 static const smb_disp_entry_t 30 smb2_disp_table[SMB2__NCMDS] = { 31 32 /* text-name, pre, func, post, cmd-code, dialect, flags */ 33 34 { "smb2_negotiate", NULL, 35 smb2_negotiate, NULL, 0, 0, 36 SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID }, 37 38 { "smb2_session_setup", NULL, 39 smb2_session_setup, NULL, 0, 0, 40 SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID }, 41 42 { "smb2_logoff", NULL, 43 smb2_logoff, NULL, 0, 0, 44 SDDF_SUPPRESS_TID }, 45 46 { "smb2_tree_connect", NULL, 47 smb2_tree_connect, NULL, 0, 0, 48 SDDF_SUPPRESS_TID }, 49 50 { "smb2_tree_disconn", NULL, 51 smb2_tree_disconn, NULL, 0, 0 }, 52 53 { "smb2_create", NULL, 54 smb2_create, NULL, 0, 0 }, 55 56 { "smb2_close", NULL, 57 smb2_close, NULL, 0, 0 }, 58 59 { "smb2_flush", NULL, 60 smb2_flush, NULL, 0, 0 }, 61 62 { "smb2_read", NULL, 63 smb2_read, NULL, 0, 0 }, 64 65 { "smb2_write", NULL, 66 smb2_write, NULL, 0, 0 }, 67 68 { "smb2_lock", NULL, 69 smb2_lock, NULL, 0, 0 }, 70 71 { "smb2_ioctl", NULL, 72 smb2_ioctl, NULL, 0, 0 }, 73 74 { "smb2_cancel", NULL, 75 smb2_cancel, NULL, 0, 0, 76 SDDF_SUPPRESS_UID | SDDF_SUPPRESS_TID }, 77 78 { "smb2_echo", NULL, 79 smb2_echo, NULL, 0, 0, 80 SDDF_SUPPRESS_UID | SDDF_SUPPRESS_TID }, 81 82 { "smb2_query_dir", NULL, 83 smb2_query_dir, NULL, 0, 0 }, 84 85 { "smb2_change_notify", NULL, 86 smb2_change_notify, NULL, 0, 0 }, 87 88 { "smb2_query_info", NULL, 89 smb2_query_info, NULL, 0, 0 }, 90 91 { "smb2_set_info", NULL, 92 smb2_set_info, NULL, 0, 0 }, 93 94 { "smb2_oplock_break_ack", NULL, 95 smb2_oplock_break_ack, NULL, 0, 0 }, 96 97 { "smb2_invalid_cmd", NULL, 98 smb2_invalid_cmd, NULL, 0, 0, 99 SDDF_SUPPRESS_UID | SDDF_SUPPRESS_TID }, 100 }; 101 102 smb_sdrc_t 103 smb2_invalid_cmd(smb_request_t *sr) 104 { 105 #ifdef DEBUG 106 cmn_err(CE_NOTE, "clnt %s bad SMB2 cmd code", 107 sr->session->ip_addr_str); 108 #endif 109 sr->smb2_status = NT_STATUS_INVALID_PARAMETER; 110 return (SDRC_DROP_VC); 111 } 112 113 /* 114 * This is the SMB2 handler for new smb requests, called from 115 * smb_session_reader after SMB negotiate is done. For most SMB2 116 * requests, we just enqueue them for the smb_session_worker to 117 * execute via the task queue, so they can block for resources 118 * without stopping the reader thread. A few protocol messages 119 * are special cases and are handled directly here in the reader 120 * thread so they don't wait for taskq scheduling. 121 * 122 * This function must either enqueue the new request for 123 * execution via the task queue, or execute it directly 124 * and then free it. If this returns non-zero, the caller 125 * will drop the session. 126 */ 127 int 128 smb2sr_newrq(smb_request_t *sr) 129 { 130 struct mbuf_chain *mbc = &sr->command; 131 taskqid_t tqid; 132 uint32_t magic; 133 int rc, skip; 134 135 if (smb_mbc_peek(mbc, 0, "l", &magic) != 0) 136 goto drop; 137 138 /* 0xFD S M B */ 139 if (magic == SMB3_ENCRYPTED_MAGIC) { 140 if (smb3_decrypt_msg(sr) != 0) 141 goto drop; 142 /* 143 * Should now be looking at an un-encrypted 144 * SMB2 message header. 145 */ 146 if (smb_mbc_peek(mbc, 0, "l", &magic) != 0) 147 goto drop; 148 } 149 150 if (magic != SMB2_PROTOCOL_MAGIC) 151 goto drop; 152 153 /* 154 * Walk the SMB2 commands in this compound message and 155 * keep track of the range of message IDs it uses. 156 */ 157 for (;;) { 158 if (smb2_decode_header(sr) != 0) 159 goto drop; 160 161 /* 162 * Cancel requests are special: They refer to 163 * an earlier message ID (or an async. ID), 164 * never a new ID, and are never compounded. 165 * This is intentionally not "goto drop" 166 * because rc may be zero (success). 167 */ 168 if (sr->smb2_cmd_code == SMB2_CANCEL) { 169 rc = smb2_newrq_cancel(sr); 170 smb_request_free(sr); 171 return (rc); 172 } 173 174 /* 175 * Keep track of the total credits in this compound 176 * and the first (real) message ID (not: 0, -1) 177 * While we're looking, verify that all (real) IDs 178 * are (first <= ID < (first + msg_credits)) 179 */ 180 if (sr->smb2_credit_charge == 0) 181 sr->smb2_credit_charge = 1; 182 sr->smb2_total_credits += sr->smb2_credit_charge; 183 184 if (sr->smb2_messageid != 0 && 185 sr->smb2_messageid != UINT64_MAX) { 186 187 if (sr->smb2_first_msgid == 0) 188 sr->smb2_first_msgid = sr->smb2_messageid; 189 190 if (sr->smb2_messageid < sr->smb2_first_msgid || 191 sr->smb2_messageid >= (sr->smb2_first_msgid + 192 sr->smb2_total_credits)) { 193 long long id = (long long) sr->smb2_messageid; 194 cmn_err(CE_WARN, "clnt %s msg ID 0x%llx " 195 "out of sequence in compound", 196 sr->session->ip_addr_str, id); 197 } 198 } 199 200 /* Normal loop exit on next == zero */ 201 if (sr->smb2_next_command == 0) 202 break; 203 204 /* Abundance of caution... */ 205 if (sr->smb2_next_command < SMB2_HDR_SIZE) 206 goto drop; 207 208 /* Advance to the next header. */ 209 skip = sr->smb2_next_command - SMB2_HDR_SIZE; 210 if (MBC_ROOM_FOR(mbc, skip) == 0) 211 goto drop; 212 mbc->chain_offset += skip; 213 } 214 /* Rewind back to the top. */ 215 mbc->chain_offset = 0; 216 217 /* 218 * Submit the request to the task queue, which calls 219 * smb2_tq_work when the workload permits. 220 */ 221 sr->sr_time_submitted = gethrtime(); 222 sr->sr_state = SMB_REQ_STATE_SUBMITTED; 223 smb_srqueue_waitq_enter(sr->session->s_srqueue); 224 tqid = taskq_dispatch(sr->sr_server->sv_worker_pool, 225 smb2_tq_work, sr, TQ_SLEEP); 226 VERIFY(tqid != TASKQID_INVALID); 227 228 return (0); 229 230 drop: 231 smb_request_free(sr); 232 return (-1); 233 } 234 235 static void 236 smb2_tq_work(void *arg) 237 { 238 smb_request_t *sr; 239 smb_srqueue_t *srq; 240 241 sr = (smb_request_t *)arg; 242 SMB_REQ_VALID(sr); 243 244 srq = sr->session->s_srqueue; 245 smb_srqueue_waitq_to_runq(srq); 246 sr->sr_worker = curthread; 247 sr->sr_time_active = gethrtime(); 248 249 /* 250 * Always dispatch to the work function, because cancelled 251 * requests need an error reply (NT_STATUS_CANCELLED). 252 */ 253 mutex_enter(&sr->sr_mutex); 254 if (sr->sr_state == SMB_REQ_STATE_SUBMITTED) 255 sr->sr_state = SMB_REQ_STATE_ACTIVE; 256 mutex_exit(&sr->sr_mutex); 257 258 smb2sr_work(sr); 259 260 smb_srqueue_runq_exit(srq); 261 } 262 263 /* 264 * Wrapper to setup a new mchain for the plaintext request that will 265 * replace the encrypted one. Returns non-zero to drop the connection. 266 * Error return values here are just for visibility in dtrace. 267 */ 268 static int 269 smb3_decrypt_msg(smb_request_t *sr) 270 { 271 struct mbuf_chain clear_mbc = {0}; 272 struct mbuf_chain tmp_mbc; 273 mbuf_t *m; 274 int clearsize; 275 int rc; 276 277 if (sr->session->dialect < SMB_VERS_3_0) { 278 /* Encrypted message in SMB 2.x */ 279 return (-1); 280 } 281 if ((sr->session->srv_cap & SMB2_CAP_ENCRYPTION) == 0) { 282 /* Should have srv_cap SMB2_CAP_ENCRYPTION flag set! */ 283 return (-2); 284 } 285 286 sr->encrypted = B_TRUE; 287 if (sr->command.max_bytes < 288 (SMB3_TFORM_HDR_SIZE + SMB2_HDR_SIZE)) { 289 /* Short transform header */ 290 return (-3); 291 } 292 clearsize = sr->command.max_bytes - SMB3_TFORM_HDR_SIZE; 293 294 clear_mbc.max_bytes = clearsize; 295 m = smb_mbuf_alloc_chain(clearsize); 296 MBC_ATTACH_MBUF(&clear_mbc, m); 297 298 rc = smb3_decrypt_sr(sr, &sr->command, &clear_mbc); 299 if (rc != 0) { 300 MBC_FLUSH(&clear_mbc); 301 return (rc); 302 } 303 304 /* Swap clear_mbc in place of command */ 305 tmp_mbc = sr->command; 306 sr->command = clear_mbc; 307 MBC_FLUSH(&tmp_mbc); // free old sr->command 308 309 return (0); 310 } 311 312 /* 313 * SMB2 credits determine how many simultaneous commands the 314 * client may issue, and bounds the range of message IDs those 315 * commands may use. With multi-credit support, commands may 316 * use ranges of message IDs, where the credits used by each 317 * command are proportional to their data transfer size. 318 * 319 * Every command may request an increase or decrease of 320 * the currently granted credits, based on the difference 321 * between the credit request and the credit charge. 322 * [MS-SMB2] 3.3.1.2 Algorithm for the Granting of Credits 323 * 324 * Most commands have credit_request=1, credit_charge=1, 325 * which keeps the credit grant unchanged. 326 * 327 * All we're really doing here (for now) is reducing the 328 * credit_response if the client requests a credit increase 329 * that would take their credit over the maximum, and 330 * limiting the decrease so they don't run out of credits. 331 * 332 * Later, this could do something dynamic based on load. 333 * 334 * One other non-obvious bit about credits: We keep the 335 * session s_max_credits low until the 1st authentication, 336 * at which point we'll set the normal maximum_credits. 337 * Some clients ask for more credits with session setup, 338 * and we need to handle that requested increase _after_ 339 * the command-specific handler returns so it won't be 340 * restricted to the lower (pre-auth) limit. 341 */ 342 static inline void 343 smb2_credit_decrease(smb_request_t *sr) 344 { 345 smb_session_t *session = sr->session; 346 uint16_t cur, d; 347 348 ASSERT3U(sr->smb2_credit_request, <, sr->smb2_credit_charge); 349 350 mutex_enter(&session->s_credits_mutex); 351 cur = session->s_cur_credits; 352 ASSERT(cur > 0); 353 354 /* Handle credit decrease. */ 355 d = sr->smb2_credit_charge - sr->smb2_credit_request; 356 357 /* 358 * Prevent underflow of current credits, and 359 * enforce a minimum of one credit, per: 360 * [MS-SMB2] 3.3.1.2 361 */ 362 if (d >= cur) { 363 /* 364 * Tried to give up more credits than we should. 365 * Reduce the decrement. 366 */ 367 d = cur - 1; 368 cur = 1; 369 DTRACE_PROBE1(smb2__credit__neg, smb_request_t *, sr); 370 } else { 371 cur -= d; 372 } 373 374 ASSERT3U(d, <=, sr->smb2_credit_charge); 375 sr->smb2_credit_response = sr->smb2_credit_charge - d; 376 377 DTRACE_PROBE3(smb2__credit__decrease, 378 smb_request_t *, sr, int, (int)cur, 379 int, (int)session->s_cur_credits); 380 381 session->s_cur_credits = cur; 382 mutex_exit(&session->s_credits_mutex); 383 } 384 385 /* 386 * Second half of SMB2 credit handling (increases) 387 */ 388 static inline void 389 smb2_credit_increase(smb_request_t *sr) 390 { 391 smb_session_t *session = sr->session; 392 uint16_t cur, d; 393 394 ASSERT3U(sr->smb2_credit_request, >, sr->smb2_credit_charge); 395 396 mutex_enter(&session->s_credits_mutex); 397 cur = session->s_cur_credits; 398 399 /* Handle credit increase. */ 400 d = sr->smb2_credit_request - sr->smb2_credit_charge; 401 402 /* 403 * If new credits would be above max, 404 * reduce the credit grant. 405 */ 406 if (d > (session->s_max_credits - cur)) { 407 d = session->s_max_credits - cur; 408 cur = session->s_max_credits; 409 DTRACE_PROBE1(smb2__credit__max, smb_request_t *, sr); 410 } else { 411 cur += d; 412 } 413 sr->smb2_credit_response = sr->smb2_credit_charge + d; 414 415 DTRACE_PROBE3(smb2__credit__increase, 416 smb_request_t *, sr, int, (int)cur, 417 int, (int)session->s_cur_credits); 418 419 session->s_cur_credits = cur; 420 mutex_exit(&session->s_credits_mutex); 421 } 422 423 /* 424 * Record some statistics: latency, rx bytes, tx bytes 425 * per: server, session & kshare. 426 */ 427 static inline void 428 smb2_record_stats(smb_request_t *sr, smb_disp_stats_t *sds, boolean_t tx_only) 429 { 430 hrtime_t dt; 431 int64_t rxb; 432 int64_t txb; 433 434 dt = gethrtime() - sr->sr_time_start; 435 rxb = (int64_t)(sr->command.chain_offset - sr->smb2_cmd_hdr); 436 txb = (int64_t)(sr->reply.chain_offset - sr->smb2_reply_hdr); 437 438 if (!tx_only) { 439 smb_server_inc_req(sr->sr_server); 440 smb_latency_add_sample(&sds->sdt_lat, dt); 441 atomic_add_64(&sds->sdt_rxb, rxb); 442 } 443 atomic_add_64(&sds->sdt_txb, txb); 444 } 445 446 /* 447 * smb2sr_work 448 * 449 * This function processes each SMB command in the current request 450 * (which may be a compound request) building a reply containing 451 * SMB reply messages, one-to-one with the SMB commands. Some SMB 452 * commands (change notify, blocking locks) may require both an 453 * "interim response" and a later "async response" at completion. 454 * In such cases, we'll encode the interim response in the reply 455 * compound we're building, and put the (now async) command on a 456 * list of commands that need further processing. After we've 457 * finished processing the commands in this compound and building 458 * the compound reply, we'll send the compound reply, and finally 459 * process the list of async commands. 460 * 461 * As we work our way through the compound request and reply, 462 * we need to keep track of the bounds of the current request 463 * and reply. For the request, this uses an MBC_SHADOW_CHAIN 464 * that begins at smb2_cmd_hdr. The reply is appended to the 465 * sr->reply chain starting at smb2_reply_hdr. 466 * 467 * This function must always free the smb request, or arrange 468 * for it to be completed and free'd later (if SDRC_SR_KEPT). 469 */ 470 void 471 smb2sr_work(struct smb_request *sr) 472 { 473 const smb_disp_entry_t *sdd; 474 smb_disp_stats_t *sds; 475 smb_session_t *session; 476 uint32_t msg_len; 477 uint16_t cmd_idx; 478 int rc = 0; 479 boolean_t disconnect = B_FALSE; 480 boolean_t related; 481 482 session = sr->session; 483 484 ASSERT(sr->smb2_async == B_FALSE); 485 ASSERT(sr->tid_tree == 0); 486 ASSERT(sr->uid_user == 0); 487 ASSERT(sr->fid_ofile == 0); 488 sr->smb_fid = (uint16_t)-1; 489 sr->smb2_status = 0; 490 491 /* temporary until we identify a user */ 492 sr->user_cr = zone_kcred(); 493 494 cmd_start: 495 /* 496 * Note that we don't check sr_state here and abort the 497 * compound if cancelled (etc.) because some SMB2 command 498 * handlers need to do work even when cancelled. 499 * 500 * We treat some status codes as if "sticky", meaning 501 * once they're set after some command handler returns, 502 * all remaining commands get this status without even 503 * calling the command-specific handler. 504 */ 505 if (sr->smb2_status != NT_STATUS_CANCELLED && 506 sr->smb2_status != NT_STATUS_INSUFFICIENT_RESOURCES) 507 sr->smb2_status = 0; 508 509 /* 510 * Decode the request header 511 * 512 * Most problems with decoding will result in the error 513 * STATUS_INVALID_PARAMETER. If the decoding problem 514 * prevents continuing, we'll close the connection. 515 * [MS-SMB2] 3.3.5.2.6 Handling Incorrectly Formatted... 516 */ 517 sr->smb2_cmd_hdr = sr->command.chain_offset; 518 if ((rc = smb2_decode_header(sr)) != 0) { 519 cmn_err(CE_WARN, "clnt %s bad SMB2 header", 520 session->ip_addr_str); 521 disconnect = B_TRUE; 522 goto cleanup; 523 } 524 525 /* 526 * The SMB2_FLAGS_SERVER_TO_REDIR should only appear 527 * in messages from the server back to the client. 528 */ 529 if ((sr->smb2_hdr_flags & SMB2_FLAGS_SERVER_TO_REDIR) != 0) { 530 cmn_err(CE_WARN, "clnt %s bad SMB2 flags", 531 session->ip_addr_str); 532 disconnect = B_TRUE; 533 goto cleanup; 534 } 535 related = (sr->smb2_hdr_flags & SMB2_FLAGS_RELATED_OPERATIONS); 536 sr->smb2_hdr_flags |= SMB2_FLAGS_SERVER_TO_REDIR; 537 if (sr->smb2_hdr_flags & SMB2_FLAGS_ASYNC_COMMAND) { 538 /* Probably an async cancel. */ 539 DTRACE_PROBE1(smb2__dispatch__async, smb_request_t *, sr); 540 } else if (sr->smb2_async) { 541 /* Previous command in compound went async. */ 542 sr->smb2_hdr_flags |= SMB2_FLAGS_ASYNC_COMMAND; 543 sr->smb2_async_id = SMB2_ASYNCID(sr); 544 } 545 546 /* 547 * In case we bail out with an error before we get to the 548 * section that computes the credit grant, initialize the 549 * response header fields so that credits won't change. 550 * Note: SMB 2.02 clients may send credit charge zero. 551 */ 552 if (sr->smb2_credit_charge == 0) 553 sr->smb2_credit_charge = 1; 554 sr->smb2_credit_response = sr->smb2_credit_charge; 555 556 /* 557 * Write a tentative reply header. 558 * 559 * We could just leave this blank, but if we're using the 560 * mdb module feature that extracts packets, it's useful 561 * to have the header mostly correct here. 562 * 563 * If we have already exhausted the output space, then the 564 * client is trying something funny. Log it and kill 'em. 565 */ 566 sr->smb2_next_reply = 0; 567 ASSERT((sr->reply.chain_offset & 7) == 0); 568 sr->smb2_reply_hdr = sr->reply.chain_offset; 569 if ((rc = smb2_encode_header(sr, B_FALSE)) != 0) { 570 cmn_err(CE_WARN, "clnt %s excessive reply", 571 session->ip_addr_str); 572 disconnect = B_TRUE; 573 goto cleanup; 574 } 575 576 /* 577 * Figure out the length of data following the SMB2 header. 578 * It ends at either the next SMB2 header if there is one 579 * (smb2_next_command != 0) or at the end of the message. 580 */ 581 if (sr->smb2_next_command != 0) { 582 /* [MS-SMB2] says this is 8-byte aligned */ 583 msg_len = sr->smb2_next_command; 584 if ((msg_len & 7) != 0 || (msg_len < SMB2_HDR_SIZE) || 585 ((sr->smb2_cmd_hdr + msg_len) > sr->command.max_bytes)) { 586 cmn_err(CE_WARN, "clnt %s bad SMB2 next cmd", 587 session->ip_addr_str); 588 disconnect = B_TRUE; 589 goto cleanup; 590 } 591 } else { 592 msg_len = sr->command.max_bytes - sr->smb2_cmd_hdr; 593 } 594 595 /* 596 * Setup a shadow chain for this SMB2 command, starting 597 * with the header and ending at either the next command 598 * or the end of the message. The signing check below 599 * needs the entire SMB2 command. After that's done, we 600 * advance chain_offset to the end of the header where 601 * the command specific handlers continue decoding. 602 */ 603 (void) MBC_SHADOW_CHAIN(&sr->smb_data, &sr->command, 604 sr->smb2_cmd_hdr, msg_len); 605 606 /* 607 * We will consume the data for this request from smb_data. 608 * That effectively consumes msg_len bytes from sr->command 609 * but doesn't update its chain_offset, so we need to update 610 * that here to make later received bytes accounting work. 611 */ 612 sr->command.chain_offset = sr->smb2_cmd_hdr + msg_len; 613 ASSERT(sr->command.chain_offset <= sr->command.max_bytes); 614 615 /* 616 * Validate the commmand code, get dispatch table entries. 617 * [MS-SMB2] 3.3.5.2.6 Handling Incorrectly Formatted... 618 * 619 * The last slot in the dispatch table is used to handle 620 * invalid commands. Same for statistics. 621 */ 622 if (sr->smb2_cmd_code < SMB2_INVALID_CMD) 623 cmd_idx = sr->smb2_cmd_code; 624 else 625 cmd_idx = SMB2_INVALID_CMD; 626 sdd = &smb2_disp_table[cmd_idx]; 627 sds = &session->s_server->sv_disp_stats2[cmd_idx]; 628 629 /* 630 * If this command is NOT "related" to the previous, 631 * clear out the UID, TID, FID state that might be 632 * left over from the previous command. 633 * 634 * If the command IS related, any new IDs are ignored, 635 * and we simply continue with the previous user, tree, 636 * and open file. 637 */ 638 if (!related) { 639 /* 640 * Drop user, tree, file; carefully ordered to 641 * avoid dangling references: file, tree, user 642 */ 643 if (sr->fid_ofile != NULL) { 644 smb_ofile_release(sr->fid_ofile); 645 sr->fid_ofile = NULL; 646 } 647 if (sr->tid_tree != NULL) { 648 smb_tree_release(sr->tid_tree); 649 sr->tid_tree = NULL; 650 } 651 if (sr->uid_user != NULL) { 652 smb_user_release(sr->uid_user); 653 sr->uid_user = NULL; 654 sr->user_cr = zone_kcred(); 655 } 656 } 657 658 /* 659 * Make sure we have a user and tree as needed 660 * according to the flags for the this command. 661 * Note that we may have inherited these. 662 */ 663 if ((sdd->sdt_flags & SDDF_SUPPRESS_UID) == 0) { 664 /* 665 * This command requires a user session. 666 */ 667 if (related) { 668 /* 669 * Previous command should have given us a user. 670 * [MS-SMB2] 3.3.5.2 Handling Related Requests 671 */ 672 if (sr->uid_user == NULL) { 673 smb2sr_put_error(sr, 674 NT_STATUS_INVALID_PARAMETER); 675 goto cmd_done; 676 } 677 sr->smb2_ssnid = sr->uid_user->u_ssnid; 678 } else { 679 /* 680 * Lookup the UID 681 * [MS-SMB2] 3.3.5.2 Verifying the Session 682 */ 683 ASSERT(sr->uid_user == NULL); 684 /* 685 * [MS-SMB2] 3.3.5.2.7 Handling Compounded Requests 686 * 687 * If this is an encrypted compound request, 688 * ensure that the ssnid in the request 689 * is the same as the tform ssnid if this 690 * message is not related. 691 * 692 * The reasons this is done seem to apply equally 693 * to uncompounded requests, so we apply it to all. 694 */ 695 696 if (sr->encrypted && 697 sr->smb2_ssnid != sr->th_ssnid) { 698 disconnect = B_TRUE; 699 goto cleanup; /* just do this for now */ 700 } 701 702 sr->uid_user = smb_session_lookup_ssnid(session, 703 sr->smb2_ssnid); 704 if (sr->uid_user == NULL) { 705 smb2sr_put_error(sr, 706 NT_STATUS_USER_SESSION_DELETED); 707 goto cmd_done; 708 } 709 710 /* 711 * [MS-SMB2] 3.3.5.2.9 Verifying the Session 712 * 713 * If we're talking 3.x, 714 * RejectUnencryptedAccess is TRUE, 715 * Session.EncryptData is TRUE, 716 * and the message wasn't encrypted, 717 * return ACCESS_DENIED. 718 * 719 * Note that Session.EncryptData can only be TRUE when 720 * we're talking 3.x. 721 */ 722 if (sr->uid_user->u_encrypt == SMB_CONFIG_REQUIRED && 723 !sr->encrypted) { 724 smb2sr_put_error(sr, 725 NT_STATUS_ACCESS_DENIED); 726 goto cmd_done; 727 } 728 729 sr->user_cr = smb_user_getcred(sr->uid_user); 730 } 731 ASSERT(sr->uid_user != NULL); 732 733 /* 734 * Encrypt if: 735 * - The cmd is not SESSION_SETUP or NEGOTIATE; AND 736 * - Session.EncryptData is TRUE 737 * 738 * Those commands suppress UID, so they can't be the cmd here. 739 */ 740 if (sr->uid_user->u_encrypt != SMB_CONFIG_DISABLED && 741 sr->th_sid_user == NULL) { 742 smb_user_hold_internal(sr->uid_user); 743 sr->th_sid_user = sr->uid_user; 744 sr->th_ssnid = sr->smb2_ssnid; 745 } 746 } 747 748 if ((sdd->sdt_flags & SDDF_SUPPRESS_TID) == 0) { 749 /* 750 * This command requires a tree connection. 751 */ 752 if (related) { 753 /* 754 * Previous command should have given us a tree. 755 * [MS-SMB2] 3.3.5.2 Handling Related Requests 756 */ 757 if (sr->tid_tree == NULL) { 758 smb2sr_put_error(sr, 759 NT_STATUS_INVALID_PARAMETER); 760 goto cmd_done; 761 } 762 sr->smb_tid = sr->tid_tree->t_tid; 763 } else { 764 /* 765 * Lookup the TID 766 * [MS-SMB2] 3.3.5.2 Verifying the Tree Connect 767 */ 768 ASSERT(sr->tid_tree == NULL); 769 sr->tid_tree = smb_session_lookup_tree(session, 770 sr->smb_tid); 771 if (sr->tid_tree == NULL) { 772 smb2sr_put_error(sr, 773 NT_STATUS_NETWORK_NAME_DELETED); 774 goto cmd_done; 775 } 776 777 /* 778 * [MS-SMB2] 3.3.5.2.11 Verifying the Tree Connect 779 * 780 * If we support 3.x, RejectUnencryptedAccess is TRUE, 781 * if Tcon.EncryptData is TRUE or 782 * global EncryptData is TRUE and 783 * the message wasn't encrypted, or 784 * if Tcon.EncryptData is TRUE or 785 * global EncryptData is TRUE or 786 * the request was encrypted and 787 * the connection doesn't support encryption, 788 * return ACCESS_DENIED. 789 * 790 * If RejectUnencryptedAccess is TRUE, we force 791 * max_protocol to at least 3.0. Additionally, 792 * if the tree requires encryption, we don't care 793 * what we support, we still enforce encryption. 794 * Since smb3_decrypt_msg() does check session->srv_cap, 795 * we only need to check sr->encrypted here. 796 */ 797 if (sr->tid_tree->t_encrypt == SMB_CONFIG_REQUIRED && 798 !sr->encrypted) { 799 smb2sr_put_error(sr, 800 NT_STATUS_ACCESS_DENIED); 801 goto cmd_done; 802 } 803 } 804 ASSERT(sr->tid_tree != NULL); 805 806 /* 807 * Encrypt if: 808 * - The cmd is not TREE_CONNECT; AND 809 * - Tree.EncryptData is TRUE 810 * 811 * TREE_CONNECT suppresses TID, so that can't be the cmd here. 812 * NOTE: assumes we can't have a tree without a user 813 */ 814 if (sr->tid_tree->t_encrypt != SMB_CONFIG_DISABLED && 815 sr->th_sid_user == NULL) { 816 smb_user_hold_internal(sr->uid_user); 817 sr->th_sid_user = sr->uid_user; 818 sr->th_ssnid = sr->smb2_ssnid; 819 } 820 } 821 822 /* 823 * SMB2 signature verification, two parts: 824 * (a) Require SMB2_FLAGS_SIGNED (for most request types) 825 * (b) If SMB2_FLAGS_SIGNED is set, check the signature. 826 * [MS-SMB2] 3.3.5.2.4 Verifying the Signature 827 */ 828 829 /* 830 * No user session means no signature check. That's OK, 831 * i.e. for commands marked SDDF_SUPPRESS_UID above. 832 * Note, this also means we won't sign the reply. 833 */ 834 if (sr->uid_user == NULL) 835 sr->smb2_hdr_flags &= ~SMB2_FLAGS_SIGNED; 836 837 /* 838 * The SDDF_SUPPRESS_UID dispatch is set for requests that 839 * don't need a UID (user). These also don't require a 840 * signature check here. 841 * 842 * [MS-SMB2] 3.3.5.2.4 Verifying the Signature 843 * 844 * If the packet was successfully decrypted, the message 845 * signature has already been verified, so we can skip this. 846 */ 847 if ((sdd->sdt_flags & SDDF_SUPPRESS_UID) == 0 && 848 !sr->encrypted && sr->uid_user != NULL && 849 (sr->uid_user->u_sign_flags & SMB_SIGNING_ENABLED) != 0) { 850 /* 851 * If the request is signed, check the signature. 852 * Otherwise, if signing is required, deny access. 853 */ 854 if ((sr->smb2_hdr_flags & SMB2_FLAGS_SIGNED) != 0) { 855 if (smb2_sign_check_request(sr) != 0) { 856 smb2sr_put_error(sr, NT_STATUS_ACCESS_DENIED); 857 DTRACE_PROBE1(smb2__sign__check, 858 smb_request_t *, sr); 859 goto cmd_done; 860 } 861 } else if ( 862 (sr->uid_user->u_sign_flags & SMB_SIGNING_CHECK) != 0) { 863 smb2sr_put_error(sr, NT_STATUS_ACCESS_DENIED); 864 goto cmd_done; 865 } 866 } 867 868 /* 869 * Now that the signing check is done with smb_data, 870 * advance past the SMB2 header we decoded earlier. 871 * This leaves sr->smb_data correctly positioned 872 * for command-specific decoding in the dispatch 873 * function called next. 874 */ 875 sr->smb_data.chain_offset = sr->smb2_cmd_hdr + SMB2_HDR_SIZE; 876 877 /* 878 * Credit adjustments (decrease) 879 * 880 * If we've gone async, credit adjustments were done 881 * when we sent the interim reply. 882 */ 883 if (!sr->smb2_async) { 884 if (sr->smb2_credit_request < sr->smb2_credit_charge) { 885 smb2_credit_decrease(sr); 886 } 887 } 888 889 /* 890 * The real work: call the SMB2 command handler 891 * (except for "sticky" smb2_status - see above) 892 */ 893 sr->sr_time_start = gethrtime(); 894 rc = SDRC_SUCCESS; 895 if (sr->smb2_status == 0) { 896 /* NB: not using pre_op */ 897 rc = (*sdd->sdt_function)(sr); 898 /* NB: not using post_op */ 899 } else { 900 smb2sr_put_error(sr, sr->smb2_status); 901 } 902 903 /* 904 * When the sdt_function returns SDRC_SR_KEPT, it means 905 * this SR may have been passed to another thread so we 906 * MUST NOT touch it anymore. 907 */ 908 if (rc == SDRC_SR_KEPT) 909 return; 910 911 MBC_FLUSH(&sr->raw_data); 912 913 /* 914 * Credit adjustments (increase) 915 */ 916 if (!sr->smb2_async) { 917 if (sr->smb2_credit_request > sr->smb2_credit_charge) { 918 smb2_credit_increase(sr); 919 } 920 } 921 922 cmd_done: 923 switch (rc) { 924 case SDRC_SUCCESS: 925 break; 926 default: 927 /* 928 * SMB2 does not use the other dispatch return codes. 929 * If we see something else, log an event so we'll 930 * know something is returning bogus status codes. 931 * If you see these in the log, use dtrace to find 932 * the code returning something else. 933 */ 934 #ifdef DEBUG 935 cmn_err(CE_NOTE, "handler for %u returned 0x%x", 936 sr->smb2_cmd_code, rc); 937 #endif 938 smb2sr_put_error(sr, NT_STATUS_INTERNAL_ERROR); 939 break; 940 case SDRC_ERROR: 941 /* 942 * Many command handlers return SDRC_ERROR for any 943 * problems decoding the request, and don't bother 944 * setting smb2_status. For those cases, the best 945 * status return would be "invalid parameter". 946 */ 947 if (sr->smb2_status == 0) 948 sr->smb2_status = NT_STATUS_INVALID_PARAMETER; 949 smb2sr_put_error(sr, sr->smb2_status); 950 break; 951 case SDRC_DROP_VC: 952 disconnect = B_TRUE; 953 goto cleanup; 954 955 case SDRC_NO_REPLY: 956 /* will free sr */ 957 goto cleanup; 958 } 959 960 /* 961 * Pad the reply to align(8) if there will be another. 962 * (We don't compound async replies.) 963 */ 964 if (!sr->smb2_async && sr->smb2_next_command != 0) 965 (void) smb_mbc_put_align(&sr->reply, 8); 966 967 /* 968 * Record some statistics. Uses: 969 * rxb = command.chain_offset - smb2_cmd_hdr; 970 * txb = reply.chain_offset - smb2_reply_hdr; 971 * which at this point represent the current cmd/reply. 972 * 973 * Note: If async, this does txb only, and 974 * skips the smb_latency_add_sample() calls. 975 */ 976 smb2_record_stats(sr, sds, sr->smb2_async); 977 978 /* 979 * If there's a next command, figure out where it starts, 980 * and fill in the next header offset for the reply. 981 * Note: We sanity checked smb2_next_command above. 982 * Once we've gone async, replies are not compounded. 983 */ 984 if (sr->smb2_next_command != 0) { 985 sr->command.chain_offset = 986 sr->smb2_cmd_hdr + sr->smb2_next_command; 987 } 988 if (sr->smb2_next_command != 0 && !sr->smb2_async) { 989 sr->smb2_next_reply = 990 sr->reply.chain_offset - sr->smb2_reply_hdr; 991 } else { 992 ASSERT(sr->smb2_next_reply == 0); 993 } 994 995 /* 996 * Overwrite the (now final) SMB2 header for this response. 997 */ 998 (void) smb2_encode_header(sr, B_TRUE); 999 1000 /* 1001 * Cannot move this into smb2_session_setup() - encoded header required. 1002 */ 1003 if (session->dialect >= SMB_VERS_3_11 && 1004 sr->smb2_cmd_code == SMB2_SESSION_SETUP && 1005 sr->smb2_status == NT_STATUS_MORE_PROCESSING_REQUIRED) { 1006 if (smb31_preauth_sha512_calc(sr, &sr->reply, 1007 sr->uid_user->u_preauth_hashval, 1008 sr->uid_user->u_preauth_hashval) != 0) 1009 cmn_err(CE_WARN, "(3) Preauth hash calculation " 1010 "failed"); 1011 } 1012 1013 /* Don't sign if we're going to encrypt */ 1014 if (sr->th_sid_user == NULL && 1015 (sr->smb2_hdr_flags & SMB2_FLAGS_SIGNED) != 0) 1016 smb2_sign_reply(sr); 1017 1018 /* 1019 * Non-async runs the whole compound before send. 1020 * When we've gone async, send each individually. 1021 */ 1022 if (!sr->smb2_async && sr->smb2_next_command != 0) 1023 goto cmd_start; 1024 1025 /* 1026 * If we have a durable handle, and this operation updated 1027 * the nvlist, write it out (before smb2_send_reply). 1028 */ 1029 if (sr->dh_nvl_dirty) { 1030 sr->dh_nvl_dirty = B_FALSE; 1031 smb2_dh_update_nvfile(sr); 1032 } 1033 1034 smb2_send_reply(sr); 1035 if (sr->smb2_async && sr->smb2_next_command != 0) { 1036 MBC_FLUSH(&sr->reply); /* New reply buffer. */ 1037 ASSERT(sr->reply.max_bytes == sr->session->reply_max_bytes); 1038 goto cmd_start; 1039 } 1040 1041 cleanup: 1042 if (disconnect) 1043 smb_session_disconnect(session); 1044 1045 /* 1046 * Do "postwork" for oplock (and maybe other things) 1047 */ 1048 if (sr->sr_postwork != NULL) 1049 smb2sr_run_postwork(sr); 1050 1051 mutex_enter(&sr->sr_mutex); 1052 sr->sr_state = SMB_REQ_STATE_COMPLETED; 1053 mutex_exit(&sr->sr_mutex); 1054 1055 smb_request_free(sr); 1056 } 1057 1058 /* 1059 * Build interim responses for the current and all following 1060 * requests in this compound, then send the compound response, 1061 * leaving the SR state so that smb2sr_work() can continue its 1062 * processing of this compound in "async mode". 1063 * 1064 * If we agree to "go async", this should return STATUS_SUCCESS. 1065 * Otherwise return STATUS_INSUFFICIENT_RESOURCES for this and 1066 * all requests following this request. (See the comments re. 1067 * "sticky" smb2_status values in smb2sr_work). 1068 * 1069 * Note: the Async ID we assign here is arbitrary, and need only 1070 * be unique among pending async responses on this connection, so 1071 * this just uses a modified messageID, which is already unique. 1072 * 1073 * Credits: All credit changes should happen via the interim 1074 * responses, so we have to manage credits here. After this 1075 * returns to smb2sr_work, the final replies for all these 1076 * commands will have smb2_credit_response = smb2_credit_charge 1077 * (meaning no further changes to the clients' credits). 1078 */ 1079 uint32_t 1080 smb2sr_go_async(smb_request_t *sr) 1081 { 1082 smb_session_t *session; 1083 smb_disp_stats_t *sds; 1084 uint16_t cmd_idx; 1085 int32_t saved_com_offset; 1086 uint32_t saved_cmd_hdr; 1087 uint16_t saved_cred_resp; 1088 uint32_t saved_hdr_flags; 1089 uint32_t saved_reply_hdr; 1090 uint32_t msg_len; 1091 boolean_t disconnect = B_FALSE; 1092 1093 if (sr->smb2_async) { 1094 /* already went async in some previous cmd. */ 1095 return (NT_STATUS_SUCCESS); 1096 } 1097 sr->smb2_async = B_TRUE; 1098 1099 /* The "server" session always runs async. */ 1100 session = sr->session; 1101 if (session->sock == NULL) 1102 return (NT_STATUS_SUCCESS); 1103 1104 sds = NULL; 1105 saved_com_offset = sr->command.chain_offset; 1106 saved_cmd_hdr = sr->smb2_cmd_hdr; 1107 saved_cred_resp = sr->smb2_credit_response; 1108 saved_hdr_flags = sr->smb2_hdr_flags; 1109 saved_reply_hdr = sr->smb2_reply_hdr; 1110 1111 /* 1112 * The command-specific handler should not yet have put any 1113 * data in the reply except for the (place holder) header. 1114 */ 1115 if (sr->reply.chain_offset != sr->smb2_reply_hdr + SMB2_HDR_SIZE) { 1116 ASSERT3U(sr->reply.chain_offset, ==, 1117 sr->smb2_reply_hdr + SMB2_HDR_SIZE); 1118 return (NT_STATUS_INTERNAL_ERROR); 1119 } 1120 1121 /* 1122 * Rewind to the start of the current header in both the 1123 * command and reply bufers, so the loop below can just 1124 * decode/encode just in every pass. This means the 1125 * current command header is decoded again, but that 1126 * avoids having to special-case the first loop pass. 1127 */ 1128 sr->command.chain_offset = sr->smb2_cmd_hdr; 1129 sr->reply.chain_offset = sr->smb2_reply_hdr; 1130 1131 /* 1132 * This command processing loop is a simplified version of 1133 * smb2sr_work() that just puts an "interim response" for 1134 * every command in the compound (NT_STATUS_PENDING). 1135 */ 1136 cmd_start: 1137 sr->smb2_status = NT_STATUS_PENDING; 1138 1139 /* 1140 * Decode the request header 1141 */ 1142 sr->smb2_cmd_hdr = sr->command.chain_offset; 1143 if ((smb2_decode_header(sr)) != 0) { 1144 cmn_err(CE_WARN, "clnt %s bad SMB2 header", 1145 session->ip_addr_str); 1146 disconnect = B_TRUE; 1147 goto cleanup; 1148 } 1149 sr->smb2_hdr_flags |= (SMB2_FLAGS_SERVER_TO_REDIR | 1150 SMB2_FLAGS_ASYNC_COMMAND); 1151 sr->smb2_async_id = SMB2_ASYNCID(sr); 1152 1153 /* 1154 * In case we bail out... 1155 */ 1156 if (sr->smb2_credit_charge == 0) 1157 sr->smb2_credit_charge = 1; 1158 sr->smb2_credit_response = sr->smb2_credit_charge; 1159 1160 /* 1161 * Write a tentative reply header. 1162 */ 1163 sr->smb2_next_reply = 0; 1164 ASSERT((sr->reply.chain_offset & 7) == 0); 1165 sr->smb2_reply_hdr = sr->reply.chain_offset; 1166 if ((smb2_encode_header(sr, B_FALSE)) != 0) { 1167 cmn_err(CE_WARN, "clnt %s excessive reply", 1168 session->ip_addr_str); 1169 disconnect = B_TRUE; 1170 goto cleanup; 1171 } 1172 1173 /* 1174 * Figure out the length of data... 1175 */ 1176 if (sr->smb2_next_command != 0) { 1177 /* [MS-SMB2] says this is 8-byte aligned */ 1178 msg_len = sr->smb2_next_command; 1179 if ((msg_len & 7) != 0 || (msg_len < SMB2_HDR_SIZE) || 1180 ((sr->smb2_cmd_hdr + msg_len) > sr->command.max_bytes)) { 1181 cmn_err(CE_WARN, "clnt %s bad SMB2 next cmd", 1182 session->ip_addr_str); 1183 disconnect = B_TRUE; 1184 goto cleanup; 1185 } 1186 } else { 1187 msg_len = sr->command.max_bytes - sr->smb2_cmd_hdr; 1188 } 1189 1190 /* 1191 * We just skip any data, so no shadow chain etc. 1192 */ 1193 sr->command.chain_offset = sr->smb2_cmd_hdr + msg_len; 1194 ASSERT(sr->command.chain_offset <= sr->command.max_bytes); 1195 1196 /* 1197 * Validate the commmand code... 1198 */ 1199 if (sr->smb2_cmd_code < SMB2_INVALID_CMD) 1200 cmd_idx = sr->smb2_cmd_code; 1201 else 1202 cmd_idx = SMB2_INVALID_CMD; 1203 sds = &session->s_server->sv_disp_stats2[cmd_idx]; 1204 1205 /* 1206 * Don't change (user, tree, file) because we want them 1207 * exactly as they were when we entered. That also means 1208 * we may not have the right user in sr->uid_user for 1209 * signature checks, so leave that until smb2sr_work 1210 * runs these commands "for real". Therefore, here 1211 * we behave as if: (sr->uid_user == NULL) 1212 */ 1213 sr->smb2_hdr_flags &= ~SMB2_FLAGS_SIGNED; 1214 1215 /* 1216 * Credit adjustments (decrease) 1217 * 1218 * NOTE: interim responses are not signed. 1219 * Any attacker can modify the credit grant 1220 * in the response. Because of this property, 1221 * it is no worse to assume the credit charge and grant 1222 * are sane without verifying the signature, 1223 * and that saves us a whole lot of work. 1224 * If the credits WERE modified, we'll find out 1225 * when we verify the signature later, 1226 * which nullifies any changes caused here. 1227 * 1228 * Skip this on the first command, because the 1229 * credit decrease was done by the caller. 1230 */ 1231 if (sr->smb2_cmd_hdr != saved_cmd_hdr) { 1232 if (sr->smb2_credit_request < sr->smb2_credit_charge) { 1233 smb2_credit_decrease(sr); 1234 } 1235 } 1236 1237 /* 1238 * The real work: ... (would be here) 1239 */ 1240 smb2sr_put_error(sr, sr->smb2_status); 1241 1242 /* 1243 * Credit adjustments (increase) 1244 */ 1245 if (sr->smb2_credit_request > sr->smb2_credit_charge) { 1246 smb2_credit_increase(sr); 1247 } 1248 1249 /* cmd_done: label */ 1250 1251 /* 1252 * Pad the reply to align(8) if there will be another. 1253 * This (interim) reply uses compounding. 1254 */ 1255 if (sr->smb2_next_command != 0) 1256 (void) smb_mbc_put_align(&sr->reply, 8); 1257 1258 /* 1259 * Record some statistics. Uses: 1260 * rxb = command.chain_offset - smb2_cmd_hdr; 1261 * txb = reply.chain_offset - smb2_reply_hdr; 1262 * which at this point represent the current cmd/reply. 1263 * 1264 * Note: We're doing smb_latency_add_sample() for all 1265 * remaining commands NOW, which means we won't include 1266 * the async part of their work in latency statistics. 1267 * That's intentional, as the async part of a command 1268 * would otherwise skew our latency statistics. 1269 */ 1270 smb2_record_stats(sr, sds, B_FALSE); 1271 1272 /* 1273 * If there's a next command, figure out where it starts, 1274 * and fill in the next header offset for the reply. 1275 * Note: We sanity checked smb2_next_command above. 1276 */ 1277 if (sr->smb2_next_command != 0) { 1278 sr->command.chain_offset = 1279 sr->smb2_cmd_hdr + sr->smb2_next_command; 1280 sr->smb2_next_reply = 1281 sr->reply.chain_offset - sr->smb2_reply_hdr; 1282 } else { 1283 ASSERT(sr->smb2_next_reply == 0); 1284 } 1285 1286 /* 1287 * Overwrite the (now final) SMB2 header for this response. 1288 */ 1289 (void) smb2_encode_header(sr, B_TRUE); 1290 1291 /* 1292 * Process whole compound before sending. 1293 */ 1294 if (sr->smb2_next_command != 0) 1295 goto cmd_start; 1296 smb2_send_reply(sr); 1297 1298 ASSERT(!disconnect); 1299 1300 cleanup: 1301 /* 1302 * Restore caller's command processing state. 1303 */ 1304 sr->smb2_cmd_hdr = saved_cmd_hdr; 1305 sr->command.chain_offset = saved_cmd_hdr; 1306 (void) smb2_decode_header(sr); 1307 sr->command.chain_offset = saved_com_offset; 1308 1309 sr->smb2_credit_response = saved_cred_resp; 1310 sr->smb2_hdr_flags = saved_hdr_flags; 1311 sr->smb2_status = NT_STATUS_SUCCESS; 1312 1313 /* 1314 * In here, the "disconnect" flag just means we had an 1315 * error decoding or encoding something. Rather than 1316 * actually disconnect here, let's assume whatever 1317 * problem we encountered will be seen by the caller 1318 * as they continue processing the compound, and just 1319 * restore everything and return an error. 1320 */ 1321 if (disconnect) { 1322 sr->smb2_async = B_FALSE; 1323 sr->smb2_reply_hdr = saved_reply_hdr; 1324 sr->reply.chain_offset = sr->smb2_reply_hdr; 1325 (void) smb2_encode_header(sr, B_FALSE); 1326 return (NT_STATUS_INVALID_PARAMETER); 1327 } 1328 1329 /* 1330 * The compound reply buffer we sent is now gone. 1331 * Setup a new reply buffer for the caller. 1332 */ 1333 sr->smb2_hdr_flags |= SMB2_FLAGS_ASYNC_COMMAND; 1334 sr->smb2_async_id = SMB2_ASYNCID(sr); 1335 sr->smb2_next_reply = 0; 1336 MBC_FLUSH(&sr->reply); 1337 ASSERT(sr->reply.max_bytes == sr->session->reply_max_bytes); 1338 ASSERT(sr->reply.chain_offset == 0); 1339 sr->smb2_reply_hdr = 0; 1340 (void) smb2_encode_header(sr, B_FALSE); 1341 1342 return (NT_STATUS_SUCCESS); 1343 } 1344 1345 int 1346 smb2_decode_header(smb_request_t *sr) 1347 { 1348 uint32_t pid, tid; 1349 uint16_t hdr_len; 1350 int rc; 1351 1352 rc = smb_mbc_decodef( 1353 &sr->command, "Nwww..wwllqllq16c", 1354 &hdr_len, /* w */ 1355 &sr->smb2_credit_charge, /* w */ 1356 &sr->smb2_chan_seq, /* w */ 1357 /* reserved .. */ 1358 &sr->smb2_cmd_code, /* w */ 1359 &sr->smb2_credit_request, /* w */ 1360 &sr->smb2_hdr_flags, /* l */ 1361 &sr->smb2_next_command, /* l */ 1362 &sr->smb2_messageid, /* q */ 1363 &pid, /* l */ 1364 &tid, /* l */ 1365 &sr->smb2_ssnid, /* q */ 1366 sr->smb2_sig); /* 16c */ 1367 if (rc) 1368 return (rc); 1369 1370 if (hdr_len != SMB2_HDR_SIZE) 1371 return (-1); 1372 1373 if (sr->smb2_hdr_flags & SMB2_FLAGS_ASYNC_COMMAND) { 1374 sr->smb2_async_id = pid | 1375 ((uint64_t)tid) << 32; 1376 sr->smb_pid = 0; 1377 sr->smb_tid = 0; 1378 } else { 1379 sr->smb2_async_id = 0; 1380 sr->smb_pid = pid; 1381 sr->smb_tid = (uint16_t)tid; /* XXX wide TIDs */ 1382 } 1383 1384 return (rc); 1385 } 1386 1387 int 1388 smb2_encode_header(smb_request_t *sr, boolean_t overwrite) 1389 { 1390 uint64_t pid_tid_aid; /* pid+tid, or async id */ 1391 int rc; 1392 1393 if (sr->smb2_hdr_flags & SMB2_FLAGS_ASYNC_COMMAND) { 1394 pid_tid_aid = sr->smb2_async_id; 1395 } else { 1396 pid_tid_aid = sr->smb_pid | 1397 ((uint64_t)sr->smb_tid) << 32; 1398 } 1399 1400 if (overwrite) { 1401 rc = smb_mbc_poke(&sr->reply, 1402 sr->smb2_reply_hdr, 1403 "Nwwlwwllqqq16c", 1404 SMB2_HDR_SIZE, /* w */ 1405 sr->smb2_credit_charge, /* w */ 1406 sr->smb2_status, /* l */ 1407 sr->smb2_cmd_code, /* w */ 1408 sr->smb2_credit_response, /* w */ 1409 sr->smb2_hdr_flags, /* l */ 1410 sr->smb2_next_reply, /* l */ 1411 sr->smb2_messageid, /* q */ 1412 pid_tid_aid, /* q */ 1413 sr->smb2_ssnid, /* q */ 1414 sr->smb2_sig); /* 16c */ 1415 } else { 1416 rc = smb_mbc_encodef(&sr->reply, 1417 "Nwwlwwllqqq16c", 1418 SMB2_HDR_SIZE, /* w */ 1419 sr->smb2_credit_charge, /* w */ 1420 sr->smb2_status, /* l */ 1421 sr->smb2_cmd_code, /* w */ 1422 sr->smb2_credit_response, /* w */ 1423 sr->smb2_hdr_flags, /* l */ 1424 sr->smb2_next_reply, /* l */ 1425 sr->smb2_messageid, /* q */ 1426 pid_tid_aid, /* q */ 1427 sr->smb2_ssnid, /* q */ 1428 sr->smb2_sig); /* 16c */ 1429 } 1430 1431 return (rc); 1432 } 1433 1434 void 1435 smb2_send_reply(smb_request_t *sr) 1436 { 1437 struct mbuf_chain enc_reply; 1438 smb_session_t *session = sr->session; 1439 mbuf_t *m; 1440 1441 /* 1442 * [MS-SMB2] 3.3.4.1.4 Encrypting the Message 1443 * 1444 * When the connection supports encryption and the dialect 1445 * is 3.x, encrypt if: 1446 * - The request was encrypted OR 1447 * - The cmd is not SESSION_SETUP or NEGOTIATE AND 1448 * -- Session.EncryptData is TRUE OR 1449 * -- The cmd is not TREE_CONNECT AND 1450 * --- Tree.EncryptData is TRUE 1451 * 1452 * This boils down to sr->th_sid_user != NULL, and the rest 1453 * is enforced when th_sid_user is set. 1454 */ 1455 1456 if ((session->capabilities & SMB2_CAP_ENCRYPTION) == 0 || 1457 sr->th_sid_user == NULL) { 1458 (void) smb_session_send(sr->session, 0, &sr->reply); 1459 return; 1460 } 1461 1462 /* 1463 * Encrypted send 1464 * 1465 * Not doing in-place encryption because we may have 1466 * loaned buffers (eg. from ZFS) that are read-only. 1467 * 1468 * Setup the transform header in its own mblk, 1469 * with leading space for the netbios header. 1470 */ 1471 MBC_INIT(&enc_reply, SMB3_TFORM_HDR_SIZE); 1472 m = enc_reply.chain; 1473 m->m_len = SMB3_TFORM_HDR_SIZE; 1474 1475 sr->th_msglen = sr->reply.chain_offset; 1476 m->m_next = smb_mbuf_alloc_chain(sr->th_msglen); 1477 enc_reply.max_bytes += sr->th_msglen; 1478 1479 if (smb3_encrypt_sr(sr, &sr->reply, &enc_reply) != 0) { 1480 cmn_err(CE_WARN, "smb3 encryption failed"); 1481 smb_session_disconnect(sr->session); 1482 } else { 1483 (void) smb_session_send(sr->session, 0, &enc_reply); 1484 } 1485 MBC_FLUSH(&enc_reply); 1486 } 1487 1488 /* 1489 * This wrapper function exists to help catch calls to smbsr_status() 1490 * (which is SMB1-specific) in common code. See smbsr_status(). 1491 * If the log message below is seen, put a dtrace probe on this 1492 * function with a stack() action to see who is calling the SMB1 1493 * "put error" from common code, and fix it. 1494 */ 1495 void 1496 smbsr_status_smb2(smb_request_t *sr, DWORD status) 1497 { 1498 const char *name; 1499 1500 if (sr->smb2_cmd_code < SMB2__NCMDS) 1501 name = smb2_disp_table[sr->smb2_cmd_code].sdt_name; 1502 else 1503 name = "<unknown>"; 1504 #ifdef DEBUG 1505 cmn_err(CE_NOTE, "smbsr_status called for %s", name); 1506 #endif 1507 1508 smb2sr_put_error_data(sr, status, NULL); 1509 } 1510 1511 void 1512 smb2sr_put_errno(struct smb_request *sr, int errnum) 1513 { 1514 uint32_t status = smb_errno2status(errnum); 1515 smb2sr_put_error_data(sr, status, NULL); 1516 } 1517 1518 void 1519 smb2sr_put_error(smb_request_t *sr, uint32_t status) 1520 { 1521 smb2sr_put_error_data(sr, status, NULL); 1522 } 1523 1524 /* 1525 * Build an SMB2 error response. [MS-SMB2] 2.2.2 1526 */ 1527 void 1528 smb2sr_put_error_data(smb_request_t *sr, uint32_t status, mbuf_chain_t *mbc) 1529 { 1530 DWORD len; 1531 1532 /* 1533 * The common dispatch code writes this when it 1534 * updates the SMB2 header before sending. 1535 */ 1536 sr->smb2_status = status; 1537 1538 /* Rewind to the end of the SMB header. */ 1539 sr->reply.chain_offset = sr->smb2_reply_hdr + SMB2_HDR_SIZE; 1540 1541 /* 1542 * NB: Must provide at least one byte of error data, 1543 * per [MS-SMB2] 2.2.2 1544 */ 1545 if (mbc != NULL && (len = MBC_LENGTH(mbc)) != 0) { 1546 (void) smb_mbc_encodef( 1547 &sr->reply, 1548 "wwlC", 1549 9, /* StructSize */ /* w */ 1550 0, /* reserved */ /* w */ 1551 len, /* l */ 1552 mbc); /* C */ 1553 } else { 1554 (void) smb_mbc_encodef( 1555 &sr->reply, 1556 "wwl.", 1557 9, /* StructSize */ /* w */ 1558 0, /* reserved */ /* w */ 1559 0); /* l. */ 1560 } 1561 } 1562 1563 /* 1564 * Build an SMB2 error context response (dialect 3.1.1). 1565 */ 1566 void 1567 smb2sr_put_error_ctx(smb_request_t *sr, uint32_t status, uint32_t errid, 1568 mbuf_chain_t *mbc) 1569 { 1570 DWORD len; 1571 1572 /* 1573 * The common dispatch code writes this when it 1574 * updates the SMB2 header before sending. 1575 */ 1576 sr->smb2_status = status; 1577 1578 /* Rewind to the end of the SMB header. */ 1579 sr->reply.chain_offset = sr->smb2_reply_hdr + SMB2_HDR_SIZE; 1580 1581 /* 1582 * Error Context is 8-byte header plus encaps. data (ErrorContextData), 1583 * which can be zero-length. 1584 */ 1585 if (mbc != NULL && (len = MBC_LENGTH(mbc)) != 0) { 1586 (void) smb_mbc_encodef( 1587 &sr->reply, 1588 "wbblllC", 1589 9, /* StructSize */ /* w */ 1590 1, /* ErrorContextCount */ /* b */ 1591 0, /* reserved */ /* b */ 1592 8+len, /* ByteCount */ /* l */ 1593 len, /* ErrorDataLength */ /* l */ 1594 errid, /* ErrorId */ /* l */ 1595 mbc); /* C */ 1596 } else { 1597 (void) smb_mbc_encodef( 1598 &sr->reply, 1599 "wbblll", 1600 9, /* StructSize */ /* w */ 1601 1, /* ErrorContextCount */ /* b */ 1602 0, /* reserved */ /* b */ 1603 8, /* ByteCount */ /* l */ 1604 0, /* ErrorDataLength */ /* l */ 1605 errid); /* ErrorId */ /* l */ 1606 } 1607 } 1608 1609 /* 1610 * Build an SMB2 error context response with SMB2_ERROR_ID_DEFAULT ErrorId. 1611 * 1612 * This only handles the case we currently need, encapsulating a 1613 * single error data section inside an SMB2_ERROR_ID_DEFAULT 1614 * error context type (which is type zero, and that's what 1615 * the zero on the end of this function name refers to). 1616 */ 1617 void 1618 smb2sr_put_error_ctx0(smb_request_t *sr, uint32_t status, mbuf_chain_t *mbc) 1619 { 1620 return (smb2sr_put_error_ctx(sr, status, SMB2_ERROR_ID_DEFAULT, mbc)); 1621 } 1622 1623 /* 1624 * smb2sr_lookup_fid 1625 * 1626 * Setup sr->fid_ofile, either inherited from a related command, 1627 * or obtained via FID lookup. Similar inheritance logic as in 1628 * smb2sr_work. 1629 */ 1630 uint32_t 1631 smb2sr_lookup_fid(smb_request_t *sr, smb2fid_t *fid) 1632 { 1633 boolean_t related = sr->smb2_hdr_flags & 1634 SMB2_FLAGS_RELATED_OPERATIONS; 1635 1636 if (related) { 1637 if (sr->fid_ofile == NULL) 1638 return (NT_STATUS_INVALID_PARAMETER); 1639 sr->smb_fid = sr->fid_ofile->f_fid; 1640 return (0); 1641 } 1642 1643 /* 1644 * If we could be sure this is called only once per cmd, 1645 * we could simply ASSERT(sr->fid_ofile == NULL) here. 1646 * However, there are cases where it can be called again 1647 * handling the same command, so let's tolerate that. 1648 */ 1649 if (sr->fid_ofile == NULL) { 1650 sr->smb_fid = (uint16_t)fid->temporal; 1651 sr->fid_ofile = smb_ofile_lookup_by_fid(sr, sr->smb_fid); 1652 } 1653 if (sr->fid_ofile == NULL || 1654 sr->fid_ofile->f_persistid != fid->persistent) 1655 return (NT_STATUS_FILE_CLOSED); 1656 1657 return (0); 1658 } 1659 1660 /* 1661 * smb2_dispatch_stats_init 1662 * 1663 * Initializes dispatch statistics for SMB2. 1664 * See also smb_dispatch_stats_init(), which fills in 1665 * the lower part of the statistics array, from zero 1666 * through SMB_COM_NUM; 1667 */ 1668 void 1669 smb2_dispatch_stats_init(smb_server_t *sv) 1670 { 1671 smb_disp_stats_t *sds = sv->sv_disp_stats2; 1672 smb_kstat_req_t *ksr; 1673 int i; 1674 1675 ksr = ((smbsrv_kstats_t *)sv->sv_ksp->ks_data)->ks_reqs2; 1676 1677 for (i = 0; i < SMB2__NCMDS; i++, ksr++) { 1678 smb_latency_init(&sds[i].sdt_lat); 1679 (void) strlcpy(ksr->kr_name, smb2_disp_table[i].sdt_name, 1680 sizeof (ksr->kr_name)); 1681 } 1682 } 1683 1684 /* 1685 * smb2_dispatch_stats_fini 1686 * 1687 * Frees and destroyes the resources used for statistics. 1688 */ 1689 void 1690 smb2_dispatch_stats_fini(smb_server_t *sv) 1691 { 1692 smb_disp_stats_t *sds = sv->sv_disp_stats2; 1693 int i; 1694 1695 for (i = 0; i < SMB2__NCMDS; i++) 1696 smb_latency_destroy(&sds[i].sdt_lat); 1697 } 1698 1699 void 1700 smb2_dispatch_stats_update(smb_server_t *sv, 1701 smb_kstat_req_t *ksr, int first, int nreq) 1702 { 1703 smb_disp_stats_t *sds = sv->sv_disp_stats2; 1704 int i; 1705 int last; 1706 1707 last = first + nreq - 1; 1708 1709 if ((first < SMB2__NCMDS) && (last < SMB2__NCMDS)) { 1710 for (i = first; i <= last; i++, ksr++) { 1711 ksr->kr_rxb = sds[i].sdt_rxb; 1712 ksr->kr_txb = sds[i].sdt_txb; 1713 mutex_enter(&sds[i].sdt_lat.ly_mutex); 1714 ksr->kr_nreq = sds[i].sdt_lat.ly_a_nreq; 1715 ksr->kr_sum = sds[i].sdt_lat.ly_a_sum; 1716 ksr->kr_a_mean = sds[i].sdt_lat.ly_a_mean; 1717 ksr->kr_a_stddev = 1718 sds[i].sdt_lat.ly_a_stddev; 1719 ksr->kr_d_mean = sds[i].sdt_lat.ly_d_mean; 1720 ksr->kr_d_stddev = 1721 sds[i].sdt_lat.ly_d_stddev; 1722 sds[i].sdt_lat.ly_d_mean = 0; 1723 sds[i].sdt_lat.ly_d_nreq = 0; 1724 sds[i].sdt_lat.ly_d_stddev = 0; 1725 sds[i].sdt_lat.ly_d_sum = 0; 1726 mutex_exit(&sds[i].sdt_lat.ly_mutex); 1727 } 1728 } 1729 } 1730 1731 /* 1732 * Append new_sr to the postwork queue. sr->smb2_cmd_code encodes 1733 * the action that should be run by this sr. 1734 * 1735 * This queue is rarely used (and normally empty) so we're OK 1736 * using a simple "walk to tail and insert" here. 1737 */ 1738 void 1739 smb2sr_append_postwork(smb_request_t *top_sr, smb_request_t *new_sr) 1740 { 1741 smb_request_t *last_sr; 1742 1743 ASSERT(top_sr->session->dialect >= SMB_VERS_2_BASE); 1744 1745 last_sr = top_sr; 1746 while (last_sr->sr_postwork != NULL) 1747 last_sr = last_sr->sr_postwork; 1748 1749 last_sr->sr_postwork = new_sr; 1750 } 1751 1752 /* 1753 * Run any "post work" that was appended to the main SR while it 1754 * was running. This is called after the request has been sent 1755 * for the main SR, and used in cases i.e. the oplock code, where 1756 * we need to send something to the client only _after_ the main 1757 * sr request has gone out. 1758 */ 1759 static void 1760 smb2sr_run_postwork(smb_request_t *top_sr) 1761 { 1762 smb_request_t *post_sr; /* the one we're running */ 1763 smb_request_t *next_sr; 1764 1765 while ((post_sr = top_sr->sr_postwork) != NULL) { 1766 next_sr = post_sr->sr_postwork; 1767 top_sr->sr_postwork = next_sr; 1768 post_sr->sr_postwork = NULL; 1769 1770 post_sr->sr_worker = top_sr->sr_worker; 1771 post_sr->sr_state = SMB_REQ_STATE_ACTIVE; 1772 1773 switch (post_sr->smb2_cmd_code) { 1774 case SMB2_OPLOCK_BREAK: 1775 smb_oplock_send_break(post_sr); 1776 break; 1777 default: 1778 ASSERT(0); 1779 } 1780 1781 /* 1782 * If we have a durable handle, and this operation 1783 * updated the nvlist, write it out. 1784 */ 1785 if (post_sr->dh_nvl_dirty) { 1786 post_sr->dh_nvl_dirty = B_FALSE; 1787 smb2_dh_update_nvfile(post_sr); 1788 } 1789 1790 post_sr->sr_state = SMB_REQ_STATE_COMPLETED; 1791 smb_request_free(post_sr); 1792 } 1793 } 1794