// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "vm_tools/seneschal/service.h"

#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <limits.h>
#include <mntent.h>
#include <signal.h>
#include <stdint.h>
#include <sys/mount.h>
#include <sys/signalfd.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>

#include <linux/vm_sockets.h>  // needs to come after sys/socket.h

#include <algorithm>
#include <string>
#include <utility>
#include <vector>

#include <base/bind.h>
#include <base/bind_helpers.h>
#include <base/files/file_enumerator.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/location.h>
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_piece.h>
#include <base/strings/string_split.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
#include <base/threading/thread_task_runner_handle.h>
#include <base/time/time.h>
#include <chromeos/dbus/service_constants.h>
#include <chromeos/scoped_minijail.h>
#include <seneschal/proto_bindings/seneschal_service.pb.h>

using std::string;

namespace vm_tools {
namespace seneschal {
namespace {
// Path to the runtime directory where we will create server jails.
constexpr char kRuntimeDir[] = "/run/seneschal";

// The chronos uid and gid.  These are used for file system access.
constexpr uid_t kChronosUid = 1000;
constexpr gid_t kChronosGid = 1000;

// Access to android files requires android-everybody gid.
constexpr gid_t kAndroidEverybodyGid = 665357;
constexpr gid_t kSupplementaryGroups[] = {kAndroidEverybodyGid};

// The gid of the chronos-access group.
constexpr gid_t kChronosAccessGid = 1001;

// The uid used for authenticating with DBus.
constexpr uid_t kDbusAuthUid = 20115;

// The crosvm uid and gid.
constexpr uid_t kCrosvmUid = 299;
constexpr gid_t kCrosvmGid = 299;

// Gids on the 9P server side that should be mapped to crosvm on the
// client side so that crosvm can access the shared data.
constexpr gid_t k9pMappedGids[] = {
    kChronosGid,
    kChronosAccessGid,
    kAndroidEverybodyGid,
};

// How long we should wait for a server process to exit.
constexpr base::TimeDelta kServerExitTimeout = base::TimeDelta::FromSeconds(2);

// Path to the 9p server.
constexpr char kServerPath[] = "/usr/bin/9s";
constexpr char kServerRoot[] = "/fsroot";
constexpr char kSeccompPolicyPath[] = "/usr/share/policy/9s-seccomp.policy";

// `mkdir -p`, essentially.  Reimplement all of base::CreateDirectory because
// we want mode 0755 instead of mode 0700.
bool MkdirRecursively(const base::FilePath& full_path) {
  if (!full_path.IsAbsolute()) {
    LOG(INFO) << "Relative paths are not supported: " << full_path.value();
    return false;
  }

  // Collect a list of all parent directories.
  std::vector<std::string> components;
  full_path.GetComponents(&components);
  DCHECK(!components.empty());

  base::ScopedFD fd(open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW));
  if (!fd.is_valid())
    return false;

