blob: f6b5f9ecd20af455d63fac83892c9f5973254abe [file] [log] [blame]
// Copyright 2020 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/updater/dm_storage.h"
#include <set>
#include <utility>
#include "base/base64.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/files/important_file_writer.h"
#include "base/strings/string16.h"
#include "base/strings/sys_string_conversions.h"
#include "chrome/updater/dm_cached_policy_info.h"
#include "chrome/updater/dm_policy_manager.h"
#include "components/policy/proto/device_management_backend.pb.h"
namespace updater {
namespace {
// This DM Token value is persisted if the server asks the client to invalidate
// the DM Token.
constexpr char kInvalidTokenValue[] = "INVALID_DM_TOKEN";
// This is the standard name for the file that PersistPolicies() uses to store
// a PolicyFetchResponse received from the DMServer during the previous request.
// The data within the PolicyFetchResponse, such as the public key, version, and
// timestamp are used for subsequent requests and validations of DMServer
// responses.
constexpr char kPolicyInfoFileName[] = "CachedPolicyInfo";
// This is the standard name for the file that PersistPolicies() uses for each
// {policy_type} that it receives from the DMServer.
constexpr char kPolicyFileName[] = "PolicyFetchResponse";
// The policy type for Omaha policy settings.
constexpr char kGoogleUpdatePolicyType[] = "google/machine-level-omaha";
// Deletes the child directories in cache root if they do not appear in
// set |policy_types_base64|.
bool DeleteObsoletePolicies(const base::FilePath& cache_root,
const std::set<std::string>& policy_types_base64) {
bool result = true;
base::FileEnumerator cached_files(cache_root,
/* recursive */ false,
base::FileEnumerator::DIRECTORIES,
FILE_PATH_LITERAL("*"));
for (base::FilePath file = cached_files.Next(); !file.empty();
file = cached_files.Next()) {
const std::string file_base_name = file.BaseName().MaybeAsASCII();
if (policy_types_base64.count(file_base_name))
continue;
if (!base::DeleteFileRecursively(file))
result = false;
}
return result;
}
} // namespace
DMStorage::DMStorage(const base::FilePath& policy_cache_root,
std::unique_ptr<TokenServiceInterface> token_service)
: policy_cache_root_(policy_cache_root),
token_service_(std::move(token_service)) {
DCHECK(token_service_);
}
DMStorage::~DMStorage() = default;
bool DMStorage::DeregisterDevice() {
return token_service_->StoreDmToken(kInvalidTokenValue);
}
bool DMStorage::IsValidDMToken() {
std::string dm_token = GetDmToken();
return !dm_token.empty() && dm_token != kInvalidTokenValue;
}
bool DMStorage::PersistPolicies(const std::string& policy_info_data,
const DMPolicyMap& policy_map) const {
// Persists policy cached info
base::FilePath policy_info_file =
policy_cache_root_.AppendASCII(kPolicyInfoFileName);
if (!base::ImportantFileWriter::WriteFileAtomically(policy_info_file,
policy_info_data)) {
return false;
}
// Persists individual policies.
std::set<std::string> policy_types_base64;
for (const auto& policy_entry : policy_map) {
const std::string& policy_type = policy_entry.first;
const std::string& policy_value = policy_entry.second;
std::string encoded_policy_type;
base::Base64Encode(policy_type, &encoded_policy_type);
policy_types_base64.emplace(encoded_policy_type);
base::FilePath policy_dir =
policy_cache_root_.AppendASCII(encoded_policy_type);
if (!base::CreateDirectory(policy_dir))
return false;
base::FilePath policy_file = policy_dir.AppendASCII(kPolicyFileName);
if (!base::ImportantFileWriter::WriteFileAtomically(policy_file,
policy_value)) {
return false;
}
}
// Purge all stale policies not in |policy_types_base64|.
return DeleteObsoletePolicies(policy_cache_root_, policy_types_base64);
}
std::unique_ptr<CachedPolicyInfo> DMStorage::GetCachedPolicyInfo() {
if (!IsValidDMToken())
return nullptr;
base::FilePath policy_info_file =
policy_cache_root_.AppendASCII(kPolicyInfoFileName);
std::string policy_info_data;
auto cached_info = std::make_unique<CachedPolicyInfo>();
if (!base::PathExists(policy_info_file) ||
!base::ReadFileToString(policy_info_file, &policy_info_data) ||
!cached_info->Populate(policy_info_data)) {
return nullptr;
}
return cached_info;
}
std::unique_ptr<PolicyManagerInterface> DMStorage::GetOmahaPolicyManager() {
if (!IsValidDMToken())
return nullptr;
std::string encoded_omaha_policy_type;
base::Base64Encode(kGoogleUpdatePolicyType, &encoded_omaha_policy_type);
base::FilePath omaha_policy_file =
policy_cache_root_.AppendASCII(encoded_omaha_policy_type)
.AppendASCII(kPolicyFileName);
std::string response_data;
::enterprise_management::PolicyFetchResponse response;
::enterprise_management::PolicyData policy_data;
::wireless_android_enterprise_devicemanagement::OmahaSettingsClientProto
omaha_settings;
if (!base::PathExists(omaha_policy_file) ||
!base::ReadFileToString(omaha_policy_file, &response_data) ||
response_data.empty() || !response.ParseFromString(response_data) ||
!policy_data.ParseFromString(response.policy_data()) ||
!policy_data.has_policy_value() ||
!omaha_settings.ParseFromString(policy_data.policy_value())) {
return nullptr;
}
return std::make_unique<DMPolicyManager>(omaha_settings);
}
} // namespace updater