// 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/win/host_service.h"

#include <sddl.h>
#include <windows.h>
#include <wtsapi32.h>

#include "base/base_paths.h"
#include "base/base_switches.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread.h"
#include "base/win/message_window.h"
#include "base/win/scoped_com_initializer.h"
#include "remoting/base/auto_thread.h"
#include "remoting/base/scoped_sc_handle_win.h"
#include "remoting/host/branding.h"
#include "remoting/host/daemon_process.h"
#include "remoting/host/host_exit_codes.h"
#include "remoting/host/logging.h"
#include "remoting/host/win/com_security.h"
#include "remoting/host/win/core_resource.h"
#include "remoting/host/win/wts_terminal_observer.h"

namespace remoting {

namespace {

const char kIoThreadName[] = "I/O thread";

// Command line switches:

// "--console" runs the service interactively for debugging purposes.
const char kConsoleSwitchName[] = "console";

// Security descriptor allowing local processes running under SYSTEM or
// LocalService accounts to call COM methods exposed by the daemon.
const wchar_t kComProcessSd[] =
    SDDL_OWNER L":" SDDL_LOCAL_SYSTEM
    SDDL_GROUP L":" SDDL_LOCAL_SYSTEM
    SDDL_DACL L":"
    SDDL_ACE(SDDL_ACCESS_ALLOWED, SDDL_COM_EXECUTE_LOCAL, SDDL_LOCAL_SYSTEM)
    SDDL_ACE(SDDL_ACCESS_ALLOWED, SDDL_COM_EXECUTE_LOCAL, SDDL_LOCAL_SERVICE);

// Appended to |kComProcessSd| to specify that only callers running at medium or
// higher integrity level are allowed to call COM methods exposed by the daemon.
const wchar_t kComProcessMandatoryLabel[] =
    SDDL_SACL L":"
    SDDL_ACE(SDDL_MANDATORY_LABEL, SDDL_NO_EXECUTE_UP, SDDL_ML_MEDIUM);

}  // namespace

HostService* HostService::GetInstance() {
  return Singleton<HostService>::get();
}

bool HostService::InitWithCommandLine(const base::CommandLine* command_line) {
  base::CommandLine::StringVector args = command_line->GetArgs();
  if (!args.empty()) {
    LOG(ERROR) << "No positional parameters expected.";
    return false;
  }

  // Run interactively if needed.
  if (run_routine_ == &HostService::RunAsService &&
      command_line->HasSwitch(kConsoleSwitchName)) {
    run_routine_ = &HostService::RunInConsole;
  }

  return true;
}

int HostService::Run() {
  return (this->*run_routine_)();
}

bool HostService::AddWtsTerminalObserver(const std::string& terminal_id,
                                         WtsTerminalObserver* observer) {
  DCHECK(main_task_runner_->BelongsToCurrentThread());

  RegisteredObserver registered_observer;
  registered_observer.terminal_id = terminal_id;
  registered_observer.session_id = kInvalidSessionId;
  registered_observer.observer = observer;

  bool session_id_found = false;
  std::list<RegisteredObserver>::const_iterator i;
  for (i = observers_.begin(); i != observers_.end(); ++i) {
    // Get the attached session ID from another observer watching the same WTS
    // console if any.
    if (i->terminal_id == terminal_id) {
      registered_observer.session_id = i->session_id;
      session_id_found = true;
    }

    // Check that |observer| hasn't been registered already.
    if (i->observer == observer)
      return false;
  }

  // If |terminal_id| is new, enumerate all sessions to see if there is one
  // attached to |terminal_id|.
  if (!session_id_found)
    registered_observer.session_id = LookupSessionId(terminal_id);

  observers_.push_back(registered_observer);

  if (registered_observer.session_id != kInvalidSessionId) {
    observer->OnSessionAttached(registered_observer.session_id);
  }

  return true;
}

void HostService::RemoveWtsTerminalObserver(WtsTerminalObserver* observer) {
  DCHECK(main_task_runner_->BelongsToCurrentThread());

  std::list<RegisteredObserver>::const_iterator i;
  for (i = observers_.begin(); i != observers_.end(); ++i) {
    if (i->observer == observer) {
      observers_.erase(i);
      return;
    }
  }
}

HostService::HostService() :
  run_routine_(&HostService::RunAsService),
  service_status_handle_(0),
  stopped_event_(true, false),
  weak_factory_(this) {
}

HostService::~HostService() {
}

void HostService::OnSessionChange(uint32 event, uint32 session_id) {
  DCHECK(main_task_runner_->BelongsToCurrentThread());
  DCHECK_NE(session_id, kInvalidSessionId);

  // Process only attach/detach notifications.
  if (event != WTS_CONSOLE_CONNECT && event != WTS_CONSOLE_DISCONNECT &&
      event != WTS_REMOTE_CONNECT && event != WTS_REMOTE_DISCONNECT) {
    return;
  }

  // Assuming that notification can arrive later query the current state of
  // |session_id|.
  std::string terminal_id;
  bool attached = LookupTerminalId(session_id, &terminal_id);

  std::list<RegisteredObserver>::iterator i = observers_.begin();
  while (i != observers_.end()) {
    std::list<RegisteredObserver>::iterator next = i;
    ++next;

    // Issue a detach notification if the session was detached from a client or
    // if it is now attached to a different client.
    if (i->session_id == session_id &&
        (!attached || !(i->terminal_id == terminal_id))) {
      i->session_id = kInvalidSessionId;
      i->observer->OnSessionDetached();
      i = next;
      continue;
    }

    // The client currently attached to |session_id| was attached to a different
    // session before. Reconnect it to |session_id|.
    if (attached && i->terminal_id == terminal_id &&
        i->session_id != session_id) {
      WtsTerminalObserver* observer = i->observer;

      if (i->session_id != kInvalidSessionId) {
        i->session_id = kInvalidSessionId;
        i->observer->OnSessionDetached();
      }

      // Verify that OnSessionDetached() above didn't remove |observer|
      // from the list.
      std::list<RegisteredObserver>::iterator j = next;
      --j;
      if (j->observer == observer) {
        j->session_id = session_id;
        observer->OnSessionAttached(session_id);
      }
    }

    i = next;
  }
}

void HostService::CreateLauncher(
    scoped_refptr<AutoThreadTaskRunner> task_runner) {
  // Launch the I/O thread.
  scoped_refptr<AutoThreadTaskRunner> io_task_runner =
      AutoThread::CreateWithType(
          kIoThreadName, task_runner, base::MessageLoop::TYPE_IO);
  if (!io_task_runner) {
    LOG(FATAL) << "Failed to start the I/O thread";
    return;
  }

  daemon_process_ = DaemonProcess::Create(
      task_runner,
      io_task_runner,
      base::Bind(&HostService::StopDaemonProcess, weak_ptr_));
}

int HostService::RunAsService() {
  SERVICE_TABLE_ENTRYW dispatch_table[] = {
    { const_cast<LPWSTR>(kWindowsServiceName), &HostService::ServiceMain },
    { NULL, NULL }
  };

  if (!StartServiceCtrlDispatcherW(dispatch_table)) {
    PLOG(ERROR) << "Failed to connect to the service control manager";
    return kInitializationFailed;
  }

  // Wait until the service thread completely exited to avoid concurrent
  // teardown of objects registered with base::AtExitManager and object
  // destoyed by the service thread.
  stopped_event_.Wait();

  return kSuccessExitCode;
}

void HostService::RunAsServiceImpl() {
  base::MessageLoopForUI message_loop;
  base::RunLoop run_loop;
  main_task_runner_ = message_loop.message_loop_proxy();
  weak_ptr_ = weak_factory_.GetWeakPtr();

  // Register the service control handler.
  service_status_handle_ = RegisterServiceCtrlHandlerExW(
      kWindowsServiceName, &HostService::ServiceControlHandler, this);
  if (service_status_handle_ == 0) {
    PLOG(ERROR) << "Failed to register the service control handler";
    return;
  }

  // Report running status of the service.
  SERVICE_STATUS service_status;
  ZeroMemory(&service_status, sizeof(service_status));
  service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  service_status.dwCurrentState = SERVICE_RUNNING;
  service_status.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN |
                                      SERVICE_ACCEPT_STOP |
                                      SERVICE_ACCEPT_SESSIONCHANGE;
  service_status.dwWin32ExitCode = kSuccessExitCode;
  if (!SetServiceStatus(service_status_handle_, &service_status)) {
    PLOG(ERROR)
        << "Failed to report service status to the service control manager";
    return;
  }

  // Initialize COM.
  base::win::ScopedCOMInitializer com_initializer;
  if (!com_initializer.succeeded())
    return;

  if (!InitializeComSecurity(base::WideToUTF8(kComProcessSd),
                             base::WideToUTF8(kComProcessMandatoryLabel),
                             false)) {
    return;
  }

  CreateLauncher(scoped_refptr<AutoThreadTaskRunner>(
      new AutoThreadTaskRunner(main_task_runner_,
                               run_loop.QuitClosure())));

  // Run the service.
  run_loop.Run();
  weak_factory_.InvalidateWeakPtrs();

  // Tell SCM that the service is stopped.
  service_status.dwCurrentState = SERVICE_STOPPED;
  service_status.dwControlsAccepted = 0;
  if (!SetServiceStatus(service_status_handle_, &service_status)) {
    PLOG(ERROR)
        << "Failed to report service status to the service control manager";
    return;
  }
}

int HostService::RunInConsole() {
  base::MessageLoopForUI message_loop;
  base::RunLoop run_loop;
  main_task_runner_ = message_loop.message_loop_proxy();
  weak_ptr_ = weak_factory_.GetWeakPtr();

  int result = kInitializationFailed;

  // Initialize COM.
  base::win::ScopedCOMInitializer com_initializer;
  if (!com_initializer.succeeded())
    return result;

  if (!InitializeComSecurity(base::WideToUTF8(kComProcessSd),
                             base::WideToUTF8(kComProcessMandatoryLabel),
                             false)) {
    return result;
  }

  // Subscribe to Ctrl-C and other console events.
  if (!SetConsoleCtrlHandler(&HostService::ConsoleControlHandler, TRUE)) {
    PLOG(ERROR) << "Failed to set console control handler";
    return result;
  }

  // Create a window for receiving session change notifications.
  base::win::MessageWindow window;
  if (!window.Create(base::Bind(&HostService::HandleMessage,
                                base::Unretained(this)))) {
    PLOG(ERROR) << "Failed to create the session notification window";
    goto cleanup;
  }

  // Subscribe to session change notifications.
  if (WTSRegisterSessionNotification(window.hwnd(),
                                     NOTIFY_FOR_ALL_SESSIONS) != FALSE) {
    CreateLauncher(scoped_refptr<AutoThreadTaskRunner>(
        new AutoThreadTaskRunner(main_task_runner_,
                                 run_loop.QuitClosure())));

    // Run the service.
    run_loop.Run();

    // Release the control handler.
    stopped_event_.Signal();

    WTSUnRegisterSessionNotification(window.hwnd());
    result = kSuccessExitCode;
  }

cleanup:
  weak_factory_.InvalidateWeakPtrs();

  // Unsubscribe from console events. Ignore the exit code. There is nothing
  // we can do about it now and the program is about to exit anyway. Even if
  // it crashes nothing is going to be broken because of it.
  SetConsoleCtrlHandler(&HostService::ConsoleControlHandler, FALSE);

  return result;
}

void HostService::StopDaemonProcess() {
  DCHECK(main_task_runner_->BelongsToCurrentThread());

  daemon_process_.reset();
}

bool HostService::HandleMessage(
    UINT message, WPARAM wparam, LPARAM lparam, LRESULT* result) {
  if (message == WM_WTSSESSION_CHANGE) {
    OnSessionChange(wparam, lparam);
    *result = 0;
    return true;
  }

  return false;
}

// static
BOOL WINAPI HostService::ConsoleControlHandler(DWORD event) {
  HostService* self = HostService::GetInstance();
  switch (event) {
    case CTRL_C_EVENT:
    case CTRL_BREAK_EVENT:
    case CTRL_CLOSE_EVENT:
    case CTRL_LOGOFF_EVENT:
    case CTRL_SHUTDOWN_EVENT:
      self->main_task_runner_->PostTask(
          FROM_HERE, base::Bind(&HostService::StopDaemonProcess,
                                self->weak_ptr_));
      return TRUE;

    default:
      return FALSE;
  }
}

// static
DWORD WINAPI HostService::ServiceControlHandler(DWORD control,
                                                DWORD event_type,
                                                LPVOID event_data,
                                                LPVOID context) {
  HostService* self = reinterpret_cast<HostService*>(context);
  switch (control) {
    case SERVICE_CONTROL_INTERROGATE:
      return NO_ERROR;

    case SERVICE_CONTROL_SHUTDOWN:
    case SERVICE_CONTROL_STOP:
      self->main_task_runner_->PostTask(
          FROM_HERE, base::Bind(&HostService::StopDaemonProcess,
                                self->weak_ptr_));
      return NO_ERROR;

    case SERVICE_CONTROL_SESSIONCHANGE:
      self->main_task_runner_->PostTask(FROM_HERE, base::Bind(
          &HostService::OnSessionChange, self->weak_ptr_, event_type,
          reinterpret_cast<WTSSESSION_NOTIFICATION*>(event_data)->dwSessionId));
      return NO_ERROR;

    default:
      return ERROR_CALL_NOT_IMPLEMENTED;
  }
}

// static
VOID WINAPI HostService::ServiceMain(DWORD argc, WCHAR* argv[]) {
  HostService* self = HostService::GetInstance();

  // Run the service.
  self->RunAsServiceImpl();

  // Release the control handler and notify the main thread that it can exit
  // now.
  self->stopped_event_.Signal();
}

int DaemonProcessMain() {
  HostService* service = HostService::GetInstance();
  if (!service->InitWithCommandLine(base::CommandLine::ForCurrentProcess())) {
    return kUsageExitCode;
  }

  return service->Run();
}

}  // namespace remoting
