diff options
author | Steve French <smfrench@gmail.com> | 2015-09-24 01:52:37 -0400 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2015-09-24 01:52:37 -0400 |
commit | ceb1b0b9b4d1089e9f2731a314689ae17784c861 (patch) | |
tree | a1297a789223a06aab10101fe713b3a5c87a4018 | |
parent | 98ce94c8df762d413b3ecb849e2b966b21606d04 (diff) |
[SMB3] Fix sec=krb5 on smb3 mounts
Kerberos, which is very important for security, was only enabled for
CIFS not SMB2/SMB3 mounts (e.g. vers=3.0)
Patch based on the information detailed in
http://thread.gmane.org/gmane.linux.kernel.cifs/10081/focus=10307
to enable Kerberized SMB2/SMB3
a) SMB2_negotiate: enable/use decode_negTokenInit in SMB2_negotiate
b) SMB2_sess_setup: handle Kerberos sectype and replicate Kerberos
SMB1 processing done in sess_auth_kerberos
Signed-off-by: Noel Power <noel.power@suse.com>
Signed-off-by: Jim McDonough <jmcd@samba.org>
CC: Stable <stable@vger.kernel.org>
Signed-off-by: Steve French <steve.french@primarydata.com>
-rw-r--r-- | fs/cifs/smb2pdu.c | 76 |
1 files changed, 61 insertions, 15 deletions
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 070fb2ad85ce..e543431db916 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; |