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 2020-2024 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 inline void 428 smb2_record_stats(smb_request_t *sr, smb_disp_stats_t *sds, boolean_t need_lat) 429 { 430 int64_t rxb; 431 int64_t txb; 432 433 rxb = (int64_t)(sr->command.chain_offset - sr->smb2_cmd_hdr); 434 txb = (int64_t)(sr->reply.chain_offset - sr->smb2_reply_hdr); 435 txb += sr->smb2_async_txb; 436 sr->smb2_async_txb = 0; 437 438 smb_server_inc_req(sr->sr_server); 439 atomic_add_64(&sds->sdt_rxb, rxb); 440 atomic_add_64(&sds->sdt_txb, txb); 441 442 if (need_lat) { 443 hrtime_t dt; 444 dt = gethrtime() - sr->sr_time_start; 445 smb_latency_add_sample(&sds->sdt_lat, dt); 446 } 447 } 448 449 /* 450 * smb2sr_work 451 * 452 * This function processes each SMB command in the current request 453 * (which may be a compound request) building a reply containing 454 * SMB reply messages, one-to-one with the SMB commands. Some SMB 455 * commands (change notify, blocking locks) may require both an 456 * "interim response" and a later "async response" at completion. 457 * In such cases, we'll encode the interim response in the reply 458 * compound we're building, and put the (now async) command on a 459 * list of commands that need further processing. After we've 460 * finished processing the commands in this compound and building 461 * the compound reply, we'll send the compound reply, and finally 462 * process the list of async commands. 463 * 464 * As we work our way through the compound request and reply, 465 * we need to keep track of the bounds of the current request 466 * and reply. For the request, this uses an MBC_SHADOW_CHAIN 467 * that begins at smb2_cmd_hdr. The reply is appended to the 468 * sr->reply chain starting at smb2_reply_hdr. 469 * 470 * This function must always free the smb request, or arrange 471 * for it to be completed and free'd later (if SDRC_SR_KEPT). 472 */ 473 void 474 smb2sr_work(struct smb_request *sr) 475 { 476 const smb_disp_entry_t *sdd; 477 smb_disp_stats_t *sds; 478 smb_session_t *session; 479 uint32_t msg_len; 480 uint16_t cmd_idx; 481 int rc = 0; 482 boolean_t disconnect = B_FALSE; 483 boolean_t related; 484 485 session = sr->session; 486 487 ASSERT(sr->smb2_async_mode == B_FALSE); 488 ASSERT(sr->tid_tree == 0); 489 ASSERT(sr->uid_user == 0); 490 ASSERT(sr->fid_ofile == 0); 491 sr->smb_fid = (uint16_t)-1; 492 sr->smb2_status = 0; 493 494 /* temporary until we identify a user */ 495 sr->user_cr = zone_kcred(); 496 497 cmd_start: 498 /* 499 * Note that we don't check sr_state here and abort the 500 * compound if cancelled (etc.) because some SMB2 command 501 * handlers need to do work even when cancelled. 502 * 503 * We treat some status codes as if "sticky", meaning 504 * once they're set after some command handler returns, 505 * all remaining commands get this status without even 506 * calling the command-specific handler. 507 */ 508 if (sr->smb2_status != NT_STATUS_CANCELLED && 509 sr->smb2_status != NT_STATUS_INSUFFICIENT_RESOURCES) 510 sr->smb2_status = 0; 511 512 /* 513 * Decode the request header 514 * 515 * Most problems with decoding will result in the error 516 * STATUS_INVALID_PARAMETER. If the decoding problem 517 * prevents continuing, we'll close the connection. 518 * [MS-SMB2] 3.3.5.2.6 Handling Incorrectly Formatted... 519 */ 520 sr->smb2_async_mode = B_FALSE; 521 sr->smb2_cmd_hdr = sr->command.chain_offset; 522 if ((rc = smb2_decode_header(sr)) != 0) { 523 cmn_err(CE_WARN, "clnt %s bad SMB2 header", 524 session->ip_addr_str); 525 disconnect = B_TRUE; 526 goto cleanup; 527 } 528 529 /* 530 * The SMB2_FLAGS_SERVER_TO_REDIR should only appear 531 * in messages from the server back to the client. 532 */ 533 if ((sr->smb2_hdr_flags & SMB2_FLAGS_SERVER_TO_REDIR) != 0) { 534 cmn_err(CE_WARN, "clnt %s bad SMB2 flags", 535 session->ip_addr_str); 536 disconnect = B_TRUE; 537 goto cleanup; 538 } 539 related = (sr->smb2_hdr_flags & SMB2_FLAGS_RELATED_OPERATIONS); 540 sr->smb2_hdr_flags |= SMB2_FLAGS_SERVER_TO_REDIR; 541 if (sr->smb2_hdr_flags & SMB2_FLAGS_ASYNC_COMMAND) { 542 /* Probably an async cancel. */ 543 DTRACE_PROBE1(smb2__dispatch__async, smb_request_t *, 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 (sr->smb2_credit_request < sr->smb2_credit_charge) 881 smb2_credit_decrease(sr); 882 883 /* 884 * The real work: call the SMB2 command handler 885 * (except for "sticky" smb2_status - see above) 886 */ 887 sr->sr_time_start = gethrtime(); 888 rc = SDRC_SUCCESS; 889 if (sr->smb2_status == 0) { 890 /* NB: not using pre_op */ 891 rc = (*sdd->sdt_function)(sr); 892 /* NB: not using post_op */ 893 } else { 894 smb2sr_put_error(sr, sr->smb2_status); 895 } 896 897 /* 898 * When the sdt_function returns SDRC_SR_KEPT, it means 899 * this SR may have been passed to another thread so we 900 * MUST NOT touch it anymore. 901 */ 902 if (rc == SDRC_SR_KEPT) 903 return; 904 905 MBC_FLUSH(&sr->raw_data); 906 907 /* 908 * Credit adjustments (increase) 909 * 910 * If we've gone async, credit adjustments were done 911 * when we sent the interim reply. 912 */ 913 if (!sr->smb2_async_mode) { 914 if (sr->smb2_credit_request > sr->smb2_credit_charge) { 915 smb2_credit_increase(sr); 916 } 917 } 918 919 cmd_done: 920 switch (rc) { 921 case SDRC_SUCCESS: 922 break; 923 default: 924 /* 925 * SMB2 does not use the other dispatch return codes. 926 * If we see something else, log an event so we'll 927 * know something is returning bogus status codes. 928 * If you see these in the log, use dtrace to find 929 * the code returning something else. 930 */ 931 #ifdef DEBUG 932 cmn_err(CE_NOTE, "handler for %u returned 0x%x", 933 sr->smb2_cmd_code, rc); 934 #endif 935 smb2sr_put_error(sr, NT_STATUS_INTERNAL_ERROR); 936 break; 937 case SDRC_ERROR: 938 /* 939 * Many command handlers return SDRC_ERROR for any 940 * problems decoding the request, and don't bother 941 * setting smb2_status. For those cases, the best 942 * status return would be "invalid parameter". 943 */ 944 if (sr->smb2_status == 0) 945 sr->smb2_status = NT_STATUS_INVALID_PARAMETER; 946 smb2sr_put_error(sr, sr->smb2_status); 947 break; 948 case SDRC_DROP_VC: 949 disconnect = B_TRUE; 950 goto cleanup; 951 952 case SDRC_NO_REPLY: 953 /* will free sr */ 954 goto cleanup; 955 } 956 957 /* 958 * Pad the reply to align(8) if there will be another. 959 */ 960 if (sr->smb2_next_command != 0) 961 (void) smb_mbc_put_align(&sr->reply, 8); 962 963 /* 964 * Record some statistics. Uses: 965 * rxb = command.chain_offset - smb2_cmd_hdr; 966 * txb = reply.chain_offset - smb2_reply_hdr; 967 * which at this point represent the current cmd/reply. 968 */ 969 smb2_record_stats(sr, sds, B_TRUE); 970 971 /* 972 * If there's a next command, figure out where it starts, 973 * and fill in the next header offset for the reply. 974 * Note: We sanity checked smb2_next_command above. 975 */ 976 if (sr->smb2_next_command != 0) { 977 sr->command.chain_offset = 978 sr->smb2_cmd_hdr + sr->smb2_next_command; 979 sr->smb2_next_reply = 980 sr->reply.chain_offset - sr->smb2_reply_hdr; 981 } else { 982 ASSERT(sr->smb2_next_reply == 0); 983 } 984 985 /* 986 * Overwrite the (now final) SMB2 header for this response. 987 */ 988 (void) smb2_encode_header(sr, B_TRUE); 989 990 /* 991 * Cannot move this into smb2_session_setup() - encoded header required. 992 */ 993 if (session->dialect >= SMB_VERS_3_11 && 994 sr->smb2_cmd_code == SMB2_SESSION_SETUP && 995 sr->smb2_status == NT_STATUS_MORE_PROCESSING_REQUIRED) { 996 if (smb31_preauth_sha512_calc(sr, &sr->reply, 997 sr->uid_user->u_preauth_hashval, 998 sr->uid_user->u_preauth_hashval) != 0) 999 cmn_err(CE_WARN, "(3) Preauth hash calculation " 1000 "failed"); 1001 } 1002 1003 /* Don't sign if we're going to encrypt */ 1004 if (sr->th_sid_user == NULL && 1005 (sr->smb2_hdr_flags & SMB2_FLAGS_SIGNED) != 0) 1006 smb2_sign_reply(sr); 1007 1008 if (sr->smb2_next_command != 0) 1009 goto cmd_start; 1010 1011 /* 1012 * If we have a durable handle, and this operation updated 1013 * the nvlist, write it out (before smb2_send_reply). 1014 */ 1015 if (sr->dh_nvl_dirty) { 1016 sr->dh_nvl_dirty = B_FALSE; 1017 smb2_dh_update_nvfile(sr); 1018 } 1019 1020 smb2_send_reply(sr); 1021 1022 cleanup: 1023 if (disconnect) 1024 smb_session_disconnect(session); 1025 1026 /* 1027 * Do "postwork" for oplock (and maybe other things) 1028 */ 1029 if (sr->sr_postwork != NULL) 1030 smb2sr_run_postwork(sr); 1031 1032 mutex_enter(&sr->sr_mutex); 1033 sr->sr_state = SMB_REQ_STATE_COMPLETED; 1034 mutex_exit(&sr->sr_mutex); 1035 1036 smb_request_free(sr); 1037 } 1038 1039 /* 1040 * Build an interim response for a command that needs to 'go async'. 1041 * This is used by requests that block for a relatively long time. 1042 * Leave the SR state so that smb2sr_work() can continue its 1043 * processing of this compound in "async mode". 1044 * 1045 * If we agree to "go async", this should return STATUS_SUCCESS. 1046 * Otherwise return STATUS_INSUFFICIENT_RESOURCES for this and 1047 * all requests following this request. (See the comments re. 1048 * "sticky" smb2_status values in smb2sr_work). 1049 * 1050 * Note: the Async ID we assign here is arbitrary, and need only 1051 * be unique among pending async responses on this connection, so 1052 * this just uses a modified messageID, which is already unique. 1053 * 1054 * Credits: All credit changes should happen via the interim 1055 * response, so we have to manage credits here. After this 1056 * returns to smb2sr_work, the final reply for this command 1057 * will have smb2_credit_response = 0 1058 * (meaning no further changes to the clients' credits). 1059 * 1060 * Compound responses: 1061 * 1062 * [MS-SMB2] 3.3.5.2.7.2 "Handling Compounded Related Requests" states: 1063 * 1064 * "When an operation requires asynchronous processing, all the subsequent 1065 * operations MUST also be processed asynchronously. The server MUST send an 1066 * interim response for all such operations as specified in section 3.3.4.2." 1067 * 1068 * One might expect that means we should also send interim responses for every 1069 * command following the current one. However, Windows does not do that, and at 1070 * least one client (mount.cifs) rejects such 'extra' responses as errors. 1071 * When asked for clarification, Microsoft Dochelp pointed to this part of 1072 * [MS-SMB2] 3.3.4.2 "Sending an Interim Response for an Asynchronous Operation" 1073 * 1074 * "The server MAY choose to send an interim response for any request..." 1075 * 1076 * Further experimentation on Windows reveals two separate behaviors, seemingly 1077 * distinguished by whether the request may block indefinitely: 1078 * 1079 * Bounded blocking (e.g. Oplock break): 1080 * - An interim response is sent before any part of the compound response. 1081 * - If multiple commands 'go async', they each send separate interim responses. 1082 * - A single compound response is sent when the final command completes. 1083 * 1084 * Indefinite blocking (e.g. Change Notify, Byte-Range Lock): 1085 * - If the command is not the last in the compound, it is rejected with 1086 * "NT_STATUS_INTERNAL_ERROR". 1087 * - All responses for commands prior to the one that 'goes async' are returned 1088 * immediately as a single compound response. 1089 * - An interim response is then sent separately from the compound response. 1090 * 1091 * We follow Windows behavior here for compatibility purposes, with one 1092 * exception: in the indefinite case, we deliver the interim response at the end 1093 * of the compound response, rather than separately, as we don't have the state 1094 * needed to modify the previous response's header to terminate the compound. 1095 * The command-specific handler chooses whether to allow this in the middle of 1096 * the compound. 1097 * 1098 * Errors here mean we failed to encode the interim response. 1099 * Rather than actually disconnect here, let's assume whatever problem we 1100 * encountered will be seen by the caller as they continue processing the 1101 * compound, and just restore everything and return an error. 1102 */ 1103 static uint32_t 1104 smb2sr_send_interim(smb_request_t *sr) 1105 { 1106 uint32_t saved_hdr_flags; 1107 boolean_t disconnect = B_FALSE; 1108 1109 sr->smb2_async_id = SMB2_ASYNCID(sr); 1110 sr->smb2_status = NT_STATUS_PENDING; 1111 sr->smb2_hdr_flags |= SMB2_FLAGS_ASYNC_COMMAND; 1112 saved_hdr_flags = sr->smb2_hdr_flags; 1113 sr->smb2_next_reply = 0; 1114 1115 if ((smb2_encode_header(sr, B_FALSE)) != 0) { 1116 cmn_err(CE_WARN, "clnt %s excessive reply", 1117 sr->session->ip_addr_str); 1118 disconnect = B_TRUE; 1119 goto cleanup; 1120 } 1121 1122 /* 1123 * Don't change (user, tree, file) because we want them 1124 * exactly as they were when we entered. 1125 * Interim responses are NOT signed; we already checked the signature 1126 * for this message, and will restore this flag on completion. 1127 */ 1128 sr->smb2_hdr_flags &= ~SMB2_FLAGS_SIGNED; 1129 1130 smb2sr_put_error(sr, sr->smb2_status); 1131 1132 /* 1133 * Credit adjustments (increase) 1134 * 1135 * NOTE: interim responses are not signed. 1136 * Any attacker can modify the credit grant 1137 * in the response. Because of this property, 1138 * it is no worse to assume the credit charge and grant 1139 * are sane without verifying the signature, 1140 * and that saves us a whole lot of work. 1141 * If the credits WERE modified, we'll find out 1142 * when we verify the signature later, 1143 * which nullifies any changes caused here. 1144 */ 1145 if (sr->smb2_credit_request > sr->smb2_credit_charge) { 1146 smb2_credit_increase(sr); 1147 } 1148 1149 DTRACE_PROBE1(go__async, smb_request_t *, sr); 1150 1151 /* 1152 * Overwrite the (now final) SMB2 header for this response. 1153 */ 1154 (void) smb2_encode_header(sr, B_TRUE); 1155 sr->smb2_async_txb = 1156 (int64_t)(sr->reply.chain_offset - sr->smb2_reply_hdr); 1157 1158 smb2_send_reply(sr); 1159 1160 /* 1161 * Now that we've responded (with credits granted), 1162 * the final response shouldn't grant any. 1163 */ 1164 sr->smb2_credit_response = 0; 1165 1166 cleanup: 1167 sr->smb2_status = NT_STATUS_SUCCESS; 1168 sr->smb2_hdr_flags = saved_hdr_flags; 1169 1170 if (disconnect) { 1171 sr->smb2_async_mode = B_FALSE; 1172 sr->smb2_hdr_flags &= SMB2_FLAGS_ASYNC_COMMAND; 1173 return (NT_STATUS_INVALID_PARAMETER); 1174 } 1175 1176 return (NT_STATUS_SUCCESS); 1177 } 1178 1179 /* 1180 * This variant of 'go async' sends the interim response on its own, 1181 * saving/restoring the response compound currently under construction. 1182 * See the longer comment above smb2sr_send_interim(). 1183 */ 1184 uint32_t 1185 smb2sr_go_async(smb_request_t *sr) 1186 { 1187 struct mbuf_chain saved_reply; 1188 uint32_t saved_reply_hdr = sr->smb2_reply_hdr; 1189 uint32_t saved_next_reply = sr->smb2_next_reply; 1190 uint32_t status; 1191 1192 if (sr->smb2_async_mode) { 1193 /* cmd is already being processed async */ 1194 return (NT_STATUS_SUCCESS); 1195 } 1196 sr->smb2_async_mode = B_TRUE; 1197 1198 /* The "server" session always runs async. */ 1199 if (sr->session->sock == NULL) 1200 return (NT_STATUS_SUCCESS); 1201 1202 /* 1203 * All the encoding functions use sr and sr->reply. 1204 * Keep a copy of the old reply MBC around so we can send out our 1205 * interim response on its own, then restore the original. 1206 */ 1207 saved_reply = sr->reply; /* struct copy */ 1208 MBC_INIT(&sr->reply, sr->reply.max_bytes); 1209 sr->smb2_reply_hdr = 0; 1210 1211 status = smb2sr_send_interim(sr); 1212 1213 MBC_FLUSH(&sr->reply); /* clear our interim reply */ 1214 sr->reply = saved_reply; /* struct copy - restore original */ 1215 sr->smb2_next_reply = saved_next_reply; 1216 sr->smb2_reply_hdr = saved_reply_hdr; 1217 1218 return (status); 1219 } 1220 1221 /* 1222 * This variant of 'go async' appends the interim response 1223 * to the response compound currently under construction. 1224 * See the longer comment above smb2sr_send_interim(). 1225 */ 1226 uint32_t 1227 smb2sr_go_async_indefinite(smb_request_t *sr) 1228 { 1229 uint32_t saved_reply_hdr = sr->smb2_reply_hdr; 1230 uint32_t status; 1231 1232 if (sr->smb2_async_mode) { 1233 /* cmd is already being processed async */ 1234 return (NT_STATUS_SUCCESS); 1235 } 1236 sr->smb2_async_mode = B_TRUE; 1237 1238 /* The "server" session always runs async. */ 1239 if (sr->session->sock == NULL) 1240 return (NT_STATUS_SUCCESS); 1241 1242 /* Rewind reply to start of header */ 1243 sr->reply.chain_offset = saved_reply_hdr; 1244 1245 status = smb2sr_send_interim(sr); 1246 if (status != NT_STATUS_SUCCESS) 1247 return (status); 1248 1249 /* We've now consumed the reply; re-initialize it. */ 1250 MBC_FLUSH(&sr->reply); 1251 ASSERT(sr->reply.max_bytes == sr->session->reply_max_bytes); 1252 ASSERT(sr->reply.chain_offset == 0); 1253 sr->smb2_reply_hdr = 0; 1254 (void) smb2_encode_header(sr, B_FALSE); 1255 1256 return (NT_STATUS_SUCCESS); 1257 } 1258 1259 int 1260 smb2_decode_header(smb_request_t *sr) 1261 { 1262 uint32_t pid, tid; 1263 uint16_t hdr_len; 1264 int rc; 1265 1266 rc = smb_mbc_decodef( 1267 &sr->command, "Nwww..wwllqllq16c", 1268 &hdr_len, /* w */ 1269 &sr->smb2_credit_charge, /* w */ 1270 &sr->smb2_chan_seq, /* w */ 1271 /* reserved .. */ 1272 &sr->smb2_cmd_code, /* w */ 1273 &sr->smb2_credit_request, /* w */ 1274 &sr->smb2_hdr_flags, /* l */ 1275 &sr->smb2_next_command, /* l */ 1276 &sr->smb2_messageid, /* q */ 1277 &pid, /* l */ 1278 &tid, /* l */ 1279 &sr->smb2_ssnid, /* q */ 1280 sr->smb2_sig); /* 16c */ 1281 if (rc) 1282 return (rc); 1283 1284 if (hdr_len != SMB2_HDR_SIZE) 1285 return (-1); 1286 1287 if (sr->smb2_hdr_flags & SMB2_FLAGS_ASYNC_COMMAND) { 1288 sr->smb2_async_id = pid | 1289 ((uint64_t)tid) << 32; 1290 sr->smb_pid = 0; 1291 sr->smb_tid = 0; 1292 } else { 1293 sr->smb2_async_id = 0; 1294 sr->smb_pid = pid; 1295 sr->smb_tid = (uint16_t)tid; /* XXX wide TIDs */ 1296 } 1297 1298 return (rc); 1299 } 1300 1301 int 1302 smb2_encode_header(smb_request_t *sr, boolean_t overwrite) 1303 { 1304 uint64_t pid_tid_aid; /* pid+tid, or async id */ 1305 int rc; 1306 1307 if (sr->smb2_hdr_flags & SMB2_FLAGS_ASYNC_COMMAND) { 1308 pid_tid_aid = sr->smb2_async_id; 1309 } else { 1310 pid_tid_aid = sr->smb_pid | 1311 ((uint64_t)sr->smb_tid) << 32; 1312 } 1313 1314 if (overwrite) { 1315 rc = smb_mbc_poke(&sr->reply, 1316 sr->smb2_reply_hdr, 1317 "Nwwlwwllqqq16c", 1318 SMB2_HDR_SIZE, /* w */ 1319 sr->smb2_credit_charge, /* w */ 1320 sr->smb2_status, /* l */ 1321 sr->smb2_cmd_code, /* w */ 1322 sr->smb2_credit_response, /* w */ 1323 sr->smb2_hdr_flags, /* l */ 1324 sr->smb2_next_reply, /* l */ 1325 sr->smb2_messageid, /* q */ 1326 pid_tid_aid, /* q */ 1327 sr->smb2_ssnid, /* q */ 1328 sr->smb2_sig); /* 16c */ 1329 } else { 1330 rc = smb_mbc_encodef(&sr->reply, 1331 "Nwwlwwllqqq16c", 1332 SMB2_HDR_SIZE, /* w */ 1333 sr->smb2_credit_charge, /* w */ 1334 sr->smb2_status, /* l */ 1335 sr->smb2_cmd_code, /* w */ 1336 sr->smb2_credit_response, /* w */ 1337 sr->smb2_hdr_flags, /* l */ 1338 sr->smb2_next_reply, /* l */ 1339 sr->smb2_messageid, /* q */ 1340 pid_tid_aid, /* q */ 1341 sr->smb2_ssnid, /* q */ 1342 sr->smb2_sig); /* 16c */ 1343 } 1344 1345 return (rc); 1346 } 1347 1348 void 1349 smb2_send_reply(smb_request_t *sr) 1350 { 1351 struct mbuf_chain enc_reply; 1352 smb_session_t *session = sr->session; 1353 mbuf_t *m; 1354 1355 /* 1356 * [MS-SMB2] 3.3.4.1.4 Encrypting the Message 1357 * 1358 * When the connection supports encryption and the dialect 1359 * is 3.x, encrypt if: 1360 * - The request was encrypted OR 1361 * - The cmd is not SESSION_SETUP or NEGOTIATE AND 1362 * -- Session.EncryptData is TRUE OR 1363 * -- The cmd is not TREE_CONNECT AND 1364 * --- Tree.EncryptData is TRUE 1365 * 1366 * This boils down to sr->th_sid_user != NULL, and the rest 1367 * is enforced when th_sid_user is set. 1368 */ 1369 1370 if ((session->capabilities & SMB2_CAP_ENCRYPTION) == 0 || 1371 sr->th_sid_user == NULL) { 1372 (void) smb_session_send(sr->session, 0, &sr->reply); 1373 return; 1374 } 1375 1376 /* 1377 * Encrypted send 1378 * 1379 * Not doing in-place encryption because we may have 1380 * loaned buffers (eg. from ZFS) that are read-only. 1381 * 1382 * Setup the transform header in its own mblk, 1383 * with leading space for the netbios header. 1384 */ 1385 MBC_INIT(&enc_reply, SMB3_TFORM_HDR_SIZE); 1386 m = enc_reply.chain; 1387 m->m_len = SMB3_TFORM_HDR_SIZE; 1388 1389 sr->th_msglen = sr->reply.chain_offset; 1390 m->m_next = smb_mbuf_alloc_chain(sr->th_msglen); 1391 enc_reply.max_bytes += sr->th_msglen; 1392 1393 if (smb3_encrypt_sr(sr, &sr->reply, &enc_reply) != 0) { 1394 cmn_err(CE_WARN, "smb3 encryption failed"); 1395 smb_session_disconnect(sr->session); 1396 } else { 1397 (void) smb_session_send(sr->session, 0, &enc_reply); 1398 } 1399 MBC_FLUSH(&enc_reply); 1400 } 1401 1402 /* 1403 * This wrapper function exists to help catch calls to smbsr_status() 1404 * (which is SMB1-specific) in common code. See smbsr_status(). 1405 * If the log message below is seen, put a dtrace probe on this 1406 * function with a stack() action to see who is calling the SMB1 1407 * "put error" from common code, and fix it. 1408 */ 1409 void 1410 smbsr_status_smb2(smb_request_t *sr, DWORD status) 1411 { 1412 const char *name; 1413 1414 if (sr->smb2_cmd_code < SMB2__NCMDS) 1415 name = smb2_disp_table[sr->smb2_cmd_code].sdt_name; 1416 else 1417 name = "<unknown>"; 1418 #ifdef DEBUG 1419 cmn_err(CE_NOTE, "smbsr_status called for %s", name); 1420 #endif 1421 1422 smb2sr_put_error_data(sr, status, NULL); 1423 } 1424 1425 void 1426 smb2sr_put_errno(struct smb_request *sr, int errnum) 1427 { 1428 uint32_t status = smb_errno2status(errnum); 1429 smb2sr_put_error_data(sr, status, NULL); 1430 } 1431 1432 void 1433 smb2sr_put_error(smb_request_t *sr, uint32_t status) 1434 { 1435 smb2sr_put_error_data(sr, status, NULL); 1436 } 1437 1438 /* 1439 * Build an SMB2 error response. [MS-SMB2] 2.2.2 1440 */ 1441 void 1442 smb2sr_put_error_data(smb_request_t *sr, uint32_t status, mbuf_chain_t *mbc) 1443 { 1444 DWORD len; 1445 1446 /* 1447 * The common dispatch code writes this when it 1448 * updates the SMB2 header before sending. 1449 */ 1450 sr->smb2_status = status; 1451 1452 /* Rewind to the end of the SMB header. */ 1453 sr->reply.chain_offset = sr->smb2_reply_hdr + SMB2_HDR_SIZE; 1454 1455 /* 1456 * NB: Must provide at least one byte of error data, 1457 * per [MS-SMB2] 2.2.2 1458 */ 1459 if (mbc != NULL && (len = MBC_LENGTH(mbc)) != 0) { 1460 (void) smb_mbc_encodef( 1461 &sr->reply, 1462 "wwlC", 1463 9, /* StructSize */ /* w */ 1464 0, /* reserved */ /* w */ 1465 len, /* l */ 1466 mbc); /* C */ 1467 } else { 1468 (void) smb_mbc_encodef( 1469 &sr->reply, 1470 "wwl.", 1471 9, /* StructSize */ /* w */ 1472 0, /* reserved */ /* w */ 1473 0); /* l. */ 1474 } 1475 } 1476 1477 /* 1478 * Build an SMB2 error context response (dialect 3.1.1). 1479 */ 1480 void 1481 smb2sr_put_error_ctx(smb_request_t *sr, uint32_t status, uint32_t errid, 1482 mbuf_chain_t *mbc) 1483 { 1484 DWORD len; 1485 1486 /* 1487 * The common dispatch code writes this when it 1488 * updates the SMB2 header before sending. 1489 */ 1490 sr->smb2_status = status; 1491 1492 /* Rewind to the end of the SMB header. */ 1493 sr->reply.chain_offset = sr->smb2_reply_hdr + SMB2_HDR_SIZE; 1494 1495 /* 1496 * Error Context is 8-byte header plus encaps. data (ErrorContextData), 1497 * which can be zero-length. 1498 */ 1499 if (mbc != NULL && (len = MBC_LENGTH(mbc)) != 0) { 1500 (void) smb_mbc_encodef( 1501 &sr->reply, 1502 "wbblllC", 1503 9, /* StructSize */ /* w */ 1504 1, /* ErrorContextCount */ /* b */ 1505 0, /* reserved */ /* b */ 1506 8+len, /* ByteCount */ /* l */ 1507 len, /* ErrorDataLength */ /* l */ 1508 errid, /* ErrorId */ /* l */ 1509 mbc); /* C */ 1510 } else { 1511 (void) smb_mbc_encodef( 1512 &sr->reply, 1513 "wbblll", 1514 9, /* StructSize */ /* w */ 1515 1, /* ErrorContextCount */ /* b */ 1516 0, /* reserved */ /* b */ 1517 8, /* ByteCount */ /* l */ 1518 0, /* ErrorDataLength */ /* l */ 1519 errid); /* ErrorId */ /* l */ 1520 } 1521 } 1522 1523 /* 1524 * Build an SMB2 error context response with SMB2_ERROR_ID_DEFAULT ErrorId. 1525 * 1526 * This only handles the case we currently need, encapsulating a 1527 * single error data section inside an SMB2_ERROR_ID_DEFAULT 1528 * error context type (which is type zero, and that's what 1529 * the zero on the end of this function name refers to). 1530 */ 1531 void 1532 smb2sr_put_error_ctx0(smb_request_t *sr, uint32_t status, mbuf_chain_t *mbc) 1533 { 1534 return (smb2sr_put_error_ctx(sr, status, SMB2_ERROR_ID_DEFAULT, mbc)); 1535 } 1536 1537 /* 1538 * smb2sr_lookup_fid 1539 * 1540 * Setup sr->fid_ofile, either inherited from a related command, 1541 * or obtained via FID lookup. Similar inheritance logic as in 1542 * smb2sr_work. 1543 */ 1544 uint32_t 1545 smb2sr_lookup_fid(smb_request_t *sr, smb2fid_t *fid) 1546 { 1547 boolean_t related = sr->smb2_hdr_flags & 1548 SMB2_FLAGS_RELATED_OPERATIONS; 1549 1550 if (related) { 1551 if (sr->fid_ofile == NULL) 1552 return (NT_STATUS_INVALID_PARAMETER); 1553 sr->smb_fid = sr->fid_ofile->f_fid; 1554 return (0); 1555 } 1556 1557 /* 1558 * If we could be sure this is called only once per cmd, 1559 * we could simply ASSERT(sr->fid_ofile == NULL) here. 1560 * However, there are cases where it can be called again 1561 * handling the same command, so let's tolerate that. 1562 */ 1563 if (sr->fid_ofile == NULL) { 1564 sr->smb_fid = (uint16_t)fid->temporal; 1565 sr->fid_ofile = smb_ofile_lookup_by_fid(sr, sr->smb_fid); 1566 } 1567 if (sr->fid_ofile == NULL || 1568 sr->fid_ofile->f_persistid != fid->persistent) 1569 return (NT_STATUS_FILE_CLOSED); 1570 1571 return (0); 1572 } 1573 1574 /* 1575 * smb2_dispatch_stats_init 1576 * 1577 * Initializes dispatch statistics for SMB2. 1578 * See also smb_dispatch_stats_init(), which fills in 1579 * the lower part of the statistics array, from zero 1580 * through SMB_COM_NUM; 1581 */ 1582 void 1583 smb2_dispatch_stats_init(smb_server_t *sv) 1584 { 1585 smb_disp_stats_t *sds = sv->sv_disp_stats2; 1586 smb_kstat_req_t *ksr; 1587 int i; 1588 1589 ksr = ((smbsrv_kstats_t *)sv->sv_ksp->ks_data)->ks_reqs2; 1590 1591 for (i = 0; i < SMB2__NCMDS; i++, ksr++) { 1592 smb_latency_init(&sds[i].sdt_lat); 1593 (void) strlcpy(ksr->kr_name, smb2_disp_table[i].sdt_name, 1594 sizeof (ksr->kr_name)); 1595 } 1596 } 1597 1598 /* 1599 * smb2_dispatch_stats_fini 1600 * 1601 * Frees and destroyes the resources used for statistics. 1602 */ 1603 void 1604 smb2_dispatch_stats_fini(smb_server_t *sv) 1605 { 1606 smb_disp_stats_t *sds = sv->sv_disp_stats2; 1607 int i; 1608 1609 for (i = 0; i < SMB2__NCMDS; i++) 1610 smb_latency_destroy(&sds[i].sdt_lat); 1611 } 1612 1613 void 1614 smb2_dispatch_stats_update(smb_server_t *sv, 1615 smb_kstat_req_t *ksr, int first, int nreq) 1616 { 1617 smb_disp_stats_t *sds = sv->sv_disp_stats2; 1618 int i; 1619 int last; 1620 1621 last = first + nreq - 1; 1622 1623 if ((first < SMB2__NCMDS) && (last < SMB2__NCMDS)) { 1624 for (i = first; i <= last; i++, ksr++) { 1625 ksr->kr_rxb = sds[i].sdt_rxb; 1626 ksr->kr_txb = sds[i].sdt_txb; 1627 mutex_enter(&sds[i].sdt_lat.ly_mutex); 1628 ksr->kr_nreq = sds[i].sdt_lat.ly_a_nreq; 1629 ksr->kr_sum = sds[i].sdt_lat.ly_a_sum; 1630 ksr->kr_a_mean = sds[i].sdt_lat.ly_a_mean; 1631 ksr->kr_a_stddev = 1632 sds[i].sdt_lat.ly_a_stddev; 1633 ksr->kr_d_mean = sds[i].sdt_lat.ly_d_mean; 1634 ksr->kr_d_stddev = 1635 sds[i].sdt_lat.ly_d_stddev; 1636 sds[i].sdt_lat.ly_d_mean = 0; 1637 sds[i].sdt_lat.ly_d_nreq = 0; 1638 sds[i].sdt_lat.ly_d_stddev = 0; 1639 sds[i].sdt_lat.ly_d_sum = 0; 1640 mutex_exit(&sds[i].sdt_lat.ly_mutex); 1641 } 1642 } 1643 } 1644 1645 /* 1646 * Append new_sr to the postwork queue. sr->smb2_cmd_code encodes 1647 * the action that should be run by this sr. 1648 * 1649 * This queue is rarely used (and normally empty) so we're OK 1650 * using a simple "walk to tail and insert" here. 1651 */ 1652 void 1653 smb2sr_append_postwork(smb_request_t *top_sr, smb_request_t *new_sr) 1654 { 1655 smb_request_t *last_sr; 1656 1657 ASSERT(top_sr->session->dialect >= SMB_VERS_2_BASE); 1658 1659 last_sr = top_sr; 1660 while (last_sr->sr_postwork != NULL) 1661 last_sr = last_sr->sr_postwork; 1662 1663 last_sr->sr_postwork = new_sr; 1664 } 1665 1666 /* 1667 * Run any "post work" that was appended to the main SR while it 1668 * was running. This is called after the request has been sent 1669 * for the main SR, and used in cases i.e. the oplock code, where 1670 * we need to send something to the client only _after_ the main 1671 * sr request has gone out. 1672 */ 1673 static void 1674 smb2sr_run_postwork(smb_request_t *top_sr) 1675 { 1676 smb_request_t *post_sr; /* the one we're running */ 1677 smb_request_t *next_sr; 1678 1679 while ((post_sr = top_sr->sr_postwork) != NULL) { 1680 next_sr = post_sr->sr_postwork; 1681 top_sr->sr_postwork = next_sr; 1682 post_sr->sr_postwork = NULL; 1683 1684 post_sr->sr_worker = top_sr->sr_worker; 1685 post_sr->sr_state = SMB_REQ_STATE_ACTIVE; 1686 1687 switch (post_sr->smb2_cmd_code) { 1688 case SMB2_OPLOCK_BREAK: 1689 smb_oplock_send_break(post_sr); 1690 break; 1691 default: 1692 ASSERT(0); 1693 } 1694 1695 /* 1696 * If we have a durable handle, and this operation 1697 * updated the nvlist, write it out. 1698 */ 1699 if (post_sr->dh_nvl_dirty) { 1700 post_sr->dh_nvl_dirty = B_FALSE; 1701 smb2_dh_update_nvfile(post_sr); 1702 } 1703 1704 post_sr->sr_state = SMB_REQ_STATE_COMPLETED; 1705 smb_request_free(post_sr); 1706 } 1707 } 1708