// Copyright (c) 2014 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 "login_manager/session_manager_dbus_adaptor.h"

#include <stdint.h>

#include <map>
#include <string>
#include <vector>

#include <base/bind.h>
#include <base/callback.h>
#include <base/files/file_util.h>
#include <base/memory/scoped_ptr.h>
#include <base/stl_util.h>
#include <chromeos/dbus/service_constants.h>
#include <dbus/exported_object.h>
#include <dbus/file_descriptor.h>
#include <dbus/message.h>

#include "login_manager/dbus_error_types.h"
#include "login_manager/policy_service.h"
#include "login_manager/session_manager_impl.h"

namespace login_manager {
namespace {

const char kBindingsPath[] =
    "/usr/share/dbus-1/interfaces/org.chromium.SessionManagerInterface.xml";
const char kDBusIntrospectableInterface[] =
    "org.freedesktop.DBus.Introspectable";
const char kDBusIntrospectMethod[] = "Introspect";

// 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<scoped_ptr<dbus::Response>(dbus::MethodCall*)> handler,
    dbus::MethodCall* method_call,
    dbus::ExportedObject::ResponseSender response_sender) {
  scoped_ptr<dbus::Response> response = handler.Run(method_call);
  if (!response)
    response = dbus::Response::FromMethodCall(method_call);
  response_sender.Run(response.Pass());
}

scoped_ptr<dbus::Response> CreateError(dbus::MethodCall* call,
                                       const std::string& name,
                                       const std::string& message) {
  return dbus::ErrorResponse::FromMethodCall(call, name, message).Pass();
}

// Creates a new "invalid args" reply to call.
scoped_ptr<dbus::Response> CreateInvalidArgsError(dbus::MethodCall* call,
                                                  std::string message) {
  return CreateError(call, DBUS_ERROR_INVALID_ARGS, "Signature is: " + message);
}

// Craft a Response to call that is appropriate, given the contents of error.
// If error is set, this will be an ErrorResponse. Otherwise, it will be a
// Response containing payload.
scoped_ptr<dbus::Response> CraftAppropriateResponseWithBool(
    dbus::MethodCall* call,
    const SessionManagerImpl::Error& error,
    bool payload) {
  scoped_ptr<dbus::Response> response;
  if (error.is_set()) {
    response = CreateError(call, error.name(), error.message());
  } else {
    response = dbus::Response::FromMethodCall(call);
    dbus::MessageWriter writer(response.get());
    writer.AppendBool(payload);
  }
  return response.Pass();
}

scoped_ptr<dbus::Response> CraftAppropriateResponseWithString(
    dbus::MethodCall* call,
    const SessionManagerImpl::Error& error,
    const std::string& payload) {
  scoped_ptr<dbus::Response> response;
  if (error.is_set()) {
    response = CreateError(call, error.name(), error.message());
  } else {
    response = dbus::Response::FromMethodCall(call);
    dbus::MessageWriter writer(response.get());
    writer.AppendString(payload);
  }
  return response.Pass();
}

scoped_ptr<dbus::Response> CraftAppropriateResponseWithBytes(
    dbus::MethodCall* call,
    const SessionManagerImpl::Error& error,
    const std::vector<uint8_t>& payload) {
  scoped_ptr<dbus::Response> response;
  if (error.is_set()) {
    response = CreateError(call, error.name(), error.message());
  } else {
    response = dbus::Response::FromMethodCall(call);
    dbus::MessageWriter writer(response.get());
    writer.AppendArrayOfBytes(vector_as_array(&payload), payload.size());
  }
  return response.Pass();
}

// Handles completion of a server-backed state key retrieval operation and
// passes the response back to the waiting DBus invocation context.
void HandleGetServerBackedStateKeysCompletion(
    dbus::MethodCall* call,
    const dbus::ExportedObject::ResponseSender& sender,
    const std::vector<std::vector<uint8_t>>& state_keys) {
  scoped_ptr<dbus::Response> response(dbus::Response::FromMethodCall(call));
  dbus::MessageWriter writer(response.get());
  dbus::MessageWriter array_writer(NULL);
  writer.OpenArray("ay", &array_writer);
  for (std::vector<std::vector<uint8_t>>::const_iterator state_key(
           state_keys.begin());
       state_key != state_keys.end();
       ++state_key) {
    array_writer.AppendArrayOfBytes(state_key->data(), state_key->size());
  }
  writer.CloseContainer(&array_writer);
  sender.Run(response.Pass());
}

}  // namespace

