Commit a065cd2b authored by Steve French's avatar Steve French Committed by Sasha Levin

[SMB3] Fix sec=krb5 on smb3 mounts

[ Upstream commit ceb1b0b9 ]

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: default avatarNoel Power <noel.power@suse.com>
Signed-off-by: default avatarJim McDonough <jmcd@samba.org>
CC: Stable <stable@vger.kernel.org>
Signed-off-by: default avatarSteve French <steve.french@primarydata.com>
Signed-off-by: default avatarSasha Levin <sasha.levin@oracle.com>
parent 7bc7f257
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#include "smb2status.h" #include "smb2status.h"
#include "smb2glob.h" #include "smb2glob.h"
#include "cifspdu.h" #include "cifspdu.h"
#include "cifs_spnego.h"
/* /*
* The following table defines the expected "StructureSize" of SMB2 requests * The following table defines the expected "StructureSize" of SMB2 requests
...@@ -427,19 +428,15 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) ...@@ -427,19 +428,15 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
cifs_dbg(FYI, "missing security blob on negprot\n"); cifs_dbg(FYI, "missing security blob on negprot\n");
rc = cifs_enable_signing(server, ses->sign); rc = cifs_enable_signing(server, ses->sign);
#ifdef CONFIG_SMB2_ASN1 /* BB REMOVEME when updated asn1.c ready */
if (rc) if (rc)
goto neg_exit; goto neg_exit;
if (blob_length) if (blob_length) {
rc = decode_negTokenInit(security_blob, blob_length, server); rc = decode_negTokenInit(security_blob, blob_length, server);
if (rc == 1) if (rc == 1)
rc = 0; rc = 0;
else if (rc == 0) { else if (rc == 0)
rc = -EIO; rc = -EIO;
goto neg_exit;
} }
#endif
neg_exit: neg_exit:
free_rsp_buf(resp_buftype, rsp); free_rsp_buf(resp_buftype, rsp);
return rc; return rc;
...@@ -533,7 +530,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -533,7 +530,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
__le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
struct TCP_Server_Info *server = ses->server; struct TCP_Server_Info *server = ses->server;
u16 blob_length = 0; u16 blob_length = 0;
char *security_blob; struct key *spnego_key = NULL;
char *security_blob = NULL;
char *ntlmssp_blob = NULL; char *ntlmssp_blob = NULL;
bool use_spnego = false; /* else use raw ntlmssp */ bool use_spnego = false; /* else use raw ntlmssp */
...@@ -561,7 +559,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -561,7 +559,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
ses->ntlmssp->sesskey_per_smbsess = true; ses->ntlmssp->sesskey_per_smbsess = true;
/* FIXME: allow for other auth types besides NTLMSSP (e.g. krb5) */ /* FIXME: allow for other auth types besides NTLMSSP (e.g. krb5) */
ses->sectype = RawNTLMSSP; if (ses->sectype != Kerberos && ses->sectype != RawNTLMSSP)
ses->sectype = RawNTLMSSP;
ssetup_ntlmssp_authenticate: ssetup_ntlmssp_authenticate:
if (phase == NtLmChallenge) if (phase == NtLmChallenge)
...@@ -590,7 +589,48 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -590,7 +589,48 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
iov[0].iov_base = (char *)req; iov[0].iov_base = (char *)req;
/* 4 for rfc1002 length field and 1 for pad */ /* 4 for rfc1002 length field and 1 for pad */
iov[0].iov_len = get_rfc1002_length(req) + 4 - 1; iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
if (phase == NtLmNegotiate) {
if (ses->sectype == Kerberos) {
#ifdef CONFIG_CIFS_UPCALL
struct cifs_spnego_msg *msg;
spnego_key = cifs_get_spnego_key(ses);
if (IS_ERR(spnego_key)) {
rc = PTR_ERR(spnego_key);
spnego_key = NULL;
goto ssetup_exit;
}
msg = spnego_key->payload.data;
/*
* check version field to make sure that cifs.upcall is
* sending us a response in an expected form
*/
if (msg->version != CIFS_SPNEGO_UPCALL_VERSION) {
cifs_dbg(VFS,
"bad cifs.upcall version. Expected %d got %d",
CIFS_SPNEGO_UPCALL_VERSION, msg->version);
rc = -EKEYREJECTED;
goto ssetup_exit;
}
ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len,
GFP_KERNEL);
if (!ses->auth_key.response) {
cifs_dbg(VFS,
"Kerberos can't allocate (%u bytes) memory",
msg->sesskey_len);
rc = -ENOMEM;
goto ssetup_exit;
}
ses->auth_key.len = msg->sesskey_len;
blob_length = msg->secblob_len;
iov[1].iov_base = msg->data + msg->sesskey_len;
iov[1].iov_len = blob_length;
#else
rc = -EOPNOTSUPP;
goto ssetup_exit;
#endif /* CONFIG_CIFS_UPCALL */
} else if (phase == NtLmNegotiate) { /* if not krb5 must be ntlmssp */
ntlmssp_blob = kmalloc(sizeof(struct _NEGOTIATE_MESSAGE), ntlmssp_blob = kmalloc(sizeof(struct _NEGOTIATE_MESSAGE),
GFP_KERNEL); GFP_KERNEL);
if (ntlmssp_blob == NULL) { if (ntlmssp_blob == NULL) {
...@@ -613,6 +653,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -613,6 +653,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
/* with raw NTLMSSP we don't encapsulate in SPNEGO */ /* with raw NTLMSSP we don't encapsulate in SPNEGO */
security_blob = ntlmssp_blob; security_blob = ntlmssp_blob;
} }
iov[1].iov_base = security_blob;
iov[1].iov_len = blob_length;
} else if (phase == NtLmAuthenticate) { } else if (phase == NtLmAuthenticate) {
req->hdr.SessionId = ses->Suid; req->hdr.SessionId = ses->Suid;
ntlmssp_blob = kzalloc(sizeof(struct _NEGOTIATE_MESSAGE) + 500, ntlmssp_blob = kzalloc(sizeof(struct _NEGOTIATE_MESSAGE) + 500,
...@@ -640,6 +682,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -640,6 +682,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
} else { } else {
security_blob = ntlmssp_blob; security_blob = ntlmssp_blob;
} }
iov[1].iov_base = security_blob;
iov[1].iov_len = blob_length;
} else { } else {
cifs_dbg(VFS, "illegal ntlmssp phase\n"); cifs_dbg(VFS, "illegal ntlmssp phase\n");
rc = -EIO; rc = -EIO;
...@@ -651,8 +695,6 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -651,8 +695,6 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
cpu_to_le16(sizeof(struct smb2_sess_setup_req) - cpu_to_le16(sizeof(struct smb2_sess_setup_req) -
1 /* pad */ - 4 /* rfc1001 len */); 1 /* pad */ - 4 /* rfc1001 len */);
req->SecurityBufferLength = cpu_to_le16(blob_length); req->SecurityBufferLength = cpu_to_le16(blob_length);
iov[1].iov_base = security_blob;
iov[1].iov_len = blob_length;
inc_rfc1001_len(req, blob_length - 1 /* pad */); inc_rfc1001_len(req, blob_length - 1 /* pad */);
...@@ -663,6 +705,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -663,6 +705,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
kfree(security_blob); kfree(security_blob);
rsp = (struct smb2_sess_setup_rsp *)iov[0].iov_base; rsp = (struct smb2_sess_setup_rsp *)iov[0].iov_base;
ses->Suid = rsp->hdr.SessionId;
if (resp_buftype != CIFS_NO_BUFFER && if (resp_buftype != CIFS_NO_BUFFER &&
rsp->hdr.Status == STATUS_MORE_PROCESSING_REQUIRED) { rsp->hdr.Status == STATUS_MORE_PROCESSING_REQUIRED) {
if (phase != NtLmNegotiate) { if (phase != NtLmNegotiate) {
...@@ -680,7 +723,6 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -680,7 +723,6 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
/* NTLMSSP Negotiate sent now processing challenge (response) */ /* NTLMSSP Negotiate sent now processing challenge (response) */
phase = NtLmChallenge; /* process ntlmssp challenge */ phase = NtLmChallenge; /* process ntlmssp challenge */
rc = 0; /* MORE_PROCESSING is not an error here but expected */ rc = 0; /* MORE_PROCESSING is not an error here but expected */
ses->Suid = rsp->hdr.SessionId;
rc = decode_ntlmssp_challenge(rsp->Buffer, rc = decode_ntlmssp_challenge(rsp->Buffer,
le16_to_cpu(rsp->SecurityBufferLength), ses); le16_to_cpu(rsp->SecurityBufferLength), ses);
} }
...@@ -737,6 +779,10 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -737,6 +779,10 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
kfree(ses->auth_key.response); kfree(ses->auth_key.response);
ses->auth_key.response = NULL; ses->auth_key.response = NULL;
} }
if (spnego_key) {
key_invalidate(spnego_key);
key_put(spnego_key);
}
kfree(ses->ntlmssp); kfree(ses->ntlmssp);
return rc; return rc;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment