Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(445)

Unified Diff: remoting/host/wts_session_process_launcher_win.cc

Issue 10832068: Moving Windows-only files: remoting/host -> remoting/host/win. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « remoting/host/wts_session_process_launcher_win.h ('k') | remoting/remoting.gyp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: remoting/host/wts_session_process_launcher_win.cc
===================================================================
--- remoting/host/wts_session_process_launcher_win.cc (revision 149037)
+++ remoting/host/wts_session_process_launcher_win.cc (working copy)
@@ -1,466 +0,0 @@
-// Copyright (c) 2012 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.
-//
-// This file implements the Windows service controlling Me2Me host processes
-// running within user sessions.
-
-#include "remoting/host/wts_session_process_launcher_win.h"
-
-#include <windows.h>
-#include <sddl.h>
-#include <limits>
-
-#include "base/base_switches.h"
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/message_loop_proxy.h"
-#include "base/process_util.h"
-#include "base/rand_util.h"
-#include "base/stringprintf.h"
-#include "base/win/scoped_handle.h"
-#include "ipc/ipc_channel_proxy.h"
-#include "ipc/ipc_message.h"
-#include "ipc/ipc_message_macros.h"
-#include "remoting/host/constants.h"
-#include "remoting/host/chromoting_messages.h"
-#include "remoting/host/launch_process_in_session_win.h"
-#include "remoting/host/sas_injector.h"
-#include "remoting/host/wts_console_monitor_win.h"
-
-using base::win::ScopedHandle;
-using base::TimeDelta;
-
-namespace {
-
-// The minimum and maximum delays between attempts to inject host process into
-// a session.
-const int kMaxLaunchDelaySeconds = 60;
-const int kMinLaunchDelaySeconds = 1;
-
-// Match the pipe name prefix used by Chrome IPC channels.
-const wchar_t kChromePipeNamePrefix[] = L"\\\\.\\pipe\\chrome.";
-
-// The IPC channel name is passed to the host in the command line.
-const char kChromotingIpcSwitchName[] = "chromoting-ipc";
-
-// The command line parameters that should be copied from the service's command
-// line to the host process.
-const char* kCopiedSwitchNames[] = {
- "auth-config", "host-config", switches::kV, switches::kVModule };
-
-// The security descriptor of the Chromoting IPC channel. It gives full access
-// to LocalSystem and denies access by anyone else.
-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::wstring GenerateRandomChannelId(void* instance) {
- return base::StringPrintf(L"%d.%p.%d",
- base::GetCurrentProcId(), instance,
- base::RandInt(0, std::numeric_limits<int>::max()));
-}
-
-// Creates the server end of the Chromoting IPC channel.
-// N.B. This code is based on IPC::Channel's implementation.
-bool CreatePipeForIpcChannel(void* instance,
- std::wstring* channel_name_out,
- ScopedHandle* pipe_out) {
- // Create security descriptor for the channel.
- SECURITY_ATTRIBUTES security_attributes;
- security_attributes.nLength = sizeof(security_attributes);
- security_attributes.bInheritHandle = FALSE;
-
- ULONG security_descriptor_length = 0;
- if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(
- kChromotingChannelSecurityDescriptor,
- SDDL_REVISION_1,
- reinterpret_cast<PSECURITY_DESCRIPTOR*>(
- &security_attributes.lpSecurityDescriptor),
- &security_descriptor_length)) {
- LOG_GETLASTERROR(ERROR) <<
- "Failed to create a security descriptor for the Chromoting IPC channel";
- return false;
- }
-
- // Generate a random channel name.
- std::wstring channel_name(GenerateRandomChannelId(instance));
-
- // Convert it to the pipe name.
- std::wstring pipe_name(kChromePipeNamePrefix);
- pipe_name.append(channel_name);
-
- // Create the server end of the pipe. This code should match the code in
- // IPC::Channel with exception of passing a non-default security descriptor.
- HANDLE pipe = CreateNamedPipeW(pipe_name.c_str(),
- PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
- FILE_FLAG_FIRST_PIPE_INSTANCE,
- PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
- 1,
- IPC::Channel::kReadBufferSize,
- IPC::Channel::kReadBufferSize,
- 5000,
- &security_attributes);
- if (pipe == INVALID_HANDLE_VALUE) {
- LOG_GETLASTERROR(ERROR) <<
- "Failed to create the server end of the Chromoting IPC channel";
- LocalFree(security_attributes.lpSecurityDescriptor);
- return false;
- }
-
- LocalFree(security_attributes.lpSecurityDescriptor);
-
- *channel_name_out = channel_name;
- pipe_out->Set(pipe);
- return true;
-}
-
-} // namespace
-
-namespace remoting {
-
-// Session id that does not represent any session.
-const uint32 kInvalidSessionId = 0xffffffff;
-
-WtsSessionProcessLauncher::WtsSessionProcessLauncher(
- WtsConsoleMonitor* monitor,
- const FilePath& host_binary,
- scoped_refptr<base::MessageLoopProxy> main_message_loop,
- scoped_refptr<base::MessageLoopProxy> ipc_message_loop)
- : host_binary_(host_binary),
- main_message_loop_(main_message_loop),
- ipc_message_loop_(ipc_message_loop),
- monitor_(monitor),
- state_(StateDetached) {
- monitor_->AddWtsConsoleObserver(this);
-}
-
-WtsSessionProcessLauncher::~WtsSessionProcessLauncher() {
- DCHECK(state_ == StateDetached);
- DCHECK(!timer_.IsRunning());
- DCHECK(process_.handle() == NULL);
- DCHECK(process_watcher_.GetWatchedObject() == NULL);
- DCHECK(chromoting_channel_.get() == NULL);
- if (monitor_ != NULL) {
- monitor_->RemoveWtsConsoleObserver(this);
- }
-}
-
-void WtsSessionProcessLauncher::LaunchProcess() {
- DCHECK(main_message_loop_->BelongsToCurrentThread());
- DCHECK(state_ == StateStarting);
- DCHECK(!timer_.IsRunning());
- DCHECK(process_.handle() == NULL);
- DCHECK(process_watcher_.GetWatchedObject() == NULL);
- DCHECK(chromoting_channel_.get() == NULL);
-
- launch_time_ = base::Time::Now();
-
- std::wstring channel_name;
- ScopedHandle pipe;
- if (CreatePipeForIpcChannel(this, &channel_name, &pipe)) {
- // Wrap the pipe into an IPC channel.
- chromoting_channel_.reset(new IPC::ChannelProxy(
- IPC::ChannelHandle(pipe.Get()),
- IPC::Channel::MODE_SERVER,
- this,
- ipc_message_loop_));
-
- // Create the host process command line passing the name of the IPC channel
- // to use and copying known switches from the service's command line.
- CommandLine command_line(host_binary_);
- command_line.AppendSwitchNative(kChromotingIpcSwitchName, channel_name);
- command_line.CopySwitchesFrom(*CommandLine::ForCurrentProcess(),
- kCopiedSwitchNames,
- _countof(kCopiedSwitchNames));
-
- // Try to launch the process and attach an object watcher to the returned
- // handle so that we get notified when the process terminates.
- if (LaunchProcessInSession(host_binary_,
- command_line.GetCommandLineString(),
- session_token_,
- &process_)) {
- if (process_watcher_.StartWatching(process_.handle(), this)) {
- state_ = StateAttached;
- return;
- } else {
- LOG(ERROR) << "Failed to arm the process watcher.";
- process_.Terminate(0);
- process_.Close();
- }
- }
-
- chromoting_channel_.reset();
- }
-
- // Something went wrong. Try to launch the host again later. The attempts rate
- // is limited by exponential backoff.
- launch_backoff_ = std::max(launch_backoff_ * 2,
- TimeDelta::FromSeconds(kMinLaunchDelaySeconds));
- launch_backoff_ = std::min(launch_backoff_,
- TimeDelta::FromSeconds(kMaxLaunchDelaySeconds));
- timer_.Start(FROM_HERE, launch_backoff_,
- this, &WtsSessionProcessLauncher::LaunchProcess);
-}
-
-void WtsSessionProcessLauncher::OnObjectSignaled(HANDLE object) {
- if (!main_message_loop_->BelongsToCurrentThread()) {
- main_message_loop_->PostTask(
- FROM_HERE, base::Bind(&WtsSessionProcessLauncher::OnObjectSignaled,
- base::Unretained(this), object));
- return;
- }
-
- // It is possible that OnObjectSignaled() task will be queued by another
- // thread right before |process_watcher_| was stopped. It such a case it is
- // safe to ignore this notification.
- if (state_ != StateAttached) {
- return;
- }
-
- DCHECK(!timer_.IsRunning());
- DCHECK(process_.handle() != NULL);
- DCHECK(process_watcher_.GetWatchedObject() == NULL);
- DCHECK(chromoting_channel_.get() != NULL);
-
- // Stop trying to restart the host if its process exited due to
- // misconfiguration.
- int exit_code;
- bool stop_trying =
- base::WaitForExitCodeWithTimeout(
- process_.handle(), &exit_code, base::TimeDelta()) &&
- kMinPermanentErrorExitCode <= exit_code &&
- exit_code <= kMaxPermanentErrorExitCode;
-
- // The host process has been terminated for some reason. The handle can now be
- // closed.
- process_.Close();
- chromoting_channel_.reset();
- state_ = StateStarting;
-
- if (stop_trying) {
- OnSessionDetached();
-
- // N.B. The service will stop once the last observer is removed from
- // the list.
- monitor_->RemoveWtsConsoleObserver(this);
- monitor_ = NULL;
- return;
- }
-
- // Expand the backoff interval if the process has died quickly or reset it if
- // it was up longer than the maximum backoff delay.
- base::TimeDelta delta = base::Time::Now() - launch_time_;
- if (delta < base::TimeDelta() ||
- delta >= base::TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)) {
- launch_backoff_ = base::TimeDelta();
- } else {
- launch_backoff_ = std::max(launch_backoff_ * 2,
- TimeDelta::FromSeconds(kMinLaunchDelaySeconds));
- launch_backoff_ = std::min(launch_backoff_,
- TimeDelta::FromSeconds(kMaxLaunchDelaySeconds));
- }
-
- // Try to restart the host.
- timer_.Start(FROM_HERE, launch_backoff_,
- this, &WtsSessionProcessLauncher::LaunchProcess);
-}
-
-bool WtsSessionProcessLauncher::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(WtsSessionProcessLauncher, message)
- IPC_MESSAGE_HANDLER(ChromotingHostMsg_SendSasToConsole,
- OnSendSasToConsole)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void WtsSessionProcessLauncher::OnSendSasToConsole() {
- if (!main_message_loop_->BelongsToCurrentThread()) {
- main_message_loop_->PostTask(
- FROM_HERE, base::Bind(&WtsSessionProcessLauncher::OnSendSasToConsole,
- base::Unretained(this)));
- return;
- }
-
- if (state_ == StateAttached) {
- if (sas_injector_.get() == NULL) {
- sas_injector_ = SasInjector::Create();
- }
-
- if (sas_injector_.get() != NULL) {
- sas_injector_->InjectSas();
- }
- }
-}
-
-void WtsSessionProcessLauncher::OnSessionAttached(uint32 session_id) {
- DCHECK(main_message_loop_->BelongsToCurrentThread());
- DCHECK(state_ == StateDetached);
- DCHECK(!timer_.IsRunning());
- DCHECK(process_.handle() == NULL);
- 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)
- return;
-
- // Now try to launch the host.
- state_ = StateStarting;
- LaunchProcess();
-}
-
-void WtsSessionProcessLauncher::OnSessionDetached() {
- DCHECK(main_message_loop_->BelongsToCurrentThread());
- DCHECK(state_ == StateDetached ||
- state_ == StateStarting ||
- state_ == StateAttached);
-
- switch (state_) {
- case StateDetached:
- DCHECK(!timer_.IsRunning());
- DCHECK(process_.handle() == NULL);
- DCHECK(process_watcher_.GetWatchedObject() == NULL);
- DCHECK(chromoting_channel_.get() == NULL);
- break;
-
- case StateStarting:
- DCHECK(process_.handle() == NULL);
- DCHECK(process_watcher_.GetWatchedObject() == NULL);
- DCHECK(chromoting_channel_.get() == NULL);
-
- timer_.Stop();
- launch_backoff_ = base::TimeDelta();
- state_ = StateDetached;
- break;
-
- case StateAttached:
- DCHECK(!timer_.IsRunning());
- DCHECK(process_.handle() != NULL);
- DCHECK(process_watcher_.GetWatchedObject() != NULL);
- DCHECK(chromoting_channel_.get() != NULL);
-
- process_watcher_.StopWatching();
- process_.Terminate(0);
- process_.Close();
- chromoting_channel_.reset();
- state_ = StateDetached;
- break;
- }
-
- session_token_.Close();
-}
-
-} // namespace remoting
« no previous file with comments | « remoting/host/wts_session_process_launcher_win.h ('k') | remoting/remoting.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698