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

#include "chromeos/tpm/install_attributes.h"

#include <stddef.h>

#include <utility>

#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/metrics/histogram_base.h"
#include "base/metrics/histogram_macros.h"
#include "base/path_service.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/system/sys_info.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "chromeos/dbus/constants/dbus_paths.h"
#include "chromeos/dbus/cryptohome/rpc.pb.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/util/tpm_util.h"
#include "components/policy/proto/install_attributes.pb.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "third_party/cros_system_api/dbus/service_constants.h"

namespace chromeos {

namespace {

InstallAttributes* g_install_attributes = nullptr;

// Calling SetForTesting sets this flag. This flag means that the production
// code which calls Initialize and Shutdown will have no effect - the test
// install attributes will remain in place until ShutdownForTesting is called.
bool g_using_install_attributes_for_testing = false;

// Number of TPM lock state query retries during consistency check.
const int kDbusRetryCount = 12;

// Interval of TPM lock state query retries during consistency check.
const int kDbusRetryIntervalInSeconds = 5;

std::string ReadMapKey(const std::map<std::string, std::string>& map,
                       const std::string& key) {
  std::map<std::string, std::string>::const_iterator entry = map.find(key);
  if (entry != map.end()) {
    return entry->second;
  }
  return std::string();
}

void WarnIfNonempty(const std::map<std::string, std::string>& map,
                    const std::string& key) {
  if (!ReadMapKey(map, key).empty()) {
    LOG(WARNING) << key << " expected to be empty.";
  }
}

// Reports the metric for whether the locking succeeded with existing locked
// attributes equal to the requested ones.
void ReportExistingLockUma(bool is_existing_lock) {
  UMA_HISTOGRAM_BOOLEAN("Enterprise.ExistingInstallAttributesLock",
                        is_existing_lock);
}

}  // namespace

// static
void InstallAttributes::Initialize() {
  // Don't reinitialize if a specific instance has already been set for test.
  if (g_using_install_attributes_for_testing)
    return;

  DCHECK(!g_install_attributes);
  DCHECK(DBusThreadManager::IsInitialized());
  g_install_attributes =
      new InstallAttributes(DBusThreadManager::Get()->GetCryptohomeClient());
  base::FilePath install_attrs_file;
  CHECK(base::PathService::Get(dbus_paths::FILE_INSTALL_ATTRIBUTES,
                               &install_attrs_file));
  g_install_attributes->Init(install_attrs_file);
}

// static
bool InstallAttributes::IsInitialized() {
  return g_install_attributes;
}

// static
void InstallAttributes::Shutdown() {
  if (g_using_install_attributes_for_testing)
    return;

  DCHECK(g_install_attributes);
  delete g_install_attributes;
  g_install_attributes = nullptr;
}

// static
InstallAttributes* InstallAttributes::Get() {
  DCHECK(g_install_attributes);
  return g_install_attributes;
}

// static
void InstallAttributes::SetForTesting(InstallAttributes* test_instance) {
  DCHECK(!g_install_attributes);
  DCHECK(!g_using_install_attributes_for_testing);
  g_install_attributes = test_instance;
  g_using_install_attributes_for_testing = true;
}

// static
void InstallAttributes::ShutdownForTesting() {
  DCHECK(g_using_install_attributes_for_testing);
  // Don't delete the test instance, we are not the owner.
  g_install_attributes = nullptr;
  g_using_install_attributes_for_testing = false;
}

// static
std::string
InstallAttributes::GetEnterpriseOwnedInstallAttributesBlobForTesting(
    const std::string& user_name) {
  cryptohome::SerializedInstallAttributes install_attrs_proto;
  cryptohome::SerializedInstallAttributes::Attribute* attribute = nullptr;

  attribute = install_attrs_proto.add_attributes();
  attribute->set_name(InstallAttributes::kAttrEnterpriseOwned);
  attribute->set_value("true");

  attribute = install_attrs_proto.add_attributes();
  attribute->set_name(InstallAttributes::kAttrEnterpriseUser);
  attribute->set_value(user_name);

  return install_attrs_proto.SerializeAsString();
}

InstallAttributes::InstallAttributes(CryptohomeClient* cryptohome_client)
    : cryptohome_client_(cryptohome_client), weak_ptr_factory_(this) {}

InstallAttributes::~InstallAttributes() {}

void InstallAttributes::Init(const base::FilePath& cache_file) {
  DCHECK(!device_locked_);

  // Mark the consistency check as running to ensure that LockDevice() is
  // blocked, but wait for the cryptohome service to be available before
  // actually calling TriggerConsistencyCheck().
  consistency_check_running_ = true;
  cryptohome_client_->WaitForServiceToBeAvailable(
      base::Bind(&InstallAttributes::OnCryptohomeServiceInitiallyAvailable,
                 weak_ptr_factory_.GetWeakPtr()));

  if (!base::PathExists(cache_file)) {
    LOG_IF(WARNING, base::SysInfo::IsRunningOnChromeOS())
        << "Install attributes missing, first sign in";
    return;
  }

  device_locked_ = true;

  char buf[16384];
  int len = base::ReadFile(cache_file, buf, sizeof(buf));
  if (len == -1 || len >= static_cast<int>(sizeof(buf))) {
    PLOG(ERROR) << "Failed to read " << cache_file.value();
    return;
  }

  cryptohome::SerializedInstallAttributes install_attrs_proto;
  if (!install_attrs_proto.ParseFromArray(buf, len)) {
    LOG(ERROR) << "Failed to parse install attributes cache.";
    return;
  }

  google::protobuf::RepeatedPtrField<
      const cryptohome::SerializedInstallAttributes::Attribute>::iterator entry;
  std::map<std::string, std::string> attr_map;
  for (entry = install_attrs_proto.attributes().begin();
       entry != install_attrs_proto.attributes().end(); ++entry) {
    // The protobuf values contain terminating null characters, so we have to
    // sanitize the value here.
    attr_map.insert(
        std::make_pair(entry->name(), std::string(entry->value().c_str())));
  }

  DecodeInstallAttributes(attr_map);
}

void InstallAttributes::ReadImmutableAttributes(const base::Closure& callback) {
  if (device_locked_) {
    callback.Run();
    return;
  }

  cryptohome_client_->InstallAttributesIsReady(
      base::Bind(&InstallAttributes::ReadAttributesIfReady,
                 weak_ptr_factory_.GetWeakPtr(), callback));
}

void InstallAttributes::ReadAttributesIfReady(const base::Closure& callback,
                                              base::Optional<bool> is_ready) {
  if (is_ready.value_or(false)) {
    registration_mode_ = policy::DEVICE_MODE_NOT_SET;
    if (!tpm_util::InstallAttributesIsInvalid() &&
        !tpm_util::InstallAttributesIsFirstInstall()) {
      device_locked_ = true;

      static const char* const kEnterpriseAttributes[] = {
          kAttrEnterpriseDeviceId,   kAttrEnterpriseDomain,
          kAttrEnterpriseRealm,      kAttrEnterpriseMode,
          kAttrEnterpriseOwned,      kAttrEnterpriseUser,
          kAttrConsumerKioskEnabled,
      };
      std::map<std::string, std::string> attr_map;
      for (size_t i = 0; i < base::size(kEnterpriseAttributes); ++i) {
        std::string value;
        if (tpm_util::InstallAttributesGet(kEnterpriseAttributes[i], &value))
          attr_map[kEnterpriseAttributes[i]] = value;
      }

      DecodeInstallAttributes(attr_map);
    }
  }
  callback.Run();
}

void InstallAttributes::SetBlockDevmodeInTpm(
    bool block_devmode,
    DBusMethodCallback<cryptohome::BaseReply> callback) {
  DCHECK(!callback.is_null());
  DCHECK(!device_locked_);

  cryptohome::SetFirmwareManagementParametersRequest request;
  // Set the flags, according to enum FirmwareManagementParametersFlags from
  // rpc.proto if devmode is blocked.
  if (block_devmode) {
    request.set_flags(
        cryptohome::DEVELOPER_DISABLE_BOOT |
        cryptohome::DEVELOPER_DISABLE_CASE_CLOSED_DEBUGGING_UNLOCK);
  }

  cryptohome_client_->SetFirmwareManagementParametersInTpm(request,
                                                           std::move(callback));
}

void InstallAttributes::LockDevice(policy::DeviceMode device_mode,
                                   const std::string& domain,
                                   const std::string& realm,
                                   const std::string& device_id,
                                   const LockResultCallback& callback) {
  CHECK((device_mode == policy::DEVICE_MODE_ENTERPRISE && !domain.empty() &&
         realm.empty() && !device_id.empty()) ||
        (device_mode == policy::DEVICE_MODE_ENTERPRISE_AD && domain.empty() &&
         !realm.empty() && !device_id.empty()) ||
        (device_mode == policy::DEVICE_MODE_DEMO && !domain.empty() &&
         realm.empty() && !device_id.empty()) ||
        (device_mode == policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH &&
         domain.empty() && realm.empty() && device_id.empty()));
  DCHECK(!callback.is_null());
  CHECK_EQ(device_lock_running_, false);

  // Check for existing lock first.
  if (device_locked_) {
    if (device_mode != registration_mode_) {
      LOG(ERROR) << "Trying to re-lock with wrong mode: device_mode: "
                 << device_mode
                 << ", registration_mode: " << registration_mode_;
      callback.Run(LOCK_WRONG_MODE);
      return;
    }

    if (domain != registration_domain_ || realm != registration_realm_ ||
        device_id != registration_device_id_) {
      LOG(ERROR) << "Trying to re-lock with non-matching parameters.";
      callback.Run(LOCK_WRONG_DOMAIN);
      return;
    }

    // Already locked in the right mode, signal success.
    ReportExistingLockUma(true /* is_existing_lock */);
    callback.Run(LOCK_SUCCESS);
    return;
  }

  // In case the consistency check is still running, postpone the device locking
  // until it has finished.  This should not introduce additional delay since
  // device locking must wait for TPM initialization anyways.
  if (consistency_check_running_) {
    CHECK(post_check_action_.is_null());
    post_check_action_ = base::Bind(&InstallAttributes::LockDevice,
                                    weak_ptr_factory_.GetWeakPtr(), device_mode,
                                    domain, realm, device_id, callback);
    return;
  }

  device_lock_running_ = true;
  cryptohome_client_->InstallAttributesIsReady(
      base::BindOnce(&InstallAttributes::LockDeviceIfAttributesIsReady,
                     weak_ptr_factory_.GetWeakPtr(), device_mode, domain, realm,
                     device_id, callback));
}

void InstallAttributes::LockDeviceIfAttributesIsReady(
    policy::DeviceMode device_mode,
    const std::string& domain,
    const std::string& realm,
    const std::string& device_id,
    const LockResultCallback& callback,
    base::Optional<bool> is_ready) {
  if (!is_ready.has_value() || !is_ready.value()) {
    device_lock_running_ = false;
    callback.Run(LOCK_NOT_READY);
    return;
  }

  // Clearing the TPM password seems to be always a good deal.
  if (tpm_util::TpmIsEnabled() && !tpm_util::TpmIsBeingOwned() &&
      tpm_util::TpmIsOwned()) {
    cryptohome_client_->CallTpmClearStoredPasswordAndBlock();
  }

  // Make sure we really have a working InstallAttrs.
  if (tpm_util::InstallAttributesIsInvalid()) {
    LOG(ERROR) << "Install attributes invalid.";
    device_lock_running_ = false;
    callback.Run(LOCK_BACKEND_INVALID);
    return;
  }

  if (!tpm_util::InstallAttributesIsFirstInstall()) {
    LOG(ERROR) << "Install attributes already installed.";
    device_lock_running_ = false;
    callback.Run(LOCK_ALREADY_LOCKED);
    return;
  }

  // Set values in the InstallAttrs.
  std::string kiosk_enabled, enterprise_owned;
  if (device_mode == policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH) {
    kiosk_enabled = "true";
  } else {
    enterprise_owned = "true";
  }
  std::string mode = GetDeviceModeString(device_mode);
  if (!tpm_util::InstallAttributesSet(kAttrConsumerKioskEnabled,
                                      kiosk_enabled) ||
      !tpm_util::InstallAttributesSet(kAttrEnterpriseOwned, enterprise_owned) ||
      !tpm_util::InstallAttributesSet(kAttrEnterpriseMode, mode) ||
      !tpm_util::InstallAttributesSet(kAttrEnterpriseDomain, domain) ||
      !tpm_util::InstallAttributesSet(kAttrEnterpriseRealm, realm) ||
      !tpm_util::InstallAttributesSet(kAttrEnterpriseDeviceId, device_id)) {
    LOG(ERROR) << "Failed writing attributes.";
    device_lock_running_ = false;
    callback.Run(LOCK_SET_ERROR);
    return;
  }

  if (!tpm_util::InstallAttributesFinalize() ||
      tpm_util::InstallAttributesIsFirstInstall()) {
    LOG(ERROR) << "Failed locking.";
    device_lock_running_ = false;
    callback.Run(LOCK_FINALIZE_ERROR);
    return;
  }

  ReadImmutableAttributes(
      base::Bind(&InstallAttributes::OnReadImmutableAttributes,
                 weak_ptr_factory_.GetWeakPtr(), device_mode, domain, realm,
                 device_id, callback));
}

void InstallAttributes::OnReadImmutableAttributes(
    policy::DeviceMode mode,
    const std::string& domain,
    const std::string& realm,
    const std::string& device_id,
    const LockResultCallback& callback) {
  device_lock_running_ = false;

  if (registration_mode_ != mode || registration_domain_ != domain ||
      registration_realm_ != realm || registration_device_id_ != device_id) {
    LOG(ERROR) << "Locked data doesn't match.";
    callback.Run(LOCK_READBACK_ERROR);
    return;
  }

  ReportExistingLockUma(false /* is_existing_lock */);
  callback.Run(LOCK_SUCCESS);
}

bool InstallAttributes::IsEnterpriseManaged() const {
  if (!device_locked_) {
    return false;
  }
  return registration_mode_ == policy::DEVICE_MODE_ENTERPRISE ||
         registration_mode_ == policy::DEVICE_MODE_ENTERPRISE_AD ||
         registration_mode_ == policy::DEVICE_MODE_DEMO;
}

bool InstallAttributes::IsActiveDirectoryManaged() const {
  if (!device_locked_) {
    return false;
  }
  return registration_mode_ == policy::DEVICE_MODE_ENTERPRISE_AD;
}

bool InstallAttributes::IsCloudManaged() const {
  if (!device_locked_) {
    return false;
  }
  return registration_mode_ == policy::DEVICE_MODE_ENTERPRISE ||
         registration_mode_ == policy::DEVICE_MODE_DEMO;
}

bool InstallAttributes::IsConsumerKioskDeviceWithAutoLaunch() {
  return device_locked_ &&
         registration_mode_ == policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH;
}

void InstallAttributes::TriggerConsistencyCheck(int dbus_retries) {
  cryptohome_client_->TpmGetPassword(
      base::Bind(&InstallAttributes::OnTpmGetPasswordCompleted,
                 weak_ptr_factory_.GetWeakPtr(), dbus_retries));
}

void InstallAttributes::OnTpmGetPasswordCompleted(
    int dbus_retries_remaining,
    base::Optional<std::string> result) {
  if (!result.has_value() && dbus_retries_remaining) {
    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
        FROM_HERE,
        base::Bind(&InstallAttributes::TriggerConsistencyCheck,
                   weak_ptr_factory_.GetWeakPtr(), dbus_retries_remaining - 1),
        base::TimeDelta::FromSeconds(kDbusRetryIntervalInSeconds));
    return;
  }