// Callback that forwards a result to a DBus invocation context.
class DBusMethodCompletion {
 public:
  static PolicyService::Completion CreateCallback(
      dbus::MethodCall* call,
      const dbus::ExportedObject::ResponseSender& sender);
  virtual ~DBusMethodCompletion();

 private:
  DBusMethodCompletion() : call_(nullptr) {}
  DBusMethodCompletion(dbus::MethodCall* call,
                       const dbus::ExportedObject::ResponseSender& sender);
  void HandleResult(const PolicyService::Error& error);

  dbus::MethodCall* call_ = nullptr;
  dbus::ExportedObject::ResponseSender sender_;

  DISALLOW_COPY_AND_ASSIGN(DBusMethodCompletion);
};

// static
PolicyService::Completion DBusMethodCompletion::CreateCallback(
      dbus::MethodCall* call,
      const dbus::ExportedObject::ResponseSender& sender) {
  return base::Bind(&DBusMethodCompletion::HandleResult,
                    base::Owned(new DBusMethodCompletion(call, sender)));
}

// Apparently, call is owned by sender, so it's safe to hang on to it.
DBusMethodCompletion::DBusMethodCompletion(
    dbus::MethodCall* call,
    const dbus::ExportedObject::ResponseSender& sender)
    : call_(call), sender_(sender) {
}

DBusMethodCompletion::~DBusMethodCompletion() {
  if (call_) {
    NOTREACHED() << "Unfinished DBUS call!";
    sender_.Run(dbus::Response::FromMethodCall(call_));
  }
}

void DBusMethodCompletion::HandleResult(const PolicyService::Error& error) {
  if (error.code() == dbus_error::kNone) {
    scoped_ptr<dbus::Response> response(dbus::Response::FromMethodCall(call_));
    dbus::MessageWriter writer(response.get());
    writer.AppendBool(true);
    sender_.Run(response.Pass());
    call_ = nullptr;
  } else {
    sender_.Run(
        dbus::ErrorResponse::FromMethodCall(call_,
                                            error.code(), error.message())
        .Pass());
    call_ = nullptr;
  }
}

SessionManagerDBusAdaptor::SessionManagerDBusAdaptor(SessionManagerImpl* impl)
    : impl_(impl) {
  CHECK(impl_);
}

SessionManagerDBusAdaptor::~SessionManagerDBusAdaptor() {
}

