When changing Ready Mode state from within an IE process, use chrome_launcher...

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
parent 30aa3ee0
...@@ -69,6 +69,7 @@ ...@@ -69,6 +69,7 @@
'dependencies': [ 'dependencies': [
'../breakpad/breakpad.gyp:breakpad_handler', '../breakpad/breakpad.gyp:breakpad_handler',
'../chrome/chrome.gyp:chrome_version_header', '../chrome/chrome.gyp:chrome_version_header',
'../google_update/google_update.gyp:google_update',
'chrome_frame.gyp:chrome_frame_utils', 'chrome_frame.gyp:chrome_frame_utils',
], ],
'resource_include_dirs': [ 'resource_include_dirs': [
...@@ -80,6 +81,8 @@ ...@@ -80,6 +81,8 @@
'chrome_launcher_version.rc', 'chrome_launcher_version.rc',
'chrome_launcher.cc', 'chrome_launcher.cc',
'chrome_launcher.h', 'chrome_launcher.h',
'update_launcher.cc',
'update_launcher.h'
], ],
'msvs_settings': { 'msvs_settings': {
'VCLinkerTool': { 'VCLinkerTool': {
......
...@@ -2,14 +2,13 @@ ...@@ -2,14 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include <windows.h> #include <windows.h>
#include <DbgHelp.h> #include <DbgHelp.h>
#include <string> #include <string>
#include "chrome_frame/chrome_launcher.h" #include "chrome_frame/chrome_launcher.h"
#include "chrome_frame/crash_server_init.h" #include "chrome_frame/crash_server_init.h"
#include "chrome_frame/update_launcher.h"
int APIENTRY wWinMain(HINSTANCE, HINSTANCE, wchar_t*, int) { int APIENTRY wWinMain(HINSTANCE, HINSTANCE, wchar_t*, int) {
const wchar_t* cmd_line = ::GetCommandLine(); const wchar_t* cmd_line = ::GetCommandLine();
...@@ -17,10 +16,15 @@ int APIENTRY wWinMain(HINSTANCE, HINSTANCE, wchar_t*, int) { ...@@ -17,10 +16,15 @@ int APIENTRY wWinMain(HINSTANCE, HINSTANCE, wchar_t*, int) {
google_breakpad::scoped_ptr<google_breakpad::ExceptionHandler> breakpad( google_breakpad::scoped_ptr<google_breakpad::ExceptionHandler> breakpad(
InitializeCrashReporting(cmd_line)); InitializeCrashReporting(cmd_line));
std::wstring update_command(
update_launcher::GetUpdateCommandFromArguments(cmd_line));
UINT exit_code = ERROR_FILE_NOT_FOUND; 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; exit_code = ERROR_SUCCESS;
}
return exit_code; return exit_code;
} }
...@@ -14,16 +14,11 @@ ...@@ -14,16 +14,11 @@
#include "chrome/common/chrome_switches.h" #include "chrome/common/chrome_switches.h"
#include "chrome_frame/chrome_frame_automation.h" #include "chrome_frame/chrome_frame_automation.h"
namespace chrome_launcher { namespace {
const wchar_t kLauncherExeBaseName[] = L"chrome_launcher.exe"; const char kUpdateCommandFlag[] = "--update-cmd";
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());
}
CommandLine* CreateChromeLauncherCommandLine() {
// The launcher EXE will be in the same directory as the Chrome Frame DLL, // 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 // 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 // tests also use this function, and live in the directory above, we test
...@@ -32,12 +27,13 @@ CommandLine* CreateLaunchCommandLine() { ...@@ -32,12 +27,13 @@ CommandLine* CreateLaunchCommandLine() {
FilePath module_path; FilePath module_path;
if (PathService::Get(base::FILE_MODULE, &module_path)) { if (PathService::Get(base::FILE_MODULE, &module_path)) {
FilePath current_dir = module_path.DirName(); 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)) { if (file_util::PathExists(same_dir_path)) {
return new CommandLine(same_dir_path); return new CommandLine(same_dir_path);
} else { } else {
FilePath servers_path = FilePath servers_path = current_dir.Append(L"servers").Append(
current_dir.Append(L"servers").Append(kLauncherExeBaseName); chrome_launcher::kLauncherExeBaseName);
DCHECK(file_util::PathExists(servers_path)) << DCHECK(file_util::PathExists(servers_path)) <<
"What module is this? It's not in 'servers' or main output dir."; "What module is this? It's not in 'servers' or main output dir.";
return new CommandLine(servers_path); return new CommandLine(servers_path);
...@@ -48,6 +44,32 @@ CommandLine* CreateLaunchCommandLine() { ...@@ -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 GetChromeExecutablePath() {
FilePath cur_path; FilePath cur_path;
PathService::Get(base::DIR_MODULE, &cur_path); PathService::Get(base::DIR_MODULE, &cur_path);
......
...@@ -23,6 +23,12 @@ extern const wchar_t kLauncherExeBaseName[]; ...@@ -23,6 +23,12 @@ extern const wchar_t kLauncherExeBaseName[];
// returned command line. // returned command line.
CommandLine* CreateLaunchCommandLine(); 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. // Returns the full path to the Chrome executable.
FilePath GetChromeExecutablePath(); FilePath GetChromeExecutablePath();
......
...@@ -14,12 +14,13 @@ ...@@ -14,12 +14,13 @@
#include "base/win/registry.h" #include "base/win/registry.h"
#include "base/win/scoped_comptr.h" #include "base/win/scoped_comptr.h"
#include "base/win/scoped_handle.h" #include "base/win/scoped_handle.h"
#include "base/win/windows_version.h"
#include "chrome/installer/util/browser_distribution.h" #include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/google_update_constants.h" #include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/master_preferences.h" #include "chrome/installer/util/master_preferences.h"
#include "chrome/installer/util/util_constants.h" #include "chrome/installer/util/util_constants.h"
#include "chrome_frame/chrome_launcher_utils.h"
#include "chrome_frame/ready_mode/ready_mode.h" #include "chrome_frame/ready_mode/ready_mode.h"
#include "google_update_idl.h" // NOLINT
namespace { namespace {
...@@ -53,28 +54,15 @@ HANDLE LaunchCommandDirectly(const std::wstring& command_field) { ...@@ -53,28 +54,15 @@ HANDLE LaunchCommandDirectly(const std::wstring& command_field) {
// the launched process, which the caller is responsible for closing, or NULL // the launched process, which the caller is responsible for closing, or NULL
// upon failure. // upon failure.
HANDLE LaunchCommandViaProcessLauncher(const std::wstring& command_field) { HANDLE LaunchCommandViaProcessLauncher(const std::wstring& command_field) {
BrowserDistribution* dist = BrowserDistribution::GetDistribution(); HANDLE launched_process = NULL;
base::win::ScopedComPtr<IProcessLauncher> ipl;
HRESULT hr = ipl.CreateInstance(__uuidof(ProcessLauncherClass));
if (FAILED(hr)) { scoped_ptr<CommandLine> command_line(
DLOG(ERROR) << "Failed to instantiate IProcessLauncher: " chrome_launcher::CreateUpdateCommandLine(command_field));
<< base::StringPrintf("0x%08x", hr);
} else {
ULONG_PTR phandle = NULL;
DWORD id = GetCurrentProcessId();
hr = ipl->LaunchCmdElevated(dist->GetAppGuid().c_str(), if (command_line != NULL)
command_field.c_str(), id, &phandle); base::LaunchApp(*command_line, false, true, &launched_process);
if (SUCCEEDED(hr))
return reinterpret_cast<HANDLE>(phandle);
DLOG(ERROR) << "Failed to invoke IProcessLauncher::LaunchCmdElevated: " return launched_process;
<< base::StringPrintf("0x%08x", hr);
}
return NULL;
} }
// Waits for the provided process to exit, and verifies that its exit code // Waits for the provided process to exit, and verifies that its exit code
...@@ -114,17 +102,34 @@ bool CheckProcessExitCode(HANDLE handle) { ...@@ -114,17 +102,34 @@ bool CheckProcessExitCode(HANDLE handle) {
return false; 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 // Attempts to launch the specified command either directly or via the
// ProcessLauncher. Returns true if the command is launched and returns a // ProcessLauncher. Returns true if the command is launched and returns a
// success code. // success code.
bool LaunchAndCheckCommand(const std::wstring& command_field) { bool LaunchAndCheckCommand(const std::wstring& command_field) {
base::win::ScopedHandle handle; base::win::ScopedHandle handle;
handle.Set(LaunchCommandDirectly(command_field)); if (CanLaunchDirectly())
if (handle.IsValid() && CheckProcessExitCode(handle)) handle.Set(LaunchCommandDirectly(command_field));
return true; else
handle.Set(LaunchCommandViaProcessLauncher(command_field));
handle.Set(LaunchCommandViaProcessLauncher(command_field));
if (handle.IsValid() && CheckProcessExitCode(handle)) if (handle.IsValid() && CheckProcessExitCode(handle))
return true; return true;
......
// 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
// 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_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment