From 8f587bf26fb65b5c85d1b05843d8eefd387c2b6f Mon Sep 17 00:00:00 2001 From: Masato Maeda Date: Fri, 10 Nov 2017 13:51:04 -0800 Subject: [PATCH 1/2] Add new config option to support thread token based agent process to start - Create agent proces from the thread token instead of current process. This is usefull when winpty.dll is called by Windows Service program to impersonate to the original user from a remote process. --- src/include/winpty_constants.h | 7 +++ src/libwinpty/winpty.cc | 103 +++++++++++++++++++++++++++------ 2 files changed, 93 insertions(+), 17 deletions(-) diff --git a/src/include/winpty_constants.h b/src/include/winpty_constants.h index 11e34cf1..46e3cd88 100755 --- a/src/include/winpty_constants.h +++ b/src/include/winpty_constants.h @@ -76,11 +76,18 @@ * See https://github.com/rprichard/winpty/issues/58. */ #define WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION 0x8ull + /* Create agent proces from the thread token instead of current process. + * This is usefull when winpty.dll is called by Windows Service program to + * impersonate to the original user from a remote process. + * See https://github.com/rprichard/winpty/issues/132. */ +#define WINPTY_FLAG_IMPERSONATE_THREAD 0x10ull + #define WINPTY_FLAG_MASK (0ull \ | WINPTY_FLAG_CONERR \ | WINPTY_FLAG_PLAIN_OUTPUT \ | WINPTY_FLAG_COLOR_ESCAPES \ | WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION \ + | WINPTY_FLAG_IMPERSONATE_THREAD \ ) /* QuickEdit mode is initially disabled, and the agent does not send mouse diff --git a/src/libwinpty/winpty.cc b/src/libwinpty/winpty.cc index 3d977498..d2cfd504 100644 --- a/src/libwinpty/winpty.cc +++ b/src/libwinpty/winpty.cc @@ -470,6 +470,7 @@ static bool shouldSpecifyHideFlag() { } static OwnedHandle startAgentProcess( + const winpty_config_t *cfg, const std::wstring &desktop, const std::wstring &controlPipeName, const std::wstring ¶ms, @@ -494,24 +495,92 @@ static OwnedHandle startAgentProcess( sui.dwFlags |= STARTF_USESHOWWINDOW; sui.wShowWindow = SW_HIDE; } + PROCESS_INFORMATION pi = {}; - const BOOL success = - CreateProcessW(exePath.c_str(), - cmdlineV.data(), - nullptr, nullptr, - /*bInheritHandles=*/FALSE, - /*dwCreationFlags=*/creationFlags, - nullptr, nullptr, - &sui, &pi); - if (!success) { - const DWORD lastError = GetLastError(); - const auto errStr = - (WStringBuilder(256) - << L"winpty-agent CreateProcess failed: cmdline='" << cmdline - << L"' err=0x" << whexOfInt(lastError)).str_moved(); - throw LibWinptyException( - WINPTY_ERROR_AGENT_CREATION_FAILED, errStr.c_str()); + if (cfg->flags & WINPTY_FLAG_IMPERSONATE_THREAD) { + HRESULT hr; + HANDLE token = nullptr; + if (!OpenThreadToken( + GetCurrentThread(), + TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY, + FALSE, + &token)) + { + const DWORD lastError = GetLastError(); + const auto errStr = + (WStringBuilder(256) + << L"winpty-agent OpenThreadToken failed: cmdline='" << cmdline + << L"' err=0x" << whexOfInt(lastError)).str_moved(); + throw LibWinptyException( + WINPTY_ERROR_AGENT_CREATION_FAILED, errStr.c_str()); + } + + HANDLE dupToken = nullptr; + if (!DuplicateTokenEx( + token, + TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY, + NULL, + SecurityImpersonation, + TokenPrimary, + &dupToken)) + { + CloseHandle(token); + const DWORD lastError = GetLastError(); + const auto errStr = + (WStringBuilder(256) + << L"winpty-agent DuplicateTokenEx failed: cmdline='" << cmdline + << L"' err=0x" << whexOfInt(lastError)).str_moved(); + throw LibWinptyException( + WINPTY_ERROR_AGENT_CREATION_FAILED, errStr.c_str()); + } + + DWORD exitCode = 0; + const BOOL success = CreateProcessAsUser( + dupToken, + exePath.c_str(), + cmdlineV.data(), + nullptr, + nullptr, + FALSE, + CREATE_DEFAULT_ERROR_MODE | CREATE_BREAKAWAY_FROM_JOB | CREATE_UNICODE_ENVIRONMENT | NORMAL_PRIORITY_CLASS, + nullptr, + nullptr, + &sui, + &pi); + if (!success) { + CloseHandle(token); + CloseHandle(dupToken); + const DWORD lastError = GetLastError(); + const auto errStr = + (WStringBuilder(256) + << L"winpty-agent CreateProcessAsUser failed: cmdline='" << cmdline + << L"' err=0x" << whexOfInt(lastError)).str_moved(); + throw LibWinptyException( + WINPTY_ERROR_AGENT_CREATION_FAILED, errStr.c_str()); + } + + CloseHandle(token); + CloseHandle(dupToken); + } else { + const BOOL success = + CreateProcessW(exePath.c_str(), + cmdlineV.data(), + nullptr, nullptr, + /*bInheritHandles=*/FALSE, + /*dwCreationFlags=*/creationFlags, + nullptr, nullptr, + &sui, &pi); + if (!success) { + const DWORD lastError = GetLastError(); + const auto errStr = + (WStringBuilder(256) + << L"winpty-agent CreateProcess failed: cmdline='" << cmdline + << L"' err=0x" << whexOfInt(lastError)).str_moved(); + throw LibWinptyException( + WINPTY_ERROR_AGENT_CREATION_FAILED, errStr.c_str()); + } } + CloseHandle(pi.hThread); TRACE("Created agent successfully, pid=%u, cmdline=%s", static_cast(pi.dwProcessId), @@ -556,7 +625,7 @@ createAgentSession(const winpty_config_t *cfg, DWORD agentPid = 0; wp->agentProcess = startAgentProcess( - desktop, pipeName, params, creationFlags, agentPid); + cfg, desktop, pipeName, params, creationFlags, agentPid); connectControlPipe(*wp.get()); verifyPipeClientPid(wp->controlPipe.get(), agentPid); From 936733069f3d544fc1a39e47abcbbf3492bda3cc Mon Sep 17 00:00:00 2001 From: Masato Maeda Date: Mon, 13 Nov 2017 11:35:50 -0800 Subject: [PATCH 2/2] Address comments --- src/include/winpty_constants.h | 4 ++-- src/libwinpty/winpty.cc | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/include/winpty_constants.h b/src/include/winpty_constants.h index 46e3cd88..83b5644f 100755 --- a/src/include/winpty_constants.h +++ b/src/include/winpty_constants.h @@ -76,8 +76,8 @@ * See https://github.com/rprichard/winpty/issues/58. */ #define WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION 0x8ull - /* Create agent proces from the thread token instead of current process. - * This is usefull when winpty.dll is called by Windows Service program to + /* Create agent process from the thread token instead of current process. + * This is useful when winpty.dll is called by Windows Service program to * impersonate to the original user from a remote process. * See https://github.com/rprichard/winpty/issues/132. */ #define WINPTY_FLAG_IMPERSONATE_THREAD 0x10ull diff --git a/src/libwinpty/winpty.cc b/src/libwinpty/winpty.cc index d2cfd504..0c6c1960 100644 --- a/src/libwinpty/winpty.cc +++ b/src/libwinpty/winpty.cc @@ -534,6 +534,7 @@ static OwnedHandle startAgentProcess( WINPTY_ERROR_AGENT_CREATION_FAILED, errStr.c_str()); } + creationFlags = CREATE_NEW_CONSOLE | CREATE_DEFAULT_ERROR_MODE | CREATE_BREAKAWAY_FROM_JOB | NORMAL_PRIORITY_CLASS; DWORD exitCode = 0; const BOOL success = CreateProcessAsUser( dupToken, @@ -542,7 +543,7 @@ static OwnedHandle startAgentProcess( nullptr, nullptr, FALSE, - CREATE_DEFAULT_ERROR_MODE | CREATE_BREAKAWAY_FROM_JOB | CREATE_UNICODE_ENVIRONMENT | NORMAL_PRIORITY_CLASS, + creationFlags, nullptr, nullptr, &sui,