// 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 "chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.h"

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/file_util.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/sequenced_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/chromeos/policy/user_policy_disk_cache.h"
#include "chrome/browser/chromeos/policy/user_policy_token_loader.h"
#include "chromeos/dbus/cryptohome_client.h"
#include "chromeos/dbus/session_manager_client.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "policy/proto/cloud_policy.pb.h"
#include "policy/proto/device_management_local.pb.h"

namespace em = enterprise_management;

namespace policy {

namespace {

// Path within |user_policy_key_dir_| that contains the policy key.
// "%s" must be substituted with the sanitized username.
const base::FilePath::CharType kPolicyKeyFile[] =
    FILE_PATH_LITERAL("%s/policy.pub");

// Maximum key size that will be loaded, in bytes.
const int kKeySizeLimit = 16 * 1024;

enum ValidationFailure {
  VALIDATION_FAILURE_DBUS,
  VALIDATION_FAILURE_LOAD_KEY,
  VALIDATION_FAILURE_SIZE,
};

void SampleValidationFailure(ValidationFailure sample) {
  UMA_HISTOGRAM_ENUMERATION("Enterprise.UserPolicyValidationFailure",
                            sample,
                            VALIDATION_FAILURE_SIZE);
}

}  // namespace

// Helper class for loading legacy policy caches.
class LegacyPolicyCacheLoader : public UserPolicyTokenLoader::Delegate,
                                public UserPolicyDiskCache::Delegate {
 public:
  typedef base::Callback<void(const std::string&,
                              const std::string&,
                              CloudPolicyStore::Status,
                              scoped_ptr<em::PolicyFetchResponse>)> Callback;

  LegacyPolicyCacheLoader(
      const base::FilePath& token_cache_file,
      const base::FilePath& policy_cache_file,
      scoped_refptr<base::SequencedTaskRunner> background_task_runner);
  virtual ~LegacyPolicyCacheLoader();

  // Starts loading, and reports the result to |callback| when done.
  void Load(const Callback& callback);

  // UserPolicyTokenLoader::Delegate:
  virtual void OnTokenLoaded(const std::string& token,
                             const std::string& device_id) OVERRIDE;

  // UserPolicyDiskCache::Delegate:
  virtual void OnDiskCacheLoaded(
      UserPolicyDiskCache::LoadResult result,
      const em::CachedCloudPolicyResponse& policy) OVERRIDE;

 private:
  // Checks whether the load operations from the legacy caches completed. If so,
  // fires the appropriate notification.
  void CheckLoadFinished();

  // Maps a disk cache LoadResult to a CloudPolicyStore::Status.
  static CloudPolicyStore::Status TranslateLoadResult(
      UserPolicyDiskCache::LoadResult result);

  base::WeakPtrFactory<LegacyPolicyCacheLoader> weak_factory_;

  scoped_refptr<UserPolicyTokenLoader> token_loader_;
  scoped_refptr<UserPolicyDiskCache> policy_cache_;

  std::string dm_token_;
  std::string device_id_;
  bool has_policy_;
  scoped_ptr<em::PolicyFetchResponse> policy_;
  CloudPolicyStore::Status status_;

  Callback callback_;

  DISALLOW_COPY_AND_ASSIGN(LegacyPolicyCacheLoader);
};

LegacyPolicyCacheLoader::LegacyPolicyCacheLoader(
    const base::FilePath& token_cache_file,
    const base::FilePath& policy_cache_file,
    scoped_refptr<base::SequencedTaskRunner> background_task_runner)
    : weak_factory_(this),
      has_policy_(false),
      status_(CloudPolicyStore::STATUS_OK) {
  token_loader_ = new UserPolicyTokenLoader(weak_factory_.GetWeakPtr(),
                                            token_cache_file,
                                            background_task_runner);
  policy_cache_ = new UserPolicyDiskCache(weak_factory_.GetWeakPtr(),
                                          policy_cache_file,
                                          background_task_runner);
}

LegacyPolicyCacheLoader::~LegacyPolicyCacheLoader() {}

void LegacyPolicyCacheLoader::Load(const Callback& callback) {
  callback_ = callback;
  token_loader_->Load();
  policy_cache_->Load();
}

void LegacyPolicyCacheLoader::OnTokenLoaded(const std::string& token,
                                            const std::string& device_id) {
  dm_token_ = token;
  device_id_ = device_id;
  token_loader_ = NULL;
  CheckLoadFinished();
}

void LegacyPolicyCacheLoader::OnDiskCacheLoaded(
    UserPolicyDiskCache::LoadResult result,
    const em::CachedCloudPolicyResponse& policy) {
  status_ = TranslateLoadResult(result);
  if (result == UserPolicyDiskCache::LOAD_RESULT_SUCCESS) {
    if (policy.has_cloud_policy())
      policy_.reset(new em::PolicyFetchResponse(policy.cloud_policy()));
  } else {
    LOG(WARNING) << "Failed to load legacy policy cache: " << result;
  }
  policy_cache_ = NULL;
  CheckLoadFinished();
}

void LegacyPolicyCacheLoader::CheckLoadFinished() {
  if (!token_loader_.get() && !policy_cache_.get())
    callback_.Run(dm_token_, device_id_, status_, policy_.Pass());
}

// static
CloudPolicyStore::Status LegacyPolicyCacheLoader::TranslateLoadResult(
    UserPolicyDiskCache::LoadResult result) {
  switch (result) {
    case UserPolicyDiskCache::LOAD_RESULT_SUCCESS:
    case UserPolicyDiskCache::LOAD_RESULT_NOT_FOUND:
      return CloudPolicyStore::STATUS_OK;
    case UserPolicyDiskCache::LOAD_RESULT_PARSE_ERROR:
    case UserPolicyDiskCache::LOAD_RESULT_READ_ERROR:
      return CloudPolicyStore::STATUS_LOAD_ERROR;
  }
  NOTREACHED();
  return CloudPolicyStore::STATUS_OK;
}

UserCloudPolicyStoreChromeOS::UserCloudPolicyStoreChromeOS(
    chromeos::CryptohomeClient* cryptohome_client,
    chromeos::SessionManagerClient* session_manager_client,
    scoped_refptr<base::SequencedTaskRunner> background_task_runner,
    const std::string& username,
    const base::FilePath& user_policy_key_dir,
    const base::FilePath& legacy_token_cache_file,
    const base::FilePath& legacy_policy_cache_file)
    : UserCloudPolicyStoreBase(background_task_runner),
      cryptohome_client_(cryptohome_client),
      session_manager_client_(session_manager_client),
      username_(username),
      user_policy_key_dir_(user_policy_key_dir),
      weak_factory_(this),
      legacy_cache_dir_(legacy_token_cache_file.DirName()),
      legacy_loader_(new LegacyPolicyCacheLoader(legacy_token_cache_file,
                                                 legacy_policy_cache_file,
                                                 background_task_runner)),
      legacy_caches_loaded_(false),
      policy_key_loaded_(false) {}

UserCloudPolicyStoreChromeOS::~UserCloudPolicyStoreChromeOS() {}

void UserCloudPolicyStoreChromeOS::Store(
    const em::PolicyFetchResponse& policy) {
  // Cancel all pending requests.
  weak_factory_.InvalidateWeakPtrs();
  scoped_ptr<em::PolicyFetchResponse> response(
      new em::PolicyFetchResponse(policy));
  EnsurePolicyKeyLoaded(
      base::Bind(&UserCloudPolicyStoreChromeOS::ValidatePolicyForStore,
                 weak_factory_.GetWeakPtr(),
                 base::Passed(&response)));
}

void UserCloudPolicyStoreChromeOS::Load() {
  // Cancel all pending requests.
  weak_factory_.InvalidateWeakPtrs();
  session_manager_client_->RetrievePolicyForUser(
      username_,
      base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyRetrieved,
                 weak_factory_.GetWeakPtr()));
}