void SessionManagerDBusAdaptor::ExportDBusMethods(
    dbus::ExportedObject* object) {
  ExportSyncDBusMethod(object,
                       kSessionManagerEmitLoginPromptVisible,
                       &SessionManagerDBusAdaptor::EmitLoginPromptVisible);
  ExportSyncDBusMethod(object,
                       "EnableChromeTesting",
                       &SessionManagerDBusAdaptor::EnableChromeTesting);
  ExportSyncDBusMethod(object,
                       kSessionManagerStartSession,
                       &SessionManagerDBusAdaptor::StartSession);
  ExportSyncDBusMethod(object,
                       kSessionManagerStopSession,
                       &SessionManagerDBusAdaptor::StopSession);

  ExportAsyncDBusMethod(object,
                        kSessionManagerStorePolicy,
                        &SessionManagerDBusAdaptor::StorePolicy);
  ExportSyncDBusMethod(object,
                       kSessionManagerRetrievePolicy,
                       &SessionManagerDBusAdaptor::RetrievePolicy);

  ExportAsyncDBusMethod(object,
                        kSessionManagerStorePolicyForUser,
                        &SessionManagerDBusAdaptor::StorePolicyForUser);
  ExportSyncDBusMethod(object,
                       kSessionManagerRetrievePolicyForUser,
                       &SessionManagerDBusAdaptor::RetrievePolicyForUser);

  ExportAsyncDBusMethod(
      object,
      kSessionManagerStoreDeviceLocalAccountPolicy,
      &SessionManagerDBusAdaptor::StoreDeviceLocalAccountPolicy);
  ExportSyncDBusMethod(
      object,
      kSessionManagerRetrieveDeviceLocalAccountPolicy,
      &SessionManagerDBusAdaptor::RetrieveDeviceLocalAccountPolicy);

  ExportSyncDBusMethod(object,
                       kSessionManagerRetrieveSessionState,
                       &SessionManagerDBusAdaptor::RetrieveSessionState);
  ExportSyncDBusMethod(object,
                       kSessionManagerRetrieveActiveSessions,
                       &SessionManagerDBusAdaptor::RetrieveActiveSessions);

  ExportSyncDBusMethod(
      object,
      kSessionManagerHandleSupervisedUserCreationStarting,
      &SessionManagerDBusAdaptor::HandleSupervisedUserCreationStarting);
  ExportSyncDBusMethod(
      object,
      kSessionManagerHandleSupervisedUserCreationFinished,
      &SessionManagerDBusAdaptor::HandleSupervisedUserCreationFinished);
  ExportSyncDBusMethod(object,
                       kSessionManagerLockScreen,
                       &SessionManagerDBusAdaptor::LockScreen);
  ExportSyncDBusMethod(object,
                       kSessionManagerHandleLockScreenShown,
                       &SessionManagerDBusAdaptor::HandleLockScreenShown);
  ExportSyncDBusMethod(object,
                       kSessionManagerHandleLockScreenDismissed,
                       &SessionManagerDBusAdaptor::HandleLockScreenDismissed);

  ExportSyncDBusMethod(object,
                       kSessionManagerRestartJob,
                       &SessionManagerDBusAdaptor::RestartJob);
  ExportSyncDBusMethod(object,
                       kSessionManagerRestartJobWithAuth,
                       &SessionManagerDBusAdaptor::RestartJobWithAuth);
  ExportSyncDBusMethod(object,
                       kSessionManagerStartDeviceWipe,
                       &SessionManagerDBusAdaptor::StartDeviceWipe);
  ExportSyncDBusMethod(object,
                       kSessionManagerSetFlagsForUser,
                       &SessionManagerDBusAdaptor::SetFlagsForUser);

  ExportAsyncDBusMethod(object,
                        kSessionManagerGetServerBackedStateKeys,
                        &SessionManagerDBusAdaptor::GetServerBackedStateKeys);
  ExportSyncDBusMethod(object,
                       kSessionManagerInitMachineInfo,
                       &SessionManagerDBusAdaptor::InitMachineInfo);

  CHECK(object->ExportMethodAndBlock(
      kDBusIntrospectableInterface,
      kDBusIntrospectMethod,
      base::Bind(&HandleSynchronousDBusMethodCall,
                 base::Bind(&SessionManagerDBusAdaptor::Introspect,
                            base::Unretained(this)))));
}

scoped_ptr<dbus::Response> SessionManagerDBusAdaptor::EmitLoginPromptVisible(
    dbus::MethodCall* call) {
  SessionManagerImpl::Error error;
  impl_->EmitLoginPromptVisible(&error);
  if (error.is_set())
    return CreateError(call, error.name(), error.message());
  return scoped_ptr<dbus::Response>(dbus::Response::FromMethodCall(call));
}

scoped_ptr<dbus::Response> SessionManagerDBusAdaptor::EnableChromeTesting(
    dbus::MethodCall* call) {
  dbus::MessageReader reader(call);
  bool relaunch;
  std::vector<std::string> extra_args;
  if (!reader.PopBool(&relaunch) || !reader.PopArrayOfStrings(&extra_args))
    return CreateInvalidArgsError(call, call->GetSignature());

  SessionManagerImpl::Error error;
  std::string testing_path =
      impl_->EnableChromeTesting(relaunch, extra_args, &error);
  return CraftAppropriateResponseWithString(call, error, testing_path);
}

