// 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/device_local_account_policy_service.h"

#include <stdint.h>

#include <utility>

#include <base/files/file_enumerator.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/memory/ref_counted.h>
#include <base/strings/string_util.h>
#include <brillo/cryptohome.h>
#include <chromeos/dbus/service_constants.h>

#include "bindings/chrome_device_policy.pb.h"
#include "login_manager/dbus_util.h"
#include "login_manager/policy_key.h"
#include "login_manager/policy_service.h"
#include "login_manager/policy_store.h"

namespace em = enterprise_management;

namespace login_manager {

const base::FilePath::CharType DeviceLocalAccountPolicyService::kPolicyDir[] =
    FILE_PATH_LITERAL("policy");

const base::FilePath::CharType
    DeviceLocalAccountPolicyService::kPolicyFileName[] =
        FILE_PATH_LITERAL("policy");

DeviceLocalAccountPolicyService::DeviceLocalAccountPolicyService(
    const base::FilePath& device_local_account_dir, PolicyKey* owner_key)
    : device_local_account_dir_(device_local_account_dir),
      owner_key_(owner_key) {}

DeviceLocalAccountPolicyService::~DeviceLocalAccountPolicyService() = default;

bool DeviceLocalAccountPolicyService::Store(
    const std::string& account_id,
    const std::vector<uint8_t>& policy_blob,
    const PolicyService::Completion& completion) {
  PolicyService* service = GetPolicyService(account_id);
  if (!service) {
    completion.Run(CreateError(dbus_error::kInvalidAccount,
                               "Invalid device-local account"));
    return false;
  }

  return service->Store(policy_blob, PolicyService::KEY_NONE,
                        SignatureCheck::kEnabled, completion);
}

bool DeviceLocalAccountPolicyService::Retrieve(
    const std::string& account_id, std::vector<uint8_t>* policy_blob) {
  PolicyService* service = GetPolicyService(account_id);
  if (!service)
    return false;

  return service->Retrieve(policy_blob);
}

void DeviceLocalAccountPolicyService::UpdateDeviceSettings(
    const em::ChromeDeviceSettingsProto& device_settings) {
  // Update the policy map.
  typedef google::protobuf::RepeatedPtrField<em::DeviceLocalAccountInfoProto>
      DeviceLocalAccountList;
  std::map<std::string, std::unique_ptr<PolicyService>> new_policy_map;
  const DeviceLocalAccountList& list(
      device_settings.device_local_accounts().account());
  for (DeviceLocalAccountList::const_iterator account(list.begin());
       account != list.end(); ++account) {
    std::string account_key;
    if (account->has_account_id()) {
      account_key = GetAccountKey(account->account_id());
    } else if (!account->has_type() &&
               account->has_deprecated_public_session_id()) {
      account_key = GetAccountKey(account->deprecated_public_session_id());
    }
    if (!account_key.empty()) {
      new_policy_map[account_key] = std::move(policy_map_[account_key]);
    }
  }
  policy_map_.swap(new_policy_map);

  MigrateUppercaseDirs();

  // Purge all existing on-disk accounts that are no longer defined.
  base::FileEnumerator enumerator(device_local_account_dir_, false,
                                  base::FileEnumerator::DIRECTORIES);
  base::FilePath subdir;
  while (!(subdir = enumerator.Next()).empty()) {
    if (IsValidAccountKey(subdir.BaseName().value()) &&
        policy_map_.find(subdir.BaseName().value()) == policy_map_.end()) {
      LOG(INFO) << "Purging " << subdir.value();
      if (!base::DeleteFile(subdir, true))
        LOG(ERROR) << "Failed to delete " << subdir.value();
    }
  }
}

bool DeviceLocalAccountPolicyService::MigrateUppercaseDirs(void) {
  base::FileEnumerator enumerator(device_local_account_dir_, false,
                                  base::FileEnumerator::DIRECTORIES);
  base::FilePath subdir;

  while (!(subdir = enumerator.Next()).empty()) {
    std::string upper = subdir.BaseName().value();
    std::string lower = base::ToLowerASCII(upper);
    if (IsValidAccountKey(lower) && lower != upper) {
      base::FilePath subdir_to(subdir.DirName().Append(lower));
      LOG(INFO) << "Migrating " << upper << " to " << lower;
      if (!base::ReplaceFile(subdir, subdir_to, NULL))
        LOG(ERROR) << "Failed to migrate " << subdir.value();
    }
  }

  return true;
}

PolicyService* DeviceLocalAccountPolicyService::GetPolicyService(
    const std::string& account_id) {
  const std::string key = GetAccountKey(account_id);
  auto entry = policy_map_.find(key);
  if (entry == policy_map_.end())
    return NULL;

  // Lazily create and initialize the policy service instance.
  if (!entry->second) {
    const base::FilePath policy_path =
        device_local_account_dir_.AppendASCII(key)
            .Append(kPolicyDir)
            .Append(kPolicyFileName);
    if (!base::CreateDirectory(policy_path.DirName())) {
      LOG(ERROR) << "Failed to create directory for " << policy_path.value();
      return NULL;
    }

    auto store = std::make_unique<PolicyStore>(policy_path);
    if (!store->LoadOrCreate()) {
      // This is non-fatal, the policy may not have been stored yet.
      LOG(WARNING) << "Failed to load policy for device-local account "
                   << account_id;
    }
    entry->second =
        std::make_unique<PolicyService>(std::move(store), owner_key_);
  }

  return entry->second.get();
}

std::string DeviceLocalAccountPolicyService::GetAccountKey(
    const std::string& account_id) {
  return brillo::cryptohome::home::SanitizeUserName(account_id);
}

bool DeviceLocalAccountPolicyService::IsValidAccountKey(
    const std::string& str) {
  return brillo::cryptohome::home::IsSanitizedUserName(str);
}

}  // namespace login_manager
