This source file includes following definitions.
- GetRegistryKeyForTransit
- OnChannelConnected
- OnPermanentError
- SendToNetwork
- OnDesktopSessionAgentAttached
- DoCreateDesktopSession
- DoCrashNetworkProcess
- LaunchNetworkProcess
- Create
- DisableAutoStart
- InitializePairingRegistry
- OpenPairingRegistry
#include "remoting/host/daemon_process.h"
#include "base/base_switches.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/process/process.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/win/registry.h"
#include "base/win/scoped_handle.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_macros.h"
#include "remoting/base/auto_thread_task_runner.h"
#include "remoting/base/scoped_sc_handle_win.h"
#include "remoting/host/branding.h"
#include "remoting/host/chromoting_messages.h"
#include "remoting/host/desktop_session_win.h"
#include "remoting/host/host_exit_codes.h"
#include "remoting/host/host_main.h"
#include "remoting/host/ipc_constants.h"
#include "remoting/host/pairing_registry_delegate_win.h"
#include "remoting/host/screen_resolution.h"
#include "remoting/host/win/launch_process_with_token.h"
#include "remoting/host/win/unprivileged_process_delegate.h"
#include "remoting/host/win/worker_process_launcher.h"
using base::win::ScopedHandle;
using base::TimeDelta;
namespace {
IPC::PlatformFileForTransit GetRegistryKeyForTransit(
base::ProcessHandle target_process,
const base::win::RegKey& key) {
base::PlatformFile handle =
reinterpret_cast<base::PlatformFile>(key.Handle());
return IPC::GetFileHandleForProcess(handle, target_process, false);
}
}
namespace remoting {
class WtsTerminalMonitor;
const char* kCopiedSwitchNames[] = { switches::kV, switches::kVModule };
class DaemonProcessWin : public DaemonProcess {
public:
DaemonProcessWin(
scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
scoped_refptr<AutoThreadTaskRunner> io_task_runner,
const base::Closure& stopped_callback);
virtual ~DaemonProcessWin();
virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
virtual void OnPermanentError(int exit_code) OVERRIDE;
virtual void SendToNetwork(IPC::Message* message) OVERRIDE;
virtual bool OnDesktopSessionAgentAttached(
int terminal_id,
base::ProcessHandle desktop_process,
IPC::PlatformFileForTransit desktop_pipe) OVERRIDE;
protected:
virtual scoped_ptr<DesktopSession> DoCreateDesktopSession(
int terminal_id,
const ScreenResolution& resolution,
bool virtual_terminal) OVERRIDE;
virtual void DoCrashNetworkProcess(
const tracked_objects::Location& location) OVERRIDE;
virtual void LaunchNetworkProcess() OVERRIDE;
void DisableAutoStart();
bool InitializePairingRegistry();
bool OpenPairingRegistry();
private:
scoped_ptr<WorkerProcessLauncher> network_launcher_;
ScopedHandle network_process_;
base::win::RegKey pairing_registry_privileged_key_;
base::win::RegKey pairing_registry_unprivileged_key_;
DISALLOW_COPY_AND_ASSIGN(DaemonProcessWin);
};
DaemonProcessWin::DaemonProcessWin(
scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
scoped_refptr<AutoThreadTaskRunner> io_task_runner,
const base::Closure& stopped_callback)
: DaemonProcess(caller_task_runner, io_task_runner, stopped_callback) {
}
DaemonProcessWin::~DaemonProcessWin() {
}
void DaemonProcessWin::OnChannelConnected(int32 peer_pid) {
network_process_.Set(OpenProcess(PROCESS_DUP_HANDLE, false, peer_pid));
if (!network_process_.IsValid()) {
CrashNetworkProcess(FROM_HERE);
return;
}
if (!InitializePairingRegistry()) {
CrashNetworkProcess(FROM_HERE);
return;
}
DaemonProcess::OnChannelConnected(peer_pid);
}
void DaemonProcessWin::OnPermanentError(int exit_code) {
if (exit_code == kInvalidHostIdExitCode)
DisableAutoStart();
DaemonProcess::OnPermanentError(exit_code);
}
void DaemonProcessWin::SendToNetwork(IPC::Message* message) {
if (network_launcher_) {
network_launcher_->Send(message);
} else {
delete message;
}
}
bool DaemonProcessWin::OnDesktopSessionAgentAttached(
int terminal_id,
base::ProcessHandle desktop_process,
IPC::PlatformFileForTransit desktop_pipe) {
base::ProcessHandle desktop_process_for_transit;
if (!DuplicateHandle(GetCurrentProcess(),
desktop_process,
network_process_,
&desktop_process_for_transit,
0,
FALSE,
DUPLICATE_SAME_ACCESS)) {
LOG_GETLASTERROR(ERROR) << "Failed to duplicate the desktop process handle";
return false;
}
SendToNetwork(new ChromotingDaemonNetworkMsg_DesktopAttached(
terminal_id, desktop_process_for_transit, desktop_pipe));
return true;
}
scoped_ptr<DesktopSession> DaemonProcessWin::DoCreateDesktopSession(
int terminal_id,
const ScreenResolution& resolution,
bool virtual_terminal) {
DCHECK(caller_task_runner()->BelongsToCurrentThread());
if (virtual_terminal) {
return DesktopSessionWin::CreateForVirtualTerminal(
caller_task_runner(), io_task_runner(), this, terminal_id, resolution);
} else {
return DesktopSessionWin::CreateForConsole(
caller_task_runner(), io_task_runner(), this, terminal_id, resolution);
}
}
void DaemonProcessWin::DoCrashNetworkProcess(
const tracked_objects::Location& location) {
DCHECK(caller_task_runner()->BelongsToCurrentThread());
network_launcher_->Crash(location);
}
void DaemonProcessWin::LaunchNetworkProcess() {
DCHECK(caller_task_runner()->BelongsToCurrentThread());
DCHECK(!network_launcher_);
base::FilePath host_binary;
if (!GetInstalledBinaryPath(kHostBinaryName, &host_binary)) {
Stop();
return;
}
scoped_ptr<CommandLine> target(new CommandLine(host_binary));
target->AppendSwitchASCII(kProcessTypeSwitchName, kProcessTypeHost);
target->CopySwitchesFrom(*CommandLine::ForCurrentProcess(),
kCopiedSwitchNames,
arraysize(kCopiedSwitchNames));
scoped_ptr<UnprivilegedProcessDelegate> delegate(
new UnprivilegedProcessDelegate(io_task_runner(), target.Pass()));
network_launcher_.reset(new WorkerProcessLauncher(delegate.Pass(), this));
}
scoped_ptr<DaemonProcess> DaemonProcess::Create(
scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
scoped_refptr<AutoThreadTaskRunner> io_task_runner,
const base::Closure& stopped_callback) {
scoped_ptr<DaemonProcessWin> daemon_process(
new DaemonProcessWin(caller_task_runner, io_task_runner,
stopped_callback));
daemon_process->Initialize();
return daemon_process.PassAs<DaemonProcess>();
}
void DaemonProcessWin::DisableAutoStart() {
ScopedScHandle scmanager(
OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE,
SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE));
if (!scmanager.IsValid()) {
LOG_GETLASTERROR(INFO)
<< "Failed to connect to the service control manager";
return;
}
DWORD desired_access = SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS;
ScopedScHandle service(
OpenService(scmanager, kWindowsServiceName, desired_access));
if (!service.IsValid()) {
LOG_GETLASTERROR(INFO)
<< "Failed to open to the '" << kWindowsServiceName << "' service";
return;
}
if (!ChangeServiceConfig(service,
SERVICE_NO_CHANGE,
SERVICE_DEMAND_START,
SERVICE_NO_CHANGE,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL)) {
LOG_GETLASTERROR(INFO)
<< "Failed to change the '" << kWindowsServiceName
<< "'service start type to 'manual'";
}
}
bool DaemonProcessWin::InitializePairingRegistry() {
if (!pairing_registry_privileged_key_.Valid()) {
if (!OpenPairingRegistry())
return false;
}
IPC::PlatformFileForTransit privileged_key = GetRegistryKeyForTransit(
network_process_, pairing_registry_privileged_key_);
IPC::PlatformFileForTransit unprivileged_key = GetRegistryKeyForTransit(
network_process_, pairing_registry_unprivileged_key_);
if (!(privileged_key && unprivileged_key))
return false;
SendToNetwork(new ChromotingDaemonNetworkMsg_InitializePairingRegistry(
privileged_key, unprivileged_key));
return true;
}
bool DaemonProcessWin::OpenPairingRegistry() {
DCHECK(!pairing_registry_privileged_key_.Valid());
DCHECK(!pairing_registry_unprivileged_key_.Valid());
base::win::RegKey root;
LONG result = root.Open(HKEY_LOCAL_MACHINE, kPairingRegistryKeyName,
KEY_READ);
if (result != ERROR_SUCCESS) {
SetLastError(result);
PLOG(ERROR) << "Failed to open HKLM\\" << kPairingRegistryKeyName;
return false;
}
base::win::RegKey privileged;
result = privileged.Open(root.Handle(), kPairingRegistryClientsKeyName,
KEY_READ | KEY_WRITE);
if (result != ERROR_SUCCESS) {
SetLastError(result);
PLOG(ERROR) << "Failed to open HKLM\\" << kPairingRegistryKeyName << "\\"
<< kPairingRegistryClientsKeyName;
return false;
}
base::win::RegKey unprivileged;
result = unprivileged.Open(root.Handle(), kPairingRegistrySecretsKeyName,
KEY_READ | KEY_WRITE);
if (result != ERROR_SUCCESS) {
SetLastError(result);
PLOG(ERROR) << "Failed to open HKLM\\" << kPairingRegistrySecretsKeyName
<< "\\" << kPairingRegistrySecretsKeyName;
return false;
}
pairing_registry_privileged_key_.Set(privileged.Take());
pairing_registry_unprivileged_key_.Set(unprivileged.Take());
return true;
}
}