void UserCloudPolicyStoreChromeOS::LoadImmediately() {
  // This blocking DBus call is in the startup path and will block the UI
  // thread. This only happens when the Profile is created synchronously, which
  // on ChromeOS happens whenever the browser is restarted into the same
  // session. That happens when the browser crashes, or right after signin if
  // the user has flags configured in about:flags.
  // However, on those paths we must load policy synchronously so that the
  // Profile initialization never sees unmanaged prefs, which would lead to
  // data loss. http://crbug.com/263061
  std::string policy_blob =
      session_manager_client_->BlockingRetrievePolicyForUser(username_);
  if (policy_blob.empty()) {
    // The session manager doesn't have policy, or the call failed.
    // Just notify that the load is done, and don't bother with the legacy
    // caches in this case.
    NotifyStoreLoaded();
    return;
  }

  scoped_ptr<em::PolicyFetchResponse> policy(new em::PolicyFetchResponse());
  if (!policy->ParseFromString(policy_blob)) {
    status_ = STATUS_PARSE_ERROR;
    NotifyStoreError();
    return;
  }

  std::string sanitized_username =
      cryptohome_client_->BlockingGetSanitizedUsername(username_);
  if (sanitized_username.empty()) {
    status_ = STATUS_LOAD_ERROR;
    NotifyStoreError();
    return;
  }

  policy_key_path_ = user_policy_key_dir_.Append(
      base::StringPrintf(kPolicyKeyFile, sanitized_username.c_str()));
  LoadPolicyKey(policy_key_path_, &policy_key_);
  policy_key_loaded_ = true;

  scoped_ptr<UserCloudPolicyValidator> validator =
      CreateValidator(policy.Pass(),
                      CloudPolicyValidatorBase::TIMESTAMP_REQUIRED);
  validator->ValidateUsername(username_);
  const bool allow_rotation = false;
  validator->ValidateSignature(policy_key_, allow_rotation);
  validator->RunValidation();
  OnRetrievedPolicyValidated(validator.get());
}

