diff options
-rw-r--r-- | base/multiprocess_test.h | 29 | ||||
-rw-r--r-- | base/process.h | 1 | ||||
-rw-r--r-- | base/process_util.h | 14 | ||||
-rw-r--r-- | base/process_util_unittest.cc | 9 | ||||
-rw-r--r-- | base/process_util_win.cc | 40 |
5 files changed, 78 insertions, 15 deletions
diff --git a/base/multiprocess_test.h b/base/multiprocess_test.h index 7b9af1a..4fa5693 100644 --- a/base/multiprocess_test.h +++ b/base/multiprocess_test.h @@ -83,21 +83,25 @@ class MultiProcessTest : public PlatformTest { } #endif - private: -#if defined(OS_WIN) - base::ProcessHandle SpawnChildImpl( - const std::wstring& procname, - bool debug_on_start) { +protected: + CommandLine MakeCmdLine(const std::wstring& procname, bool debug_on_start) { CommandLine cl(*CommandLine::ForCurrentProcess()); - base::ProcessHandle handle = static_cast<base::ProcessHandle>(NULL); cl.AppendSwitchWithValue(kRunClientProcess, procname); - if (debug_on_start) cl.AppendSwitch(switches::kDebugOnStart); + return cl; + } - base::LaunchApp(cl, false, true, &handle); + private: +#if defined(OS_WIN) + base::ProcessHandle SpawnChildImpl(const std::wstring& procname, + bool debug_on_start) { + base::ProcessHandle handle = static_cast<base::ProcessHandle>(NULL); + base::LaunchApp(MakeCmdLine(procname, debug_on_start), + false, true, &handle); return handle; } + #elif defined(OS_POSIX) // TODO(port): with the CommandLine refactoring, this code is very similar // to the Windows code. Investigate whether this can be made shorter. @@ -105,14 +109,9 @@ class MultiProcessTest : public PlatformTest { const std::wstring& procname, const base::file_handle_mapping_vector& fds_to_map, bool debug_on_start) { - CommandLine cl(*CommandLine::ForCurrentProcess()); base::ProcessHandle handle = base::kNullProcessHandle; - cl.AppendSwitchWithValue(kRunClientProcess, procname); - - if (debug_on_start) - cl.AppendSwitch(switches::kDebugOnStart); - - base::LaunchApp(cl.argv(), fds_to_map, false, &handle); + base::LaunchApp(MakeCmdLine(procname, debug_on_start).argv(), + fds_to_map, false, &handle); return handle; } #endif diff --git a/base/process.h b/base/process.h index 6ac29e9..f52c455 100644 --- a/base/process.h +++ b/base/process.h @@ -21,6 +21,7 @@ namespace base { #if defined(OS_WIN) typedef HANDLE ProcessHandle; typedef DWORD ProcessId; +typedef HANDLE UserTokenHandle; const ProcessHandle kNullProcessHandle = NULL; #elif defined(OS_POSIX) // On POSIX, our ProcessHandle will just be the PID. diff --git a/base/process_util.h b/base/process_util.h index 1dc01df..99f68c0 100644 --- a/base/process_util.h +++ b/base/process_util.h @@ -140,6 +140,20 @@ void CloseSuperfluousFds(const base::InjectiveMultimap& saved_map); // that it doesn't leak! bool LaunchApp(const std::wstring& cmdline, bool wait, bool start_hidden, ProcessHandle* process_handle); + +// Runs the given application name with the given command line as if the user +// represented by |token| had launched it. The caveats about |cmdline| and +// |process_handle| explained for LaunchApp above apply as well. +// +// Whether the application is visible on the interactive desktop depends on +// the token belonging to an interactive logon session. +// +// To avoid hard to diagnose problems, this function internally loads the +// environment variables associated with the user and if this operation fails +// the entire call fails as well. +bool LaunchAppAsUser(UserTokenHandle token, const std::wstring& cmdline, + bool start_hidden, ProcessHandle* process_handle); + #elif defined(OS_POSIX) // Runs the application specified in argv[0] with the command line argv. // Before launching all FDs open in the parent process will be marked as diff --git a/base/process_util_unittest.cc b/base/process_util_unittest.cc index da84c227..2ccca54 100644 --- a/base/process_util_unittest.cc +++ b/base/process_util_unittest.cc @@ -188,6 +188,15 @@ TEST_F(ProcessUtilTest, GetAppOutput) { ASSERT_TRUE(base::GetAppOutput(other_cmd_line, &output)); EXPECT_EQ("", output); } + +TEST_F(ProcessUtilTest, LaunchAsUser) { + base::UserTokenHandle token; + ASSERT_TRUE(OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)); + std::wstring cmdline = + this->MakeCmdLine(L"SimpleChildProcess", false).command_line_string(); + EXPECT_TRUE(base::LaunchAppAsUser(token, cmdline, false, NULL)); +} + #endif // defined(OS_WIN) #if defined(OS_POSIX) diff --git a/base/process_util_win.cc b/base/process_util_win.cc index 42e727c..3b1ab9a 100644 --- a/base/process_util_win.cc +++ b/base/process_util_win.cc @@ -7,6 +7,7 @@ #include <fcntl.h> #include <io.h> #include <windows.h> +#include <userenv.h> #include <psapi.h> #include <ios> @@ -17,6 +18,9 @@ #include "base/scoped_handle_win.h" #include "base/scoped_ptr.h" +// userenv.dll is required for CreateEnvironmentBlock(). +#pragma comment(lib, "userenv.lib") + namespace base { namespace { @@ -162,6 +166,42 @@ bool LaunchApp(const std::wstring& cmdline, return true; } + +bool LaunchAppAsUser(UserTokenHandle token, const std::wstring& cmdline, + bool start_hidden, ProcessHandle* process_handle) { + STARTUPINFO startup_info = {0}; + startup_info.cb = sizeof(startup_info); + PROCESS_INFORMATION process_info; + if (start_hidden) { + startup_info.dwFlags = STARTF_USESHOWWINDOW; + startup_info.wShowWindow = SW_HIDE; + } + DWORD flags = CREATE_UNICODE_ENVIRONMENT; + void* enviroment_block = NULL; + + if(!CreateEnvironmentBlock(&enviroment_block, token, FALSE)) + return false; + + BOOL launched = + CreateProcessAsUser(token, NULL, const_cast<wchar_t*>(cmdline.c_str()), + NULL, NULL, FALSE, flags, enviroment_block, + NULL, &startup_info, &process_info); + + DestroyEnvironmentBlock(enviroment_block); + + if (!launched) + return false; + + CloseHandle(process_info.hThread); + + if (process_handle) { + *process_handle = process_info.hProcess; + } else { + CloseHandle(process_info.hProcess); + } + return true; +} + bool LaunchApp(const CommandLine& cl, bool wait, bool start_hidden, ProcessHandle* process_handle) { return LaunchApp(cl.command_line_string(), wait, |