[linux-cifs-client] [PATCH 4/5] [CIFS] have CIFSSMBNegotiate handle SPNEGO via upcall

Jeff Layton jlayton at redhat.com
Thu Oct 25 17:43:47 GMT 2007


Change args for CIFSSMBNegotiate to take key pointer and a hostname
string. Have it call cifs_get_spnego_key when the NegotiateProtocol
response contains a SPNEGO blob.

Signed-off-by: Jeff Layton <jlayton at redhat.com>
---
 fs/cifs/cifsproto.h |    3 ++-
 fs/cifs/cifssmb.c   |   41 ++++++++++++++++++++++++++++++-----------
 fs/cifs/connect.c   |    7 +++++--
 3 files changed, 37 insertions(+), 14 deletions(-)

diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 0f8a99d..41c29c5 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -104,7 +104,8 @@ void cifs_proc_clean(void);
 
 extern int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
 			struct nls_table *nls_info, const char *unc);
-extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses);
+extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses,
+			struct key **spnego_key, const char *hostname);
 
 extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
 			const char *tree, struct cifsTconInfo *tcon,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 31686e9..68ac988 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -38,6 +38,7 @@
 #include "cifsproto.h"
 #include "cifs_unicode.h"
 #include "cifs_debug.h"
+#include "cifs_spnego.h"
 
 #ifdef CONFIG_CIFS_POSIX
 static struct {
@@ -407,7 +408,8 @@ static int validate_t2(struct smb_t2_rsp *pSMB)
 	return rc;
 }
 int
-CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
+CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses,
+		 struct key **spnego_key, const char *hostname)
 {
 	NEGOTIATE_REQ *pSMB;
 	NEGOTIATE_RSP *pSMBr;
@@ -641,19 +643,36 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
 			memcpy(server->server_GUID,
 			       pSMBr->u.extended_response.GUID, 16);
 
-		if (count == 16) {
+		if (count == 16)
 			server->secType = RawNTLMSSP;
-		} else {
-			rc = decode_negTokenInit(pSMBr->u.extended_response.
-						 SecurityBlob,
-						 count - 16,
-						 &server->secType);
-			if (rc == 1) {
-			/* BB Need to fill struct for sessetup here */
-				rc = -EOPNOTSUPP;
-			} else {
+		else {
+#ifdef CONFIG_CIFS_UPCALL
+			struct cifs_spnego_msg *msg;
+			*spnego_key = cifs_get_spnego_key(ses, pSMBr->u.
+						extended_response.SecurityBlob,
+						count - 16, hostname);
+			if (IS_ERR(*spnego_key)) {
+				rc = PTR_ERR(*spnego_key);
+				*spnego_key = NULL;
+				goto neg_err_exit;
+			}
+
+			msg = (struct cifs_spnego_msg *)
+						(*spnego_key)->payload.data;
+			if (msg->flags & CIFS_SPNEGO_KRB5)
+				server->secType = Kerberos;
+			else if (msg->flags & CIFS_SPNEGO_NTLMSSP)
+				server->secType = NTLMSSP;
+			else {
 				rc = -EINVAL;
+				goto neg_err_exit;
 			}
+#else /* CONFIG_CIFS_UPCALL */
+			cERROR(1, ("SPNEGO response received, but "
+				   "CONFIG_CIFS_UPCALL not enabled!"));
+			rc = -EINVAL;
+			goto neg_err_exit;
+#endif /* CONFIG_CIFS_UPCALL */
 		}
 	} else
 		server->capabilities &= ~CAP_EXTENDED_SECURITY;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 057d55c..37e9474 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3546,6 +3546,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
 	char ntlm_session_key[CIFS_SESS_KEY_SIZE];
 	int ntlmv2_flag = FALSE;
 	int first_time = 0;
+	struct key *spnego_key = NULL;
 	char *hostname;
 
 	hostname = extract_hostname_from_unc(unc);
@@ -3557,9 +3558,9 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
 
 	/* what if server changes its buffer size after dropping the session? */
 	if (pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
-		rc = CIFSSMBNegotiate(xid, pSesInfo);
+		rc = CIFSSMBNegotiate(xid, pSesInfo, &spnego_key, hostname);
 		if (rc == -EAGAIN) /* retry only once on 1st time connection */ {
-			rc = CIFSSMBNegotiate(xid, pSesInfo);
+			rc = CIFSSMBNegotiate(xid, pSesInfo, &spnego_key, hostname);
 			if (rc == -EAGAIN)
 				rc = -EHOSTDOWN;
 		}
@@ -3666,6 +3667,8 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
 		}
 	}
 ss_err_exit:
+	if (spnego_key)
+		key_put(spnego_key);
 	if (hostname)
 		kfree(hostname);
 
-- 
1.5.2.1



More information about the linux-cifs-client mailing list