summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/multiprocess_test.h29
-rw-r--r--base/process.h1
-rw-r--r--base/process_util.h14
-rw-r--r--base/process_util_unittest.cc9
-rw-r--r--base/process_util_win.cc40
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,