// Copyright (c) 2012 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/policy_service.h"

#include <stdint.h>

#include <set>
#include <string>
#include <utility>

#include <base/bind.h>
#include <base/callback.h>
#include <base/files/file_enumerator.h>
#include <base/location.h>
#include <base/logging.h>
#include <base/synchronization/waitable_event.h>
#include <brillo/message_loops/message_loop.h>
#include <chromeos/dbus/service_constants.h>

#include "bindings/device_management_backend.pb.h"
#include "login_manager/blob_util.h"
#include "login_manager/dbus_util.h"
#include "login_manager/nss_util.h"
#include "login_manager/policy_key.h"
#include "login_manager/policy_store.h"
#include "login_manager/resilient_policy_store.h"
#include "login_manager/system_utils.h"
#include "login_manager/validator_utils.h"

namespace em = enterprise_management;

namespace login_manager {

PolicyNamespace MakeChromePolicyNamespace() {
  return std::make_pair(POLICY_DOMAIN_CHROME, std::string());
}

// Returns true if the domain, when part of a PolicyNamespace, expects a
// non-empty |component_id()|.
bool IsComponentDomain(PolicyDomain domain) {
  switch (domain) {
    case POLICY_DOMAIN_CHROME:
      return false;
    case POLICY_DOMAIN_EXTENSIONS:
    case POLICY_DOMAIN_SIGNIN_EXTENSIONS:
      return true;
  }
  NOTREACHED();
  return false;
}

constexpr char PolicyService::kChromePolicyFileName[] = "policy";
constexpr char PolicyService::kExtensionsPolicyFileNamePrefix[] =
    "policy_extension_id_";
constexpr char PolicyService::kSignInExtensionsPolicyFileNamePrefix[] =
    "policy_signin_extension_id_";

PolicyService::PolicyService(const base::FilePath& policy_dir,
                             PolicyKey* policy_key,
                             LoginMetrics* metrics,
                             bool resilient_chrome_policy_store)
    : metrics_(metrics),
      policy_dir_(policy_dir),
      policy_key_(policy_key),
      resilient_chrome_policy_store_(resilient_chrome_policy_store),
      delegate_(NULL),
      weak_ptr_factory_(this) {}

PolicyService::~PolicyService() = default;

bool PolicyService::Store(const PolicyNamespace& ns,
                          const std::vector<uint8_t>& policy_blob,
                          int key_flags,
                          SignatureCheck signature_check,
                          const Completion& completion) {
  em::PolicyFetchResponse policy;
  if (!policy.ParseFromArray(policy_blob.data(), policy_blob.size()) ||
      !policy.has_policy_data()) {
    constexpr char kMessage[] = "Unable to parse policy protobuf.";
    LOG(ERROR) << kMessage;
    completion.Run(CreateError(dbus_error::kSigDecodeFail, kMessage));
    return false;
  }

  return StorePolicy(ns, policy, key_flags, signature_check, completion);
}

bool PolicyService::Retrieve(const PolicyNamespace& ns,
                             std::vector<uint8_t>* policy_blob) {
  *policy_blob = SerializeAsBlob(GetOrCreateStore(ns)->Get());
  return true;
}

bool PolicyService::Delete(const PolicyNamespace& ns,
                           SignatureCheck signature_check) {
  // Don't delete Chrome user or device policy.
  if (!IsComponentDomain(ns.first)) {
    LOG(ERROR) << "Deletion only allowed for component policy.";
    return false;
  }

  // Don't delete signed policy.
  if (signature_check != SignatureCheck::kDisabled) {
    LOG(ERROR) << "Deletion of signed policy not allowed.";
    return false;
  }

  // Delete file on disk if it exists.
  if (!GetOrCreateStore(ns)->Delete()) {
    LOG(ERROR) << "Failed to delete store.";
    return false;
  }

  // Delete store.
  policy_stores_.erase(ns);

  return true;
}

std::vector<std::string> PolicyService::ListComponentIds(PolicyDomain domain) {
  // Get all component IDs from policy files stored on disk.
  std::vector<std::string> file_component_ids;
  switch (domain) {
    case POLICY_DOMAIN_CHROME:
      // Does not support component IDs, early out.
      return std::vector<std::string>();

    case POLICY_DOMAIN_EXTENSIONS:
      file_component_ids = FindComponentIds(kExtensionsPolicyFileNamePrefix,
                                            &ValidateExtensionId);
      break;

    case POLICY_DOMAIN_SIGNIN_EXTENSIONS:
      file_component_ids = FindComponentIds(
          kSignInExtensionsPolicyFileNamePrefix, &ValidateExtensionId);
      break;
  }

  // We might have missed some IDs from component policy that has not been
  // written out yet, so check the stores as well.
  std::set<std::string> component_ids(file_component_ids.begin(),
                                      file_component_ids.end());
  for (const auto& kv : policy_stores_) {
    const PolicyNamespace& ns = kv.first;
    const std::string& component_id = ns.second;
    const PolicyStore* store = kv.second.get();
    // Only count stores that actually have policy!
    if (ns.first == domain && store->Get().has_policy_data())
      component_ids.insert(component_id);
  }

  return std::vector<std::string>(component_ids.begin(), component_ids.end());
}

void PolicyService::PersistPolicy(const PolicyNamespace& ns,
                                  const Completion& completion) {
  const bool success = GetOrCreateStore(ns)->Persist();
  OnPolicyPersisted(completion,
                    success ? dbus_error::kNone : dbus_error::kSigEncodeFail);
}

void PolicyService::PersistAllPolicy() {
  for (const auto& kv : policy_stores_)
    kv.second->Persist();
}

PolicyStore* PolicyService::GetOrCreateStore(const PolicyNamespace& ns) {
  PolicyStoreMap::const_iterator iter = policy_stores_.find(ns);
  if (iter != policy_stores_.end())
    return iter->second.get();

  bool resilient =
      (ns == MakeChromePolicyNamespace() && resilient_chrome_policy_store_);
  std::unique_ptr<PolicyStore> store;
  if (resilient)
    store = std::make_unique<ResilientPolicyStore>(GetPolicyPath(ns), metrics_);
  else
    store = std::make_unique<PolicyStore>(GetPolicyPath(ns));

  store->EnsureLoadedOrCreated();
  PolicyStore* policy_store_ptr = store.get();
  policy_stores_[ns] = std::move(store);
  return policy_store_ptr;
}

void PolicyService::SetStoreForTesting(const PolicyNamespace& ns,
                                       std::unique_ptr<PolicyStore> store) {
  policy_stores_[ns] = std::move(store);
}

void PolicyService::PostPersistKeyTask() {
  brillo::MessageLoop::current()->PostTask(
      FROM_HERE,
      base::Bind(&PolicyService::PersistKey, weak_ptr_factory_.GetWeakPtr()));
}

void PolicyService::PostPersistPolicyTask(const PolicyNamespace& ns,
                                          const Completion& completion) {
  brillo::MessageLoop::current()->PostTask(
      FROM_HERE, base::Bind(&PolicyService::PersistPolicy,
                            weak_ptr_factory_.GetWeakPtr(), ns, completion));
}

bool PolicyService::StorePolicy(const PolicyNamespace& ns,
                                const em::PolicyFetchResponse& policy,
                                int key_flags,
                                SignatureCheck signature_check,
                                const Completion& completion) {
  if (signature_check == SignatureCheck::kDisabled) {
    GetOrCreateStore(ns)->Set(policy);
    PostPersistPolicyTask(ns, completion);
    return true;
  }

  // Determine if the policy has pushed a new owner key and, if so, set it.
  if (policy.has_new_public_key() && !key()->Equals(policy.new_public_key())) {
    // The policy contains a new key, and it is different from |key_|.
    std::vector<uint8_t> der = StringToBlob(policy.new_public_key());

    bool installed = false;
    if (key()->IsPopulated()) {
      if (policy.has_new_public_key_signature() && (key_flags & KEY_ROTATE)) {
        // Graceful key rotation.
        LOG(INFO) << "Attempting policy key rotation.";
        installed =
            key()->Rotate(der, StringToBlob(policy.new_public_key_signature()));
      }
    } else if (key_flags & KEY_INSTALL_NEW) {
      LOG(INFO) << "Attempting to install new policy key.";
      installed = key()->PopulateFromBuffer(der);
    }
    if (!installed && (key_flags & KEY_CLOBBER)) {
      LOG(INFO) << "Clobbering existing policy key.";
      installed = key()->ClobberCompromisedKey(der);
    }

    if (!installed) {
      constexpr char kMessage[] = "Failed to install policy key!";
      LOG(ERROR) << kMessage;
      completion.Run(CreateError(dbus_error::kPubkeySetIllegal, kMessage));
      return false;
    }

    // If here, need to persist the key just loaded into memory to disk.
    PostPersistKeyTask();
  }

  // Validate signature on policy and persist to disk.
  if (!key()->Verify(StringToBlob(policy.policy_data()),
                     StringToBlob(policy.policy_data_signature()))) {
    constexpr char kMessage[] = "Signature could not be verified.";
    LOG(ERROR) << kMessage;
    completion.Run(CreateError(dbus_error::kVerifyFail, kMessage));
    return false;
  }

  GetOrCreateStore(ns)->Set(policy);
  PostPersistPolicyTask(ns, completion);
  return true;
}

void PolicyService::OnKeyPersisted(bool status) {
  if (status)
    LOG(INFO) << "Persisted policy key to disk.";
  else
    LOG(ERROR) << "Failed to persist policy key to disk.";
  if (delegate_)
    delegate_->OnKeyPersisted(status);
}

void PolicyService::OnPolicyPersisted(const Completion& completion,
                                      const std::string& dbus_error_code) {
  brillo::ErrorPtr error;
  if (dbus_error_code != dbus_error::kNone) {
    constexpr char kMessage[] = "Failed to persist policy to disk.";
    LOG(ERROR) << kMessage << ": " << dbus_error_code;
    error = CreateError(dbus_error_code, kMessage);
  }

  if (!completion.is_null())
    completion.Run(std::move(error));
  else
    error.reset();

  if (delegate_)
    delegate_->OnPolicyPersisted(dbus_error_code == dbus_error::kNone);
}

void PolicyService::PersistKey() {
  OnKeyPersisted(key()->Persist());
}

base::FilePath PolicyService::GetPolicyPath(const PolicyNamespace& ns) {
  // If the store has already been already created, return the store's path.
  PolicyStoreMap::const_iterator iter = policy_stores_.find(ns);
  if (iter != policy_stores_.end())
    return iter->second->policy_path();

  const PolicyDomain& domain = ns.first;
  const std::string& component_id = ns.second;
  switch (domain) {
    case POLICY_DOMAIN_CHROME:
      return policy_dir_.AppendASCII(kChromePolicyFileName);
    case POLICY_DOMAIN_EXTENSIONS:
      // Double-check extension ID (should have already been checked before).
      CHECK(ValidateExtensionId(component_id));
      return policy_dir_.AppendASCII(kExtensionsPolicyFileNamePrefix +
                                     component_id);
    case POLICY_DOMAIN_SIGNIN_EXTENSIONS:
      // Double-check extension ID (should have already been checked before).
      CHECK(ValidateExtensionId(component_id));
      return policy_dir_.AppendASCII(kSignInExtensionsPolicyFileNamePrefix +
                                     component_id);
  }
}

std::vector<std::string> PolicyService::FindComponentIds(
    const std::string& policy_filename_prefix, ComponentIdFilter filter) {
  std::vector<std::string> component_ids;
  base::FileEnumerator policy_files(policy_dir_, false /* recursive */,
                                    base::FileEnumerator::FILES,
                                    policy_filename_prefix + "*");
  base::FilePath policy_path;
  while (!(policy_path = policy_files.Next()).empty()) {
    const base::FilePath policy_filename = policy_path.BaseName();
    DCHECK_GE(policy_filename.value().size(), policy_filename_prefix.size());
    std::string component_id =
        policy_filename.value().substr(policy_filename_prefix.size());
    if (filter(component_id))
      component_ids.push_back(std::move(component_id));
  }
  return component_ids;
}

}  // namespace login_manager
