diff options
| -rw-r--r-- | fs/cifs/cifsencrypt.c | 53 | ||||
| -rw-r--r-- | fs/cifs/smb2ops.c | 8 | ||||
| -rw-r--r-- | fs/cifs/smb2pdu.c | 84 |
3 files changed, 126 insertions, 19 deletions
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index aa0dc2573374..afa09fce8151 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
| @@ -444,6 +444,48 @@ find_domain_name(struct cifs_ses *ses, const struct nls_table *nls_cp) | |||
| 444 | return 0; | 444 | return 0; |
| 445 | } | 445 | } |
| 446 | 446 | ||
| 447 | /* Server has provided av pairs/target info in the type 2 challenge | ||
| 448 | * packet and we have plucked it and stored within smb session. | ||
| 449 | * We parse that blob here to find the server given timestamp | ||
| 450 | * as part of ntlmv2 authentication (or local current time as | ||
| 451 | * default in case of failure) | ||
| 452 | */ | ||
| 453 | static __le64 | ||
| 454 | find_timestamp(struct cifs_ses *ses) | ||
| 455 | { | ||
| 456 | unsigned int attrsize; | ||
| 457 | unsigned int type; | ||
| 458 | unsigned int onesize = sizeof(struct ntlmssp2_name); | ||
| 459 | unsigned char *blobptr; | ||
| 460 | unsigned char *blobend; | ||
| 461 | struct ntlmssp2_name *attrptr; | ||
| 462 | |||
| 463 | if (!ses->auth_key.len || !ses->auth_key.response) | ||
| 464 | return 0; | ||
| 465 | |||
| 466 | blobptr = ses->auth_key.response; | ||
| 467 | blobend = blobptr + ses->auth_key.len; | ||
| 468 | |||
| 469 | while (blobptr + onesize < blobend) { | ||
| 470 | attrptr = (struct ntlmssp2_name *) blobptr; | ||
| 471 | type = le16_to_cpu(attrptr->type); | ||
| 472 | if (type == NTLMSSP_AV_EOL) | ||
| 473 | break; | ||
| 474 | blobptr += 2; /* advance attr type */ | ||
| 475 | attrsize = le16_to_cpu(attrptr->length); | ||
| 476 | blobptr += 2; /* advance attr size */ | ||
| 477 | if (blobptr + attrsize > blobend) | ||
| 478 | break; | ||
| 479 | if (type == NTLMSSP_AV_TIMESTAMP) { | ||
| 480 | if (attrsize == sizeof(u64)) | ||
| 481 | return *((__le64 *)blobptr); | ||
| 482 | } | ||
| 483 | blobptr += attrsize; /* advance attr value */ | ||
| 484 | } | ||
| 485 | |||
| 486 | return cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | ||
| 487 | } | ||
| 488 | |||
| 447 | static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, | 489 | static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, |
| 448 | const struct nls_table *nls_cp) | 490 | const struct nls_table *nls_cp) |
| 449 | { | 491 | { |
| @@ -641,6 +683,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) | |||
| 641 | struct ntlmv2_resp *ntlmv2; | 683 | struct ntlmv2_resp *ntlmv2; |
| 642 | char ntlmv2_hash[16]; | 684 | char ntlmv2_hash[16]; |
| 643 | unsigned char *tiblob = NULL; /* target info blob */ | 685 | unsigned char *tiblob = NULL; /* target info blob */ |
| 686 | __le64 rsp_timestamp; | ||
| 644 | 687 | ||
| 645 | if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) { | 688 | if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) { |
| 646 | if (!ses->domainName) { | 689 | if (!ses->domainName) { |
| @@ -659,6 +702,12 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) | |||
| 659 | } | 702 | } |
| 660 | } | 703 | } |
| 661 | 704 | ||
| 705 | /* Must be within 5 minutes of the server (or in range +/-2h | ||
| 706 | * in case of Mac OS X), so simply carry over server timestamp | ||
| 707 | * (as Windows 7 does) | ||
| 708 | */ | ||
| 709 | rsp_timestamp = find_timestamp(ses); | ||
| 710 | |||
| 662 | baselen = CIFS_SESS_KEY_SIZE + sizeof(struct ntlmv2_resp); | 711 | baselen = CIFS_SESS_KEY_SIZE + sizeof(struct ntlmv2_resp); |
| 663 | tilen = ses->auth_key.len; | 712 | tilen = ses->auth_key.len; |
| 664 | tiblob = ses->auth_key.response; | 713 | tiblob = ses->auth_key.response; |
| @@ -675,8 +724,8 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) | |||
| 675 | (ses->auth_key.response + CIFS_SESS_KEY_SIZE); | 724 | (ses->auth_key.response + CIFS_SESS_KEY_SIZE); |
| 676 | ntlmv2->blob_signature = cpu_to_le32(0x00000101); | 725 | ntlmv2->blob_signature = cpu_to_le32(0x00000101); |
| 677 | ntlmv2->reserved = 0; | 726 | ntlmv2->reserved = 0; |
| 678 | /* Must be within 5 minutes of the server */ | 727 | ntlmv2->time = rsp_timestamp; |
| 679 | ntlmv2->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | 728 | |
| 680 | get_random_bytes(&ntlmv2->client_chal, sizeof(ntlmv2->client_chal)); | 729 | get_random_bytes(&ntlmv2->client_chal, sizeof(ntlmv2->client_chal)); |
| 681 | ntlmv2->reserved2 = 0; | 730 | ntlmv2->reserved2 = 0; |
| 682 | 731 | ||
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index df91bcf56d67..18da19f4f811 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c | |||
| @@ -50,9 +50,13 @@ change_conf(struct TCP_Server_Info *server) | |||
| 50 | break; | 50 | break; |
| 51 | default: | 51 | default: |
| 52 | server->echoes = true; | 52 | server->echoes = true; |
| 53 | server->oplocks = true; | 53 | if (enable_oplocks) { |
| 54 | server->oplocks = true; | ||
| 55 | server->oplock_credits = 1; | ||
| 56 | } else | ||
| 57 | server->oplocks = false; | ||
| 58 | |||
| 54 | server->echo_credits = 1; | 59 | server->echo_credits = 1; |
| 55 | server->oplock_credits = 1; | ||
| 56 | } | 60 | } |
| 57 | server->credits -= server->echo_credits + server->oplock_credits; | 61 | server->credits -= server->echo_credits + server->oplock_credits; |
| 58 | return 0; | 62 | return 0; |
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 070fb2ad85ce..ce83e2edbe0a 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
| @@ -46,6 +46,7 @@ | |||
| 46 | #include "smb2status.h" | 46 | #include "smb2status.h" |
| 47 | #include "smb2glob.h" | 47 | #include "smb2glob.h" |
| 48 | #include "cifspdu.h" | 48 | #include "cifspdu.h" |
| 49 | #include "cifs_spnego.h" | ||
| 49 | 50 | ||
| 50 | /* | 51 | /* |
| 51 | * The following table defines the expected "StructureSize" of SMB2 requests | 52 | * The following table defines the expected "StructureSize" of SMB2 requests |
| @@ -486,19 +487,15 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) | |||
| 486 | cifs_dbg(FYI, "missing security blob on negprot\n"); | 487 | cifs_dbg(FYI, "missing security blob on negprot\n"); |
| 487 | 488 | ||
| 488 | rc = cifs_enable_signing(server, ses->sign); | 489 | rc = cifs_enable_signing(server, ses->sign); |
| 489 | #ifdef CONFIG_SMB2_ASN1 /* BB REMOVEME when updated asn1.c ready */ | ||
| 490 | if (rc) | 490 | if (rc) |
| 491 | goto neg_exit; | 491 | goto neg_exit; |
| 492 | if (blob_length) | 492 | if (blob_length) { |
| 493 | rc = decode_negTokenInit(security_blob, blob_length, server); | 493 | rc = decode_negTokenInit(security_blob, blob_length, server); |
| 494 | if (rc == 1) | 494 | if (rc == 1) |
| 495 | rc = 0; | 495 | rc = 0; |
| 496 | else if (rc == 0) { | 496 | else if (rc == 0) |
| 497 | rc = -EIO; | 497 | rc = -EIO; |
| 498 | goto neg_exit; | ||
| 499 | } | 498 | } |
| 500 | #endif | ||
| 501 | |||
| 502 | neg_exit: | 499 | neg_exit: |
| 503 | free_rsp_buf(resp_buftype, rsp); | 500 | free_rsp_buf(resp_buftype, rsp); |
| 504 | return rc; | 501 | return rc; |
| @@ -592,7 +589,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, | |||
| 592 | __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ | 589 | __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ |
| 593 | struct TCP_Server_Info *server = ses->server; | 590 | struct TCP_Server_Info *server = ses->server; |
| 594 | u16 blob_length = 0; | 591 | u16 blob_length = 0; |
| 595 | char *security_blob; | 592 | struct key *spnego_key = NULL; |
| 593 | char *security_blob = NULL; | ||
| 596 | char *ntlmssp_blob = NULL; | 594 | char *ntlmssp_blob = NULL; |
| 597 | bool use_spnego = false; /* else use raw ntlmssp */ | 595 | bool use_spnego = false; /* else use raw ntlmssp */ |
| 598 | 596 | ||
| @@ -620,7 +618,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, | |||
| 620 | ses->ntlmssp->sesskey_per_smbsess = true; | 618 | ses->ntlmssp->sesskey_per_smbsess = true; |
| 621 | 619 | ||
| 622 | /* FIXME: allow for other auth types besides NTLMSSP (e.g. krb5) */ | 620 | /* FIXME: allow for other auth types besides NTLMSSP (e.g. krb5) */ |
| 623 | ses->sectype = RawNTLMSSP; | 621 | if (ses->sectype != Kerberos && ses->sectype != RawNTLMSSP) |
| 622 | ses->sectype = RawNTLMSSP; | ||
| 624 | 623 | ||
| 625 | ssetup_ntlmssp_authenticate: | 624 | ssetup_ntlmssp_authenticate: |
| 626 | if (phase == NtLmChallenge) | 625 | if (phase == NtLmChallenge) |
| @@ -649,7 +648,48 @@ ssetup_ntlmssp_authenticate: | |||
| 649 | iov[0].iov_base = (char *)req; | 648 | iov[0].iov_base = (char *)req; |
| 650 | /* 4 for rfc1002 length field and 1 for pad */ | 649 | /* 4 for rfc1002 length field and 1 for pad */ |
| 651 | iov[0].iov_len = get_rfc1002_length(req) + 4 - 1; | 650 | iov[0].iov_len = get_rfc1002_length(req) + 4 - 1; |
| 652 | if (phase == NtLmNegotiate) { | 651 | |
| 652 | if (ses->sectype == Kerberos) { | ||
| 653 | #ifdef CONFIG_CIFS_UPCALL | ||
| 654 | struct cifs_spnego_msg *msg; | ||
| 655 | |||
| 656 | spnego_key = cifs_get_spnego_key(ses); | ||
| 657 | if (IS_ERR(spnego_key)) { | ||
| 658 | rc = PTR_ERR(spnego_key); | ||
| 659 | spnego_key = NULL; | ||
| 660 | goto ssetup_exit; | ||
| 661 | } | ||
| 662 | |||
| 663 | msg = spnego_key->payload.data; | ||
| 664 | /* | ||
| 665 | * check version field to make sure that cifs.upcall is | ||
| 666 | * sending us a response in an expected form | ||
| 667 | */ | ||
| 668 | if (msg->version != CIFS_SPNEGO_UPCALL_VERSION) { | ||
| 669 | cifs_dbg(VFS, | ||
| 670 | "bad cifs.upcall version. Expected %d got %d", | ||
| 671 | CIFS_SPNEGO_UPCALL_VERSION, msg->version); | ||
| 672 | rc = -EKEYREJECTED; | ||
| 673 | goto ssetup_exit; | ||
| 674 | } | ||
| 675 | ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len, | ||
| 676 | GFP_KERNEL); | ||
| 677 | if (!ses->auth_key.response) { | ||
| 678 | cifs_dbg(VFS, | ||
| 679 | "Kerberos can't allocate (%u bytes) memory", | ||
| 680 | msg->sesskey_len); | ||
| 681 | rc = -ENOMEM; | ||
| 682 | goto ssetup_exit; | ||
| 683 | } | ||
| 684 | ses->auth_key.len = msg->sesskey_len; | ||
| 685 | blob_length = msg->secblob_len; | ||
| 686 | iov[1].iov_base = msg->data + msg->sesskey_len; | ||
| 687 | iov[1].iov_len = blob_length; | ||
| 688 | #else | ||
| 689 | rc = -EOPNOTSUPP; | ||
| 690 | goto ssetup_exit; | ||
| 691 | #endif /* CONFIG_CIFS_UPCALL */ | ||
| 692 | } else if (phase == NtLmNegotiate) { /* if not krb5 must be ntlmssp */ | ||
| 653 | ntlmssp_blob = kmalloc(sizeof(struct _NEGOTIATE_MESSAGE), | 693 | ntlmssp_blob = kmalloc(sizeof(struct _NEGOTIATE_MESSAGE), |
| 654 | GFP_KERNEL); | 694 | GFP_KERNEL); |
| 655 | if (ntlmssp_blob == NULL) { | 695 | if (ntlmssp_blob == NULL) { |
| @@ -672,6 +712,8 @@ ssetup_ntlmssp_authenticate: | |||
| 672 | /* with raw NTLMSSP we don't encapsulate in SPNEGO */ | 712 | /* with raw NTLMSSP we don't encapsulate in SPNEGO */ |
| 673 | security_blob = ntlmssp_blob; | 713 | security_blob = ntlmssp_blob; |
| 674 | } | 714 | } |
| 715 | iov[1].iov_base = security_blob; | ||
| 716 | iov[1].iov_len = blob_length; | ||
| 675 | } else if (phase == NtLmAuthenticate) { | 717 | } else if (phase == NtLmAuthenticate) { |
| 676 | req->hdr.SessionId = ses->Suid; | 718 | req->hdr.SessionId = ses->Suid; |
| 677 | ntlmssp_blob = kzalloc(sizeof(struct _NEGOTIATE_MESSAGE) + 500, | 719 | ntlmssp_blob = kzalloc(sizeof(struct _NEGOTIATE_MESSAGE) + 500, |
| @@ -699,6 +741,8 @@ ssetup_ntlmssp_authenticate: | |||
| 699 | } else { | 741 | } else { |
| 700 | security_blob = ntlmssp_blob; | 742 | security_blob = ntlmssp_blob; |
| 701 | } | 743 | } |
| 744 | iov[1].iov_base = security_blob; | ||
| 745 | iov[1].iov_len = blob_length; | ||
| 702 | } else { | 746 | } else { |
| 703 | cifs_dbg(VFS, "illegal ntlmssp phase\n"); | 747 | cifs_dbg(VFS, "illegal ntlmssp phase\n"); |
| 704 | rc = -EIO; | 748 | rc = -EIO; |
| @@ -710,8 +754,6 @@ ssetup_ntlmssp_authenticate: | |||
| 710 | cpu_to_le16(sizeof(struct smb2_sess_setup_req) - | 754 | cpu_to_le16(sizeof(struct smb2_sess_setup_req) - |
| 711 | 1 /* pad */ - 4 /* rfc1001 len */); | 755 | 1 /* pad */ - 4 /* rfc1001 len */); |
| 712 | req->SecurityBufferLength = cpu_to_le16(blob_length); | 756 | req->SecurityBufferLength = cpu_to_le16(blob_length); |
| 713 | iov[1].iov_base = security_blob; | ||
| 714 | iov[1].iov_len = blob_length; | ||
| 715 | 757 | ||
| 716 | inc_rfc1001_len(req, blob_length - 1 /* pad */); | 758 | inc_rfc1001_len(req, blob_length - 1 /* pad */); |
| 717 | 759 | ||
| @@ -722,6 +764,7 @@ ssetup_ntlmssp_authenticate: | |||
| 722 | 764 | ||
| 723 | kfree(security_blob); | 765 | kfree(security_blob); |
| 724 | rsp = (struct smb2_sess_setup_rsp *)iov[0].iov_base; | 766 | rsp = (struct smb2_sess_setup_rsp *)iov[0].iov_base; |
| 767 | ses->Suid = rsp->hdr.SessionId; | ||
| 725 | if (resp_buftype != CIFS_NO_BUFFER && | 768 | if (resp_buftype != CIFS_NO_BUFFER && |
| 726 | rsp->hdr.Status == STATUS_MORE_PROCESSING_REQUIRED) { | 769 | rsp->hdr.Status == STATUS_MORE_PROCESSING_REQUIRED) { |
| 727 | if (phase != NtLmNegotiate) { | 770 | if (phase != NtLmNegotiate) { |
| @@ -739,7 +782,6 @@ ssetup_ntlmssp_authenticate: | |||
| 739 | /* NTLMSSP Negotiate sent now processing challenge (response) */ | 782 | /* NTLMSSP Negotiate sent now processing challenge (response) */ |
| 740 | phase = NtLmChallenge; /* process ntlmssp challenge */ | 783 | phase = NtLmChallenge; /* process ntlmssp challenge */ |
| 741 | rc = 0; /* MORE_PROCESSING is not an error here but expected */ | 784 | rc = 0; /* MORE_PROCESSING is not an error here but expected */ |
| 742 | ses->Suid = rsp->hdr.SessionId; | ||
| 743 | rc = decode_ntlmssp_challenge(rsp->Buffer, | 785 | rc = decode_ntlmssp_challenge(rsp->Buffer, |
| 744 | le16_to_cpu(rsp->SecurityBufferLength), ses); | 786 | le16_to_cpu(rsp->SecurityBufferLength), ses); |
| 745 | } | 787 | } |
| @@ -796,6 +838,10 @@ keygen_exit: | |||
| 796 | kfree(ses->auth_key.response); | 838 | kfree(ses->auth_key.response); |
| 797 | ses->auth_key.response = NULL; | 839 | ses->auth_key.response = NULL; |
| 798 | } | 840 | } |
| 841 | if (spnego_key) { | ||
| 842 | key_invalidate(spnego_key); | ||
| 843 | key_put(spnego_key); | ||
| 844 | } | ||
| 799 | kfree(ses->ntlmssp); | 845 | kfree(ses->ntlmssp); |
| 800 | 846 | ||
| 801 | return rc; | 847 | return rc; |
| @@ -876,6 +922,12 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, | |||
| 876 | if (tcon && tcon->bad_network_name) | 922 | if (tcon && tcon->bad_network_name) |
| 877 | return -ENOENT; | 923 | return -ENOENT; |
| 878 | 924 | ||
| 925 | if ((tcon->seal) && | ||
| 926 | ((ses->server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) == 0)) { | ||
| 927 | cifs_dbg(VFS, "encryption requested but no server support"); | ||
| 928 | return -EOPNOTSUPP; | ||
| 929 | } | ||
| 930 | |||
| 879 | unc_path = kmalloc(MAX_SHARENAME_LENGTH * 2, GFP_KERNEL); | 931 | unc_path = kmalloc(MAX_SHARENAME_LENGTH * 2, GFP_KERNEL); |
| 880 | if (unc_path == NULL) | 932 | if (unc_path == NULL) |
| 881 | return -ENOMEM; | 933 | return -ENOMEM; |
| @@ -955,6 +1007,8 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, | |||
| 955 | ((tcon->share_flags & SHI1005_FLAGS_DFS) == 0)) | 1007 | ((tcon->share_flags & SHI1005_FLAGS_DFS) == 0)) |
| 956 | cifs_dbg(VFS, "DFS capability contradicts DFS flag\n"); | 1008 | cifs_dbg(VFS, "DFS capability contradicts DFS flag\n"); |
| 957 | init_copy_chunk_defaults(tcon); | 1009 | init_copy_chunk_defaults(tcon); |
| 1010 | if (tcon->share_flags & SHI1005_FLAGS_ENCRYPT_DATA) | ||
| 1011 | cifs_dbg(VFS, "Encrypted shares not supported"); | ||
| 958 | if (tcon->ses->server->ops->validate_negotiate) | 1012 | if (tcon->ses->server->ops->validate_negotiate) |
| 959 | rc = tcon->ses->server->ops->validate_negotiate(xid, tcon); | 1013 | rc = tcon->ses->server->ops->validate_negotiate(xid, tcon); |
| 960 | tcon_exit: | 1014 | tcon_exit: |
