// 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 #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/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 "url/gurl.h" 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(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 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(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()); } } // namespace policy