scoped_ptr<dbus::Response> SessionManagerDBusAdaptor::StartSession(
    dbus::MethodCall* call) {
  dbus::MessageReader reader(call);
  std::string email, unique_id;
  if (!reader.PopString(&email) || !reader.PopString(&unique_id))
    return CreateInvalidArgsError(call, call->GetSignature());

  SessionManagerImpl::Error error;
  bool success = impl_->StartSession(email, unique_id, &error);
  return CraftAppropriateResponseWithBool(call, error, success);
}

scoped_ptr<dbus::Response> SessionManagerDBusAdaptor::StopSession(
    dbus::MethodCall* call) {
  // Though this takes a string (unique_id), it is ignored.
  bool success = impl_->StopSession();
  scoped_ptr<dbus::Response> response(dbus::Response::FromMethodCall(call));
  dbus::MessageWriter writer(response.get());
  writer.AppendBool(success);
  return response.Pass();
}

void SessionManagerDBusAdaptor::StorePolicy(
    dbus::MethodCall* call,
    dbus::ExportedObject::ResponseSender sender) {
  const uint8_t* policy_blob = NULL;
  size_t policy_blob_len = 0;
  dbus::MessageReader reader(call);
  // policy_blob points into reader after pop.
  if (!reader.PopArrayOfBytes(&policy_blob, &policy_blob_len)) {
    sender.Run(CreateInvalidArgsError(call, call->GetSignature()).Pass());
  } else {
    impl_->StorePolicy(policy_blob, policy_blob_len,
                       DBusMethodCompletion::CreateCallback(call, sender));
    // Response will be sent asynchronously.
  }
}

scoped_ptr<dbus::Response> SessionManagerDBusAdaptor::RetrievePolicy(
    dbus::MethodCall* call) {
  std::vector<uint8_t> policy_data;
  SessionManagerImpl::Error error;
  impl_->RetrievePolicy(&policy_data, &error);
  return CraftAppropriateResponseWithBytes(call, error, policy_data);
}

void SessionManagerDBusAdaptor::StorePolicyForUser(
    dbus::MethodCall* call,
    dbus::ExportedObject::ResponseSender sender) {
  std::string user_email;
  const uint8_t* policy_blob = NULL;
  size_t policy_blob_len = 0;
  dbus::MessageReader reader(call);
  // policy_blob points into reader after pop.
  if (!reader.PopString(&user_email) ||
      !reader.PopArrayOfBytes(&policy_blob, &policy_blob_len)) {
    sender.Run(CreateInvalidArgsError(call, call->GetSignature()).Pass());
  } else {
    impl_->StorePolicyForUser(user_email,
                              policy_blob,
                              policy_blob_len,
                              DBusMethodCompletion::CreateCallback(call,
                                                                   sender));
    // Response will normally be sent asynchronously.
  }
}

scoped_ptr<dbus::Response> SessionManagerDBusAdaptor::RetrievePolicyForUser(
    dbus::MethodCall* call) {
  std::string user_email;
  dbus::MessageReader reader(call);

  if (!reader.PopString(&user_email))
    return CreateInvalidArgsError(call, call->GetSignature());

  std::vector<uint8_t> policy_data;
  SessionManagerImpl::Error error;
  impl_->RetrievePolicyForUser(user_email, &policy_data, &error);
  return CraftAppropriateResponseWithBytes(call, error, policy_data);
}

void SessionManagerDBusAdaptor::StoreDeviceLocalAccountPolicy(
    dbus::MethodCall* call,
    dbus::ExportedObject::ResponseSender sender) {
  std::string account_id;
  const uint8_t* policy_blob = NULL;
  size_t policy_blob_len = 0;
  dbus::MessageReader reader(call);
  // policy_blob points into reader after pop.
  if (!reader.PopString(&account_id) ||
      !reader.PopArrayOfBytes(&policy_blob, &policy_blob_len)) {
    sender.Run(CreateInvalidArgsError(call, call->GetSignature()).Pass());
  } else {
    impl_->StoreDeviceLocalAccountPolicy(
        account_id,
        policy_blob,
        policy_blob_len,
        DBusMethodCompletion::CreateCallback(call, sender));
    // Response will be sent asynchronously.
  }
}

