aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorShirish Pargaonkar <shirishpargaonkar@gmail.com>2010-10-13 19:15:00 -0400
committerSteve French <sfrench@us.ibm.com>2010-10-14 14:05:19 -0400
commit5d0d28824c76409f0d1a645bf0ae81318c8ffa42 (patch)
tree592838282fc891dc9a51424e0f57c0694ad31075 /fs/cifs
parentd7c86ff8cd00abc730fe5d031f43dc9138b6324e (diff)
NTLM authentication and signing - Calculate auth response per smb session
Start calculation auth response within a session. Move/Add pertinet data structures like session key, server challenge and ntlmv2_hash in a session structure. We should do the calculations within a session before copying session key and response over to server data structures because a session setup can fail. Only after a very first smb session succeeds, it copies/makes its session key, session key of smb connection. This key stays with the smb connection throughout its life. Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com> Reviewed-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifsencrypt.c16
-rw-r--r--fs/cifs/cifsglob.h6
-rw-r--r--fs/cifs/cifssmb.c4
-rw-r--r--fs/cifs/connect.c18
-rw-r--r--fs/cifs/sess.c28
5 files changed, 36 insertions, 36 deletions
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index e3edd8a6840b..7ac0056294cf 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -458,7 +458,7 @@ calc_exit_1:
458calc_exit_2: 458calc_exit_2:
459 /* BB FIXME what about bytes 24 through 40 of the signing key? 459 /* BB FIXME what about bytes 24 through 40 of the signing key?
460 compare with the NTLM example */ 460 compare with the NTLM example */
461 hmac_md5_final(ses->server->ntlmv2_hash, pctxt); 461 hmac_md5_final(ses->ntlmv2_hash, pctxt);
462 462
463 kfree(pctxt); 463 kfree(pctxt);
464 return rc; 464 return rc;
@@ -502,14 +502,14 @@ setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
502 } 502 }
503 CalcNTLMv2_response(ses, resp_buf); 503 CalcNTLMv2_response(ses, resp_buf);
504 504
505 /* now calculate the MAC key for NTLMv2 */ 505 /* now calculate the session key for NTLMv2 */
506 hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context); 506 hmac_md5_init_limK_to_64(ses->ntlmv2_hash, 16, &context);
507 hmac_md5_update(resp_buf, 16, &context); 507 hmac_md5_update(resp_buf, 16, &context);
508 hmac_md5_final(ses->server->session_key.data.ntlmv2.key, &context); 508 hmac_md5_final(ses->auth_key.data.ntlmv2.key, &context);
509 509
510 memcpy(&ses->server->session_key.data.ntlmv2.resp, resp_buf, 510 memcpy(&ses->auth_key.data.ntlmv2.resp, resp_buf,
511 sizeof(struct ntlmv2_resp)); 511 sizeof(struct ntlmv2_resp));
512 ses->server->session_key.len = 16 + sizeof(struct ntlmv2_resp); 512 ses->auth_key.len = 16 + sizeof(struct ntlmv2_resp);
513 513
514 return 0; 514 return 0;
515 515
@@ -526,8 +526,8 @@ void CalcNTLMv2_response(const struct cifsSesInfo *ses,
526{ 526{
527 struct HMACMD5Context context; 527 struct HMACMD5Context context;
528 /* rest of v2 struct already generated */ 528 /* rest of v2 struct already generated */
529 memcpy(v2_session_response + 8, ses->server->cryptKey, 8); 529 memcpy(v2_session_response + 8, ses->cryptKey, 8);
530 hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context); 530 hmac_md5_init_limK_to_64(ses->ntlmv2_hash, 16, &context);
531 531
532 hmac_md5_update(v2_session_response+8, 532 hmac_md5_update(v2_session_response+8,
533 sizeof(struct ntlmv2_resp) - 8, &context); 533 sizeof(struct ntlmv2_resp) - 8, &context);
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index e2b760ef22ff..6c69bd762498 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -179,12 +179,10 @@ struct TCP_Server_Info {
179 int capabilities; /* allow selective disabling of caps by smb sess */ 179 int capabilities; /* allow selective disabling of caps by smb sess */
180 int timeAdj; /* Adjust for difference in server time zone in sec */ 180 int timeAdj; /* Adjust for difference in server time zone in sec */
181 __u16 CurrentMid; /* multiplex id - rotating counter */ 181 __u16 CurrentMid; /* multiplex id - rotating counter */
182 char cryptKey[CIFS_CRYPTO_KEY_SIZE];
183 /* 16th byte of RFC1001 workstation name is always null */ 182 /* 16th byte of RFC1001 workstation name is always null */
184 char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; 183 char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
185 __u32 sequence_number; /* needed for CIFS PDU signature */ 184 __u32 sequence_number; /* needed for CIFS PDU signature */
186 struct session_key session_key; 185 struct session_key session_key;
187 char ntlmv2_hash[16];
188 unsigned long lstrp; /* when we got last response from this server */ 186 unsigned long lstrp; /* when we got last response from this server */
189 u16 dialect; /* dialect index that server chose */ 187 u16 dialect; /* dialect index that server chose */
190 /* extended security flavors that server supports */ 188 /* extended security flavors that server supports */
@@ -192,6 +190,7 @@ struct TCP_Server_Info {
192 bool sec_mskerberos; /* supports legacy MS Kerberos */ 190 bool sec_mskerberos; /* supports legacy MS Kerberos */
193 bool sec_kerberosu2u; /* supports U2U Kerberos */ 191 bool sec_kerberosu2u; /* supports U2U Kerberos */
194 bool sec_ntlmssp; /* supports NTLMSSP */ 192 bool sec_ntlmssp; /* supports NTLMSSP */
193 bool session_estab; /* mark when very first sess is established */
195#ifdef CONFIG_CIFS_FSCACHE 194#ifdef CONFIG_CIFS_FSCACHE
196 struct fscache_cookie *fscache; /* client index cache cookie */ 195 struct fscache_cookie *fscache; /* client index cache cookie */
197#endif 196#endif
@@ -223,6 +222,9 @@ struct cifsSesInfo {
223 char userName[MAX_USERNAME_SIZE + 1]; 222 char userName[MAX_USERNAME_SIZE + 1];
224 char *domainName; 223 char *domainName;
225 char *password; 224 char *password;
225 char cryptKey[CIFS_CRYPTO_KEY_SIZE];
226 struct session_key auth_key;
227 char ntlmv2_hash[16];
226 unsigned int tilen; /* length of the target info blob */ 228 unsigned int tilen; /* length of the target info blob */
227 unsigned char *tiblob; /* target info blob in challenge response */ 229 unsigned char *tiblob; /* target info blob in challenge response */
228 bool need_reconnect:1; /* connection reset, uid now invalid */ 230 bool need_reconnect:1; /* connection reset, uid now invalid */
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 54bd83af772c..a420c7b08522 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -503,7 +503,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
503 503
504 if (rsp->EncryptionKeyLength == 504 if (rsp->EncryptionKeyLength ==
505 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) { 505 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
506 memcpy(server->cryptKey, rsp->EncryptionKey, 506 memcpy(ses->cryptKey, rsp->EncryptionKey,
507 CIFS_CRYPTO_KEY_SIZE); 507 CIFS_CRYPTO_KEY_SIZE);
508 } else if (server->secMode & SECMODE_PW_ENCRYPT) { 508 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
509 rc = -EIO; /* need cryptkey unless plain text */ 509 rc = -EIO; /* need cryptkey unless plain text */
@@ -574,7 +574,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
574 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone); 574 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
575 server->timeAdj *= 60; 575 server->timeAdj *= 60;
576 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { 576 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
577 memcpy(server->cryptKey, pSMBr->u.EncryptionKey, 577 memcpy(ses->cryptKey, pSMBr->u.EncryptionKey,
578 CIFS_CRYPTO_KEY_SIZE); 578 CIFS_CRYPTO_KEY_SIZE);
579 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) 579 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
580 && (pSMBr->EncryptionKeyLength == 0)) { 580 && (pSMBr->EncryptionKeyLength == 0)) {
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 4944fc84d5ef..019f00380d12 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -173,6 +173,8 @@ cifs_reconnect(struct TCP_Server_Info *server)
173 sock_release(server->ssocket); 173 sock_release(server->ssocket);
174 server->ssocket = NULL; 174 server->ssocket = NULL;
175 } 175 }
176 server->sequence_number = 0;
177 server->session_estab = false;
176 178
177 spin_lock(&GlobalMid_Lock); 179 spin_lock(&GlobalMid_Lock);
178 list_for_each(tmp, &server->pending_mid_q) { 180 list_for_each(tmp, &server->pending_mid_q) {
@@ -205,7 +207,6 @@ cifs_reconnect(struct TCP_Server_Info *server)
205 spin_lock(&GlobalMid_Lock); 207 spin_lock(&GlobalMid_Lock);
206 if (server->tcpStatus != CifsExiting) 208 if (server->tcpStatus != CifsExiting)
207 server->tcpStatus = CifsGood; 209 server->tcpStatus = CifsGood;
208 server->sequence_number = 0;
209 spin_unlock(&GlobalMid_Lock); 210 spin_unlock(&GlobalMid_Lock);
210 /* atomic_set(&server->inFlight,0);*/ 211 /* atomic_set(&server->inFlight,0);*/
211 wake_up(&server->response_q); 212 wake_up(&server->response_q);
@@ -1631,6 +1632,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
1631 volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); 1632 volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
1632 memcpy(tcp_ses->server_RFC1001_name, 1633 memcpy(tcp_ses->server_RFC1001_name,
1633 volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); 1634 volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
1635 tcp_ses->session_estab = false;
1634 tcp_ses->sequence_number = 0; 1636 tcp_ses->sequence_number = 0;
1635 INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); 1637 INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
1636 INIT_LIST_HEAD(&tcp_ses->smb_ses_list); 1638 INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
@@ -2983,14 +2985,13 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
2983#ifdef CONFIG_CIFS_WEAK_PW_HASH 2985#ifdef CONFIG_CIFS_WEAK_PW_HASH
2984 if ((global_secflags & CIFSSEC_MAY_LANMAN) && 2986 if ((global_secflags & CIFSSEC_MAY_LANMAN) &&
2985 (ses->server->secType == LANMAN)) 2987 (ses->server->secType == LANMAN))
2986 calc_lanman_hash(tcon->password, ses->server->cryptKey, 2988 calc_lanman_hash(tcon->password, ses->cryptKey,
2987 ses->server->secMode & 2989 ses->server->secMode &
2988 SECMODE_PW_ENCRYPT ? true : false, 2990 SECMODE_PW_ENCRYPT ? true : false,
2989 bcc_ptr); 2991 bcc_ptr);
2990 else 2992 else
2991#endif /* CIFS_WEAK_PW_HASH */ 2993#endif /* CIFS_WEAK_PW_HASH */
2992 SMBNTencrypt(tcon->password, ses->server->cryptKey, 2994 SMBNTencrypt(tcon->password, ses->cryptKey, bcc_ptr);
2993 bcc_ptr);
2994 2995
2995 bcc_ptr += CIFS_SESS_KEY_SIZE; 2996 bcc_ptr += CIFS_SESS_KEY_SIZE;
2996 if (ses->capabilities & CAP_UNICODE) { 2997 if (ses->capabilities & CAP_UNICODE) {
@@ -3175,6 +3176,15 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses,
3175 if (rc) { 3176 if (rc) {
3176 cERROR(1, "Send error in SessSetup = %d", rc); 3177 cERROR(1, "Send error in SessSetup = %d", rc);
3177 } else { 3178 } else {
3179 mutex_lock(&ses->server->srv_mutex);
3180 if (!server->session_estab) {
3181 memcpy(&server->session_key.data,
3182 &ses->auth_key.data, ses->auth_key.len);
3183 server->session_key.len = ses->auth_key.len;
3184 ses->server->session_estab = true;
3185 }
3186 mutex_unlock(&server->srv_mutex);
3187
3178 cFYI(1, "CIFS Session Established successfully"); 3188 cFYI(1, "CIFS Session Established successfully");
3179 spin_lock(&GlobalMid_Lock); 3189 spin_lock(&GlobalMid_Lock);
3180 ses->status = CifsGood; 3190 ses->status = CifsGood;
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index c926e6c7c0c6..2111bed71b1f 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -402,7 +402,7 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
402 return -EINVAL; 402 return -EINVAL;
403 } 403 }
404 404
405 memcpy(ses->server->cryptKey, pblob->Challenge, CIFS_CRYPTO_KEY_SIZE); 405 memcpy(ses->cryptKey, pblob->Challenge, CIFS_CRYPTO_KEY_SIZE);
406 /* BB we could decode pblob->NegotiateFlags; some may be useful */ 406 /* BB we could decode pblob->NegotiateFlags; some may be useful */
407 /* In particular we can examine sign flags */ 407 /* In particular we can examine sign flags */
408 /* BB spec says that if AvId field of MsvAvTimestamp is populated then 408 /* BB spec says that if AvId field of MsvAvTimestamp is populated then
@@ -591,17 +591,12 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
591 int bytes_remaining; 591 int bytes_remaining;
592 struct key *spnego_key = NULL; 592 struct key *spnego_key = NULL;
593 __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ 593 __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
594 bool first_time;
595 int blob_len; 594 int blob_len;
596 char *ntlmsspblob = NULL; 595 char *ntlmsspblob = NULL;
597 596
598 if (ses == NULL) 597 if (ses == NULL)
599 return -EINVAL; 598 return -EINVAL;
600 599
601 read_lock(&cifs_tcp_ses_lock);
602 first_time = is_first_ses_reconnect(ses);
603 read_unlock(&cifs_tcp_ses_lock);
604
605 type = ses->server->secType; 600 type = ses->server->secType;
606 601
607 cFYI(1, "sess setup type %d", type); 602 cFYI(1, "sess setup type %d", type);
@@ -672,7 +667,7 @@ ssetup_ntlmssp_authenticate:
672 /* BB calculate hash with password */ 667 /* BB calculate hash with password */
673 /* and copy into bcc */ 668 /* and copy into bcc */
674 669
675 calc_lanman_hash(ses->password, ses->server->cryptKey, 670 calc_lanman_hash(ses->password, ses->cryptKey,
676 ses->server->secMode & SECMODE_PW_ENCRYPT ? 671 ses->server->secMode & SECMODE_PW_ENCRYPT ?
677 true : false, lnm_session_key); 672 true : false, lnm_session_key);
678 673
@@ -699,15 +694,11 @@ ssetup_ntlmssp_authenticate:
699 cpu_to_le16(CIFS_SESS_KEY_SIZE); 694 cpu_to_le16(CIFS_SESS_KEY_SIZE);
700 695
701 /* calculate session key */ 696 /* calculate session key */
702 SMBNTencrypt(ses->password, ses->server->cryptKey, 697 SMBNTencrypt(ses->password, ses->cryptKey, ntlm_session_key);
703 ntlm_session_key);
704 698
705 if (first_time) /* should this be moved into common code 699 cifs_calculate_session_key(&ses->auth_key,
706 with similar ntlmv2 path? */ 700 ntlm_session_key, ses->password);
707 cifs_calculate_session_key(&ses->server->session_key,
708 ntlm_session_key, ses->password);
709 /* copy session key */ 701 /* copy session key */
710
711 memcpy(bcc_ptr, (char *)ntlm_session_key, CIFS_SESS_KEY_SIZE); 702 memcpy(bcc_ptr, (char *)ntlm_session_key, CIFS_SESS_KEY_SIZE);
712 bcc_ptr += CIFS_SESS_KEY_SIZE; 703 bcc_ptr += CIFS_SESS_KEY_SIZE;
713 memcpy(bcc_ptr, (char *)ntlm_session_key, CIFS_SESS_KEY_SIZE); 704 memcpy(bcc_ptr, (char *)ntlm_session_key, CIFS_SESS_KEY_SIZE);
@@ -794,17 +785,14 @@ ssetup_ntlmssp_authenticate:
794 } 785 }
795 /* bail out if key is too long */ 786 /* bail out if key is too long */
796 if (msg->sesskey_len > 787 if (msg->sesskey_len >
797 sizeof(ses->server->session_key.data.krb5)) { 788 sizeof(ses->auth_key.data.krb5)) {
798 cERROR(1, "Kerberos signing key too long (%u bytes)", 789 cERROR(1, "Kerberos signing key too long (%u bytes)",
799 msg->sesskey_len); 790 msg->sesskey_len);
800 rc = -EOVERFLOW; 791 rc = -EOVERFLOW;
801 goto ssetup_exit; 792 goto ssetup_exit;
802 } 793 }
803 if (first_time) { 794 ses->auth_key.len = msg->sesskey_len;
804 ses->server->session_key.len = msg->sesskey_len; 795 memcpy(ses->auth_key.data.krb5, msg->data, msg->sesskey_len);
805 memcpy(ses->server->session_key.data.krb5,
806 msg->data, msg->sesskey_len);
807 }
808 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; 796 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
809 capabilities |= CAP_EXTENDED_SECURITY; 797 capabilities |= CAP_EXTENDED_SECURITY;
810 pSMB->req.Capabilities = cpu_to_le32(capabilities); 798 pSMB->req.Capabilities = cpu_to_le32(capabilities);