summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorerikwright@chromium.org <erikwright@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-24 19:14:11 +0000
committererikwright@chromium.org <erikwright@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-24 19:14:11 +0000
commitefd97484dbba5faec394693002228a1f0e2c2f82 (patch)
treefcf94e84e1dc8213debb308fc4c405738eac3543
parent30aa3ee0461f0475180d50d4adc4b925fe7e1315 (diff)
downloadchromium_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.gyp3
-rw-r--r--chrome_frame/chrome_launcher_main.cc12
-rw-r--r--chrome_frame/chrome_launcher_utils.cc44
-rw-r--r--chrome_frame/chrome_launcher_utils.h6
-rw-r--r--chrome_frame/ready_mode/internal/registry_ready_mode_state.cc53
-rw-r--r--chrome_frame/update_launcher.cc94
-rw-r--r--chrome_frame/update_launcher.h26
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_