This source file includes following definitions.
- LoadPolicyFromDisk
 
- WriteStringToFile
 
- StorePolicyToDiskOnBackgroundThread
 
- verification_key_
 
- Create
 
- SetSigninUsername
 
- LoadImmediately
 
- Clear
 
- Load
 
- PolicyLoaded
 
- InstallLoadedPolicyAfterValidation
 
- Validate
 
- StorePolicyAfterValidation
 
#include "components/policy/core/common/cloud/user_cloud_policy_store.h"
#include "base/bind.h"
#include "base/file_util.h"
#include "base/location.h"
#include "base/metrics/histogram.h"
#include "base/task_runner_util.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "policy/proto/cloud_policy.pb.h"
#include "policy/proto/device_management_backend.pb.h"
#include "policy/proto/policy_signing_key.pb.h"
namespace em = enterprise_management;
namespace policy {
enum PolicyLoadStatus {
  
  LOAD_RESULT_SUCCESS,
  
  LOAD_RESULT_NO_POLICY_FILE,
  
  
  LOAD_RESULT_LOAD_ERROR,
};
struct PolicyLoadResult {
  PolicyLoadStatus status;
  em::PolicyFetchResponse policy;
  em::PolicySigningKey key;
};
namespace {
const base::FilePath::CharType kPolicyDir[] = FILE_PATH_LITERAL("Policy");
const base::FilePath::CharType kPolicyCacheFile[] =
    FILE_PATH_LITERAL("User Policy");
const base::FilePath::CharType kKeyCacheFile[] =
    FILE_PATH_LITERAL("Signing Key");
const char kMetricPolicyHasVerifiedCachedKey[] =
    "Enterprise.PolicyHasVerifiedCachedKey";
const size_t kPolicySizeLimit = 1024 * 1024;
const size_t kKeySizeLimit = 16 * 1024;
policy::PolicyLoadResult LoadPolicyFromDisk(
    const base::FilePath& policy_path,
    const base::FilePath& key_path) {
  policy::PolicyLoadResult result;
  
  
  
  if (!base::PathExists(policy_path)) {
    result.status = policy::LOAD_RESULT_NO_POLICY_FILE;
    return result;
  }
  std::string data;
  if (!base::ReadFileToString(policy_path, &data, kPolicySizeLimit) ||
      !result.policy.ParseFromString(data)) {
    LOG(WARNING) << "Failed to read or parse policy data from "
                 << policy_path.value();
    result.status = policy::LOAD_RESULT_LOAD_ERROR;
    return result;
  }
  if (!base::ReadFileToString(key_path, &data, kKeySizeLimit) ||
      !result.key.ParseFromString(data)) {
    
    
    
    
    LOG(ERROR) << "Failed to read or parse key data from " << key_path.value();
    result.key.clear_signing_key();
  }
  
  
  
  UMA_HISTOGRAM_BOOLEAN(kMetricPolicyHasVerifiedCachedKey,
                        result.key.has_signing_key());
  result.status = policy::LOAD_RESULT_SUCCESS;
  return result;
}
bool WriteStringToFile(const base::FilePath path, const std::string& data) {
 if (!base::CreateDirectory(path.DirName())) {
    DLOG(WARNING) << "Failed to create directory " << path.DirName().value();
    return false;
  }
  int size = data.size();
  if (base::WriteFile(path, data.c_str(), size) != size) {
    DLOG(WARNING) << "Failed to write " << path.value();
    return false;
  }
  return true;
}
void StorePolicyToDiskOnBackgroundThread(
    const base::FilePath& policy_path,
    const base::FilePath& key_path,
    const std::string& verification_key,
    const em::PolicyFetchResponse& policy) {
  DVLOG(1) << "Storing policy to " << policy_path.value();
  std::string data;
  if (!policy.SerializeToString(&data)) {
    DLOG(WARNING) << "Failed to serialize policy data";
    return;
  }
  if (!WriteStringToFile(policy_path, data))
    return;
  if (policy.has_new_public_key()) {
    
    em::PolicySigningKey key_info;
    key_info.set_signing_key(policy.new_public_key());
    key_info.set_signing_key_signature(
        policy.new_public_key_verification_signature());
    key_info.set_verification_key(verification_key);
    std::string key_data;
    if (!key_info.SerializeToString(&key_data)) {
      DLOG(WARNING) << "Failed to serialize policy signing key";
      return;
    }
    WriteStringToFile(key_path, key_data);
  }
}
}  
UserCloudPolicyStore::UserCloudPolicyStore(
    const base::FilePath& policy_path,
    const base::FilePath& key_path,
    const std::string& verification_key,
    scoped_refptr<base::SequencedTaskRunner> background_task_runner)
    : UserCloudPolicyStoreBase(background_task_runner),
      weak_factory_(this),
      policy_path_(policy_path),
      key_path_(key_path),
      verification_key_(verification_key) {}
UserCloudPolicyStore::~UserCloudPolicyStore() {}
scoped_ptr<UserCloudPolicyStore> UserCloudPolicyStore::Create(
    const base::FilePath& profile_path,
    const std::string& verification_key,
    scoped_refptr<base::SequencedTaskRunner> background_task_runner) {
  base::FilePath policy_path =
      profile_path.Append(kPolicyDir).Append(kPolicyCacheFile);
  base::FilePath key_path =
      profile_path.Append(kPolicyDir).Append(kKeyCacheFile);
  return make_scoped_ptr(new UserCloudPolicyStore(
      policy_path, key_path, verification_key, background_task_runner));
}
void UserCloudPolicyStore::SetSigninUsername(const std::string& username) {
  signin_username_ = username;
}
void UserCloudPolicyStore::LoadImmediately() {
  DVLOG(1) << "Initiating immediate policy load from disk";
  
  weak_factory_.InvalidateWeakPtrs();
  
  PolicyLoadResult result = LoadPolicyFromDisk(policy_path_, key_path_);
  
  PolicyLoaded(false, result);
}
void UserCloudPolicyStore::Clear() {
  background_task_runner()->PostTask(
      FROM_HERE,
      base::Bind(base::IgnoreResult(&base::DeleteFile), policy_path_, false));
  background_task_runner()->PostTask(
      FROM_HERE,
      base::Bind(base::IgnoreResult(&base::DeleteFile), key_path_, false));
  policy_.reset();
  policy_map_.Clear();
  policy_key_.clear();
  NotifyStoreLoaded();
}
void UserCloudPolicyStore::Load() {
  DVLOG(1) << "Initiating policy load from disk";
  
  weak_factory_.InvalidateWeakPtrs();
  
  
  base::PostTaskAndReplyWithResult(
      background_task_runner(),
      FROM_HERE,
      base::Bind(&LoadPolicyFromDisk, policy_path_, key_path_),
      base::Bind(&UserCloudPolicyStore::PolicyLoaded,
                 weak_factory_.GetWeakPtr(), true));
}
void UserCloudPolicyStore::PolicyLoaded(bool validate_in_background,
                                        PolicyLoadResult result) {
  switch (result.status) {
    case LOAD_RESULT_LOAD_ERROR:
      status_ = STATUS_LOAD_ERROR;
      NotifyStoreError();
      break;
    case LOAD_RESULT_NO_POLICY_FILE:
      DVLOG(1) << "No policy found on disk";
      NotifyStoreLoaded();
      break;
    case LOAD_RESULT_SUCCESS: {
      
      scoped_ptr<em::PolicyFetchResponse> cloud_policy(
          new em::PolicyFetchResponse(result.policy));
      scoped_ptr<em::PolicySigningKey> key(
          new em::PolicySigningKey(result.key));
      bool doing_key_rotation = false;
      const std::string& verification_key = verification_key_;
      if (!key->has_verification_key() ||
          key->verification_key() != verification_key_) {
        
        
        
        doing_key_rotation = true;
        DLOG(WARNING) << "Verification key rotation detected";
        
        
        
      }
      Validate(cloud_policy.Pass(),
               key.Pass(),
               verification_key,
               validate_in_background,
               base::Bind(
                   &UserCloudPolicyStore::InstallLoadedPolicyAfterValidation,
                   weak_factory_.GetWeakPtr(),
                   doing_key_rotation,
                   result.key.has_signing_key() ?
                       result.key.signing_key() : std::string()));
      break;
    }
    default:
      NOTREACHED();
  }
}
void UserCloudPolicyStore::InstallLoadedPolicyAfterValidation(
    bool doing_key_rotation,
    const std::string& signing_key,
    UserCloudPolicyValidator* validator) {
  validation_status_ = validator->status();
  if (!validator->success()) {
    DVLOG(1) << "Validation failed: status=" << validation_status_;
    status_ = STATUS_VALIDATION_ERROR;
    NotifyStoreError();
    return;
  }
  DVLOG(1) << "Validation succeeded - installing policy with dm_token: " <<
      validator->policy_data()->request_token();
  DVLOG(1) << "Device ID: " << validator->policy_data()->device_id();
  
  
  if (doing_key_rotation) {
    validator->policy_data()->clear_public_key_version();
    policy_key_.clear();
  } else {
    
    policy_key_ = signing_key;
  }
  InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
  status_ = STATUS_OK;
  NotifyStoreLoaded();
}
void UserCloudPolicyStore::Store(const em::PolicyFetchResponse& policy) {
  
  
  weak_factory_.InvalidateWeakPtrs();
  scoped_ptr<em::PolicyFetchResponse> policy_copy(
      new em::PolicyFetchResponse(policy));
  Validate(policy_copy.Pass(),
           scoped_ptr<em::PolicySigningKey>(),
           verification_key_,
           true,
           base::Bind(&UserCloudPolicyStore::StorePolicyAfterValidation,
                      weak_factory_.GetWeakPtr()));
}
void UserCloudPolicyStore::Validate(
    scoped_ptr<em::PolicyFetchResponse> policy,
    scoped_ptr<em::PolicySigningKey> cached_key,
    const std::string& verification_key,
    bool validate_in_background,
    const UserCloudPolicyValidator::CompletionCallback& callback) {
  const bool signed_policy = policy->has_policy_data_signature();
  
  scoped_ptr<UserCloudPolicyValidator> validator = CreateValidator(
      policy.Pass(),
      CloudPolicyValidatorBase::TIMESTAMP_NOT_BEFORE);
  
  
  
  
  
  
  std::string owning_domain;
  
  
  
  if (!signin_username_.empty()) {
    DVLOG(1) << "Validating username: " << signin_username_;
    validator->ValidateUsername(signin_username_, true);
    owning_domain = gaia::ExtractDomainName(
        gaia::CanonicalizeEmail(gaia::SanitizeEmail(signin_username_)));
  }
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  if (cached_key) {
    
    DCHECK(policy_key_.empty() || policy_key_ == cached_key->signing_key());
    if (!signed_policy || !cached_key->has_signing_key()) {
      
      
      
      DLOG(WARNING) << "Allowing unsigned cached blob for migration";
    } else {
      
      
      
      validator->ValidateCachedKey(cached_key->signing_key(),
                                   cached_key->signing_key_signature(),
                                   verification_key,
                                   owning_domain);
      const bool no_rotation = false;
      validator->ValidateSignature(cached_key->signing_key(),
                                   verification_key,
                                   owning_domain,
                                   no_rotation);
    }
  } else {
    
    
    if (policy_key_.empty()) {
      
      
      
      validator->ValidateInitialKey(verification_key, owning_domain);
    } else {
      
      
      
      
      const bool allow_rotation = true;
      validator->ValidateSignature(
          policy_key_, verification_key, owning_domain, allow_rotation);
    }
  }
  if (validate_in_background) {
    
    
    validator.release()->StartValidation(callback);
  } else {
    
    validator->RunValidation();
    callback.Run(validator.get());
  }
}
void UserCloudPolicyStore::StorePolicyAfterValidation(
    UserCloudPolicyValidator* validator) {
  validation_status_ = validator->status();
  DVLOG(1) << "Policy validation complete: status = " << validation_status_;
  if (!validator->success()) {
    status_ = STATUS_VALIDATION_ERROR;
    NotifyStoreError();
    return;
  }
  
  
  background_task_runner()->PostTask(
      FROM_HERE,
      base::Bind(&StorePolicyToDiskOnBackgroundThread,
                 policy_path_, key_path_, verification_key_,
                 *validator->policy()));
  InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass());
  
  if (validator->policy()->has_new_public_key())
    policy_key_ = validator->policy()->new_public_key();
  status_ = STATUS_OK;
  NotifyStoreLoaded();
}
}