void UserCloudPolicyStoreChromeOS::ValidatePolicyForStore(
    scoped_ptr<em::PolicyFetchResponse> policy) {
  // Create and configure a validator.
  scoped_ptr<UserCloudPolicyValidator> validator =
      CreateValidator(policy.Pass(),
                      CloudPolicyValidatorBase::TIMESTAMP_REQUIRED);
  validator->ValidateUsername(username_);
  if (policy_key_.empty()) {
    validator->ValidateInitialKey();
  } else {
    const bool allow_rotation = true;
    validator->ValidateSignature(policy_key_, allow_rotation);
  }

  // Start validation. The Validator will delete itself once validation is
  // complete.
  validator.release()->StartValidation(
      base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated,
                 weak_factory_.GetWeakPtr()));
}

void UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated(
    UserCloudPolicyValidator* validator) {
  validation_status_ = validator->status();

  UMA_HISTOGRAM_ENUMERATION(
      "Enterprise.UserPolicyValidationStoreStatus",
      validation_status_,
      UserCloudPolicyValidator::VALIDATION_POLICY_PARSE_ERROR + 1);

  if (!validator->success()) {
    status_ = STATUS_VALIDATION_ERROR;
    NotifyStoreError();
    return;
  }

  std::string policy_blob;
  if (!validator->policy()->SerializeToString(&policy_blob)) {
    status_ = STATUS_SERIALIZE_ERROR;
    NotifyStoreError();
    return;
  }

  session_manager_client_->StorePolicyForUser(
      username_,
      policy_blob,
      validator->policy()->new_public_key(),
      base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyStored,
                 weak_factory_.GetWeakPtr()));
}

void UserCloudPolicyStoreChromeOS::OnPolicyStored(bool success) {
  if (!success) {
    status_ = STATUS_STORE_ERROR;
    NotifyStoreError();
  } else {
    // Load the policy right after storing it, to make sure it was accepted by
    // the session manager. An additional validation is performed after the
    // load; reload the key for that validation too, in case it was rotated.
    ReloadPolicyKey(base::Bind(&UserCloudPolicyStoreChromeOS::Load,
                               weak_factory_.GetWeakPtr()));
  }
}