  base::HistogramBase::Sample state;
  // If the result has a value, we are interested if install attributes file
  // exists (device_locked_), if the device is enrolled (registration_mode_) and
  // if the TPM is locked, meaning the TPM password is deleted so
  // the value from result is empty.
  if (result.has_value()) {
    const bool is_cloud_managed =
        registration_mode_ == policy::DEVICE_MODE_ENTERPRISE ||
        registration_mode_ == policy::DEVICE_MODE_DEMO;
    state = (device_locked_ ? 1 : 0) | (is_cloud_managed ? 2 : 0) |
            (result->empty() ? 4 : 0);
  } else {
    state = 8;
  }
  UMA_HISTOGRAM_ENUMERATION("Enterprise.AttributesTPMConsistency", state, 9);

  // Run any action (LockDevice call) that might have queued behind the
  // consistency check.
  consistency_check_running_ = false;
  if (!post_check_action_.is_null()) {
    post_check_action_.Run();
    post_check_action_.Reset();
  }
}

// Warning: The values for these keys (but not the keys themselves) are stored
// in the protobuf with a trailing zero.  Also note that some of these constants
// have been copied to login_manager/device_policy_service.cc.  Please make sure
// that all changes to the constants are reflected there as well.
const char InstallAttributes::kConsumerDeviceMode[] = "consumer";
const char InstallAttributes::kEnterpriseDeviceMode[] = "enterprise";
const char InstallAttributes::kEnterpriseADDeviceMode[] = "enterprise_ad";
const char InstallAttributes::kLegacyRetailDeviceMode[] = "kiosk";
const char InstallAttributes::kConsumerKioskDeviceMode[] = "consumer_kiosk";
const char InstallAttributes::kDemoDeviceMode[] = "demo_mode";

