| @@ -46,6 +46,7 @@ · 45 unmodified lines |
| 46 | 46 | #include "smb2status.h" |
| 47 | 47 | #include "smb2glob.h" |
| 48 | 48 | #include "cifspdu.h" |
| 49 | +#include "cifs_spnego.h" |
| 49 | 50 | |
| 50 | 51 | /* |
| 51 | 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) · 434 unmodified lines |
| 486 | 487 | cifs_dbg(FYI, "missing security blob on negprot\n"); |
| 487 | 488 | |
| 488 | 489 | rc = cifs_enable_signing(server, ses->sign); |
| 489 | | −#ifdef CONFIG_SMB2_ASN1 /* BB REMOVEME when updated asn1.c ready */ |
| 490 | 490 | if (rc) |
| 491 | 491 | goto neg_exit; |
| 492 | | − if (blob_length) |
| 492 | + if (blob_length) { |
| 493 | 493 | rc = decode_negTokenInit(security_blob, blob_length, server); |
| 494 | | − if (rc == 1) |
| 495 | | − rc = 0; |
| 496 | | − else if (rc == 0) { |
| 497 | | − rc = -EIO; |
| 498 | | − goto neg_exit; |
| 494 | + if (rc == 1) |
| 495 | + rc = 0; |
| 496 | + else if (rc == 0) |
| 497 | + rc = -EIO; |
| 499 | 498 | } |
| 500 | | −#endif |
| 501 | | − |
| 502 | 499 | neg_exit: |
| 503 | 500 | free_rsp_buf(resp_buftype, rsp); |
| 504 | 501 | return rc; |
| @@ -592,7 +589,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, · 87 unmodified lines |
| 592 | 589 | __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ |
| 593 | 590 | struct TCP_Server_Info *server = ses->server; |
| 594 | 591 | u16 blob_length = 0; |
| 595 | | − char *security_blob; |
| 592 | + struct key *spnego_key = NULL; |
| 593 | + char *security_blob = NULL; |
| 596 | 594 | char *ntlmssp_blob = NULL; |
| 597 | 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, · 21 unmodified lines |
| 620 | 618 | ses->ntlmssp->sesskey_per_smbsess = true; |
| 621 | 619 | |
| 622 | 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 | 624 | ssetup_ntlmssp_authenticate: |
| 626 | 625 | if (phase == NtLmChallenge) |
| @@ -649,7 +648,48 @@ ssetup_ntlmssp_authenticate: · 22 unmodified lines |
| 649 | 648 | iov[0].iov_base = (char *)req; |
| 650 | 649 | /* 4 for rfc1002 length field and 1 for pad */ |
| 651 | 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 | 693 | ntlmssp_blob = kmalloc(sizeof(struct _NEGOTIATE_MESSAGE), |
| 654 | 694 | GFP_KERNEL); |
| 655 | 695 | if (ntlmssp_blob == NULL) { |
| @@ -672,6 +712,8 @@ ssetup_ntlmssp_authenticate: · 16 unmodified lines |
| 672 | 712 | /* with raw NTLMSSP we don't encapsulate in SPNEGO */ |
| 673 | 713 | security_blob = ntlmssp_blob; |
| 674 | 714 | } |
| 715 | + iov[1].iov_base = security_blob; |
| 716 | + iov[1].iov_len = blob_length; |
| 675 | 717 | } else if (phase == NtLmAuthenticate) { |
| 676 | 718 | req->hdr.SessionId = ses->Suid; |
| 677 | 719 | ntlmssp_blob = kzalloc(sizeof(struct _NEGOTIATE_MESSAGE) + 500, |
| @@ -699,6 +741,8 @@ ssetup_ntlmssp_authenticate: · 21 unmodified lines |
| 699 | 741 | } else { |
| 700 | 742 | security_blob = ntlmssp_blob; |
| 701 | 743 | } |
| 744 | + iov[1].iov_base = security_blob; |
| 745 | + iov[1].iov_len = blob_length; |
| 702 | 746 | } else { |
| 703 | 747 | cifs_dbg(VFS, "illegal ntlmssp phase\n"); |
| 704 | 748 | rc = -EIO; |
| @@ -710,8 +754,6 @@ ssetup_ntlmssp_authenticate: · 5 unmodified lines |
| 710 | 754 | cpu_to_le16(sizeof(struct smb2_sess_setup_req) - |
| 711 | 755 | 1 /* pad */ - 4 /* rfc1001 len */); |
| 712 | 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 | 758 | inc_rfc1001_len(req, blob_length - 1 /* pad */); |
| 717 | 759 | |
| @@ -722,6 +764,7 @@ ssetup_ntlmssp_authenticate: · 4 unmodified lines |
| 722 | 764 | |
| 723 | 765 | kfree(security_blob); |
| 724 | 766 | rsp = (struct smb2_sess_setup_rsp *)iov[0].iov_base; |
| 767 | + ses->Suid = rsp->hdr.SessionId; |
| 725 | 768 | if (resp_buftype != CIFS_NO_BUFFER && |
| 726 | 769 | rsp->hdr.Status == STATUS_MORE_PROCESSING_REQUIRED) { |
| 727 | 770 | if (phase != NtLmNegotiate) { |
| @@ -739,7 +782,6 @@ ssetup_ntlmssp_authenticate: · 11 unmodified lines |
| 739 | 782 | /* NTLMSSP Negotiate sent now processing challenge (response) */ |
| 740 | 783 | phase = NtLmChallenge; /* process ntlmssp challenge */ |
| 741 | 784 | rc = 0; /* MORE_PROCESSING is not an error here but expected */ |
| 742 | | − ses->Suid = rsp->hdr.SessionId; |
| 743 | 785 | rc = decode_ntlmssp_challenge(rsp->Buffer, |
| 744 | 786 | le16_to_cpu(rsp->SecurityBufferLength), ses); |
| 745 | 787 | } |
| @@ -796,6 +838,10 @@ keygen_exit: · 50 unmodified lines |
| 796 | 838 | kfree(ses->auth_key.response); |
| 797 | 839 | ses->auth_key.response = NULL; |
| 798 | 840 | } |
| 841 | + if (spnego_key) { |
| 842 | + key_invalidate(spnego_key); |
| 843 | + key_put(spnego_key); |
| 844 | + } |
| 799 | 845 | kfree(ses->ntlmssp); |
| 800 | 846 | |
| 801 | 847 | return rc; |
| @@ -876,6 +922,12 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, · 74 unmodified lines |
| 876 | 922 | if (tcon && tcon->bad_network_name) |
| 877 | 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 | 931 | unc_path = kmalloc(MAX_SHARENAME_LENGTH * 2, GFP_KERNEL); |
| 880 | 932 | if (unc_path == NULL) |
| 881 | 933 | return -ENOMEM; |
| @@ -955,6 +1007,8 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, · 73 unmodified lines |
| 955 | 1007 | ((tcon->share_flags & SHI1005_FLAGS_DFS) == 0)) |
| 956 | 1008 | cifs_dbg(VFS, "DFS capability contradicts DFS flag\n"); |
| 957 | 1009 | init_copy_chunk_defaults(tcon); |
| 1010 | + if (tcon->share_flags & SHI1005_FLAGS_ENCRYPT_DATA) |
| 1011 | + cifs_dbg(VFS, "Encrypted shares not supported"); |
| 958 | 1012 | if (tcon->ses->server->ops->validate_negotiate) |
| 959 | 1013 | rc = tcon->ses->server->ops->validate_negotiate(xid, tcon); |
| 960 | 1014 | tcon_exit: |