OLD | NEW |
| (Empty) |
1 // Copyright 2007-2009 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 <windows.h> | |
17 #include <msi.h> | |
18 #include <atlpath.h> | |
19 #include "base/scoped_ptr.h" | |
20 #include "omaha/base/app_util.h" | |
21 #include "omaha/base/atlregmapex.h" | |
22 #include "omaha/base/omaha_version.h" | |
23 #include "omaha/base/file.h" | |
24 #include "omaha/base/path.h" | |
25 #include "omaha/base/time.h" | |
26 #include "omaha/base/utils.h" | |
27 #include "omaha/base/vistautil.h" | |
28 #include "omaha/common/config_manager.h" | |
29 #include "omaha/common/const_cmd_line.h" | |
30 #include "omaha/common/const_goopdate.h" | |
31 #include "omaha/common/scheduled_task_utils.h" | |
32 #include "omaha/setup/msi_test_utils.h" | |
33 #include "omaha/setup/setup_google_update.h" | |
34 #include "omaha/testing/unit_test.h" | |
35 | |
36 namespace omaha { | |
37 | |
38 namespace { | |
39 | |
40 const TCHAR kMsiInstallRegValue[] = _T("MsiStubRun"); | |
41 const TCHAR kMsiUninstallKey[] = | |
42 _T("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\") | |
43 _T("Uninstall\\{A92DAB39-4E2C-4304-9AB6-BC44E68B55E2}"); | |
44 const TCHAR kRunKey[] = | |
45 _T("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"); | |
46 | |
47 const TCHAR* const kAppId1 = _T("{B7E61EF9-AAE5-4cdf-A2D3-E4C8DF975145}"); | |
48 const TCHAR* const kAppId2 = _T("{35F1A986-417D-4039-8718-781DD418232A}"); | |
49 | |
50 const TCHAR kRegistryHiveOverrideRootInHklm[] = | |
51 _T("HKLM\\Software\\") _T(SHORT_COMPANY_NAME_ANSI) | |
52 _T("\\") _T(PRODUCT_NAME_ANSI) | |
53 _T("\\UnitTest\\"); | |
54 | |
55 // Copies the shell and DLLs that FinishInstall needs. | |
56 // Does not replace files if they already exist. | |
57 void CopyFilesRequiredByFinishInstall(bool is_machine, const CString& version) { | |
58 const CString omaha_path = is_machine ? | |
59 GetGoogleUpdateMachinePath() : GetGoogleUpdateUserPath(); | |
60 const CString expected_shell_path = | |
61 ConcatenatePath(omaha_path, kOmahaShellFileName); | |
62 const CString version_path = ConcatenatePath(omaha_path, version); | |
63 | |
64 ASSERT_SUCCEEDED(CreateDir(omaha_path, NULL)); | |
65 ASSERT_SUCCEEDED(File::Copy( | |
66 ConcatenatePath(app_util::GetCurrentModuleDirectory(), | |
67 kOmahaShellFileName), | |
68 expected_shell_path, | |
69 false)); | |
70 | |
71 ASSERT_SUCCEEDED(CreateDir(version_path, NULL)); | |
72 | |
73 const TCHAR* files[] = {kOmahaDllName, | |
74 kHelperInstallerName, | |
75 // TODO(omaha3): Enable once this is being built. | |
76 #if 0 | |
77 _T("GoopdateBho.dll"), | |
78 #endif | |
79 UPDATE_PLUGIN_FILENAME}; | |
80 for (size_t i = 0; i < arraysize(files); ++i) { | |
81 ASSERT_SUCCEEDED(File::Copy( | |
82 ConcatenatePath(app_util::GetCurrentModuleDirectory(), | |
83 files[i]), | |
84 ConcatenatePath(version_path, files[i]), | |
85 false)); | |
86 } | |
87 } | |
88 | |
89 // RegisterOrUnregisterCOMLocalServer() called from FinishInstall() runs in a | |
90 // separate process. When using registry redirection in the test, the new | |
91 // process writes to the real registry, so the unit test fails. This function | |
92 // creates dummy entries that VerifyCOMLocalServerRegistration() verifies, and | |
93 // is happy about. | |
94 void SetupCOMLocalServerRegistration(bool is_machine) { | |
95 // Setup the following for the unit test: | |
96 // * LocalServer32 under CLSID_OnDemandMachineAppsClass or | |
97 // CLSID_OnDemandUserAppsClass should be the current exe's module path. | |
98 // * InProcServer32 under CLSID of IID_IGoogleUpdate should be the path of the | |
99 // current module. | |
100 // * ProxyStubClsid32 under IGoogleUpdate interface should be the CLSID of the | |
101 // proxy, which is PROXY_CLSID_IS. | |
102 | |
103 CString base_clsid_key(is_machine ? _T("HKLM") : _T("HKCU")); | |
104 base_clsid_key += _T("\\Software\\Classes\\CLSID\\"); | |
105 CString ondemand_clsid_key(base_clsid_key); | |
106 // TODO(omaha3): Implement this for Omaha 3. | |
107 #if 0 | |
108 ondemand_clsid_key += GuidToString(is_machine ? | |
109 __uuidof(OnDemandMachineAppsClass) : | |
110 __uuidof(OnDemandUserAppsClass)); | |
111 CString local_server_key(ondemand_clsid_key + _T("\\LocalServer32")); | |
112 CString expected_server(app_util::GetModulePath(NULL)); | |
113 EnclosePath(&expected_server); | |
114 ASSERT_FALSE(expected_server.IsEmpty()); | |
115 ASSERT_SUCCEEDED(RegKey::SetValue(local_server_key, | |
116 NULL, | |
117 expected_server)); | |
118 | |
119 const GUID proxy_clsid = PROXY_CLSID_IS; | |
120 CString ondemand_proxy_clsid_key(base_clsid_key); | |
121 ondemand_proxy_clsid_key += GuidToString(proxy_clsid); | |
122 CString inproc_server_key(ondemand_proxy_clsid_key + _T("\\InProcServer32")); | |
123 expected_server = app_util::GetCurrentModulePath(); | |
124 ASSERT_FALSE(expected_server.IsEmpty()); | |
125 ASSERT_SUCCEEDED(RegKey::SetValue(inproc_server_key, | |
126 NULL, | |
127 expected_server)); | |
128 | |
129 CString igoogleupdate_interface_key(is_machine ? _T("HKLM") : _T("HKCU")); | |
130 igoogleupdate_interface_key += _T("\\Software\\Classes\\Interface\\"); | |
131 igoogleupdate_interface_key += GuidToString(__uuidof(IGoogleUpdate)); | |
132 igoogleupdate_interface_key += _T("\\ProxyStubClsid32"); | |
133 CString proxy_interface_value(GuidToString(proxy_clsid)); | |
134 ASSERT_FALSE(proxy_interface_value.IsEmpty()); | |
135 ASSERT_SUCCEEDED(RegKey::SetValue(igoogleupdate_interface_key, | |
136 NULL, | |
137 proxy_interface_value)); | |
138 #endif | |
139 } | |
140 | |
141 void VerifyAccessRightsForTrustee(const CString& key_name, | |
142 ACCESS_MASK expected_access_rights, | |
143 CDacl* dacl, | |
144 TRUSTEE* trustee) { | |
145 CString fail_message; | |
146 fail_message.Format(_T("Key: %s; Trustee: "), key_name); | |
147 if (TRUSTEE_IS_NAME == trustee->TrusteeForm) { | |
148 fail_message.Append(trustee->ptstrName); | |
149 } else { | |
150 EXPECT_TRUE(TRUSTEE_IS_SID == trustee->TrusteeForm); | |
151 fail_message.Append(_T("is a SID")); | |
152 } | |
153 | |
154 // Cast away the const so the pointer can be passed to the API. This should | |
155 // be safe for these purposes and because this is a unit test. | |
156 PACL pacl = const_cast<PACL>(dacl->GetPACL()); | |
157 ACCESS_MASK access_rights = 0; | |
158 EXPECT_EQ(ERROR_SUCCESS, ::GetEffectiveRightsFromAcl(pacl, | |
159 trustee, | |
160 &access_rights)) << | |
161 fail_message.GetString(); | |
162 EXPECT_EQ(expected_access_rights, access_rights) << fail_message.GetString(); | |
163 } | |
164 | |
165 // TODO(omaha): It would be nice to test the access for a non-admin process. | |
166 // The test requires admin privileges to run, so this would likely require | |
167 // running a de-elevated process. | |
168 void VerifyHklmKeyHasIntegrity( | |
169 const CString& key_name, | |
170 ACCESS_MASK expected_non_admin_interactive_access) { | |
171 | |
172 // These checks can take a long time, so avoid them by default. | |
173 if (!ShouldRunEnormousTest()) { | |
174 return; | |
175 } | |
176 | |
177 const ACCESS_MASK kExpectedPowerUsersAccess = vista_util::IsVistaOrLater() ? | |
178 0 : DELETE | READ_CONTROL | KEY_READ | KEY_WRITE; | |
179 | |
180 CDacl dacl; | |
181 RegKey key; | |
182 EXPECT_SUCCEEDED(key.Open(key_name)); | |
183 EXPECT_TRUE(::AtlGetDacl(key.Key(), SE_REGISTRY_KEY, &dacl)); | |
184 | |
185 CString current_user_sid_string; | |
186 EXPECT_SUCCEEDED( | |
187 user_info::GetProcessUser(NULL, NULL, ¤t_user_sid_string)); | |
188 PSID current_user_sid = NULL; | |
189 EXPECT_TRUE(ConvertStringSidToSid(current_user_sid_string, | |
190 ¤t_user_sid)); | |
191 TRUSTEE current_user = {0}; | |
192 current_user.TrusteeForm = TRUSTEE_IS_SID; | |
193 current_user.TrusteeType = TRUSTEE_IS_USER; | |
194 current_user.ptstrName = static_cast<LPTSTR>(current_user_sid); | |
195 VerifyAccessRightsForTrustee(key_name, KEY_ALL_ACCESS, &dacl, ¤t_user); | |
196 EXPECT_FALSE(::LocalFree(current_user_sid)); | |
197 | |
198 PSID local_system_sid = NULL; | |
199 EXPECT_TRUE(ConvertStringSidToSid(kLocalSystemSid, &local_system_sid)); | |
200 TRUSTEE local_system = {0}; | |
201 local_system.TrusteeForm = TRUSTEE_IS_SID; | |
202 local_system.TrusteeType = TRUSTEE_IS_USER; | |
203 local_system.ptstrName = static_cast<LPTSTR>(local_system_sid); | |
204 VerifyAccessRightsForTrustee(key_name, KEY_ALL_ACCESS, &dacl, &local_system); | |
205 EXPECT_FALSE(::LocalFree(local_system_sid)); | |
206 | |
207 TRUSTEE administrators = {0}; | |
208 administrators.TrusteeForm = TRUSTEE_IS_NAME; | |
209 administrators.TrusteeType = TRUSTEE_IS_GROUP; | |
210 administrators.ptstrName = _T("Administrators"); | |
211 VerifyAccessRightsForTrustee(key_name, | |
212 KEY_ALL_ACCESS, | |
213 &dacl, | |
214 &administrators); | |
215 | |
216 TRUSTEE users = {0}; | |
217 users.TrusteeForm = TRUSTEE_IS_NAME; | |
218 users.TrusteeType = TRUSTEE_IS_GROUP; | |
219 users.ptstrName = _T("Users"); | |
220 VerifyAccessRightsForTrustee(key_name, KEY_READ, &dacl, &users); | |
221 | |
222 TRUSTEE power_users = {0}; | |
223 power_users.TrusteeForm = TRUSTEE_IS_NAME; | |
224 power_users.TrusteeType = TRUSTEE_IS_GROUP; | |
225 power_users.ptstrName = _T("Power Users"); | |
226 VerifyAccessRightsForTrustee(key_name, | |
227 kExpectedPowerUsersAccess, | |
228 &dacl, | |
229 &power_users); | |
230 | |
231 TRUSTEE interactive = {0}; | |
232 interactive.TrusteeForm = TRUSTEE_IS_NAME; | |
233 interactive.TrusteeType = TRUSTEE_IS_GROUP; | |
234 interactive.ptstrName = _T("INTERACTIVE"); | |
235 VerifyAccessRightsForTrustee(key_name, | |
236 expected_non_admin_interactive_access, | |
237 &dacl, | |
238 &interactive); | |
239 | |
240 TRUSTEE everyone = {0}; | |
241 everyone.TrusteeForm = TRUSTEE_IS_NAME; | |
242 everyone.TrusteeType = TRUSTEE_IS_GROUP; | |
243 everyone.ptstrName = _T("Everyone"); | |
244 VerifyAccessRightsForTrustee(key_name, 0, &dacl, &everyone); | |
245 | |
246 TRUSTEE guest = {0}; | |
247 guest.TrusteeForm = TRUSTEE_IS_NAME; | |
248 guest.TrusteeType = TRUSTEE_IS_USER; | |
249 guest.ptstrName = _T("Guest"); | |
250 VerifyAccessRightsForTrustee(key_name, 0, &dacl, &guest); | |
251 } | |
252 | |
253 } // namespace | |
254 | |
255 // INTERACTIVE group inherits privileges from Users in the default case. | |
256 void VerifyHklmKeyHasDefaultIntegrity(const CString& key_full_name) { | |
257 VerifyHklmKeyHasIntegrity(key_full_name, KEY_READ); | |
258 } | |
259 | |
260 void VerifyHklmKeyHasMediumIntegrity(const CString& key_full_name) { | |
261 VerifyHklmKeyHasIntegrity(key_full_name, KEY_READ | KEY_SET_VALUE); | |
262 } | |
263 | |
264 class SetupGoogleUpdateTest : public testing::Test { | |
265 protected: | |
266 explicit SetupGoogleUpdateTest(bool is_machine) | |
267 : is_machine_(is_machine) { | |
268 } | |
269 | |
270 virtual void SetUp() { | |
271 setup_google_update_.reset(new SetupGoogleUpdate(is_machine_)); | |
272 } | |
273 | |
274 HRESULT InstallRegistryValues() { | |
275 return setup_google_update_->InstallRegistryValues(); | |
276 } | |
277 | |
278 HRESULT InstallLaunchMechanisms() { | |
279 return setup_google_update_->InstallLaunchMechanisms(); | |
280 } | |
281 | |
282 void UninstallLaunchMechanisms() { | |
283 setup_google_update_->UninstallLaunchMechanisms(); | |
284 } | |
285 | |
286 HRESULT CreateClientStateMedium() { | |
287 return setup_google_update_->CreateClientStateMedium(); | |
288 } | |
289 | |
290 HRESULT InstallMsiHelper() { | |
291 return setup_google_update_->InstallMsiHelper(); | |
292 } | |
293 | |
294 HRESULT UninstallMsiHelper() { | |
295 return setup_google_update_->UninstallMsiHelper(); | |
296 } | |
297 | |
298 bool is_machine_; | |
299 scoped_ptr<SetupGoogleUpdate> setup_google_update_; | |
300 }; | |
301 | |
302 class SetupGoogleUpdateUserTest : public SetupGoogleUpdateTest { | |
303 protected: | |
304 SetupGoogleUpdateUserTest() | |
305 : SetupGoogleUpdateTest(false) { | |
306 } | |
307 }; | |
308 | |
309 class SetupGoogleUpdateMachineTest : public SetupGoogleUpdateTest { | |
310 protected: | |
311 SetupGoogleUpdateMachineTest() | |
312 : SetupGoogleUpdateTest(true) { | |
313 } | |
314 }; | |
315 | |
316 class SetupGoogleUpdateUserRegistryProtectedTest | |
317 : public SetupGoogleUpdateUserTest { | |
318 protected: | |
319 SetupGoogleUpdateUserRegistryProtectedTest() | |
320 : SetupGoogleUpdateUserTest(), | |
321 hive_override_key_name_(kRegistryHiveOverrideRoot) { | |
322 const CString expected_shell_path = | |
323 ConcatenatePath(GetGoogleUpdateUserPath(), kOmahaShellFileName); | |
324 expected_run_key_value_.Format(_T("\"%s\" /c"), expected_shell_path); | |
325 } | |
326 | |
327 virtual void SetUp() { | |
328 RegKey::DeleteKey(hive_override_key_name_, true); | |
329 // Do not override HKLM because it contains the CSIDL_* definitions. | |
330 OverrideSpecifiedRegistryHives(hive_override_key_name_, false, true); | |
331 | |
332 SetupGoogleUpdateUserTest::SetUp(); | |
333 } | |
334 | |
335 virtual void TearDown() { | |
336 SetupGoogleUpdateUserTest::TearDown(); | |
337 | |
338 RestoreRegistryHives(); | |
339 ASSERT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true)); | |
340 } | |
341 | |
342 CString hive_override_key_name_; | |
343 CString expected_run_key_value_; | |
344 }; | |
345 | |
346 class SetupGoogleUpdateMachineRegistryProtectedTest | |
347 : public SetupGoogleUpdateMachineTest { | |
348 protected: | |
349 SetupGoogleUpdateMachineRegistryProtectedTest() | |
350 : SetupGoogleUpdateMachineTest(), | |
351 hive_override_key_name_(kRegistryHiveOverrideRoot) { | |
352 } | |
353 | |
354 virtual void SetUp() { | |
355 RegKey::DeleteKey(hive_override_key_name_, true); | |
356 OverrideRegistryHives(hive_override_key_name_); | |
357 | |
358 // Add CSIDL values needed by the tests. | |
359 ASSERT_SUCCEEDED(RegKey::SetValue(kCsidlSystemIdsRegKey, | |
360 kCsidlProgramFilesRegValue, | |
361 _T("C:\\Program Files"))); | |
362 | |
363 SetupGoogleUpdateMachineTest::SetUp(); | |
364 } | |
365 | |
366 virtual void TearDown() { | |
367 SetupGoogleUpdateMachineTest::TearDown(); | |
368 | |
369 RestoreRegistryHives(); | |
370 ASSERT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true)); | |
371 } | |
372 | |
373 CString hive_override_key_name_; | |
374 }; | |
375 | |
376 // There are a few tests where keys need to inherit the HKLM privileges, so put | |
377 // the override root in HKLM. All tests using this framework must run as admin. | |
378 class SetupGoogleUpdateMachineRegistryProtectedInHklmTest | |
379 : public SetupGoogleUpdateMachineRegistryProtectedTest { | |
380 protected: | |
381 SetupGoogleUpdateMachineRegistryProtectedInHklmTest() | |
382 : SetupGoogleUpdateMachineRegistryProtectedTest() { | |
383 hive_override_key_name_ = kRegistryHiveOverrideRootInHklm; | |
384 } | |
385 }; | |
386 | |
387 // This test uninstalls all other versions of Omaha. | |
388 TEST_F(SetupGoogleUpdateUserRegistryProtectedTest, | |
389 FinishInstall_RunKeyDoesNotExist) { | |
390 if (!ShouldRunLargeTest()) { | |
391 return; | |
392 } | |
393 | |
394 // The version in the real registry must be set because it is used by | |
395 // GoogleUpdate.exe during registrations. | |
396 RestoreRegistryHives(); | |
397 const bool had_pv = RegKey::HasValue(USER_REG_CLIENTS_GOOPDATE, | |
398 kRegValueProductVersion); | |
399 EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE, | |
400 kRegValueProductVersion, | |
401 GetVersionString())); | |
402 OverrideSpecifiedRegistryHives(hive_override_key_name_, false, true); | |
403 | |
404 CopyFilesRequiredByFinishInstall(is_machine_, GetVersionString()); | |
405 SetupCOMLocalServerRegistration(is_machine_); | |
406 | |
407 EXPECT_SUCCEEDED(RegKey::CreateKey(_T("HKCU\\Software\\Classes"))); | |
408 | |
409 ASSERT_FALSE(RegKey::HasKey(kRunKey)); | |
410 | |
411 EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE, | |
412 _T("mi"), | |
413 _T("39980C99-CDD5-43A0-93C7-69D90C14729"))); | |
414 EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE, | |
415 _T("mi"), | |
416 _T("39980C99-CDD5-43A0-93C7-69D90C14729"))); | |
417 EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE, | |
418 _T("ui"), | |
419 _T("49980C99-CDD5-43A0-93C7-69D90C14729"))); | |
420 | |
421 EXPECT_SUCCEEDED(setup_google_update_->FinishInstall()); | |
422 | |
423 // Check the system state. | |
424 | |
425 CPath expected_shell_path(GetGoogleUpdateUserPath()); | |
426 expected_shell_path.Append(kOmahaShellFileName); | |
427 CString shell_path; | |
428 EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_UPDATE, _T("path"), &shell_path)); | |
429 EXPECT_STREQ(expected_shell_path, shell_path); | |
430 | |
431 CString value; | |
432 EXPECT_SUCCEEDED(RegKey::GetValue(kRunKey, | |
433 _T(OMAHA_APP_NAME_ANSI), | |
434 &value)); | |
435 EXPECT_STREQ(expected_run_key_value_, value); | |
436 EXPECT_TRUE(scheduled_task_utils::IsInstalledGoopdateTaskUA(false)); | |
437 EXPECT_FALSE(scheduled_task_utils::IsDisabledGoopdateTaskUA(false)); | |
438 | |
439 EXPECT_SUCCEEDED( | |
440 RegKey::GetValue(USER_REG_UPDATE, kRegValueInstalledVersion, &value)); | |
441 EXPECT_EQ(GetVersionString(), value); | |
442 EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, kRegValueLastChecked)); | |
443 | |
444 EXPECT_TRUE(RegKey::HasValue(USER_REG_UPDATE, _T("mi"))); | |
445 EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("mi"))); | |
446 EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("ui"))); | |
447 | |
448 // TODO(omaha): Check for other state. | |
449 | |
450 // Clean up the launch mechanisms, at least one of which is not in the | |
451 // overriding registry. | |
452 UninstallLaunchMechanisms(); | |
453 EXPECT_FALSE(RegKey::HasValue(kRunKey, _T(OMAHA_APP_NAME_ANSI))); | |
454 EXPECT_FALSE(scheduled_task_utils::IsInstalledGoopdateTaskUA(false)); | |
455 | |
456 if (!had_pv) { | |
457 // Delete the pv value. Some tests or shell .exe instances may see this | |
458 // value and assume Omaha is correctly installed. | |
459 RestoreRegistryHives(); | |
460 EXPECT_SUCCEEDED(RegKey::DeleteValue(USER_REG_CLIENTS_GOOPDATE, | |
461 kRegValueProductVersion)); | |
462 } | |
463 } | |
464 | |
465 // TODO(omaha): Assumes GoogleUpdate.exe exists in the installed location, which | |
466 // is not always true when run independently. | |
467 TEST_F(SetupGoogleUpdateUserRegistryProtectedTest, InstallRegistryValues) { | |
468 if (IsTestRunByLocalSystem()) { | |
469 return; | |
470 } | |
471 | |
472 // For this test only, we must also override HKLM in order to check that | |
473 // MACHINE_REG_CLIENT_STATE_MEDIUM was not created. | |
474 // Get the correct value of and set the CSIDL value needed by the test. | |
475 CString profile_path; | |
476 EXPECT_SUCCEEDED(GetFolderPath(CSIDL_PROFILE, &profile_path)); | |
477 OverrideSpecifiedRegistryHives(hive_override_key_name_, true, true); | |
478 CString user_sid; | |
479 EXPECT_SUCCEEDED(user_info::GetProcessUser(NULL, NULL, &user_sid)); | |
480 const TCHAR* const kProfileListKey = | |
481 _T("HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\") | |
482 _T("ProfileList\\"); | |
483 const CString profile_path_key = kProfileListKey + user_sid; | |
484 EXPECT_SUCCEEDED( | |
485 RegKey::SetValue(profile_path_key, _T("ProfileImagePath"), profile_path)); | |
486 | |
487 EXPECT_SUCCEEDED(InstallRegistryValues()); | |
488 const uint32 now = Time64ToInt32(GetCurrent100NSTime()); | |
489 | |
490 EXPECT_TRUE(RegKey::HasKey(USER_REG_GOOGLE)); | |
491 EXPECT_TRUE(RegKey::HasKey(USER_REG_UPDATE)); | |
492 EXPECT_TRUE(RegKey::HasKey(USER_REG_CLIENTS)); | |
493 EXPECT_TRUE(RegKey::HasKey(USER_REG_CLIENT_STATE)); | |
494 EXPECT_TRUE(RegKey::HasKey(USER_REG_CLIENTS_GOOPDATE)); | |
495 EXPECT_TRUE(RegKey::HasKey(USER_REG_CLIENT_STATE_GOOPDATE)); | |
496 EXPECT_FALSE(RegKey::HasKey(MACHINE_REG_CLIENT_STATE_MEDIUM)); | |
497 | |
498 // Ensure no unexpected keys were created. | |
499 RegKey google_key; | |
500 EXPECT_SUCCEEDED(google_key.Open(USER_REG_GOOGLE)); | |
501 EXPECT_EQ(1, google_key.GetSubkeyCount()); | |
502 | |
503 RegKey update_key; | |
504 EXPECT_SUCCEEDED(update_key.Open(USER_REG_UPDATE)); | |
505 EXPECT_EQ(2, update_key.GetSubkeyCount()); | |
506 | |
507 RegKey clients_key; | |
508 EXPECT_SUCCEEDED(clients_key.Open(USER_REG_CLIENTS)); | |
509 EXPECT_EQ(1, clients_key.GetSubkeyCount()); | |
510 | |
511 RegKey client_state_key; | |
512 EXPECT_SUCCEEDED(client_state_key.Open(USER_REG_CLIENT_STATE)); | |
513 EXPECT_EQ(1, client_state_key.GetSubkeyCount()); | |
514 | |
515 CPath expected_shell_path(GetGoogleUpdateUserPath()); | |
516 expected_shell_path.Append(kOmahaShellFileName); | |
517 CString shell_path; | |
518 EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_UPDATE, _T("path"), &shell_path)); | |
519 EXPECT_STREQ(expected_shell_path, shell_path); | |
520 | |
521 CString product_version; | |
522 EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE, | |
523 _T("pv"), | |
524 &product_version)); | |
525 EXPECT_STREQ(GetVersionString(), product_version); | |
526 } | |
527 | |
528 // TODO(omaha): Assumes GoogleUpdate.exe exists in the installed location, which | |
529 // is not always true when run independently. | |
530 // TODO(omaha): Fails when run by itself on Windows Vista. | |
531 TEST_F(SetupGoogleUpdateMachineRegistryProtectedInHklmTest, | |
532 InstallRegistryValues) { | |
533 EXPECT_SUCCEEDED(InstallRegistryValues()); | |
534 const uint32 now = Time64ToInt32(GetCurrent100NSTime()); | |
535 | |
536 EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_GOOGLE)); | |
537 EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_UPDATE)); | |
538 EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENTS)); | |
539 EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENT_STATE)); | |
540 EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENTS_GOOPDATE)); | |
541 EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENT_STATE_GOOPDATE)); | |
542 EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENT_STATE_MEDIUM)); | |
543 | |
544 // Ensure no unexpected keys were created. | |
545 RegKey google_key; | |
546 EXPECT_SUCCEEDED(google_key.Open(MACHINE_REG_GOOGLE)); | |
547 EXPECT_EQ(1, google_key.GetSubkeyCount()); | |
548 | |
549 RegKey update_key; | |
550 EXPECT_SUCCEEDED(update_key.Open(MACHINE_REG_UPDATE)); | |
551 EXPECT_EQ(3, update_key.GetSubkeyCount()); | |
552 | |
553 RegKey clients_key; | |
554 EXPECT_SUCCEEDED(clients_key.Open(MACHINE_REG_CLIENTS)); | |
555 EXPECT_EQ(1, clients_key.GetSubkeyCount()); | |
556 | |
557 RegKey client_state_key; | |
558 EXPECT_SUCCEEDED(client_state_key.Open(MACHINE_REG_CLIENT_STATE)); | |
559 EXPECT_EQ(1, client_state_key.GetSubkeyCount()); | |
560 | |
561 RegKey client_state_medium_key; | |
562 EXPECT_SUCCEEDED( | |
563 client_state_medium_key.Open(MACHINE_REG_CLIENT_STATE_MEDIUM)); | |
564 EXPECT_EQ(0, client_state_medium_key.GetSubkeyCount()); | |
565 VerifyHklmKeyHasDefaultIntegrity(MACHINE_REG_CLIENT_STATE_MEDIUM); | |
566 | |
567 CString expected_shell_path; | |
568 EXPECT_SUCCEEDED(GetFolderPath(CSIDL_PROGRAM_FILES, &expected_shell_path)); | |
569 expected_shell_path.Append(_T("\\") SHORT_COMPANY_NAME | |
570 _T("\\") PRODUCT_NAME | |
571 _T("\\GoogleUpdate.exe")); | |
572 CString shell_path; | |
573 EXPECT_SUCCEEDED( | |
574 RegKey::GetValue(MACHINE_REG_UPDATE, _T("path"), &shell_path)); | |
575 EXPECT_STREQ(expected_shell_path, shell_path); | |
576 | |
577 CString product_version; | |
578 EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE, | |
579 _T("pv"), | |
580 &product_version)); | |
581 EXPECT_STREQ(GetVersionString(), product_version); | |
582 | |
583 // Test permission of Update and ClientState. ClientStateMedium checked above. | |
584 VerifyHklmKeyHasDefaultIntegrity(MACHINE_REG_UPDATE); | |
585 VerifyHklmKeyHasDefaultIntegrity(MACHINE_REG_CLIENT_STATE); | |
586 | |
587 // Test the permission inheritance for ClientStateMedium. | |
588 const CString app_client_state_medium_key_name = AppendRegKeyPath( | |
589 MACHINE_REG_CLIENT_STATE_MEDIUM, | |
590 kAppId1); | |
591 EXPECT_SUCCEEDED(RegKey::CreateKey(app_client_state_medium_key_name)); | |
592 | |
593 VerifyHklmKeyHasMediumIntegrity(app_client_state_medium_key_name); | |
594 } | |
595 | |
596 TEST_F(SetupGoogleUpdateMachineRegistryProtectedInHklmTest, | |
597 CreateClientStateMedium_KeyAlreadyExistsWithSamePermissions) { | |
598 EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_UPDATE)); | |
599 EXPECT_SUCCEEDED(CreateClientStateMedium()); | |
600 VerifyHklmKeyHasDefaultIntegrity(MACHINE_REG_CLIENT_STATE_MEDIUM); | |
601 | |
602 EXPECT_SUCCEEDED(CreateClientStateMedium()); | |
603 VerifyHklmKeyHasDefaultIntegrity(MACHINE_REG_CLIENT_STATE_MEDIUM); | |
604 } | |
605 | |
606 // CreateClientStateMedium does not replace permissions on existing keys. | |
607 TEST_F(SetupGoogleUpdateMachineRegistryProtectedInHklmTest, | |
608 CreateClientStateMedium_KeysAlreadyExistWithDifferentPermissions) { | |
609 // The checks in this test can take a long time, so avoid them by default. | |
610 if (!ShouldRunEnormousTest()) { | |
611 return; | |
612 } | |
613 | |
614 const CString app1_client_state_medium_key_name = AppendRegKeyPath( | |
615 MACHINE_REG_CLIENT_STATE_MEDIUM, | |
616 kAppId1); | |
617 const CString app2_client_state_medium_key_name = AppendRegKeyPath( | |
618 MACHINE_REG_CLIENT_STATE_MEDIUM, | |
619 kAppId2); | |
620 | |
621 TRUSTEE users = {0}; | |
622 users.TrusteeForm = TRUSTEE_IS_NAME; | |
623 users.TrusteeType = TRUSTEE_IS_GROUP; | |
624 users.ptstrName = _T("Users"); | |
625 | |
626 TRUSTEE interactive = {0}; | |
627 interactive.TrusteeForm = TRUSTEE_IS_NAME; | |
628 interactive.TrusteeType = TRUSTEE_IS_GROUP; | |
629 interactive.ptstrName = _T("INTERACTIVE"); | |
630 | |
631 EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_UPDATE)); | |
632 | |
633 CDacl dacl; | |
634 dacl.AddAllowedAce(Sids::Admins(), GENERIC_ALL); | |
635 // Interactive is not explicitly set. | |
636 dacl.AddAllowedAce(Sids::Users(), KEY_WRITE); | |
637 | |
638 CSecurityDesc security_descriptor; | |
639 security_descriptor.SetDacl(dacl); | |
640 security_descriptor.MakeAbsolute(); | |
641 | |
642 CSecurityAttributes sa; | |
643 sa.Set(security_descriptor); | |
644 | |
645 EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_CLIENT_STATE_MEDIUM, | |
646 REG_NONE, | |
647 REG_OPTION_NON_VOLATILE, | |
648 &sa)); | |
649 | |
650 EXPECT_SUCCEEDED(RegKey::CreateKey(app1_client_state_medium_key_name)); | |
651 | |
652 | |
653 EXPECT_SUCCEEDED(CreateClientStateMedium()); | |
654 | |
655 // Verify the ACLs for the existing keys were not changed. | |
656 // INTERACTIVE appears to inherit the privileges of Users. | |
657 VerifyAccessRightsForTrustee( | |
658 MACHINE_REG_CLIENT_STATE_MEDIUM, KEY_WRITE, &dacl, &users); | |
659 VerifyAccessRightsForTrustee( | |
660 MACHINE_REG_CLIENT_STATE_MEDIUM, KEY_WRITE, &dacl, &interactive); | |
661 VerifyAccessRightsForTrustee( | |
662 app1_client_state_medium_key_name, KEY_WRITE, &dacl, &users); | |
663 VerifyAccessRightsForTrustee( | |
664 app1_client_state_medium_key_name, KEY_WRITE, &dacl, &interactive); | |
665 | |
666 // Verify the ACLs of newly created subkeys. | |
667 EXPECT_SUCCEEDED(RegKey::CreateKey(app2_client_state_medium_key_name)); | |
668 VerifyAccessRightsForTrustee( | |
669 app2_client_state_medium_key_name, KEY_WRITE, &dacl, &users); | |
670 VerifyAccessRightsForTrustee( | |
671 app2_client_state_medium_key_name, KEY_WRITE, &dacl, &interactive); | |
672 } | |
673 | |
674 TEST_F(SetupGoogleUpdateUserRegistryProtectedTest, | |
675 InstallLaunchMechanisms_RunKeyValueExists) { | |
676 EXPECT_SUCCEEDED(RegKey::SetValue(kRunKey, | |
677 _T(OMAHA_APP_NAME_ANSI), | |
678 _T("fo /b"))); | |
679 | |
680 EXPECT_SUCCEEDED(InstallLaunchMechanisms()); | |
681 | |
682 CString value; | |
683 EXPECT_SUCCEEDED(RegKey::GetValue(kRunKey, | |
684 _T(OMAHA_APP_NAME_ANSI), | |
685 &value)); | |
686 EXPECT_STREQ(expected_run_key_value_, value); | |
687 EXPECT_TRUE(scheduled_task_utils::IsInstalledGoopdateTaskUA(false)); | |
688 EXPECT_FALSE(scheduled_task_utils::IsDisabledGoopdateTaskUA(false)); | |
689 | |
690 UninstallLaunchMechanisms(); | |
691 EXPECT_FALSE(RegKey::HasValue(kRunKey, _T(OMAHA_APP_NAME_ANSI))); | |
692 EXPECT_FALSE(scheduled_task_utils::IsInstalledGoopdateTaskUA(false)); | |
693 } | |
694 | |
695 TEST_F(SetupGoogleUpdateUserRegistryProtectedTest, | |
696 InstallLaunchMechanisms_RunKeyDoesNotExist) { | |
697 ASSERT_FALSE(RegKey::HasKey(kRunKey)); | |
698 | |
699 EXPECT_SUCCEEDED(InstallLaunchMechanisms()); | |
700 | |
701 CString value; | |
702 EXPECT_SUCCEEDED(RegKey::GetValue(kRunKey, | |
703 _T(OMAHA_APP_NAME_ANSI), | |
704 &value)); | |
705 EXPECT_STREQ(expected_run_key_value_, value); | |
706 EXPECT_TRUE(scheduled_task_utils::IsInstalledGoopdateTaskUA(false)); | |
707 EXPECT_FALSE(scheduled_task_utils::IsDisabledGoopdateTaskUA(false)); | |
708 | |
709 UninstallLaunchMechanisms(); | |
710 EXPECT_FALSE(RegKey::HasValue(kRunKey, _T(OMAHA_APP_NAME_ANSI))); | |
711 EXPECT_FALSE(scheduled_task_utils::IsInstalledGoopdateTaskUA(false)); | |
712 } | |
713 | |
714 // The helper can be installed when the test begins. | |
715 // It will not be installed when the test successfully completes. | |
716 TEST_F(SetupGoogleUpdateMachineTest, InstallAndUninstallMsiHelper) { | |
717 if (!ShouldRunLargeTest()) { | |
718 return; | |
719 } | |
720 const TCHAR* MsiInstallRegValueKey = | |
721 ConfigManager::Instance()->machine_registry_update(); | |
722 | |
723 CopyFilesRequiredByFinishInstall(is_machine_, GetVersionString()); | |
724 | |
725 if (vista_util::IsUserAdmin()) { | |
726 // Prepare for the test - make sure the helper isn't installed. | |
727 EXPECT_HRESULT_SUCCEEDED(UninstallMsiHelper()); | |
728 EXPECT_FALSE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue)); | |
729 EXPECT_FALSE(RegKey::HasKey(kMsiUninstallKey)); | |
730 | |
731 // Verify installation. | |
732 DWORD reg_value = 0xffffffff; | |
733 EXPECT_HRESULT_SUCCEEDED(InstallMsiHelper()); | |
734 EXPECT_TRUE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue)); | |
735 EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(MsiInstallRegValueKey, | |
736 kMsiInstallRegValue, | |
737 ®_value)); | |
738 EXPECT_EQ(0, reg_value); | |
739 EXPECT_TRUE(RegKey::HasKey(kMsiUninstallKey)); | |
740 | |
741 // Verify over-install. | |
742 EXPECT_HRESULT_SUCCEEDED(InstallMsiHelper()); | |
743 EXPECT_TRUE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue)); | |
744 EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(MsiInstallRegValueKey, | |
745 kMsiInstallRegValue, | |
746 ®_value)); | |
747 EXPECT_EQ(0, reg_value); | |
748 EXPECT_TRUE(RegKey::HasKey(kMsiUninstallKey)); | |
749 | |
750 // Verify uninstall. | |
751 EXPECT_HRESULT_SUCCEEDED(UninstallMsiHelper()); | |
752 EXPECT_FALSE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue)); | |
753 EXPECT_FALSE(RegKey::HasKey(kMsiUninstallKey)); | |
754 | |
755 // Verify uninstall when not currently installed. | |
756 EXPECT_HRESULT_SUCCEEDED(UninstallMsiHelper()); | |
757 } else { | |
758 { | |
759 // This method expects to be called elevated and makes an assumption | |
760 // about a return value. | |
761 ExpectAsserts expect_asserts; | |
762 EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_INSTALL_PACKAGE_REJECTED), | |
763 InstallMsiHelper()); | |
764 } | |
765 if (IsMsiHelperInstalled()) { | |
766 // If the MSI is installed UninstallMsiHelper returns | |
767 // ERROR_INSTALL_FAILURE. | |
768 EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_INSTALL_FAILURE), | |
769 UninstallMsiHelper()); | |
770 } else { | |
771 // If the MSI is not installed UninstallMsiHelper returns S_OK. | |
772 EXPECT_HRESULT_SUCCEEDED(UninstallMsiHelper()); | |
773 } | |
774 } | |
775 } | |
776 | |
777 // This test installs a different build of the helper installer then calls | |
778 // InstallMsiHelper to install the one that has been built. | |
779 // If run without the REINSTALL property, ERROR_PRODUCT_VERSION would occur. | |
780 // This test verifies that such overinstalls are correctly handled and that the | |
781 // registry value is correctly changed. | |
782 // Note: The name of the installer cannot be different. MSI tries to find the | |
783 // original filename in the new directory. | |
784 // The helper can be installed when the test begins. | |
785 // It will not be installed when the test successfully completes. | |
786 TEST_F(SetupGoogleUpdateMachineTest, | |
787 InstallMsiHelper_OverinstallDifferentMsiBuild) { | |
788 if (!ShouldRunLargeTest()) { | |
789 return; | |
790 } | |
791 if (!vista_util::IsUserAdmin()) { | |
792 std::wcout << _T("\tThis test did not run because it must be run as admin.") | |
793 << std::endl; | |
794 return; | |
795 } | |
796 | |
797 const TCHAR kDifferentMsi[] = | |
798 _T("unittest_support\\GoogleUpdateHelper.msi"); | |
799 const TCHAR* MsiInstallRegValueKey = | |
800 ConfigManager::Instance()->machine_registry_update(); | |
801 | |
802 CopyFilesRequiredByFinishInstall(is_machine_, GetVersionString()); | |
803 | |
804 CString different_msi_path(app_util::GetCurrentModuleDirectory()); | |
805 ASSERT_TRUE(::PathAppend(CStrBuf(different_msi_path, MAX_PATH), | |
806 kDifferentMsi)); | |
807 | |
808 // Prepare for the test - make sure the helper is not installed. | |
809 EXPECT_HRESULT_SUCCEEDED(UninstallMsiHelper()); | |
810 EXPECT_FALSE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue)); | |
811 EXPECT_FALSE(RegKey::HasKey(kMsiUninstallKey)); | |
812 | |
813 // Install an older version of the MSI. | |
814 DWORD reg_value = 0xffffffff; | |
815 ::MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); | |
816 EXPECT_EQ(ERROR_SUCCESS, ::MsiInstallProduct(different_msi_path, _T(""))); | |
817 EXPECT_TRUE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue)); | |
818 EXPECT_HRESULT_SUCCEEDED( | |
819 RegKey::GetValue(MsiInstallRegValueKey, kMsiInstallRegValue, ®_value)); | |
820 EXPECT_EQ(9, reg_value); | |
821 EXPECT_TRUE(RegKey::HasKey(kMsiUninstallKey)); | |
822 | |
823 // Over-install. | |
824 EXPECT_HRESULT_SUCCEEDED(InstallMsiHelper()); | |
825 EXPECT_TRUE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue)); | |
826 EXPECT_HRESULT_SUCCEEDED( | |
827 RegKey::GetValue(MsiInstallRegValueKey, kMsiInstallRegValue, ®_value)); | |
828 EXPECT_EQ(0, reg_value); | |
829 EXPECT_TRUE(RegKey::HasKey(kMsiUninstallKey)); | |
830 | |
831 // Clean up. | |
832 EXPECT_HRESULT_SUCCEEDED(UninstallMsiHelper()); | |
833 EXPECT_FALSE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue)); | |
834 EXPECT_FALSE(RegKey::HasKey(kMsiUninstallKey)); | |
835 } | |
836 | |
837 } // namespace omaha | |
OLD | NEW |