| 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 |