Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1026)

Side by Side Diff: net/proxy_auth.cc

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/proxy_auth.h ('k') | net/simple_request.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2008-2009 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 // ========================================================================
15 #include "omaha/net/proxy_auth.h"
16 #include <atlcom.h>
17 #include <pstore.h>
18 #include <wincred.h>
19 #include <wincrypt.h>
20 #include "omaha/base/commontypes.h"
21 #include "omaha/base/encrypt.h"
22 #include "omaha/base/logging.h"
23 #include "omaha/base/smart_handle.h"
24 #include "omaha/base/string.h"
25 #include "omaha/base/system_info.h"
26 #include "omaha/goopdate/cred_dialog.h"
27 #include "omaha/third_party/smartany/scoped_any.h"
28
29 using omaha::encrypt::EncryptData;
30 using omaha::encrypt::DecryptData;
31
32 namespace omaha {
33
34 static const GUID kPreIE7CredTypeGuid = { 0x5e7e8100, 0x9138, 0x11d1,
35 { 0x94, 0x5a, 0x00, 0xc0, 0x4f, 0xc3, 0x08, 0xff } };
36 static const GUID kPreIE7CredSubtypeGuid = { 0 };
37
38 #define kIE7CredKey "abe2869f-9b47-4cd9-a358-c22904dba7f7"
39
40 bool ProxyAuth::IsPromptAllowed() {
41 __mutexScope(lock_);
42 return prompt_cancelled_ < cancel_prompt_threshold_;
43 }
44
45 void ProxyAuth::PromptCancelled() {
46 __mutexScope(lock_);
47 prompt_cancelled_++;
48 }
49
50 CString ProxyAuth::ExtractProxy(const CString& proxy_settings,
51 bool isHttps) {
52 if (proxy_settings.IsEmpty()) {
53 NET_LOG(L3, (_T("[ProxyAuth::ExtractProxy][Empty settings")));
54 return proxy_settings;
55 }
56
57 int equals_index = String_FindChar(proxy_settings, L'=');
58 if (equals_index >= 0) {
59 const wchar_t* prefix = L"http=";
60 if (isHttps)
61 prefix = L"https=";
62
63 int prefix_index = String_FindString(proxy_settings, prefix);
64 if (prefix_index == -1) {
65 // fallback to whatever we've got after an equals sign
66 prefix = L"=";
67 prefix_index = equals_index;
68 }
69
70 int first = prefix_index + lstrlen(prefix);
71 int length = String_FindChar(proxy_settings, L' ');
72 if (length == -1) {
73 return proxy_settings.Mid(first);
74 } else {
75 return proxy_settings.Mid(first, length);
76 }
77 }
78
79 return proxy_settings;
80 }
81
82 void ProxyAuth::ConfigureProxyAuth(bool is_machine,
83 uint32 cancel_prompt_threshold) {
84 ASSERT1(cancel_prompt_threshold);
85
86 proxy_prompt_is_machine_ = is_machine;
87 cancel_prompt_threshold_ = cancel_prompt_threshold;
88 }
89
90 bool ProxyAuth::PromptUser(const CString& server,
91 const ProxyAuthConfig& proxy_auth_config) {
92 NET_LOG(L3, (_T("[ProxyAuth::PromptUser][%s][%s]"),
93 server, proxy_auth_config.ToString()));
94
95 CString user;
96 CString pass;
97
98 HRESULT hr = LaunchCredentialDialog(
99 proxy_prompt_is_machine_,
100 proxy_auth_config.parent_hwnd,
101 server,
102 proxy_auth_config.prompt_caption,
103 &user,
104 &pass);
105
106 if (SUCCEEDED(hr)) {
107 AddCred(server, user, pass);
108 } else if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) {
109 PromptCancelled();
110 }
111
112 SecureZeroMemory(user.GetBuffer(), user.GetAllocLength() * sizeof(TCHAR));
113 SecureZeroMemory(pass.GetBuffer(), pass.GetAllocLength() * sizeof(TCHAR));
114
115 return SUCCEEDED(hr);
116 }
117
118 bool ProxyAuth::GetProxyCredentials(bool allow_ui, bool force_ui,
119 const CString& proxy_server,
120 const ProxyAuthConfig& proxy_auth_config,
121 CString* username, CString* password,
122 uint32* auth_scheme) {
123 NET_LOG(L3, (_T("[ProxyAuth::GetProxyCredentials][%d][%s]"),
124 allow_ui, proxy_auth_config.ToString()));
125
126 CString server(proxy_server);
127 if (server.IsEmpty()) {
128 server = kDefaultProxyServer;
129 }
130
131 __mutexScope(lock_);
132 int i = -1;
133 if (!force_ui)
134 i = servers_.Find(server);
135
136 if (i == -1) {
137 if (ReadFromIE7(server) || ReadFromPreIE7(server) ||
138 (allow_ui && proxy_auth_config.parent_hwnd && IsPromptAllowed() &&
139 PromptUser(server, proxy_auth_config))) {
140 i = servers_.GetSize() - 1;
141 }
142 }
143
144 if (i >= 0) {
145 ASSERT1(!usernames_[i].IsEmpty() && !passwords_[i].empty());
146 std::vector<uint8> decrypted_password;
147 HRESULT hr = DecryptData(NULL,
148 0,
149 &passwords_[i].front(),
150 passwords_[i].size(),
151 &decrypted_password);
152 if (FAILED(hr)) {
153 NET_LOG(LE, (_T("[DecryptData failed][0x%x]"), hr));
154 return false;
155 }
156
157 *username = usernames_[i];
158 *password = reinterpret_cast<TCHAR*>(&decrypted_password.front());
159 *auth_scheme = auth_schemes_[i];
160 }
161
162 NET_LOG(L3, (_T("[ProxyAuth::GetProxyCredentials][%d][%s][%s][%d]"),
163 i, proxy_server, *username, *auth_scheme));
164 return i >= 0;
165 }
166
167 static bool ParseCredsFromRawBuffer(const BYTE* buffer, const DWORD bytes,
168 CString* username, CString* password) {
169 ASSERT1(bytes > 0);
170 if (bytes <= 0)
171 return false;
172
173 const char* ascii_buffer = reinterpret_cast<const char*>(buffer);
174 const unsigned ascii_length =
175 static_cast<const unsigned>(strlen(ascii_buffer));
176
177 // The buffer could be ascii or wide characters, so we detect which one it
178 // is and copy the ascii characters to a wide string if necessary
179 const wchar_t* user_pass = NULL;
180 CString temp;
181 if (ascii_length == bytes - 1) {
182 temp = AnsiToWideString(ascii_buffer, ascii_length);
183 user_pass = temp.GetString();
184 } else {
185 user_pass = reinterpret_cast<const wchar_t*>(buffer);
186 }
187
188 int colon_pos = String_FindChar(user_pass, L':');
189 if (colon_pos >= 0) {
190 username->SetString(user_pass, colon_pos);
191 password->SetString(user_pass + colon_pos + 1);
192 }
193
194 return colon_pos >= 0;
195 }
196
197 void ProxyAuth::AddCred(const CString& server, const CString& username,
198 const CString& password) {
199 std::vector<uint8> encrypted_password;
200 HRESULT hr = EncryptData(NULL,
201 0,
202 password,
203 (password.GetLength() + 1) * sizeof(TCHAR),
204 &encrypted_password);
205 if (FAILED(hr)) {
206 NET_LOG(LE, (_T("[EncryptData failed][0x%x]"), hr));
207 return;
208 }
209
210 __mutexScope(lock_);
211 int i = servers_.Find(server);
212 if (i == -1) {
213 servers_.Add(server);
214 usernames_.Add(username);
215 passwords_.Add(encrypted_password);
216 auth_schemes_.Add(UNKNOWN_AUTH_SCHEME);
217 } else {
218 usernames_[i] = username;
219 passwords_[i] = encrypted_password;
220 auth_schemes_[i] = UNKNOWN_AUTH_SCHEME;
221 }
222
223 NET_LOG(L3, (_T("[ProxyAuth::AddCred][%s][%s]"), server, username));
224 }
225
226 HRESULT ProxyAuth::SetProxyAuthScheme(const CString& proxy_server,
227 uint32 scheme) {
228 CString server(proxy_server);
229 if (server.IsEmpty()) {
230 server = kDefaultProxyServer;
231 }
232
233 __mutexScope(lock_);
234 int i = servers_.Find(server);
235 if (i == -1) {
236 NET_LOG(LE, (_T("[ProxyAuth::SetProxyAuthScheme][%s not found]"), server));
237 return E_INVALIDARG;
238 }
239
240 auth_schemes_[i] = scheme;
241 NET_LOG(L3, (_T("[ProxyAuth::SetProxyAuthScheme][%s][%s][%d]"),
242 server, usernames_[i], scheme));
243 return S_OK;
244 }
245
246 // This approach (the key in particular) comes from a securityfocus posting:
247 // http://www.securityfocus.com/archive/1/458115/30/0/threaded
248 bool ProxyAuth::ReadFromIE7(const CString& server) {
249 scoped_library crypt_lib(::LoadLibrary(L"crypt32.dll"));
250 ASSERT1(crypt_lib);
251 if (!crypt_lib)
252 return false;
253
254 typedef BOOL (__stdcall *CryptUnprotectData_type)(DATA_BLOB*, LPWSTR*,
255 DATA_BLOB*, PVOID, CRYPTPROTECT_PROMPTSTRUCT*, DWORD, DATA_BLOB*);
256 CryptUnprotectData_type CryptUnprotectData_fn =
257 reinterpret_cast<CryptUnprotectData_type>(
258 GetProcAddress(get(crypt_lib), "CryptUnprotectData"));
259 ASSERT1(CryptUnprotectData_fn);
260 if (!CryptUnprotectData_fn)
261 return false;
262
263 // Load CredEnumerate and CredFree dynamically because they don't exist on
264 // Win2K and so loading the GoogleDesktopCommon.dll otherwise.
265 scoped_library advapi_lib(::LoadLibrary(L"advapi32.dll"));
266 ASSERT1(advapi_lib);
267 if (!advapi_lib)
268 return false;
269
270 typedef BOOL (__stdcall *CredEnumerateW_type)(LPCWSTR, DWORD, DWORD*,
271 PCREDENTIAL**);
272 CredEnumerateW_type CredEnumerateW_fn =
273 reinterpret_cast<CredEnumerateW_type>(
274 GetProcAddress(get(advapi_lib), "CredEnumerateW"));
275 ASSERT1(CredEnumerateW_fn || SystemInfo::IsRunningOnW2K());
276 if (!CredEnumerateW_fn)
277 return false;
278
279 typedef VOID (__stdcall *CredFree_type)(PVOID);
280 CredFree_type CredFree_fn = reinterpret_cast<CredFree_type>(
281 GetProcAddress(get(advapi_lib), "CredFree"));
282 ASSERT1(CredFree_fn || SystemInfo::IsRunningOnW2K());
283 if (!CredFree_fn)
284 return false;
285
286 // Done with dynamically loading methods. CredEnumerate (and CredFree if
287 // we didn't return) will have failed to load on Win2K
288
289 DATA_BLOB optional_entropy;
290
291 char key[ARRAYSIZE(kIE7CredKey)] = kIE7CredKey;
292 int16 temp[ARRAYSIZE(key)];
293 for (int i = 0; i < ARRAYSIZE(key); ++i)
294 temp[i] = static_cast<int16>(key[i] * 4);
295
296 optional_entropy.pbData = reinterpret_cast<BYTE*>(&temp);
297 optional_entropy.cbData = sizeof(temp);
298
299 CString target(NOTRANSL(L"Microsoft_WinInet_"));
300 target += server;
301 target += L"*";
302
303 DWORD count = 0;
304 CREDENTIAL** credentials = NULL;
305 CString username;
306 CString password;
307
308 bool found = false;
309 if (CredEnumerateW_fn(target, 0, &count, &credentials)) {
310 for (unsigned i = 0; i < count; ++i) {
311 if (credentials[i]->Type == CRED_TYPE_GENERIC) {
312 DATA_BLOB data_in;
313 DATA_BLOB data_out = { 0 };
314 data_in.pbData = static_cast<BYTE*>(credentials[i]->CredentialBlob);
315 data_in.cbData = credentials[i]->CredentialBlobSize;
316
317 if (CryptUnprotectData_fn(&data_in, NULL, &optional_entropy, NULL, NULL,
318 0, &data_out)) {
319 found = ParseCredsFromRawBuffer(data_out.pbData, data_out.cbData,
320 &username, &password);
321 LocalFree(data_out.pbData);
322 if (found) {
323 AddCred(server, username, password);
324 break;
325 }
326 }
327 }
328 }
329 CredFree_fn(credentials);
330 }
331
332 return found;
333 }
334
335 bool ProxyAuth::ReadFromPreIE7(const CString& server) {
336 scoped_library pstore_lib(::LoadLibrary(L"pstorec.dll"));
337 ASSERT1(pstore_lib);
338 if (!pstore_lib)
339 return false;
340
341 typedef HRESULT (__stdcall *PStoreCreateInstance_type)(IPStore**,
342 PST_PROVIDERID*, void*, DWORD);
343 PStoreCreateInstance_type PStoreCreateInstance_fn =
344 reinterpret_cast<PStoreCreateInstance_type>(
345 GetProcAddress(get(pstore_lib), "PStoreCreateInstance"));
346 ASSERT1(PStoreCreateInstance_fn);
347 if (!PStoreCreateInstance_fn)
348 return false;
349
350 CString username;
351 CString password;
352 bool found = false;
353
354 scoped_co_init initializer(COINIT_APARTMENTTHREADED);
355 HRESULT hr = E_FAIL;
356
357 // The best reference I found about these iterators, especially how to free
358 // the item_name returned by this iterator was a microsoft patent application:
359 // http://www.patentstorm.us/patents/6272631-description.html
360 CComPtr<IPStore> pstore;
361 VERIFY1(SUCCEEDED(hr = PStoreCreateInstance_fn(&pstore, NULL, NULL, 0)));
362 if (SUCCEEDED(hr)) {
363 CComPtr<IEnumPStoreTypes> enum_types;
364 VERIFY1(SUCCEEDED(hr = pstore->EnumTypes(PST_KEY_CURRENT_USER, 0,
365 &enum_types)));
366 if (SUCCEEDED(hr)) {
367 GUID type_guid = { 0 };
368 // Get the types one at a time
369 while (enum_types->Next(1, &type_guid, NULL) == S_OK) {
370 if (type_guid != kPreIE7CredTypeGuid)
371 continue;
372
373 CComPtr<IEnumPStoreTypes> enum_subtypes;
374 VERIFY1(SUCCEEDED(hr = pstore->EnumSubtypes(PST_KEY_CURRENT_USER,
375 &type_guid, 0, &enum_subtypes)));
376 if (SUCCEEDED(hr)) {
377 GUID subtype_guid = { 0 };
378 // Get the subtypes one at a time
379 while (enum_subtypes->Next(1, &subtype_guid, NULL) == S_OK) {
380 if (subtype_guid != kPreIE7CredSubtypeGuid)
381 continue;
382
383 CComPtr<IEnumPStoreItems> enum_items;
384 VERIFY1(SUCCEEDED(hr = pstore->EnumItems(PST_KEY_CURRENT_USER,
385 &type_guid, &subtype_guid, 0, &enum_items)));
386 if (SUCCEEDED(hr)) {
387 wchar_t* item_name = NULL;
388 // Get the items one at a time
389 while (enum_items->Next(1, &item_name, NULL) == S_OK) {
390 DWORD data_length = 0;
391 byte* data = NULL;
392
393 VERIFY1(SUCCEEDED(hr = pstore->ReadItem(PST_KEY_CURRENT_USER,
394 &type_guid, &subtype_guid, item_name, &data_length, &data,
395 NULL, 0)));
396 if (SUCCEEDED(hr)) {
397 found = ParseCredsFromRawBuffer(data, data_length,
398 &username, &password);
399 CoTaskMemFree(data);
400 }
401
402 CoTaskMemFree(item_name);
403 if (found) {
404 AddCred(server, username, password);
405 break;
406 }
407 } // end enum_items loop
408 }
409 } // end enum_subtypes loop
410 }
411 } // end enum_types loop
412 }
413 }
414
415 return found;
416 }
417
418 } // namespace omaha
419
OLDNEW
« no previous file with comments | « net/proxy_auth.h ('k') | net/simple_request.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698