cifs: Split Kerberos authentication off CIFS_SessSetup()
Signed-off-by: Sachin Prabhu <sprabhu@redhat.com> Reviewed-by: Shirish Pargaonkar <spargaonkar@suse.com> Signed-off-by: Steve French <smfrench@gmail.com>
This commit is contained in:
parent
583cf7afc7
commit
ee03c646dd
215
fs/cifs/sess.c
215
fs/cifs/sess.c
@ -963,6 +963,155 @@ sess_auth_ntlmv2(struct sess_data *sess_data)
|
|||||||
ses->auth_key.response = NULL;
|
ses->auth_key.response = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_CIFS_UPCALL
|
||||||
|
static void
|
||||||
|
sess_auth_kerberos(struct sess_data *sess_data)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
struct smb_hdr *smb_buf;
|
||||||
|
SESSION_SETUP_ANDX *pSMB;
|
||||||
|
char *bcc_ptr;
|
||||||
|
struct cifs_ses *ses = sess_data->ses;
|
||||||
|
__u32 capabilities;
|
||||||
|
__u16 bytes_remaining;
|
||||||
|
struct key *spnego_key = NULL;
|
||||||
|
struct cifs_spnego_msg *msg;
|
||||||
|
u16 blob_len;
|
||||||
|
|
||||||
|
/* extended security */
|
||||||
|
/* wct = 12 */
|
||||||
|
rc = sess_alloc_buffer(sess_data, 12);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
|
||||||
|
bcc_ptr = sess_data->iov[2].iov_base;
|
||||||
|
capabilities = cifs_ssetup_hdr(ses, pSMB);
|
||||||
|
|
||||||
|
spnego_key = cifs_get_spnego_key(ses);
|
||||||
|
if (IS_ERR(spnego_key)) {
|
||||||
|
rc = PTR_ERR(spnego_key);
|
||||||
|
spnego_key = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 out_put_spnego_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 out_put_spnego_key;
|
||||||
|
}
|
||||||
|
ses->auth_key.len = msg->sesskey_len;
|
||||||
|
|
||||||
|
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
||||||
|
capabilities |= CAP_EXTENDED_SECURITY;
|
||||||
|
pSMB->req.Capabilities = cpu_to_le32(capabilities);
|
||||||
|
sess_data->iov[1].iov_base = msg->data + msg->sesskey_len;
|
||||||
|
sess_data->iov[1].iov_len = msg->secblob_len;
|
||||||
|
pSMB->req.SecurityBlobLength = cpu_to_le16(sess_data->iov[1].iov_len);
|
||||||
|
|
||||||
|
if (ses->capabilities & CAP_UNICODE) {
|
||||||
|
/* unicode strings must be word aligned */
|
||||||
|
if ((sess_data->iov[0].iov_len
|
||||||
|
+ sess_data->iov[1].iov_len) % 2) {
|
||||||
|
*bcc_ptr = 0;
|
||||||
|
bcc_ptr++;
|
||||||
|
}
|
||||||
|
unicode_oslm_strings(&bcc_ptr, sess_data->nls_cp);
|
||||||
|
unicode_domain_string(&bcc_ptr, ses, sess_data->nls_cp);
|
||||||
|
} else {
|
||||||
|
/* BB: is this right? */
|
||||||
|
ascii_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
sess_data->iov[2].iov_len = (long) bcc_ptr -
|
||||||
|
(long) sess_data->iov[2].iov_base;
|
||||||
|
|
||||||
|
rc = sess_sendreceive(sess_data);
|
||||||
|
if (rc)
|
||||||
|
goto out_put_spnego_key;
|
||||||
|
|
||||||
|
pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
|
||||||
|
smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base;
|
||||||
|
|
||||||
|
if (smb_buf->WordCount != 4) {
|
||||||
|
rc = -EIO;
|
||||||
|
cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount);
|
||||||
|
goto out_put_spnego_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (le16_to_cpu(pSMB->resp.Action) & GUEST_LOGIN)
|
||||||
|
cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */
|
||||||
|
|
||||||
|
ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */
|
||||||
|
cifs_dbg(FYI, "UID = %llu\n", ses->Suid);
|
||||||
|
|
||||||
|
bytes_remaining = get_bcc(smb_buf);
|
||||||
|
bcc_ptr = pByteArea(smb_buf);
|
||||||
|
|
||||||
|
blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
|
||||||
|
if (blob_len > bytes_remaining) {
|
||||||
|
cifs_dbg(VFS, "bad security blob length %d\n",
|
||||||
|
blob_len);
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto out_put_spnego_key;
|
||||||
|
}
|
||||||
|
bcc_ptr += blob_len;
|
||||||
|
bytes_remaining -= blob_len;
|
||||||
|
|
||||||
|
/* BB check if Unicode and decode strings */
|
||||||
|
if (bytes_remaining == 0) {
|
||||||
|
/* no string area to decode, do nothing */
|
||||||
|
} else if (smb_buf->Flags2 & SMBFLG2_UNICODE) {
|
||||||
|
/* unicode string area must be word-aligned */
|
||||||
|
if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) {
|
||||||
|
++bcc_ptr;
|
||||||
|
--bytes_remaining;
|
||||||
|
}
|
||||||
|
decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses,
|
||||||
|
sess_data->nls_cp);
|
||||||
|
} else {
|
||||||
|
decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,
|
||||||
|
sess_data->nls_cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = sess_establish_session(sess_data);
|
||||||
|
out_put_spnego_key:
|
||||||
|
key_invalidate(spnego_key);
|
||||||
|
key_put(spnego_key);
|
||||||
|
out:
|
||||||
|
sess_data->result = rc;
|
||||||
|
sess_data->func = NULL;
|
||||||
|
sess_free_buffer(sess_data);
|
||||||
|
kfree(ses->auth_key.response);
|
||||||
|
ses->auth_key.response = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static void
|
||||||
|
sess_auth_kerberos(struct sess_data *sess_data)
|
||||||
|
{
|
||||||
|
cifs_dbg(VFS, "Kerberos negotiated but upcall support disabled!\n");
|
||||||
|
sess_data->result = -ENOSYS;
|
||||||
|
sess_data->func = NULL;
|
||||||
|
}
|
||||||
|
#endif /* ! CONFIG_CIFS_UPCALL */
|
||||||
|
|
||||||
int
|
int
|
||||||
CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
|
CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
|
||||||
@ -980,7 +1129,6 @@ CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
|
|||||||
struct kvec iov[3];
|
struct kvec iov[3];
|
||||||
enum securityEnum type;
|
enum securityEnum type;
|
||||||
__u16 action, bytes_remaining;
|
__u16 action, bytes_remaining;
|
||||||
struct key *spnego_key = NULL;
|
|
||||||
__le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
|
__le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
|
||||||
u16 blob_len;
|
u16 blob_len;
|
||||||
char *ntlmsspblob = NULL;
|
char *ntlmsspblob = NULL;
|
||||||
@ -1017,6 +1165,9 @@ CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
|
|||||||
case NTLMv2:
|
case NTLMv2:
|
||||||
sess_auth_ntlmv2(sess_data);
|
sess_auth_ntlmv2(sess_data);
|
||||||
goto out;
|
goto out;
|
||||||
|
case Kerberos:
|
||||||
|
sess_auth_kerberos(sess_data);
|
||||||
|
goto out;
|
||||||
default:
|
default:
|
||||||
cifs_dbg(FYI, "Continuing with CIFS_SessSetup\n");
|
cifs_dbg(FYI, "Continuing with CIFS_SessSetup\n");
|
||||||
}
|
}
|
||||||
@ -1072,63 +1223,7 @@ CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
|
|||||||
iov[1].iov_base = NULL;
|
iov[1].iov_base = NULL;
|
||||||
iov[1].iov_len = 0;
|
iov[1].iov_len = 0;
|
||||||
|
|
||||||
if (type == Kerberos) {
|
if (type == RawNTLMSSP) {
|
||||||
#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, "incorrect version of cifs.upcall "
|
|
||||||
"expected %d but 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;
|
|
||||||
|
|
||||||
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
|
||||||
capabilities |= CAP_EXTENDED_SECURITY;
|
|
||||||
pSMB->req.Capabilities = cpu_to_le32(capabilities);
|
|
||||||
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 + iov[1].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 */
|
|
||||||
cifs_dbg(VFS, "Kerberos negotiated but upcall support disabled!\n");
|
|
||||||
rc = -ENOSYS;
|
|
||||||
goto ssetup_exit;
|
|
||||||
#endif /* CONFIG_CIFS_UPCALL */
|
|
||||||
} else if (type == RawNTLMSSP) {
|
|
||||||
if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) {
|
if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) {
|
||||||
cifs_dbg(VFS, "NTLMSSP requires Unicode support\n");
|
cifs_dbg(VFS, "NTLMSSP requires Unicode support\n");
|
||||||
rc = -ENOSYS;
|
rc = -ENOSYS;
|
||||||
@ -1268,10 +1363,6 @@ CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ssetup_exit:
|
ssetup_exit:
|
||||||
if (spnego_key) {
|
|
||||||
key_invalidate(spnego_key);
|
|
||||||
key_put(spnego_key);
|
|
||||||
}
|
|
||||||
kfree(str_area);
|
kfree(str_area);
|
||||||
kfree(ntlmsspblob);
|
kfree(ntlmsspblob);
|
||||||
ntlmsspblob = NULL;
|
ntlmsspblob = NULL;
|
||||||
|
Loading…
Reference in New Issue
Block a user