Commit 2442421b authored by Steve French's avatar Steve French

[CIFS] Have CIFS_SessSetup build correct SPNEGO SessionSetup request

Have CIFS_SessSetup call cifs_get_spnego_key when Kerberos is
negotiated. Use the info in the key payload to build a session
setup request packet. Also clean up how the request buffer in
the function is freed on error.

With appropriate user space helper (in samba/source/client). Kerberos
support (secure session establishment can be done now via Kerberos,
previously users would have to use NTLMv2 instead for more secure
session setup).
Signed-off-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
parent 8840dee9
Version 1.52 Version 1.52
------------ ------------
Fix oops on second mount to server when null auth is used. Fix oops on second mount to server when null auth is used.
Enable experimental Kerberos support
Version 1.51 Version 1.51
------------ ------------
......
...@@ -16,7 +16,7 @@ SecurityDescriptors ...@@ -16,7 +16,7 @@ SecurityDescriptors
c) Better pam/winbind integration (e.g. to handle uid mapping c) Better pam/winbind integration (e.g. to handle uid mapping
better) better)
d) Kerberos/SPNEGO session setup support - (started) d) Verify that Kerberos signing works
e) Cleanup now unneeded SessSetup code in e) Cleanup now unneeded SessSetup code in
fs/cifs/connect.c and add back in NTLMSSP code if any servers fs/cifs/connect.c and add back in NTLMSSP code if any servers
......
...@@ -110,6 +110,7 @@ struct mac_key { ...@@ -110,6 +110,7 @@ struct mac_key {
unsigned int len; unsigned int len;
union { union {
char ntlm[CIFS_SESS_KEY_SIZE + 16]; char ntlm[CIFS_SESS_KEY_SIZE + 16];
char krb5[CIFS_SESS_KEY_SIZE + 16]; /* BB: length correct? */
struct { struct {
char key[16]; char key[16];
struct ntlmv2_resp resp; struct ntlmv2_resp resp;
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "ntlmssp.h" #include "ntlmssp.h"
#include "nterr.h" #include "nterr.h"
#include <linux/utsname.h> #include <linux/utsname.h>
#include "cifs_spnego.h"
extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
unsigned char *p24); unsigned char *p24);
...@@ -340,11 +341,12 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ...@@ -340,11 +341,12 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
SESSION_SETUP_ANDX *pSMB; SESSION_SETUP_ANDX *pSMB;
__u32 capabilities; __u32 capabilities;
int count; int count;
int resp_buf_type = 0; int resp_buf_type;
struct kvec iov[2]; struct kvec iov[3];
enum securityEnum type; enum securityEnum type;
__u16 action; __u16 action;
int bytes_remaining; int bytes_remaining;
struct key *spnego_key = NULL;
if (ses == NULL) if (ses == NULL)
return -EINVAL; return -EINVAL;
...@@ -377,24 +379,32 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ...@@ -377,24 +379,32 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
capabilities = cifs_ssetup_hdr(ses, pSMB); capabilities = cifs_ssetup_hdr(ses, pSMB);
/* we will send the SMB in two pieces, /* we will send the SMB in three pieces:
a fixed length beginning part, and a a fixed length beginning part, an optional
second part which will include the strings SPNEGO blob (which can be zero length), and a
and rest of bcc area, in order to avoid having last part which will include the strings
to do a large buffer 17K allocation */ and rest of bcc area. This allows us to avoid
a large buffer 17K allocation */
iov[0].iov_base = (char *)pSMB; iov[0].iov_base = (char *)pSMB;
iov[0].iov_len = smb_buf->smb_buf_length + 4; iov[0].iov_len = smb_buf->smb_buf_length + 4;
/* setting this here allows the code at the end of the function
to free the request buffer if there's an error */
resp_buf_type = CIFS_SMALL_BUFFER;
/* 2000 big enough to fit max user, domain, NOS name etc. */ /* 2000 big enough to fit max user, domain, NOS name etc. */
str_area = kmalloc(2000, GFP_KERNEL); str_area = kmalloc(2000, GFP_KERNEL);
if (str_area == NULL) { if (str_area == NULL) {
cifs_small_buf_release(smb_buf); rc = -ENOMEM;
return -ENOMEM; goto ssetup_exit;
} }
bcc_ptr = str_area; bcc_ptr = str_area;
ses->flags &= ~CIFS_SES_LANMAN; ses->flags &= ~CIFS_SES_LANMAN;
iov[1].iov_base = NULL;
iov[1].iov_len = 0;
if (type == LANMAN) { if (type == LANMAN) {
#ifdef CONFIG_CIFS_WEAK_PW_HASH #ifdef CONFIG_CIFS_WEAK_PW_HASH
char lnm_session_key[CIFS_SESS_KEY_SIZE]; char lnm_session_key[CIFS_SESS_KEY_SIZE];
...@@ -463,8 +473,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ...@@ -463,8 +473,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
struct ntlmv2_resp */ struct ntlmv2_resp */
if (v2_sess_key == NULL) { if (v2_sess_key == NULL) {
cifs_small_buf_release(smb_buf); rc = -ENOMEM;
return -ENOMEM; goto ssetup_exit;
} }
pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
...@@ -499,21 +509,66 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ...@@ -499,21 +509,66 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); unicode_ssetup_strings(&bcc_ptr, ses, nls_cp);
} else } else
ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); 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);
if (IS_ERR(spnego_key)) {
rc = PTR_ERR(spnego_key);
spnego_key = NULL;
goto ssetup_exit;
}
msg = spnego_key->payload.data;
/* bail out if key is too long */
if (msg->sesskey_len >
sizeof(ses->server->mac_signing_key.data.krb5)) {
cERROR(1, ("Kerberos signing key too long (%u bytes)",
msg->sesskey_len));
rc = -EOVERFLOW;
goto ssetup_exit;
}
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; pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
capabilities |= CAP_EXTENDED_SECURITY; capabilities |= CAP_EXTENDED_SECURITY;
pSMB->req.Capabilities = cpu_to_le32(capabilities); 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 = -ENOSYS;
goto ssetup_exit;
#endif /* CONFIG_CIFS_UPCALL */
} else {
cERROR(1, ("secType %d not supported!", type));
rc = -ENOSYS;
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; smb_buf->smb_buf_length += count;
BCC_LE(smb_buf) = cpu_to_le16(count); BCC_LE(smb_buf) = cpu_to_le16(count);
iov[1].iov_base = str_area; rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type,
iov[1].iov_len = count;
rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type,
CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR); CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR);
/* SMB request buf freed in SendReceive2 */ /* SMB request buf freed in SendReceive2 */
...@@ -560,6 +615,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ...@@ -560,6 +615,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
ses, nls_cp); ses, nls_cp);
ssetup_exit: ssetup_exit:
if (spnego_key)
key_put(spnego_key);
kfree(str_area); kfree(str_area);
if (resp_buf_type == CIFS_SMALL_BUFFER) { if (resp_buf_type == CIFS_SMALL_BUFFER) {
cFYI(1, ("ssetup freeing small buf %p", iov[0].iov_base)); cFYI(1, ("ssetup freeing small buf %p", iov[0].iov_base));
......
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