scoped_ptr<dbus::Response>
SessionManagerDBusAdaptor::RetrieveDeviceLocalAccountPolicy(
    dbus::MethodCall* call) {
  std::string account_id;
  dbus::MessageReader reader(call);

  if (!reader.PopString(&account_id))
    return CreateInvalidArgsError(call, call->GetSignature());

  std::vector<uint8_t> policy_data;
  SessionManagerImpl::Error error;
  impl_->RetrieveDeviceLocalAccountPolicy(account_id, &policy_data, &error);
  return CraftAppropriateResponseWithBytes(call, error, policy_data);
}

scoped_ptr<dbus::Response> SessionManagerDBusAdaptor::RetrieveSessionState(
    dbus::MethodCall* call) {
  scoped_ptr<dbus::Response> response(dbus::Response::FromMethodCall(call));
  dbus::MessageWriter writer(response.get());
  writer.AppendString(impl_->RetrieveSessionState());
  return response.Pass();
}

scoped_ptr<dbus::Response> SessionManagerDBusAdaptor::RetrieveActiveSessions(
    dbus::MethodCall* call) {
  std::map<std::string, std::string> sessions;
  impl_->RetrieveActiveSessions(&sessions);

  scoped_ptr<dbus::Response> response(dbus::Response::FromMethodCall(call));
  dbus::MessageWriter writer(response.get());
  dbus::MessageWriter array_writer(NULL);
  writer.OpenArray("{ss}", &array_writer);
  for (std::map<std::string, std::string>::const_iterator it = sessions.begin();
       it != sessions.end();
       ++it) {
    dbus::MessageWriter entry_writer(NULL);
    array_writer.OpenDictEntry(&entry_writer);
    entry_writer.AppendString(it->first);
    entry_writer.AppendString(it->second);
    array_writer.CloseContainer(&entry_writer);
  }
  writer.CloseContainer(&array_writer);
  return response.Pass();
}

scoped_ptr<dbus::Response>
SessionManagerDBusAdaptor::HandleSupervisedUserCreationStarting(
    dbus::MethodCall* call) {
  impl_->HandleSupervisedUserCreationStarting();
  return scoped_ptr<dbus::Response>(dbus::Response::FromMethodCall(call));
}

scoped_ptr<dbus::Response>
SessionManagerDBusAdaptor::HandleSupervisedUserCreationFinished(
    dbus::MethodCall* call) {
  impl_->HandleSupervisedUserCreationFinished();
  return scoped_ptr<dbus::Response>(dbus::Response::FromMethodCall(call));
}

scoped_ptr<dbus::Response> SessionManagerDBusAdaptor::LockScreen(
    dbus::MethodCall* call) {
  SessionManagerImpl::Error error;
  impl_->LockScreen(&error);

  if (error.is_set())
    return CreateError(call, error.name(), error.message());
  return scoped_ptr<dbus::Response>(dbus::Response::FromMethodCall(call));
}

scoped_ptr<dbus::Response> SessionManagerDBusAdaptor::HandleLockScreenShown(
    dbus::MethodCall* call) {
  impl_->HandleLockScreenShown();
  return scoped_ptr<dbus::Response>(dbus::Response::FromMethodCall(call));
}

scoped_ptr<dbus::Response> SessionManagerDBusAdaptor::HandleLockScreenDismissed(
    dbus::MethodCall* call) {
  impl_->HandleLockScreenDismissed();
  return scoped_ptr<dbus::Response>(dbus::Response::FromMethodCall(call));
}

scoped_ptr<dbus::Response> SessionManagerDBusAdaptor::RestartJob(
    dbus::MethodCall* call) {
  int pid;
  std::string arguments;
  dbus::MessageReader reader(call);
  if (!reader.PopInt32(&pid) || !reader.PopString(&arguments))
    return CreateInvalidArgsError(call, call->GetSignature());

  SessionManagerImpl::Error error;
  bool success = impl_->RestartJob(static_cast<pid_t>(pid), arguments, &error);
  return CraftAppropriateResponseWithBool(call, error, success);
}

