| // 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 <stdint.h> |
| |
| #include <base/files/file_enumerator.h> |
| #include <base/files/file_util.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 "bindings/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_t* policy_data, |
| uint32_t policy_data_size, |
| PolicyService::Completion completion) { |
| PolicyService* service = GetPolicyService(account_id); |
| if (!service) { |
| PolicyService::Error error(dbus_error::kInvalidAccount, |
| "Invalid device-local account"); |
| completion.Run(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_t>* 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 = base::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 |