diff options
author | Steve French <sfrench@us.ibm.com> | 2010-08-20 16:42:26 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2010-08-20 16:42:26 -0400 |
commit | 9fbc590860e75785bdaf8b83e48fabfe4d4f7d58 (patch) | |
tree | dccc154927cf1e12c702537b5bc028158b938e21 /fs/cifs/sess.c | |
parent | bf4f12113812ac5be76c5590c6f50c8346f784a4 (diff) |
[CIFS] Fix ntlmv2 auth with ntlmssp
Make ntlmv2 as an authentication mechanism within ntlmssp
instead of ntlmv1.
Parse type 2 response in ntlmssp negotiation to pluck
AV pairs and use them to calculate ntlmv2 response token.
Also, assign domain name from the sever response in type 2
packet of ntlmssp and use that (netbios) domain name in
calculation of response.
Enable cifs/smb signing using rc4 and md5.
Changed name of the structure mac_key to session_key to reflect
the type of key it holds.
Use kernel crypto_shash_* APIs instead of the equivalent cifs functions.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/sess.c')
-rw-r--r-- | fs/cifs/sess.c | 118 |
1 files changed, 89 insertions, 29 deletions
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 0a57cb7db5dd..41fc5328120d 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, | |||
383 | static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, | 383 | static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, |
384 | struct cifsSesInfo *ses) | 384 | struct cifsSesInfo *ses) |
385 | { | 385 | { |
386 | unsigned int tioffset; /* challeng message target info area */ | ||
387 | unsigned int tilen; /* challeng 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,18 @@ 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->server->tilen = tilen; | ||
414 | if (tilen) { | ||
415 | ses->server->tiblob = kmalloc(tilen, GFP_KERNEL); | ||
416 | if (!ses->server->tiblob) { | ||
417 | cERROR(1, "Challenge target info allocation failure"); | ||
418 | return -ENOMEM; | ||
419 | } | ||
420 | memcpy(ses->server->tiblob, bcc_ptr + tioffset, tilen); | ||
421 | } | ||
422 | |||
408 | return 0; | 423 | return 0; |
409 | } | 424 | } |
410 | 425 | ||
@@ -451,10 +466,12 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
451 | struct cifsSesInfo *ses, | 466 | struct cifsSesInfo *ses, |
452 | const struct nls_table *nls_cp, bool first) | 467 | const struct nls_table *nls_cp, bool first) |
453 | { | 468 | { |
469 | int rc; | ||
470 | unsigned int size; | ||
454 | AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer; | 471 | AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer; |
455 | __u32 flags; | 472 | __u32 flags; |
456 | unsigned char *tmp; | 473 | unsigned char *tmp; |
457 | char ntlm_session_key[CIFS_SESS_KEY_SIZE]; | 474 | struct ntlmv2_resp ntlmv2_response = {}; |
458 | 475 | ||
459 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); | 476 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); |
460 | sec_blob->MessageType = NtLmAuthenticate; | 477 | sec_blob->MessageType = NtLmAuthenticate; |
@@ -477,19 +494,25 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
477 | sec_blob->LmChallengeResponse.Length = 0; | 494 | sec_blob->LmChallengeResponse.Length = 0; |
478 | sec_blob->LmChallengeResponse.MaximumLength = 0; | 495 | sec_blob->LmChallengeResponse.MaximumLength = 0; |
479 | 496 | ||
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_mac_key(&ses->server->mac_signing_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); | 497 | sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); |
488 | sec_blob->NtChallengeResponse.Length = cpu_to_le16(CIFS_SESS_KEY_SIZE); | 498 | rc = setup_ntlmv2_rsp(ses, (char *)&ntlmv2_response, nls_cp); |
489 | sec_blob->NtChallengeResponse.MaximumLength = | 499 | if (rc) { |
490 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | 500 | cERROR(1, "error rc: %d during ntlmssp ntlmv2 setup", rc); |
501 | goto setup_ntlmv2_ret; | ||
502 | } | ||
503 | size = sizeof(struct ntlmv2_resp); | ||
504 | memcpy(tmp, (char *)&ntlmv2_response, size); | ||
505 | tmp += size; | ||
506 | if (ses->server->tilen > 0) { | ||
507 | memcpy(tmp, ses->server->tiblob, ses->server->tilen); | ||
508 | tmp += ses->server->tilen; | ||
509 | } else | ||
510 | ses->server->tilen = 0; | ||
491 | 511 | ||
492 | tmp += CIFS_SESS_KEY_SIZE; | 512 | sec_blob->NtChallengeResponse.Length = cpu_to_le16(size + |
513 | ses->server->tilen); | ||
514 | sec_blob->NtChallengeResponse.MaximumLength = | ||
515 | cpu_to_le16(size + ses->server->tilen); | ||
493 | 516 | ||
494 | if (ses->domainName == NULL) { | 517 | if (ses->domainName == NULL) { |
495 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); | 518 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); |
@@ -501,7 +524,6 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
501 | len = cifs_strtoUCS((__le16 *)tmp, ses->domainName, | 524 | len = cifs_strtoUCS((__le16 *)tmp, ses->domainName, |
502 | MAX_USERNAME_SIZE, nls_cp); | 525 | MAX_USERNAME_SIZE, nls_cp); |
503 | len *= 2; /* unicode is 2 bytes each */ | 526 | len *= 2; /* unicode is 2 bytes each */ |
504 | len += 2; /* trailing null */ | ||
505 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); | 527 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); |
506 | sec_blob->DomainName.Length = cpu_to_le16(len); | 528 | sec_blob->DomainName.Length = cpu_to_le16(len); |
507 | sec_blob->DomainName.MaximumLength = cpu_to_le16(len); | 529 | sec_blob->DomainName.MaximumLength = cpu_to_le16(len); |
@@ -518,7 +540,6 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
518 | len = cifs_strtoUCS((__le16 *)tmp, ses->userName, | 540 | len = cifs_strtoUCS((__le16 *)tmp, ses->userName, |
519 | MAX_USERNAME_SIZE, nls_cp); | 541 | MAX_USERNAME_SIZE, nls_cp); |
520 | len *= 2; /* unicode is 2 bytes each */ | 542 | len *= 2; /* unicode is 2 bytes each */ |
521 | len += 2; /* trailing null */ | ||
522 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); | 543 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); |
523 | sec_blob->UserName.Length = cpu_to_le16(len); | 544 | sec_blob->UserName.Length = cpu_to_le16(len); |
524 | sec_blob->UserName.MaximumLength = cpu_to_le16(len); | 545 | sec_blob->UserName.MaximumLength = cpu_to_le16(len); |
@@ -530,9 +551,26 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
530 | sec_blob->WorkstationName.MaximumLength = 0; | 551 | sec_blob->WorkstationName.MaximumLength = 0; |
531 | tmp += 2; | 552 | tmp += 2; |
532 | 553 | ||
533 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); | 554 | if ((ses->server->ntlmssp.server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) && |
534 | sec_blob->SessionKey.Length = 0; | 555 | !calc_seckey(ses->server)) { |
535 | sec_blob->SessionKey.MaximumLength = 0; | 556 | memcpy(tmp, ses->server->ntlmssp.ciphertext, CIFS_CPHTXT_SIZE); |
557 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
558 | sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE); | ||
559 | sec_blob->SessionKey.MaximumLength = | ||
560 | cpu_to_le16(CIFS_CPHTXT_SIZE); | ||
561 | tmp += CIFS_CPHTXT_SIZE; | ||
562 | } else { | ||
563 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
564 | sec_blob->SessionKey.Length = 0; | ||
565 | sec_blob->SessionKey.MaximumLength = 0; | ||
566 | } | ||
567 | |||
568 | ses->server->sequence_number = 0; | ||
569 | |||
570 | setup_ntlmv2_ret: | ||
571 | if (ses->server->tilen > 0) | ||
572 | kfree(ses->server->tiblob); | ||
573 | |||
536 | return tmp - pbuffer; | 574 | return tmp - pbuffer; |
537 | } | 575 | } |
538 | 576 | ||
@@ -546,15 +584,14 @@ static void setup_ntlmssp_neg_req(SESSION_SETUP_ANDX *pSMB, | |||
546 | return; | 584 | return; |
547 | } | 585 | } |
548 | 586 | ||
549 | static int setup_ntlmssp_auth_req(SESSION_SETUP_ANDX *pSMB, | 587 | static int setup_ntlmssp_auth_req(char *ntlmsspblob, |
550 | struct cifsSesInfo *ses, | 588 | struct cifsSesInfo *ses, |
551 | const struct nls_table *nls, bool first_time) | 589 | const struct nls_table *nls, bool first_time) |
552 | { | 590 | { |
553 | int bloblen; | 591 | int bloblen; |
554 | 592 | ||
555 | bloblen = build_ntlmssp_auth_blob(&pSMB->req.SecurityBlob[0], ses, nls, | 593 | bloblen = build_ntlmssp_auth_blob(ntlmsspblob, ses, nls, |
556 | first_time); | 594 | first_time); |
557 | pSMB->req.SecurityBlobLength = cpu_to_le16(bloblen); | ||
558 | 595 | ||
559 | return bloblen; | 596 | return bloblen; |
560 | } | 597 | } |
@@ -580,6 +617,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
580 | struct key *spnego_key = NULL; | 617 | struct key *spnego_key = NULL; |
581 | __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ | 618 | __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ |
582 | bool first_time; | 619 | bool first_time; |
620 | char *ntlmsspblob; | ||
583 | 621 | ||
584 | if (ses == NULL) | 622 | if (ses == NULL) |
585 | return -EINVAL; | 623 | return -EINVAL; |
@@ -690,7 +728,7 @@ ssetup_ntlmssp_authenticate: | |||
690 | 728 | ||
691 | if (first_time) /* should this be moved into common code | 729 | if (first_time) /* should this be moved into common code |
692 | with similar ntlmv2 path? */ | 730 | with similar ntlmv2 path? */ |
693 | cifs_calculate_mac_key(&ses->server->mac_signing_key, | 731 | cifs_calculate_session_key(&ses->server->session_key, |
694 | ntlm_session_key, ses->password); | 732 | ntlm_session_key, ses->password); |
695 | /* copy session key */ | 733 | /* copy session key */ |
696 | 734 | ||
@@ -729,12 +767,21 @@ ssetup_ntlmssp_authenticate: | |||
729 | cpu_to_le16(sizeof(struct ntlmv2_resp)); | 767 | cpu_to_le16(sizeof(struct ntlmv2_resp)); |
730 | 768 | ||
731 | /* calculate session key */ | 769 | /* calculate session key */ |
732 | setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); | 770 | rc = setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); |
771 | if (rc) { | ||
772 | kfree(v2_sess_key); | ||
773 | goto ssetup_exit; | ||
774 | } | ||
733 | /* FIXME: calculate MAC key */ | 775 | /* FIXME: calculate MAC key */ |
734 | memcpy(bcc_ptr, (char *)v2_sess_key, | 776 | memcpy(bcc_ptr, (char *)v2_sess_key, |
735 | sizeof(struct ntlmv2_resp)); | 777 | sizeof(struct ntlmv2_resp)); |
736 | bcc_ptr += sizeof(struct ntlmv2_resp); | 778 | bcc_ptr += sizeof(struct ntlmv2_resp); |
737 | kfree(v2_sess_key); | 779 | kfree(v2_sess_key); |
780 | if (ses->server->tilen > 0) { | ||
781 | memcpy(bcc_ptr, ses->server->tiblob, | ||
782 | ses->server->tilen); | ||
783 | bcc_ptr += ses->server->tilen; | ||
784 | } | ||
738 | if (ses->capabilities & CAP_UNICODE) { | 785 | if (ses->capabilities & CAP_UNICODE) { |
739 | if (iov[0].iov_len % 2) { | 786 | if (iov[0].iov_len % 2) { |
740 | *bcc_ptr = 0; | 787 | *bcc_ptr = 0; |
@@ -765,15 +812,15 @@ ssetup_ntlmssp_authenticate: | |||
765 | } | 812 | } |
766 | /* bail out if key is too long */ | 813 | /* bail out if key is too long */ |
767 | if (msg->sesskey_len > | 814 | if (msg->sesskey_len > |
768 | sizeof(ses->server->mac_signing_key.data.krb5)) { | 815 | sizeof(ses->server->session_key.data.krb5)) { |
769 | cERROR(1, "Kerberos signing key too long (%u bytes)", | 816 | cERROR(1, "Kerberos signing key too long (%u bytes)", |
770 | msg->sesskey_len); | 817 | msg->sesskey_len); |
771 | rc = -EOVERFLOW; | 818 | rc = -EOVERFLOW; |
772 | goto ssetup_exit; | 819 | goto ssetup_exit; |
773 | } | 820 | } |
774 | if (first_time) { | 821 | if (first_time) { |
775 | ses->server->mac_signing_key.len = msg->sesskey_len; | 822 | ses->server->session_key.len = msg->sesskey_len; |
776 | memcpy(ses->server->mac_signing_key.data.krb5, | 823 | memcpy(ses->server->session_key.data.krb5, |
777 | msg->data, msg->sesskey_len); | 824 | msg->data, msg->sesskey_len); |
778 | } | 825 | } |
779 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | 826 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; |
@@ -815,12 +862,26 @@ ssetup_ntlmssp_authenticate: | |||
815 | if (phase == NtLmNegotiate) { | 862 | if (phase == NtLmNegotiate) { |
816 | setup_ntlmssp_neg_req(pSMB, ses); | 863 | setup_ntlmssp_neg_req(pSMB, ses); |
817 | iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); | 864 | iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); |
865 | iov[1].iov_base = &pSMB->req.SecurityBlob[0]; | ||
818 | } else if (phase == NtLmAuthenticate) { | 866 | } else if (phase == NtLmAuthenticate) { |
819 | int blob_len; | 867 | int blob_len; |
820 | blob_len = setup_ntlmssp_auth_req(pSMB, ses, | 868 | ntlmsspblob = kmalloc(5 * |
821 | nls_cp, | 869 | sizeof(struct _AUTHENTICATE_MESSAGE), |
822 | first_time); | 870 | GFP_KERNEL); |
871 | if (!ntlmsspblob) { | ||
872 | cERROR(1, "Can't allocate NTLMSSP"); | ||
873 | rc = -ENOMEM; | ||
874 | goto ssetup_exit; | ||
875 | } | ||
876 | |||
877 | blob_len = setup_ntlmssp_auth_req(ntlmsspblob, | ||
878 | ses, | ||
879 | nls_cp, | ||
880 | first_time); | ||
823 | iov[1].iov_len = blob_len; | 881 | iov[1].iov_len = blob_len; |
882 | iov[1].iov_base = ntlmsspblob; | ||
883 | pSMB->req.SecurityBlobLength = | ||
884 | cpu_to_le16(blob_len); | ||
824 | /* Make sure that we tell the server that we | 885 | /* Make sure that we tell the server that we |
825 | are using the uid that it just gave us back | 886 | are using the uid that it just gave us back |
826 | on the response (challenge) */ | 887 | on the response (challenge) */ |
@@ -830,7 +891,6 @@ ssetup_ntlmssp_authenticate: | |||
830 | rc = -ENOSYS; | 891 | rc = -ENOSYS; |
831 | goto ssetup_exit; | 892 | goto ssetup_exit; |
832 | } | 893 | } |
833 | iov[1].iov_base = &pSMB->req.SecurityBlob[0]; | ||
834 | /* unicode strings must be word aligned */ | 894 | /* unicode strings must be word aligned */ |
835 | if ((iov[0].iov_len + iov[1].iov_len) % 2) { | 895 | if ((iov[0].iov_len + iov[1].iov_len) % 2) { |
836 | *bcc_ptr = 0; | 896 | *bcc_ptr = 0; |