diff options
author | erikwright@chromium.org <erikwright@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-24 19:14:11 +0000 |
---|---|---|
committer | erikwright@chromium.org <erikwright@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-24 19:14:11 +0000 |
commit | efd97484dbba5faec394693002228a1f0e2c2f82 (patch) | |
tree | fcf94e84e1dc8213debb308fc4c405738eac3543 | |
parent | 30aa3ee0461f0475180d50d4adc4b925fe7e1315 (diff) | |
download | chromium_src-efd97484dbba5faec394693002228a1f0e2c2f82.zip chromium_src-efd97484dbba5faec394693002228a1f0e2c2f82.tar.gz chromium_src-efd97484dbba5faec394693002228a1f0e2c2f82.tar.bz2 |
When changing Ready Mode state from within an IE process, use chrome_launcher to invoke the ProcessLauncher, so as to not cause a UAC prompt (chrome_launcher is permitted via elevation policy).
BUG=None
TEST=Install GCF in Ready Mode on Vista, interact with it.
Review URL: http://codereview.chromium.org/6355011
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@72361 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome_frame/chrome_frame_launcher.gyp | 3 | ||||
-rw-r--r-- | chrome_frame/chrome_launcher_main.cc | 12 | ||||
-rw-r--r-- | chrome_frame/chrome_launcher_utils.cc | 44 | ||||
-rw-r--r-- | chrome_frame/chrome_launcher_utils.h | 6 | ||||
-rw-r--r-- | chrome_frame/ready_mode/internal/registry_ready_mode_state.cc | 53 | ||||
-rw-r--r-- | chrome_frame/update_launcher.cc | 94 | ||||
-rw-r--r-- | chrome_frame/update_launcher.h | 26 |
7 files changed, 199 insertions, 39 deletions
diff --git a/chrome_frame/chrome_frame_launcher.gyp b/chrome_frame/chrome_frame_launcher.gyp index 53bab2c..d357e88 100644 --- a/chrome_frame/chrome_frame_launcher.gyp +++ b/chrome_frame/chrome_frame_launcher.gyp @@ -69,6 +69,7 @@ 'dependencies': [ '../breakpad/breakpad.gyp:breakpad_handler', '../chrome/chrome.gyp:chrome_version_header', + '../google_update/google_update.gyp:google_update', 'chrome_frame.gyp:chrome_frame_utils', ], 'resource_include_dirs': [ @@ -80,6 +81,8 @@ 'chrome_launcher_version.rc', 'chrome_launcher.cc', 'chrome_launcher.h', + 'update_launcher.cc', + 'update_launcher.h' ], 'msvs_settings': { 'VCLinkerTool': { diff --git a/chrome_frame/chrome_launcher_main.cc b/chrome_frame/chrome_launcher_main.cc index d56ca92..5716345 100644 --- a/chrome_frame/chrome_launcher_main.cc +++ b/chrome_frame/chrome_launcher_main.cc @@ -2,14 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - #include <windows.h> #include <DbgHelp.h> #include <string> #include "chrome_frame/chrome_launcher.h" #include "chrome_frame/crash_server_init.h" - +#include "chrome_frame/update_launcher.h" int APIENTRY wWinMain(HINSTANCE, HINSTANCE, wchar_t*, int) { const wchar_t* cmd_line = ::GetCommandLine(); @@ -17,10 +16,15 @@ int APIENTRY wWinMain(HINSTANCE, HINSTANCE, wchar_t*, int) { google_breakpad::scoped_ptr<google_breakpad::ExceptionHandler> breakpad( InitializeCrashReporting(cmd_line)); + std::wstring update_command( + update_launcher::GetUpdateCommandFromArguments(cmd_line)); + UINT exit_code = ERROR_FILE_NOT_FOUND; - if (chrome_launcher::SanitizeAndLaunchChrome(::GetCommandLine())) { + + if (!update_command.empty()) + exit_code = update_launcher::LaunchUpdateCommand(update_command); + else if (chrome_launcher::SanitizeAndLaunchChrome(cmd_line)) exit_code = ERROR_SUCCESS; - } return exit_code; } diff --git a/chrome_frame/chrome_launcher_utils.cc b/chrome_frame/chrome_launcher_utils.cc index 1b5943a..83d64ed 100644 --- a/chrome_frame/chrome_launcher_utils.cc +++ b/chrome_frame/chrome_launcher_utils.cc @@ -14,16 +14,11 @@ #include "chrome/common/chrome_switches.h" #include "chrome_frame/chrome_frame_automation.h" -namespace chrome_launcher { +namespace { -const wchar_t kLauncherExeBaseName[] = L"chrome_launcher.exe"; - -CommandLine* CreateLaunchCommandLine() { - // Shortcut for OS versions that don't need the integrity broker. - if (base::win::GetVersion() < base::win::VERSION_VISTA) { - return new CommandLine(GetChromeExecutablePath()); - } +const char kUpdateCommandFlag[] = "--update-cmd"; +CommandLine* CreateChromeLauncherCommandLine() { // The launcher EXE will be in the same directory as the Chrome Frame DLL, // so create a full path to it based on this assumption. Since our unit // tests also use this function, and live in the directory above, we test @@ -32,12 +27,13 @@ CommandLine* CreateLaunchCommandLine() { FilePath module_path; if (PathService::Get(base::FILE_MODULE, &module_path)) { FilePath current_dir = module_path.DirName(); - FilePath same_dir_path = current_dir.Append(kLauncherExeBaseName); + FilePath same_dir_path = current_dir.Append( + chrome_launcher::kLauncherExeBaseName); if (file_util::PathExists(same_dir_path)) { return new CommandLine(same_dir_path); } else { - FilePath servers_path = - current_dir.Append(L"servers").Append(kLauncherExeBaseName); + FilePath servers_path = current_dir.Append(L"servers").Append( + chrome_launcher::kLauncherExeBaseName); DCHECK(file_util::PathExists(servers_path)) << "What module is this? It's not in 'servers' or main output dir."; return new CommandLine(servers_path); @@ -48,6 +44,32 @@ CommandLine* CreateLaunchCommandLine() { } } +} // namespace + +namespace chrome_launcher { + +const wchar_t kLauncherExeBaseName[] = L"chrome_launcher.exe"; + +CommandLine* CreateUpdateCommandLine(const std::wstring& update_command) { + CommandLine* command_line = CreateChromeLauncherCommandLine(); + + if (command_line) { + command_line->AppendArg(kUpdateCommandFlag); + command_line->AppendArg(WideToASCII(update_command)); + } + + return command_line; +} + +CommandLine* CreateLaunchCommandLine() { + // Shortcut for OS versions that don't need the integrity broker. + if (base::win::GetVersion() < base::win::VERSION_VISTA) { + return new CommandLine(GetChromeExecutablePath()); + } + + return CreateChromeLauncherCommandLine(); +} + FilePath GetChromeExecutablePath() { FilePath cur_path; PathService::Get(base::DIR_MODULE, &cur_path); diff --git a/chrome_frame/chrome_launcher_utils.h b/chrome_frame/chrome_launcher_utils.h index 31698c5..4f5cdad 100644 --- a/chrome_frame/chrome_launcher_utils.h +++ b/chrome_frame/chrome_launcher_utils.h @@ -23,6 +23,12 @@ extern const wchar_t kLauncherExeBaseName[]; // returned command line. CommandLine* CreateLaunchCommandLine(); +// Creates a command line suitable for launching the specified command through +// Google Update. +// +// You must delete the returned command line. +CommandLine* CreateUpdateCommandLine(const std::wstring& update_command); + // Returns the full path to the Chrome executable. FilePath GetChromeExecutablePath(); diff --git a/chrome_frame/ready_mode/internal/registry_ready_mode_state.cc b/chrome_frame/ready_mode/internal/registry_ready_mode_state.cc index 880fd51..94d7a1b 100644 --- a/chrome_frame/ready_mode/internal/registry_ready_mode_state.cc +++ b/chrome_frame/ready_mode/internal/registry_ready_mode_state.cc @@ -14,12 +14,13 @@ #include "base/win/registry.h" #include "base/win/scoped_comptr.h" #include "base/win/scoped_handle.h" +#include "base/win/windows_version.h" #include "chrome/installer/util/browser_distribution.h" #include "chrome/installer/util/google_update_constants.h" #include "chrome/installer/util/master_preferences.h" #include "chrome/installer/util/util_constants.h" +#include "chrome_frame/chrome_launcher_utils.h" #include "chrome_frame/ready_mode/ready_mode.h" -#include "google_update_idl.h" // NOLINT namespace { @@ -53,28 +54,15 @@ HANDLE LaunchCommandDirectly(const std::wstring& command_field) { // the launched process, which the caller is responsible for closing, or NULL // upon failure. HANDLE LaunchCommandViaProcessLauncher(const std::wstring& command_field) { - BrowserDistribution* dist = BrowserDistribution::GetDistribution(); - - base::win::ScopedComPtr<IProcessLauncher> ipl; - HRESULT hr = ipl.CreateInstance(__uuidof(ProcessLauncherClass)); + HANDLE launched_process = NULL; - if (FAILED(hr)) { - DLOG(ERROR) << "Failed to instantiate IProcessLauncher: " - << base::StringPrintf("0x%08x", hr); - } else { - ULONG_PTR phandle = NULL; - DWORD id = GetCurrentProcessId(); + scoped_ptr<CommandLine> command_line( + chrome_launcher::CreateUpdateCommandLine(command_field)); - hr = ipl->LaunchCmdElevated(dist->GetAppGuid().c_str(), - command_field.c_str(), id, &phandle); - if (SUCCEEDED(hr)) - return reinterpret_cast<HANDLE>(phandle); + if (command_line != NULL) + base::LaunchApp(*command_line, false, true, &launched_process); - DLOG(ERROR) << "Failed to invoke IProcessLauncher::LaunchCmdElevated: " - << base::StringPrintf("0x%08x", hr); - } - - return NULL; + return launched_process; } // Waits for the provided process to exit, and verifies that its exit code @@ -114,17 +102,34 @@ bool CheckProcessExitCode(HANDLE handle) { return false; } +// If we are running on XP (no protected mode) or in a high-integrity process, +// we can invoke the installer directly. If not, we will have to go via the +// ProcessLauncher. +bool CanLaunchDirectly() { + if (base::win::GetVersion() < base::win::VERSION_VISTA) + return true; + + base::IntegrityLevel integrity_level = base::INTEGRITY_UNKNOWN; + if (!base::GetProcessIntegrityLevel(base::GetCurrentProcessHandle(), + &integrity_level)) { + DLOG(ERROR) << "Failed to determine process integrity level."; + return false; + } + + return integrity_level == base::HIGH_INTEGRITY; +} + // Attempts to launch the specified command either directly or via the // ProcessLauncher. Returns true if the command is launched and returns a // success code. bool LaunchAndCheckCommand(const std::wstring& command_field) { base::win::ScopedHandle handle; - handle.Set(LaunchCommandDirectly(command_field)); - if (handle.IsValid() && CheckProcessExitCode(handle)) - return true; + if (CanLaunchDirectly()) + handle.Set(LaunchCommandDirectly(command_field)); + else + handle.Set(LaunchCommandViaProcessLauncher(command_field)); - handle.Set(LaunchCommandViaProcessLauncher(command_field)); if (handle.IsValid() && CheckProcessExitCode(handle)) return true; diff --git a/chrome_frame/update_launcher.cc b/chrome_frame/update_launcher.cc new file mode 100644 index 0000000..2aff8ad --- /dev/null +++ b/chrome_frame/update_launcher.cc @@ -0,0 +1,94 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome_frame/update_launcher.h" + +#include <windows.h> +#include <Shellapi.h> + +#include "google_update_idl.h" // NOLINT + +namespace { + +const wchar_t kChromeFrameGuid[] = L"{8BA986DA-5100-405E-AA35-86F34A02ACBF}"; + +const DWORD kLaunchFailureExitCode = 0xFF; + +const wchar_t kUpdateCommandFlag[] = L"--update-cmd"; + +// Waits indefinitely for the provided process to exit. Returns the process's +// exit code, or kLaunchFailureExitCode if an error occurs in the waiting. +DWORD WaitForProcessExitCode(HANDLE handle) { + DWORD exit_code = 0; + + DWORD wait_result = ::WaitForSingleObject(handle, INFINITE); + + if (wait_result == WAIT_OBJECT_0 && ::GetExitCodeProcess(handle, &exit_code)) + return exit_code; + + return kLaunchFailureExitCode; +} + +} // namespace + +namespace update_launcher { + +std::wstring GetUpdateCommandFromArguments(const wchar_t* command_line) { + std::wstring command; + + if (command_line != NULL) { + int num_args = 0; + wchar_t** args = NULL; + args = ::CommandLineToArgvW(command_line, &num_args); + + if (args) { + if (num_args == 3 && _wcsicmp(args[1], kUpdateCommandFlag) == 0) + command = args[2]; + ::LocalFree(args); + } + } + + return command; +} + +// Because we do not have 'base' and all of its pretty RAII helpers, please +// ensure that this function only ever contains a single 'return', in order +// to reduce the chance of introducing a leak. +DWORD LaunchUpdateCommand(const std::wstring& command) { + DWORD exit_code = kLaunchFailureExitCode; + + HRESULT hr = ::CoInitialize(NULL); + + if (SUCCEEDED(hr)) { + IProcessLauncher* ipl = NULL; + HANDLE process = NULL; + + hr = ::CoCreateInstance(__uuidof(ProcessLauncherClass), NULL, + CLSCTX_ALL, __uuidof(IProcessLauncher), + reinterpret_cast<void**>(&ipl)); + + if (SUCCEEDED(hr)) { + ULONG_PTR phandle = NULL; + DWORD id = ::GetCurrentProcessId(); + + hr = ipl->LaunchCmdElevated(kChromeFrameGuid, + command.c_str(), id, &phandle); + if (SUCCEEDED(hr)) { + process = reinterpret_cast<HANDLE>(phandle); + exit_code = WaitForProcessExitCode(process); + } + } + + if (process) + ::CloseHandle(process); + if (ipl) + ipl->Release(); + + ::CoUninitialize(); + } + + return exit_code; +} + +} // namespace process_launcher diff --git a/chrome_frame/update_launcher.h b/chrome_frame/update_launcher.h new file mode 100644 index 0000000..a78ba83 --- /dev/null +++ b/chrome_frame/update_launcher.h @@ -0,0 +1,26 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_FRAME_UPDATE_LAUNCHER_H_ +#define CHROME_FRAME_UPDATE_LAUNCHER_H_ +#pragma once + +#include <string> + +typedef unsigned long DWORD; // NOLINT + +namespace update_launcher { + +// If the command line asks us to run a command via the ProcessLauncher, returns +// the command ID. Otherwise, returns an empty string. +std::wstring GetUpdateCommandFromArguments(const wchar_t* command_line); + +// Launches the specified command via the ProcessLauncher, waits for the process +// to exit, and returns the exit code for chrome_launcher (normally the launched +// command's exit code, or 0xFF in case of failure to launch). +DWORD LaunchUpdateCommand(const std::wstring& command); + +} // namespace process_launcher + +#endif // CHROME_FRAME_UPDATE_LAUNCHER_H_ |