OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/http/http_auth_handler_ntlm.h" | 5 #include "net/http/http_auth_handler_ntlm.h" |
6 | 6 |
7 #include <stdlib.h> | 7 #include <stdlib.h> |
8 // For gethostname | 8 // For gethostname |
9 #if defined(OS_POSIX) | 9 #if defined(OS_POSIX) |
10 #include <unistd.h> | 10 #include <unistd.h> |
11 #elif defined(OS_WIN) | 11 #elif defined(OS_WIN) |
12 #include <winsock2.h> | 12 #include <winsock2.h> |
13 #endif | 13 #endif |
14 | 14 |
15 #include "base/md5.h" | 15 #include "base/md5.h" |
16 #include "base/rand_util.h" | 16 #include "base/rand_util.h" |
17 #include "base/string_util.h" | 17 #include "base/string_util.h" |
18 #include "base/sys_string_conversions.h" | 18 #include "base/sys_string_conversions.h" |
19 #include "net/base/base64.h" | 19 #include "net/base/base64.h" |
20 #include "net/base/net_errors.h" | 20 #include "net/base/net_errors.h" |
| 21 #include "net/base/net_util.h" |
21 #include "net/http/des.h" | 22 #include "net/http/des.h" |
22 #include "net/http/md4.h" | 23 #include "net/http/md4.h" |
23 | 24 |
24 namespace net { | 25 namespace net { |
25 | 26 |
26 // Based on mozilla/security/manager/ssl/src/nsNTLMAuthModule.cpp, | 27 // Based on mozilla/security/manager/ssl/src/nsNTLMAuthModule.cpp, |
27 // CVS rev. 1.14. | 28 // CVS rev. 1.14. |
28 // | 29 // |
29 // TODO(wtc): | 30 // TODO(wtc): |
30 // - The IS_BIG_ENDIAN code is not tested. | 31 // - The IS_BIG_ENDIAN code is not tested. |
(...skipping 401 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
432 // so we can ignore target information. We may want to enable | 433 // so we can ignore target information. We may want to enable |
433 // support for these alternate mechanisms in the future. | 434 // support for these alternate mechanisms in the future. |
434 return OK; | 435 return OK; |
435 } | 436 } |
436 | 437 |
437 static void GenerateRandom(uint8* output, size_t n) { | 438 static void GenerateRandom(uint8* output, size_t n) { |
438 for (size_t i = 0; i < n; ++i) | 439 for (size_t i = 0; i < n; ++i) |
439 output[i] = base::RandInt(0, 255); | 440 output[i] = base::RandInt(0, 255); |
440 } | 441 } |
441 | 442 |
442 static void GetHostName(char* name, size_t namelen) { | |
443 if (gethostname(name, namelen) != 0) | |
444 name[0] = '\0'; | |
445 } | |
446 | |
447 // TODO(wtc): these two function pointers should become static members of | |
448 // HttpAuthHandlerNTLM. They are file-scope static variables now so that | |
449 // GenerateType3Msg can use them without being a friend function. We should | |
450 // have HttpAuthHandlerNTLM absorb NTLMAuthModule and pass the host name and | |
451 // random bytes as input arguments to GenerateType3Msg. | |
452 static HttpAuthHandlerNTLM::GenerateRandomProc generate_random_proc_ = | |
453 GenerateRandom; | |
454 static HttpAuthHandlerNTLM::HostNameProc get_host_name_proc_ = GetHostName; | |
455 | |
456 // Returns OK or a network error code. | 443 // Returns OK or a network error code. |
457 static int GenerateType3Msg(const string16& domain, | 444 static int GenerateType3Msg(const string16& domain, |
458 const string16& username, | 445 const string16& username, |
459 const string16& password, | 446 const string16& password, |
460 const void* in_buf, | 447 const std::string& hostname, |
461 uint32 in_len, | 448 const void* rand_8_bytes, |
462 void** out_buf, | 449 const void* in_buf, |
463 uint32* out_len) { | 450 uint32 in_len, |
| 451 void** out_buf, |
| 452 uint32* out_len) { |
464 // in_buf contains Type-2 msg (the challenge) from server. | 453 // in_buf contains Type-2 msg (the challenge) from server. |
465 | 454 |
466 int rv; | 455 int rv; |
467 Type2Msg msg; | 456 Type2Msg msg; |
468 | 457 |
469 rv = ParseType2Msg(in_buf, in_len, &msg); | 458 rv = ParseType2Msg(in_buf, in_len, &msg); |
470 if (rv != OK) | 459 if (rv != OK) |
471 return rv; | 460 return rv; |
472 | 461 |
473 bool unicode = (msg.flags & NTLM_NegotiateUnicode) != 0; | 462 bool unicode = (msg.flags & NTLM_NegotiateUnicode) != 0; |
474 | 463 |
475 // Temporary buffers for unicode strings | 464 // Temporary buffers for unicode strings |
476 #ifdef IS_BIG_ENDIAN | 465 #ifdef IS_BIG_ENDIAN |
477 string16 ucs_domain_buf, ucs_user_buf; | 466 string16 ucs_domain_buf, ucs_user_buf; |
478 #endif | 467 #endif |
479 string16 ucs_host_buf; | 468 string16 ucs_host_buf; |
480 // Temporary buffers for oem strings | 469 // Temporary buffers for oem strings |
481 std::string oem_domain_buf, oem_user_buf, oem_host_buf; | 470 std::string oem_domain_buf, oem_user_buf; |
482 // Pointers and lengths for the string buffers; encoding is unicode if | 471 // Pointers and lengths for the string buffers; encoding is unicode if |
483 // the "negotiate unicode" flag was set in the Type-2 message. | 472 // the "negotiate unicode" flag was set in the Type-2 message. |
484 const void* domain_ptr; | 473 const void* domain_ptr; |
485 const void* user_ptr; | 474 const void* user_ptr; |
486 const void* host_ptr; | 475 const void* host_ptr; |
487 uint32 domain_len, user_len, host_len; | 476 uint32 domain_len, user_len, host_len; |
488 | 477 |
489 // | 478 // |
490 // Get domain name. | 479 // Get domain name. |
491 // | 480 // |
(...skipping 30 matching lines...) Expand all Loading... |
522 #endif | 511 #endif |
523 } else { | 512 } else { |
524 oem_user_buf = base::SysWideToNativeMB(UTF16ToWide(username)); | 513 oem_user_buf = base::SysWideToNativeMB(UTF16ToWide(username)); |
525 user_ptr = oem_user_buf.data(); | 514 user_ptr = oem_user_buf.data(); |
526 user_len = oem_user_buf.length(); | 515 user_len = oem_user_buf.length(); |
527 } | 516 } |
528 | 517 |
529 // | 518 // |
530 // Get workstation name (use local machine's hostname). | 519 // Get workstation name (use local machine's hostname). |
531 // | 520 // |
532 char host_buf[256]; // Host names are limited to 255 bytes. | |
533 get_host_name_proc_(host_buf, sizeof(host_buf)); | |
534 host_len = strlen(host_buf); | |
535 if (host_len == 0) | |
536 return ERR_UNEXPECTED; | |
537 if (unicode) { | 521 if (unicode) { |
538 // hostname is ASCII, so we can do a simple zero-pad expansion: | 522 // hostname is ASCII, so we can do a simple zero-pad expansion: |
539 ucs_host_buf.assign(host_buf, host_buf + host_len); | 523 ucs_host_buf.assign(hostname.begin(), hostname.end()); |
540 host_ptr = ucs_host_buf.data(); | 524 host_ptr = ucs_host_buf.data(); |
541 host_len = ucs_host_buf.length() * 2; | 525 host_len = ucs_host_buf.length() * 2; |
542 #ifdef IS_BIG_ENDIAN | 526 #ifdef IS_BIG_ENDIAN |
543 WriteUnicodeLE(const_cast<void*>(host_ptr), (const char16*) host_ptr, | 527 WriteUnicodeLE(const_cast<void*>(host_ptr), (const char16*) host_ptr, |
544 ucs_host_buf.length()); | 528 ucs_host_buf.length()); |
545 #endif | 529 #endif |
546 } else { | 530 } else { |
547 host_ptr = host_buf; | 531 host_ptr = hostname.data(); |
| 532 host_len = hostname.length(); |
548 } | 533 } |
549 | 534 |
550 // | 535 // |
551 // Now that we have generated all of the strings, we can allocate out_buf. | 536 // Now that we have generated all of the strings, we can allocate out_buf. |
552 // | 537 // |
553 *out_len = NTLM_TYPE3_HEADER_LEN + host_len + domain_len + user_len + | 538 *out_len = NTLM_TYPE3_HEADER_LEN + host_len + domain_len + user_len + |
554 LM_RESP_LEN + NTLM_RESP_LEN; | 539 LM_RESP_LEN + NTLM_RESP_LEN; |
555 *out_buf = malloc(*out_len); | 540 *out_buf = malloc(*out_len); |
556 if (!*out_buf) | 541 if (!*out_buf) |
557 return ERR_OUT_OF_MEMORY; | 542 return ERR_OUT_OF_MEMORY; |
558 | 543 |
559 // | 544 // |
560 // Next, we compute the LM and NTLM responses. | 545 // Next, we compute the LM and NTLM responses. |
561 // | 546 // |
562 uint8 lm_resp[LM_RESP_LEN]; | 547 uint8 lm_resp[LM_RESP_LEN]; |
563 uint8 ntlm_resp[NTLM_RESP_LEN]; | 548 uint8 ntlm_resp[NTLM_RESP_LEN]; |
564 uint8 ntlm_hash[NTLM_HASH_LEN]; | 549 uint8 ntlm_hash[NTLM_HASH_LEN]; |
565 if (msg.flags & NTLM_NegotiateNTLM2Key) { | 550 if (msg.flags & NTLM_NegotiateNTLM2Key) { |
566 // compute NTLM2 session response | 551 // compute NTLM2 session response |
567 MD5Digest session_hash; | 552 MD5Digest session_hash; |
568 uint8 temp[16]; | 553 uint8 temp[16]; |
569 | 554 |
570 generate_random_proc_(lm_resp, 8); | 555 memcpy(lm_resp, rand_8_bytes, 8); |
571 memset(lm_resp + 8, 0, LM_RESP_LEN - 8); | 556 memset(lm_resp + 8, 0, LM_RESP_LEN - 8); |
572 | 557 |
573 memcpy(temp, msg.challenge, 8); | 558 memcpy(temp, msg.challenge, 8); |
574 memcpy(temp + 8, lm_resp, 8); | 559 memcpy(temp + 8, lm_resp, 8); |
575 MD5Sum(temp, 16, &session_hash); | 560 MD5Sum(temp, 16, &session_hash); |
576 | 561 |
577 NTLM_Hash(password, ntlm_hash); | 562 NTLM_Hash(password, ntlm_hash); |
578 LM_Response(ntlm_hash, session_hash.a, ntlm_resp); | 563 LM_Response(ntlm_hash, session_hash.a, ntlm_resp); |
579 } else { | 564 } else { |
580 NTLM_Hash(password, ntlm_hash); | 565 NTLM_Hash(password, ntlm_hash); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
631 | 616 |
632 // 52 : session key sec buf (not used) | 617 // 52 : session key sec buf (not used) |
633 cursor = WriteSecBuf(cursor, 0, 0); | 618 cursor = WriteSecBuf(cursor, 0, 0); |
634 | 619 |
635 // 60 : negotiated flags | 620 // 60 : negotiated flags |
636 cursor = WriteDWORD(cursor, msg.flags & NTLM_TYPE1_FLAGS); | 621 cursor = WriteDWORD(cursor, msg.flags & NTLM_TYPE1_FLAGS); |
637 | 622 |
638 return OK; | 623 return OK; |
639 } | 624 } |
640 | 625 |
641 //----------------------------------------------------------------------------- | |
642 | |
643 class NTLMAuthModule { | |
644 public: | |
645 NTLMAuthModule() {} | |
646 | |
647 ~NTLMAuthModule(); | |
648 | |
649 int Init(const string16& domain, | |
650 const string16& username, | |
651 const string16& password); | |
652 | |
653 int GetNextToken(const void* in_token, | |
654 uint32 in_token_len, | |
655 void** out_token, | |
656 uint32* out_token_len); | |
657 | |
658 private: | |
659 string16 domain_; | |
660 string16 username_; | |
661 string16 password_; | |
662 }; | |
663 | |
664 NTLMAuthModule::~NTLMAuthModule() { | |
665 ZapString(&password_); | |
666 } | |
667 | |
668 int NTLMAuthModule::Init(const string16& domain, | |
669 const string16& username, | |
670 const string16& password) { | |
671 domain_ = domain; | |
672 username_ = username; | |
673 password_ = password; | |
674 return OK; | |
675 } | |
676 | |
677 int NTLMAuthModule::GetNextToken(const void* in_token, | |
678 uint32 in_token_len, | |
679 void** out_token, | |
680 uint32* out_token_len) { | |
681 int rv; | |
682 | |
683 // If in_token is non-null, then assume it contains a type 2 message... | |
684 if (in_token) { | |
685 LogToken("in-token", in_token, in_token_len); | |
686 rv = GenerateType3Msg(domain_, username_, password_, in_token, | |
687 in_token_len, out_token, out_token_len); | |
688 } else { | |
689 rv = GenerateType1Msg(out_token, out_token_len); | |
690 } | |
691 | |
692 if (rv == OK) | |
693 LogToken("out-token", *out_token, *out_token_len); | |
694 | |
695 return rv; | |
696 } | |
697 | |
698 // NTLM authentication is specified in "NTLM Over HTTP Protocol Specification" | 626 // NTLM authentication is specified in "NTLM Over HTTP Protocol Specification" |
699 // [MS-NTHT]. | 627 // [MS-NTHT]. |
700 | 628 |
701 HttpAuthHandlerNTLM::HttpAuthHandlerNTLM() | 629 // static |
702 : ntlm_module_(new NTLMAuthModule) { | 630 HttpAuthHandlerNTLM::GenerateRandomProc |
| 631 HttpAuthHandlerNTLM::generate_random_proc_ = GenerateRandom; |
| 632 |
| 633 // static |
| 634 HttpAuthHandlerNTLM::HostNameProc |
| 635 HttpAuthHandlerNTLM::get_host_name_proc_ = GetMyHostName; |
| 636 |
| 637 HttpAuthHandlerNTLM::HttpAuthHandlerNTLM() { |
703 } | 638 } |
704 | 639 |
705 HttpAuthHandlerNTLM::~HttpAuthHandlerNTLM() { | 640 HttpAuthHandlerNTLM::~HttpAuthHandlerNTLM() { |
| 641 // Wipe our copy of the password from memory, to reduce the chance of being |
| 642 // written to the paging file on disk. |
| 643 ZapString(&password_); |
706 } | 644 } |
707 | 645 |
708 bool HttpAuthHandlerNTLM::NeedsIdentity() { | 646 bool HttpAuthHandlerNTLM::NeedsIdentity() { |
709 return !auth_data_.empty(); | 647 return !auth_data_.empty(); |
710 } | 648 } |
711 | 649 |
712 std::string HttpAuthHandlerNTLM::GenerateCredentials( | 650 std::string HttpAuthHandlerNTLM::GenerateCredentials( |
713 const std::wstring& username, | 651 const std::wstring& username, |
714 const std::wstring& password, | 652 const std::wstring& password, |
715 const HttpRequestInfo* request, | 653 const HttpRequestInfo* request, |
716 const ProxyInfo* proxy) { | 654 const ProxyInfo* proxy) { |
717 int rv; | |
718 // TODO(wtc): See if we can use char* instead of void* for in_buf and | 655 // TODO(wtc): See if we can use char* instead of void* for in_buf and |
719 // out_buf. This change will need to propagate to GetNextToken, | 656 // out_buf. This change will need to propagate to GetNextToken, |
720 // GenerateType1Msg, and GenerateType3Msg, and perhaps further. | 657 // GenerateType1Msg, and GenerateType3Msg, and perhaps further. |
721 const void* in_buf; | 658 const void* in_buf; |
722 void* out_buf; | 659 void* out_buf; |
723 uint32 in_buf_len, out_buf_len; | 660 uint32 in_buf_len, out_buf_len; |
724 std::string decoded_auth_data; | 661 std::string decoded_auth_data; |
725 | 662 |
726 // |username| may be in the form "DOMAIN\user". Parse it into the two | 663 // |username| may be in the form "DOMAIN\user". Parse it into the two |
727 // components. | 664 // components. |
728 std::wstring domain; | 665 std::wstring domain; |
729 std::wstring user; | 666 std::wstring user; |
730 size_t backslash_idx = username.find(L'\\'); | 667 size_t backslash_idx = username.find(L'\\'); |
731 if (backslash_idx == std::wstring::npos) { | 668 if (backslash_idx == std::wstring::npos) { |
732 user = username; | 669 user = username; |
733 } else { | 670 } else { |
734 domain = username.substr(0, backslash_idx); | 671 domain = username.substr(0, backslash_idx); |
735 user = username.substr(backslash_idx + 1); | 672 user = username.substr(backslash_idx + 1); |
736 } | 673 } |
737 rv = ntlm_module_->Init(WideToUTF16(domain), WideToUTF16(user), | 674 domain_ = WideToUTF16(domain); |
738 WideToUTF16(password)); | 675 username_ = WideToUTF16(user); |
| 676 password_ = WideToUTF16(password); |
739 | 677 |
740 // Initial challenge. | 678 // Initial challenge. |
741 if (auth_data_.empty()) { | 679 if (auth_data_.empty()) { |
742 in_buf_len = 0; | 680 in_buf_len = 0; |
743 in_buf = NULL; | 681 in_buf = NULL; |
744 } else { | 682 } else { |
745 // Decode |auth_data_| into the input buffer. | 683 // Decode |auth_data_| into the input buffer. |
746 int len = auth_data_.length(); | 684 int len = auth_data_.length(); |
747 | 685 |
748 // Strip off any padding. | 686 // Strip off any padding. |
749 // (See https://bugzilla.mozilla.org/show_bug.cgi?id=230351.) | 687 // (See https://bugzilla.mozilla.org/show_bug.cgi?id=230351.) |
750 // | 688 // |
751 // Our base64 decoder requires that the length be a multiple of 4. | 689 // Our base64 decoder requires that the length be a multiple of 4. |
752 while (len > 0 && len % 4 != 0 && auth_data_[len - 1] == '=') | 690 while (len > 0 && len % 4 != 0 && auth_data_[len - 1] == '=') |
753 len--; | 691 len--; |
754 auth_data_.erase(len); | 692 auth_data_.erase(len); |
755 | 693 |
756 if (!Base64Decode(auth_data_, &decoded_auth_data)) | 694 if (!Base64Decode(auth_data_, &decoded_auth_data)) |
757 return std::string(); // Improper base64 encoding | 695 return std::string(); // Improper base64 encoding |
758 in_buf_len = decoded_auth_data.length(); | 696 in_buf_len = decoded_auth_data.length(); |
759 in_buf = decoded_auth_data.data(); | 697 in_buf = decoded_auth_data.data(); |
760 } | 698 } |
761 | 699 |
762 rv = ntlm_module_->GetNextToken(in_buf, in_buf_len, &out_buf, &out_buf_len); | 700 int rv = GetNextToken(in_buf, in_buf_len, &out_buf, &out_buf_len); |
763 if (rv != OK) | 701 if (rv != OK) |
764 return std::string(); | 702 return std::string(); |
765 | 703 |
766 // Base64 encode data in output buffer and prepend "NTLM ". | 704 // Base64 encode data in output buffer and prepend "NTLM ". |
767 std::string encode_input(static_cast<char*>(out_buf), out_buf_len); | 705 std::string encode_input(static_cast<char*>(out_buf), out_buf_len); |
768 std::string encode_output; | 706 std::string encode_output; |
769 bool ok = Base64Encode(encode_input, &encode_output); | 707 bool ok = Base64Encode(encode_input, &encode_output); |
770 // OK, we are done with |out_buf| | 708 // OK, we are done with |out_buf| |
771 free(out_buf); | 709 free(out_buf); |
772 if (!ok) | 710 if (!ok) |
773 return std::string(); | 711 return std::string(); |
774 return std::string("NTLM ") + encode_output; | 712 return std::string("NTLM ") + encode_output; |
775 } | 713 } |
776 | 714 |
777 // static | 715 // static |
778 void HttpAuthHandlerNTLM::SetGenerateRandomProc(GenerateRandomProc proc) { | 716 HttpAuthHandlerNTLM::GenerateRandomProc |
| 717 HttpAuthHandlerNTLM::SetGenerateRandomProc( |
| 718 GenerateRandomProc proc) { |
| 719 GenerateRandomProc old_proc = generate_random_proc_; |
779 generate_random_proc_ = proc; | 720 generate_random_proc_ = proc; |
| 721 return old_proc; |
780 } | 722 } |
781 | 723 |
782 // static | 724 // static |
783 void HttpAuthHandlerNTLM::SetHostNameProc(HostNameProc proc) { | 725 HttpAuthHandlerNTLM::HostNameProc HttpAuthHandlerNTLM::SetHostNameProc( |
| 726 HostNameProc proc) { |
| 727 HostNameProc old_proc = get_host_name_proc_; |
784 get_host_name_proc_ = proc; | 728 get_host_name_proc_ = proc; |
| 729 return old_proc; |
785 } | 730 } |
786 | 731 |
787 // The NTLM challenge header looks like: | 732 // The NTLM challenge header looks like: |
788 // WWW-Authenticate: NTLM auth-data | 733 // WWW-Authenticate: NTLM auth-data |
789 bool HttpAuthHandlerNTLM::ParseChallenge( | 734 bool HttpAuthHandlerNTLM::ParseChallenge( |
790 std::string::const_iterator challenge_begin, | 735 std::string::const_iterator challenge_begin, |
791 std::string::const_iterator challenge_end) { | 736 std::string::const_iterator challenge_end) { |
792 scheme_ = "ntlm"; | 737 scheme_ = "ntlm"; |
793 score_ = 3; | 738 score_ = 3; |
794 properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED; | 739 properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED; |
795 auth_data_.clear(); | 740 auth_data_.clear(); |
796 | 741 |
797 // Verify the challenge's auth-scheme. | 742 // Verify the challenge's auth-scheme. |
798 HttpAuth::ChallengeTokenizer challenge_tok(challenge_begin, challenge_end); | 743 HttpAuth::ChallengeTokenizer challenge_tok(challenge_begin, challenge_end); |
799 if (!challenge_tok.valid() || | 744 if (!challenge_tok.valid() || |
800 !LowerCaseEqualsASCII(challenge_tok.scheme(), "ntlm")) | 745 !LowerCaseEqualsASCII(challenge_tok.scheme(), "ntlm")) |
801 return false; | 746 return false; |
802 | 747 |
803 // Extract the auth-data. We can't use challenge_tok.GetNext() because | 748 // Extract the auth-data. We can't use challenge_tok.GetNext() because |
804 // auth-data is base64-encoded and may contain '=' padding at the end, | 749 // auth-data is base64-encoded and may contain '=' padding at the end, |
805 // which would be mistaken for a name=value pair. | 750 // which would be mistaken for a name=value pair. |
806 challenge_begin += 4; // Skip over "NTLM". | 751 challenge_begin += 4; // Skip over "NTLM". |
807 HttpUtil::TrimLWS(&challenge_begin, &challenge_end); | 752 HttpUtil::TrimLWS(&challenge_begin, &challenge_end); |
808 | 753 |
809 auth_data_.assign(challenge_begin, challenge_end); | 754 auth_data_.assign(challenge_begin, challenge_end); |
810 | 755 |
811 return true; | 756 return true; |
812 } | 757 } |
813 | 758 |
| 759 int HttpAuthHandlerNTLM::GetNextToken(const void* in_token, |
| 760 uint32 in_token_len, |
| 761 void** out_token, |
| 762 uint32* out_token_len) { |
| 763 int rv; |
| 764 |
| 765 // If in_token is non-null, then assume it contains a type 2 message... |
| 766 if (in_token) { |
| 767 LogToken("in-token", in_token, in_token_len); |
| 768 std::string hostname = get_host_name_proc_(); |
| 769 if (hostname.empty()) |
| 770 return ERR_UNEXPECTED; |
| 771 uint8 rand_buf[8]; |
| 772 generate_random_proc_(rand_buf, 8); |
| 773 rv = GenerateType3Msg(domain_, username_, password_, hostname, rand_buf, |
| 774 in_token, in_token_len, out_token, out_token_len); |
| 775 } else { |
| 776 rv = GenerateType1Msg(out_token, out_token_len); |
| 777 } |
| 778 |
| 779 if (rv == OK) |
| 780 LogToken("out-token", *out_token, *out_token_len); |
| 781 |
| 782 return rv; |
| 783 } |
| 784 |
814 } // namespace net | 785 } // namespace net |
OLD | NEW |