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

Side by Side Diff: net/network_config.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/network_config.h ('k') | net/network_config_unittest.cc » ('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 2007-2010 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
16 #include "omaha/net/network_config.h"
17
18 #include <winhttp.h>
19 #include <atlconv.h>
20 #include <atlsecurity.h>
21 #include <algorithm>
22 #include <hash_set>
23 #include <vector>
24 #include "base/error.h"
25 #include "base/scoped_ptr.h"
26 #include "base/scope_guard.h"
27 #include "omaha/base/browser_utils.h"
28 #include "omaha/base/const_object_names.h"
29 #include "omaha/base/constants.h"
30 #include "omaha/base/debug.h"
31 #include "omaha/base/error.h"
32 #include "omaha/base/encrypt.h"
33 #include "omaha/base/logging.h"
34 #include "omaha/base/omaha_version.h"
35 #include "omaha/base/path.h"
36 #include "omaha/base/reg_key.h"
37 #include "omaha/base/scoped_ptr_address.h"
38 #include "omaha/base/string.h"
39 #include "omaha/base/system.h"
40 #include "omaha/base/user_info.h"
41 #include "omaha/base/utils.h"
42 #include "omaha/common/config_manager.h"
43 #include "omaha/net/cup_request.h"
44 #include "omaha/net/http_client.h"
45
46 using omaha::encrypt::EncryptData;
47 using omaha::encrypt::DecryptData;
48
49 namespace omaha {
50
51 // Computes the hash value of a ProxyConfig object. Names in the stdext
52 // namespace are not currently part of the ISO C++ standard.
53 uint32 hash_value(const ProxyConfig& config) {
54 uint32 hash = stdext::hash_value(config.auto_detect) ^
55 stdext::hash_value(config.auto_config_url.GetString()) ^
56 stdext::hash_value(config.proxy.GetString()) ^
57 stdext::hash_value(config.proxy_bypass.GetString());
58 return hash;
59 }
60
61 const TCHAR* const NetworkConfigManager::kNetworkSubkey = _T("network");
62 const TCHAR* const NetworkConfigManager::kNetworkCupSubkey = _T("secure");
63 const TCHAR* const NetworkConfigManager::kCupClientSecretKey = _T("sk");
64 const TCHAR* const NetworkConfigManager::kCupClientCookie = _T("c");
65
66 const TCHAR* const NetworkConfig::kUserAgent = _T("Google Update/%s");
67
68 const TCHAR* const NetworkConfig::kRegKeyProxy = GOOPDATE_MAIN_KEY _T("proxy");
69 const TCHAR* const NetworkConfig::kRegValueSource = _T("source");
70
71 const TCHAR* const NetworkConfig::kWPADIdentifier = _T("auto");
72 const TCHAR* const NetworkConfig::kDirectConnectionIdentifier = _T("direct");
73
74 NetworkConfig::NetworkConfig(bool is_machine)
75 : is_machine_(is_machine),
76 is_initialized_(false) {}
77
78 NetworkConfig::~NetworkConfig() {
79 if (session_.session_handle && http_client_.get()) {
80 http_client_->Close(session_.session_handle);
81 session_.session_handle = NULL;
82 }
83 Clear();
84 }
85
86 // Initialize creates or opens a global lock to synchronize access to
87 // registry where CUP credentials are stored. Each user including non-elevated
88 // admins stores network configuration data, such as the CUP password in
89 // its HKCU. The admin users, including the LOCAL_SYSTEM, store data in HKLM.
90 // Therefore, the naming of the global lock is different: users have their
91 // lock postfixed with their sid, so the serialization only occurs within the
92 // same user's programs. Admin users use the same named lock since they store
93 // data in a shared HKLM. The data of the admin users is disambiguated by
94 // postfixing their registry sub key with sids.
95 // In conclusion, users have sid-postfixed locks and their data goes in
96 // their respective HKCU. Admin users have the same lock and their data goes
97 // under HKLM in sid-postfixed stores.
98 //
99 // The named lock is created in the global namespace to account for users
100 // logging in from different TS sessions.
101 //
102 // The CUP credentials must be protected with ACLs so non-elevated admins can't
103 // read elevated-admins' keys and attack the protocol.
104 //
105 // Also, an Internet session is created.
106 HRESULT NetworkConfig::Initialize() {
107 ASSERT1(!is_initialized_);
108
109 http_client_.reset(CreateHttpClient());
110 ASSERT1(http_client_.get());
111 if (!http_client_.get()) {
112 NET_LOG(LE, (_T("[CreateHttpClient failed]")));
113 return E_UNEXPECTED;
114 }
115 HRESULT hr = http_client_->Initialize();
116 if (FAILED(hr)) {
117 // TODO(omaha): This makes an assumption that only WinHttp is
118 // supported by the network code.
119 NET_LOG(LE, (_T("[http_client_->Initialize() failed][0x%x]"), hr));
120 return OMAHA_NET_E_WINHTTP_NOT_AVAILABLE;
121 }
122
123 // Initializes the WinHttp session and configures WinHttp to work in
124 // asynchronous mode. In this mode, the network requests are non-blocking
125 // and asynchronous events are generated when a request is complete.
126 hr = http_client_->Open(NULL,
127 WINHTTP_ACCESS_TYPE_NO_PROXY,
128 WINHTTP_NO_PROXY_NAME,
129 WINHTTP_NO_PROXY_BYPASS,
130 WINHTTP_FLAG_ASYNC,
131 &session_.session_handle);
132 if (FAILED(hr)) {
133 NET_LOG(LE, (_T("[http_client_->Open() failed][0x%x]"), hr));
134 return hr;
135 }
136
137 Add(new UpdateDevProxyDetector);
138 BrowserType browser_type(BROWSER_UNKNOWN);
139 GetDefaultBrowserType(&browser_type);
140 if (browser_type == BROWSER_FIREFOX) {
141 Add(new FirefoxProxyDetector);
142 }
143 // There is no Chrome detector because it uses the same proxy settings as IE.
144 Add(new IEProxyDetector);
145 Add(new DefaultProxyDetector);
146
147 // Use a global network configuration override if available.
148 ConfigManager* config_manager = ConfigManager::Instance();
149 CString net_config;
150 if (SUCCEEDED(config_manager->GetNetConfig(&net_config))) {
151 ProxyConfig config_override = NetworkConfig::ParseNetConfig(net_config);
152 SetConfigurationOverride(&config_override);
153 }
154
155 ConfigureProxyAuth();
156
157 is_initialized_ = true;
158 return S_OK;
159 }
160
161 void NetworkConfig::Add(ProxyDetectorInterface* detector) {
162 ASSERT1(detector);
163 __mutexBlock(lock_) {
164 detectors_.push_back(detector);
165 }
166 }
167
168 void NetworkConfig::Clear() {
169 __mutexBlock(lock_) {
170 for (size_t i = 0; i != detectors_.size(); ++i) {
171 delete detectors_[i];
172 }
173 detectors_.clear();
174 configurations_.clear();
175 }
176 }
177
178 HRESULT NetworkConfig::Detect() {
179 __mutexBlock(lock_) {
180 std::vector<ProxyConfig> configurations;
181
182 for (size_t i = 0; i != detectors_.size(); ++i) {
183 ProxyConfig config;
184 if (SUCCEEDED(detectors_[i]->Detect(&config))) {
185 configurations.push_back(config);
186 }
187 }
188 configurations_.swap(configurations);
189 }
190
191 return S_OK;
192 }
193
194 void NetworkConfig::SortProxies(std::vector<ProxyConfig>* configurations) {
195 ASSERT1(configurations);
196
197 std::stable_sort(configurations->begin(), configurations->end(),
198 ProxySortPredicate);
199 }
200
201 HRESULT NetworkConfig::ConfigFromIdentifier(const CString& id,
202 ProxyConfig* config) {
203 ASSERT1(config);
204
205 *config = ProxyConfig();
206 if (id == kWPADIdentifier) {
207 config->source = kWPADIdentifier;
208 config->auto_detect = true;
209 } else if (id == kDirectConnectionIdentifier) {
210 config->source = kDirectConnectionIdentifier;
211 } else {
212 return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
213 }
214
215 return S_OK;
216 }
217
218 void NetworkConfig::AppendLastKnownGoodProxyConfig(
219 std::vector<ProxyConfig>* configurations) const {
220 ASSERT1(configurations);
221 ProxyConfig last_known_good_config;
222 if (SUCCEEDED(LoadProxyConfig(&last_known_good_config))) {
223 configurations->push_back(last_known_good_config);
224 }
225 }
226
227 void NetworkConfig::AppendStaticProxyConfigs(
228 std::vector<ProxyConfig>* configurations) {
229 ASSERT1(configurations);
230 ProxyConfig config;
231
232 HRESULT hr = ConfigFromIdentifier(kWPADIdentifier, &config);
233 if (SUCCEEDED(hr)) {
234 configurations->push_back(config);
235 }
236
237 hr = ConfigFromIdentifier(kDirectConnectionIdentifier, &config);
238 if (SUCCEEDED(hr)) {
239 configurations->push_back(config);
240 }
241 }
242
243 HRESULT NetworkConfig::Detect(const CString& proxy_source,
244 ProxyConfig* config) const {
245 ASSERT1(config);
246 __mutexBlock(lock_) {
247 std::vector<ProxyConfig> configurations;
248 for (size_t i = 0; i != detectors_.size(); ++i) {
249 if (proxy_source == detectors_[i]->source()) {
250 return detectors_[i]->Detect(config);
251 }
252 }
253 }
254
255 return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
256 }
257
258 std::vector<ProxyConfig> NetworkConfig::GetConfigurations() const {
259 std::vector<ProxyConfig> configurations;
260 __mutexBlock(lock_) {
261 configurations = configurations_;
262 }
263 return configurations;
264 }
265
266 HRESULT NetworkConfig::GetConfigurationOverride(ProxyConfig* config) {
267 ASSERT1(config);
268 __mutexBlock(lock_) {
269 if (configuration_override_.get()) {
270 *config = *configuration_override_;
271 return S_OK;
272 }
273 }
274 return E_FAIL;
275 }
276
277 void NetworkConfig::SetConfigurationOverride(
278 const ProxyConfig* configuration_override) {
279 __mutexBlock(lock_) {
280 if (configuration_override) {
281 configuration_override_.reset(new ProxyConfig);
282 *configuration_override_ = *configuration_override;
283 configuration_override_->source = _T("updatedev/netconfig");
284 } else {
285 configuration_override_.reset();
286 }
287 }
288 }
289
290 HRESULT NetworkConfig::GetCupCredentials(
291 CupCredentials* cup_credentials) const {
292 return NetworkConfigManager::Instance().GetCupCredentials(cup_credentials);
293 }
294
295 HRESULT NetworkConfig::SetCupCredentials(
296 const CupCredentials* cup_credentials) const {
297 NetworkConfigManager& network_manager = NetworkConfigManager::Instance();
298 if (cup_credentials == NULL) {
299 network_manager.ClearCupCredentials();
300 return S_OK;
301 }
302
303 return network_manager.SetCupCredentials(*cup_credentials);
304 }
305
306 // Serializes configurations for debugging purposes.
307 CString NetworkConfig::ToString(const ProxyConfig& config) {
308 CString result;
309 result.AppendFormat(_T("priority=%u, source=%s, "),
310 config.priority, config.source);
311
312 switch (GetAccessType(config)) {
313 case WINHTTP_ACCESS_TYPE_NO_PROXY:
314 result.AppendFormat(_T("direct connection"));
315 break;
316 case WINHTTP_ACCESS_TYPE_NAMED_PROXY:
317 result.AppendFormat(_T("named proxy=%s, bypass=%s"),
318 config.proxy, config.proxy_bypass);
319 break;
320 case WINHTTP_ACCESS_TYPE_AUTO_DETECT:
321 result.AppendFormat(_T("wpad=%d, script=%s"),
322 config.auto_detect, config.auto_config_url);
323 break;
324 default:
325 ASSERT1(false);
326 break;
327 }
328 return result;
329 }
330
331 CString NetworkConfig::ToString(const std::vector<ProxyConfig>& config) {
332 CString result;
333 for (size_t i = 0; i != config.size(); ++i) {
334 result.Append(NetworkConfig::ToString(config[i]));
335 result.Append(_T("\r\n"));
336 }
337 return result;
338 }
339
340 int NetworkConfig::GetAccessType(const ProxyConfig& config) {
341 if (config.auto_detect || !config.auto_config_url.IsEmpty()) {
342 return WINHTTP_ACCESS_TYPE_AUTO_DETECT;
343 } else if (!config.proxy.IsEmpty()) {
344 return WINHTTP_ACCESS_TYPE_NAMED_PROXY;
345 } else {
346 return WINHTTP_ACCESS_TYPE_NO_PROXY;
347 }
348 }
349
350 bool NetworkConfig::IsUsingCupTestKeys() {
351 DWORD value = 0;
352 if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,
353 kRegValueCupKeys,
354 &value))) {
355 return value != 0;
356 } else {
357 return false;
358 }
359 }
360
361 void NetworkConfig::ConfigureProxyAuth() {
362 const uint32 kProxyMaxPrompts = 1;
363 return proxy_auth_.ConfigureProxyAuth(is_machine_, kProxyMaxPrompts);
364 }
365
366 bool NetworkConfig::GetProxyCredentials(bool allow_ui,
367 bool force_ui,
368 const CString& proxy_settings,
369 const ProxyAuthConfig& config,
370 bool is_https,
371 CString* username,
372 CString* password,
373 uint32* auth_scheme) {
374 ASSERT1(username);
375 ASSERT1(password);
376 ASSERT1(auth_scheme);
377
378 const CString& proxy = ProxyAuth::ExtractProxy(proxy_settings, is_https);
379 return proxy_auth_.GetProxyCredentials(allow_ui, force_ui, proxy,
380 config, username,
381 password, auth_scheme);
382 }
383
384 HRESULT NetworkConfig::SetProxyAuthScheme(const CString& proxy_settings,
385 bool is_https,
386 uint32 auth_scheme) {
387 ASSERT1(auth_scheme != UNKNOWN_AUTH_SCHEME);
388 const CString& proxy = ProxyAuth::ExtractProxy(proxy_settings, is_https);
389 return proxy_auth_.SetProxyAuthScheme(proxy, auth_scheme);
390 }
391
392 // TODO(omaha): the code does WPAD auto detect in all cases. It is possible for
393 // a configuration to specify no auto detection but provide the proxy script
394 // url. The current code does not account for this yet.
395 HRESULT NetworkConfig::GetProxyForUrl(const CString& url,
396 const CString& auto_config_url,
397 HttpClient::ProxyInfo* proxy_info) {
398 ASSERT1(proxy_info);
399
400 NET_LOG(L3, (_T("[NetworkConfig::GetProxyForUrl][%s]"), url));
401
402 HttpClient::AutoProxyOptions auto_proxy_options = {0};
403 auto_proxy_options.flags = WINHTTP_AUTOPROXY_AUTO_DETECT;
404 auto_proxy_options.auto_detect_flags = WINHTTP_AUTO_DETECT_TYPE_DHCP |
405 WINHTTP_AUTO_DETECT_TYPE_DNS_A;
406 if (!auto_config_url.IsEmpty()) {
407 auto_proxy_options.auto_config_url = auto_config_url;
408 auto_proxy_options.flags |= WINHTTP_AUTOPROXY_CONFIG_URL;
409 }
410 auto_proxy_options.auto_logon_if_challenged = true;
411
412 HRESULT hr = http_client_->GetProxyForUrl(session_.session_handle,
413 url,
414 &auto_proxy_options,
415 proxy_info);
416
417 if (FAILED(hr) && ::UrlIsFileUrl(auto_config_url)) {
418 // Some HttpClient implementations, namely WinHTTP, only support PAC files
419 // with http or https schemes. Attempt an alternate resolution scheme using
420 // jsproxy.dll if the initial attempt fails.
421 ASSERT1(user_info::IsThreadImpersonating());
422
423 CString local_file;
424 hr = ConvertFileUriToLocalPath(auto_config_url, &local_file);
425 if (FAILED(hr)) {
426 NET_LOG(LE, (_T("[ConvertFileUriToLocalPath failed][0x%08x]"), hr));
427 return hr;
428 }
429
430 hr = GetProxyForUrlLocal(url, local_file, proxy_info);
431 }
432
433 return hr;
434 }
435
436 CString NetworkConfig::GetUserAgent() {
437 CString user_agent;
438 user_agent.Format(kUserAgent, GetVersionString());
439 return user_agent;
440 }
441
442 CString NetworkConfig::GetMID() {
443 CString mid;
444 RegKey::GetValue(MACHINE_REG_UPDATE_DEV, kRegValueMID, &mid);
445 return mid;
446 }
447
448 CString NetworkConfig::JoinStrings(const TCHAR* s1,
449 const TCHAR* s2,
450 const TCHAR* delim) {
451 CString result;
452 const TCHAR* components[] = {s1, s2};
453 JoinStringsInArray(components, arraysize(components), delim, &result);
454 return result;
455 }
456
457 // Using std::hash_set adds about 2K uncompressed code size. Using a CAtlMap
458 // adds about 1.5K. Usually, there are only five detected configurations so
459 // an O(n^2) algorithm would work well. The advantage of the current
460 // implementation is simplicity. It also does not handle conflicts. Conflicts
461 // are not expected, due to how the ProxyConfig structure is being used.
462 // TODO(omaha): consider not using the hash_set and save about 1K of code.
463 void NetworkConfig::RemoveDuplicates(std::vector<ProxyConfig>* config) {
464 ASSERT1(config);
465
466 // Iterate over the input configurations, remember the hash of each
467 // distinct configuration, and remove the duplicates by skipping the
468 // configurations seen before.
469 std::vector<ProxyConfig> input(*config);
470 config->clear();
471
472 typedef stdext::hash_set<uint32> Keys;
473 Keys keys;
474 for (size_t i = 0; i != input.size(); ++i) {
475 std::pair<Keys::iterator, bool> result(keys.insert(hash_value(input[i])));
476 if (result.second) {
477 config->push_back(input[i]);
478 }
479 }
480 }
481
482 HRESULT NetworkConfig::CreateProxyConfigRegKey(RegKey* key) {
483 ASSERT1(key);
484 CString config_root;
485
486 if (!user_info::IsRunningAsSystem()) {
487 scoped_hkey user_root_key;
488 HRESULT hr = ::RegOpenCurrentUser(KEY_READ | KEY_WRITE,
489 address(user_root_key));
490 if (FAILED(hr)) {
491 return hr;
492 }
493 return key->Create(get(user_root_key), kRegKeyProxy);
494 } else {
495 return key->Create(HKEY_LOCAL_MACHINE, kRegKeyProxy);
496 }
497 }
498
499 HRESULT NetworkConfig::SaveProxyConfig(const ProxyConfig& config) {
500 const CString& new_configuration = config.source;
501 NET_LOG(L3, (_T("[NetworkConfig::SaveProxyConfig][%s]"), new_configuration));
502
503 RegKey key;
504 HRESULT hr = CreateProxyConfigRegKey(&key);
505 if (FAILED(hr)) {
506 return hr;
507 }
508
509 CString current_configuration;
510 if (SUCCEEDED(key.GetValue(kRegValueSource, &current_configuration)) &&
511 current_configuration != new_configuration) {
512 NET_LOG(L3, (_T("[Network configuration changed from %s to %s"),
513 current_configuration, new_configuration));
514 }
515
516 return key.SetValue(kRegValueSource, new_configuration);
517 }
518
519 HRESULT NetworkConfig::LoadProxyConfig(ProxyConfig* config) const {
520 ASSERT1(config);
521
522 *config = ProxyConfig();
523
524 RegKey key;
525 HRESULT hr = CreateProxyConfigRegKey(&key);
526 if (FAILED(hr)) {
527 return hr;
528 }
529
530 CString source;
531 hr = key.GetValue(kRegValueSource, &source);
532 if (FAILED(hr)) {
533 return hr;
534 }
535
536 hr = NetworkConfig::ConfigFromIdentifier(source, config);
537 if (FAILED(hr)) {
538 hr = Detect(source, config);
539 if (FAILED(hr)) {
540 return hr;
541 }
542 }
543
544 config->priority = ProxyConfig::PROXY_PRIORITY_LAST_KNOWN_GOOD;
545
546 return S_OK;
547 }
548
549 ProxyConfig NetworkConfig::ParseNetConfig(const CString& net_config) {
550 ProxyConfig config;
551 int pos(0);
552 CString token = net_config.Tokenize(_T(";"), pos);
553 while (pos != -1) {
554 CString name, value;
555 if (ParseNameValuePair(token, _T('='), &name, &value)) {
556 bool auto_detect(false);
557 if (name == _T("wpad") &&
558 SUCCEEDED(String_StringToBool(value, &auto_detect))) {
559 config.auto_detect = auto_detect;
560 } else if (name == _T("script")) {
561 config.auto_config_url = value;
562 } else if (name == _T("proxy")) {
563 config.proxy = value;
564 }
565 }
566 token = net_config.Tokenize(_T(";"), pos);
567 }
568 return config;
569 }
570
571 // Note: The jsproxy functions are exposed to public users as part of the
572 // DOJ consent decree and are not formally supported by Microsoft.
573
574 GPA_WRAP(jsproxy.dll,
575 InternetInitializeAutoProxyDll,
576 (DWORD dwVersion, LPSTR lpszDownloadedTempFile, LPSTR lpszMime, LPCVOID lpAutoProxyCallbacks, LPCVOID lpAutoProxyScriptBuffer), // NOLINT
577 (dwVersion, lpszDownloadedTempFile, lpszMime, lpAutoProxyCallbacks, lpA utoProxyScriptBuffer), // NOLINT
578 WINAPI,
579 BOOL,
580 FALSE);
581
582 GPA_WRAP(jsproxy.dll,
583 InternetGetProxyInfo,
584 (LPCSTR lpszUrl, DWORD dwUrlLength, LPSTR lpszUrlHostName, DWORD dwUrlH ostNameLength, LPSTR *lplpszProxyHostName, LPDWORD lpdwProxyHostNameLength), // NOLINT
585 (lpszUrl, dwUrlLength, lpszUrlHostName, dwUrlHostNameLength, lplpszProx yHostName, lpdwProxyHostNameLength), // NOLINT
586 WINAPI,
587 BOOL,
588 FALSE);
589
590 GPA_WRAP(jsproxy.dll,
591 InternetDeInitializeAutoProxyDll,
592 (LPSTR lpszMime, DWORD dwReserved),
593 (lpszMime, dwReserved),
594 WINAPI,
595 BOOL,
596 FALSE);
597
598 HRESULT NetworkConfig::GetProxyForUrlLocal(const CString& url,
599 const CString& path_to_pac_file,
600 HttpClient::ProxyInfo* proxy_info) {
601 scoped_library jsproxy_lib(::LoadLibrary(_T("jsproxy.dll")));
602 ASSERT1(jsproxy_lib);
603 if (!jsproxy_lib) {
604 HRESULT hr = HRESULTFromLastError();
605 NET_LOG(LE, (_T("[GetProxyForUrlLocal][jsproxy not loaded][0x%08x]"), hr));
606 return hr;
607 }
608
609 // Convert the inputs to ANSI, and call into JSProxy to execute the PAC
610 // script; we should get back out a PAC-format list of proxies to use.
611 //
612 // TODO(omaha3): The MSDN prototypes specify LPSTR, and I've assumed this
613 // implies CP_ACP. However, depending on how this was implemented internally,
614 // conversion to UTF8 might work better. Investigate this later and confirm.
615 CStringA path_a(path_to_pac_file);
616
617 if (FALSE == InternetInitializeAutoProxyDllWrap(0, CStrBufA(path_a, MAX_PATH),
618 NULL, NULL, NULL)) {
619 HRESULT hr = HRESULTFromLastError();
620 NET_LOG(LE, (_T("[GetProxyForUrlLocal][jsproxy init failed][0x%08x]"), hr));
621 return hr;
622 }
623
624 ON_SCOPE_EXIT(InternetDeInitializeAutoProxyDllWrap, (LPSTR)NULL, 0);
625
626 CStringA url_a(url);
627 CStringA url_hostname_a(GetUriHostNameHostOnly(url, false));
628
629 scoped_hglobal proxy_ptr;
630 DWORD proxy_len = 0;
631 if (FALSE == InternetGetProxyInfoWrap(
632 url_a,
633 url_a.GetLength(),
634 CStrBufA(url_hostname_a, url_hostname_a.GetLength()),
635 url_hostname_a.GetLength(),
636 reinterpret_cast<LPSTR*>(address(proxy_ptr)),
637 &proxy_len)) {
638 HRESULT hr = HRESULTFromLastError();
639 NET_LOG(LE, (_T("[GetProxyForUrlLocal][jsproxy failed][0x%08x]"), hr));
640 return hr;
641 }
642
643 ASSERT1(proxy_ptr && proxy_len > 0);
644 CStringA proxy(reinterpret_cast<LPSTR>(get(proxy_ptr)), proxy_len);
645 ConvertPacResponseToProxyInfo(proxy, proxy_info);
646 return S_OK;
647 }
648
649 void NetworkConfig::ConvertPacResponseToProxyInfo(
650 const CStringA& response,
651 HttpClient::ProxyInfo* proxy_info) {
652 ASSERT1(proxy_info);
653
654 NET_LOG(L4, (_T("[ConvertPacResponseToProxyInfo][%s]"), CString(response)));
655
656 // The proxy list response from a PAC file for a file is a string of proxies
657 // to attempt in order, delimited by semicolons, with a keyword denoting how
658 // to use the proxy. For example:
659 //
660 // PROXY prx1.samp.com; PROXY prx2.test.com:8080; SOCKS prx3.test.com; DIRECT
661 //
662 // We convert this to a direct semicolon-separated list of host/ports. We
663 // stop parsing if we see DIRECT; we omit any non-PROXY entries.
664 CString proxy_list;
665 for (int start = 0; start >= 0 && start < response.GetLength();) {
666 int semi_pos = response.Find(';', start);
667 if (semi_pos < 0) {
668 semi_pos = response.GetLength();
669 }
670
671 CStringA entry = response.Mid(start, semi_pos - start).Trim().MakeLower();
672 if (entry == "direct") {
673 break;
674 }
675 if (0 == entry.Find("proxy ")) {
676 // This is a valid proxy entry. Strip the leading "PROXY " and add it
677 // to our parsed list.
678 if (!proxy_list.IsEmpty()) {
679 proxy_list.AppendChar(_T(';'));
680 }
681 proxy_list.Append(CString(entry.Mid(6)));
682 }
683
684 start = semi_pos + 1;
685 }
686
687 if (proxy_list.IsEmpty()) {
688 proxy_info->access_type = WINHTTP_ACCESS_TYPE_NO_PROXY;
689 proxy_info->proxy = NULL;
690 proxy_info->proxy_bypass = NULL;
691 } else {
692 // The convention is that any strings in a WINHTTP_PROXY_INFO are expected
693 // to be freed by the caller using GlobalFree(). Convert our intermediary
694 // CString to a GlobalAlloc() buffer and write that out.
695 size_t list_len = (proxy_list.GetLength() + 1) * sizeof(TCHAR);
696 TCHAR* list_hglob = reinterpret_cast<TCHAR*>(::GlobalAlloc(GPTR, list_len));
697 memcpy(list_hglob, proxy_list.GetString(), list_len);
698 proxy_info->access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
699 proxy_info->proxy = list_hglob;
700 proxy_info->proxy_bypass = NULL;
701 }
702 }
703
704 const NetworkConfigManager* const NetworkConfigManager::kInvalidInstance =
705 reinterpret_cast<const NetworkConfigManager* const>(-1);
706 NetworkConfigManager* NetworkConfigManager::instance_ = NULL;
707 LLock NetworkConfigManager::instance_lock_;
708 bool NetworkConfigManager::is_machine_ = false;
709
710 NetworkConfigManager::NetworkConfigManager() {
711 }
712
713 NetworkConfigManager::~NetworkConfigManager() {
714 SaveCupCredentialsToRegistry();
715 }
716
717 HRESULT NetworkConfigManager::CreateInstance() {
718 __mutexScope(instance_lock_);
719 ASSERT1(instance_ != kInvalidInstance);
720 if (!instance_) {
721 NET_LOG(L1, (_T("[NetworkConfigManager::CreateInstance][is_machine: %d]"),
722 is_machine_));
723 instance_ = new NetworkConfigManager();
724 VERIFY1(SUCCEEDED(instance_->InitializeLock()));
725 VERIFY1(SUCCEEDED(instance_->InitializeRegistryKey()));
726 instance_->LoadCupCredentialsFromRegistry();
727 }
728
729 return S_OK;
730 }
731
732 void NetworkConfigManager::DeleteInstance() {
733 ASSERT1(instance_ != kInvalidInstance);
734
735 NetworkConfigManager* instance =
736 omaha::interlocked_exchange_pointer(&instance_, kInvalidInstance);
737
738 if (kInvalidInstance != instance && NULL != instance) {
739 instance->DeleteInstanceInternal();
740 delete instance;
741 }
742 }
743
744 NetworkConfigManager& NetworkConfigManager::Instance() {
745 __mutexScope(instance_lock_);
746 if (!instance_) {
747 VERIFY1(SUCCEEDED(NetworkConfigManager::CreateInstance()));
748 }
749 return *instance_;
750 }
751
752 void NetworkConfigManager::set_is_machine(bool is_machine) {
753 __mutexScope(instance_lock_);
754 if (instance_) {
755 NET_LOG(LE, (_T("set_is_machine called after instance created.")));
756 }
757
758 is_machine_ = is_machine;
759 }
760
761 void NetworkConfigManager::DeleteInstanceInternal() {
762 __mutexBlock(lock_) {
763 std::map<CString, NetworkConfig*>::iterator it;
764
765 for (it = user_network_config_map_.begin();
766 it != user_network_config_map_.end();
767 ++it) {
768 if (NULL != it->second) {
769 delete it->second;
770 }
771 }
772 user_network_config_map_.clear();
773 }
774 }
775
776 HRESULT NetworkConfigManager::GetUserNetworkConfig(
777 NetworkConfig** network_config) {
778 CString sid;
779 HRESULT hr = user_info::GetEffectiveUserSid(&sid);
780 if (FAILED(hr)) {
781 NET_LOG(LE, (_T("[GetEffectiveUserSid failed][0x%x]"), hr));
782 return hr;
783 }
784
785 __mutexBlock(lock_) {
786 std::map<CString, NetworkConfig*>::iterator it;
787 it = user_network_config_map_.find(sid);
788
789 if (user_network_config_map_.end() != it) {
790 *network_config = it->second;
791 return S_OK;
792 }
793
794 hr = CreateNetworkConfigInstance(network_config, is_machine_);
795 if (SUCCEEDED(hr)) {
796 user_network_config_map_.insert(std::make_pair(sid, *network_config));
797 }
798
799 return hr;
800 }
801
802 return E_FAIL;
803 }
804
805 HRESULT NetworkConfigManager::CreateNetworkConfigInstance(
806 NetworkConfig** network_config_ptr,
807 bool is_machine) {
808 ASSERT1(network_config_ptr);
809
810 NetworkConfig* network_config(new NetworkConfig(is_machine));
811 HRESULT hr = network_config->Initialize();
812 if (FAILED(hr)) {
813 NET_LOG(LE, (_T("[NetworkConfig::Initialize() failed][0x%x]"), hr));
814 delete network_config;
815 return hr;
816 }
817
818 *network_config_ptr = network_config;
819 return S_OK;
820 }
821
822 HRESULT NetworkConfigManager::InitializeLock() {
823 NamedObjectAttributes lock_attr;
824 GetNamedObjectAttributes(kNetworkConfigLock, is_machine_, &lock_attr);
825 return global_lock_.InitializeWithSecAttr(lock_attr.name, &lock_attr.sa) ?
826 S_OK : E_FAIL;
827 }
828
829 HRESULT NetworkConfigManager::InitializeRegistryKey() {
830 // The registry path under which to store persistent network configuration.
831 // The "network" subkey is created with default security. Below "network",
832 // the "secure" key is created so that only system and administrators have
833 // access to it.
834 CString reg_path = is_machine_ ? MACHINE_REG_UPDATE : USER_REG_UPDATE;
835 reg_path = AppendRegKeyPath(reg_path, kNetworkSubkey);
836 RegKey reg_key_network;
837 DWORD disposition = 0;
838 HRESULT hr = reg_key_network.Create(reg_path,
839 NULL, // Class.
840 0, // Options.
841 KEY_CREATE_SUB_KEY, // SAM desired.
842 NULL, // Security attrs.
843 &disposition);
844 if (FAILED(hr)) {
845 return hr;
846 }
847
848 // When initializing for machine, grant access to administrators and system.
849 scoped_ptr<CSecurityAttributes> sa;
850 if (is_machine_) {
851 sa.reset(new CSecurityAttributes);
852 GetAdminDaclSecurityAttributes(sa.get(), GENERIC_ALL);
853 }
854
855 disposition = 0;
856 RegKey reg_key_network_secure;
857 hr = reg_key_network_secure.Create(reg_key_network.Key(), // Parent.
858 kNetworkCupSubkey, // Subkey name.
859 NULL, // Class.
860 0, // Options.
861 KEY_READ, // SAM desired.
862 sa.get(), // Security attrs.
863 &disposition);
864 if (FAILED(hr)) {
865 return hr;
866 }
867 return S_OK;
868 }
869
870 HRESULT NetworkConfigManager::SetCupCredentials(
871 const CupCredentials& cup_credentials) {
872 __mutexScope(lock_);
873
874 const std::vector<uint8>& sk_in(cup_credentials.sk);
875
876 if (sk_in.empty()) {
877 return E_INVALIDARG;
878 }
879
880 std::vector<uint8> sk_out;
881 HRESULT hr = EncryptData(NULL, 0, &sk_in.front(), sk_in.size(), &sk_out);
882 if (FAILED(hr)) {
883 return hr;
884 }
885
886 cup_credentials_.reset(new CupCredentials);
887
888 cup_credentials_->sk.swap(sk_out);
889 cup_credentials_->c.SetString(cup_credentials.c);
890
891 return S_OK;
892 }
893
894 HRESULT NetworkConfigManager::GetCupCredentials(
895 CupCredentials* cup_credentials) {
896 ASSERT1(cup_credentials);
897 __mutexScope(lock_);
898 if (cup_credentials_ == NULL || cup_credentials_->sk.empty()) {
899 return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
900 }
901
902 std::vector<uint8> decrypted_sk;
903 HRESULT hr = DecryptData(NULL,
904 0,
905 &cup_credentials_->sk.front(),
906 cup_credentials_->sk.size(),
907 &decrypted_sk);
908 if (FAILED(hr)) {
909 return hr;
910 }
911 cup_credentials->sk.swap(decrypted_sk);
912 cup_credentials->c.SetString(cup_credentials_->c);
913
914 return S_OK;
915 }
916
917 // This function should be called in singleton creation stage,
918 // thus no lock is needed.
919 HRESULT NetworkConfigManager::LoadCupCredentialsFromRegistry() {
920 __mutexScope(global_lock_);
921
922 CString reg_path = is_machine_ ? MACHINE_REG_UPDATE : USER_REG_UPDATE;
923 reg_path = AppendRegKeyPath(reg_path, kNetworkSubkey);
924 CString key_name = AppendRegKeyPath(reg_path, kNetworkCupSubkey);
925 RegKey reg_key;
926 HRESULT hr = reg_key.Open(key_name, KEY_READ);
927 if (FAILED(hr)) {
928 return hr;
929 }
930 scoped_array<byte> buf;
931 DWORD buf_length = 0;
932 hr = reg_key.GetValue(kCupClientSecretKey, address(buf), &buf_length);
933 if (FAILED(hr)) {
934 return hr;
935 }
936 CString cookie;
937 hr = reg_key.GetValue(kCupClientCookie, &cookie);
938 if (FAILED(hr)) {
939 return hr;
940 }
941 if (buf_length == 0) {
942 return E_FAIL;
943 }
944 cup_credentials_.reset(new CupCredentials);
945 cup_credentials_->sk.resize(buf_length);
946 memcpy(&cup_credentials_->sk.front(), buf.get(), buf_length);
947 cup_credentials_->c = CT2A(cookie);
948
949 return S_OK;
950 }
951
952 // This function is called in the destructor only thus no lock is needed.
953 HRESULT NetworkConfigManager::SaveCupCredentialsToRegistry() {
954 __mutexScope(global_lock_);
955
956 CString reg_path = is_machine_ ? MACHINE_REG_UPDATE : USER_REG_UPDATE;
957 reg_path = AppendRegKeyPath(reg_path, kNetworkSubkey);
958 CString key_name = AppendRegKeyPath(reg_path, kNetworkCupSubkey);
959 RegKey reg_key;
960 HRESULT hr = reg_key.Open(key_name, KEY_WRITE);
961 if (FAILED(hr)) {
962 NET_LOG(L2, (_T("[Registry key open failed][%s][0x%08x]"), key_name, hr));
963 return hr;
964 }
965
966 if (cup_credentials_ == NULL || cup_credentials_->sk.empty()) {
967 HRESULT hr1 = reg_key.DeleteValue(kCupClientSecretKey);
968 HRESULT hr2 = reg_key.DeleteValue(kCupClientCookie);
969 return (SUCCEEDED(hr1) && SUCCEEDED(hr2)) ? S_OK : HRESULTFromLastError();
970 }
971
972 hr = reg_key.SetValue(kCupClientSecretKey,
973 static_cast<const byte*>(&cup_credentials_->sk.front()),
974 cup_credentials_->sk.size());
975 if (FAILED(hr)) {
976 return hr;
977 }
978 hr = reg_key.SetValue(kCupClientCookie, CA2T(cup_credentials_->c));
979 if (FAILED(hr)) {
980 return hr;
981 }
982 return S_OK;
983 }
984
985 void NetworkConfigManager::ClearCupCredentials() {
986 __mutexScope(lock_);
987 cup_credentials_.reset(NULL);
988 }
989
990 } // namespace omaha
991
OLDNEW
« no previous file with comments | « net/network_config.h ('k') | net/network_config_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698