Commit ceb1b0b9 authored by Steve French's avatar Steve French

[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: 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>
parent 98ce94c8
......@@ -46,6 +46,7 @@
#include "smb2status.h"
#include "smb2glob.h"
#include "cifspdu.h"
#include "cifs_spnego.h"
/*
* The following table defines the expected "StructureSize" of SMB2 requests
......@@ -486,19 +487,15 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
cifs_dbg(FYI, "missing security blob on negprot\n");
rc = cifs_enable_signing(server, ses->sign);
#ifdef CONFIG_SMB2_ASN1 /* BB REMOVEME when updated asn1.c ready */
if (rc)
goto neg_exit;
if (blob_length)
if (blob_length) {
rc = decode_negTokenInit(security_blob, blob_length, server);
if (rc == 1)
rc = 0;
else if (rc == 0) {
else if (rc == 0)
rc = -EIO;
goto neg_exit;
}
#endif
neg_exit:
free_rsp_buf(resp_buftype, rsp);
return rc;
......@@ -592,7 +589,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
__le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
struct TCP_Server_Info *server = ses->server;
u16 blob_length = 0;
char *security_blob;
struct key *spnego_key = NULL;
char *security_blob = NULL;
char *ntlmssp_blob = NULL;
bool use_spnego = false; /* else use raw ntlmssp */
......@@ -620,6 +618,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
ses->ntlmssp->sesskey_per_smbsess = true;
/* FIXME: allow for other auth types besides NTLMSSP (e.g. krb5) */
if (ses->sectype != Kerberos && ses->sectype != RawNTLMSSP)
ses->sectype = RawNTLMSSP;
ssetup_ntlmssp_authenticate:
......@@ -649,7 +648,48 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
iov[0].iov_base = (char *)req;
/* 4 for rfc1002 length field and 1 for pad */
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),
GFP_KERNEL);
if (ntlmssp_blob == NULL) {
......@@ -672,6 +712,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
/* with raw NTLMSSP we don't encapsulate in SPNEGO */
security_blob = ntlmssp_blob;
}
iov[1].iov_base = security_blob;
iov[1].iov_len = blob_length;
} else if (phase == NtLmAuthenticate) {
req->hdr.SessionId = ses->Suid;
ntlmssp_blob = kzalloc(sizeof(struct _NEGOTIATE_MESSAGE) + 500,
......@@ -699,6 +741,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
} else {
security_blob = ntlmssp_blob;
}
iov[1].iov_base = security_blob;
iov[1].iov_len = blob_length;
} else {
cifs_dbg(VFS, "illegal ntlmssp phase\n");
rc = -EIO;
......@@ -710,8 +754,6 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
cpu_to_le16(sizeof(struct smb2_sess_setup_req) -
1 /* pad */ - 4 /* rfc1001 len */);
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 */);
......@@ -722,6 +764,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
kfree(security_blob);
rsp = (struct smb2_sess_setup_rsp *)iov[0].iov_base;
ses->Suid = rsp->hdr.SessionId;
if (resp_buftype != CIFS_NO_BUFFER &&
rsp->hdr.Status == STATUS_MORE_PROCESSING_REQUIRED) {
if (phase != NtLmNegotiate) {
......@@ -739,7 +782,6 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
/* NTLMSSP Negotiate sent now processing challenge (response) */
phase = NtLmChallenge; /* process ntlmssp challenge */
rc = 0; /* MORE_PROCESSING is not an error here but expected */
ses->Suid = rsp->hdr.SessionId;
rc = decode_ntlmssp_challenge(rsp->Buffer,
le16_to_cpu(rsp->SecurityBufferLength), ses);
}
......@@ -796,6 +838,10 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
kfree(ses->auth_key.response);
ses->auth_key.response = NULL;
}
if (spnego_key) {
key_invalidate(spnego_key);
key_put(spnego_key);
}
kfree(ses->ntlmssp);
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