scoped_ptr<dbus::Response> SessionManagerDBusAdaptor::RestartJobWithAuth(
    dbus::MethodCall* call) {
  dbus::FileDescriptor fd;
  std::string arguments;
  dbus::MessageReader reader(call);
  if (!reader.PopFileDescriptor(&fd) || !reader.PopString(&arguments))
    return CreateInvalidArgsError(call, call->GetSignature());

  fd.CheckValidity();
  CHECK(fd.is_valid());

  SessionManagerImpl::Error error;
  if (impl_->RestartJobWithAuth(fd.value(), arguments, &error))
    return dbus::Response::FromMethodCall(call);
  return CreateError(call, error.name(), error.message());
}

scoped_ptr<dbus::Response> SessionManagerDBusAdaptor::StartDeviceWipe(
    dbus::MethodCall* call) {
  SessionManagerImpl::Error error;
  impl_->StartDeviceWipe("session_manager_dbus_request", &error);
  return CraftAppropriateResponseWithBool(call, error, true);
}

scoped_ptr<dbus::Response> SessionManagerDBusAdaptor::SetFlagsForUser(
    dbus::MethodCall* call) {
  dbus::MessageReader reader(call);
  std::string user_email;
  std::vector<std::string> session_user_flags;
  if (!reader.PopString(&user_email) ||
      !reader.PopArrayOfStrings(&session_user_flags)) {
    return CreateInvalidArgsError(call, call->GetSignature());
  }
  impl_->SetFlagsForUser(user_email, session_user_flags);
  return scoped_ptr<dbus::Response>(dbus::Response::FromMethodCall(call));
}

void SessionManagerDBusAdaptor::GetServerBackedStateKeys(
    dbus::MethodCall* call,
    dbus::ExportedObject::ResponseSender sender) {
  std::vector<std::vector<uint8_t>> state_keys;
  impl_->RequestServerBackedStateKeys(
      base::Bind(&HandleGetServerBackedStateKeysCompletion, call, sender));
}

scoped_ptr<dbus::Response> SessionManagerDBusAdaptor::InitMachineInfo(
    dbus::MethodCall* call) {
  dbus::MessageReader reader(call);
  std::string data;
  if (!reader.PopString(&data))
    return CreateInvalidArgsError(call, call->GetSignature());

  SessionManagerImpl::Error error;
  impl_->InitMachineInfo(data, &error);
  if (error.is_set())
    return CreateError(call, error.name(), error.message());
  return scoped_ptr<dbus::Response>(dbus::Response::FromMethodCall(call));
}

scoped_ptr<dbus::Response> SessionManagerDBusAdaptor::Introspect(
    dbus::MethodCall* call) {
  std::string output;
  if (!base::ReadFileToString(base::FilePath(kBindingsPath), &output)) {
    PLOG(ERROR) << "Can't read XML bindings from disk:";
    return CreateError(call, "Can't read XML bindings from disk.", "");
  }
  scoped_ptr<dbus::Response> response(dbus::Response::FromMethodCall(call));
  dbus::MessageWriter writer(response.get());
  writer.AppendString(output);
  return response.Pass();
}

void SessionManagerDBusAdaptor::ExportSyncDBusMethod(
    dbus::ExportedObject* object,
    const std::string& method_name,
    SyncDBusMethodCallMemberFunction member) {
  DCHECK(object);
  CHECK(object->ExportMethodAndBlock(
      kSessionManagerInterface,
      method_name,
      base::Bind(&HandleSynchronousDBusMethodCall,
                 base::Bind(member, base::Unretained(this)))));
}

void SessionManagerDBusAdaptor::ExportAsyncDBusMethod(
    dbus::ExportedObject* object,
    const std::string& method_name,
    AsyncDBusMethodCallMemberFunction member) {
  DCHECK(object);
  CHECK(
      object->ExportMethodAndBlock(kSessionManagerInterface,
                                   method_name,
                                   base::Bind(member, base::Unretained(this))));
}

}  // namespace login_manager
