// 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/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,
                       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::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