void UserCloudPolicyStoreChromeOS::OnPolicyRetrieved(
    const std::string& policy_blob) {
  if (policy_blob.empty()) {
    // Policy fetch failed. Try legacy caches if we haven't done that already.
    if (!legacy_caches_loaded_ && legacy_loader_.get()) {
      legacy_caches_loaded_ = true;
      legacy_loader_->Load(
          base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished,
                     weak_factory_.GetWeakPtr()));
    } else {
      // session_manager doesn't have policy. Adjust internal state and notify
      // the world about the policy update.
      policy_.reset();
      NotifyStoreLoaded();
    }
    return;
  }

  // Policy is supplied by session_manager. Disregard legacy data from now on.
  legacy_loader_.reset();

  scoped_ptr<em::PolicyFetchResponse> policy(new em::PolicyFetchResponse());
  if (!policy->ParseFromString(policy_blob)) {
    status_ = STATUS_PARSE_ERROR;
    NotifyStoreError();
    return;
  }

  // Load |policy_key_| to verify the loaded policy.
  EnsurePolicyKeyLoaded(
      base::Bind(&UserCloudPolicyStoreChromeOS::ValidateRetrievedPolicy,
                 weak_factory_.GetWeakPtr(),
                 base::Passed(&policy)));
}

void UserCloudPolicyStoreChromeOS::ValidateRetrievedPolicy(
    scoped_ptr<em::PolicyFetchResponse> policy) {
  // Create and configure a validator for the loaded policy.
  scoped_ptr<UserCloudPolicyValidator> validator =
      CreateValidator(policy.Pass(),
                      CloudPolicyValidatorBase::TIMESTAMP_REQUIRED);
  validator->ValidateUsername(username_);
  const bool allow_rotation = false;
  validator->ValidateSignature(policy_key_, allow_rotation);
  // Start validation. The Validator will delete itself once validation is
  // complete.
  validator.release()->StartValidation(
      base::Bind(&UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated,
                 weak_factory_.GetWeakPtr()));
}

void UserCloudPolicyStoreChromeOS::OnRetrievedPolicyValidated(
    UserCloudPolicyValidator* validator) {
  validation_status_ = validator->status();

  UMA_HISTOGRAM_ENUMERATION(
      "Enterprise.UserPolicyValidationLoadStatus",
      validation_status_,
      UserCloudPolicyValidator::VALIDATION_POLICY_PARSE_ERROR + 1);

  if (!validator->success()) {
    status_ = STATUS_VALIDATION_ERROR;
    NotifyStoreError();
    return;
  }

  InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
  status_ = STATUS_OK;

  // Policy has been loaded successfully. This indicates that new-style policy
  // is working, so the legacy cache directory can be removed.
  if (!legacy_cache_dir_.empty()) {
    background_task_runner()->PostTask(
        FROM_HERE,
        base::Bind(&UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir,
                   legacy_cache_dir_));
    legacy_cache_dir_.clear();
  }
  NotifyStoreLoaded();
}

void UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished(
    const std::string& dm_token,
    const std::string& device_id,
    Status status,
    scoped_ptr<em::PolicyFetchResponse> policy) {
  status_ = status;
  if (policy.get()) {
    // Create and configure a validator for the loaded legacy policy. Note that
    // the signature on this policy is not verified.
    scoped_ptr<UserCloudPolicyValidator> validator =
        CreateValidator(policy.Pass(),
                        CloudPolicyValidatorBase::TIMESTAMP_REQUIRED);
    validator->ValidateUsername(username_);
    validator.release()->StartValidation(
        base::Bind(&UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated,
                   weak_factory_.GetWeakPtr(),
                   dm_token,
                   device_id));
  } else {
    InstallLegacyTokens(dm_token, device_id);
  }
}

void UserCloudPolicyStoreChromeOS::OnLegacyPolicyValidated(
    const std::string& dm_token,
    const std::string& device_id,
    UserCloudPolicyValidator* validator) {
  validation_status_ = validator->status();
  if (validator->success()) {
    status_ = STATUS_OK;
    InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());

    // Clear the public key version. The public key version field would
    // otherwise indicate that we have key installed in the store when in fact
    // we haven't. This may result in policy updates failing signature
    // verification.
    policy_->clear_public_key_version();
  } else {
    status_ = STATUS_VALIDATION_ERROR;
  }

  InstallLegacyTokens(dm_token, device_id);
}

