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 |