| 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/application_usage_data.h" | |
| 17 #include "omaha/base/const_utils.h" | |
| 18 #include "omaha/base/logging.h" | |
| 19 #include "omaha/base/reg_key.h" | |
| 20 #include "omaha/base/string.h" | |
| 21 #include "omaha/base/user_info.h" | |
| 22 #include "omaha/base/utils.h" | |
| 23 #include "omaha/base/vistautil.h" | |
| 24 #include "omaha/common/app_registry_utils.h" | |
| 25 #include "omaha/common/const_goopdate.h" | |
| 26 | |
| 27 namespace omaha { | |
| 28 | |
| 29 namespace { | |
| 30 | |
| 31 HRESULT RegistryReadStringOrDword(const RegKey& key, | |
| 32 const CString& value_name, | |
| 33 CString* result) { | |
| 34 ASSERT1(result); | |
| 35 DWORD type = REG_NONE; | |
| 36 DWORD value = 0; | |
| 37 | |
| 38 HRESULT hr = key.GetValueType(value_name, &type); | |
| 39 if (FAILED(hr)) { | |
| 40 return hr; | |
| 41 } | |
| 42 | |
| 43 switch (type) { | |
| 44 case REG_DWORD: | |
| 45 hr = key.GetValue(value_name, &value); | |
| 46 if (FAILED(hr)) { | |
| 47 return hr; | |
| 48 } | |
| 49 *result = itostr(static_cast<const uint32>(value)); | |
| 50 return S_OK; | |
| 51 case REG_SZ: | |
| 52 return key.GetValue(value_name, result); | |
| 53 default: | |
| 54 return HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH); | |
| 55 } | |
| 56 } | |
| 57 | |
| 58 } // namespace | |
| 59 | |
| 60 ApplicationUsageData::ApplicationUsageData(bool is_machine, | |
| 61 bool check_low_integrity) | |
| 62 : exists_(false), | |
| 63 did_run_(false), | |
| 64 is_machine_(is_machine), | |
| 65 is_pre_update_check_(true), | |
| 66 check_low_integrity_(check_low_integrity) { | |
| 67 } | |
| 68 | |
| 69 ApplicationUsageData::~ApplicationUsageData() { | |
| 70 } | |
| 71 | |
| 72 HRESULT ApplicationUsageData::ReadDidRun(const CString& app_guid) { | |
| 73 CORE_LOG(L4, (_T("[ApplicationUsageData::ReadDidRun][%s]"), app_guid)); | |
| 74 is_pre_update_check_ = true; | |
| 75 HRESULT hr = ProcessDidRun(app_guid); | |
| 76 if (FAILED(hr)) { | |
| 77 CORE_LOG(LW, (_T("[ProcessDidRun failed][0x%08x]"), hr)); | |
| 78 return hr; | |
| 79 } | |
| 80 | |
| 81 return S_OK; | |
| 82 } | |
| 83 | |
| 84 ActiveStates ApplicationUsageData::active_state() const { | |
| 85 if (exists()) { | |
| 86 return did_run() ? ACTIVE_RUN : ACTIVE_NOTRUN; | |
| 87 } else { | |
| 88 return ACTIVE_UNKNOWN; | |
| 89 } | |
| 90 } | |
| 91 | |
| 92 HRESULT ApplicationUsageData::ResetDidRun(const CString& app_guid) { | |
| 93 CORE_LOG(L4, (_T("[ApplicationUsageData::ResetDidRun][%s]"), app_guid)); | |
| 94 is_pre_update_check_ = false; | |
| 95 return ProcessDidRun(app_guid); | |
| 96 } | |
| 97 | |
| 98 HRESULT ApplicationUsageData::ProcessDidRun(const CString& app_guid) { | |
| 99 CORE_LOG(L4, (_T("[ApplicationUsageData::ProcessDidRun][%s]"), app_guid)); | |
| 100 return is_machine_ ? ProcessMachineDidRun(app_guid) : | |
| 101 ProcessUserDidRun(app_guid); | |
| 102 } | |
| 103 | |
| 104 HRESULT ApplicationUsageData::ProcessMachineDidRun(const CString& app_guid) { | |
| 105 ASSERT1(is_machine_); | |
| 106 | |
| 107 // Logic is as follows: | |
| 108 // for each user under HKU\<sid> | |
| 109 // pre/post process HKU\<sid> | |
| 110 // if vista | |
| 111 // pre/post process HKU\<lowintegrity IE>\<sid> | |
| 112 // pre/post process HKLM | |
| 113 RegKey users_key; | |
| 114 HRESULT hr = users_key.Open(USERS_KEY, KEY_READ); | |
| 115 if (SUCCEEDED(hr)) { | |
| 116 uint32 num_users = users_key.GetSubkeyCount(); | |
| 117 for (uint32 i = 0; i < num_users; ++i) { | |
| 118 CString sub_key_name; | |
| 119 hr = users_key.GetSubkeyNameAt(i, &sub_key_name); | |
| 120 if (FAILED(hr)) { | |
| 121 CORE_LOG(LEVEL_WARNING, (_T("[Key enum failed.][0x%08x][%d][%s]"), | |
| 122 hr, i, USERS_KEY)); | |
| 123 continue; | |
| 124 } | |
| 125 | |
| 126 CString temp_key = AppendRegKeyPath(USERS_KEY, | |
| 127 sub_key_name, | |
| 128 GOOPDATE_REG_RELATIVE_CLIENT_STATE); | |
| 129 CString user_state_key_name = AppendRegKeyPath(temp_key, app_guid); | |
| 130 hr = ProcessKey(user_state_key_name); | |
| 131 if (FAILED(hr)) { | |
| 132 CORE_LOG(L4, (_T("[ProcessKey failed][%s][0x%08x]"), app_guid, hr)); | |
| 133 } | |
| 134 | |
| 135 if (check_low_integrity_) { | |
| 136 // If we are running on vista we need to also look at the low | |
| 137 // integrity IE key where IE can write to. Note that we cannot | |
| 138 // use the IEGetWriteableHKCU function since this function assumes | |
| 139 // that we are running with the user's credentials. | |
| 140 CString temp_key = AppendRegKeyPath(USERS_KEY, | |
| 141 sub_key_name, | |
| 142 USER_REG_VISTA_LOW_INTEGRITY_HKCU); | |
| 143 CString li_hkcu_name = AppendRegKeyPath( | |
| 144 AppendRegKeyPath( | |
| 145 temp_key, | |
| 146 sub_key_name, | |
| 147 GOOPDATE_REG_RELATIVE_CLIENT_STATE), | |
| 148 app_guid); | |
| 149 hr = ProcessKey(li_hkcu_name); | |
| 150 if (FAILED(hr)) { | |
| 151 CORE_LOG(L4, (_T("[ProcessKey failed][%s][0x%08x]"), app_guid, hr)); | |
| 152 } | |
| 153 } | |
| 154 } // End of for | |
| 155 | |
| 156 // Now Process the machine did run value also. | |
| 157 CString machine_state_key_name = | |
| 158 app_registry_utils::GetAppClientStateKey(true, app_guid); | |
| 159 hr = ProcessBackWardCompatKey(machine_state_key_name); | |
| 160 if (FAILED(hr)) { | |
| 161 CORE_LOG(L4, (_T("[ProcessBackWardCompatKey failed][0x%08x][%s]"), | |
| 162 hr, machine_state_key_name)); | |
| 163 } | |
| 164 } else { | |
| 165 CORE_LOG(LW, (_T("[Key open failed.][0x%08x][%s]"), hr, USERS_KEY)); | |
| 166 } | |
| 167 | |
| 168 return S_OK; | |
| 169 } | |
| 170 | |
| 171 HRESULT ApplicationUsageData::ProcessUserDidRun(const CString& app_guid) { | |
| 172 ASSERT1(!is_machine_); | |
| 173 | |
| 174 // Logic: | |
| 175 // Pre/Post process HKCU\ | |
| 176 // if vista: | |
| 177 // Pre/Post process HKCU\LowIntegrity | |
| 178 CString state_key_name = app_registry_utils::GetAppClientStateKey(false, | |
| 179 app_guid); | |
| 180 HRESULT hr = ProcessKey(state_key_name); | |
| 181 if (FAILED(hr)) { | |
| 182 CORE_LOG(L4, (_T("[ProcessKey failed][0x%08x][%s]"), | |
| 183 hr, state_key_name)); | |
| 184 } | |
| 185 | |
| 186 if (check_low_integrity_) { | |
| 187 // If we are running on vista we need to also look at the low | |
| 188 // integrity IE key where IE can write to. To avoid loading | |
| 189 // ieframe.dll into our process, we just use the registry | |
| 190 // key location directly instead of using IEGetWriteableHKCU | |
| 191 CString sid; | |
| 192 hr = user_info::GetProcessUser(NULL, NULL, &sid); | |
| 193 if (FAILED(hr)) { | |
| 194 CORE_LOG(LEVEL_WARNING, (_T("[GetProcessUser failed][0x%08x][%s]"), | |
| 195 hr, app_guid)); | |
| 196 return hr; | |
| 197 } | |
| 198 | |
| 199 CString temp_name = AppendRegKeyPath(USER_KEY_NAME, | |
| 200 USER_REG_VISTA_LOW_INTEGRITY_HKCU, | |
| 201 sid); | |
| 202 CString lowintegrity_hkcu_name = AppendRegKeyPath( | |
| 203 temp_name, | |
| 204 GOOPDATE_REG_RELATIVE_CLIENT_STATE, | |
| 205 app_guid); | |
| 206 hr = ProcessKey(lowintegrity_hkcu_name); | |
| 207 if (FAILED(hr)) { | |
| 208 CORE_LOG(LEVEL_WARNING, (_T("[Could not ProcessKey][0x%08x][%s]"), | |
| 209 hr, app_guid)); | |
| 210 } | |
| 211 } | |
| 212 | |
| 213 return S_OK; | |
| 214 } | |
| 215 | |
| 216 HRESULT ApplicationUsageData::ProcessKey(const CString& key_name) { | |
| 217 return is_pre_update_check_ ? ProcessPreUpdateCheck(key_name) : | |
| 218 ProcessPostUpdateCheck(key_name); | |
| 219 } | |
| 220 | |
| 221 HRESULT ApplicationUsageData::ProcessPreUpdateCheck(const CString& key_name) { | |
| 222 // Read in the regkey value if it exists, and or it with the previous value. | |
| 223 RegKey key; | |
| 224 HRESULT hr = key.Open(key_name, KEY_READ); | |
| 225 if (FAILED(hr)) { | |
| 226 CORE_LOG(L4, (_T("[failed to open key][%s][0x%08x]"), key_name, hr)); | |
| 227 return hr; | |
| 228 } | |
| 229 | |
| 230 // Now that we have the key, we should try and read the value of the | |
| 231 // did run key. | |
| 232 CString did_run_str(_T("0")); | |
| 233 hr = RegistryReadStringOrDword(key, kRegValueDidRun, &did_run_str); | |
| 234 if (FAILED(hr)) { | |
| 235 CORE_LOG(L3, (_T("[RegKey::GetValue failed][0x%08x][%s][%s]"), | |
| 236 hr, key_name, kRegValueDidRun)); | |
| 237 return hr; | |
| 238 } | |
| 239 | |
| 240 if (did_run_str == _T("1")) { | |
| 241 did_run_ = true; | |
| 242 } | |
| 243 exists_ = true; | |
| 244 | |
| 245 return hr; | |
| 246 } | |
| 247 | |
| 248 HRESULT ApplicationUsageData::ProcessBackWardCompatKey( | |
| 249 const CString& key_name) { | |
| 250 // This method exists to support the installers that have not been | |
| 251 // updated to write to the HKCU key. Remove when we have all the installers | |
| 252 // correcly updated. | |
| 253 if (is_pre_update_check_) { | |
| 254 // Read in the regkey value if it exists, and or it with the previous value. | |
| 255 RegKey key; | |
| 256 HRESULT hr = key.Open(key_name, KEY_READ); | |
| 257 if (FAILED(hr)) { | |
| 258 CORE_LOG(L4, (_T("[failed to open key][%s][0x%08x]"), key_name, hr)); | |
| 259 return hr; | |
| 260 } | |
| 261 | |
| 262 // Now that we have the key, we should try and read the value of the | |
| 263 // did run key. | |
| 264 CString did_run_str; | |
| 265 hr = RegistryReadStringOrDword(key, kRegValueDidRun, &did_run_str); | |
| 266 if (FAILED(hr)) { | |
| 267 CORE_LOG(L3, (_T("[RegKey::GetValue failed][0x%08x][%s][%s]"), | |
| 268 hr, key_name, kRegValueDidRun)); | |
| 269 return hr; | |
| 270 } | |
| 271 | |
| 272 if (did_run_str == _T("1")) { | |
| 273 did_run_ = true; | |
| 274 } | |
| 275 exists_ = true; | |
| 276 | |
| 277 return hr; | |
| 278 } else { | |
| 279 RegKey key; | |
| 280 HRESULT hr = key.Open(key_name); | |
| 281 if (FAILED(hr)) { | |
| 282 CORE_LOG(L4, (_T("[failed to open key][%s][0x%08x]"), key_name, hr)); | |
| 283 return hr; | |
| 284 } | |
| 285 | |
| 286 // If the value exists, then it means that the installer has been updated, | |
| 287 // and we delete the machine value. | |
| 288 if (exists_) { | |
| 289 hr = RegKey::DeleteValue(key_name, kRegValueDidRun); | |
| 290 if (FAILED(hr)) { | |
| 291 CORE_LOG(LEVEL_WARNING, (_T("[RegKey::DeleteValue failed][0x%08x][%s]"), | |
| 292 hr, key_name)); | |
| 293 return hr; | |
| 294 } | |
| 295 } else { | |
| 296 // Since the value does not exist else where, we reset the value in the | |
| 297 // HKLM key to zero. | |
| 298 exists_ = true; | |
| 299 CString did_run_str; | |
| 300 hr = RegistryReadStringOrDword(key, kRegValueDidRun, &did_run_str); | |
| 301 if (SUCCEEDED(hr)) { | |
| 302 hr = key.SetValue(kRegValueDidRun, _T("0")); | |
| 303 if (FAILED(hr)) { | |
| 304 CORE_LOG(LEVEL_WARNING, (_T("[RegKey::SetValue failed][0x%08x][%s]"), | |
| 305 hr, key_name)); | |
| 306 return hr; | |
| 307 } | |
| 308 } | |
| 309 } | |
| 310 } | |
| 311 | |
| 312 return S_OK; | |
| 313 } | |
| 314 | |
| 315 HRESULT ApplicationUsageData::ProcessPostUpdateCheck(const CString& key_name) { | |
| 316 RegKey key; | |
| 317 HRESULT hr = key.Open(key_name); | |
| 318 if (FAILED(hr)) { | |
| 319 CORE_LOG(L4, (_T("[failed to open key][%s][0x%08x]"), key_name, hr)); | |
| 320 return hr; | |
| 321 } | |
| 322 | |
| 323 CString did_run_str; | |
| 324 hr = RegistryReadStringOrDword(key, kRegValueDidRun, &did_run_str); | |
| 325 if (SUCCEEDED(hr)) { | |
| 326 exists_ = true; | |
| 327 hr = key.SetValue(kRegValueDidRun, _T("0")); | |
| 328 if (FAILED(hr)) { | |
| 329 CORE_LOG(LEVEL_WARNING, (_T("[RegKey::SetValue failed][0x%08x][%s]"), | |
| 330 hr, key_name)); | |
| 331 return hr; | |
| 332 } | |
| 333 } | |
| 334 return S_OK; | |
| 335 } | |
| 336 | |
| 337 } // namespace omaha | |
| OLD | NEW |