diff options
Diffstat (limited to 'fs/cifs/sess.c')
-rw-r--r-- | fs/cifs/sess.c | 119 |
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, | |||
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; /* 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 */ |
450 | static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | 466 | static 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 | |||
560 | setup_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 | |||
549 | static 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 | ||
563 | int | 575 | int |
@@ -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); |