diff options
Diffstat (limited to 'fs/cifs/sess.c')
-rw-r--r-- | fs/cifs/sess.c | 167 |
1 files changed, 70 insertions, 97 deletions
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 795095f4eac6..2a11efd96592 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -80,7 +80,7 @@ static __le16 get_next_vcnum(struct cifsSesInfo *ses) if (max_vcs < 2) max_vcs = 0xFFFF; - write_lock(&cifs_tcp_ses_lock); + spin_lock(&cifs_tcp_ses_lock); if ((ses->need_reconnect) && is_first_ses_reconnect(ses)) goto get_vc_num_exit; /* vcnum will be zero */ for (i = ses->server->srv_count - 1; i < max_vcs; i++) { @@ -112,7 +112,7 @@ static __le16 get_next_vcnum(struct cifsSesInfo *ses) vcnum = i; ses->vcnum = vcnum; get_vc_num_exit: - write_unlock(&cifs_tcp_ses_lock); + spin_unlock(&cifs_tcp_ses_lock); return cpu_to_le16(vcnum); } @@ -383,8 +383,8 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft, static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, struct cifsSesInfo *ses) { - unsigned int tioffset; /* challeng message target info area */ - unsigned int tilen; /* challeng message target info area length */ + unsigned int tioffset; /* challenge message target info area */ + unsigned int tilen; /* challenge message target info area length */ CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr; @@ -402,24 +402,23 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, return -EINVAL; } - memcpy(ses->server->cryptKey, pblob->Challenge, CIFS_CRYPTO_KEY_SIZE); + memcpy(ses->cryptKey, pblob->Challenge, CIFS_CRYPTO_KEY_SIZE); /* BB we could decode pblob->NegotiateFlags; some may be useful */ /* In particular we can examine sign flags */ /* BB spec says that if AvId field of MsvAvTimestamp is populated then we must set the MIC field of the AUTHENTICATE_MESSAGE */ - ses->server->ntlmssp.server_flags = le32_to_cpu(pblob->NegotiateFlags); - tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset); tilen = cpu_to_le16(pblob->TargetInfoArray.Length); - ses->server->tilen = tilen; - if (tilen) { - ses->server->tiblob = kmalloc(tilen, GFP_KERNEL); - if (!ses->server->tiblob) { + ses->tilen = tilen; + if (ses->tilen) { + ses->tiblob = kmalloc(tilen, GFP_KERNEL); + if (!ses->tiblob) { cERROR(1, "Challenge target info allocation failure"); + ses->tilen = 0; return -ENOMEM; } - memcpy(ses->server->tiblob, bcc_ptr + tioffset, tilen); + memcpy(ses->tiblob, bcc_ptr + tioffset, ses->tilen); } return 0; @@ -444,11 +443,10 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_NTLM; if (ses->server->secMode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { - flags |= NTLMSSP_NEGOTIATE_SIGN | - NTLMSSP_NEGOTIATE_KEY_XCH | - NTLMSSP_NEGOTIATE_EXTENDED_SEC; - } + (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + flags |= NTLMSSP_NEGOTIATE_SIGN; + if (ses->server->secMode & SECMODE_SIGN_REQUIRED) + flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; sec_blob->NegotiateFlags |= cpu_to_le32(flags); @@ -466,8 +464,9 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, maximum possible size is fixed and small, making this approach cleaner. This function returns the length of the data in the blob */ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, + u16 *buflen, struct cifsSesInfo *ses, - const struct nls_table *nls_cp, bool first) + const struct nls_table *nls_cp) { int rc; unsigned int size; @@ -482,7 +481,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | - NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; + NTLMSSP_NEGOTIATE_NTLM; if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) flags |= NTLMSSP_NEGOTIATE_SIGN; @@ -500,22 +499,23 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); rc = setup_ntlmv2_rsp(ses, (char *)&ntlmv2_response, nls_cp); if (rc) { - cERROR(1, "error rc: %d during ntlmssp ntlmv2 setup", rc); + cERROR(1, "Error %d during NTLMSSP authentication", rc); goto setup_ntlmv2_ret; } size = sizeof(struct ntlmv2_resp); memcpy(tmp, (char *)&ntlmv2_response, size); tmp += size; - if (ses->server->tilen > 0) { - memcpy(tmp, ses->server->tiblob, ses->server->tilen); - tmp += ses->server->tilen; - } else - ses->server->tilen = 0; + if (ses->tilen > 0) { + memcpy(tmp, ses->tiblob, ses->tilen); + tmp += ses->tilen; + } - sec_blob->NtChallengeResponse.Length = cpu_to_le16(size + - ses->server->tilen); + sec_blob->NtChallengeResponse.Length = cpu_to_le16(size + ses->tilen); sec_blob->NtChallengeResponse.MaximumLength = - cpu_to_le16(size + ses->server->tilen); + cpu_to_le16(size + ses->tilen); + kfree(ses->tiblob); + ses->tiblob = NULL; + ses->tilen = 0; if (ses->domainName == NULL) { sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); @@ -554,27 +554,13 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, sec_blob->WorkstationName.MaximumLength = 0; tmp += 2; - if ((ses->server->ntlmssp.server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) && - !calc_seckey(ses->server)) { - memcpy(tmp, ses->server->ntlmssp.ciphertext, CIFS_CPHTXT_SIZE); - sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); - sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE); - sec_blob->SessionKey.MaximumLength = - cpu_to_le16(CIFS_CPHTXT_SIZE); - tmp += CIFS_CPHTXT_SIZE; - } else { - sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); - sec_blob->SessionKey.Length = 0; - sec_blob->SessionKey.MaximumLength = 0; - } - - ses->server->sequence_number = 0; + sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); + sec_blob->SessionKey.Length = 0; + sec_blob->SessionKey.MaximumLength = 0; setup_ntlmv2_ret: - if (ses->server->tilen > 0) - kfree(ses->server->tiblob); - - return tmp - pbuffer; + *buflen = tmp - pbuffer; + return rc; } @@ -586,18 +572,6 @@ static void setup_ntlmssp_neg_req(SESSION_SETUP_ANDX *pSMB, return; } - -static int setup_ntlmssp_auth_req(char *ntlmsspblob, - struct cifsSesInfo *ses, - const struct nls_table *nls, bool first_time) -{ - int bloblen; - - bloblen = build_ntlmssp_auth_blob(ntlmsspblob, ses, nls, - first_time); - - return bloblen; -} #endif int @@ -619,15 +593,12 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int bytes_remaining; struct key *spnego_key = NULL; __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ - bool first_time; + u16 blob_len; + char *ntlmsspblob = NULL; if (ses == NULL) return -EINVAL; - read_lock(&cifs_tcp_ses_lock); - first_time = is_first_ses_reconnect(ses); - read_unlock(&cifs_tcp_ses_lock); - type = ses->server->secType; cFYI(1, "sess setup type %d", type); @@ -698,7 +669,7 @@ ssetup_ntlmssp_authenticate: /* BB calculate hash with password */ /* and copy into bcc */ - calc_lanman_hash(ses->password, ses->server->cryptKey, + calc_lanman_hash(ses->password, ses->cryptKey, ses->server->secMode & SECMODE_PW_ENCRYPT ? true : false, lnm_session_key); @@ -725,15 +696,11 @@ ssetup_ntlmssp_authenticate: cpu_to_le16(CIFS_SESS_KEY_SIZE); /* calculate session key */ - SMBNTencrypt(ses->password, ses->server->cryptKey, - ntlm_session_key); + SMBNTencrypt(ses->password, ses->cryptKey, ntlm_session_key); - if (first_time) /* should this be moved into common code - with similar ntlmv2 path? */ - cifs_calculate_session_key(&ses->server->session_key, - ntlm_session_key, ses->password); + cifs_calculate_session_key(&ses->auth_key, + ntlm_session_key, ses->password); /* copy session key */ - memcpy(bcc_ptr, (char *)ntlm_session_key, CIFS_SESS_KEY_SIZE); bcc_ptr += CIFS_SESS_KEY_SIZE; memcpy(bcc_ptr, (char *)ntlm_session_key, CIFS_SESS_KEY_SIZE); @@ -765,25 +732,31 @@ ssetup_ntlmssp_authenticate: pSMB->req_no_secext.CaseInsensitivePasswordLength = 0; /* cpu_to_le16(LM2_SESS_KEY_SIZE); */ - pSMB->req_no_secext.CaseSensitivePasswordLength = - cpu_to_le16(sizeof(struct ntlmv2_resp)); - /* calculate session key */ rc = setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); if (rc) { + cERROR(1, "Error %d during NTLMv2 authentication", rc); kfree(v2_sess_key); goto ssetup_exit; } - /* FIXME: calculate MAC key */ memcpy(bcc_ptr, (char *)v2_sess_key, - sizeof(struct ntlmv2_resp)); + sizeof(struct ntlmv2_resp)); bcc_ptr += sizeof(struct ntlmv2_resp); kfree(v2_sess_key); - if (ses->server->tilen > 0) { - memcpy(bcc_ptr, ses->server->tiblob, - ses->server->tilen); - bcc_ptr += ses->server->tilen; + /* set case sensitive password length after tilen may get + * assigned, tilen is 0 otherwise. + */ + pSMB->req_no_secext.CaseSensitivePasswordLength = + cpu_to_le16(sizeof(struct ntlmv2_resp) + ses->tilen); + if (ses->tilen > 0) { + memcpy(bcc_ptr, ses->tiblob, ses->tilen); + bcc_ptr += ses->tilen; + /* we never did allocate ses->domainName to free */ + kfree(ses->tiblob); + ses->tiblob = NULL; + ses->tilen = 0; } + if (ses->capabilities & CAP_UNICODE) { if (iov[0].iov_len % 2) { *bcc_ptr = 0; @@ -814,17 +787,14 @@ ssetup_ntlmssp_authenticate: } /* bail out if key is too long */ if (msg->sesskey_len > - sizeof(ses->server->session_key.data.krb5)) { + sizeof(ses->auth_key.data.krb5)) { cERROR(1, "Kerberos signing key too long (%u bytes)", msg->sesskey_len); rc = -EOVERFLOW; goto ssetup_exit; } - if (first_time) { - ses->server->session_key.len = msg->sesskey_len; - memcpy(ses->server->session_key.data.krb5, - msg->data, msg->sesskey_len); - } + ses->auth_key.len = msg->sesskey_len; + memcpy(ses->auth_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); @@ -866,11 +836,13 @@ ssetup_ntlmssp_authenticate: iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); iov[1].iov_base = &pSMB->req.SecurityBlob[0]; } else if (phase == NtLmAuthenticate) { - int blob_len; - char *ntlmsspblob; - - ntlmsspblob = kmalloc(5 * - sizeof(struct _AUTHENTICATE_MESSAGE), + /* 5 is an empirical value, large enought to + * hold authenticate message, max 10 of + * av paris, doamin,user,workstation mames, + * flags etc.. + */ + ntlmsspblob = kmalloc( + 5*sizeof(struct _AUTHENTICATE_MESSAGE), GFP_KERNEL); if (!ntlmsspblob) { cERROR(1, "Can't allocate NTLMSSP"); @@ -878,10 +850,10 @@ ssetup_ntlmssp_authenticate: goto ssetup_exit; } - blob_len = setup_ntlmssp_auth_req(ntlmsspblob, - ses, - nls_cp, - first_time); + 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 = @@ -959,7 +931,6 @@ ssetup_ntlmssp_authenticate: bcc_ptr = pByteArea(smb_buf); if (smb_buf->WordCount == 4) { - __u16 blob_len; blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); if (blob_len > bytes_remaining) { cERROR(1, "bad security blob length %d", blob_len); @@ -995,6 +966,8 @@ ssetup_exit: key_put(spnego_key); } kfree(str_area); + kfree(ntlmsspblob); + ntlmsspblob = NULL; if (resp_buf_type == CIFS_SMALL_BUFFER) { cFYI(1, "ssetup freeing small buf %p", iov[0].iov_base); cifs_small_buf_release(iov[0].iov_base); |