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 @@
'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': {
......
......@@ -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;
}
......@@ -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);
......
......@@ -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();
......
......@@ -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;
......
// 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