Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(63)

Side by Side Diff: common/goopdate_utils.cc

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « common/goopdate_utils.h ('k') | common/goopdate_utils_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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/common/goopdate_utils.h"
17 #include <atlsecurity.h>
18 #include "omaha/base/app_util.h"
19 #include "omaha/base/const_addresses.h"
20 #include "omaha/base/const_object_names.h"
21 #include "omaha/base/const_utils.h"
22 #include "omaha/base/debug.h"
23 #include "omaha/base/error.h"
24 #include "omaha/base/file.h"
25 #include "omaha/base/logging.h"
26 #include "omaha/base/omaha_version.h"
27 #include "omaha/base/path.h"
28 #include "omaha/base/proc_utils.h"
29 #include "omaha/base/process.h"
30 #include "omaha/base/reg_key.h"
31 #include "omaha/base/safe_format.h"
32 #include "omaha/base/scope_guard.h"
33 #include "omaha/base/scoped_impersonation.h"
34 #include "omaha/base/service_utils.h"
35 #include "omaha/base/string.h"
36 #include "omaha/base/system.h"
37 #include "omaha/base/system_info.h"
38 #include "omaha/base/user_info.h"
39 #include "omaha/base/utils.h"
40 #include "omaha/base/vista_utils.h"
41 #include "omaha/base/vistautil.h"
42 #include "omaha/common/command_line_builder.h"
43 #include "omaha/common/config_manager.h"
44 #include "omaha/common/const_cmd_line.h"
45 #include "omaha/common/const_goopdate.h"
46 #include "omaha/common/oem_install_utils.h"
47 #include "omaha/statsreport/metrics.h"
48 #include "goopdate/omaha3_idl.h"
49
50 namespace omaha {
51
52 namespace goopdate_utils {
53
54 namespace {
55
56 const int kTerminateBrowserTimeoutMs = 60000;
57
58 bool IsMachineProcessWithoutPrivileges(bool is_machine_process) {
59 return is_machine_process && !vista_util::IsUserAdmin();
60 }
61
62 HRESULT LaunchImpersonatedCmdLine(const CString& cmd_line) {
63 CORE_LOG(L3, (_T("[LaunchImpersonatedCmdLine][%s]"), cmd_line));
64
65 scoped_handle impersonation_token;
66 HRESULT hr = vista::GetLoggedOnUserToken(address(impersonation_token));
67 if (FAILED(hr)) {
68 UTIL_LOG(LE, (_T("[GetLoggedOnUserToken failed][0x%x]"), hr));
69 return hr;
70 }
71
72 scoped_impersonation impersonate_user(get(impersonation_token));
73 hr = HRESULT_FROM_WIN32(impersonate_user.result());
74 if (FAILED(hr)) {
75 UTIL_LOG(LE, (_T("[impersonation failed][0x%x]"), hr));
76 return hr;
77 }
78
79 CComPtr<IProcessLauncher> launcher;
80 hr = launcher.CoCreateInstance(CLSID_ProcessLauncherClass,
81 NULL,
82 CLSCTX_LOCAL_SERVER);
83 if (FAILED(hr)) {
84 UTIL_LOG(LE, (_T("[CoCreateInstance IProcessLauncher failed][0x%x]"), hr));
85 return hr;
86 }
87
88 hr = launcher->LaunchCmdLine(cmd_line);
89 if (FAILED(hr)) {
90 UTIL_LOG(LE, (_T("[IProcessLauncher.LaunchBrowser failed][0x%x]"), hr));
91 return hr;
92 }
93
94 return S_OK;
95 }
96
97 HRESULT LaunchImpersonatedBrowser(BrowserType type, const CString& url) {
98 CORE_LOG(L3, (_T("[LaunchImpersonatedBrowser][%u][%s]"), type, url));
99
100 scoped_handle impersonation_token;
101 HRESULT hr = vista::GetLoggedOnUserToken(address(impersonation_token));
102 if (FAILED(hr)) {
103 UTIL_LOG(LE, (_T("[GetLoggedOnUserToken failed][0x%x]"), hr));
104 return hr;
105 }
106
107 scoped_impersonation impersonate_user(get(impersonation_token));
108 hr = HRESULT_FROM_WIN32(impersonate_user.result());
109 if (FAILED(hr)) {
110 UTIL_LOG(LE, (_T("[impersonation failed][0x%x]"), hr));
111 return hr;
112 }
113
114 CComPtr<IProcessLauncher> launcher;
115 hr = launcher.CoCreateInstance(CLSID_ProcessLauncherClass,
116 NULL,
117 CLSCTX_LOCAL_SERVER);
118 if (FAILED(hr)) {
119 UTIL_LOG(LE, (_T("[CoCreateInstance IProcessLauncher failed][0x%x]"), hr));
120 return hr;
121 }
122
123 hr = launcher->LaunchBrowser(type, url);
124 if (FAILED(hr)) {
125 UTIL_LOG(LE, (_T("[IProcessLauncher.LaunchBrowser failed][0x%x]"), hr));
126 return hr;
127 }
128
129 return S_OK;
130 }
131
132 } // namespace
133
134 HRESULT LaunchCmdLine(bool is_machine, const CString& cmd_line) {
135 CORE_LOG(L3, (_T("[LaunchCmdLine][%d][%s]"), is_machine, cmd_line));
136
137 if (is_machine && vista_util::IsVistaOrLater() && vista_util::IsUserAdmin()) {
138 return LaunchImpersonatedCmdLine(cmd_line);
139 }
140
141 HRESULT hr = System::ShellExecuteCommandLine(cmd_line, NULL, NULL);
142 if (FAILED(hr)) {
143 UTIL_LOG(LE, (_T("[ShellExecuteCommandLine failed][0x%x]"), hr));
144 return hr;
145 }
146
147 return S_OK;
148 }
149
150 HRESULT LaunchBrowser(bool is_machine, BrowserType type, const CString& url) {
151 CORE_LOG(L3, (_T("[LaunchBrowser][%d][%u][%s]"), is_machine, type, url));
152
153 if (is_machine && vista_util::IsVistaOrLater() && vista_util::IsUserAdmin()) {
154 // Other than having a service launch the browser using CreateProcessAsUser,
155 // there is no easy solution if we are unable to launch the browser
156 // impersonated.
157 return LaunchImpersonatedBrowser(type, url);
158 }
159
160 HRESULT hr = RunBrowser(type, url);
161 if (FAILED(hr)) {
162 UTIL_LOG(LE, (_T("[RunBrowser failed][0x%x]"), hr));
163 return hr;
164 }
165
166 return S_OK;
167 }
168
169 CString BuildGoogleUpdateExeDir(bool is_machine) {
170 ConfigManager& cm = *ConfigManager::Instance();
171 return is_machine ? cm.GetMachineGoopdateInstallDir() :
172 cm.GetUserGoopdateInstallDir();
173 }
174
175 CString BuildGoogleUpdateExePath(bool is_machine) {
176 CORE_LOG(L3, (_T("[BuildGoogleUpdateExePath][%d]"), is_machine));
177
178 CPath full_file_path(BuildGoogleUpdateExeDir(is_machine));
179 VERIFY1(full_file_path.Append(kOmahaShellFileName));
180
181 return full_file_path;
182 }
183
184 CString BuildGoogleUpdateServicesPath(bool is_machine) {
185 CORE_LOG(L3, (_T("[BuildGoogleUpdateServicesPath][%d]"), is_machine));
186
187 CPath full_file_path(BuildInstallDirectory(is_machine, GetVersionString()));
188 VERIFY1(full_file_path.Append(kCrashHandlerFileName));
189
190 return full_file_path;
191 }
192
193 HRESULT StartElevatedSelfWithArgsAndWait(const TCHAR* args, DWORD* exit_code) {
194 ASSERT1(args);
195 ASSERT1(exit_code);
196 CORE_LOG(L3, (_T("[StartElevatedSelfWithArgsAndWait]")));
197
198 // Get the process executable.
199 TCHAR filename[MAX_PATH] = {0};
200 if (::GetModuleFileName(NULL, filename, MAX_PATH) == 0) {
201 HRESULT hr = HRESULTFromLastError();
202 CORE_LOG(LEVEL_ERROR, (_T("[GetModuleFileName failed][0x%08x]"), hr));
203 return hr;
204 }
205
206 // Launch self elevated and wait.
207 *exit_code = 0;
208 CORE_LOG(L1,
209 (_T("[RunElevated filename='%s'][arguments='%s']"), filename, args));
210 // According to the MSDN documentation for ::ShowWindow: "nCmdShow. This
211 // parameter is ignored the first time an application calls ShowWindow, if
212 // the program that launched the application provides a STARTUPINFO
213 // structure.". We want to force showing the UI window. So we pass in
214 // SW_SHOWNORMAL.
215 HRESULT hr(vista_util::RunElevated(filename, args, SW_SHOWNORMAL, exit_code));
216 CORE_LOG(L2, (_T("[elevated instance exit code][%u]"), *exit_code));
217 if (FAILED(hr)) {
218 CORE_LOG(LEVEL_ERROR, (_T("[RunElevated failed][0x%08x]"), hr));
219 return hr;
220 }
221
222 return S_OK;
223 }
224
225 HRESULT StartGoogleUpdateWithArgs(bool is_machine,
226 const TCHAR* args,
227 HANDLE* process) {
228 CORE_LOG(L3, (_T("[StartGoogleUpdateWithArgs][%d][%s]"),
229 is_machine, args ? args : _T("")));
230
231 CString exe_path = BuildGoogleUpdateExePath(is_machine);
232
233 CORE_LOG(L3, (_T("[command line][%s][%s]"), exe_path, args ? args : _T("")));
234
235 HRESULT hr = System::ShellExecuteProcess(exe_path, args, NULL, process);
236 if (FAILED(hr)) {
237 CORE_LOG(LE, (_T("[can't start process][%s][0x%08x]"), exe_path, hr));
238 return hr;
239 }
240 return S_OK;
241 }
242
243 HRESULT StartCrashHandler(bool is_machine) {
244 CORE_LOG(L3, (_T("[StartCrashHandler]")));
245
246 ASSERT1(!is_machine || user_info::IsRunningAsSystem());
247
248 CString exe_path = BuildGoogleUpdateServicesPath(is_machine);
249 CommandLineBuilder builder(COMMANDLINE_MODE_CRASH_HANDLER);
250 CString cmd_line = builder.GetCommandLineArgs();
251 return System::StartProcessWithArgs(exe_path, cmd_line);
252 }
253
254 bool IsRunningFromOfficialGoopdateDir(bool is_machine) {
255 const ConfigManager& cm = *ConfigManager::Instance();
256 bool is_official_dir = is_machine ?
257 cm.IsRunningFromMachineGoopdateInstallDir() :
258 cm.IsRunningFromUserGoopdateInstallDir();
259 CORE_LOG(L3, (_T("[running from official dir][%d]"), is_official_dir));
260 return is_official_dir;
261 }
262
263 CString GetHKRoot() {
264 return IsRunningFromOfficialGoopdateDir(true) ? _T("HKLM") : _T("HKCU");
265 }
266
267 HRESULT InitializeSecurity() {
268 // Creates a security descriptor in absolute format and includes the owner
269 // and the primary group. We grant access to admins and system.
270 CSecurityDesc security_descriptor;
271 if (SystemInfo::IsRunningOnVistaOrLater()) {
272 // To allow for low-integrity IE to call into IGoogleUpdate.
273 security_descriptor.FromString(LOW_INTEGRITY_SDDL_SACL);
274 }
275 security_descriptor.SetOwner(Sids::Admins());
276 security_descriptor.SetGroup(Sids::Admins());
277 CDacl dacl;
278 dacl.AddAllowedAce(Sids::System(), COM_RIGHTS_EXECUTE);
279 dacl.AddAllowedAce(Sids::Admins(), COM_RIGHTS_EXECUTE);
280 dacl.AddAllowedAce(Sids::AuthenticatedUser(), COM_RIGHTS_EXECUTE);
281
282 security_descriptor.SetDacl(dacl);
283 security_descriptor.MakeAbsolute();
284
285 SECURITY_DESCRIPTOR* sd = const_cast<SECURITY_DESCRIPTOR*>(
286 security_descriptor.GetPSECURITY_DESCRIPTOR());
287
288 return ::CoInitializeSecurity(
289 sd,
290 -1,
291 NULL, // Let COM choose what authentication services to register.
292 NULL,
293 RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // Data integrity and encryption.
294 RPC_C_IMP_LEVEL_IDENTIFY, // Only allow a server to identify.
295 NULL,
296 EOAC_DYNAMIC_CLOAKING | EOAC_NO_CUSTOM_MARSHAL,
297 NULL);
298 }
299
300 // This is only used for legacy handoff support.
301 CString GetProductName(const CString& app_guid) {
302 const TCHAR* product_name = NULL;
303 const TCHAR gears_guid[] = _T("{283EAF47-8817-4c2b-A801-AD1FADFB7BAA}");
304 const TCHAR google_talk_plugin[] =
305 _T("{D0AB2EBC-931B-4013-9FEB-C9C4C2225C8C}");
306 const TCHAR youtube_uploader_guid[] =
307 _T("{A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}");
308
309 if (app_guid.CompareNoCase(gears_guid) == 0) {
310 product_name = _T("Gears");
311 } else if (app_guid.CompareNoCase(google_talk_plugin) == 0) {
312 product_name = _T("Google Talk Plugin");
313 } else if (app_guid.CompareNoCase(youtube_uploader_guid) == 0) {
314 product_name = _T("YouTube Uploader");
315 } else {
316 product_name = _T("Google App");
317 }
318 return product_name;
319 }
320
321 HRESULT RedirectHKCR(bool is_machine) {
322 RegKey classes_key;
323 HRESULT hr = classes_key.Open(is_machine ?
324 HKEY_LOCAL_MACHINE :
325 HKEY_CURRENT_USER,
326 _T("Software\\Classes"),
327 KEY_ALL_ACCESS);
328 if (FAILED(hr)) {
329 ASSERT(FALSE, (_T("RedirectHKCR - key.Open(%d) fail %d"), is_machine, hr));
330 return hr;
331 }
332
333 LONG result = ::RegOverridePredefKey(HKEY_CLASSES_ROOT, classes_key.Key());
334 if (result != ERROR_SUCCESS) {
335 ASSERT(false, (_T("RedirectHKCR - RegOverridePredefKey fail %d"), result));
336 return HRESULT_FROM_WIN32(result);
337 }
338
339 return S_OK;
340 }
341
342 HRESULT RemoveRedirectHKCR() {
343 LONG result = ::RegOverridePredefKey(HKEY_CLASSES_ROOT, NULL);
344 if (result != ERROR_SUCCESS) {
345 ASSERT(FALSE, (_T("RemoveRedirectHKCR - RegOverridePredefKey %d"), result));
346 return HRESULT_FROM_WIN32(result);
347 }
348
349 return S_OK;
350 }
351
352 HRESULT RegisterTypeLib(bool is_admin,
353 const CComBSTR& path,
354 ITypeLib* type_lib) {
355 // Typelib registration.
356 CORE_LOG(L3, (_T("[Registering TypeLib]")));
357 HRESULT hr = S_OK;
358 if (!is_admin &&
359 SUCCEEDED(goopdate_utils::RegisterTypeLibForUser(type_lib, path, NULL))) {
360 return S_OK;
361 }
362
363 // For Admin cases, we use ::RegisterTypeLib().
364 // For platforms where ::RegisterTypeLibForUser is not available, we register
365 // with ::RegisterTypeLib, and rely on HKCR=>HKCU redirection.
366 hr = ::RegisterTypeLib(type_lib, path, NULL);
367 ASSERT(SUCCEEDED(hr), (_T("[TypeLib registration failed][0x%08x]"), hr));
368 return hr;
369 }
370
371 HRESULT UnRegisterTypeLib(bool is_admin, const CComBSTR&, ITypeLib* type_lib) {
372 // Typelib unregistration.
373 CORE_LOG(L3, (_T("[Unregistering Typelib]")));
374 TLIBATTR* tlib_attr = NULL;
375 HRESULT hr = type_lib->GetLibAttr(&tlib_attr);
376 ASSERT(SUCCEEDED(hr), (_T("[GetLibAttr failed][0x%08x]"), hr));
377 if (FAILED(hr)) {
378 return hr;
379 }
380 ON_SCOPE_EXIT_OBJ(*type_lib, &ITypeLib::ReleaseTLibAttr, tlib_attr);
381
382 if (!is_admin &&
383 SUCCEEDED(goopdate_utils::UnRegisterTypeLibForUser(
384 tlib_attr->guid,
385 tlib_attr->wMajorVerNum,
386 tlib_attr->wMinorVerNum,
387 tlib_attr->lcid,
388 tlib_attr->syskind))) {
389 return S_OK;
390 }
391
392 // For Admin cases, we use ::UnRegisterTypeLib().
393 // For platforms where ::UnRegisterTypeLibForUser is not available, we
394 // unregister with ::UnRegisterTypeLib, and rely on HKCR=>HKCU redirection.
395 hr = ::UnRegisterTypeLib(tlib_attr->guid,
396 tlib_attr->wMajorVerNum,
397 tlib_attr->wMinorVerNum,
398 tlib_attr->lcid,
399 tlib_attr->syskind);
400
401 // We assert before the check for TYPE_E_REGISTRYACCESS below because we want
402 // to catch the case where we're trying to unregister more than once because
403 // that would be a bug.
404 ASSERT(SUCCEEDED(hr),
405 (_T("[UnRegisterTypeLib failed. ")
406 _T("This is likely a multiple unregister bug.][0x%08x]"), hr));
407
408 // If you try to unregister a type library that's already unregistered,
409 // it will return with this failure, which is OK.
410 if (hr == TYPE_E_REGISTRYACCESS) {
411 hr = S_OK;
412 }
413
414 return hr;
415 }
416
417 HRESULT RegisterOrUnregisterModule(bool is_machine,
418 bool register_server,
419 RegisterOrUnregisterFunction registrar,
420 void* data) {
421 ASSERT1(registrar);
422
423 // ATL by default registers the control to HKCR and we want to register
424 // either in HKLM, or in HKCU, depending on whether we are laying down
425 // the system googleupdate, or the user googleupdate.
426 // We solve this for the user goopdate case by:
427 // * Having the RGS file take a HKROOT parameter that translates to either
428 // HKLM or HKCU.
429 // * Redirecting HKCR to HKCU\software\classes, for a user installation, to
430 // cover Proxy registration.
431 // For the machine case, we still redirect HKCR to HKLM\\Software\\Classes,
432 // to ensure that Proxy registration happens in HKLM.
433 HRESULT hr = RedirectHKCR(is_machine);
434 ASSERT1(SUCCEEDED(hr));
435 if (FAILED(hr)) {
436 return hr;
437 }
438 // We need to stop redirecting at the end of this function.
439 ON_SCOPE_EXIT(RemoveRedirectHKCR);
440
441 hr = (*registrar)(data, register_server);
442 if (FAILED(hr)) {
443 CORE_LOG(LW, (_T("[RegisterOrUnregisterModule failed][%d][0x%08x]"),
444 register_server, hr));
445 ASSERT1(!register_server);
446 }
447
448 return hr;
449 }
450
451 HRESULT RegisterOrUnregisterModuleWithTypelib(
452 bool is_machine,
453 bool register_server,
454 RegisterOrUnregisterFunction registrar,
455 void* data) {
456 ASSERT1(registrar);
457
458 // By default, ATL registers the control to HKCR and we want to register
459 // either in HKLM, or in HKCU, depending on whether we are laying down
460 // the machine googleupdate, or the user googleupdate.
461 // We solve this for the user goopdate case by:
462 // * Having the RGS file take a HKROOT parameter that translates to either
463 // HKLM or HKCU.
464 // * Redirecting HKCR to HKCU\software\classes, for a user installation, to
465 // cover AppId and TypeLib registration
466 // * All the above makes ATL work correctly for 2K/XP. However on Win2K3
467 // and Vista, redirection does not work by itself, because in these
468 // platforms, RegisterTypeLib writes explicitly to HKLM\Software\Classes.
469 // We need to specifically call the new RegisterTypeLibForUser() API.
470 // So, we do that as well.
471 // For the machine case, we still redirect HKCR to HKLM\\Software\\Classes,
472 // because otherwise RegisterTypeLib ends up overwriting HKCU if the key
473 // already exists in HKCU.
474 HRESULT hr = RedirectHKCR(is_machine);
475 ASSERT1(SUCCEEDED(hr));
476 if (FAILED(hr)) {
477 return hr;
478 }
479 // We need to stop redirecting at the end of this function.
480 ON_SCOPE_EXIT(RemoveRedirectHKCR);
481
482 // load the type library.
483 CComPtr<ITypeLib> type_lib;
484 CComBSTR path;
485 hr = ::AtlLoadTypeLib(_AtlBaseModule.GetModuleInstance(), NULL, &path,
486 &type_lib);
487 if (FAILED(hr)) {
488 ASSERT(false, (_T("[AtlLoadTypeLib failed][0x%08x]"), hr));
489 return hr;
490 }
491
492 if (register_server) {
493 hr = (*registrar)(data, register_server);
494 if (FAILED(hr)) {
495 ASSERT(false, (_T("[Module registration failed][0x%08x]"), hr));
496 return hr;
497 }
498
499 return RegisterTypeLib(is_machine, path, type_lib);
500 } else {
501 hr = UnRegisterTypeLib(is_machine, path, type_lib);
502 if (FAILED(hr)) {
503 ASSERT(false, (_T("[UnRegisterTypeLib failed][0x%08x]"), hr));
504 return hr;
505 }
506
507 return (*registrar)(data, register_server);
508 }
509 }
510
511 HRESULT RegisterTypeLibForUser(ITypeLib* lib,
512 OLECHAR* path,
513 OLECHAR* help_dir) {
514 CORE_LOG(L3, (_T("[RegisterTypeLibForUser]")));
515 ASSERT1(lib);
516 ASSERT1(path);
517 // help_dir can be NULL.
518
519 const TCHAR* library_name = _T("oleaut32.dll");
520 scoped_library module(static_cast<HINSTANCE>(::LoadLibrary(library_name)));
521 if (!module) {
522 HRESULT hr = HRESULTFromLastError();
523 CORE_LOG(LEVEL_ERROR,
524 (_T("[LoadLibrary failed][%s][0x%08x]"), library_name, hr));
525 return hr;
526 }
527
528 // RegisterTypeLibForUser function from oleaut32.dll.
529 typedef HRESULT(__stdcall *PF)(ITypeLib*, OLECHAR*, OLECHAR*);
530
531 const char* function_name = "RegisterTypeLibForUser";
532 PF fp = reinterpret_cast<PF>(::GetProcAddress(get(module), function_name));
533 if (!fp) {
534 HRESULT hr = HRESULTFromLastError();
535 CORE_LOG(LEVEL_ERROR,
536 (_T("[GetProcAddress failed][%s][0x%08x]"),
537 function_name, library_name, hr));
538 return hr;
539 }
540
541 CORE_LOG(L3, (_T("[Calling RegisterTypelibForUser in oleaut]")));
542 HRESULT hr = fp(lib, path, help_dir);
543 if (FAILED(hr)) {
544 CORE_LOG(LEVEL_ERROR, (_T("[regtypelib_for_user failed][0x%08x]"), hr));
545 return hr;
546 }
547
548 return S_OK;
549 }
550
551 HRESULT UnRegisterTypeLibForUser(REFGUID lib_id,
552 WORD major_ver_num,
553 WORD minor_ver_num,
554 LCID lcid,
555 SYSKIND syskind) {
556 CORE_LOG(L3, (_T("[UnRegisterTypeLibForUser]")));
557
558 const TCHAR* library_name = _T("oleaut32.dll");
559 scoped_library module(static_cast<HINSTANCE>(::LoadLibrary(library_name)));
560 if (!module) {
561 HRESULT hr = HRESULTFromLastError();
562 CORE_LOG(LEVEL_ERROR,
563 (_T("[LoadLibrary failed][%s][0x%08x]"), library_name, hr));
564 return hr;
565 }
566
567 // UnRegisterTypeLibForUser function from oleaut32.dll.
568 typedef HRESULT (__stdcall *PF)(REFGUID, WORD, WORD, LCID, SYSKIND);
569
570 const char* function_name = "UnRegisterTypeLibForUser";
571 PF fp = reinterpret_cast<PF>(::GetProcAddress(get(module), function_name));
572 if (!fp) {
573 HRESULT hr = HRESULTFromLastError();
574 CORE_LOG(LEVEL_ERROR,
575 (_T("[GetProcAddress failed][%s][0x%08x]"),
576 function_name, library_name, hr));
577 return hr;
578 }
579
580 CORE_LOG(L3, (_T("[Calling UnRegisterTypeLibForUser in oleaut]")));
581 HRESULT hr = fp(lib_id, major_ver_num, minor_ver_num, lcid, syskind);
582 if (FAILED(hr)) {
583 CORE_LOG(LEVEL_ERROR, (_T("[unregtypelib_for_user failed][0x%08x]"), hr));
584 return hr;
585 }
586
587 return S_OK;
588 }
589
590 // TODO(omaha): This method's name is much more specific than what it does. Can
591 // we just copy the code to scheduled task and service code and eliminate it?
592 // Reads the current value under {HKLM|HKCU}\Google\Update\value_name. Returns
593 // default_val if value_name does not exist.
594 CString GetCurrentVersionedName(bool is_machine,
595 const TCHAR* value_name,
596 const TCHAR* default_val) {
597 CORE_LOG(L3, (_T("[ConfigManager::GetCurrentVersionedName]")));
598 ASSERT1(value_name && *value_name);
599 ASSERT1(default_val && *default_val);
600
601 const TCHAR* key_name = is_machine ? MACHINE_REG_UPDATE : USER_REG_UPDATE;
602 CString name;
603 HRESULT hr(RegKey::GetValue(key_name, value_name, &name));
604 if (FAILED(hr)) {
605 CORE_LOG(L4, (_T("[GetValue failed][%s][0x%x][Using default name][%s]"),
606 value_name, hr, default_val));
607 name = default_val;
608 }
609
610 CORE_LOG(L3, (_T("[Versioned Name][%s]"), name));
611 return name;
612 }
613
614 // Creates a unique name of the form "{prefix}1c9b3d6baf90df3" and stores it in
615 // the registry under HKLM/HKCU\Google\Update\value_name. Subsequent
616 // invocations of GetCurrentTaskName() will return this new value.
617 HRESULT CreateAndSetVersionedNameInRegistry(bool is_machine,
618 const TCHAR* prefix,
619 const TCHAR* value_name) {
620 ASSERT1(prefix && *prefix);
621 ASSERT1(value_name && *value_name);
622
623 // TODO(omaha): Move from service_utils.h since it is used for other purposes.
624 CString name(ServiceInstall::GenerateServiceName(prefix));
625 CORE_LOG(L3, (_T("Versioned name[%s][%s][%s]"), prefix, value_name, name));
626
627 const TCHAR* key_name = is_machine ? MACHINE_REG_UPDATE : USER_REG_UPDATE;
628 return RegKey::SetValue(key_name, value_name, name);
629 }
630
631 HRESULT TerminateAllBrowsers(
632 BrowserType type,
633 TerminateBrowserResult* browser_res,
634 TerminateBrowserResult* default_res) {
635 UTIL_LOG(L3, (_T("[TerminateAllBrowsers][%d]"), type));
636 ASSERT1(default_res);
637 ASSERT1(browser_res);
638
639 if (type == BROWSER_UNKNOWN ||
640 type == BROWSER_DEFAULT ||
641 type >= BROWSER_MAX) {
642 ASSERT1(false);
643 return E_INVALIDARG;
644 }
645
646 const BrowserType kFirstBrowser = BROWSER_IE;
647 const int kNumSupportedBrowsers = BROWSER_MAX - kFirstBrowser;
648
649 BrowserType default_type = BROWSER_UNKNOWN;
650 HRESULT hr = GetDefaultBrowserType(&default_type);
651 if (FAILED(hr)) {
652 UTIL_LOG(LW, (_T("[GetDefaultBrowserType failed][0x%08x]"), hr));
653 return hr;
654 }
655
656 TerminateBrowserResult terminate_results[kNumSupportedBrowsers];
657
658 for (int browser = 0; browser < kNumSupportedBrowsers; ++browser) {
659 const BrowserType browser_type =
660 static_cast<BrowserType>(kFirstBrowser + browser);
661 hr = TerminateBrowserProcess(browser_type,
662 CString(),
663 0,
664 &terminate_results[browser].found);
665 if (FAILED(hr)) {
666 UTIL_LOG(LW, (_T("[TerminateBrowserProcess failed][%u][0x%08x]"),
667 browser_type, hr));
668 }
669 }
670
671 // Now wait for the all browser instances to die.
672 // TODO(omaha): Wait for all processes at once rather than waiting for
673 // (kTerminateBrowserTimeoutMs * # supported browsers) ms.
674 for (int browser = 0; browser < kNumSupportedBrowsers; ++browser) {
675 const BrowserType browser_type =
676 static_cast<BrowserType>(kFirstBrowser + browser);
677 hr = WaitForBrowserToDie(browser_type,
678 CString(),
679 kTerminateBrowserTimeoutMs);
680 if (FAILED(hr)) {
681 UTIL_LOG(LW, (_T("[WaitForBrowserToDie failed][%u][0x%08x]"),
682 browser_type, hr));
683 } else {
684 terminate_results[browser].could_terminate = true;
685 }
686 }
687
688 *browser_res = terminate_results[type - kFirstBrowser];
689 *default_res = terminate_results[default_type - kFirstBrowser];
690
691 return S_OK;
692 }
693
694 // default_type can be BROWSER_UNKNOWN.
695 // If browsers that must be closed could not be terminated, false is returned.
696 // This method and TerminateBrowserProcesses assume the user did not shutdown
697 // the specified browser. They restart and shutdown, respectively, the default
698 // browser when the specified browser is not found. The reason for this may have
699 // been that the the specified (stamped) browser could be in a bad state on the
700 // machine and trying to start it would fail.
701 // This may also be required to support hosted cases (i.e. AOL and Maxthon).
702 // TODO(omaha): If we assume the stamped browser is okay, check whether the
703 // specified browser is installed rather than relying on whether the browser was
704 // running. It is perfectly valid for the browser to not be running.
705 // TODO(omaha): Why not try the default browser if browsers that require
706 // shutdown failed to terminate.
707 bool GetBrowserToRestart(BrowserType type,
708 BrowserType default_type,
709 const TerminateBrowserResult& res,
710 const TerminateBrowserResult& def_res,
711 BrowserType* browser_type) {
712 ASSERT1(browser_type);
713 ASSERT1(type != BROWSER_UNKNOWN &&
714 type != BROWSER_DEFAULT &&
715 type < BROWSER_MAX);
716 ASSERT1(default_type != BROWSER_DEFAULT && default_type < BROWSER_MAX);
717 UTIL_LOG(L3, (_T("[GetBrowserToRestart][%d]"), type));
718
719 *browser_type = BROWSER_UNKNOWN;
720
721 if (res.found) {
722 switch (type) {
723 case BROWSER_IE:
724 *browser_type = BROWSER_IE;
725 return true;
726 case BROWSER_FIREFOX: // Only one process.
727 case BROWSER_CHROME: // One process per plug-in, even for upgrades.
728 if (res.could_terminate) {
729 *browser_type = type;
730 return true;
731 }
732 return false;
733 case BROWSER_UNKNOWN:
734 case BROWSER_DEFAULT:
735 case BROWSER_MAX:
736 default:
737 break;
738 }
739 }
740
741 // We did not find the browser that we wanted to restart. Hence we need to
742 // determine if we could shutdown the default browser.
743 switch (default_type) {
744 case BROWSER_IE:
745 *browser_type = BROWSER_IE;
746 return true;
747 case BROWSER_FIREFOX:
748 case BROWSER_CHROME:
749 if (!def_res.found || def_res.found && def_res.could_terminate) {
750 *browser_type = default_type;
751 return true;
752 }
753 break;
754 case BROWSER_UNKNOWN:
755 case BROWSER_DEFAULT:
756 case BROWSER_MAX:
757 default:
758 break;
759 }
760
761 return false;
762 }
763
764 // See the comments about the default browser above GetBrowserToRestart.
765 HRESULT TerminateBrowserProcesses(BrowserType type,
766 TerminateBrowserResult* browser_res,
767 TerminateBrowserResult* default_res) {
768 UTIL_LOG(L3, (_T("[TerminateBrowserProcesses][%d]"), type));
769 ASSERT1(browser_res);
770 ASSERT1(default_res);
771
772 browser_res->could_terminate = false;
773 default_res->could_terminate = false;
774
775 if (type == BROWSER_UNKNOWN ||
776 type == BROWSER_DEFAULT ||
777 type >= BROWSER_MAX) {
778 ASSERT1(false);
779 return E_UNEXPECTED;
780 }
781
782 CString sid;
783 HRESULT hr = user_info::GetProcessUser(NULL, NULL, &sid);
784 if (FAILED(hr)) {
785 UTIL_LOG(LE, (_T("[GetProcessUser failed][0x%08x]"), hr));
786 return hr;
787 }
788
789 hr = TerminateBrowserProcess(type,
790 sid,
791 kTerminateBrowserTimeoutMs,
792 &browser_res->found);
793 if (FAILED(hr)) {
794 UTIL_LOG(LW, (_T("[TerminateBrowserProcess failed][0x%08x]"), hr));
795 } else {
796 browser_res->could_terminate = true;
797 }
798
799 // Since no instances of the browser type exist, we try to find and kill
800 // all instances of the default browser.
801 if (!browser_res->found) {
802 // We dont want to try and terminate the default browser, if it is the
803 // same as the browser that we tried above.
804
805 BrowserType default_type = BROWSER_UNKNOWN;
806 hr = GetDefaultBrowserType(&default_type);
807 if (FAILED(hr)) {
808 UTIL_LOG(LW, (_T("[GetDefaultBrowserType failed][0x%08x]"), hr));
809 }
810
811 UTIL_LOG(L3, (_T("[Trying to kill the default browser %d]"), default_type));
812 if (default_type != type) {
813 hr = TerminateBrowserProcess(BROWSER_DEFAULT,
814 sid,
815 kTerminateBrowserTimeoutMs,
816 &default_res->found);
817 if (FAILED(hr)) {
818 UTIL_LOG(LW, (_T("[TerminateBrowserProcess failed][0x%08x]"), hr));
819 } else {
820 default_res->could_terminate = true;
821 }
822 }
823 }
824
825 return hr;
826 }
827
828 HRESULT GetBrowserImagePathFromProcess(BrowserType type,
829 uint32 explorer_pid,
830 CString* path) {
831 ASSERT1(path);
832
833 if (type == BROWSER_UNKNOWN || type >= BROWSER_MAX) {
834 ASSERT1(false);
835 return E_UNEXPECTED;
836 }
837
838 if (type == BROWSER_DEFAULT) {
839 return GetDefaultBrowserPath(path);
840 }
841
842 CString user_sid;
843 HRESULT hr = Process::GetProcessOwner(explorer_pid, &user_sid);
844 if (FAILED(hr)) {
845 UTIL_LOG(LEVEL_WARNING, (_T("[GetProcessOwner failed.][0x%08x]"), hr));
846 return hr;
847 }
848
849 CString browser_name;
850 hr = BrowserTypeToProcessName(type, &browser_name);
851 if (FAILED(hr)) {
852 UTIL_LOG(LW, (_T("[BrowserTypeToProcessName failed.][0x%08x]"), hr));
853 return hr;
854 }
855
856 hr = Process::GetImagePath(browser_name, user_sid, path);
857 if (FAILED(hr)) {
858 UTIL_LOG(LW, (_T("[GetImagePath failed.][0x%08x]"), hr));
859 return hr;
860 }
861
862 return S_OK;
863 }
864
865 HRESULT ConvertStringToBrowserType(const CString& text, BrowserType* type) {
866 ASSERT1(type != NULL);
867
868 if (text.GetLength() != 1) {
869 return GOOPDATEUTILS_E_BROWSERTYPE;
870 }
871
872 int browser_type = 0;
873 if (!String_StringToDecimalIntChecked(text, &browser_type)) {
874 return GOOPDATEUTILS_E_BROWSERTYPE;
875 }
876
877 if (browser_type >= BROWSER_MAX) {
878 return GOOPDATEUTILS_E_BROWSERTYPE;
879 }
880
881 *type = static_cast<BrowserType>(browser_type);
882 return S_OK;
883 }
884
885 CString ConvertBrowserTypeToString(BrowserType type) {
886 CString text = itostr(static_cast<int>(type));
887 ASSERT1(!text.IsEmpty());
888 return text;
889 }
890
891 HRESULT GetOSInfo(CString* os_version, CString* service_pack) {
892 ASSERT1(os_version);
893 ASSERT1(service_pack);
894
895 OSVERSIONINFO os_version_info = { 0 };
896 os_version_info.dwOSVersionInfoSize = sizeof(os_version_info);
897 if (!::GetVersionEx(&os_version_info)) {
898 HRESULT hr = HRESULTFromLastError();
899 UTIL_LOG(LW, (_T("[GetVersionEx failed][0x%08x]"), hr));
900 return hr;
901 }
902
903 os_version->Format(_T("%d.%d"),
904 os_version_info.dwMajorVersion,
905 os_version_info.dwMinorVersion);
906 *service_pack = os_version_info.szCSDVersion;
907 return S_OK;
908 }
909
910 CPath BuildInstallDirectory(bool is_machine, const CString& version) {
911 ConfigManager& cm = *ConfigManager::Instance();
912 CPath install_dir(is_machine ? cm.GetMachineGoopdateInstallDir() :
913 cm.GetUserGoopdateInstallDir());
914 VERIFY1(install_dir.Append(version));
915
916 return install_dir;
917 }
918
919 // This method does a very specific job of searching for install workers,
920 // for the user and machine omaha. It also includes the on-demand updates COM
921 // server, because we treat it similar to interactive installs, and selfupdate.
922 //
923 // In machine case we search in all the accounts since the install worker can be
924 // running in any admin account and the machine update worker runs as SYSTEM.
925 // In the user case, we only search the user's account.
926 // In both cases, the Needsadmin command line parameter is checked for
927 // true/false in the machine/user case, respectively.
928 //
929 // Only adds processes to the input vector; does not clear it.
930 //
931 // TODO(omaha): For now we search for the needs_admin=true in the command
932 // line to determine a machine install. Another option of identifying omaha's
933 // is to use the presence of a named mutex. So the user omaha will create
934 // Global\<sid>\Mutex and the machine will create Global\Mutex, in here then
935 // we can test for the presence of the name to decide if an interactive
936 // omaha is running.
937 // TODO(omaha): Consider further filtering the processes based on whether
938 // the owner is elevated in case of machine omaha.
939 // Looks for the /ig command line used in Omaha 2.
940 HRESULT GetInstallWorkerProcesses(bool is_machine,
941 std::vector<uint32>* processes) {
942 ASSERT1(processes);
943
944 CString user_sid;
945 DWORD flags = EXCLUDE_CURRENT_PROCESS |
946 EXCLUDE_PARENT_PROCESS |
947 INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING;
948
949 std::vector<CString> command_lines;
950 CString command_line_to_include;
951 command_line_to_include.Format(_T("/%s"), kCmdLineInstall);
952 command_lines.push_back(command_line_to_include);
953 command_line_to_include.Format(_T("/%s"), kCmdLineInstallElevated);
954 command_lines.push_back(command_line_to_include);
955 command_line_to_include.Format(_T("/%s"), kCmdLineAppHandoffInstall);
956 command_lines.push_back(command_line_to_include);
957 command_line_to_include.Format(_T("/%s"), kCmdLineUpdate);
958 command_lines.push_back(command_line_to_include);
959 command_line_to_include.Format(_T("/%s"),
960 kCmdLineLegacyFinishGoogleUpdateInstall);
961 command_lines.push_back(command_line_to_include);
962 command_lines.push_back(kCmdLineComServerDash);
963
964 if (!is_machine) {
965 // Search only the same sid as the current user.
966 flags |= INCLUDE_ONLY_PROCESS_OWNED_BY_USER;
967
968 HRESULT hr = user_info::GetProcessUser(NULL, NULL, &user_sid);
969 if (FAILED(hr)) {
970 CORE_LOG(LE, (_T("[GetProcessUser failed][0x%08x]"), hr));
971 return hr;
972 }
973 }
974
975 std::vector<uint32> all_install_worker_processes;
976 HRESULT hr = Process::FindProcesses(flags,
977 kOmahaShellFileName,
978 true,
979 user_sid,
980 command_lines,
981 &all_install_worker_processes);
982 if (FAILED(hr)) {
983 CORE_LOG(LE, (_T("[FindProcesses failed][0x%08x]"), hr));
984 return hr;
985 }
986
987 CString official_path;
988 hr = GetFolderPath(is_machine ? CSIDL_PROGRAM_FILES : CSIDL_LOCAL_APPDATA,
989 &official_path);
990 ASSERT1(SUCCEEDED(hr));
991 ASSERT1(!official_path.IsEmpty());
992
993 for (size_t i = 0; i < all_install_worker_processes.size(); ++i) {
994 CString cmd_line;
995 const uint32 process = all_install_worker_processes[i];
996 if (SUCCEEDED(Process::GetCommandLine(process, &cmd_line))) {
997 cmd_line.MakeLower();
998 // TODO(omaha): FindProcess method does not allow regex's to be specified
999 // along with the include command line. Change Process to allow this.
1000 if (cmd_line.Find(is_machine ? kNeedsAdminYes : kNeedsAdminNo) != -1) {
1001 CORE_LOG(L4, (_T("[Including process][%s]"), cmd_line));
1002 processes->push_back(process);
1003 }
1004
1005 // A needsadmin=prefers instance could be installing either for machine or
1006 // for user.
1007 if (cmd_line.Find(kNeedsAdminPrefers) != -1) {
1008 CORE_LOG(L4, (_T("[Including process][%s]"), cmd_line));
1009 processes->push_back(process);
1010 }
1011
1012 // The -Embedding does not have a needsAdmin. Decide whether to include it
1013 // if it matches the official path for the requested instance type.
1014 CString exe_path;
1015 if (cmd_line.Find(kCmdLineComServerDash) != -1 &&
1016 SUCCEEDED(GetExePathFromCommandLine(cmd_line, &exe_path)) &&
1017 String_StrNCmp(official_path, exe_path, official_path.GetLength(),
1018 true) == 0) {
1019 CORE_LOG(L4, (_T("[Including process][%s]"), cmd_line));
1020 processes->push_back(process);
1021 }
1022 }
1023 }
1024
1025 return S_OK;
1026 }
1027
1028 // The event name saved to the environment variable does not contain the
1029 // decoration added by GetNamedObjectAttributes.
1030 HRESULT CreateUniqueEventInEnvironment(const CString& var_name,
1031 bool is_machine,
1032 HANDLE* unique_event) {
1033 ASSERT1(unique_event);
1034
1035 GUID event_guid = GUID_NULL;
1036 HRESULT hr = ::CoCreateGuid(&event_guid);
1037 if (FAILED(hr)) {
1038 CORE_LOG(LE, (_T("[::CoCreateGuid failed][0x%08x]"), hr));
1039 return hr;
1040 }
1041
1042 CString event_name(GuidToString(event_guid));
1043 NamedObjectAttributes attr;
1044 GetNamedObjectAttributes(event_name, is_machine, &attr);
1045
1046 hr = CreateEvent(&attr, unique_event);
1047 if (FAILED(hr)) {
1048 CORE_LOG(LW, (_T("[CreateEvent failed in CreateUniqueEventInEnvironment]"),
1049 _T("[%s][0x%08x]"), var_name, hr));
1050 return hr;
1051 }
1052
1053 CORE_LOG(L3, (_T("[created unique event][%s][%s]"), var_name, event_name));
1054
1055 if (!::SetEnvironmentVariable(var_name, event_name)) {
1056 DWORD error = ::GetLastError();
1057 CORE_LOG(LE, (_T("[::SetEnvironmentVariable failed][%d]"), error));
1058 return HRESULT_FROM_WIN32(error);
1059 }
1060
1061 return S_OK;
1062 }
1063
1064 HRESULT OpenUniqueEventFromEnvironment(const CString& var_name,
1065 bool is_machine,
1066 HANDLE* unique_event) {
1067 ASSERT1(unique_event);
1068
1069 TCHAR event_name[MAX_PATH] = {0};
1070 if (!::GetEnvironmentVariable(var_name, event_name, arraysize(event_name))) {
1071 DWORD error = ::GetLastError();
1072 CORE_LOG(LW, (_T("[Failed to read environment variable][%s][%d]"),
1073 var_name, error));
1074 return HRESULT_FROM_WIN32(error);
1075 }
1076
1077 CORE_LOG(L3, (_T("[read unique event][%s][%s]"), var_name, event_name));
1078
1079 NamedObjectAttributes attr;
1080 GetNamedObjectAttributes(event_name, is_machine, &attr);
1081 *unique_event = ::OpenEvent(EVENT_ALL_ACCESS, false, attr.name);
1082
1083 if (!*unique_event) {
1084 DWORD error = ::GetLastError();
1085 CORE_LOG(LW, (_T("[::OpenEvent failed][%s][%d]"), attr.name, error));
1086 return HRESULT_FROM_WIN32(error);
1087 }
1088
1089 return S_OK;
1090 }
1091
1092 // The caller is responsible for reseting the event and closing the handle.
1093 HRESULT CreateEvent(NamedObjectAttributes* event_attr, HANDLE* event_handle) {
1094 ASSERT1(event_handle);
1095 ASSERT1(event_attr);
1096 ASSERT1(!event_attr->name.IsEmpty());
1097 *event_handle = ::CreateEvent(&event_attr->sa,
1098 true, // manual reset
1099 false, // not signaled
1100 event_attr->name);
1101
1102 if (!*event_handle) {
1103 DWORD error = ::GetLastError();
1104 CORE_LOG(LEVEL_ERROR, (_T("[::CreateEvent failed][%d]"), error));
1105 return HRESULT_FROM_WIN32(error);
1106 }
1107
1108 return S_OK;
1109 }
1110
1111 bool IsTestSource() {
1112 return !ConfigManager::Instance()->GetTestSource().IsEmpty();
1113 }
1114
1115 HRESULT ReadNameValuePairsFromFile(const CString& file_path,
1116 const CString& group_name,
1117 std::map<CString, CString>* pairs) {
1118 ASSERT1(pairs);
1119
1120 if (!File::Exists(file_path)) {
1121 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
1122 }
1123
1124 pairs->clear();
1125
1126 TCHAR str_buf[32768] = {0};
1127
1128 // Retrieve all key names in the section requested.
1129 DWORD buf_count = ::GetPrivateProfileString(group_name,
1130 NULL,
1131 NULL,
1132 str_buf,
1133 arraysize(str_buf),
1134 file_path);
1135
1136 DWORD offset = 0;
1137 while (offset < buf_count) {
1138 TCHAR val_buf[1024] = {0};
1139 CString current_key = &(str_buf[offset]);
1140 DWORD val_count = ::GetPrivateProfileString(group_name,
1141 current_key,
1142 NULL,
1143 val_buf,
1144 arraysize(val_buf),
1145 file_path);
1146 (*pairs)[current_key] = val_buf;
1147 offset += current_key.GetLength() + 1;
1148 }
1149
1150 return S_OK;
1151 }
1152
1153 HRESULT WriteNameValuePairsToFile(const CString& file_path,
1154 const CString& group_name,
1155 const std::map<CString, CString>& pairs) {
1156 std::map<CString, CString>::const_iterator it = pairs.begin();
1157 for (; it != pairs.end(); ++it) {
1158 if (!::WritePrivateProfileString(group_name,
1159 it->first,
1160 it->second,
1161 file_path)) {
1162 return HRESULTFromLastError();
1163 }
1164 }
1165
1166 return S_OK;
1167 }
1168
1169 bool IsAppInstallWorkerRunning(bool is_machine) {
1170 CORE_LOG(L3, (_T("[IsAppInstallWorkerRunning][%d]"), is_machine));
1171 std::vector<uint32> processes;
1172 VERIFY1(SUCCEEDED(GetInstallWorkerProcesses(is_machine, &processes)));
1173 return !processes.empty();
1174 }
1175
1176 // Returns true if the version does not begin with "1.0." or "1.1.".
1177 bool IsGoogleUpdate2OrLater(const CString& version) {
1178 const ULONGLONG kFirstOmaha2Version = MAKEDLLVERULL(1, 2, 0, 0);
1179 ULONGLONG version_number = VersionFromString(version);
1180 ASSERT1(0 != version_number);
1181
1182 if (kFirstOmaha2Version <= version_number) {
1183 return true;
1184 }
1185
1186 return false;
1187 }
1188
1189 HRESULT WriteInstallerDataToTempFile(const CString& installer_data,
1190 CString* installer_data_file_path) {
1191 ASSERT1(installer_data_file_path);
1192
1193 // TODO(omaha): consider eliminating the special case and simply create an
1194 // empty file.
1195 CORE_LOG(L2, (_T("[WriteInstallerDataToTempFile][data=%s]"), installer_data));
1196 if (installer_data.IsEmpty()) {
1197 return S_FALSE;
1198 }
1199
1200 CString temp_file;
1201 if (!::GetTempFileName(app_util::GetTempDir(),
1202 _T("gui"),
1203 0,
1204 CStrBuf(temp_file, MAX_PATH))) {
1205 HRESULT hr = HRESULTFromLastError();
1206 CORE_LOG(LE, (_T("[::GetTempFileName failed][0x08%x]"), hr));
1207 return hr;
1208 }
1209
1210 scoped_hfile file_handle(::CreateFile(temp_file,
1211 GENERIC_WRITE,
1212 FILE_SHARE_READ,
1213 NULL,
1214 CREATE_ALWAYS,
1215 FILE_ATTRIBUTE_NORMAL,
1216 NULL));
1217 if (!file_handle) {
1218 HRESULT hr = HRESULTFromLastError();
1219 CORE_LOG(LE, (_T("[::CreateFile failed][0x08%x]"), hr));
1220 return hr;
1221 }
1222
1223 CStringA installer_data_utf8_bom;
1224 SafeCStringAFormat(&installer_data_utf8_bom, "%c%c%c%s",
1225 0xEF, 0xBB, 0xBF, WideToUtf8(installer_data));
1226
1227 DWORD bytes_written = 0;
1228 if (!::WriteFile(get(file_handle),
1229 installer_data_utf8_bom,
1230 installer_data_utf8_bom.GetLength(),
1231 &bytes_written,
1232 NULL)) {
1233 HRESULT hr = HRESULTFromLastError();
1234 CORE_LOG(LE, (_T("[::WriteFile failed][0x08%x]"), hr));
1235 return hr;
1236 }
1237
1238 *installer_data_file_path = temp_file;
1239 return S_OK;
1240 }
1241
1242 // Returns true if the absolute difference between time moments is greater than
1243 // the interval between update checks.
1244 // Deals with clocks rolling backwards, in scenarios where the clock indicates
1245 // some time in the future, for example next year, last_checked_ is updated to
1246 // reflect that time, and then the clock is adjusted back to present.
1247 bool ShouldCheckForUpdates(bool is_machine) {
1248 ConfigManager* cm = ConfigManager::Instance();
1249 bool is_period_overridden = false;
1250 const int update_interval = cm->GetLastCheckPeriodSec(&is_period_overridden);
1251 if (0 == update_interval) {
1252 ASSERT1(is_period_overridden);
1253 OPT_LOG(L1, (_T("[ShouldCheckForUpdates returned 0][checks disabled]")));
1254 return false;
1255 }
1256
1257 const int time_difference = cm->GetTimeSinceLastCheckedSec(is_machine);
1258
1259 const bool result = time_difference >= update_interval ? true : false;
1260 CORE_LOG(L3, (_T("[ShouldCheckForUpdates returned %d][%u]"),
1261 result, is_period_overridden));
1262 return result;
1263 }
1264
1265 HRESULT UpdateLastChecked(bool is_machine) {
1266 // Set the last check value to the current value.
1267 DWORD now = Time64ToInt32(GetCurrent100NSTime());
1268 CORE_LOG(L3, (_T("[UpdateLastChecked][now %d]"), now));
1269 HRESULT hr = ConfigManager::Instance()->SetLastCheckedTime(is_machine, now);
1270 if (FAILED(hr)) {
1271 CORE_LOG(LE, (_T("[SetLastCheckedTime failed][0x%08x]"), hr));
1272 return hr;
1273 }
1274 return S_OK;
1275 }
1276
1277 HRESULT LaunchUninstallProcess(bool is_machine) {
1278 CORE_LOG(L2, (_T("[LaunchUninstallProcess]")));
1279 CString exe_path = BuildGoogleUpdateExePath(is_machine);
1280 CommandLineBuilder builder(COMMANDLINE_MODE_UNINSTALL);
1281 CString cmd_line = builder.GetCommandLineArgs();
1282 return System::StartProcessWithArgs(exe_path, cmd_line);
1283 }
1284
1285 HANDLE GetImpersonationTokenForMachineProcess(bool is_machine) {
1286 if (!is_machine) {
1287 return NULL;
1288 }
1289
1290 CAccessToken access_token;
1291 if (access_token.GetThreadToken(TOKEN_READ)) {
1292 return NULL;
1293 }
1294
1295 bool is_local_system(false);
1296 VERIFY1(SUCCEEDED(IsSystemProcess(&is_local_system)));
1297 if (!is_local_system) {
1298 return NULL;
1299 }
1300
1301 HANDLE handle = NULL;
1302 HRESULT hr = vista::GetLoggedOnUserToken(&handle);
1303 if (FAILED(hr)) {
1304 UTIL_LOG(LE, (_T("[GetLoggedOnUserToken failed][0x%x]"), hr));
1305 return NULL;
1306 }
1307
1308 return handle;
1309 }
1310
1311 HRESULT EnableSEHOP(bool enable) {
1312 CORE_LOG(L3, (_T("[EnableSEHOP][%d]"), enable));
1313 CString omaha_ifeo_key_path;
1314 omaha_ifeo_key_path.Format(_T("%s\\%s"),
1315 kRegKeyImageFileExecutionOptions,
1316 kOmahaShellFileName);
1317 return enable ?
1318 RegKey::SetValue(omaha_ifeo_key_path, kRegKeyDisableSEHOPValue,
1319 static_cast<DWORD>(0)) :
1320 RegKey::DeleteValue(omaha_ifeo_key_path, kRegKeyDisableSEHOPValue);
1321 }
1322
1323 DEFINE_METRIC_count(opt_in_uid_generated);
1324 HRESULT CreateUserId(bool is_machine) {
1325 // Do not create user ID when doing OEM installation - to avoid a large
1326 // number of machines have the same ID.
1327 if (oem_install_utils::IsOemInstalling(is_machine)) {
1328 return E_FAIL;
1329 }
1330
1331 GLock user_id_lock;
1332 NamedObjectAttributes lock_attr;
1333 GetNamedObjectAttributes(kOptUserIdLock, is_machine, &lock_attr);
1334 if (!user_id_lock.InitializeWithSecAttr(lock_attr.name, &lock_attr.sa)) {
1335 return E_FAIL;
1336 }
1337
1338 __mutexScope(user_id_lock);
1339 RegKey update_key;
1340 const ConfigManager& config_manager = *ConfigManager::Instance();
1341 HRESULT hr = update_key.Create(config_manager.registry_update(is_machine));
1342 if (FAILED(hr)) {
1343 return hr;
1344 }
1345
1346 if (update_key.HasValue(kRegValueUserId)) {
1347 return S_OK;
1348 }
1349
1350 CString user_id;
1351 hr = GetGuid(&user_id);
1352 if (FAILED(hr)) {
1353 return hr;
1354 }
1355
1356 hr = update_key.SetValue(kRegValueUserId, user_id);
1357 if (FAILED(hr)) {
1358 return hr;
1359 }
1360
1361 ++metric_opt_in_uid_generated;
1362 CORE_LOG(L3, (_T("[Create unique user ID: %s]"), user_id));
1363 return S_OK;
1364 }
1365
1366 void DeleteUserId(bool is_machine) {
1367 RegKey::DeleteValue(ConfigManager::Instance()->registry_update(is_machine),
1368 kRegValueUserId);
1369 }
1370
1371 CString GetUserIdLazyInit(bool is_machine) {
1372 const ConfigManager& config_manager = *ConfigManager::Instance();
1373 if (oem_install_utils::IsOemInstalling(is_machine) ||
1374 !config_manager.CanCollectStats(is_machine)) {
1375 DeleteUserId(is_machine);
1376 return CString();
1377 }
1378
1379 if (!RegKey::HasValue(config_manager.registry_update(is_machine),
1380 kRegValueUserId)) {
1381 VERIFY1(SUCCEEDED(CreateUserId(is_machine)));
1382 }
1383
1384 CString user_id;
1385 RegKey::GetValue(config_manager.registry_update(is_machine),
1386 kRegValueUserId,
1387 &user_id);
1388 return user_id;
1389 }
1390
1391 } // namespace goopdate_utils
1392
1393 } // namespace omaha
OLDNEW
« no previous file with comments | « common/goopdate_utils.h ('k') | common/goopdate_utils_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698