aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSachin Prabhu <sprabhu@redhat.com>2016-10-07 14:11:21 -0400
committerSteve French <smfrench@gmail.com>2016-10-13 20:48:30 -0400
commit3baf1a7b921500596b77487d5a34a27d656fc032 (patch)
tree01fa365ebac04681a957be2fe9c16bab1c411b00
parentcb978ac8b85fa8861352e57fcf8020f7f7bfbd82 (diff)
SMB2: Separate Kerberos authentication from SMB2_sess_setup
Add helper functions and split Kerberos authentication off SMB2_sess_setup. Signed-off-by: Sachin Prabhu <sprabhu@redhat.com> Signed-off-by: Steve French <smfrench@gmail.com> Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
-rw-r--r--fs/cifs/smb2pdu.c276
1 files changed, 230 insertions, 46 deletions
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index d6a045690266..386b512189b2 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -593,6 +593,216 @@ vneg_out:
593 return -EIO; 593 return -EIO;
594} 594}
595 595
596struct SMB2_sess_data {
597 unsigned int xid;
598 struct cifs_ses *ses;
599 struct nls_table *nls_cp;
600 void (*func)(struct SMB2_sess_data *);
601 int result;
602 u64 previous_session;
603
604 /* we will send the SMB in three pieces:
605 * a fixed length beginning part, an optional
606 * SPNEGO blob (which can be zero length), and a
607 * last part which will include the strings
608 * and rest of bcc area. This allows us to avoid
609 * a large buffer 17K allocation
610 */
611 int buf0_type;
612 struct kvec iov[2];
613};
614
615static int
616SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data)
617{
618 int rc;
619 struct cifs_ses *ses = sess_data->ses;
620 struct smb2_sess_setup_req *req;
621 struct TCP_Server_Info *server = ses->server;
622
623 rc = small_smb2_init(SMB2_SESSION_SETUP, NULL, (void **) &req);
624 if (rc)
625 return rc;
626
627 req->hdr.SessionId = 0; /* First session, not a reauthenticate */
628
629 /* if reconnect, we need to send previous sess id, otherwise it is 0 */
630 req->PreviousSessionId = sess_data->previous_session;
631
632 req->Flags = 0; /* MBZ */
633 /* to enable echos and oplocks */
634 req->hdr.CreditRequest = cpu_to_le16(3);
635
636 /* only one of SMB2 signing flags may be set in SMB2 request */
637 if (server->sign)
638 req->SecurityMode = SMB2_NEGOTIATE_SIGNING_REQUIRED;
639 else if (global_secflags & CIFSSEC_MAY_SIGN) /* one flag unlike MUST_ */
640 req->SecurityMode = SMB2_NEGOTIATE_SIGNING_ENABLED;
641 else
642 req->SecurityMode = 0;
643
644 req->Capabilities = 0;
645 req->Channel = 0; /* MBZ */
646
647 sess_data->iov[0].iov_base = (char *)req;
648 /* 4 for rfc1002 length field and 1 for pad */
649 sess_data->iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
650 /*
651 * This variable will be used to clear the buffer
652 * allocated above in case of any error in the calling function.
653 */
654 sess_data->buf0_type = CIFS_SMALL_BUFFER;
655
656 return 0;
657}
658
659static void
660SMB2_sess_free_buffer(struct SMB2_sess_data *sess_data)
661{
662 free_rsp_buf(sess_data->buf0_type, sess_data->iov[0].iov_base);
663 sess_data->buf0_type = CIFS_NO_BUFFER;
664}
665
666static int
667SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data)
668{
669 int rc;
670 struct smb2_sess_setup_req *req = sess_data->iov[0].iov_base;
671
672 /* Testing shows that buffer offset must be at location of Buffer[0] */
673 req->SecurityBufferOffset =
674 cpu_to_le16(sizeof(struct smb2_sess_setup_req) -
675 1 /* pad */ - 4 /* rfc1001 len */);
676 req->SecurityBufferLength = cpu_to_le16(sess_data->iov[1].iov_len);
677
678 inc_rfc1001_len(req, sess_data->iov[1].iov_len - 1 /* pad */);
679
680 /* BB add code to build os and lm fields */
681
682 rc = SendReceive2(sess_data->xid, sess_data->ses,
683 sess_data->iov, 2,
684 &sess_data->buf0_type,
685 CIFS_LOG_ERROR | CIFS_NEG_OP);
686
687 return rc;
688}
689
690static int
691SMB2_sess_establish_session(struct SMB2_sess_data *sess_data)
692{
693 int rc = 0;
694 struct cifs_ses *ses = sess_data->ses;
695
696 mutex_lock(&ses->server->srv_mutex);
697 if (ses->server->sign && ses->server->ops->generate_signingkey) {
698 rc = ses->server->ops->generate_signingkey(ses);
699 kfree(ses->auth_key.response);
700 ses->auth_key.response = NULL;
701 if (rc) {
702 cifs_dbg(FYI,
703 "SMB3 session key generation failed\n");
704 mutex_unlock(&ses->server->srv_mutex);
705 goto keygen_exit;
706 }
707 }
708 if (!ses->server->session_estab) {
709 ses->server->sequence_number = 0x2;
710 ses->server->session_estab = true;
711 }
712 mutex_unlock(&ses->server->srv_mutex);
713
714 cifs_dbg(FYI, "SMB2/3 session established successfully\n");
715 spin_lock(&GlobalMid_Lock);
716 ses->status = CifsGood;
717 ses->need_reconnect = false;
718 spin_unlock(&GlobalMid_Lock);
719
720keygen_exit:
721 if (!ses->server->sign) {
722 kfree(ses->auth_key.response);
723 ses->auth_key.response = NULL;
724 }
725 return rc;
726}
727
728#ifdef CONFIG_CIFS_UPCALL
729static void
730SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
731{
732 int rc;
733 struct cifs_ses *ses = sess_data->ses;
734 struct cifs_spnego_msg *msg;
735 struct key *spnego_key = NULL;
736 struct smb2_sess_setup_rsp *rsp = NULL;
737
738 rc = SMB2_sess_alloc_buffer(sess_data);
739 if (rc)
740 goto out;
741
742 spnego_key = cifs_get_spnego_key(ses);
743 if (IS_ERR(spnego_key)) {
744 rc = PTR_ERR(spnego_key);
745 spnego_key = NULL;
746 goto out;
747 }
748
749 msg = spnego_key->payload.data[0];
750 /*
751 * check version field to make sure that cifs.upcall is
752 * sending us a response in an expected form
753 */
754 if (msg->version != CIFS_SPNEGO_UPCALL_VERSION) {
755 cifs_dbg(VFS,
756 "bad cifs.upcall version. Expected %d got %d",
757 CIFS_SPNEGO_UPCALL_VERSION, msg->version);
758 rc = -EKEYREJECTED;
759 goto out_put_spnego_key;
760 }
761
762 ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len,
763 GFP_KERNEL);
764 if (!ses->auth_key.response) {
765 cifs_dbg(VFS,
766 "Kerberos can't allocate (%u bytes) memory",
767 msg->sesskey_len);
768 rc = -ENOMEM;
769 goto out_put_spnego_key;
770 }
771 ses->auth_key.len = msg->sesskey_len;
772
773 sess_data->iov[1].iov_base = msg->data + msg->sesskey_len;
774 sess_data->iov[1].iov_len = msg->secblob_len;
775
776 rc = SMB2_sess_sendreceive(sess_data);
777 if (rc)
778 goto out_put_spnego_key;
779
780 rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base;
781 ses->Suid = rsp->hdr.SessionId;
782
783 ses->session_flags = le16_to_cpu(rsp->SessionFlags);
784 if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA)
785 cifs_dbg(VFS, "SMB3 encryption not supported yet\n");
786
787 rc = SMB2_sess_establish_session(sess_data);
788out_put_spnego_key:
789 key_invalidate(spnego_key);
790 key_put(spnego_key);
791out:
792 sess_data->result = rc;
793 sess_data->func = NULL;
794 SMB2_sess_free_buffer(sess_data);
795}
796#else
797static void
798SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
799{
800 cifs_dbg(VFS, "Kerberos negotiated but upcall support disabled!\n");
801 sess_data->result = -EOPNOTSUPP;
802 sess_data->func = NULL;
803}
804#endif
805
596int 806int
597SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, 807SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
598 const struct nls_table *nls_cp) 808 const struct nls_table *nls_cp)
@@ -605,11 +815,11 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
605 __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ 815 __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
606 struct TCP_Server_Info *server = ses->server; 816 struct TCP_Server_Info *server = ses->server;
607 u16 blob_length = 0; 817 u16 blob_length = 0;
608 struct key *spnego_key = NULL;
609 char *security_blob = NULL; 818 char *security_blob = NULL;
610 unsigned char *ntlmssp_blob = NULL; 819 unsigned char *ntlmssp_blob = NULL;
611 bool use_spnego = false; /* else use raw ntlmssp */ 820 bool use_spnego = false; /* else use raw ntlmssp */
612 u64 previous_session = ses->Suid; 821 u64 previous_session = ses->Suid;
822 struct SMB2_sess_data *sess_data;
613 823
614 cifs_dbg(FYI, "Session Setup\n"); 824 cifs_dbg(FYI, "Session Setup\n");
615 825
@@ -618,6 +828,20 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
618 return -EIO; 828 return -EIO;
619 } 829 }
620 830
831 sess_data = kzalloc(sizeof(struct SMB2_sess_data), GFP_KERNEL);
832 if (!sess_data)
833 return -ENOMEM;
834 sess_data->xid = xid;
835 sess_data->ses = ses;
836 sess_data->buf0_type = CIFS_NO_BUFFER;
837 sess_data->nls_cp = (struct nls_table *) nls_cp;
838 sess_data->previous_session = ses->Suid;
839
840 if (ses->sectype == Kerberos) {
841 SMB2_auth_kerberos(sess_data);
842 goto out;
843 }
844
621 /* 845 /*
622 * If we are here due to reconnect, free per-smb session key 846 * If we are here due to reconnect, free per-smb session key
623 * in case signing was required. 847 * in case signing was required.
@@ -670,47 +894,7 @@ ssetup_ntlmssp_authenticate:
670 /* 4 for rfc1002 length field and 1 for pad */ 894 /* 4 for rfc1002 length field and 1 for pad */
671 iov[0].iov_len = get_rfc1002_length(req) + 4 - 1; 895 iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
672 896
673 if (ses->sectype == Kerberos) { 897 if (phase == NtLmNegotiate) {
674#ifdef CONFIG_CIFS_UPCALL
675 struct cifs_spnego_msg *msg;
676
677 spnego_key = cifs_get_spnego_key(ses);
678 if (IS_ERR(spnego_key)) {
679 rc = PTR_ERR(spnego_key);
680 spnego_key = NULL;
681 goto ssetup_exit;
682 }
683
684 msg = spnego_key->payload.data[0];
685 /*
686 * check version field to make sure that cifs.upcall is
687 * sending us a response in an expected form
688 */
689 if (msg->version != CIFS_SPNEGO_UPCALL_VERSION) {
690 cifs_dbg(VFS,
691 "bad cifs.upcall version. Expected %d got %d",
692 CIFS_SPNEGO_UPCALL_VERSION, msg->version);
693 rc = -EKEYREJECTED;
694 goto ssetup_exit;
695 }
696 ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len,
697 GFP_KERNEL);
698 if (!ses->auth_key.response) {
699 cifs_dbg(VFS,
700 "Kerberos can't allocate (%u bytes) memory",
701 msg->sesskey_len);
702 rc = -ENOMEM;
703 goto ssetup_exit;
704 }
705 ses->auth_key.len = msg->sesskey_len;
706 blob_length = msg->secblob_len;
707 iov[1].iov_base = msg->data + msg->sesskey_len;
708 iov[1].iov_len = blob_length;
709#else
710 rc = -EOPNOTSUPP;
711 goto ssetup_exit;
712#endif /* CONFIG_CIFS_UPCALL */
713 } else if (phase == NtLmNegotiate) { /* if not krb5 must be ntlmssp */
714 ntlmssp_blob = kmalloc(sizeof(struct _NEGOTIATE_MESSAGE), 898 ntlmssp_blob = kmalloc(sizeof(struct _NEGOTIATE_MESSAGE),
715 GFP_KERNEL); 899 GFP_KERNEL);
716 if (ntlmssp_blob == NULL) { 900 if (ntlmssp_blob == NULL) {
@@ -853,13 +1037,13 @@ keygen_exit:
853 kfree(ses->auth_key.response); 1037 kfree(ses->auth_key.response);
854 ses->auth_key.response = NULL; 1038 ses->auth_key.response = NULL;
855 } 1039 }
856 if (spnego_key) {
857 key_invalidate(spnego_key);
858 key_put(spnego_key);
859 }
860 kfree(ses->ntlmssp); 1040 kfree(ses->ntlmssp);
861 1041
862 return rc; 1042 return rc;
1043out:
1044 rc = sess_data->result;
1045 kfree(sess_data);
1046 return rc;
863} 1047}
864 1048
865int 1049int