blob: f2c0c88acf1ebf5f40c0136648dec210617da305 [file] [log] [blame]
// 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_manager.h"
#include <utility>
#include <base/files/file_enumerator.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/memory/ptr_util.h>
#include <base/strings/string_util.h>
#include <brillo/cryptohome.h>
#include "bindings/chrome_device_policy.pb.h"
#include "login_manager/policy_service.h"
#include "login_manager/policy_store.h"
namespace em = enterprise_management;
namespace login_manager {
// Device-local account state directory.
constexpr base::FilePath::CharType DeviceLocalAccountManager::kPolicyDir[] =
FILE_PATH_LITERAL("policy");
constexpr base::FilePath::CharType
DeviceLocalAccountManager::kPolicyFileName[] = FILE_PATH_LITERAL("policy");
DeviceLocalAccountManager::DeviceLocalAccountManager(
const base::FilePath& state_dir, PolicyKey* owner_key)
: state_dir_(state_dir), owner_key_(owner_key) {}
DeviceLocalAccountManager::~DeviceLocalAccountManager() = default;
void DeviceLocalAccountManager::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(state_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 DeviceLocalAccountManager::MigrateUppercaseDirs() {
base::FileEnumerator enumerator(state_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* DeviceLocalAccountManager::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 nullptr;
// Lazily create and initialize the policy service instance.
if (!entry->second) {
const base::FilePath policy_path =
state_dir_.AppendASCII(key).Append(kPolicyDir).Append(kPolicyFileName);
if (!base::CreateDirectory(policy_path.DirName())) {
LOG(ERROR) << "Failed to create directory for " << policy_path.value();
return nullptr;
}
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 DeviceLocalAccountManager::GetAccountKey(
const std::string& account_id) {
return brillo::cryptohome::home::SanitizeUserName(account_id);
}
bool DeviceLocalAccountManager::IsValidAccountKey(const std::string& str) {
return brillo::cryptohome::home::IsSanitizedUserName(str);
}
} // namespace login_manager