OLD | NEW |
| (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/goopdate/code_red_check.h" | |
17 #include "omaha/base/constants.h" | |
18 #include "omaha/base/scoped_impersonation.h" | |
19 #include "omaha/base/utils.h" | |
20 #include "omaha/base/vista_utils.h" | |
21 #include "omaha/common/goopdate_utils.h" | |
22 #include "omaha/goopdate/goopdate_metrics.h" | |
23 #include "omaha/net/network_request.h" | |
24 #include "omaha/net/bits_request.h" | |
25 #include "omaha/net/simple_request.h" | |
26 #include "omaha/recovery/client/google_update_recovery.h" | |
27 | |
28 namespace omaha { | |
29 | |
30 namespace { | |
31 | |
32 bool IsThreadImpersonatingUser() { | |
33 CAccessToken access_token; | |
34 return access_token.GetThreadToken(TOKEN_READ); | |
35 } | |
36 | |
37 HRESULT DownloadCodeRedFile(const TCHAR* url, | |
38 const TCHAR* file_path, | |
39 void*, | |
40 int* http_status_code) { | |
41 ASSERT1(url); | |
42 ASSERT1(file_path); | |
43 ASSERT1(http_status_code); | |
44 *http_status_code = 0; | |
45 NetworkConfig* network_config = NULL; | |
46 NetworkConfigManager& network_manager = NetworkConfigManager::Instance(); | |
47 HRESULT hr = network_manager.GetUserNetworkConfig(&network_config); | |
48 if (FAILED(hr)) { | |
49 return hr; | |
50 } | |
51 NetworkRequest network_request(network_config->session()); | |
52 | |
53 network_request.AddHttpRequest(new SimpleRequest); | |
54 | |
55 // BITS takes the job to BG_JOB_STATE_TRANSIENT_ERROR when the server returns | |
56 // 204. After the "no progress time out", the BITS job errors out. Since | |
57 // BITS follows the WinHTTP in the fallback chain, the code is expected to | |
58 // execute only if WinHTTP fails to get a response from the server. | |
59 | |
60 // BITS transfers files only when the job owner is logged on. | |
61 bool is_logged_on(false); | |
62 if (IsThreadImpersonatingUser()) { | |
63 // Code red download thread only impersonates to logged on user. So when | |
64 // impersonation happens, it means the user is logged on. | |
65 is_logged_on = true; | |
66 } else { | |
67 // Assumes the caller is not logged on if the function failed. | |
68 hr = IsUserLoggedOn(&is_logged_on); | |
69 ASSERT1(SUCCEEDED(hr) || !is_logged_on); | |
70 } | |
71 if (is_logged_on) { | |
72 BitsRequest* bits_request(new BitsRequest); | |
73 bits_request->set_minimum_retry_delay(kSecPerMin); | |
74 bits_request->set_no_progress_timeout(5 * kSecPerMin); | |
75 network_request.AddHttpRequest(bits_request); | |
76 } | |
77 | |
78 hr = network_request.DownloadFile(CString(url), CString(file_path)); | |
79 if (FAILED(hr)) { | |
80 return E_FAIL; | |
81 } | |
82 | |
83 *http_status_code = network_request.http_status_code(); | |
84 switch (network_request.http_status_code()) { | |
85 case HTTP_STATUS_OK: | |
86 return S_OK; | |
87 case HTTP_STATUS_NO_CONTENT: | |
88 return E_FAIL; | |
89 default: | |
90 return E_FAIL; | |
91 } | |
92 } | |
93 | |
94 HRESULT CreateUniqueTempFileForLoggedOnUser(CString* target_file) { | |
95 ASSERT1(target_file); | |
96 CAccessToken access_token; | |
97 TCHAR buffer[MAX_PATH] = {0}; | |
98 VERIFY1(access_token.GetThreadToken(TOKEN_READ)); | |
99 HRESULT hr = ::SHGetFolderPath(NULL, | |
100 CSIDL_LOCAL_APPDATA, | |
101 access_token.GetHandle(), | |
102 SHGFP_TYPE_CURRENT, | |
103 buffer); | |
104 if (FAILED(hr)) { | |
105 return hr; | |
106 } | |
107 | |
108 return GetNewFileNameInDirectory(buffer, target_file); | |
109 } | |
110 | |
111 HRESULT DownloadCodeRedFileAsLoggedOnUser(const TCHAR* url, | |
112 const TCHAR* file_path, | |
113 void* callback_argument, | |
114 int* http_status_code) { | |
115 ASSERT1(http_status_code); | |
116 *http_status_code = 0; | |
117 scoped_handle logged_on_user_token( | |
118 goopdate_utils::GetImpersonationTokenForMachineProcess(true)); | |
119 if (!valid(logged_on_user_token)) { | |
120 return E_FAIL; | |
121 } | |
122 | |
123 HRESULT hr = S_OK; | |
124 CString download_target_path; | |
125 { | |
126 scoped_impersonation impersonate_user(get(logged_on_user_token)); | |
127 hr = HRESULT_FROM_WIN32(impersonate_user.result()); | |
128 if (FAILED(hr)) { | |
129 return hr; | |
130 } | |
131 | |
132 hr = CreateUniqueTempFileForLoggedOnUser(&download_target_path); | |
133 if (FAILED(hr)) { | |
134 return hr; | |
135 } | |
136 if (download_target_path.IsEmpty()) { | |
137 return E_FAIL; | |
138 } | |
139 | |
140 hr = DownloadCodeRedFile(url, | |
141 download_target_path, | |
142 callback_argument, | |
143 http_status_code); | |
144 if (FAILED(hr)) { | |
145 ::DeleteFile(download_target_path); | |
146 return hr; | |
147 } | |
148 } | |
149 | |
150 const DWORD kMoveFlag = MOVEFILE_COPY_ALLOWED | | |
151 MOVEFILE_REPLACE_EXISTING | | |
152 MOVEFILE_WRITE_THROUGH; | |
153 if (!::MoveFileEx(download_target_path, | |
154 file_path, | |
155 kMoveFlag)) { | |
156 hr = HRESULT_FROM_WIN32(::GetLastError()); | |
157 } | |
158 | |
159 ::DeleteFile(download_target_path); | |
160 return hr; | |
161 } | |
162 | |
163 // Download Callback for Code Red. | |
164 // Returns S_OK when the download of the Code Red file succeeds and E_FAIL | |
165 // otherwise. | |
166 HRESULT CodeRedDownloadCallback(const TCHAR* url, | |
167 const TCHAR* file_path, | |
168 void* callback_argument) { | |
169 ++metric_cr_callback_total; | |
170 | |
171 int http_status_code = 0; | |
172 HRESULT hr = DownloadCodeRedFileAsLoggedOnUser(url, | |
173 file_path, | |
174 callback_argument, | |
175 &http_status_code); | |
176 if (FAILED(hr) && (http_status_code != HTTP_STATUS_NO_CONTENT)) { | |
177 hr = DownloadCodeRedFile(url, | |
178 file_path, | |
179 callback_argument, | |
180 &http_status_code); | |
181 } | |
182 | |
183 switch (http_status_code) { | |
184 case HTTP_STATUS_OK: | |
185 ++metric_cr_callback_status_200; | |
186 break; | |
187 case HTTP_STATUS_NO_CONTENT: | |
188 ++metric_cr_callback_status_204; | |
189 break; | |
190 default: | |
191 ++metric_cr_callback_status_other; | |
192 break; | |
193 } | |
194 | |
195 return hr; | |
196 } | |
197 | |
198 } // namespace | |
199 | |
200 HRESULT CheckForCodeRed(bool is_machine, const CString& omaha_version) { | |
201 HRESULT hr = FixGoogleUpdate(kGoogleUpdateAppId, | |
202 omaha_version, | |
203 _T(""), // Omaha doesn't have a language. | |
204 is_machine, | |
205 &CodeRedDownloadCallback, | |
206 NULL); | |
207 CORE_LOG(L2, (_T("[FixGoogleUpdate returned 0x%08x]"), hr)); | |
208 return hr; | |
209 } | |
210 | |
211 } // namespace omaha | |
OLD | NEW |