[linux-cifs-client] [PATCH 6/6] [CIFS] have CIFS_SessSetup build correct SPNEGO SessionSetup request

Jeff Layton jlayton at redhat.com
Wed Oct 31 15:31:46 GMT 2007


Change CIFS_SessSetup to take a hostname arg, and have it call
cifs_get_spnego_key. Use the info in the key payload to build a
session setup request packet when Kerberos is enabled.

Signed-off-by: Jeff Layton <jlayton at redhat.com>
---
 fs/cifs/cifsglob.h  |    1 +
 fs/cifs/cifsproto.h |    4 +-
 fs/cifs/connect.c   |    4 +-
 fs/cifs/sess.c      |   59 ++++++++++++++++++++++++++++++++++++++++++++-------
 4 files changed, 56 insertions(+), 12 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 87f51f2..eb9295c 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -110,6 +110,7 @@ struct mac_key {
 	unsigned int len;
 	union {
 		char ntlm[CIFS_SESS_KEY_SIZE + 16];
+		char krb5[CIFS_SESS_KEY_SIZE + 16];
 		struct {
 			char key[16];
 			struct ntlmv2_resp resp;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index b256e8a..65dce89 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -79,8 +79,8 @@ extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
 extern struct key *cifs_get_spnego_key(struct cifsSesInfo *sesInfo,
 					const char *hostname);
 extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
-			     const int stage,
-			     const struct nls_table *nls_cp);
+			const int stage, const struct nls_table *nls_cp,
+			const char *hostname);
 extern __u16 GetNextMid(struct TCP_Server_Info *server);
 extern struct oplock_q_entry *AllocOplockQEntry(struct inode *, u16,
 						 struct cifsTconInfo *);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 057d55c..f730763 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3586,8 +3586,8 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
 			pSesInfo->server->capabilities,
 			pSesInfo->server->timeAdj));
 		if (experimEnabled < 2)
-			rc = CIFS_SessSetup(xid, pSesInfo,
-					    first_time, nls_info);
+			rc = CIFS_SessSetup(xid, pSesInfo, first_time,
+						nls_info, hostname);
 		else if (extended_security
 				&& (pSesInfo->capabilities
 					& CAP_EXTENDED_SECURITY)
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 899dc60..cf14e16 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -29,6 +29,7 @@
 #include "ntlmssp.h"
 #include "nterr.h"
 #include <linux/utsname.h>
+#include "cifs_spnego.h"
 
 extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
 			 unsigned char *p24);
@@ -330,7 +331,7 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft,
 
 int
 CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
-		const struct nls_table *nls_cp)
+		const struct nls_table *nls_cp, const char *hostname)
 {
 	int rc = 0;
 	int wct;
@@ -341,10 +342,11 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
 	__u32 capabilities;
 	int count;
 	int resp_buf_type = 0;
-	struct kvec iov[2];
+	struct kvec iov[3];
 	enum securityEnum type;
 	__u16 action;
 	int bytes_remaining;
+	struct key *spnego_key = NULL;
 
 	if (ses == NULL)
 		return -EINVAL;
@@ -395,6 +397,9 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
 
 	ses->flags &= ~CIFS_SES_LANMAN;
 
+	iov[1].iov_base = NULL;
+	iov[1].iov_len = 0;
+
 	if (type == LANMAN) {
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
 		char lnm_session_key[CIFS_SESS_KEY_SIZE];
@@ -499,21 +504,57 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
 			unicode_ssetup_strings(&bcc_ptr, ses, nls_cp);
 		} else
 			ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
-	} else /* NTLMSSP or SPNEGO */ {
+	} else if (type == Kerberos) {
+#ifdef CONFIG_CIFS_UPCALL
+		struct cifs_spnego_msg *msg;
+		spnego_key = cifs_get_spnego_key(ses, hostname);
+		if (IS_ERR(spnego_key)) {
+			rc = PTR_ERR(spnego_key);
+			spnego_key = NULL;
+			goto ssetup_exit;
+		}
+		msg = spnego_key->payload.data;
+		ses->server->mac_signing_key.len = msg->sesskey_len;
+		memcpy(ses->server->mac_signing_key.data.krb5, msg->data,
+			msg->sesskey_len);
 		pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
 		capabilities |= CAP_EXTENDED_SECURITY;
 		pSMB->req.Capabilities = cpu_to_le32(capabilities);
-		/* BB set password lengths */
+		iov[1].iov_base = msg->data + msg->sesskey_len;
+		iov[1].iov_len = msg->secblob_len;
+		pSMB->req.SecurityBlobLength = cpu_to_le16(iov[1].iov_len);
+
+		if (ses->capabilities & CAP_UNICODE) {
+			/* unicode strings must be word aligned */
+			if (iov[0].iov_len % 2) {
+				*bcc_ptr = 0;
+				bcc_ptr++;
+			}
+			unicode_oslm_strings(&bcc_ptr, nls_cp);
+			unicode_domain_string(&bcc_ptr, ses, nls_cp);
+		} else
+			/* BB: is this right? */
+			ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
+#else /* ! CONFIG_CIFS_UPCALL */
+		cERROR(1,("Kerberos negotiated, but upcall support disabled!"));
+		rc = -EINVAL;
+		goto ssetup_exit;
+#endif /* CONFIG_CIFS_UPCALL */
+	} else {
+		cERROR(1,("secType %d not supported!", type));
+		rc = -EINVAL;
+		goto ssetup_exit;
 	}
 
-	count = (long) bcc_ptr - (long) str_area;
+	iov[2].iov_base = str_area;
+	iov[2].iov_len = (long) bcc_ptr - (long) str_area;
+
+	count = iov[1].iov_len + iov[2].iov_len;
 	smb_buf->smb_buf_length += count;
 
 	BCC_LE(smb_buf) = cpu_to_le16(count);
 
-	iov[1].iov_base = str_area;
-	iov[1].iov_len = count;
-	rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type,
+	rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type,
 			  0 /* not long op */, 1 /* log NT STATUS if any */ );
 	/* SMB request buf freed in SendReceive2 */
 
@@ -560,6 +601,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
 					 ses, nls_cp);
 
 ssetup_exit:
+	if (spnego_key)
+		key_put(spnego_key);
 	kfree(str_area);
 	if (resp_buf_type == CIFS_SMALL_BUFFER) {
 		cFYI(1, ("ssetup freeing small buf %p", iov[0].iov_base));
-- 
1.5.2.1



More information about the linux-cifs-client mailing list