Commit 73f0bac9 authored by alexeypa@chromium.org's avatar alexeypa@chromium.org

[Chromoting] Move CreateSessionToken() next to launch process utilities.

BUG=134694


Review URL: https://chromiumcodereview.appspot.com/10828160

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@150508 0039d316-1c4b-4281-b951-d872f2087c98
parent bc0d7b86
......@@ -11,6 +11,7 @@
#include "base/basictypes.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/move.h"
namespace base {
namespace win {
......@@ -36,6 +37,8 @@ extern "C" {
// takes a raw handle pointer only.
template <class Traits, class Verifier>
class GenericScopedHandle {
MOVE_ONLY_TYPE_FOR_CPP_03(GenericScopedHandle, RValue)
public:
typedef typename Traits::Handle Handle;
......@@ -45,6 +48,10 @@ class GenericScopedHandle {
Set(handle);
}
// Move constructor for C++03 move emulation of this type.
GenericScopedHandle(RValue& other) : handle_(other.Take()) {
}
~GenericScopedHandle() {
Close();
}
......@@ -53,6 +60,14 @@ class GenericScopedHandle {
return Traits::IsHandleValid(handle_);
}
// Move operator= for C++03 move emulation of this type.
GenericScopedHandle& operator=(RValue& other) {
// Swapping the handles helps to avoid problems while assigning a handle
// to itself. It is also cheap and matches base::scoped_ptr behavior.
Swap(other);
return *this;
}
void Set(Handle handle) {
if (handle_ != handle) {
Close();
......@@ -82,6 +97,12 @@ class GenericScopedHandle {
return &handle_;
}
void Swap(GenericScopedHandle& other) {
Handle tmp = handle_;
handle_ = other.handle_;
other.handle_ = tmp;
}
// Transfers ownership away from this object.
Handle Take() {
Handle temp = handle_;
......@@ -106,8 +127,6 @@ class GenericScopedHandle {
private:
Handle handle_;
DISALLOW_COPY_AND_ASSIGN(GenericScopedHandle);
};
#undef BASE_WIN_GET_CALLER
......
......@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "base/single_thread_task_runner.h"
#include "base/win/scoped_handle.h"
namespace remoting {
......
......@@ -40,6 +40,62 @@ const int kMinLaunchDelaySeconds = 1;
// Name of the default session desktop.
const char kDefaultDesktopName[] = "winsta0\\default";
// Copies the process token making it a primary impersonation token.
// The returned handle will have |desired_access| rights.
bool CopyProcessToken(DWORD desired_access, ScopedHandle* token_out) {
ScopedHandle process_token;
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_DUPLICATE | desired_access,
process_token.Receive())) {
LOG_GETLASTERROR(ERROR) << "Failed to open process token";
return false;
}
ScopedHandle copied_token;
if (!DuplicateTokenEx(process_token,
desired_access,
NULL,
SecurityImpersonation,
TokenPrimary,
copied_token.Receive())) {
LOG_GETLASTERROR(ERROR) << "Failed to duplicate the process token";
return false;
}
*token_out = copied_token.Pass();
return true;
}
// Creates a copy of the current process with SE_TCB_NAME privilege enabled.
bool CreatePrivilegedToken(ScopedHandle* token_out) {
ScopedHandle privileged_token;
DWORD desired_access = TOKEN_ADJUST_PRIVILEGES | TOKEN_IMPERSONATE |
TOKEN_DUPLICATE | TOKEN_QUERY;
if (!CopyProcessToken(desired_access, &privileged_token)) {
return false;
}
// Get the LUID for the SE_TCB_NAME privilege.
TOKEN_PRIVILEGES state;
state.PrivilegeCount = 1;
state.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!LookupPrivilegeValue(NULL, SE_TCB_NAME, &state.Privileges[0].Luid)) {
LOG_GETLASTERROR(ERROR) <<
"Failed to lookup the LUID for the SE_TCB_NAME privilege";
return false;
}
// Enable the SE_TCB_NAME privilege.
if (!AdjustTokenPrivileges(privileged_token, FALSE, &state, 0, NULL, 0)) {
LOG_GETLASTERROR(ERROR) <<
"Failed to enable SE_TCB_NAME privilege in a token";
return false;
}
*token_out = privileged_token.Pass();
return true;
}
// Requests the execution server to create a process in the specified session
// using the default (i.e. Winlogon) token. This routine relies on undocumented
// OS functionality and will likely not work on anything but XP or W2K3.
......@@ -173,7 +229,7 @@ bool CreateRemoteSessionProcess(
// Pass the request to create a process in the target session.
DWORD bytes;
if (!WriteFile(pipe.Get(), buffer.get(), size, &bytes, NULL)) {
if (!WriteFile(pipe, buffer.get(), size, &bytes, NULL)) {
LOG_GETLASTERROR(ERROR) << "Failed to send CreateProcessAsUser request";
return false;
}
......@@ -187,7 +243,7 @@ bool CreateRemoteSessionProcess(
};
CreateProcessResponse response;
if (!ReadFile(pipe.Get(), &response, sizeof(response), &bytes, NULL)) {
if (!ReadFile(pipe, &response, sizeof(response), &bytes, NULL)) {
LOG_GETLASTERROR(ERROR) << "Failed to receive CreateProcessAsUser response";
return false;
}
......@@ -244,6 +300,48 @@ bool CreateRemoteSessionProcess(
namespace remoting {
// Creates a copy of the current process token for the given |session_id| so
// it can be used to launch a process in that session.
bool CreateSessionToken(uint32 session_id, ScopedHandle* token_out) {
ScopedHandle session_token;
DWORD desired_access = TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID |
TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY;
if (!CopyProcessToken(desired_access, &session_token)) {
return false;
}
// Temporarily enable the SE_TCB_NAME privilege as it is required by
// SetTokenInformation(TokenSessionId).
ScopedHandle privileged_token;
if (!CreatePrivilegedToken(&privileged_token)) {
return false;
}
if (!ImpersonateLoggedOnUser(privileged_token)) {
LOG_GETLASTERROR(ERROR) <<
"Failed to impersonate the privileged token";
return false;
}
// Change the session ID of the token.
DWORD new_session_id = session_id;
if (!SetTokenInformation(session_token,
TokenSessionId,
&new_session_id,
sizeof(new_session_id))) {
LOG_GETLASTERROR(ERROR) << "Failed to change session ID of a token";
// Revert to the default token.
CHECK(RevertToSelf());
return false;
}
// Revert to the default token.
CHECK(RevertToSelf());
*token_out = session_token.Pass();
return true;
}
bool LaunchProcessWithToken(const FilePath& binary,
const CommandLine::StringType& command_line,
HANDLE user_token,
......
......@@ -11,9 +11,14 @@
#include "base/command_line.h"
#include "base/file_path.h"
#include "base/process_util.h"
#include "base/win/scoped_handle.h"
namespace remoting {
// Creates a copy of the current process token for the given |session_id| so
// it can be used to launch a process in that session.
bool CreateSessionToken(uint32 session_id, base::win::ScopedHandle* token_out);
// Launches |binary| in the security context of the user represented by
// |user_token|. The session ID specified by the token is respected as well.
bool LaunchProcessWithToken(const FilePath& binary,
......
......@@ -63,92 +63,6 @@ const char* kCopiedSwitchNames[] = {
const wchar_t kChromotingChannelSecurityDescriptor[] =
L"O:SYG:SYD:(A;;GA;;;SY)";
// Takes the process token and makes a copy of it. The returned handle will have
// |desired_access| rights.
bool CopyProcessToken(DWORD desired_access,
ScopedHandle* token_out) {
HANDLE handle;
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_DUPLICATE | desired_access,
&handle)) {
LOG_GETLASTERROR(ERROR) << "Failed to open process token";
return false;
}
ScopedHandle process_token(handle);
if (!DuplicateTokenEx(process_token,
desired_access,
NULL,
SecurityImpersonation,
TokenPrimary,
&handle)) {
LOG_GETLASTERROR(ERROR) << "Failed to duplicate the process token";
return false;
}
token_out->Set(handle);
return true;
}
// Creates a copy of the current process with SE_TCB_NAME privilege enabled.
bool CreatePrivilegedToken(ScopedHandle* token_out) {
ScopedHandle privileged_token;
DWORD desired_access = TOKEN_ADJUST_PRIVILEGES | TOKEN_IMPERSONATE |
TOKEN_DUPLICATE | TOKEN_QUERY;
if (!CopyProcessToken(desired_access, &privileged_token)) {
return false;
}
// Get the LUID for the SE_TCB_NAME privilege.
TOKEN_PRIVILEGES state;
state.PrivilegeCount = 1;
state.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!LookupPrivilegeValue(NULL, SE_TCB_NAME, &state.Privileges[0].Luid)) {
LOG_GETLASTERROR(ERROR) <<
"Failed to lookup the LUID for the SE_TCB_NAME privilege";
return false;
}
// Enable the SE_TCB_NAME privilege.
if (!AdjustTokenPrivileges(privileged_token, FALSE, &state, 0, NULL, 0)) {
LOG_GETLASTERROR(ERROR) <<
"Failed to enable SE_TCB_NAME privilege in a token";
return false;
}
token_out->Set(privileged_token.Take());
return true;
}
// Creates a copy of the current process token for the given |session_id| so
// it can be used to launch a process in that session.
bool CreateSessionToken(uint32 session_id,
ScopedHandle* token_out) {
ScopedHandle session_token;
DWORD desired_access = TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID |
TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY;
if (!CopyProcessToken(desired_access, &session_token)) {
return false;
}
// Change the session ID of the token.
DWORD new_session_id = session_id;
if (!SetTokenInformation(session_token,
TokenSessionId,
&new_session_id,
sizeof(new_session_id))) {
LOG_GETLASTERROR(ERROR) <<
"Failed to change session ID of a token";
return false;
}
token_out->Set(session_token.Take());
return true;
}
// Generates random channel ID.
// N.B. Stolen from src/content/common/child_process_host_impl.cc
std::string GenerateRandomChannelId(void* instance) {
......@@ -407,29 +321,8 @@ void WtsSessionProcessLauncher::OnSessionAttached(uint32 session_id) {
DCHECK(process_watcher_.GetWatchedObject() == NULL);
DCHECK(chromoting_channel_.get() == NULL);
// Temporarily enable the SE_TCB_NAME privilege. The privileged token is
// created as needed and kept for later reuse.
if (privileged_token_.Get() == NULL) {
if (!CreatePrivilegedToken(&privileged_token_)) {
return;
}
}
if (!ImpersonateLoggedOnUser(privileged_token_)) {
LOG_GETLASTERROR(ERROR) <<
"Failed to impersonate the privileged token";
return;
}
// While the SE_TCB_NAME privilege is enabled, create a session token for
// the launched process.
bool result = CreateSessionToken(session_id, &session_token_);
// Revert to the default token. The default token is sufficient to call
// CreateProcessAsUser() successfully.
CHECK(RevertToSelf());
if (!result)
// Create a session token for the launched process.
if (!CreateSessionToken(session_id, &session_token_))
return;
// Now try to launch the host.
......
......@@ -93,9 +93,6 @@ class WtsSessionProcessLauncher
// This pointer is used to unsubscribe from session attach and detach events.
WtsConsoleMonitor* monitor_;
// Impersonation token that has the SE_TCB_NAME privilege enabled.
base::win::ScopedHandle privileged_token_;
// The handle of the process injected into the console session.
base::Process process_;
......
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