| Index: net/proxy_auth.cc
|
| diff --git a/net/proxy_auth.cc b/net/proxy_auth.cc
|
| deleted file mode 100644
|
| index 96f40a512c66b396af8c37c3c2d6c401000fce59..0000000000000000000000000000000000000000
|
| --- a/net/proxy_auth.cc
|
| +++ /dev/null
|
| @@ -1,419 +0,0 @@
|
| -// Copyright 2008-2009 Google Inc.
|
| -//
|
| -// Licensed under the Apache License, Version 2.0 (the "License");
|
| -// you may not use this file except in compliance with the License.
|
| -// You may obtain a copy of the License at
|
| -//
|
| -// http://www.apache.org/licenses/LICENSE-2.0
|
| -//
|
| -// Unless required by applicable law or agreed to in writing, software
|
| -// distributed under the License is distributed on an "AS IS" BASIS,
|
| -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| -// See the License for the specific language governing permissions and
|
| -// limitations under the License.
|
| -// ========================================================================
|
| -#include "omaha/net/proxy_auth.h"
|
| -#include <atlcom.h>
|
| -#include <pstore.h>
|
| -#include <wincred.h>
|
| -#include <wincrypt.h>
|
| -#include "omaha/base/commontypes.h"
|
| -#include "omaha/base/encrypt.h"
|
| -#include "omaha/base/logging.h"
|
| -#include "omaha/base/smart_handle.h"
|
| -#include "omaha/base/string.h"
|
| -#include "omaha/base/system_info.h"
|
| -#include "omaha/goopdate/cred_dialog.h"
|
| -#include "omaha/third_party/smartany/scoped_any.h"
|
| -
|
| -using omaha::encrypt::EncryptData;
|
| -using omaha::encrypt::DecryptData;
|
| -
|
| -namespace omaha {
|
| -
|
| -static const GUID kPreIE7CredTypeGuid = { 0x5e7e8100, 0x9138, 0x11d1,
|
| - { 0x94, 0x5a, 0x00, 0xc0, 0x4f, 0xc3, 0x08, 0xff } };
|
| -static const GUID kPreIE7CredSubtypeGuid = { 0 };
|
| -
|
| -#define kIE7CredKey "abe2869f-9b47-4cd9-a358-c22904dba7f7"
|
| -
|
| -bool ProxyAuth::IsPromptAllowed() {
|
| - __mutexScope(lock_);
|
| - return prompt_cancelled_ < cancel_prompt_threshold_;
|
| -}
|
| -
|
| -void ProxyAuth::PromptCancelled() {
|
| - __mutexScope(lock_);
|
| - prompt_cancelled_++;
|
| -}
|
| -
|
| -CString ProxyAuth::ExtractProxy(const CString& proxy_settings,
|
| - bool isHttps) {
|
| - if (proxy_settings.IsEmpty()) {
|
| - NET_LOG(L3, (_T("[ProxyAuth::ExtractProxy][Empty settings")));
|
| - return proxy_settings;
|
| - }
|
| -
|
| - int equals_index = String_FindChar(proxy_settings, L'=');
|
| - if (equals_index >= 0) {
|
| - const wchar_t* prefix = L"http=";
|
| - if (isHttps)
|
| - prefix = L"https=";
|
| -
|
| - int prefix_index = String_FindString(proxy_settings, prefix);
|
| - if (prefix_index == -1) {
|
| - // fallback to whatever we've got after an equals sign
|
| - prefix = L"=";
|
| - prefix_index = equals_index;
|
| - }
|
| -
|
| - int first = prefix_index + lstrlen(prefix);
|
| - int length = String_FindChar(proxy_settings, L' ');
|
| - if (length == -1) {
|
| - return proxy_settings.Mid(first);
|
| - } else {
|
| - return proxy_settings.Mid(first, length);
|
| - }
|
| - }
|
| -
|
| - return proxy_settings;
|
| -}
|
| -
|
| -void ProxyAuth::ConfigureProxyAuth(bool is_machine,
|
| - uint32 cancel_prompt_threshold) {
|
| - ASSERT1(cancel_prompt_threshold);
|
| -
|
| - proxy_prompt_is_machine_ = is_machine;
|
| - cancel_prompt_threshold_ = cancel_prompt_threshold;
|
| -}
|
| -
|
| -bool ProxyAuth::PromptUser(const CString& server,
|
| - const ProxyAuthConfig& proxy_auth_config) {
|
| - NET_LOG(L3, (_T("[ProxyAuth::PromptUser][%s][%s]"),
|
| - server, proxy_auth_config.ToString()));
|
| -
|
| - CString user;
|
| - CString pass;
|
| -
|
| - HRESULT hr = LaunchCredentialDialog(
|
| - proxy_prompt_is_machine_,
|
| - proxy_auth_config.parent_hwnd,
|
| - server,
|
| - proxy_auth_config.prompt_caption,
|
| - &user,
|
| - &pass);
|
| -
|
| - if (SUCCEEDED(hr)) {
|
| - AddCred(server, user, pass);
|
| - } else if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) {
|
| - PromptCancelled();
|
| - }
|
| -
|
| - SecureZeroMemory(user.GetBuffer(), user.GetAllocLength() * sizeof(TCHAR));
|
| - SecureZeroMemory(pass.GetBuffer(), pass.GetAllocLength() * sizeof(TCHAR));
|
| -
|
| - return SUCCEEDED(hr);
|
| -}
|
| -
|
| -bool ProxyAuth::GetProxyCredentials(bool allow_ui, bool force_ui,
|
| - const CString& proxy_server,
|
| - const ProxyAuthConfig& proxy_auth_config,
|
| - CString* username, CString* password,
|
| - uint32* auth_scheme) {
|
| - NET_LOG(L3, (_T("[ProxyAuth::GetProxyCredentials][%d][%s]"),
|
| - allow_ui, proxy_auth_config.ToString()));
|
| -
|
| - CString server(proxy_server);
|
| - if (server.IsEmpty()) {
|
| - server = kDefaultProxyServer;
|
| - }
|
| -
|
| - __mutexScope(lock_);
|
| - int i = -1;
|
| - if (!force_ui)
|
| - i = servers_.Find(server);
|
| -
|
| - if (i == -1) {
|
| - if (ReadFromIE7(server) || ReadFromPreIE7(server) ||
|
| - (allow_ui && proxy_auth_config.parent_hwnd && IsPromptAllowed() &&
|
| - PromptUser(server, proxy_auth_config))) {
|
| - i = servers_.GetSize() - 1;
|
| - }
|
| - }
|
| -
|
| - if (i >= 0) {
|
| - ASSERT1(!usernames_[i].IsEmpty() && !passwords_[i].empty());
|
| - std::vector<uint8> decrypted_password;
|
| - HRESULT hr = DecryptData(NULL,
|
| - 0,
|
| - &passwords_[i].front(),
|
| - passwords_[i].size(),
|
| - &decrypted_password);
|
| - if (FAILED(hr)) {
|
| - NET_LOG(LE, (_T("[DecryptData failed][0x%x]"), hr));
|
| - return false;
|
| - }
|
| -
|
| - *username = usernames_[i];
|
| - *password = reinterpret_cast<TCHAR*>(&decrypted_password.front());
|
| - *auth_scheme = auth_schemes_[i];
|
| - }
|
| -
|
| - NET_LOG(L3, (_T("[ProxyAuth::GetProxyCredentials][%d][%s][%s][%d]"),
|
| - i, proxy_server, *username, *auth_scheme));
|
| - return i >= 0;
|
| -}
|
| -
|
| -static bool ParseCredsFromRawBuffer(const BYTE* buffer, const DWORD bytes,
|
| - CString* username, CString* password) {
|
| - ASSERT1(bytes > 0);
|
| - if (bytes <= 0)
|
| - return false;
|
| -
|
| - const char* ascii_buffer = reinterpret_cast<const char*>(buffer);
|
| - const unsigned ascii_length =
|
| - static_cast<const unsigned>(strlen(ascii_buffer));
|
| -
|
| - // The buffer could be ascii or wide characters, so we detect which one it
|
| - // is and copy the ascii characters to a wide string if necessary
|
| - const wchar_t* user_pass = NULL;
|
| - CString temp;
|
| - if (ascii_length == bytes - 1) {
|
| - temp = AnsiToWideString(ascii_buffer, ascii_length);
|
| - user_pass = temp.GetString();
|
| - } else {
|
| - user_pass = reinterpret_cast<const wchar_t*>(buffer);
|
| - }
|
| -
|
| - int colon_pos = String_FindChar(user_pass, L':');
|
| - if (colon_pos >= 0) {
|
| - username->SetString(user_pass, colon_pos);
|
| - password->SetString(user_pass + colon_pos + 1);
|
| - }
|
| -
|
| - return colon_pos >= 0;
|
| -}
|
| -
|
| -void ProxyAuth::AddCred(const CString& server, const CString& username,
|
| - const CString& password) {
|
| - std::vector<uint8> encrypted_password;
|
| - HRESULT hr = EncryptData(NULL,
|
| - 0,
|
| - password,
|
| - (password.GetLength() + 1) * sizeof(TCHAR),
|
| - &encrypted_password);
|
| - if (FAILED(hr)) {
|
| - NET_LOG(LE, (_T("[EncryptData failed][0x%x]"), hr));
|
| - return;
|
| - }
|
| -
|
| - __mutexScope(lock_);
|
| - int i = servers_.Find(server);
|
| - if (i == -1) {
|
| - servers_.Add(server);
|
| - usernames_.Add(username);
|
| - passwords_.Add(encrypted_password);
|
| - auth_schemes_.Add(UNKNOWN_AUTH_SCHEME);
|
| - } else {
|
| - usernames_[i] = username;
|
| - passwords_[i] = encrypted_password;
|
| - auth_schemes_[i] = UNKNOWN_AUTH_SCHEME;
|
| - }
|
| -
|
| - NET_LOG(L3, (_T("[ProxyAuth::AddCred][%s][%s]"), server, username));
|
| -}
|
| -
|
| -HRESULT ProxyAuth::SetProxyAuthScheme(const CString& proxy_server,
|
| - uint32 scheme) {
|
| - CString server(proxy_server);
|
| - if (server.IsEmpty()) {
|
| - server = kDefaultProxyServer;
|
| - }
|
| -
|
| - __mutexScope(lock_);
|
| - int i = servers_.Find(server);
|
| - if (i == -1) {
|
| - NET_LOG(LE, (_T("[ProxyAuth::SetProxyAuthScheme][%s not found]"), server));
|
| - return E_INVALIDARG;
|
| - }
|
| -
|
| - auth_schemes_[i] = scheme;
|
| - NET_LOG(L3, (_T("[ProxyAuth::SetProxyAuthScheme][%s][%s][%d]"),
|
| - server, usernames_[i], scheme));
|
| - return S_OK;
|
| -}
|
| -
|
| -// This approach (the key in particular) comes from a securityfocus posting:
|
| -// http://www.securityfocus.com/archive/1/458115/30/0/threaded
|
| -bool ProxyAuth::ReadFromIE7(const CString& server) {
|
| - scoped_library crypt_lib(::LoadLibrary(L"crypt32.dll"));
|
| - ASSERT1(crypt_lib);
|
| - if (!crypt_lib)
|
| - return false;
|
| -
|
| - typedef BOOL (__stdcall *CryptUnprotectData_type)(DATA_BLOB*, LPWSTR*,
|
| - DATA_BLOB*, PVOID, CRYPTPROTECT_PROMPTSTRUCT*, DWORD, DATA_BLOB*);
|
| - CryptUnprotectData_type CryptUnprotectData_fn =
|
| - reinterpret_cast<CryptUnprotectData_type>(
|
| - GetProcAddress(get(crypt_lib), "CryptUnprotectData"));
|
| - ASSERT1(CryptUnprotectData_fn);
|
| - if (!CryptUnprotectData_fn)
|
| - return false;
|
| -
|
| - // Load CredEnumerate and CredFree dynamically because they don't exist on
|
| - // Win2K and so loading the GoogleDesktopCommon.dll otherwise.
|
| - scoped_library advapi_lib(::LoadLibrary(L"advapi32.dll"));
|
| - ASSERT1(advapi_lib);
|
| - if (!advapi_lib)
|
| - return false;
|
| -
|
| - typedef BOOL (__stdcall *CredEnumerateW_type)(LPCWSTR, DWORD, DWORD*,
|
| - PCREDENTIAL**);
|
| - CredEnumerateW_type CredEnumerateW_fn =
|
| - reinterpret_cast<CredEnumerateW_type>(
|
| - GetProcAddress(get(advapi_lib), "CredEnumerateW"));
|
| - ASSERT1(CredEnumerateW_fn || SystemInfo::IsRunningOnW2K());
|
| - if (!CredEnumerateW_fn)
|
| - return false;
|
| -
|
| - typedef VOID (__stdcall *CredFree_type)(PVOID);
|
| - CredFree_type CredFree_fn = reinterpret_cast<CredFree_type>(
|
| - GetProcAddress(get(advapi_lib), "CredFree"));
|
| - ASSERT1(CredFree_fn || SystemInfo::IsRunningOnW2K());
|
| - if (!CredFree_fn)
|
| - return false;
|
| -
|
| - // Done with dynamically loading methods. CredEnumerate (and CredFree if
|
| - // we didn't return) will have failed to load on Win2K
|
| -
|
| - DATA_BLOB optional_entropy;
|
| -
|
| - char key[ARRAYSIZE(kIE7CredKey)] = kIE7CredKey;
|
| - int16 temp[ARRAYSIZE(key)];
|
| - for (int i = 0; i < ARRAYSIZE(key); ++i)
|
| - temp[i] = static_cast<int16>(key[i] * 4);
|
| -
|
| - optional_entropy.pbData = reinterpret_cast<BYTE*>(&temp);
|
| - optional_entropy.cbData = sizeof(temp);
|
| -
|
| - CString target(NOTRANSL(L"Microsoft_WinInet_"));
|
| - target += server;
|
| - target += L"*";
|
| -
|
| - DWORD count = 0;
|
| - CREDENTIAL** credentials = NULL;
|
| - CString username;
|
| - CString password;
|
| -
|
| - bool found = false;
|
| - if (CredEnumerateW_fn(target, 0, &count, &credentials)) {
|
| - for (unsigned i = 0; i < count; ++i) {
|
| - if (credentials[i]->Type == CRED_TYPE_GENERIC) {
|
| - DATA_BLOB data_in;
|
| - DATA_BLOB data_out = { 0 };
|
| - data_in.pbData = static_cast<BYTE*>(credentials[i]->CredentialBlob);
|
| - data_in.cbData = credentials[i]->CredentialBlobSize;
|
| -
|
| - if (CryptUnprotectData_fn(&data_in, NULL, &optional_entropy, NULL, NULL,
|
| - 0, &data_out)) {
|
| - found = ParseCredsFromRawBuffer(data_out.pbData, data_out.cbData,
|
| - &username, &password);
|
| - LocalFree(data_out.pbData);
|
| - if (found) {
|
| - AddCred(server, username, password);
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - }
|
| - CredFree_fn(credentials);
|
| - }
|
| -
|
| - return found;
|
| -}
|
| -
|
| -bool ProxyAuth::ReadFromPreIE7(const CString& server) {
|
| - scoped_library pstore_lib(::LoadLibrary(L"pstorec.dll"));
|
| - ASSERT1(pstore_lib);
|
| - if (!pstore_lib)
|
| - return false;
|
| -
|
| - typedef HRESULT (__stdcall *PStoreCreateInstance_type)(IPStore**,
|
| - PST_PROVIDERID*, void*, DWORD);
|
| - PStoreCreateInstance_type PStoreCreateInstance_fn =
|
| - reinterpret_cast<PStoreCreateInstance_type>(
|
| - GetProcAddress(get(pstore_lib), "PStoreCreateInstance"));
|
| - ASSERT1(PStoreCreateInstance_fn);
|
| - if (!PStoreCreateInstance_fn)
|
| - return false;
|
| -
|
| - CString username;
|
| - CString password;
|
| - bool found = false;
|
| -
|
| - scoped_co_init initializer(COINIT_APARTMENTTHREADED);
|
| - HRESULT hr = E_FAIL;
|
| -
|
| - // The best reference I found about these iterators, especially how to free
|
| - // the item_name returned by this iterator was a microsoft patent application:
|
| - // http://www.patentstorm.us/patents/6272631-description.html
|
| - CComPtr<IPStore> pstore;
|
| - VERIFY1(SUCCEEDED(hr = PStoreCreateInstance_fn(&pstore, NULL, NULL, 0)));
|
| - if (SUCCEEDED(hr)) {
|
| - CComPtr<IEnumPStoreTypes> enum_types;
|
| - VERIFY1(SUCCEEDED(hr = pstore->EnumTypes(PST_KEY_CURRENT_USER, 0,
|
| - &enum_types)));
|
| - if (SUCCEEDED(hr)) {
|
| - GUID type_guid = { 0 };
|
| - // Get the types one at a time
|
| - while (enum_types->Next(1, &type_guid, NULL) == S_OK) {
|
| - if (type_guid != kPreIE7CredTypeGuid)
|
| - continue;
|
| -
|
| - CComPtr<IEnumPStoreTypes> enum_subtypes;
|
| - VERIFY1(SUCCEEDED(hr = pstore->EnumSubtypes(PST_KEY_CURRENT_USER,
|
| - &type_guid, 0, &enum_subtypes)));
|
| - if (SUCCEEDED(hr)) {
|
| - GUID subtype_guid = { 0 };
|
| - // Get the subtypes one at a time
|
| - while (enum_subtypes->Next(1, &subtype_guid, NULL) == S_OK) {
|
| - if (subtype_guid != kPreIE7CredSubtypeGuid)
|
| - continue;
|
| -
|
| - CComPtr<IEnumPStoreItems> enum_items;
|
| - VERIFY1(SUCCEEDED(hr = pstore->EnumItems(PST_KEY_CURRENT_USER,
|
| - &type_guid, &subtype_guid, 0, &enum_items)));
|
| - if (SUCCEEDED(hr)) {
|
| - wchar_t* item_name = NULL;
|
| - // Get the items one at a time
|
| - while (enum_items->Next(1, &item_name, NULL) == S_OK) {
|
| - DWORD data_length = 0;
|
| - byte* data = NULL;
|
| -
|
| - VERIFY1(SUCCEEDED(hr = pstore->ReadItem(PST_KEY_CURRENT_USER,
|
| - &type_guid, &subtype_guid, item_name, &data_length, &data,
|
| - NULL, 0)));
|
| - if (SUCCEEDED(hr)) {
|
| - found = ParseCredsFromRawBuffer(data, data_length,
|
| - &username, &password);
|
| - CoTaskMemFree(data);
|
| - }
|
| -
|
| - CoTaskMemFree(item_name);
|
| - if (found) {
|
| - AddCred(server, username, password);
|
| - break;
|
| - }
|
| - } // end enum_items loop
|
| - }
|
| - } // end enum_subtypes loop
|
| - }
|
| - } // end enum_types loop
|
| - }
|
| - }
|
| -
|
| - return found;
|
| -}
|
| -
|
| -} // namespace omaha
|
| -
|
|
|