cifs: Separate rawntlmssp auth from CIFS_SessSetup()
Separate rawntlmssp authentication from CIFS_SessSetup(). Also cleanup CIFS_SessSetup() since we no longer do any auth within it. 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:
Родитель
ee03c646dd
Коммит
cc87c47d9d
566
fs/cifs/sess.c
566
fs/cifs/sess.c
|
@ -1113,39 +1113,262 @@ sess_auth_kerberos(struct sess_data *sess_data)
|
||||||
}
|
}
|
||||||
#endif /* ! CONFIG_CIFS_UPCALL */
|
#endif /* ! CONFIG_CIFS_UPCALL */
|
||||||
|
|
||||||
int
|
/*
|
||||||
CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
|
* The required kvec buffers have to be allocated before calling this
|
||||||
const struct nls_table *nls_cp)
|
* function.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
_sess_auth_rawntlmssp_assemble_req(struct sess_data *sess_data)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
|
||||||
int wct;
|
|
||||||
struct smb_hdr *smb_buf;
|
struct smb_hdr *smb_buf;
|
||||||
char *bcc_ptr;
|
|
||||||
char *str_area;
|
|
||||||
SESSION_SETUP_ANDX *pSMB;
|
SESSION_SETUP_ANDX *pSMB;
|
||||||
|
struct cifs_ses *ses = sess_data->ses;
|
||||||
__u32 capabilities;
|
__u32 capabilities;
|
||||||
__u16 count;
|
char *bcc_ptr;
|
||||||
int resp_buf_type;
|
|
||||||
struct kvec iov[3];
|
|
||||||
enum securityEnum type;
|
|
||||||
__u16 action, bytes_remaining;
|
|
||||||
__le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
|
|
||||||
u16 blob_len;
|
|
||||||
char *ntlmsspblob = NULL;
|
|
||||||
struct sess_data *sess_data;
|
|
||||||
|
|
||||||
if (ses == NULL) {
|
pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
|
||||||
WARN(1, "%s: ses == NULL!", __func__);
|
smb_buf = (struct smb_hdr *)pSMB;
|
||||||
return -EINVAL;
|
|
||||||
|
capabilities = cifs_ssetup_hdr(ses, pSMB);
|
||||||
|
if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) {
|
||||||
|
cifs_dbg(VFS, "NTLMSSP requires Unicode support\n");
|
||||||
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
sess_data = kzalloc(sizeof(struct sess_data), GFP_KERNEL);
|
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
||||||
if (!sess_data)
|
capabilities |= CAP_EXTENDED_SECURITY;
|
||||||
return -ENOMEM;
|
pSMB->req.Capabilities |= cpu_to_le32(capabilities);
|
||||||
sess_data->xid = xid;
|
|
||||||
sess_data->ses = ses;
|
bcc_ptr = sess_data->iov[2].iov_base;
|
||||||
sess_data->buf0_type = CIFS_NO_BUFFER;
|
/* unicode strings must be word aligned */
|
||||||
sess_data->nls_cp = (struct nls_table *) nls_cp;
|
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);
|
||||||
|
|
||||||
|
sess_data->iov[2].iov_len = (long) bcc_ptr -
|
||||||
|
(long) sess_data->iov[2].iov_base;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data);
|
||||||
|
|
||||||
|
static void
|
||||||
|
sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct smb_hdr *smb_buf;
|
||||||
|
SESSION_SETUP_ANDX *pSMB;
|
||||||
|
struct cifs_ses *ses = sess_data->ses;
|
||||||
|
__u16 bytes_remaining;
|
||||||
|
char *bcc_ptr;
|
||||||
|
u16 blob_len;
|
||||||
|
|
||||||
|
cifs_dbg(FYI, "rawntlmssp session setup negotiate phase\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if memory allocation is successful, caller of this function
|
||||||
|
* frees it.
|
||||||
|
*/
|
||||||
|
ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL);
|
||||||
|
if (!ses->ntlmssp) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
ses->ntlmssp->sesskey_per_smbsess = false;
|
||||||
|
|
||||||
|
/* wct = 12 */
|
||||||
|
rc = sess_alloc_buffer(sess_data, 12);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
|
||||||
|
|
||||||
|
/* Build security blob before we assemble the request */
|
||||||
|
build_ntlmssp_negotiate_blob(pSMB->req.SecurityBlob, ses);
|
||||||
|
sess_data->iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE);
|
||||||
|
sess_data->iov[1].iov_base = pSMB->req.SecurityBlob;
|
||||||
|
pSMB->req.SecurityBlobLength = cpu_to_le16(sizeof(NEGOTIATE_MESSAGE));
|
||||||
|
|
||||||
|
rc = _sess_auth_rawntlmssp_assemble_req(sess_data);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
rc = sess_sendreceive(sess_data);
|
||||||
|
|
||||||
|
pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
|
||||||
|
smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base;
|
||||||
|
|
||||||
|
/* If true, rc here is expected and not an error */
|
||||||
|
if (sess_data->buf0_type != CIFS_NO_BUFFER &&
|
||||||
|
smb_buf->Status.CifsError ==
|
||||||
|
cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
|
||||||
|
rc = 0;
|
||||||
|
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
cifs_dbg(FYI, "rawntlmssp session setup challenge phase\n");
|
||||||
|
|
||||||
|
if (smb_buf->WordCount != 4) {
|
||||||
|
rc = -EIO;
|
||||||
|
cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = decode_ntlmssp_challenge(bcc_ptr, blob_len, ses);
|
||||||
|
out:
|
||||||
|
sess_free_buffer(sess_data);
|
||||||
|
|
||||||
|
if (!rc) {
|
||||||
|
sess_data->func = sess_auth_rawntlmssp_authenticate;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Else error. Cleanup */
|
||||||
|
kfree(ses->auth_key.response);
|
||||||
|
ses->auth_key.response = NULL;
|
||||||
|
kfree(ses->ntlmssp);
|
||||||
|
ses->ntlmssp = NULL;
|
||||||
|
|
||||||
|
sess_data->func = NULL;
|
||||||
|
sess_data->result = rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct smb_hdr *smb_buf;
|
||||||
|
SESSION_SETUP_ANDX *pSMB;
|
||||||
|
struct cifs_ses *ses = sess_data->ses;
|
||||||
|
__u16 bytes_remaining;
|
||||||
|
char *bcc_ptr;
|
||||||
|
char *ntlmsspblob = NULL;
|
||||||
|
u16 blob_len;
|
||||||
|
|
||||||
|
cifs_dbg(FYI, "rawntlmssp session setup authenticate phase\n");
|
||||||
|
|
||||||
|
/* wct = 12 */
|
||||||
|
rc = sess_alloc_buffer(sess_data, 12);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Build security blob before we assemble the request */
|
||||||
|
pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
|
||||||
|
smb_buf = (struct smb_hdr *)pSMB;
|
||||||
|
/*
|
||||||
|
* 5 is an empirical value, large enough to hold
|
||||||
|
* authenticate message plus max 10 of av paris,
|
||||||
|
* domain, user, workstation names, flags, etc.
|
||||||
|
*/
|
||||||
|
ntlmsspblob = kzalloc(5*sizeof(struct _AUTHENTICATE_MESSAGE),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!ntlmsspblob) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = build_ntlmssp_auth_blob(ntlmsspblob,
|
||||||
|
&blob_len, ses, sess_data->nls_cp);
|
||||||
|
if (rc)
|
||||||
|
goto out_free_ntlmsspblob;
|
||||||
|
sess_data->iov[1].iov_len = blob_len;
|
||||||
|
sess_data->iov[1].iov_base = ntlmsspblob;
|
||||||
|
pSMB->req.SecurityBlobLength = cpu_to_le16(blob_len);
|
||||||
|
/*
|
||||||
|
* Make sure that we tell the server that we are using
|
||||||
|
* the uid that it just gave us back on the response
|
||||||
|
* (challenge)
|
||||||
|
*/
|
||||||
|
smb_buf->Uid = ses->Suid;
|
||||||
|
|
||||||
|
rc = _sess_auth_rawntlmssp_assemble_req(sess_data);
|
||||||
|
if (rc)
|
||||||
|
goto out_free_ntlmsspblob;
|
||||||
|
|
||||||
|
rc = sess_sendreceive(sess_data);
|
||||||
|
if (rc)
|
||||||
|
goto out_free_ntlmsspblob;
|
||||||
|
|
||||||
|
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_free_ntlmsspblob;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (le16_to_cpu(pSMB->resp.Action) & GUEST_LOGIN)
|
||||||
|
cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */
|
||||||
|
|
||||||
|
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_free_ntlmsspblob;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
out_free_ntlmsspblob:
|
||||||
|
kfree(ntlmsspblob);
|
||||||
|
out:
|
||||||
|
sess_free_buffer(sess_data);
|
||||||
|
|
||||||
|
if (!rc)
|
||||||
|
rc = sess_establish_session(sess_data);
|
||||||
|
|
||||||
|
/* Cleanup */
|
||||||
|
kfree(ses->auth_key.response);
|
||||||
|
ses->auth_key.response = NULL;
|
||||||
|
kfree(ses->ntlmssp);
|
||||||
|
ses->ntlmssp = NULL;
|
||||||
|
|
||||||
|
sess_data->func = NULL;
|
||||||
|
sess_data->result = rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int select_sec(struct cifs_ses *ses, struct sess_data *sess_data)
|
||||||
|
{
|
||||||
|
int type;
|
||||||
|
|
||||||
type = select_sectype(ses->server, ses->sectype);
|
type = select_sectype(ses->server, ses->sectype);
|
||||||
cifs_dbg(FYI, "sess setup type %d\n", type);
|
cifs_dbg(FYI, "sess setup type %d\n", type);
|
||||||
|
@ -1157,261 +1380,74 @@ CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case LANMAN:
|
case LANMAN:
|
||||||
sess_auth_lanman(sess_data);
|
/* LANMAN and plaintext are less secure and off by default.
|
||||||
goto out;
|
* So we make this explicitly be turned on in kconfig (in the
|
||||||
|
* build) and turned on at runtime (changed from the default)
|
||||||
|
* in proc/fs/cifs or via mount parm. Unfortunately this is
|
||||||
|
* needed for old Win (e.g. Win95), some obscure NAS and OS/2 */
|
||||||
|
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||||
|
sess_data->func = sess_auth_lanman;
|
||||||
|
break;
|
||||||
|
#else
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
#endif
|
||||||
case NTLM:
|
case NTLM:
|
||||||
sess_auth_ntlm(sess_data);
|
sess_data->func = sess_auth_ntlm;
|
||||||
goto out;
|
break;
|
||||||
case NTLMv2:
|
case NTLMv2:
|
||||||
sess_auth_ntlmv2(sess_data);
|
sess_data->func = sess_auth_ntlmv2;
|
||||||
goto out;
|
break;
|
||||||
case Kerberos:
|
case Kerberos:
|
||||||
sess_auth_kerberos(sess_data);
|
#ifdef CONFIG_CIFS_UPCALL
|
||||||
goto out;
|
sess_data->func = sess_auth_kerberos;
|
||||||
|
break;
|
||||||
|
#else
|
||||||
|
cifs_dbg(VFS, "Kerberos negotiated but upcall support disabled!\n");
|
||||||
|
return -ENOSYS;
|
||||||
|
break;
|
||||||
|
#endif /* CONFIG_CIFS_UPCALL */
|
||||||
|
case RawNTLMSSP:
|
||||||
|
sess_data->func = sess_auth_rawntlmssp_negotiate;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
cifs_dbg(FYI, "Continuing with CIFS_SessSetup\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == RawNTLMSSP) {
|
|
||||||
/* if memory allocation is successful, caller of this function
|
|
||||||
* frees it.
|
|
||||||
*/
|
|
||||||
ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL);
|
|
||||||
if (!ses->ntlmssp)
|
|
||||||
return -ENOMEM;
|
|
||||||
ses->ntlmssp->sesskey_per_smbsess = false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ssetup_ntlmssp_authenticate:
|
|
||||||
if (phase == NtLmChallenge)
|
|
||||||
phase = NtLmAuthenticate; /* if ntlmssp, now final phase */
|
|
||||||
|
|
||||||
/* same size: negotiate or auth, NTLMSSP or extended security */
|
|
||||||
wct = 12;
|
|
||||||
|
|
||||||
rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses,
|
|
||||||
(void **)&smb_buf);
|
|
||||||
if (rc)
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
pSMB = (SESSION_SETUP_ANDX *)smb_buf;
|
|
||||||
|
|
||||||
capabilities = cifs_ssetup_hdr(ses, pSMB);
|
|
||||||
|
|
||||||
/* we will send the SMB in three pieces:
|
|
||||||
a fixed length beginning part, an optional
|
|
||||||
SPNEGO blob (which can be zero length), and a
|
|
||||||
last part which will include the strings
|
|
||||||
and rest of bcc area. This allows us to avoid
|
|
||||||
a large buffer 17K allocation */
|
|
||||||
iov[0].iov_base = (char *)pSMB;
|
|
||||||
iov[0].iov_len = be32_to_cpu(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. */
|
|
||||||
str_area = kmalloc(2000, GFP_KERNEL);
|
|
||||||
if (str_area == NULL) {
|
|
||||||
rc = -ENOMEM;
|
|
||||||
goto ssetup_exit;
|
|
||||||
}
|
|
||||||
bcc_ptr = str_area;
|
|
||||||
|
|
||||||
iov[1].iov_base = NULL;
|
|
||||||
iov[1].iov_len = 0;
|
|
||||||
|
|
||||||
if (type == RawNTLMSSP) {
|
|
||||||
if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) {
|
|
||||||
cifs_dbg(VFS, "NTLMSSP requires Unicode support\n");
|
|
||||||
rc = -ENOSYS;
|
|
||||||
goto ssetup_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
cifs_dbg(FYI, "ntlmssp session setup phase %d\n", phase);
|
|
||||||
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
|
||||||
capabilities |= CAP_EXTENDED_SECURITY;
|
|
||||||
pSMB->req.Capabilities |= cpu_to_le32(capabilities);
|
|
||||||
switch(phase) {
|
|
||||||
case NtLmNegotiate:
|
|
||||||
build_ntlmssp_negotiate_blob(
|
|
||||||
pSMB->req.SecurityBlob, ses);
|
|
||||||
iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE);
|
|
||||||
iov[1].iov_base = pSMB->req.SecurityBlob;
|
|
||||||
pSMB->req.SecurityBlobLength =
|
|
||||||
cpu_to_le16(sizeof(NEGOTIATE_MESSAGE));
|
|
||||||
break;
|
|
||||||
case NtLmAuthenticate:
|
|
||||||
/*
|
|
||||||
* 5 is an empirical value, large enough to hold
|
|
||||||
* authenticate message plus max 10 of av paris,
|
|
||||||
* domain, user, workstation names, flags, etc.
|
|
||||||
*/
|
|
||||||
ntlmsspblob = kzalloc(
|
|
||||||
5*sizeof(struct _AUTHENTICATE_MESSAGE),
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!ntlmsspblob) {
|
|
||||||
rc = -ENOMEM;
|
|
||||||
goto ssetup_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = build_ntlmssp_auth_blob(ntlmsspblob,
|
|
||||||
&blob_len, ses, nls_cp);
|
|
||||||
if (rc)
|
|
||||||
goto ssetup_exit;
|
|
||||||
iov[1].iov_len = blob_len;
|
|
||||||
iov[1].iov_base = ntlmsspblob;
|
|
||||||
pSMB->req.SecurityBlobLength = cpu_to_le16(blob_len);
|
|
||||||
/*
|
|
||||||
* Make sure that we tell the server that we are using
|
|
||||||
* the uid that it just gave us back on the response
|
|
||||||
* (challenge)
|
|
||||||
*/
|
|
||||||
smb_buf->Uid = ses->Suid;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cifs_dbg(VFS, "invalid phase %d\n", phase);
|
|
||||||
rc = -ENOSYS;
|
|
||||||
goto ssetup_exit;
|
|
||||||
}
|
|
||||||
/* 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);
|
|
||||||
} else {
|
|
||||||
cifs_dbg(VFS, "secType %d not supported!\n", type);
|
cifs_dbg(VFS, "secType %d not supported!\n", type);
|
||||||
rc = -ENOSYS;
|
return -ENOSYS;
|
||||||
goto ssetup_exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
iov[2].iov_base = str_area;
|
return 0;
|
||||||
iov[2].iov_len = (long) bcc_ptr - (long) str_area;
|
}
|
||||||
|
|
||||||
count = iov[1].iov_len + iov[2].iov_len;
|
int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
|
||||||
smb_buf->smb_buf_length =
|
const struct nls_table *nls_cp)
|
||||||
cpu_to_be32(be32_to_cpu(smb_buf->smb_buf_length) + count);
|
{
|
||||||
|
int rc = 0;
|
||||||
|
struct sess_data *sess_data;
|
||||||
|
|
||||||
put_bcc(count, smb_buf);
|
if (ses == NULL) {
|
||||||
|
WARN(1, "%s: ses == NULL!", __func__);
|
||||||
rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type,
|
return -EINVAL;
|
||||||
CIFS_LOG_ERROR);
|
|
||||||
/* SMB request buf freed in SendReceive2 */
|
|
||||||
|
|
||||||
pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base;
|
|
||||||
smb_buf = (struct smb_hdr *)iov[0].iov_base;
|
|
||||||
|
|
||||||
if ((type == RawNTLMSSP) && (resp_buf_type != CIFS_NO_BUFFER) &&
|
|
||||||
(smb_buf->Status.CifsError ==
|
|
||||||
cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))) {
|
|
||||||
if (phase != NtLmNegotiate) {
|
|
||||||
cifs_dbg(VFS, "Unexpected more processing error\n");
|
|
||||||
goto ssetup_exit;
|
|
||||||
}
|
|
||||||
/* NTLMSSP Negotiate sent now processing challenge (response) */
|
|
||||||
phase = NtLmChallenge; /* process ntlmssp challenge */
|
|
||||||
rc = 0; /* MORE_PROC rc is not an error here, but expected */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sess_data = kzalloc(sizeof(struct sess_data), GFP_KERNEL);
|
||||||
|
if (!sess_data)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
rc = select_sec(ses, sess_data);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto ssetup_exit;
|
goto out;
|
||||||
|
|
||||||
if (smb_buf->WordCount != 4) {
|
sess_data->xid = xid;
|
||||||
rc = -EIO;
|
sess_data->ses = ses;
|
||||||
cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount);
|
sess_data->buf0_type = CIFS_NO_BUFFER;
|
||||||
goto ssetup_exit;
|
sess_data->nls_cp = (struct nls_table *) nls_cp;
|
||||||
}
|
|
||||||
action = le16_to_cpu(pSMB->resp.Action);
|
|
||||||
if (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);
|
|
||||||
/* response can have either 3 or 4 word count - Samba sends 3 */
|
|
||||||
/* and lanman response is 3 */
|
|
||||||
bytes_remaining = get_bcc(smb_buf);
|
|
||||||
bcc_ptr = pByteArea(smb_buf);
|
|
||||||
|
|
||||||
blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
|
while (sess_data->func)
|
||||||
if (blob_len > bytes_remaining) {
|
sess_data->func(sess_data);
|
||||||
cifs_dbg(VFS, "bad security blob length %d\n",
|
|
||||||
blob_len);
|
|
||||||
rc = -EINVAL;
|
|
||||||
goto ssetup_exit;
|
|
||||||
}
|
|
||||||
if (phase == NtLmChallenge) {
|
|
||||||
rc = decode_ntlmssp_challenge(bcc_ptr, blob_len, ses);
|
|
||||||
if (rc)
|
|
||||||
goto ssetup_exit;
|
|
||||||
}
|
|
||||||
bcc_ptr += blob_len;
|
|
||||||
bytes_remaining -= blob_len;
|
|
||||||
|
|
||||||
/* BB check if Unicode and decode strings */
|
/* Store result before we free sess_data */
|
||||||
if (bytes_remaining == 0) {
|
rc = sess_data->result;
|
||||||
/* 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, nls_cp);
|
|
||||||
} else {
|
|
||||||
decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, nls_cp);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssetup_exit:
|
|
||||||
kfree(str_area);
|
|
||||||
kfree(ntlmsspblob);
|
|
||||||
ntlmsspblob = NULL;
|
|
||||||
if (resp_buf_type == CIFS_SMALL_BUFFER) {
|
|
||||||
cifs_dbg(FYI, "ssetup freeing small buf %p\n", iov[0].iov_base);
|
|
||||||
cifs_small_buf_release(iov[0].iov_base);
|
|
||||||
} else if (resp_buf_type == CIFS_LARGE_BUFFER)
|
|
||||||
cifs_buf_release(iov[0].iov_base);
|
|
||||||
|
|
||||||
/* if ntlmssp, and negotiate succeeded, proceed to authenticate phase */
|
|
||||||
if ((phase == NtLmChallenge) && (rc == 0))
|
|
||||||
goto ssetup_ntlmssp_authenticate;
|
|
||||||
|
|
||||||
if (!rc) {
|
|
||||||
mutex_lock(&ses->server->srv_mutex);
|
|
||||||
if (!ses->server->session_estab) {
|
|
||||||
if (ses->server->sign) {
|
|
||||||
ses->server->session_key.response =
|
|
||||||
kmemdup(ses->auth_key.response,
|
|
||||||
ses->auth_key.len, GFP_KERNEL);
|
|
||||||
if (!ses->server->session_key.response) {
|
|
||||||
rc = -ENOMEM;
|
|
||||||
mutex_unlock(&ses->server->srv_mutex);
|
|
||||||
goto keycp_exit;
|
|
||||||
}
|
|
||||||
ses->server->session_key.len =
|
|
||||||
ses->auth_key.len;
|
|
||||||
}
|
|
||||||
ses->server->sequence_number = 0x2;
|
|
||||||
ses->server->session_estab = true;
|
|
||||||
}
|
|
||||||
mutex_unlock(&ses->server->srv_mutex);
|
|
||||||
|
|
||||||
cifs_dbg(FYI, "CIFS session established successfully\n");
|
|
||||||
spin_lock(&GlobalMid_Lock);
|
|
||||||
ses->status = CifsGood;
|
|
||||||
ses->need_reconnect = false;
|
|
||||||
spin_unlock(&GlobalMid_Lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
keycp_exit:
|
|
||||||
kfree(ses->auth_key.response);
|
|
||||||
ses->auth_key.response = NULL;
|
|
||||||
kfree(ses->ntlmssp);
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
rc = sess_data->result;
|
|
||||||
kfree(sess_data);
|
kfree(sess_data);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче