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