void UserCloudPolicyStoreChromeOS::InstallLegacyTokens(
    const std::string& dm_token,
    const std::string& device_id) {
  // Write token and device ID to |policy_|, giving them precedence over the
  // policy blob. This is to match the legacy behavior, which used token and
  // device id exclusively from the token cache file.
  if (!dm_token.empty() && !device_id.empty()) {
    if (!policy_.get())
      policy_.reset(new em::PolicyData());
    policy_->set_request_token(dm_token);
    policy_->set_device_id(device_id);
  }

  // Tell the rest of the world that the policy load completed.
  NotifyStoreLoaded();
}

// static
void UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir(
    const base::FilePath& dir) {
  if (base::PathExists(dir) && !base::DeleteFile(dir, true))
    LOG(ERROR) << "Failed to remove cache dir " << dir.value();
}

void UserCloudPolicyStoreChromeOS::ReloadPolicyKey(
    const base::Closure& callback) {
  std::vector<uint8>* key = new std::vector<uint8>();
  background_task_runner()->PostTaskAndReply(
      FROM_HERE,
      base::Bind(&UserCloudPolicyStoreChromeOS::LoadPolicyKey,
                 policy_key_path_,
                 key),
      base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyKeyReloaded,
                 weak_factory_.GetWeakPtr(),
                 base::Owned(key),
                 callback));
}

// static
void UserCloudPolicyStoreChromeOS::LoadPolicyKey(const base::FilePath& path,
                                                 std::vector<uint8>* key) {
  if (!base::PathExists(path)) {
    // There is no policy key the first time that a user fetches policy. If
    // |path| does not exist then that is the most likely scenario, so there's
    // no need to sample a failure.
    VLOG(1) << "No key at " << path.value();
    return;
  }

  int64 size;
  if (!base::GetFileSize(path, &size)) {
    LOG(ERROR) << "Could not get size of " << path.value();
  } else if (size == 0 || size > kKeySizeLimit) {
    LOG(ERROR) << "Key at " << path.value() << " has bad size " << size;
  } else {
    key->resize(size);
    int read_size = base::ReadFile(
        path, reinterpret_cast<char*>(vector_as_array(key)), size);
    if (read_size != size) {
      LOG(ERROR) << "Failed to read key at " << path.value();
      key->clear();
    }
  }

  if (key->empty())
    SampleValidationFailure(VALIDATION_FAILURE_LOAD_KEY);
}

void UserCloudPolicyStoreChromeOS::OnPolicyKeyReloaded(
    std::vector<uint8>* key,
    const base::Closure& callback) {
  policy_key_.swap(*key);
  policy_key_loaded_ = true;
  callback.Run();
}

void UserCloudPolicyStoreChromeOS::EnsurePolicyKeyLoaded(
    const base::Closure& callback) {
  if (policy_key_loaded_) {
    callback.Run();
  } else {
    // Get the hashed username that's part of the key's path, to determine
    // |policy_key_path_|.
    cryptohome_client_->GetSanitizedUsername(username_,
        base::Bind(&UserCloudPolicyStoreChromeOS::OnGetSanitizedUsername,
                   weak_factory_.GetWeakPtr(),
                   callback));
  }
}

void UserCloudPolicyStoreChromeOS::OnGetSanitizedUsername(
    const base::Closure& callback,
    chromeos::DBusMethodCallStatus call_status,
    const std::string& sanitized_username) {
  // The default empty path will always yield an empty key.
  if (call_status == chromeos::DBUS_METHOD_CALL_SUCCESS &&
      !sanitized_username.empty()) {
    policy_key_path_ = user_policy_key_dir_.Append(
        base::StringPrintf(kPolicyKeyFile, sanitized_username.c_str()));
  } else {
    SampleValidationFailure(VALIDATION_FAILURE_DBUS);
  }
  ReloadPolicyKey(callback);
}

}  // namespace policy
