| // Copyright (c) 2012 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/browser/policy/configuration_policy_handler.h" |
| |
| #include <algorithm> |
| |
| #include "base/callback.h" |
| #include "base/files/file_path.h" |
| #include "base/json/json_writer.h" |
| #include "base/logging.h" |
| #include "base/prefs/pref_value_map.h" |
| #include "base/strings/string16.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| #include "chrome/browser/chrome_notification_types.h" |
| #include "chrome/browser/policy/configuration_policy_pref_store.h" |
| #include "chrome/browser/policy/external_data_fetcher.h" |
| #include "chrome/browser/policy/policy_error_map.h" |
| #include "chrome/browser/policy/policy_map.h" |
| #include "grit/generated_resources.h" |
| #include "policy/policy_constants.h" |
| #include "url/gurl.h" |
| |
| #if !defined(OS_ANDROID) |
| #include "chrome/browser/policy/policy_path_parser.h" |
| #endif |
| |
| namespace policy { |
| |
| namespace { |
| |
| // Helper function ------------------------------------------------------------- |
| |
| // Utility function that returns a JSON representation of the given |dict| as |
| // a StringValue. The caller owns the returned object. |
| base::StringValue* DictionaryToJSONString(const base::DictionaryValue* dict) { |
| std::string json_string; |
| base::JSONWriter::WriteWithOptions( |
| dict, |
| base::JSONWriter::OPTIONS_DO_NOT_ESCAPE | |
| base::JSONWriter::OPTIONS_PRETTY_PRINT, |
| &json_string); |
| return Value::CreateStringValue(json_string); |
| } |
| |
| |
| } // namespace |
| |
| |
| // ConfigurationPolicyHandler implementation ----------------------------------- |
| |
| // static |
| std::string ConfigurationPolicyHandler::ValueTypeToString(Value::Type type) { |
| static const char* strings[] = { |
| "null", |
| "boolean", |
| "integer", |
| "double", |
| "string", |
| "binary", |
| "dictionary", |
| "list" |
| }; |
| CHECK(static_cast<size_t>(type) < arraysize(strings)); |
| return std::string(strings[type]); |
| } |
| |
| ConfigurationPolicyHandler::ConfigurationPolicyHandler() { |
| } |
| |
| ConfigurationPolicyHandler::~ConfigurationPolicyHandler() { |
| } |
| |
| void ConfigurationPolicyHandler::PrepareForDisplaying( |
| PolicyMap* policies) const { |
| // jstemplate can't render DictionaryValues/objects. Convert those values to |
| // a string representation. |
| base::DictionaryValue* dict; |
| base::ListValue* list; |
| for (PolicyMap::const_iterator it = policies->begin(); |
| it != policies->end(); ++it) { |
| const PolicyMap::Entry& entry = it->second; |
| if (entry.value->GetAsDictionary(&dict)) { |
| base::StringValue* value = DictionaryToJSONString(dict); |
| policies->Set(it->first, entry.level, entry.scope, |
| value, entry.external_data_fetcher ? |
| new ExternalDataFetcher(*entry.external_data_fetcher) : |
| NULL); |
| } else if (entry.value->GetAsList(&list)) { |
| for (size_t i = 0; i < list->GetSize(); ++i) { |
| if (list->GetDictionary(i, &dict)) { |
| list->Set(i, DictionaryToJSONString(dict)); |
| } |
| } |
| } |
| } |
| } |
| |
| |
| // TypeCheckingPolicyHandler implementation ------------------------------------ |
| |
| TypeCheckingPolicyHandler::TypeCheckingPolicyHandler( |
| const char* policy_name, |
| Value::Type value_type) |
| : policy_name_(policy_name), |
| value_type_(value_type) { |
| } |
| |
| TypeCheckingPolicyHandler::~TypeCheckingPolicyHandler() { |
| } |
| |
| const char* TypeCheckingPolicyHandler::policy_name() const { |
| return policy_name_; |
| } |
| |
| bool TypeCheckingPolicyHandler::CheckPolicySettings(const PolicyMap& policies, |
| PolicyErrorMap* errors) { |
| const Value* value = NULL; |
| return CheckAndGetValue(policies, errors, &value); |
| } |
| |
| bool TypeCheckingPolicyHandler::CheckAndGetValue(const PolicyMap& policies, |
| PolicyErrorMap* errors, |
| const Value** value) { |
| *value = policies.GetValue(policy_name_); |
| if (*value && !(*value)->IsType(value_type_)) { |
| errors->AddError(policy_name_, |
| IDS_POLICY_TYPE_ERROR, |
| ValueTypeToString(value_type_)); |
| return false; |
| } |
| return true; |
| } |
| |
| |
| // IntRangePolicyHandlerBase implementation ------------------------------------ |
| |
| IntRangePolicyHandlerBase::IntRangePolicyHandlerBase( |
| const char* policy_name, |
| int min, |
| int max, |
| bool clamp) |
| : TypeCheckingPolicyHandler(policy_name, base::Value::TYPE_INTEGER), |
| min_(min), |
| max_(max), |
| clamp_(clamp) { |
| } |
| |
| bool IntRangePolicyHandlerBase::CheckPolicySettings(const PolicyMap& policies, |
| PolicyErrorMap* errors) { |
| const base::Value* value; |
| return CheckAndGetValue(policies, errors, &value) && |
| EnsureInRange(value, NULL, errors); |
| } |
| |
| IntRangePolicyHandlerBase::~IntRangePolicyHandlerBase() { |
| } |
| |
| bool IntRangePolicyHandlerBase::EnsureInRange(const base::Value* input, |
| int* output, |
| PolicyErrorMap* errors) { |
| if (!input) |
| return true; |
| |
| int value; |
| if (!input->GetAsInteger(&value)) { |
| NOTREACHED(); |
| return false; |
| } |
| |
| if (value < min_ || value > max_) { |
| if (errors) { |
| errors->AddError(policy_name(), |
| IDS_POLICY_OUT_OF_RANGE_ERROR, |
| base::IntToString(value)); |
| } |
| |
| if (!clamp_) |
| return false; |
| |
| value = std::min(std::max(value, min_), max_); |
| } |
| |
| if (output) |
| *output = value; |
| return true; |
| } |
| |
| |
| // StringToIntEnumListPolicyHandler implementation ----------------------------- |
| |
| StringToIntEnumListPolicyHandler::StringToIntEnumListPolicyHandler( |
| const char* policy_name, |
| const char* pref_path, |
| const MappingEntry* mapping_begin, |
| const MappingEntry* mapping_end) |
| : TypeCheckingPolicyHandler(policy_name, base::Value::TYPE_LIST), |
| pref_path_(pref_path), |
| mapping_begin_(mapping_begin), |
| mapping_end_(mapping_end) {} |
| |
| bool StringToIntEnumListPolicyHandler::CheckPolicySettings( |
| const PolicyMap& policies, |
| PolicyErrorMap* errors) { |
| const base::Value* value; |
| return CheckAndGetValue(policies, errors, &value) && |
| Convert(value, NULL, errors); |
| } |
| |
| void StringToIntEnumListPolicyHandler::ApplyPolicySettings( |
| const PolicyMap& policies, |
| PrefValueMap* prefs) { |
| if (!pref_path_) |
| return; |
| const base::Value* value = policies.GetValue(policy_name()); |
| scoped_ptr<base::ListValue> list(new base::ListValue()); |
| if (value && Convert(value, list.get(), NULL)) |
| prefs->SetValue(pref_path_, list.release()); |
| } |
| |
| bool StringToIntEnumListPolicyHandler::Convert(const base::Value* input, |
| base::ListValue* output, |
| PolicyErrorMap* errors) { |
| if (!input) |
| return true; |
| |
| const base::ListValue* list_value = NULL; |
| if (!input->GetAsList(&list_value)) { |
| NOTREACHED(); |
| return false; |
| } |
| |
| for (base::ListValue::const_iterator entry(list_value->begin()); |
| entry != list_value->end(); ++entry) { |
| std::string entry_value; |
| if (!(*entry)->GetAsString(&entry_value)) { |
| if (errors) { |
| errors->AddError(policy_name(), |
| entry - list_value->begin(), |
| IDS_POLICY_TYPE_ERROR, |
| ValueTypeToString(base::Value::TYPE_STRING)); |
| } |
| continue; |
| } |
| bool found = false; |
| for (const MappingEntry* mapping_entry(mapping_begin_); |
| mapping_entry != mapping_end_; ++mapping_entry) { |
| if (mapping_entry->enum_value == entry_value) { |
| found = true; |
| if (output) |
| output->AppendInteger(mapping_entry->int_value); |
| break; |
| } |
| } |
| if (!found) { |
| if (errors) { |
| errors->AddError(policy_name(), |
| entry - list_value->begin(), |
| IDS_POLICY_OUT_OF_RANGE_ERROR); |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| |
| // IntRangePolicyHandler implementation ---------------------------------------- |
| |
| IntRangePolicyHandler::IntRangePolicyHandler(const char* policy_name, |
| const char* pref_path, |
| int min, |
| int max, |
| bool clamp) |
| : IntRangePolicyHandlerBase(policy_name, min, max, clamp), |
| pref_path_(pref_path) { |
| } |
| |
| IntRangePolicyHandler::~IntRangePolicyHandler() { |
| } |
| |
| void IntRangePolicyHandler::ApplyPolicySettings(const PolicyMap& policies, |
| PrefValueMap* prefs) { |
| if (!pref_path_) |
| return; |
| const base::Value* value = policies.GetValue(policy_name()); |
| int value_in_range; |
| if (value && EnsureInRange(value, &value_in_range, NULL)) { |
| prefs->SetValue(pref_path_, |
| base::Value::CreateIntegerValue(value_in_range)); |
| } |
| } |
| |
| |
| // IntPercentageToDoublePolicyHandler implementation --------------------------- |
| |
| IntPercentageToDoublePolicyHandler::IntPercentageToDoublePolicyHandler( |
| const char* policy_name, |
| const char* pref_path, |
| int min, |
| int max, |
| bool clamp) |
| : IntRangePolicyHandlerBase(policy_name, min, max, clamp), |
| pref_path_(pref_path) { |
| } |
| |
| IntPercentageToDoublePolicyHandler::~IntPercentageToDoublePolicyHandler() { |
| } |
| |
| void IntPercentageToDoublePolicyHandler::ApplyPolicySettings( |
| const PolicyMap& policies, |
| PrefValueMap* prefs) { |
| if (!pref_path_) |
| return; |
| const base::Value* value = policies.GetValue(policy_name()); |
| int percentage; |
| if (value && EnsureInRange(value, &percentage, NULL)) { |
| prefs->SetValue(pref_path_, base::Value::CreateDoubleValue( |
| static_cast<double>(percentage) / 100.)); |
| } |
| } |
| |
| |
| // SimplePolicyHandler implementation ------------------------------------------ |
| |
| SimplePolicyHandler::SimplePolicyHandler( |
| const char* policy_name, |
| const char* pref_path, |
| Value::Type value_type) |
| : TypeCheckingPolicyHandler(policy_name, value_type), |
| pref_path_(pref_path) { |
| } |
| |
| SimplePolicyHandler::~SimplePolicyHandler() { |
| } |
| |
| void SimplePolicyHandler::ApplyPolicySettings(const PolicyMap& policies, |
| PrefValueMap* prefs) { |
| if (!pref_path_) |
| return; |
| const Value* value = policies.GetValue(policy_name()); |
| if (value) |
| prefs->SetValue(pref_path_, value->DeepCopy()); |
| } |
| |
| |
| // Android doesn't support these policies, and doesn't have a policy_path_parser |
| // implementation. |
| #if !defined(OS_ANDROID) |
| |
| // DiskCacheDirPolicyHandler implementation ------------------------------------ |
| |
| DiskCacheDirPolicyHandler::DiskCacheDirPolicyHandler(const char* pref_name) |
| : TypeCheckingPolicyHandler(key::kDiskCacheDir, Value::TYPE_STRING), |
| pref_name_(pref_name) {} |
| |
| DiskCacheDirPolicyHandler::~DiskCacheDirPolicyHandler() { |
| } |
| |
| void DiskCacheDirPolicyHandler::ApplyPolicySettings(const PolicyMap& policies, |
| PrefValueMap* prefs) { |
| const Value* value = policies.GetValue(policy_name()); |
| base::FilePath::StringType string_value; |
| if (value && value->GetAsString(&string_value)) { |
| base::FilePath::StringType expanded_value = |
| policy::path_parser::ExpandPathVariables(string_value); |
| prefs->SetValue(pref_name_, Value::CreateStringValue(expanded_value)); |
| } |
| } |
| |
| #endif // !defined(OS_ANDROID) |
| |
| } // namespace policy |