blob: b9c33130855fa44cdc51fd4a70ad401790037355 [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_policy_service.h"
#include <base/file_util.h>
#include <base/files/file_enumerator.h>
#include <base/logging.h>
#include <base/memory/ref_counted.h>
#include <base/memory/scoped_ptr.h>
#include <base/message_loop/message_loop_proxy.h>
#include <base/stl_util.h>
#include <base/strings/string_util.h>
#include <chromeos/cryptohome.h>
#include "login_manager/chrome_device_policy.pb.h"
#include "login_manager/dbus_error_types.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,
const scoped_refptr<base::MessageLoopProxy>& main_loop)
: device_local_account_dir_(device_local_account_dir),
owner_key_(owner_key),
main_loop_(main_loop) {
}
DeviceLocalAccountPolicyService::~DeviceLocalAccountPolicyService() {
STLDeleteValues(&policy_map_);
}
bool DeviceLocalAccountPolicyService::Store(const std::string& account_id,
const uint8* policy_data,
uint32 policy_data_size,
PolicyService::Completion* completion) {
PolicyService* service = GetPolicyService(account_id);
if (!service) {
PolicyService::Error error(dbus_error::kInvalidAccount,
"Invalid device-local account");
completion->ReportFailure(error);
return false;
}
// NB: Passing 0 for flags disallows all key changes.
return service->Store(policy_data, policy_data_size, completion, 0);
}
bool DeviceLocalAccountPolicyService::Retrieve(
const std::string& account_id,
std::vector<uint8>* policy_data) {
PolicyService* service = GetPolicyService(account_id);
if (!service)
return false;
return service->Retrieve(policy_data);
}
void DeviceLocalAccountPolicyService::UpdateDeviceSettings(
const em::ChromeDeviceSettingsProto& device_settings) {
// Update the policy map.
typedef google::protobuf::RepeatedPtrField<em::DeviceLocalAccountInfoProto>
DeviceLocalAccountList;
std::map<std::string, 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] = policy_map_[account_key];
policy_map_[account_key] = NULL;
}
}
policy_map_.swap(new_policy_map);
STLDeleteValues(&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 = StringToLowerASCII(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);
std::map<std::string, PolicyService*>::iterator 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;
}
scoped_ptr<PolicyStore> store(new 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 =
new PolicyService(store.Pass(), owner_key_, main_loop_);
}
return entry->second;
}
std::string DeviceLocalAccountPolicyService::GetAccountKey(
const std::string& account_id) {
return chromeos::cryptohome::home::SanitizeUserName(account_id);
}
bool DeviceLocalAccountPolicyService::IsValidAccountKey(
const std::string& str) {
return chromeos::cryptohome::home::IsSanitizedUserName(str);
}
} // namespace login_manager