Kerberized mount.cifs with SMB>1?
Subsystems (2)
Hi Steve, *
I came across this thread
http://thread.gmane.org/gmane.linux.kernel.cifs/10081/focus=10305 when investigating why mount.cifs wasn't working with smb2. I have tried to follow the information there and have created a patch. I have tested this successfully against SMB2.0, SMB2.1, SMB3.0, SMB3.02. Regarding the patch I followed as much as I could sess_auth_kerberos method in cifs.c[1]. Some things I didn't quite see how to handle as they don't seem relevant in SMB2 e.g. the unicode_oslm_strings, unicode_domain_string, ascii_ssetup_strings handling, also I only just noticed I missed the "bad security blob length" check (but not sure if it is needed for smb1+) Anyway be interested in a review of the patch :-)
thanks,
Noel
[1] actually I followed CIFS_SessSetup of an older cifs version but then when rebasing glanced at the new 'sess_auth_kerberos'
From c9270ed720865d8fa748adf6908bcb9c8074c785 Mon Sep 17 00:00:00 2001
From: Noel Power <[email protected]>
Date: Mon, 20 Jul 2015 12:06:07 +0100
Subject: [PATCH] kerberos mount for SMB2, SMB3
Patch based on the information detailed in
http://thread.gmane.org/gmane.linux.kernel.cifs/10081/focus=10307
to enable SMB2/SMB3 kerberozied.
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
--- fs/cifs/smb2pdu.c | 153 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 100 insertions(+), 53 deletions(-)
fs/cifs/smb2pdu.c +100 -53
@@ -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,7 +487,6 @@ 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)
@@ -497,7 +497,6 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) rc = -EIO ; goto neg_exit; } -#endif neg_exit:free_rsp_buf (resp_buftype, rsp);
@@ -592,9 +591,10 @@ 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; +char *security_blob =NULL ;char *ntlmssp_blob =NULL ;bool use_spnego = false;/* else use raw ntlmssp */ +struct key *spnego_key =NULL ;cifs_dbg (FYI ,"Session Setup\n" );
@@ -620,7 +620,8 @@ 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) */ - ses->sectype = RawNTLMSSP; +if (ses->sectype != Kerberos && ses->sectype != RawNTLMSSP) + ses->sectype = RawNTLMSSP; ssetup_ntlmssp_authenticate:if (phase == NtLmChallenge)
@@ -649,60 +650,104 @@ ssetup_ntlmssp_authenticate: 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) { - ntlmssp_blob =kmalloc (sizeof (struct _NEGOTIATE_MESSAGE ), -GFP_KERNEL ); -if (ntlmssp_blob ==NULL ) { - rc = -ENOMEM ; + +if (ses->sectype == RawNTLMSSP) { +if (phase == NtLmNegotiate) { + ntlmssp_blob = +kmalloc (sizeof (struct _NEGOTIATE_MESSAGE ), +GFP_KERNEL ); +if (ntlmssp_blob ==NULL ) { + rc = -ENOMEM ; + goto ssetup_exit; + } +build_ntlmssp_negotiate_blob (ntlmssp_blob, ses); +if (use_spnego) { +/* blob_length = build_spnego_ntlmssp_blob( +&security_blob, +sizeof(struct _NEGOTIATE_MESSAGE), +ntlmssp_blob); */ +/* BB eventually need to add this */ +cifs_dbg (VFS , +"spnego not supported for SMB2 yet\n" ); + rc = -EOPNOTSUPP ; +kfree (ntlmssp_blob); + goto ssetup_exit; + }else { + blob_length =sizeof (struct _NEGOTIATE_MESSAGE ); +/* with raw NTLMSSP we don't encapsulate in SPNEGO */ + security_blob = ntlmssp_blob; + } + }else if (phase == NtLmAuthenticate) { + req->hdr.SessionId = ses->Suid; + ntlmssp_blob = +kzalloc (sizeof (struct _NEGOTIATE_MESSAGE ) +500 , +GFP_KERNEL ); +if (ntlmssp_blob ==NULL ) { + rc = -ENOMEM ; + goto ssetup_exit; + } + rc =build_ntlmssp_auth_blob (ntlmssp_blob, &blob_length, + ses, nls_cp); +if (rc) { +cifs_dbg (FYI , +"build_ntlmssp_auth_blob failed %d\n" , + rc); + goto ssetup_exit;/* BB double check error handling */ + } +if (use_spnego) { +/* blob_length = build_spnego_ntlmssp_blob( +&security_blob, +blob_length, +ntlmssp_blob); */ +cifs_dbg (VFS , +"spnego not supported for SMB2 yet\n" ); + rc = -EOPNOTSUPP ; +kfree (ntlmssp_blob); + goto ssetup_exit; + }else { + security_blob = ntlmssp_blob; + } + }else { +cifs_dbg (VFS ,"illegal ntlmssp phase\n" ); + rc = -EIO ; goto ssetup_exit; } -build_ntlmssp_negotiate_blob (ntlmssp_blob, ses); -if (use_spnego) { -/* blob_length = build_spnego_ntlmssp_blob( -&security_blob, -sizeof(struct _NEGOTIATE_MESSAGE), -ntlmssp_blob); */ -/* BB eventually need to add this */ -cifs_dbg (VFS ,"spnego not supported for SMB2 yet\n" ); - rc = -EOPNOTSUPP ; -kfree (ntlmssp_blob); + iov[1 ].iov_base = security_blob; + iov[1 ].iov_len = blob_length; + }else if (ses->sectype == Kerberos) { +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; - }else { - blob_length =sizeof (struct _NEGOTIATE_MESSAGE ); -/* with raw NTLMSSP we don't encapsulate in SPNEGO */ - security_blob = ntlmssp_blob; } - }else if (phase == NtLmAuthenticate) { - req->hdr.SessionId = ses->Suid; - ntlmssp_blob =kzalloc (sizeof (struct _NEGOTIATE_MESSAGE ) +500 , -GFP_KERNEL ); -if (ntlmssp_blob ==NULL ) { - rc = -ENOMEM ; + + 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 ,"incorrect version of cifs.upcall " +"expected %d but got %d)" , +CIFS_SPNEGO_UPCALL_VERSION , msg->version); + rc = -EKEYREJECTED ; goto ssetup_exit; } - rc =build_ntlmssp_auth_blob (ntlmssp_blob, &blob_length, ses, - nls_cp); -if (rc) { -cifs_dbg (FYI ,"build_ntlmssp_auth_blob failed %d\n" , - rc); - goto ssetup_exit;/* BB double check error handling */ - } -if (use_spnego) { -/* blob_length = build_spnego_ntlmssp_blob( -&security_blob, -blob_length, -ntlmssp_blob); */ -cifs_dbg (VFS ,"spnego not supported for SMB2 yet\n" ); - rc = -EOPNOTSUPP ; -kfree (ntlmssp_blob); + + 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; - }else { - security_blob = ntlmssp_blob; } - }else { -cifs_dbg (VFS ,"illegal ntlmssp phase\n" ); - rc = -EIO ; - 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; }/* Testing shows that buffer offset must be at location of Buffer[0] */
@@ -710,8 +755,6 @@ ssetup_ntlmssp_authenticate: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 +765,7 @@ ssetup_ntlmssp_authenticate: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 +783,6 @@ ssetup_ntlmssp_authenticate:/* 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 +839,10 @@ keygen_exit: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;
Signature · 1 line
1.8.5.6