aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/sess.c
diff options
context:
space:
mode:
authorShirish Pargaonkar <shirishpargaonkar@gmail.com>2010-09-18 23:02:18 -0400
committerSteve French <sfrench@us.ibm.com>2010-09-29 15:04:29 -0400
commit2b149f11978b44199954710d32c0eecf6c9efd9c (patch)
treeefd48d4b64fc07a244890d1fced9c767ae4f369b /fs/cifs/sess.c
parent5f98ca9afb9c004f8948c0d40920503de447918a (diff)
cifs NTLMv2/NTLMSSP ntlmv2 within ntlmssp autentication code
Attribue Value (AV) pairs or Target Info (TI) pairs are part of ntlmv2 authentication. Structure ntlmv2_resp had only definition for two av pairs. So removed it, and now allocation of av pairs is dynamic. For servers like Windows 7/2008, av pairs sent by server in challege packet (type 2 in the ntlmssp exchange/negotiation) can vary. Server sends them during ntlmssp negotiation. So when ntlmssp is used as an authentication mechanism, type 2 challenge packet from server has this information. Pluck it and use the entire blob for authenticaiton purpose. If user has not specified, extract (netbios) domain name from the av pairs which is used to calculate ntlmv2 hash. Servers like Windows 7 are particular about the AV pair blob. Servers like Windows 2003, are not very strict about the contents of av pair blob used during ntlmv2 authentication. So when security mechanism such as ntlmv2 is used (not ntlmv2 in ntlmssp), there is no negotiation and so genereate a minimal blob that gets used in ntlmv2 authentication as well as gets sent. Fields tilen and tilbob are session specific. AV pair values are defined. To calculate ntlmv2 response we need ti/av pair blob. For sec mech like ntlmssp, the blob is plucked from type 2 response from the server. From this blob, netbios name of the domain is retrieved, if user has not already provided, to be included in the Target String as part of ntlmv2 hash calculations. For sec mech like ntlmv2, create a minimal, two av pair blob. The allocated blob is freed in case of error. In case there is no error, this blob is used in calculating ntlmv2 response (in CalcNTLMv2_response) and is also copied on the response to the server, and then freed. The type 3 ntlmssp response is prepared on a buffer, 5 * sizeof of struct _AUTHENTICATE_MESSAGE, an empirical value large enough to hold _AUTHENTICATE_MESSAGE plus a blob with max possible 10 values as part of ntlmv2 response and lmv2 keys and domain, user, workstation names etc. Also, kerberos gets selected as a default mechanism if server supports it, over the other security mechanisms. Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/sess.c')
-rw-r--r--fs/cifs/sess.c119
1 files changed, 81 insertions, 38 deletions
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 88820127650e..af18a500f7e0 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -383,6 +383,9 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft,
383static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, 383static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
384 struct cifsSesInfo *ses) 384 struct cifsSesInfo *ses)
385{ 385{
386 unsigned int tioffset; /* challenge message target info area */
387 unsigned int tilen; /* challenge message target info area length */
388
386 CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr; 389 CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr;
387 390
388 if (blob_len < sizeof(CHALLENGE_MESSAGE)) { 391 if (blob_len < sizeof(CHALLENGE_MESSAGE)) {
@@ -405,6 +408,19 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
405 /* 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
406 we must set the MIC field of the AUTHENTICATE_MESSAGE */ 409 we must set the MIC field of the AUTHENTICATE_MESSAGE */
407 410
411 tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset);
412 tilen = cpu_to_le16(pblob->TargetInfoArray.Length);
413 ses->tilen = tilen;
414 if (ses->tilen) {
415 ses->tiblob = kmalloc(tilen, GFP_KERNEL);
416 if (!ses->tiblob) {
417 cERROR(1, "Challenge target info allocation failure");
418 ses->tilen = 0;
419 return -ENOMEM;
420 }
421 memcpy(ses->tiblob, bcc_ptr + tioffset, ses->tilen);
422 }
423
408 return 0; 424 return 0;
409} 425}
410 426
@@ -425,7 +441,7 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
425 /* BB is NTLMV2 session security format easier to use here? */ 441 /* BB is NTLMV2 session security format easier to use here? */
426 flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | 442 flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET |
427 NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | 443 NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
428 NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; 444 NTLMSSP_NEGOTIATE_NTLM;
429 if (ses->server->secMode & 445 if (ses->server->secMode &
430 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) 446 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
431 flags |= NTLMSSP_NEGOTIATE_SIGN; 447 flags |= NTLMSSP_NEGOTIATE_SIGN;
@@ -449,12 +465,14 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
449 This function returns the length of the data in the blob */ 465 This function returns the length of the data in the blob */
450static int build_ntlmssp_auth_blob(unsigned char *pbuffer, 466static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
451 struct cifsSesInfo *ses, 467 struct cifsSesInfo *ses,
452 const struct nls_table *nls_cp, bool first) 468 const struct nls_table *nls_cp)
453{ 469{
470 int rc;
471 unsigned int size;
454 AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer; 472 AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer;
455 __u32 flags; 473 __u32 flags;
456 unsigned char *tmp; 474 unsigned char *tmp;
457 char ntlm_session_key[CIFS_SESS_KEY_SIZE]; 475 struct ntlmv2_resp ntlmv2_response = {};
458 476
459 memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); 477 memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
460 sec_blob->MessageType = NtLmAuthenticate; 478 sec_blob->MessageType = NtLmAuthenticate;
@@ -462,7 +480,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
462 flags = NTLMSSP_NEGOTIATE_56 | 480 flags = NTLMSSP_NEGOTIATE_56 |
463 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO | 481 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO |
464 NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | 482 NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
465 NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; 483 NTLMSSP_NEGOTIATE_NTLM;
466 if (ses->server->secMode & 484 if (ses->server->secMode &
467 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) 485 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
468 flags |= NTLMSSP_NEGOTIATE_SIGN; 486 flags |= NTLMSSP_NEGOTIATE_SIGN;
@@ -477,19 +495,26 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
477 sec_blob->LmChallengeResponse.Length = 0; 495 sec_blob->LmChallengeResponse.Length = 0;
478 sec_blob->LmChallengeResponse.MaximumLength = 0; 496 sec_blob->LmChallengeResponse.MaximumLength = 0;
479 497
480 /* calculate session key, BB what about adding similar ntlmv2 path? */
481 SMBNTencrypt(ses->password, ses->server->cryptKey, ntlm_session_key);
482 if (first)
483 cifs_calculate_session_key(&ses->server->session_key,
484 ntlm_session_key, ses->password);
485
486 memcpy(tmp, ntlm_session_key, CIFS_SESS_KEY_SIZE);
487 sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); 498 sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer);
488 sec_blob->NtChallengeResponse.Length = cpu_to_le16(CIFS_SESS_KEY_SIZE); 499 rc = setup_ntlmv2_rsp(ses, (char *)&ntlmv2_response, nls_cp);
489 sec_blob->NtChallengeResponse.MaximumLength = 500 if (rc) {
490 cpu_to_le16(CIFS_SESS_KEY_SIZE); 501 cERROR(1, "Error %d during NTLMSSP authentication", rc);
502 goto setup_ntlmv2_ret;
503 }
504 size = sizeof(struct ntlmv2_resp);
505 memcpy(tmp, (char *)&ntlmv2_response, size);
506 tmp += size;
507 if (ses->tilen > 0) {
508 memcpy(tmp, ses->tiblob, ses->tilen);
509 tmp += ses->tilen;
510 }
491 511
492 tmp += CIFS_SESS_KEY_SIZE; 512 sec_blob->NtChallengeResponse.Length = cpu_to_le16(size + ses->tilen);
513 sec_blob->NtChallengeResponse.MaximumLength =
514 cpu_to_le16(size + ses->tilen);
515 kfree(ses->tiblob);
516 ses->tiblob = NULL;
517 ses->tilen = 0;
493 518
494 if (ses->domainName == NULL) { 519 if (ses->domainName == NULL) {
495 sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); 520 sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer);
@@ -501,7 +526,6 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
501 len = cifs_strtoUCS((__le16 *)tmp, ses->domainName, 526 len = cifs_strtoUCS((__le16 *)tmp, ses->domainName,
502 MAX_USERNAME_SIZE, nls_cp); 527 MAX_USERNAME_SIZE, nls_cp);
503 len *= 2; /* unicode is 2 bytes each */ 528 len *= 2; /* unicode is 2 bytes each */
504 len += 2; /* trailing null */
505 sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); 529 sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer);
506 sec_blob->DomainName.Length = cpu_to_le16(len); 530 sec_blob->DomainName.Length = cpu_to_le16(len);
507 sec_blob->DomainName.MaximumLength = cpu_to_le16(len); 531 sec_blob->DomainName.MaximumLength = cpu_to_le16(len);
@@ -518,7 +542,6 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
518 len = cifs_strtoUCS((__le16 *)tmp, ses->userName, 542 len = cifs_strtoUCS((__le16 *)tmp, ses->userName,
519 MAX_USERNAME_SIZE, nls_cp); 543 MAX_USERNAME_SIZE, nls_cp);
520 len *= 2; /* unicode is 2 bytes each */ 544 len *= 2; /* unicode is 2 bytes each */
521 len += 2; /* trailing null */
522 sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); 545 sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer);
523 sec_blob->UserName.Length = cpu_to_le16(len); 546 sec_blob->UserName.Length = cpu_to_le16(len);
524 sec_blob->UserName.MaximumLength = cpu_to_le16(len); 547 sec_blob->UserName.MaximumLength = cpu_to_le16(len);
@@ -533,6 +556,8 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
533 sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); 556 sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer);
534 sec_blob->SessionKey.Length = 0; 557 sec_blob->SessionKey.Length = 0;
535 sec_blob->SessionKey.MaximumLength = 0; 558 sec_blob->SessionKey.MaximumLength = 0;
559
560setup_ntlmv2_ret:
536 return tmp - pbuffer; 561 return tmp - pbuffer;
537} 562}
538 563
@@ -545,19 +570,6 @@ static void setup_ntlmssp_neg_req(SESSION_SETUP_ANDX *pSMB,
545 570
546 return; 571 return;
547} 572}
548
549static int setup_ntlmssp_auth_req(SESSION_SETUP_ANDX *pSMB,
550 struct cifsSesInfo *ses,
551 const struct nls_table *nls, bool first_time)
552{
553 int bloblen;
554
555 bloblen = build_ntlmssp_auth_blob(&pSMB->req.SecurityBlob[0], ses, nls,
556 first_time);
557 pSMB->req.SecurityBlobLength = cpu_to_le16(bloblen);
558
559 return bloblen;
560}
561#endif 573#endif
562 574
563int 575int
@@ -580,6 +592,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
580 struct key *spnego_key = NULL; 592 struct key *spnego_key = NULL;
581 __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ 593 __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
582 bool first_time; 594 bool first_time;
595 int blob_len;
596 char *ntlmsspblob = NULL;
583 597
584 if (ses == NULL) 598 if (ses == NULL)
585 return -EINVAL; 599 return -EINVAL;
@@ -729,12 +743,24 @@ ssetup_ntlmssp_authenticate:
729 cpu_to_le16(sizeof(struct ntlmv2_resp)); 743 cpu_to_le16(sizeof(struct ntlmv2_resp));
730 744
731 /* calculate session key */ 745 /* calculate session key */
732 setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); 746 rc = setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp);
733 /* FIXME: calculate MAC key */ 747 if (rc) {
748 cERROR(1, "Error %d during NTLMv2 authentication", rc);
749 kfree(v2_sess_key);
750 goto ssetup_exit;
751 }
734 memcpy(bcc_ptr, (char *)v2_sess_key, 752 memcpy(bcc_ptr, (char *)v2_sess_key,
735 sizeof(struct ntlmv2_resp)); 753 sizeof(struct ntlmv2_resp));
736 bcc_ptr += sizeof(struct ntlmv2_resp); 754 bcc_ptr += sizeof(struct ntlmv2_resp);
737 kfree(v2_sess_key); 755 kfree(v2_sess_key);
756 if (ses->tilen > 0) {
757 memcpy(bcc_ptr, ses->tiblob, ses->tilen);
758 bcc_ptr += ses->tilen;
759 /* we never did allocate ses->domainName to free */
760 kfree(ses->tiblob);
761 ses->tiblob = NULL;
762 ses->tilen = 0;
763 }
738 if (ses->capabilities & CAP_UNICODE) { 764 if (ses->capabilities & CAP_UNICODE) {
739 if (iov[0].iov_len % 2) { 765 if (iov[0].iov_len % 2) {
740 *bcc_ptr = 0; 766 *bcc_ptr = 0;
@@ -815,12 +841,28 @@ ssetup_ntlmssp_authenticate:
815 if (phase == NtLmNegotiate) { 841 if (phase == NtLmNegotiate) {
816 setup_ntlmssp_neg_req(pSMB, ses); 842 setup_ntlmssp_neg_req(pSMB, ses);
817 iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); 843 iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE);
844 iov[1].iov_base = &pSMB->req.SecurityBlob[0];
818 } else if (phase == NtLmAuthenticate) { 845 } else if (phase == NtLmAuthenticate) {
819 int blob_len; 846 /* 5 is an empirical value, large enought to
820 blob_len = setup_ntlmssp_auth_req(pSMB, ses, 847 * hold authenticate message, max 10 of
821 nls_cp, 848 * av paris, doamin,user,workstation mames,
822 first_time); 849 * flags etc..
850 */
851 ntlmsspblob = kmalloc(
852 5*sizeof(struct _AUTHENTICATE_MESSAGE),
853 GFP_KERNEL);
854 if (!ntlmsspblob) {
855 cERROR(1, "Can't allocate NTLMSSP");
856 rc = -ENOMEM;
857 goto ssetup_exit;
858 }
859
860 blob_len = build_ntlmssp_auth_blob(ntlmsspblob,
861 ses, nls_cp);
823 iov[1].iov_len = blob_len; 862 iov[1].iov_len = blob_len;
863 iov[1].iov_base = ntlmsspblob;
864 pSMB->req.SecurityBlobLength =
865 cpu_to_le16(blob_len);
824 /* Make sure that we tell the server that we 866 /* Make sure that we tell the server that we
825 are using the uid that it just gave us back 867 are using the uid that it just gave us back
826 on the response (challenge) */ 868 on the response (challenge) */
@@ -830,7 +872,6 @@ ssetup_ntlmssp_authenticate:
830 rc = -ENOSYS; 872 rc = -ENOSYS;
831 goto ssetup_exit; 873 goto ssetup_exit;
832 } 874 }
833 iov[1].iov_base = &pSMB->req.SecurityBlob[0];
834 /* unicode strings must be word aligned */ 875 /* unicode strings must be word aligned */
835 if ((iov[0].iov_len + iov[1].iov_len) % 2) { 876 if ((iov[0].iov_len + iov[1].iov_len) % 2) {
836 *bcc_ptr = 0; 877 *bcc_ptr = 0;
@@ -931,6 +972,8 @@ ssetup_exit:
931 key_put(spnego_key); 972 key_put(spnego_key);
932 } 973 }
933 kfree(str_area); 974 kfree(str_area);
975 kfree(ntlmsspblob);
976 ntlmsspblob = NULL;
934 if (resp_buf_type == CIFS_SMALL_BUFFER) { 977 if (resp_buf_type == CIFS_SMALL_BUFFER) {
935 cFYI(1, "ssetup freeing small buf %p", iov[0].iov_base); 978 cFYI(1, "ssetup freeing small buf %p", iov[0].iov_base);
936 cifs_small_buf_release(iov[0].iov_base); 979 cifs_small_buf_release(iov[0].iov_base);