  // Iterate through the parents and create the missing ones. '+ 1' is for
  // skipping "/".
  for (std::vector<std::string>::const_iterator i = components.begin() + 1;
       i != components.end(); ++i) {
    // Try to create the directory. Note that Chromium's MkdirRecursively() uses
    // 0700, but we use 0755.
    if (mkdirat(fd.get(), i->c_str(), 0755) != 0) {
      if (errno != EEXIST) {
        PLOG(ERROR) << "Failed to mkdirat " << *i
                    << ": full_path=" << full_path.value();
        return false;
      }

      // The path already exists. Make sure that the path is a directory.
      struct stat st;
      if (fstatat(fd.get(), i->c_str(), &st, AT_SYMLINK_NOFOLLOW) != 0) {
        PLOG(ERROR) << "Failed to fstatat " << *i
                    << ": full_path=" << full_path.value();
        return false;
      }
      if (!S_ISDIR(st.st_mode)) {
        LOG(ERROR) << *i << " is not a directory: st_mode=" << st.st_mode
                   << ", full_path=" << full_path.value();
        return false;
      }
    }

    // Updates the FD so it refers to the new directory created or checked
    // above.
    const int new_fd =
        openat(fd.get(), i->c_str(), O_RDONLY | O_NOFOLLOW | O_NONBLOCK, 0);
    if (new_fd < 0) {
      PLOG(ERROR) << "Failed to openat " << *i
                  << ": full_path=" << full_path.value();
      return false;
    }
    fd.reset(new_fd);
    continue;
  }
  return true;
}

// Passes |method_call| to |handler| and passes the response to
// |response_sender|. If |handler| returns NULL, an empty response is created
// and sent.
void HandleSynchronousDBusMethodCall(
    base::Callback<std::unique_ptr<dbus::Response>(dbus::MethodCall*)> handler,
    dbus::MethodCall* method_call,
    dbus::ExportedObject::ResponseSender response_sender) {
  std::unique_ptr<dbus::Response> response = handler.Run(method_call);
  if (!response)
    response = dbus::Response::FromMethodCall(method_call);
  response_sender.Run(std::move(response));
}

}  // namespace

Service::ServerInfo::ServerInfo(pid_t pid, base::FilePath root_dir)
    : pid_(pid) {
  CHECK(root_dir_.Set(root_dir));
}

Service::ServerInfo::ServerInfo(Service::ServerInfo&& other)
    : pid_(other.pid_) {
  CHECK(root_dir_.Set(other.root_dir_.Take()));
}

Service::ServerInfo& Service::ServerInfo::operator=(
    Service::ServerInfo&& other) {
  // Self assignment check is required.
  if (this != &other) {
    pid_ = other.pid_;
    CHECK(root_dir_.Set(other.root_dir_.Take()));
  }

  return *this;
}

Service::ServerInfo::~ServerInfo() {
  if (!root_dir_.IsValid()) {
    // Nothing to see here.
    return;
  }

  // Clean up the mounts so that we can delete the temporary directory.  An
  // error in any of these operations means that we cannot safely delete the
  // directory.  Instead the directory will get cleaned up when seneschal exits
  // as this will delete the mount namespace and all the mounts in it.
  string contents;
  if (!base::ReadFileToString(base::FilePath("/proc/self/mounts"), &contents)) {
    PLOG(ERROR) << "Unable to read contents of /proc/self/mounts; not deleting "
                << "runtime directory";
    root_dir_.Take();
    return;
  }

  std::vector<string> mounts;
  for (base::StringPiece line : base::SplitStringPiece(
           contents, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
    std::vector<base::StringPiece> mount_data = base::SplitStringPiece(
        line, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
    if (mount_data.size() < 6) {
      LOG(ERROR) << "Invalid mount data: " << line;
      root_dir_.Take();
      return;
    }

    // The mount point is the second column.
    if (root_dir_.GetPath().IsParent(base::FilePath(mount_data[1]))) {
      mounts.emplace_back(mount_data[1].as_string());
    }
  }

  // Now unmount everything in reverse order.
  for (auto iter = mounts.rbegin(), end = mounts.rend(); iter != end; ++iter) {
    if (umount(iter->c_str()) != 0) {
      PLOG(ERROR) << "Unable to unmount path; not deleting runtime directory";
      root_dir_.Take();
      return;
    }
  }
}

// static
std::unique_ptr<Service> Service::Create(base::Closure quit_closure) {
  std::unique_ptr<Service> service(new Service(std::move(quit_closure)));

  if (!service->Init()) {
    service.reset();
  }

  return service;
}

Service::Service(base::Closure quit_closure)
    : next_server_handle_(1),
      watcher_(FROM_HERE),
      quit_closure_(std::move(quit_closure)),
      weak_factory_(this) {}

bool Service::Init() {
  // Set up the dbus service.
  dbus::Bus::Options opts;
  opts.bus_type = dbus::Bus::SYSTEM;
  bus_ = new dbus::Bus(std::move(opts));

  // When authenticating with DBus a client process that wants to connect to
  // the system dbus daemon sends an authentication request with its current
  // effective uid.  The dbus daemon then uses SO_PEERCRED to verify that the
  // uid of the client process matches what it claims to be.  Normally this is
  // fine but when the client process runs inside a user namespace it thinks it
  // has uid 0 inside the namespace while the dbus daemon, which runs outside
  // the namespace, thinks it has some other uid.  To deal with this we
  // temprarily change our effective uid to match the effective uid outside the
  // user namespace and then change it back once we have authenticated with the
  // dbus daemon.
  if (seteuid(kDbusAuthUid) != 0) {
    PLOG(ERROR) << "Unable to change effective uid to " << kDbusAuthUid;
    return false;
  }

  if (!bus_->Connect()) {
    LOG(ERROR) << "Failed to connect to system bus";
    return false;
  }

  if (seteuid(0) != 0) {
    PLOG(ERROR) << "Unable to change effective uid back to 0";
    return false;
  }

  // Add chronos-access to our list of supplementary groups.  This is needed so
  // that we can access the user's files in the /home directory.
  gid_t list[NGROUPS_MAX] = {};
  int count = getgroups(NGROUPS_MAX, list);
  if (count < 0) {
    PLOG(ERROR) << "Failed to get supplementary groups";
    return false;
  }
  CHECK_LT(count, NGROUPS_MAX);

  list[count++] = kChronosAccessGid;
  if (setgroups(count, list) != 0) {
    PLOG(ERROR) << "Failed to add chronos-access to supplementary groups";
    return false;
  }

  exported_object_ =
      bus_->GetExportedObject(dbus::ObjectPath(kSeneschalServicePath));
  if (!exported_object_) {
    LOG(ERROR) << "Failed to export " << kSeneschalServicePath << " object";
    return false;
  }

  using ServiceMethod =
      std::unique_ptr<dbus::Response> (Service::*)(dbus::MethodCall*);
  const std::map<const char*, ServiceMethod> kServiceMethods = {
      {kStartServerMethod, &Service::StartServer},
      {kStopServerMethod, &Service::StopServer},
      {kSharePathMethod, &Service::SharePath},
      {kUnsharePathMethod, &Service::UnsharePath},
  };

  for (const auto& iter : kServiceMethods) {
    bool ret = exported_object_->ExportMethodAndBlock(
        kSeneschalInterface, iter.first,
        base::Bind(&HandleSynchronousDBusMethodCall,
                   base::Bind(iter.second, base::Unretained(this))));
    if (!ret) {
      LOG(ERROR) << "Failed to export method " << iter.first;
      return false;
    }
  }

  if (!bus_->RequestOwnershipAndBlock(kSeneschalServiceName,
                                      dbus::Bus::REQUIRE_PRIMARY)) {
    LOG(ERROR) << "Failed to take ownership of " << kSeneschalServiceName;
    return false;
  }

  // Set up the signalfd for receiving SIGCHLD and SIGTERM.
  sigset_t mask;
  sigemptyset(&mask);
  sigaddset(&mask, SIGCHLD);
  sigaddset(&mask, SIGTERM);

  signal_fd_.reset(signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC));
  if (!signal_fd_.is_valid()) {
    PLOG(ERROR) << "Failed to create signalfd";
    return false;
  }

  bool ret = base::MessageLoopForIO::current()->WatchFileDescriptor(
      signal_fd_.get(), true /*persistent*/, base::MessageLoopForIO::WATCH_READ,
      &watcher_, this);
  if (!ret) {
    LOG(ERROR) << "Failed to watch signalfd";
    return false;
  }

  // Now block signals from the normal signal handling path so that we will get
  // them via the signalfd.
  if (sigprocmask(SIG_BLOCK, &mask, nullptr) < 0) {
    PLOG(ERROR) << "Failed to block signals via sigprocmask";
    return false;
  }

  return true;
}

void Service::OnFileCanReadWithoutBlocking(int fd) {
  DCHECK_EQ(signal_fd_.get(), fd);

  struct signalfd_siginfo siginfo;
  if (read(signal_fd_.get(), &siginfo, sizeof(siginfo)) != sizeof(siginfo)) {
    PLOG(ERROR) << "Failed to read from signalfd";
    return;
  }

  if (siginfo.ssi_signo == SIGCHLD) {
    HandleChildExit();
  } else if (siginfo.ssi_signo == SIGTERM) {
    HandleSigterm();
  } else {
    LOG(ERROR) << "Received unknown signal from signal fd: "
               << strsignal(siginfo.ssi_signo);
  }
}

void Service::OnFileCanWriteWithoutBlocking(int fd) {
  NOTREACHED();
}

void Service::HandleChildExit() {
  // We can't just rely on the information in the siginfo structure because
  // more than one child may have exited but only one SIGCHLD will be
  // generated.
  while (true) {
    int status;
    pid_t pid = waitpid(-1, &status, WNOHANG);
    if (pid <= 0) {
      if (pid == -1 && errno != ECHILD) {
        PLOG(ERROR) << "Unable to reap child processes";
      }
      break;
    }

    if (WIFEXITED(status)) {
      LOG(INFO) << "Process " << pid << " exited with status "
                << WEXITSTATUS(status);
    } else if (WIFSIGNALED(status)) {
      LOG(INFO) << "Process " << pid << " killed by signal " << WTERMSIG(status)
                << (WCOREDUMP(status) ? " (core dumped)" : "");
    } else {
      LOG(WARNING) << "Unknown exit status " << status << " for process "
                   << pid;
    }

    // See if this is a process we launched.
    for (const auto& pair : servers_) {
      if (pid == pair.second.pid()) {
        servers_.erase(pair.first);
        break;
      }
    }
  }
}

void Service::HandleSigterm() {
  LOG(INFO) << "Shutting down due to SIGTERM";

  // Close our connection to the bus.
  bus_->ShutdownAndBlock();

  // Stop the message loop.
  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure_);
}

// Handles a request to start a new 9p server.
std::unique_ptr<dbus::Response> Service::StartServer(
    dbus::MethodCall* method_call) {
  LOG(INFO) << "Received request to start new 9p server";

  std::unique_ptr<dbus::Response> dbus_response(
      dbus::Response::FromMethodCall(method_call));

  dbus::MessageReader reader(method_call);
  dbus::MessageWriter writer(dbus_response.get());

  StartServerRequest request;
  StartServerResponse response;

  if (!reader.PopArrayOfBytesAsProto(&request)) {
    LOG(ERROR) << "Unable to parse StartServerRequest from message";
    response.set_failure_reason("Unable to parse protobuf");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  base::ScopedTempDir root_dir;
  if (!root_dir.CreateUniqueTempDirUnderPath(base::FilePath(kRuntimeDir))) {
    LOG(ERROR) << "Unable to create working dir for server";
    response.set_failure_reason("Unable to create working dir for server");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // Make sure the child process has permission to read the contents.
  if (chmod(root_dir.GetPath().value().c_str(), 0755) != 0) {
    PLOG(ERROR) << "Failed to change permissions for "
                << root_dir.GetPath().value();
    response.set_failure_reason(
        "Failed to change permissions for server's working dir");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // Create the directory that the server will serve to clients.  Offset the
  // root path by 1 because Append wants relative paths.
  base::FilePath client_root = root_dir.GetPath().Append(&kServerRoot[1]);
  if (mkdir(client_root.value().c_str(), 0755) != 0) {
    PLOG(ERROR) << "Unable to create server root dir";
    response.set_failure_reason("Unable to create server root dir");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // Get the listening address and any extra command line options.
  std::vector<string> args = {kServerPath, "-r", kServerRoot};
  base::ScopedFD listen_fd;
  bool valid_address = false;
  switch (request.listen_address_case()) {
    case StartServerRequest::kVsock: {
      const VsockAddress& addr = request.vsock();
      if (addr.accept_cid() < 3) {
        LOG(ERROR) << "Missing or invalid accept_cid field in vsock address: "
                   << addr.accept_cid();
        break;
      }

      args.emplace_back("--accept_cid");
      args.emplace_back(std::to_string(addr.accept_cid()));
      args.emplace_back(string("vsock:") + std::to_string(addr.port()));
      valid_address = true;
      break;
    }
    case StartServerRequest::kFd: {
      if (!reader.PopFileDescriptor(&listen_fd)) {
        LOG(ERROR) << "No fd found in incoming message";
        break;
      }

      // Clear close-on-exec as this FD needs to be passed to 9s.
      int flags = fcntl(listen_fd.get(), F_GETFD);
      if (flags == -1) {
        PLOG(ERROR) << "Failed to get flags for passed fd";
        break;
      }
      if (fcntl(listen_fd.get(), F_SETFD, flags & ~FD_CLOEXEC) == -1) {
        PLOG(ERROR) << "Failed to clear close-on-exec flag for fd";
        break;
      }

      args.emplace_back(base::StringPrintf("unix-fd:%d", listen_fd.get()));

      args.emplace_back("--uid_map");
      args.emplace_back(base::StringPrintf("%u:%u", kChronosUid, kCrosvmUid));

      for (auto gid : k9pMappedGids) {
        args.emplace_back("--gid_map");
        args.emplace_back(base::StringPrintf("%u:%u", gid, kCrosvmGid));
      }

      valid_address = true;
      break;
    }
    case StartServerRequest::kUnixAddr:
    case StartServerRequest::kNet:
      LOG(ERROR) << "Listen address not implemented: "
                 << request.listen_address_case();
      break;
    case StartServerRequest::LISTEN_ADDRESS_NOT_SET:
      LOG(ERROR) << "Listen address not set";
    default:
      LOG(ERROR) << "Unknown listen address: " << request.listen_address_case();
      break;
  }

  if (!valid_address) {
    LOG(ERROR) << "Unable to create listening address";
    response.set_failure_reason("Unable to create listening address");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  std::vector<const char*> argv(args.size());
  std::transform(args.begin(), args.end(), argv.begin(),
                 [](const string& arg) -> const char* { return arg.c_str(); });
  argv.emplace_back(nullptr);

  // Mount in some useful paths.  We cannot use minijail_bind here because that
  // implicitly enters a new mount namespace and we explicitly want the child
  // process to live in seneschal's mount namespace.
  constexpr struct {
    const char* src;
    bool writable;
  } bind_mounts[] = {
      {
          .src = "/proc",
          .writable = false,
      },
      {
          .src = "/dev/null",
          .writable = true,
      },
      {
          .src = "/dev/log",
          .writable = true,
      },
  };
  for (const auto& bind_mount : bind_mounts) {
    // Offset by 1 because Append wants relative paths.
    base::FilePath dst = root_dir.GetPath().Append(&bind_mount.src[1]);
    struct stat info;
    if (stat(bind_mount.src, &info) != 0) {
      PLOG(ERROR) << "Unable to stat " << bind_mount.src;
      response.set_failure_reason("Unable to set up server jail");
      writer.AppendProtoAsArrayOfBytes(response);
      return dbus_response;
    }

    if (S_ISDIR(info.st_mode)) {
      // Only need to create the directory.
      if (!MkdirRecursively(dst)) {
        PLOG(ERROR) << "Failed to create " << dst.value();
        response.set_failure_reason("Unable to set up server jail");
        writer.AppendProtoAsArrayOfBytes(response);
        return dbus_response;
      }
    } else {
      // Need to create the file and the parent directories.
      if (!MkdirRecursively(dst.DirName())) {
        PLOG(ERROR) << "Failed to create " << dst.DirName().value();
        response.set_failure_reason("Unable to set up server jail");
        writer.AppendProtoAsArrayOfBytes(response);
        return dbus_response;
      }

      // Now touch the file so we can mount over it.
      base::ScopedFD file(open(dst.value().c_str(),
                               O_WRONLY | O_CREAT | O_CLOEXEC | O_NONBLOCK,
                               0600) != 0);
      if (!file.is_valid()) {
        PLOG(ERROR) << "Unable to touch " << dst.value();
        response.set_failure_reason("Unable to set up server jail");
        writer.AppendProtoAsArrayOfBytes(response);
        return dbus_response;
      }
    }

    // Now actually do the bind mount.
    unsigned long flags = MS_BIND | MS_REC;  // NOLINT(runtime/int)
    const char* target = dst.value().c_str();
    if (mount(bind_mount.src, target, "none", flags, nullptr) != 0) {
      PLOG(ERROR) << "Unable to bind mount " << bind_mount.src;
      response.set_failure_reason("Unable to set up server jail");
      writer.AppendProtoAsArrayOfBytes(response);
      return dbus_response;
    }

    // Remount read-only if necessary.
    if (!bind_mount.writable) {
      flags |= MS_REMOUNT | MS_RDONLY | MS_NOSUID | MS_NODEV | MS_NOEXEC;
      if (mount(bind_mount.src, target, "none", flags, nullptr) != 0) {
        PLOG(ERROR) << "Unable to remount " << bind_mount.src << " read-only";
        response.set_failure_reason("Unable to set up server jail");
        writer.AppendProtoAsArrayOfBytes(response);
        return dbus_response;
      }
    }
  }

  ScopedMinijail jail(minijail_new());
  if (!jail) {
    LOG(ERROR) << "Unable to create minijail";
    response.set_failure_reason("Unable to create minijail");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // Add android-everybody for access to android files.
  minijail_set_supplementary_gids(jail.get(), arraysize(kSupplementaryGroups),
                                  kSupplementaryGroups);
  // We want this process to share namespaces with its parent.
  minijail_change_uid(jail.get(), kChronosUid);
  minijail_change_gid(jail.get(), kChronosGid);

  // The process can only see what is in its root directory.
  int ret =
      minijail_enter_chroot(jail.get(), root_dir.GetPath().value().c_str());
  if (ret < 0) {
    LOG(ERROR) << "Unable to configure pivot_root: " << strerror(-ret);
    response.set_failure_reason("Unable to configure pivot_root");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // We will manage this process's lifetime.
  minijail_run_as_init(jail.get());

  // It doesn't need any caps or any new privileges.
  minijail_use_caps(jail.get(), 0);
  minijail_no_new_privs(jail.get());

  // Use a seccomp filter.
  minijail_log_seccomp_filter_failures(jail.get());
  minijail_parse_seccomp_filters(jail.get(), kSeccompPolicyPath);
  minijail_use_seccomp_filter(jail.get());

  // Reset the signal mask since we block SIGCHLD and SIGTERM in this process
  // for signalfd.
  minijail_reset_signal_mask(jail.get());
  minijail_reset_signal_handlers(jail.get());

  // Launch the server.
  pid_t child_pid = 0;
  ret = minijail_run_pid(jail.get(), kServerPath,
                         const_cast<char* const*>(argv.data()), &child_pid);
  if (ret < 0) {
    LOG(ERROR) << "Unable to spawn server process: " << strerror(-ret);
    response.set_failure_reason("Unable to spawn server");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // We're done.
  LOG(INFO) << "Started server on " << root_dir.GetPath().value();

  uint32_t handle = next_server_handle_++;
  servers_.emplace(handle, ServerInfo(child_pid, root_dir.Take()));

  response.set_success(true);
  response.set_handle(handle);
  writer.AppendProtoAsArrayOfBytes(response);
  return dbus_response;
}

// Handles a request to stop a running 9p server.
std::unique_ptr<dbus::Response> Service::StopServer(
    dbus::MethodCall* method_call) {
  LOG(INFO) << "Received request to stop server";

  std::unique_ptr<dbus::Response> dbus_response(
      dbus::Response::FromMethodCall(method_call));

  dbus::MessageReader reader(method_call);
  dbus::MessageWriter writer(dbus_response.get());

  StopServerRequest request;
  StopServerResponse response;

  if (!reader.PopArrayOfBytesAsProto(&request)) {
    LOG(ERROR) << "Unable to parse StopServerRequest from message";
    response.set_failure_reason("Unable to parse protobuf");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  const auto& iter = servers_.find(request.handle());
  if (iter == servers_.end()) {
    // The server is gone.  Nothing left to do here.
    response.set_success(true);
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // Otherwise we send the process a SIGTERM and report success while lazily
  // ensuring the server will exit.  This works because we don't reuse handles
  // (unless we somehow spawn ~4 billion servers in ~2 seconds).
  if (kill(iter->second.pid(), SIGTERM) != 0 && errno != ESRCH) {
    PLOG(ERROR) << "Unable to send SIGTERM to child process";
    response.set_failure_reason("Unable to send signal to child process");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
      FROM_HERE,
      base::Bind(&Service::KillServer, weak_factory_.GetWeakPtr(),
                 request.handle()),
      kServerExitTimeout);

  response.set_success(true);
  writer.AppendProtoAsArrayOfBytes(response);
  return dbus_response;
}

// Handles a request to share a path with a running server.
std::unique_ptr<dbus::Response> Service::SharePath(
    dbus::MethodCall* method_call) {
  LOG(INFO) << "Received request to share path with server";

  std::unique_ptr<dbus::Response> dbus_response(
      dbus::Response::FromMethodCall(method_call));

  dbus::MessageReader reader(method_call);
  dbus::MessageWriter writer(dbus_response.get());

  SharePathRequest request;
  SharePathResponse response;

  if (!reader.PopArrayOfBytesAsProto(&request)) {
    LOG(ERROR) << "Unable to parse SharePathRequest from message";
    response.set_failure_reason("Unable to parse protobuf");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  const auto& iter = servers_.find(request.handle());
  if (iter == servers_.end()) {
    LOG(ERROR) << "Requested server does not exist";
    response.set_failure_reason("Requested server does not exist");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // Validate path.
  base::FilePath path(request.shared_path().path());
  if (path.IsAbsolute() || path.ReferencesParent() ||
      path.BaseName().value() == ".") {
    LOG(ERROR) << "Requested path references parent, is absolute, or ends "
               << "with ./";
    response.set_failure_reason(
        "Path must be relative and cannot reference parent components nor end "
        "with \".\"");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // Validate owner_id.
  base::FilePath owner_id(request.owner_id());
  bool owner_id_required =
      request.storage_location() == SharePathRequest::DOWNLOADS ||
      request.storage_location() == SharePathRequest::MY_FILES;
  if (owner_id.ReferencesParent() || owner_id.BaseName() != owner_id ||
      (owner_id_required && owner_id.value().size() == 0)) {
    LOG(ERROR) << "owner_id references parent, or is "
                  "more than 1 component, or is required and not populated";
    response.set_failure_reason("owner_id must be a single valid component");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // Validate drivefs_mount_name.
  base::FilePath drivefs_mount_name(request.drivefs_mount_name());
  bool drivefs_mount_name_required =
      request.storage_location() == SharePathRequest::DRIVEFS_MY_DRIVE ||
      request.storage_location() == SharePathRequest::DRIVEFS_TEAM_DRIVES ||
      request.storage_location() == SharePathRequest::DRIVEFS_COMPUTERS;
  if (drivefs_mount_name.ReferencesParent() ||
      drivefs_mount_name.BaseName() != drivefs_mount_name ||
      (drivefs_mount_name_required &&
       !base::StartsWith(drivefs_mount_name.value(), "drivefs-",
                         base::CompareCase::SENSITIVE))) {
    LOG(ERROR) << "drivefs_mount_name references parent, or is "
                  "more than 1 component, or is required and not populated";
    response.set_failure_reason(
        "drivefs_mount_name must be a single valid component");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // Build the source and destination directories.
  base::FilePath src;
  base::FilePath dst =
      iter->second.root_dir().GetPath().Append(&kServerRoot[1]);

  // Used later to strip out the prefix from the destination so that we return
  // the relative path to the shared target.
  const size_t prefix_len = dst.value().size() + 1;

  switch (request.storage_location()) {
    case SharePathRequest::DOWNLOADS:
      src = base::FilePath("/home/user/").Append(owner_id).Append("Downloads");
      dst = dst.Append("MyFiles").Append("Downloads");
      break;
    case SharePathRequest::DRIVEFS_MY_DRIVE:
      src = base::FilePath("/media/fuse/")
                .Append(drivefs_mount_name)
                .Append("root");
      dst = dst.Append("GoogleDrive").Append("MyDrive");
      break;
    case SharePathRequest::DRIVEFS_TEAM_DRIVES:
      src = base::FilePath("/media/fuse/")
                .Append(drivefs_mount_name)
                .Append("team_drives");
      dst = dst.Append("GoogleDrive").Append("SharedDrives");
      break;
    case SharePathRequest::DRIVEFS_COMPUTERS:
      src = base::FilePath("/media/fuse/")
                .Append(drivefs_mount_name)
                .Append("Computers");
      dst = dst.Append("GoogleDrive").Append("Computers");
      break;
    // Note: DriveFs .Trash directory must not ever be shared since it would
    // allow linux apps to make permanent deletes to Drive.
    case SharePathRequest::REMOVABLE:
      src = base::FilePath("/media/removable");
      dst = dst.Append("removable");
      break;
    case SharePathRequest::MY_FILES:
      src = base::FilePath("/home/user/").Append(owner_id).Append("MyFiles");
      dst = dst.Append("MyFiles");
      break;
    case SharePathRequest::PLAY_FILES:
      src = base::FilePath("/run/arc/sdcard/write/emulated/0");
      dst = dst.Append("PlayFiles");
      break;
    default:
      LOG(ERROR) << "Unknown storage location: " << request.storage_location();
      response.set_failure_reason("Unknown storage location");
      writer.AppendProtoAsArrayOfBytes(response);
      return dbus_response;
  }

  // Get the remaining path.

  src = src.Append(path);
  if (!base::PathExists(src)) {
    LOG(ERROR) << "Requested path does not exist";
    response.set_failure_reason("Requested path does not exist");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  dst = dst.Append(path);
  // The destination directory may already exist either because one of its
  // children was shared and it was automatically created or one of its parents
  // was shared and it's already visible.
  if (!base::PathExists(dst)) {
    // First create everything up to the basename.
    if (!MkdirRecursively(dst.DirName())) {
      response.set_failure_reason(
          "Failed to create parent directory for destination");
      writer.AppendProtoAsArrayOfBytes(response);
      return dbus_response;
    }

    // Then create a file or directory, as necessary.
    struct stat info;
    if (stat(src.value().c_str(), &info) != 0) {
      PLOG(ERROR) << "Unable to stat source path";
      response.set_failure_reason("Unable to stat source path");
      writer.AppendProtoAsArrayOfBytes(response);
      return dbus_response;
    }

    if (S_ISDIR(info.st_mode)) {
      if (mkdir(dst.value().c_str(), 0700) != 0 && errno != EEXIST) {
        PLOG(ERROR) << "Unable to create destination directory";
        response.set_failure_reason("Unable to create destination directory");
        writer.AppendProtoAsArrayOfBytes(response);
        return dbus_response;
      }
    } else {
      base::ScopedFD file(open(dst.value().c_str(),
                               O_WRONLY | O_CREAT | O_CLOEXEC | O_NONBLOCK,
                               0600) != 0);
      if (!file.is_valid()) {
        PLOG(ERROR) << "Unable to create destination file";
        response.set_failure_reason("Unable to create destination file");
        writer.AppendProtoAsArrayOfBytes(response);
        return dbus_response;
      }
    }
  }

  // Do the mount.
  unsigned long flags = MS_BIND | MS_REC;  // NOLINT(runtime/int)
  const char* source = src.value().c_str();
  const char* target = dst.value().c_str();
  if (mount(source, target, "none", flags, nullptr) != 0) {
    PLOG(ERROR) << "Unable to create bind mount";
    response.set_failure_reason("Unable to create bind mount");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // Left out because we do not currently have permissions to change the flags
  // of a mount, even if it reduces privilege.  Thanks, Torvalds.
  // We cannot specify `MS_BIND` and `MS_RDONLY` in the same mount call so
  // we have remount the path to make it read-only.
  // if (!request.shared_path().writable()) {
  //   flags |= MS_REMOUNT | MS_RDONLY;
  //   if (mount(source, target, "none", flags, nullptr) != 0) {
  //     PLOG(ERROR) << "Unable to remount read-only";

  //     // Unmount the target so that we don't leak it in a writable state.
  //     // There's not a lot we can do in case of failure here.
  //     umount2(target, MNT_DETACH);
  //     // TODO: also delete the path

  //     response.set_failure_reason("Unable to remount read-only");
  //     writer.AppendProtoAsArrayOfBytes(response);
  //     return dbus_response;
  //   }
  // }

  response.set_success(true);
  response.set_path(dst.value().substr(prefix_len));
  writer.AppendProtoAsArrayOfBytes(response);
  return dbus_response;
}

// Handles a request to unshare a path with a running server.
std::unique_ptr<dbus::Response> Service::UnsharePath(
    dbus::MethodCall* method_call) {
  LOG(INFO) << "Received request to unshare path with server";

  std::unique_ptr<dbus::Response> dbus_response(
      dbus::Response::FromMethodCall(method_call));

  dbus::MessageReader reader(method_call);
  dbus::MessageWriter writer(dbus_response.get());

  UnsharePathRequest request;
  UnsharePathResponse response;

  if (!reader.PopArrayOfBytesAsProto(&request)) {
    LOG(ERROR) << "Unable to parse UnsharePathRequest from message";
    response.set_failure_reason("Unable to parse protobuf");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  const auto& iter = servers_.find(request.handle());
  if (iter == servers_.end()) {
    LOG(ERROR) << "Requested server does not exist";
    response.set_failure_reason("Requested server does not exist");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // Validate path.
  base::FilePath path(request.path());
  if (path.empty() || path.IsAbsolute() || path.ReferencesParent() ||
      path.BaseName().value() == ".") {
    LOG(ERROR) << "Requested path is empty, references parent, is absolute, or "
                  "ends with ./";
    response.set_failure_reason(
        "Path must be non-empty, relative, cannot reference parent components, "
        "nor end with \".\"");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  base::FilePath server_root =
      iter->second.root_dir().GetPath().Append(&kServerRoot[1]);
  base::FilePath dst = server_root.Append(path);
  // Ensure path exists.
  if (!base::PathExists(dst)) {
    LOG(ERROR) << "Unshare path does not exist";
    response.set_failure_reason("Unshare path does not exist");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // After unmounting, clean up empty directories.  Assume at first that we can
  // delete the topmost directory under server_root, but validate / modify this
  // path to ensure it does not contain any other mount points.  E.g. if
  // dst=<server_root>/MyFiles/a/b1/c/d, then assume we can delete
  // <server_root>/MyFiles, but if another mount exists at or under
  // <server_root>/MyFiles/a/b2, then we only delete from
  // <server_root>/MyFiles/a/b1.
  base::FilePath path_to_delete = server_root;
  std::vector<std::string> server_root_components;
  server_root.GetComponents(&server_root_components);
  size_t path_to_delete_depth = server_root_components.size();
  std::vector<std::string> dst_components;
  dst.GetComponents(&dst_components);

  // Ensure path is listed in /proc/self/mounts and has no parents within
  // server_root.
  bool path_is_mount = false;
  bool path_has_parent_mount = false;
  base::ScopedFILE mountinfo(fopen("/proc/self/mounts", "r"));
  if (!mountinfo) {
    LOG(ERROR) << "Failed to open /proc/self/mounts";
    response.set_failure_reason("Failed to open /proc/self/mounts");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }
  // List of paths to be unmounted includes path and any children.
  std::vector<base::FilePath> mount_points;
  char buf[1024 + 4];
  struct mntent entry;
  while (getmntent_r(mountinfo.get(), &entry, buf, sizeof(buf)) != nullptr) {
    base::FilePath mount_point(entry.mnt_dir);
    if (mount_point == dst) {
      // Mount is dst.  This is expected/required that one entry will match.
      path_is_mount = true;
      mount_points.emplace_back(mount_point);
    } else if (dst.IsParent(mount_point)) {
      // Mount is a child of dst.  This is OK, we will unmount it before
      // unmounting dst.
      mount_points.emplace_back(mount_point);
    } else if (server_root.IsParent(mount_point) && mount_point.IsParent(dst)) {
      // Mount is a parent of dst.  This is an error condition and we will soon
      // fail.
      path_has_parent_mount = true;
    } else {
      // Modify path_to_delete if required so it does not contain mount_point.
      std::vector<std::string> mount_point_components;
      mount_point.GetComponents(&mount_point_components);
      for (size_t i = 0;
           i < dst_components.size() - 1 && i < mount_point_components.size() &&
           dst_components[i] == mount_point_components[i];
           ++i) {
        if (i == path_to_delete_depth) {
          path_to_delete =
              path_to_delete.Append(dst_components[path_to_delete_depth++]);
        }
      }
    }
  }
  // Set path_to_delete to have 1 more component past server_root or any path
  // common with another mount.
  path_to_delete =
      path_to_delete.Append(dst_components[path_to_delete_depth++]);

  if (!path_is_mount) {
    LOG(ERROR) << "Path is not a mount point";
    response.set_failure_reason("Path is not a mount point");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }
  if (path_has_parent_mount) {
    LOG(ERROR) << "Path has a parent mount point";
    response.set_failure_reason("Path has a parent mount point");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  // In reverse order, unmount paths.
  for (auto iter = mount_points.rbegin(), end = mount_points.rend();
       iter != end; ++iter) {
    if (umount(iter->value().c_str()) != 0) {
      LOG(ERROR) << "Failed to unmount";
      response.set_failure_reason("Failed to unmount");
      writer.AppendProtoAsArrayOfBytes(response);
      return dbus_response;
    }
  }

  // Remove path_to_delete.  Recursive is required to delete any children mount
  // dirs that were created prior to this path being mounted, and any empty
  // directories that were created for this mount.  Recursive delete is safe
  // since no mounts exist under this directory.
  if (!base::DeleteFile(path_to_delete, true)) {
    LOG(ERROR) << "Delete path failed";
    response.set_failure_reason("Delete path failed");
    writer.AppendProtoAsArrayOfBytes(response);
    return dbus_response;
  }

  response.set_success(true);
  writer.AppendProtoAsArrayOfBytes(response);
  return dbus_response;
}

// Forcibly kills a server if it hasn't already exited.
void Service::KillServer(uint32_t handle) {
  const auto& iter = servers_.find(handle);
  if (iter != servers_.end()) {
    // Kill it with fire.
    if (kill(iter->second.pid(), SIGKILL) != 0) {
      PLOG(ERROR) << "Unable to send SIGKILL to child process";
    }
  }
  // We reap the child process through the normal sigchld handling mechanism.
}

}  // namespace seneschal
}  // namespace vm_tools
