Changeset 745 for trunk/server/source3/smbd/smb2_server.c
- Timestamp:
- Nov 27, 2012, 4:43:17 PM (13 years ago)
- Location:
- trunk/server
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/server
- Property svn:mergeinfo changed
/vendor/current merged: 581,587,591,594,597,600,615,618,740
- Property svn:mergeinfo changed
-
trunk/server/source3/smbd/smb2_server.c
r414 r745 4 4 5 5 Copyright (C) Stefan Metzmacher 2009 6 Copyright (C) Jeremy Allison 2010 6 7 7 8 This program is free software; you can redistribute it and/or modify … … 20 21 21 22 #include "includes.h" 23 #include "smbd/smbd.h" 22 24 #include "smbd/globals.h" 23 25 #include "../libcli/smb/smb_common.h" 24 26 #include "../lib/tsocket/tsocket.h" 27 #include "../lib/util/tevent_ntstatus.h" 28 #include "smbprofile.h" 29 30 #define OUTVEC_ALLOC_SIZE (SMB2_HDR_BODY + 9) 31 32 static const char *smb2_names[] = { 33 "SMB2_NEGPROT", 34 "SMB2_SESSSETUP", 35 "SMB2_LOGOFF", 36 "SMB2_TCON", 37 "SMB2_TDIS", 38 "SMB2_CREATE", 39 "SMB2_CLOSE", 40 "SMB2_FLUSH", 41 "SMB2_READ", 42 "SMB2_WRITE", 43 "SMB2_LOCK", 44 "SMB2_IOCTL", 45 "SMB2_CANCEL", 46 "SMB2_KEEPALIVE", 47 "SMB2_FIND", 48 "SMB2_NOTIFY", 49 "SMB2_GETINFO", 50 "SMB2_SETINFO", 51 "SMB2_BREAK" 52 }; 53 54 const char *smb2_opcode_name(uint16_t opcode) 55 { 56 if (opcode > 0x12) { 57 return "Bad SMB2 opcode"; 58 } 59 return smb2_names[opcode]; 60 } 61 62 static void print_req_vectors(struct smbd_smb2_request *req) 63 { 64 int i; 65 66 for (i = 0; i < req->in.vector_count; i++) { 67 dbgtext("\treq->in.vector[%u].iov_len = %u\n", 68 (unsigned int)i, 69 (unsigned int)req->in.vector[i].iov_len); 70 } 71 for (i = 0; i < req->out.vector_count; i++) { 72 dbgtext("\treq->out.vector[%u].iov_len = %u\n", 73 (unsigned int)i, 74 (unsigned int)req->out.vector[i].iov_len); 75 } 76 } 25 77 26 78 bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size) … … 62 114 sconn->smb2.sessions.limit = 0x0000FFFE; 63 115 sconn->smb2.sessions.list = NULL; 64 65 ret = tstream_bsd_existing_socket(sconn, smbd_server_fd(), 116 sconn->smb2.seqnum_low = 0; 117 sconn->smb2.credits_granted = 0; 118 sconn->smb2.max_credits = lp_smb2_max_credits(); 119 sconn->smb2.credits_bitmap = bitmap_talloc(sconn, 120 DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR*sconn->smb2.max_credits); 121 if (sconn->smb2.credits_bitmap == NULL) { 122 return NT_STATUS_NO_MEMORY; 123 } 124 125 ret = tstream_bsd_existing_socket(sconn, sconn->sock, 66 126 &sconn->smb2.stream); 67 127 if (ret == -1) { … … 71 131 72 132 /* Ensure child is set to non-blocking mode */ 73 set_blocking(s mbd_server_fd(),false);133 set_blocking(sconn->sock, false); 74 134 return NT_STATUS_OK; 75 135 } … … 108 168 static int smbd_smb2_request_destructor(struct smbd_smb2_request *req) 109 169 { 110 if (req->out.vector) {111 DLIST_REMOVE(req->sconn->smb2.requests, req);112 }113 114 170 if (req->parent) { 115 171 *req->parent = NULL; … … 126 182 struct smbd_smb2_request *req; 127 183 184 #if 0 185 /* Enable this to find subtle valgrind errors. */ 186 mem_pool = talloc_init("smbd_smb2_request_allocate"); 187 #else 128 188 mem_pool = talloc_pool(mem_ctx, 8192); 189 #endif 129 190 if (mem_pool == NULL) { 130 191 return NULL; … … 235 296 } 236 297 298 static bool smb2_validate_message_id(struct smbd_server_connection *sconn, 299 const uint8_t *inhdr) 300 { 301 uint64_t message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID); 302 struct bitmap *credits_bm = sconn->smb2.credits_bitmap; 303 uint16_t opcode = IVAL(inhdr, SMB2_HDR_OPCODE); 304 unsigned int bitmap_offset; 305 306 if (opcode == SMB2_OP_CANCEL) { 307 /* SMB2_CANCEL requests by definition resend messageids. */ 308 return true; 309 } 310 311 if (message_id < sconn->smb2.seqnum_low || 312 message_id > (sconn->smb2.seqnum_low + 313 (sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR))) { 314 DEBUG(0,("smb2_validate_message_id: bad message_id " 315 "%llu (low = %llu, max = %lu)\n", 316 (unsigned long long)message_id, 317 (unsigned long long)sconn->smb2.seqnum_low, 318 (unsigned long)sconn->smb2.max_credits )); 319 return false; 320 } 321 322 /* client just used a credit. */ 323 SMB_ASSERT(sconn->smb2.credits_granted > 0); 324 sconn->smb2.credits_granted -= 1; 325 326 /* Mark the message_id as seen in the bitmap. */ 327 bitmap_offset = (unsigned int)(message_id % 328 (uint64_t)(sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR)); 329 if (bitmap_query(credits_bm, bitmap_offset)) { 330 DEBUG(0,("smb2_validate_message_id: duplicate message_id " 331 "%llu (bm offset %u)\n", 332 (unsigned long long)message_id, 333 bitmap_offset)); 334 return false; 335 } 336 bitmap_set(credits_bm, bitmap_offset); 337 338 if (message_id == sconn->smb2.seqnum_low + 1) { 339 /* Move the window forward by all the message_id's 340 already seen. */ 341 while (bitmap_query(credits_bm, bitmap_offset)) { 342 DEBUG(10,("smb2_validate_message_id: clearing " 343 "id %llu (position %u) from bitmap\n", 344 (unsigned long long)(sconn->smb2.seqnum_low + 1), 345 bitmap_offset )); 346 bitmap_clear(credits_bm, bitmap_offset); 347 sconn->smb2.seqnum_low += 1; 348 bitmap_offset = (bitmap_offset + 1) % 349 (sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR); 350 } 351 } 352 353 return true; 354 } 355 237 356 static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req) 238 357 { … … 262 381 inhdr = (const uint8_t *)req->in.vector[idx].iov_base; 263 382 264 /* setupthe SMB2 header */383 /* Check the SMB2 header */ 265 384 if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) { 385 return NT_STATUS_INVALID_PARAMETER; 386 } 387 388 if (!smb2_validate_message_id(req->sconn, inhdr)) { 266 389 return NT_STATUS_INVALID_PARAMETER; 267 390 } … … 315 438 } 316 439 440 static void smb2_set_operation_credit(struct smbd_server_connection *sconn, 441 const struct iovec *in_vector, 442 struct iovec *out_vector) 443 { 444 const uint8_t *inhdr = (const uint8_t *)in_vector->iov_base; 445 uint8_t *outhdr = (uint8_t *)out_vector->iov_base; 446 uint16_t credits_requested; 447 uint32_t out_flags; 448 uint16_t credits_granted = 0; 449 450 credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT); 451 out_flags = IVAL(outhdr, SMB2_HDR_FLAGS); 452 453 SMB_ASSERT(sconn->smb2.max_credits >= sconn->smb2.credits_granted); 454 455 if (out_flags & SMB2_HDR_FLAG_ASYNC) { 456 /* 457 * In case we already send an async interim 458 * response, we should not grant 459 * credits on the final response. 460 */ 461 credits_requested = 0; 462 } 463 464 if (credits_requested) { 465 uint16_t modified_credits_requested; 466 uint32_t multiplier; 467 468 /* 469 * Split up max_credits into 1/16ths, and then scale 470 * the requested credits by how many 16ths have been 471 * currently granted. Less than 1/16th == grant all 472 * requested (100%), scale down as more have been 473 * granted. Never ask for less than 1 as the client 474 * asked for at least 1. JRA. 475 */ 476 477 multiplier = 16 - (((sconn->smb2.credits_granted * 16) / sconn->smb2.max_credits) % 16); 478 479 modified_credits_requested = (multiplier * credits_requested) / 16; 480 if (modified_credits_requested == 0) { 481 modified_credits_requested = 1; 482 } 483 484 /* Remember what we gave out. */ 485 credits_granted = MIN(modified_credits_requested, 486 (sconn->smb2.max_credits - sconn->smb2.credits_granted)); 487 } 488 489 if (credits_granted == 0 && sconn->smb2.credits_granted == 0) { 490 /* First negprot packet, or ensure the client credits can 491 never drop to zero. */ 492 credits_granted = 1; 493 } 494 495 SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted); 496 sconn->smb2.credits_granted += credits_granted; 497 498 DEBUG(10,("smb2_set_operation_credit: requested %u, " 499 "granted %u, total granted %u\n", 500 (unsigned int)credits_requested, 501 (unsigned int)credits_granted, 502 (unsigned int)sconn->smb2.credits_granted )); 503 } 504 505 static void smb2_calculate_credits(const struct smbd_smb2_request *inreq, 506 struct smbd_smb2_request *outreq) 507 { 508 int count, idx; 509 510 count = outreq->out.vector_count; 511 512 for (idx=1; idx < count; idx += 3) { 513 smb2_set_operation_credit(outreq->sconn, 514 &inreq->in.vector[idx], 515 &outreq->out.vector[idx]); 516 } 517 } 518 317 519 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req) 318 520 { … … 322 524 323 525 count = req->in.vector_count; 324 vector = talloc_ array(req, struct iovec, count);526 vector = talloc_zero_array(req, struct iovec, count); 325 527 if (vector == NULL) { 326 528 return NT_STATUS_NO_MEMORY; … … 340 542 341 543 if ((idx + 3) < count) { 342 /* we have a next command */ 343 next_command_ofs = SMB2_HDR_BODY + 8; 544 /* we have a next command - 545 * setup for the error case. */ 546 next_command_ofs = SMB2_HDR_BODY + 9; 344 547 } 345 548 … … 347 550 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS); 348 551 349 outhdr = talloc_ array(vector, uint8_t,350 SMB2_HDR_BODY + 8);552 outhdr = talloc_zero_array(vector, uint8_t, 553 OUTVEC_ALLOC_SIZE); 351 554 if (outhdr == NULL) { 352 555 return NT_STATUS_NO_MEMORY; … … 372 575 SSVAL(outhdr, SMB2_HDR_OPCODE, 373 576 SVAL(inhdr, SMB2_HDR_OPCODE)); 374 /* Make up a number for now... JRA. FIXME ! FIXME !*/375 SSVAL(outhdr, SMB2_HDR_CREDIT, 20);376 577 SIVAL(outhdr, SMB2_HDR_FLAGS, 377 578 IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT); … … 413 614 } 414 615 616 static bool dup_smb2_vec3(TALLOC_CTX *ctx, 617 struct iovec *outvec, 618 const struct iovec *srcvec) 619 { 620 /* vec[0] is always boilerplate and must 621 * be allocated with size OUTVEC_ALLOC_SIZE. */ 622 623 outvec[0].iov_base = talloc_memdup(ctx, 624 srcvec[0].iov_base, 625 OUTVEC_ALLOC_SIZE); 626 if (!outvec[0].iov_base) { 627 return false; 628 } 629 outvec[0].iov_len = SMB2_HDR_BODY; 630 631 /* 632 * If this is a "standard" vec[1] of length 8, 633 * pointing to srcvec[0].iov_base + SMB2_HDR_BODY, 634 * then duplicate this. Else use talloc_memdup(). 635 */ 636 637 if (srcvec[1].iov_len == 8 && 638 srcvec[1].iov_base == 639 ((uint8_t *)srcvec[0].iov_base) + 640 SMB2_HDR_BODY) { 641 outvec[1].iov_base = ((uint8_t *)outvec[0].iov_base) + 642 SMB2_HDR_BODY; 643 outvec[1].iov_len = 8; 644 } else { 645 outvec[1].iov_base = talloc_memdup(ctx, 646 srcvec[1].iov_base, 647 srcvec[1].iov_len); 648 if (!outvec[1].iov_base) { 649 return false; 650 } 651 outvec[1].iov_len = srcvec[1].iov_len; 652 } 653 654 /* 655 * If this is a "standard" vec[2] of length 1, 656 * pointing to srcvec[0].iov_base + (OUTVEC_ALLOC_SIZE - 1) 657 * then duplicate this. Else use talloc_memdup(). 658 */ 659 660 if (srcvec[2].iov_base && 661 srcvec[2].iov_len) { 662 if (srcvec[2].iov_base == 663 ((uint8_t *)srcvec[0].iov_base) + 664 (OUTVEC_ALLOC_SIZE - 1) && 665 srcvec[2].iov_len == 1) { 666 /* Common SMB2 error packet case. */ 667 outvec[2].iov_base = ((uint8_t *)outvec[0].iov_base) + 668 (OUTVEC_ALLOC_SIZE - 1); 669 } else { 670 outvec[2].iov_base = talloc_memdup(ctx, 671 srcvec[2].iov_base, 672 srcvec[2].iov_len); 673 if (!outvec[2].iov_base) { 674 return false; 675 } 676 } 677 outvec[2].iov_len = srcvec[2].iov_len; 678 } else { 679 outvec[2].iov_base = NULL; 680 outvec[2].iov_len = 0; 681 } 682 return true; 683 } 684 685 static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *req) 686 { 687 struct smbd_smb2_request *newreq = NULL; 688 struct iovec *outvec = NULL; 689 int count = req->out.vector_count; 690 int i; 691 692 newreq = smbd_smb2_request_allocate(req->sconn); 693 if (!newreq) { 694 return NULL; 695 } 696 697 newreq->sconn = req->sconn; 698 newreq->session = req->session; 699 newreq->do_signing = req->do_signing; 700 newreq->current_idx = req->current_idx; 701 newreq->async = false; 702 newreq->cancelled = false; 703 /* Note we are leaving: 704 ->tcon 705 ->smb1req 706 ->compat_chain_fsp 707 uninitialized as NULL here as 708 they're not used in the interim 709 response code. JRA. */ 710 711 outvec = talloc_zero_array(newreq, struct iovec, count); 712 if (!outvec) { 713 TALLOC_FREE(newreq); 714 return NULL; 715 } 716 newreq->out.vector = outvec; 717 newreq->out.vector_count = count; 718 719 /* Setup the outvec's identically to req. */ 720 outvec[0].iov_base = newreq->out.nbt_hdr; 721 outvec[0].iov_len = 4; 722 memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4); 723 724 /* Setup the vectors identically to the ones in req. */ 725 for (i = 1; i < count; i += 3) { 726 if (!dup_smb2_vec3(outvec, &outvec[i], &req->out.vector[i])) { 727 break; 728 } 729 } 730 731 if (i < count) { 732 /* Alloc failed. */ 733 TALLOC_FREE(newreq); 734 return NULL; 735 } 736 737 smb2_setup_nbt_length(newreq->out.vector, 738 newreq->out.vector_count); 739 740 return newreq; 741 } 742 743 static void smbd_smb2_request_writev_done(struct tevent_req *subreq); 744 745 static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request *req) 746 { 747 int i = 0; 748 uint8_t *outhdr = NULL; 749 struct smbd_smb2_request *nreq = NULL; 750 751 /* Create a new smb2 request we'll use 752 for the interim return. */ 753 nreq = dup_smb2_req(req); 754 if (!nreq) { 755 return NT_STATUS_NO_MEMORY; 756 } 757 758 /* Lose the last 3 out vectors. They're the 759 ones we'll be using for the async reply. */ 760 nreq->out.vector_count -= 3; 761 762 smb2_setup_nbt_length(nreq->out.vector, 763 nreq->out.vector_count); 764 765 /* Step back to the previous reply. */ 766 i = nreq->current_idx - 3; 767 outhdr = (uint8_t *)nreq->out.vector[i].iov_base; 768 /* And end the chain. */ 769 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0); 770 771 /* Calculate outgoing credits */ 772 smb2_calculate_credits(req, nreq); 773 774 /* Re-sign if needed. */ 775 if (nreq->do_signing) { 776 NTSTATUS status; 777 status = smb2_signing_sign_pdu(nreq->session->session_key, 778 &nreq->out.vector[i], 3); 779 if (!NT_STATUS_IS_OK(status)) { 780 return status; 781 } 782 } 783 if (DEBUGLEVEL >= 10) { 784 dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n", 785 (unsigned int)nreq->current_idx ); 786 dbgtext("smb2_send_async_interim_response: returning %u vectors\n", 787 (unsigned int)nreq->out.vector_count ); 788 print_req_vectors(nreq); 789 } 790 nreq->subreq = tstream_writev_queue_send(nreq, 791 nreq->sconn->smb2.event_ctx, 792 nreq->sconn->smb2.stream, 793 nreq->sconn->smb2.send_queue, 794 nreq->out.vector, 795 nreq->out.vector_count); 796 797 if (nreq->subreq == NULL) { 798 return NT_STATUS_NO_MEMORY; 799 } 800 801 tevent_req_set_callback(nreq->subreq, 802 smbd_smb2_request_writev_done, 803 nreq); 804 805 return NT_STATUS_OK; 806 } 807 415 808 struct smbd_smb2_request_pending_state { 416 417 uint8_t buf[4 + SMB2_HDR_BODY + 0x08];418 struct iovec vector;809 struct smbd_server_connection *sconn; 810 uint8_t buf[4 + SMB2_HDR_BODY + 0x08 + 1]; 811 struct iovec vector[3]; 419 812 }; 420 421 static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq);422 423 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,424 struct tevent_req *subreq)425 {426 struct smbd_smb2_request_pending_state *state;427 uint8_t *outhdr;428 int i = req->current_idx;429 uint32_t flags;430 uint64_t message_id;431 uint64_t async_id;432 uint8_t *hdr;433 uint8_t *body;434 435 if (!tevent_req_is_in_progress(subreq)) {436 return NT_STATUS_OK;437 }438 439 req->subreq = subreq;440 subreq = NULL;441 442 outhdr = (uint8_t *)req->out.vector[i].iov_base;443 444 flags = IVAL(outhdr, SMB2_HDR_FLAGS);445 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);446 447 async_id = message_id; /* keep it simple for now... */448 SIVAL(outhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);449 SBVAL(outhdr, SMB2_HDR_PID, async_id);450 451 /* TODO: add a paramter to delay this */452 state = talloc(req->sconn, struct smbd_smb2_request_pending_state);453 if (state == NULL) {454 return NT_STATUS_NO_MEMORY;455 }456 state->sconn = req->sconn;457 458 state->vector.iov_base = (void *)state->buf;459 state->vector.iov_len = sizeof(state->buf);460 461 _smb2_setlen(state->buf, sizeof(state->buf) - 4);462 hdr = state->buf + 4;463 body = hdr + SMB2_HDR_BODY;464 465 SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);466 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);467 SSVAL(hdr, SMB2_HDR_EPOCH, 0);468 SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));469 SSVAL(hdr, SMB2_HDR_OPCODE,470 SVAL(outhdr, SMB2_HDR_OPCODE));471 SSVAL(hdr, SMB2_HDR_CREDIT, 1);472 SIVAL(hdr, SMB2_HDR_FLAGS,473 IVAL(outhdr, SMB2_HDR_FLAGS));474 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);475 SBVAL(hdr, SMB2_HDR_MESSAGE_ID,476 BVAL(outhdr, SMB2_HDR_MESSAGE_ID));477 SBVAL(hdr, SMB2_HDR_PID,478 BVAL(outhdr, SMB2_HDR_PID));479 SBVAL(hdr, SMB2_HDR_SESSION_ID,480 BVAL(outhdr, SMB2_HDR_SESSION_ID));481 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);482 483 SSVAL(body, 0x00, 0x08 + 1);484 485 SCVAL(body, 0x02, 0);486 SCVAL(body, 0x03, 0);487 SIVAL(body, 0x04, 0);488 489 subreq = tstream_writev_queue_send(state,490 req->sconn->smb2.event_ctx,491 req->sconn->smb2.stream,492 req->sconn->smb2.send_queue,493 &state->vector, 1);494 if (subreq == NULL) {495 return NT_STATUS_NO_MEMORY;496 }497 tevent_req_set_callback(subreq,498 smbd_smb2_request_pending_writev_done,499 state);500 501 return NT_STATUS_OK;502 }503 813 504 814 static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq) … … 506 816 struct smbd_smb2_request_pending_state *state = 507 817 tevent_req_callback_data(subreq, 508 struct smbd_smb2_request_pending_state);818 struct smbd_smb2_request_pending_state); 509 819 struct smbd_server_connection *sconn = state->sconn; 510 820 int ret; … … 520 830 521 831 TALLOC_FREE(state); 832 } 833 834 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req, 835 struct tevent_req *subreq) 836 { 837 NTSTATUS status; 838 struct smbd_smb2_request_pending_state *state = NULL; 839 int i = req->current_idx; 840 uint8_t *reqhdr = NULL; 841 uint8_t *hdr = NULL; 842 uint8_t *body = NULL; 843 uint32_t flags = 0; 844 uint64_t message_id = 0; 845 uint64_t async_id = 0; 846 struct iovec *outvec = NULL; 847 848 if (!tevent_req_is_in_progress(subreq)) { 849 return NT_STATUS_OK; 850 } 851 852 req->subreq = subreq; 853 subreq = NULL; 854 855 if (req->async) { 856 /* We're already async. */ 857 return NT_STATUS_OK; 858 } 859 860 if (req->in.vector_count > i + 3) { 861 /* 862 * We're trying to go async in a compound 863 * request chain. This is not allowed. 864 * Cancel the outstanding request. 865 */ 866 tevent_req_cancel(req->subreq); 867 return smbd_smb2_request_error(req, 868 NT_STATUS_INSUFFICIENT_RESOURCES); 869 } 870 871 if (DEBUGLEVEL >= 10) { 872 dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n", 873 (unsigned int)req->current_idx ); 874 print_req_vectors(req); 875 } 876 877 if (req->out.vector_count > 4) { 878 /* This is a compound reply. We 879 * must do an interim response 880 * followed by the async response 881 * to match W2K8R2. 882 */ 883 status = smb2_send_async_interim_response(req); 884 if (!NT_STATUS_IS_OK(status)) { 885 return status; 886 } 887 } 888 889 /* Don't return an intermediate packet on a pipe read/write. */ 890 if (req->tcon && req->tcon->compat_conn && IS_IPC(req->tcon->compat_conn)) { 891 return NT_STATUS_OK; 892 } 893 894 reqhdr = (uint8_t *)req->out.vector[i].iov_base; 895 flags = (IVAL(reqhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED); 896 message_id = BVAL(reqhdr, SMB2_HDR_MESSAGE_ID); 897 async_id = message_id; /* keep it simple for now... */ 898 899 /* 900 * What we send is identical to a smbd_smb2_request_error 901 * packet with an error status of STATUS_PENDING. Make use 902 * of this fact sometime when refactoring. JRA. 903 */ 904 905 state = talloc_zero(req->sconn, struct smbd_smb2_request_pending_state); 906 if (state == NULL) { 907 return NT_STATUS_NO_MEMORY; 908 } 909 state->sconn = req->sconn; 910 911 state->vector[0].iov_base = (void *)state->buf; 912 state->vector[0].iov_len = 4; 913 914 state->vector[1].iov_base = state->buf + 4; 915 state->vector[1].iov_len = SMB2_HDR_BODY; 916 917 state->vector[2].iov_base = state->buf + 4 + SMB2_HDR_BODY; 918 state->vector[2].iov_len = 9; 919 920 smb2_setup_nbt_length(state->vector, 3); 921 922 hdr = (uint8_t *)state->vector[1].iov_base; 923 body = (uint8_t *)state->vector[2].iov_base; 924 925 SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC); 926 SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY); 927 SSVAL(hdr, SMB2_HDR_EPOCH, 0); 928 SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING)); 929 SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(reqhdr, SMB2_HDR_OPCODE)); 930 931 SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC); 932 SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0); 933 SBVAL(hdr, SMB2_HDR_MESSAGE_ID, message_id); 934 SBVAL(hdr, SMB2_HDR_PID, async_id); 935 SBVAL(hdr, SMB2_HDR_SESSION_ID, 936 BVAL(reqhdr, SMB2_HDR_SESSION_ID)); 937 memset(hdr+SMB2_HDR_SIGNATURE, 0, 16); 938 939 SSVAL(body, 0x00, 0x08 + 1); 940 941 SCVAL(body, 0x02, 0); 942 SCVAL(body, 0x03, 0); 943 SIVAL(body, 0x04, 0); 944 /* Match W2K8R2... */ 945 SCVAL(body, 0x08, 0x21); 946 947 /* Ensure we correctly go through crediting. Grant 948 the credits now, and zero credits on the final 949 response. */ 950 smb2_set_operation_credit(req->sconn, 951 &req->in.vector[i], 952 &state->vector[1]); 953 954 if (req->do_signing) { 955 status = smb2_signing_sign_pdu(req->session->session_key, 956 &state->vector[1], 2); 957 if (!NT_STATUS_IS_OK(status)) { 958 return status; 959 } 960 } 961 962 subreq = tstream_writev_queue_send(state, 963 req->sconn->smb2.event_ctx, 964 req->sconn->smb2.stream, 965 req->sconn->smb2.send_queue, 966 state->vector, 967 3); 968 969 if (subreq == NULL) { 970 return NT_STATUS_NO_MEMORY; 971 } 972 973 tevent_req_set_callback(subreq, 974 smbd_smb2_request_pending_writev_done, 975 state); 976 977 /* Note we're going async with this request. */ 978 req->async = true; 979 980 /* 981 * Now manipulate req so that the outstanding async request 982 * is the only one left in the struct smbd_smb2_request. 983 */ 984 985 if (req->current_idx == 1) { 986 /* There was only one. */ 987 goto out; 988 } 989 990 /* Re-arrange the in.vectors. */ 991 req->in.vector[1] = req->in.vector[i]; 992 req->in.vector[2] = req->in.vector[i+1]; 993 req->in.vector[3] = req->in.vector[i+2]; 994 req->in.vector_count = 4; 995 /* Reset the new in size. */ 996 smb2_setup_nbt_length(req->in.vector, 4); 997 998 /* Now recreate the out.vectors. */ 999 outvec = talloc_zero_array(req, struct iovec, 4); 1000 if (!outvec) { 1001 return NT_STATUS_NO_MEMORY; 1002 } 1003 1004 /* 0 is always boilerplate and must 1005 * be of size 4 for the length field. */ 1006 1007 outvec[0].iov_base = req->out.nbt_hdr; 1008 outvec[0].iov_len = 4; 1009 SIVAL(req->out.nbt_hdr, 0, 0); 1010 1011 if (!dup_smb2_vec3(outvec, &outvec[1], &req->out.vector[i])) { 1012 return NT_STATUS_NO_MEMORY; 1013 } 1014 1015 TALLOC_FREE(req->out.vector); 1016 1017 req->out.vector = outvec; 1018 1019 req->current_idx = 1; 1020 req->out.vector_count = 4; 1021 1022 out: 1023 1024 smb2_setup_nbt_length(req->out.vector, 1025 req->out.vector_count); 1026 1027 /* Ensure our final reply matches the interim one. */ 1028 reqhdr = (uint8_t *)req->out.vector[1].iov_base; 1029 SIVAL(reqhdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC); 1030 SBVAL(reqhdr, SMB2_HDR_PID, async_id); 1031 1032 { 1033 const uint8_t *inhdr = 1034 (const uint8_t *)req->in.vector[1].iov_base; 1035 DEBUG(10,("smbd_smb2_request_pending_queue: opcode[%s] mid %llu " 1036 "going async\n", 1037 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)), 1038 (unsigned long long)async_id )); 1039 } 1040 return NT_STATUS_OK; 522 1041 } 523 1042 … … 531 1050 uint64_t search_message_id; 532 1051 uint64_t search_async_id; 1052 uint64_t found_id; 533 1053 534 1054 inhdr = (const uint8_t *)req->in.vector[i].iov_base; … … 542 1062 * cancel requests never have a response 543 1063 */ 1064 DLIST_REMOVE(req->sconn->smb2.requests, req); 544 1065 TALLOC_FREE(req); 545 1066 … … 558 1079 if (flags & SMB2_HDR_FLAG_ASYNC) { 559 1080 if (search_async_id == async_id) { 1081 found_id = async_id; 560 1082 break; 561 1083 } 562 1084 } else { 563 1085 if (search_message_id == message_id) { 1086 found_id = message_id; 564 1087 break; 565 1088 } … … 568 1091 569 1092 if (cur && cur->subreq) { 1093 inhdr = (const uint8_t *)cur->in.vector[i].iov_base; 1094 DEBUG(10,("smbd_smb2_request_process_cancel: attempting to " 1095 "cancel opcode[%s] mid %llu\n", 1096 smb2_opcode_name((uint16_t)IVAL(inhdr, SMB2_HDR_OPCODE)), 1097 (unsigned long long)found_id )); 570 1098 tevent_req_cancel(cur->subreq); 571 1099 } … … 574 1102 } 575 1103 576 staticNTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)1104 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req) 577 1105 { 578 1106 const uint8_t *inhdr; … … 580 1108 uint16_t opcode; 581 1109 uint32_t flags; 1110 uint64_t mid; 582 1111 NTSTATUS status; 583 1112 NTSTATUS session_status; 584 1113 uint32_t allowed_flags; 1114 NTSTATUS return_value; 585 1115 586 1116 inhdr = (const uint8_t *)req->in.vector[i].iov_base; … … 590 1120 flags = IVAL(inhdr, SMB2_HDR_FLAGS); 591 1121 opcode = IVAL(inhdr, SMB2_HDR_OPCODE); 592 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%u]\n", opcode)); 1122 mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID); 1123 DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n", 1124 smb2_opcode_name(opcode), 1125 (unsigned long long)mid)); 593 1126 594 1127 allowed_flags = SMB2_HDR_FLAG_CHAINED | … … 602 1135 } 603 1136 1137 /* 1138 * Check if the client provided a valid session id, 1139 * if so smbd_smb2_request_check_session() calls 1140 * set_current_user_info(). 1141 * 1142 * As some command don't require a valid session id 1143 * we defer the check of the session_status 1144 */ 604 1145 session_status = smbd_smb2_request_check_session(req); 605 1146 … … 637 1178 switch (opcode) { 638 1179 case SMB2_OP_NEGPROT: 639 return smbd_smb2_request_process_negprot(req); 1180 /* This call needs to be run as root */ 1181 change_to_root_user(); 1182 1183 { 1184 START_PROFILE(smb2_negprot); 1185 return_value = smbd_smb2_request_process_negprot(req); 1186 END_PROFILE(smb2_negprot); 1187 } 1188 break; 640 1189 641 1190 case SMB2_OP_SESSSETUP: 642 return smbd_smb2_request_process_sesssetup(req); 1191 /* This call needs to be run as root */ 1192 change_to_root_user(); 1193 1194 { 1195 START_PROFILE(smb2_sesssetup); 1196 return_value = smbd_smb2_request_process_sesssetup(req); 1197 END_PROFILE(smb2_sesssetup); 1198 } 1199 break; 643 1200 644 1201 case SMB2_OP_LOGOFF: 645 1202 if (!NT_STATUS_IS_OK(session_status)) { 646 return smbd_smb2_request_error(req, session_status); 647 } 648 return smbd_smb2_request_process_logoff(req); 1203 return_value = smbd_smb2_request_error(req, session_status); 1204 break; 1205 } 1206 1207 /* This call needs to be run as root */ 1208 change_to_root_user(); 1209 1210 { 1211 START_PROFILE(smb2_logoff); 1212 return_value = smbd_smb2_request_process_logoff(req); 1213 END_PROFILE(smb2_logoff); 1214 } 1215 break; 649 1216 650 1217 case SMB2_OP_TCON: 651 1218 if (!NT_STATUS_IS_OK(session_status)) { 652 return smbd_smb2_request_error(req, session_status); 653 } 654 status = smbd_smb2_request_check_session(req); 655 if (!NT_STATUS_IS_OK(status)) { 656 return smbd_smb2_request_error(req, status); 657 } 658 return smbd_smb2_request_process_tcon(req); 1219 return_value = smbd_smb2_request_error(req, session_status); 1220 break; 1221 } 1222 1223 /* 1224 * This call needs to be run as root. 1225 * 1226 * smbd_smb2_request_process_tcon() 1227 * calls make_connection_snum(), which will call 1228 * change_to_user(), when needed. 1229 */ 1230 change_to_root_user(); 1231 1232 { 1233 START_PROFILE(smb2_tcon); 1234 return_value = smbd_smb2_request_process_tcon(req); 1235 END_PROFILE(smb2_tcon); 1236 } 1237 break; 659 1238 660 1239 case SMB2_OP_TDIS: 661 1240 if (!NT_STATUS_IS_OK(session_status)) { 662 return smbd_smb2_request_error(req, session_status); 663 } 1241 return_value = smbd_smb2_request_error(req, session_status); 1242 break; 1243 } 1244 /* 1245 * This call needs to be run as user. 1246 * 1247 * smbd_smb2_request_check_tcon() 1248 * calls change_to_user() on success. 1249 */ 664 1250 status = smbd_smb2_request_check_tcon(req); 665 1251 if (!NT_STATUS_IS_OK(status)) { 666 return smbd_smb2_request_error(req, status); 667 } 668 return smbd_smb2_request_process_tdis(req); 1252 return_value = smbd_smb2_request_error(req, status); 1253 break; 1254 } 1255 /* This call needs to be run as root */ 1256 change_to_root_user(); 1257 1258 1259 { 1260 START_PROFILE(smb2_tdis); 1261 return_value = smbd_smb2_request_process_tdis(req); 1262 END_PROFILE(smb2_tdis); 1263 } 1264 break; 669 1265 670 1266 case SMB2_OP_CREATE: 671 1267 if (!NT_STATUS_IS_OK(session_status)) { 672 return smbd_smb2_request_error(req, session_status); 673 } 1268 return_value = smbd_smb2_request_error(req, session_status); 1269 break; 1270 } 1271 /* 1272 * This call needs to be run as user. 1273 * 1274 * smbd_smb2_request_check_tcon() 1275 * calls change_to_user() on success. 1276 */ 674 1277 status = smbd_smb2_request_check_tcon(req); 675 1278 if (!NT_STATUS_IS_OK(status)) { 676 return smbd_smb2_request_error(req, status); 677 } 678 return smbd_smb2_request_process_create(req); 1279 return_value = smbd_smb2_request_error(req, status); 1280 break; 1281 } 1282 1283 { 1284 START_PROFILE(smb2_create); 1285 return_value = smbd_smb2_request_process_create(req); 1286 END_PROFILE(smb2_create); 1287 } 1288 break; 679 1289 680 1290 case SMB2_OP_CLOSE: 681 1291 if (!NT_STATUS_IS_OK(session_status)) { 682 return smbd_smb2_request_error(req, session_status); 683 } 1292 return_value = smbd_smb2_request_error(req, session_status); 1293 break; 1294 } 1295 /* 1296 * This call needs to be run as user. 1297 * 1298 * smbd_smb2_request_check_tcon() 1299 * calls change_to_user() on success. 1300 */ 684 1301 status = smbd_smb2_request_check_tcon(req); 685 1302 if (!NT_STATUS_IS_OK(status)) { 686 return smbd_smb2_request_error(req, status); 687 } 688 return smbd_smb2_request_process_close(req); 1303 return_value = smbd_smb2_request_error(req, status); 1304 break; 1305 } 1306 1307 { 1308 START_PROFILE(smb2_close); 1309 return_value = smbd_smb2_request_process_close(req); 1310 END_PROFILE(smb2_close); 1311 } 1312 break; 689 1313 690 1314 case SMB2_OP_FLUSH: 691 1315 if (!NT_STATUS_IS_OK(session_status)) { 692 return smbd_smb2_request_error(req, session_status); 693 } 1316 return_value = smbd_smb2_request_error(req, session_status); 1317 break; 1318 } 1319 /* 1320 * This call needs to be run as user. 1321 * 1322 * smbd_smb2_request_check_tcon() 1323 * calls change_to_user() on success. 1324 */ 694 1325 status = smbd_smb2_request_check_tcon(req); 695 1326 if (!NT_STATUS_IS_OK(status)) { 696 return smbd_smb2_request_error(req, status); 697 } 698 return smbd_smb2_request_process_flush(req); 1327 return_value = smbd_smb2_request_error(req, status); 1328 break; 1329 } 1330 1331 { 1332 START_PROFILE(smb2_flush); 1333 return_value = smbd_smb2_request_process_flush(req); 1334 END_PROFILE(smb2_flush); 1335 } 1336 break; 699 1337 700 1338 case SMB2_OP_READ: 701 1339 if (!NT_STATUS_IS_OK(session_status)) { 702 return smbd_smb2_request_error(req, session_status); 703 } 1340 return_value = smbd_smb2_request_error(req, session_status); 1341 break; 1342 } 1343 /* 1344 * This call needs to be run as user. 1345 * 1346 * smbd_smb2_request_check_tcon() 1347 * calls change_to_user() on success. 1348 */ 704 1349 status = smbd_smb2_request_check_tcon(req); 705 1350 if (!NT_STATUS_IS_OK(status)) { 706 return smbd_smb2_request_error(req, status); 707 } 708 return smbd_smb2_request_process_read(req); 1351 return_value = smbd_smb2_request_error(req, status); 1352 break; 1353 } 1354 1355 { 1356 START_PROFILE(smb2_read); 1357 return_value = smbd_smb2_request_process_read(req); 1358 END_PROFILE(smb2_read); 1359 } 1360 break; 709 1361 710 1362 case SMB2_OP_WRITE: 711 1363 if (!NT_STATUS_IS_OK(session_status)) { 712 return smbd_smb2_request_error(req, session_status); 713 } 1364 return_value = smbd_smb2_request_error(req, session_status); 1365 break; 1366 } 1367 /* 1368 * This call needs to be run as user. 1369 * 1370 * smbd_smb2_request_check_tcon() 1371 * calls change_to_user() on success. 1372 */ 714 1373 status = smbd_smb2_request_check_tcon(req); 715 1374 if (!NT_STATUS_IS_OK(status)) { 716 return smbd_smb2_request_error(req, status); 717 } 718 return smbd_smb2_request_process_write(req); 1375 return_value = smbd_smb2_request_error(req, status); 1376 break; 1377 } 1378 1379 { 1380 START_PROFILE(smb2_write); 1381 return_value = smbd_smb2_request_process_write(req); 1382 END_PROFILE(smb2_write); 1383 } 1384 break; 719 1385 720 1386 case SMB2_OP_LOCK: 721 1387 if (!NT_STATUS_IS_OK(session_status)) { 722 return smbd_smb2_request_error(req, session_status); 723 } 1388 /* Too ugly to live ? JRA. */ 1389 if (NT_STATUS_EQUAL(session_status,NT_STATUS_USER_SESSION_DELETED)) { 1390 session_status = NT_STATUS_FILE_CLOSED; 1391 } 1392 return_value = smbd_smb2_request_error(req, session_status); 1393 break; 1394 } 1395 /* 1396 * This call needs to be run as user. 1397 * 1398 * smbd_smb2_request_check_tcon() 1399 * calls change_to_user() on success. 1400 */ 724 1401 status = smbd_smb2_request_check_tcon(req); 725 1402 if (!NT_STATUS_IS_OK(status)) { 726 return smbd_smb2_request_error(req, status); 727 } 728 return smbd_smb2_request_process_lock(req); 1403 /* Too ugly to live ? JRA. */ 1404 if (NT_STATUS_EQUAL(status,NT_STATUS_NETWORK_NAME_DELETED)) { 1405 status = NT_STATUS_FILE_CLOSED; 1406 } 1407 return_value = smbd_smb2_request_error(req, status); 1408 break; 1409 } 1410 1411 { 1412 START_PROFILE(smb2_lock); 1413 return_value = smbd_smb2_request_process_lock(req); 1414 END_PROFILE(smb2_lock); 1415 } 1416 break; 729 1417 730 1418 case SMB2_OP_IOCTL: 731 1419 if (!NT_STATUS_IS_OK(session_status)) { 732 return smbd_smb2_request_error(req, session_status); 733 } 1420 return_value = smbd_smb2_request_error(req, session_status); 1421 break; 1422 } 1423 /* 1424 * This call needs to be run as user. 1425 * 1426 * smbd_smb2_request_check_tcon() 1427 * calls change_to_user() on success. 1428 */ 734 1429 status = smbd_smb2_request_check_tcon(req); 735 1430 if (!NT_STATUS_IS_OK(status)) { 736 return smbd_smb2_request_error(req, status); 737 } 738 return smbd_smb2_request_process_ioctl(req); 1431 return_value = smbd_smb2_request_error(req, status); 1432 break; 1433 } 1434 1435 { 1436 START_PROFILE(smb2_ioctl); 1437 return_value = smbd_smb2_request_process_ioctl(req); 1438 END_PROFILE(smb2_ioctl); 1439 } 1440 break; 739 1441 740 1442 case SMB2_OP_CANCEL: 741 return smbd_smb2_request_process_cancel(req); 1443 /* 1444 * This call needs to be run as root 1445 * 1446 * That is what we also do in the SMB1 case. 1447 */ 1448 change_to_root_user(); 1449 1450 { 1451 START_PROFILE(smb2_cancel); 1452 return_value = smbd_smb2_request_process_cancel(req); 1453 END_PROFILE(smb2_cancel); 1454 } 1455 break; 742 1456 743 1457 case SMB2_OP_KEEPALIVE: 744 return smbd_smb2_request_process_keepalive(req); 1458 /* This call needs to be run as root */ 1459 change_to_root_user(); 1460 1461 { 1462 START_PROFILE(smb2_keepalive); 1463 return_value = smbd_smb2_request_process_keepalive(req); 1464 END_PROFILE(smb2_keepalive); 1465 } 1466 break; 745 1467 746 1468 case SMB2_OP_FIND: 747 1469 if (!NT_STATUS_IS_OK(session_status)) { 748 return smbd_smb2_request_error(req, session_status); 749 } 1470 return_value = smbd_smb2_request_error(req, session_status); 1471 break; 1472 } 1473 /* 1474 * This call needs to be run as user. 1475 * 1476 * smbd_smb2_request_check_tcon() 1477 * calls change_to_user() on success. 1478 */ 750 1479 status = smbd_smb2_request_check_tcon(req); 751 1480 if (!NT_STATUS_IS_OK(status)) { 752 return smbd_smb2_request_error(req, status); 753 } 754 return smbd_smb2_request_process_find(req); 1481 return_value = smbd_smb2_request_error(req, status); 1482 break; 1483 } 1484 1485 { 1486 START_PROFILE(smb2_find); 1487 return_value = smbd_smb2_request_process_find(req); 1488 END_PROFILE(smb2_find); 1489 } 1490 break; 755 1491 756 1492 case SMB2_OP_NOTIFY: 757 1493 if (!NT_STATUS_IS_OK(session_status)) { 758 return smbd_smb2_request_error(req, session_status); 759 } 1494 return_value = smbd_smb2_request_error(req, session_status); 1495 break; 1496 } 1497 /* 1498 * This call needs to be run as user. 1499 * 1500 * smbd_smb2_request_check_tcon() 1501 * calls change_to_user() on success. 1502 */ 760 1503 status = smbd_smb2_request_check_tcon(req); 761 1504 if (!NT_STATUS_IS_OK(status)) { 762 return smbd_smb2_request_error(req, status); 763 } 764 return smbd_smb2_request_process_notify(req); 1505 return_value = smbd_smb2_request_error(req, status); 1506 break; 1507 } 1508 1509 { 1510 START_PROFILE(smb2_notify); 1511 return_value = smbd_smb2_request_process_notify(req); 1512 END_PROFILE(smb2_notify); 1513 } 1514 break; 765 1515 766 1516 case SMB2_OP_GETINFO: 767 1517 if (!NT_STATUS_IS_OK(session_status)) { 768 return smbd_smb2_request_error(req, session_status); 769 } 1518 return_value = smbd_smb2_request_error(req, session_status); 1519 break; 1520 } 1521 /* 1522 * This call needs to be run as user. 1523 * 1524 * smbd_smb2_request_check_tcon() 1525 * calls change_to_user() on success. 1526 */ 770 1527 status = smbd_smb2_request_check_tcon(req); 771 1528 if (!NT_STATUS_IS_OK(status)) { 772 return smbd_smb2_request_error(req, status); 773 } 774 return smbd_smb2_request_process_getinfo(req); 1529 return_value = smbd_smb2_request_error(req, status); 1530 break; 1531 } 1532 1533 { 1534 START_PROFILE(smb2_getinfo); 1535 return_value = smbd_smb2_request_process_getinfo(req); 1536 END_PROFILE(smb2_getinfo); 1537 } 1538 break; 775 1539 776 1540 case SMB2_OP_SETINFO: 777 1541 if (!NT_STATUS_IS_OK(session_status)) { 778 return smbd_smb2_request_error(req, session_status); 779 } 1542 return_value = smbd_smb2_request_error(req, session_status); 1543 break; 1544 } 1545 /* 1546 * This call needs to be run as user. 1547 * 1548 * smbd_smb2_request_check_tcon() 1549 * calls change_to_user() on success. 1550 */ 780 1551 status = smbd_smb2_request_check_tcon(req); 781 1552 if (!NT_STATUS_IS_OK(status)) { 782 return smbd_smb2_request_error(req, status); 783 } 784 return smbd_smb2_request_process_setinfo(req); 1553 return_value = smbd_smb2_request_error(req, status); 1554 break; 1555 } 1556 1557 { 1558 START_PROFILE(smb2_setinfo); 1559 return_value = smbd_smb2_request_process_setinfo(req); 1560 END_PROFILE(smb2_setinfo); 1561 } 1562 break; 785 1563 786 1564 case SMB2_OP_BREAK: 787 1565 if (!NT_STATUS_IS_OK(session_status)) { 788 return smbd_smb2_request_error(req, session_status); 789 } 1566 return_value = smbd_smb2_request_error(req, session_status); 1567 break; 1568 } 1569 /* 1570 * This call needs to be run as user. 1571 * 1572 * smbd_smb2_request_check_tcon() 1573 * calls change_to_user() on success. 1574 */ 790 1575 status = smbd_smb2_request_check_tcon(req); 791 1576 if (!NT_STATUS_IS_OK(status)) { 792 return smbd_smb2_request_error(req, status); 793 } 794 return smbd_smb2_request_process_break(req); 795 } 796 797 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); 798 } 799 800 static void smbd_smb2_request_dispatch_compound(struct tevent_req *subreq); 801 static void smbd_smb2_request_writev_done(struct tevent_req *subreq); 1577 return_value = smbd_smb2_request_error(req, status); 1578 break; 1579 } 1580 1581 { 1582 START_PROFILE(smb2_break); 1583 return_value = smbd_smb2_request_process_break(req); 1584 END_PROFILE(smb2_break); 1585 } 1586 break; 1587 1588 default: 1589 return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); 1590 break; 1591 } 1592 return return_value; 1593 } 802 1594 803 1595 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req) 804 1596 { 805 1597 struct tevent_req *subreq; 1598 int i = req->current_idx; 806 1599 807 1600 req->subreq = NULL; 808 1601 1602 req->current_idx += 3; 1603 1604 if (req->current_idx < req->out.vector_count) { 1605 /* 1606 * We must process the remaining compound 1607 * SMB2 requests before any new incoming SMB2 1608 * requests. This is because incoming SMB2 1609 * requests may include a cancel for a 1610 * compound request we haven't processed 1611 * yet. 1612 */ 1613 struct tevent_immediate *im = tevent_create_immediate(req); 1614 if (!im) { 1615 return NT_STATUS_NO_MEMORY; 1616 } 1617 tevent_schedule_immediate(im, 1618 req->sconn->smb2.event_ctx, 1619 smbd_smb2_request_dispatch_immediate, 1620 req); 1621 return NT_STATUS_OK; 1622 } 1623 809 1624 smb2_setup_nbt_length(req->out.vector, req->out.vector_count); 810 1625 1626 /* Set credit for this operation (zero credits if this 1627 is a final reply for an async operation). */ 1628 smb2_set_operation_credit(req->sconn, 1629 &req->in.vector[i], 1630 &req->out.vector[i]); 1631 811 1632 if (req->do_signing) { 812 int i = req->current_idx;813 1633 NTSTATUS status; 814 1634 status = smb2_signing_sign_pdu(req->session->session_key, … … 819 1639 } 820 1640 821 req->current_idx += 3; 822 823 if (req->current_idx < req->out.vector_count) { 824 struct timeval zero = timeval_zero(); 825 subreq = tevent_wakeup_send(req, 826 req->sconn->smb2.event_ctx, 827 zero); 828 if (subreq == NULL) { 829 return NT_STATUS_NO_MEMORY; 830 } 831 tevent_req_set_callback(subreq, 832 smbd_smb2_request_dispatch_compound, 833 req); 834 835 return NT_STATUS_OK; 1641 if (DEBUGLEVEL >= 10) { 1642 dbgtext("smbd_smb2_request_reply: sending...\n"); 1643 print_req_vectors(req); 1644 } 1645 1646 /* I am a sick, sick man... :-). Sendfile hack ... JRA. */ 1647 if (req->out.vector_count == 4 && 1648 req->out.vector[3].iov_base == NULL && 1649 req->out.vector[3].iov_len != 0) { 1650 /* Dynamic part is NULL. Chop it off, 1651 We're going to send it via sendfile. */ 1652 req->out.vector_count -= 1; 836 1653 } 837 1654 … … 846 1663 } 847 1664 tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req); 1665 /* 1666 * We're done with this request - 1667 * move it off the "being processed" queue. 1668 */ 1669 DLIST_REMOVE(req->sconn->smb2.requests, req); 848 1670 849 1671 return NT_STATUS_OK; 850 1672 } 851 1673 852 static void smbd_smb2_request_dispatch_compound(struct tevent_req *subreq) 853 { 854 struct smbd_smb2_request *req = tevent_req_callback_data(subreq, 1674 void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx, 1675 struct tevent_immediate *im, 1676 void *private_data) 1677 { 1678 struct smbd_smb2_request *req = talloc_get_type_abort(private_data, 855 1679 struct smbd_smb2_request); 856 1680 struct smbd_server_connection *sconn = req->sconn; 857 1681 NTSTATUS status; 858 1682 859 tevent_wakeup_recv(subreq); 860 TALLOC_FREE(subreq); 861 862 DEBUG(10,("smbd_smb2_request_dispatch_compound: idx[%d] of %d vectors\n", 863 req->current_idx, req->in.vector_count)); 1683 TALLOC_FREE(im); 1684 1685 if (DEBUGLEVEL >= 10) { 1686 DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n", 1687 req->current_idx, req->in.vector_count)); 1688 print_req_vectors(req); 1689 } 864 1690 865 1691 status = smbd_smb2_request_dispatch(req); … … 883 1709 if (ret == -1) { 884 1710 NTSTATUS status = map_nt_error_from_unix(sys_errno); 1711 DEBUG(2,("smbd_smb2_request_writev_done: client write error %s\n", 1712 nt_errstr(status))); 885 1713 smbd_server_connection_terminate(sconn, nt_errstr(status)); 886 1714 return; 887 1715 } 888 }889 890 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,891 NTSTATUS status,892 DATA_BLOB *info,893 const char *location)894 {895 uint8_t *outhdr;896 uint8_t *outbody;897 int i = req->current_idx;898 899 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",900 i, nt_errstr(status), info ? " +info" : "",901 location));902 903 outhdr = (uint8_t *)req->out.vector[i].iov_base;904 905 SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));906 907 outbody = outhdr + SMB2_HDR_BODY;908 909 req->out.vector[i+1].iov_base = (void *)outbody;910 req->out.vector[i+1].iov_len = 8;911 912 if (info) {913 SIVAL(outbody, 0x04, info->length);914 req->out.vector[i+2].iov_base = (void *)info->data;915 req->out.vector[i+2].iov_len = info->length;916 } else {917 req->out.vector[i+2].iov_base = NULL;918 req->out.vector[i+2].iov_len = 0;919 }920 921 /*922 * if a request fails, all other remaining923 * compounded requests should fail too924 */925 req->next_status = NT_STATUS_INVALID_PARAMETER;926 927 return smbd_smb2_request_reply(req);928 1716 } 929 1717 … … 934 1722 { 935 1723 uint8_t *outhdr; 936 uint8_t *outdyn;937 1724 int i = req->current_idx; 938 1725 uint32_t next_command_ofs; … … 954 1741 955 1742 outhdr = (uint8_t *)req->out.vector[i].iov_base; 956 /* the fallback dynamic buffer */957 outdyn = outhdr + SMB2_HDR_BODY + 8;958 1743 959 1744 next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND); … … 1010 1795 1011 1796 new_size = old_size + pad_size; 1012 new_dyn = talloc_ array(req->out.vector,1797 new_dyn = talloc_zero_array(req->out.vector, 1013 1798 uint8_t, new_size); 1014 1799 if (new_dyn == NULL) { … … 1022 1807 req->out.vector[i+2].iov_base = (void *)new_dyn; 1023 1808 req->out.vector[i+2].iov_len = new_size; 1024 1025 TALLOC_FREE(old_dyn);1026 1809 } 1027 1810 next_command_ofs += pad_size; … … 1032 1815 return smbd_smb2_request_reply(req); 1033 1816 } 1817 1818 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req, 1819 NTSTATUS status, 1820 DATA_BLOB *info, 1821 const char *location) 1822 { 1823 DATA_BLOB body; 1824 int i = req->current_idx; 1825 uint8_t *outhdr = (uint8_t *)req->out.vector[i].iov_base; 1826 1827 DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n", 1828 i, nt_errstr(status), info ? " +info" : "", 1829 location)); 1830 1831 body.data = outhdr + SMB2_HDR_BODY; 1832 body.length = 8; 1833 SSVAL(body.data, 0, 9); 1834 1835 if (info) { 1836 SIVAL(body.data, 0x04, info->length); 1837 } else { 1838 /* Allocated size of req->out.vector[i].iov_base 1839 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for 1840 * 1 byte without having to do an alloc. 1841 */ 1842 info = talloc_zero_array(req->out.vector, 1843 DATA_BLOB, 1844 1); 1845 if (!info) { 1846 return NT_STATUS_NO_MEMORY; 1847 } 1848 info->data = ((uint8_t *)outhdr) + 1849 OUTVEC_ALLOC_SIZE - 1; 1850 info->length = 1; 1851 SCVAL(info->data, 0, 0); 1852 } 1853 1854 /* 1855 * if a request fails, all other remaining 1856 * compounded requests should fail too 1857 */ 1858 req->next_status = NT_STATUS_INVALID_PARAMETER; 1859 1860 return smbd_smb2_request_done_ex(req, status, body, info, __location__); 1861 } 1862 1034 1863 1035 1864 struct smbd_smb2_send_oplock_break_state { … … 1493 2322 { 1494 2323 NTSTATUS status; 1495 struct smbd_smb2_request *req ;2324 struct smbd_smb2_request *req = NULL; 1496 2325 struct tevent_req *subreq; 1497 2326 … … 1530 2359 } 1531 2360 tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn); 2361 2362 sconn->num_requests++; 1532 2363 } 1533 2364 … … 1542 2373 TALLOC_FREE(subreq); 1543 2374 if (!NT_STATUS_IS_OK(status)) { 2375 DEBUG(2,("smbd_smb2_request_incoming: client read error %s\n", 2376 nt_errstr(status))); 1544 2377 smbd_server_connection_terminate(sconn, nt_errstr(status)); 1545 2378 return; … … 1584 2417 } 1585 2418 tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn); 1586 } 2419 2420 sconn->num_requests++; 2421 2422 /* The timeout_processing function isn't run nearly 2423 often enough to implement 'max log size' without 2424 overrunning the size of the file by many megabytes. 2425 This is especially true if we are running at debug 2426 level 10. Checking every 50 SMB2s is a nice 2427 tradeoff of performance vs log file size overrun. */ 2428 2429 if ((sconn->num_requests % 50) == 0 && 2430 need_to_check_log_size()) { 2431 change_to_root_user(); 2432 check_log_size(); 2433 } 2434 }
Note:
See TracChangeset
for help on using the changeset viewer.