const char InstallAttributes::kAttrEnterpriseDeviceId[] =
    "enterprise.device_id";
const char InstallAttributes::kAttrEnterpriseDomain[] = "enterprise.domain";
const char InstallAttributes::kAttrEnterpriseRealm[] = "enterprise.realm";
const char InstallAttributes::kAttrEnterpriseMode[] = "enterprise.mode";
const char InstallAttributes::kAttrEnterpriseOwned[] = "enterprise.owned";
const char InstallAttributes::kAttrEnterpriseUser[] = "enterprise.user";
const char InstallAttributes::kAttrConsumerKioskEnabled[] =
    "consumer.app_kiosk_enabled";

void InstallAttributes::OnCryptohomeServiceInitiallyAvailable(
    bool service_is_ready) {
  if (!service_is_ready)
    LOG(ERROR) << "Failed waiting for cryptohome D-Bus service availability.";

  // Start the consistency check even if we failed to wait for availability;
  // hopefully the service will become available eventually.
  TriggerConsistencyCheck(kDbusRetryCount);
}

std::string InstallAttributes::GetDeviceModeString(policy::DeviceMode mode) {
  switch (mode) {
    case policy::DEVICE_MODE_CONSUMER:
      return InstallAttributes::kConsumerDeviceMode;
    case policy::DEVICE_MODE_ENTERPRISE:
      return InstallAttributes::kEnterpriseDeviceMode;
    case policy::DEVICE_MODE_ENTERPRISE_AD:
      return InstallAttributes::kEnterpriseADDeviceMode;
    case policy::DEVICE_MODE_LEGACY_RETAIL_MODE:
      return InstallAttributes::kLegacyRetailDeviceMode;
    case policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH:
      return InstallAttributes::kConsumerKioskDeviceMode;
    case policy::DEVICE_MODE_DEMO:
      return InstallAttributes::kDemoDeviceMode;
    case policy::DEVICE_MODE_PENDING:
    case policy::DEVICE_MODE_NOT_SET:
      break;
  }
  NOTREACHED() << "Invalid device mode: " << mode;
  return std::string();
}

policy::DeviceMode InstallAttributes::GetDeviceModeFromString(
    const std::string& mode) {
  if (mode == InstallAttributes::kConsumerDeviceMode)
    return policy::DEVICE_MODE_CONSUMER;
  if (mode == InstallAttributes::kEnterpriseDeviceMode)
    return policy::DEVICE_MODE_ENTERPRISE;
  if (mode == InstallAttributes::kEnterpriseADDeviceMode)
    return policy::DEVICE_MODE_ENTERPRISE_AD;
  if (mode == InstallAttributes::kLegacyRetailDeviceMode)
    return policy::DEVICE_MODE_LEGACY_RETAIL_MODE;
  if (mode == InstallAttributes::kConsumerKioskDeviceMode)
    return policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH;
  if (mode == InstallAttributes::kDemoDeviceMode)
    return policy::DEVICE_MODE_DEMO;
  return policy::DEVICE_MODE_NOT_SET;
}

void InstallAttributes::DecodeInstallAttributes(
    const std::map<std::string, std::string>& attr_map) {
  // Start from a clean slate.
  registration_mode_ = policy::DEVICE_MODE_NOT_SET;
  registration_domain_.clear();
  registration_realm_.clear();
  registration_device_id_.clear();

  const std::string enterprise_owned =
      ReadMapKey(attr_map, kAttrEnterpriseOwned);
  const std::string consumer_kiosk_enabled =
      ReadMapKey(attr_map, kAttrConsumerKioskEnabled);
  const std::string mode = ReadMapKey(attr_map, kAttrEnterpriseMode);
  const std::string domain = ReadMapKey(attr_map, kAttrEnterpriseDomain);
  const std::string realm = ReadMapKey(attr_map, kAttrEnterpriseRealm);
  const std::string device_id = ReadMapKey(attr_map, kAttrEnterpriseDeviceId);
  const std::string user_deprecated = ReadMapKey(attr_map, kAttrEnterpriseUser);

  if (enterprise_owned == "true") {
    WarnIfNonempty(attr_map, kAttrConsumerKioskEnabled);
    registration_device_id_ = device_id;

    // Set registration_mode_.
    registration_mode_ = GetDeviceModeFromString(mode);
    if (registration_mode_ != policy::DEVICE_MODE_ENTERPRISE &&
        registration_mode_ != policy::DEVICE_MODE_ENTERPRISE_AD &&
        registration_mode_ != policy::DEVICE_MODE_DEMO) {
      if (!mode.empty()) {
        LOG(WARNING) << "Bad " << kAttrEnterpriseMode << ": " << mode;
      }
      registration_mode_ = policy::DEVICE_MODE_ENTERPRISE;
    }

    if (registration_mode_ == policy::DEVICE_MODE_ENTERPRISE ||
        registration_mode_ == policy::DEVICE_MODE_DEMO) {
      // Either set registration_domain_ ...
      WarnIfNonempty(attr_map, kAttrEnterpriseRealm);
      if (!domain.empty()) {
        // The canonicalization is for compatibility with earlier versions.
        registration_domain_ = gaia::CanonicalizeDomain(domain);
      } else if (!user_deprecated.empty()) {
        // Compatibility for pre M19 code.
        registration_domain_ = gaia::ExtractDomainName(user_deprecated);
      } else {
        LOG(WARNING) << "Couldn't read domain.";
      }
    } else {
      // ... or set registration_realm_.
      WarnIfNonempty(attr_map, kAttrEnterpriseDomain);
      if (!realm.empty()) {
        registration_realm_ = realm;
      } else {
        LOG(WARNING) << "Couldn't read realm.";
      }
    }

    return;
  }

  WarnIfNonempty(attr_map, kAttrEnterpriseOwned);
  WarnIfNonempty(attr_map, kAttrEnterpriseDomain);
  WarnIfNonempty(attr_map, kAttrEnterpriseRealm);
  WarnIfNonempty(attr_map, kAttrEnterpriseDeviceId);
  WarnIfNonempty(attr_map, kAttrEnterpriseUser);
  if (consumer_kiosk_enabled == "true") {
    registration_mode_ = policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH;
    return;
  }

  WarnIfNonempty(attr_map, kAttrConsumerKioskEnabled);
  if (user_deprecated.empty()) {
    registration_mode_ = policy::DEVICE_MODE_CONSUMER;
  }
}

}  // namespace chromeos
