| // 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 "components/policy/core/browser/configuration_policy_handler.h" |
| |
| #include <stddef.h> |
| |
| #include <algorithm> |
| #include <utility> |
| |
| #include "base/callback.h" |
| #include "base/files/file_path.h" |
| #include "base/logging.h" |
| #include "base/macros.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/strings/string16.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| #include "components/policy/core/browser/policy_error_map.h" |
| #include "components/policy/core/common/policy_map.h" |
| #include "components/prefs/pref_value_map.h" |
| #include "grit/components_strings.h" |
| #include "url/gurl.h" |
| |
| namespace policy { |
| |
| // ConfigurationPolicyHandler implementation ----------------------------------- |
| |
| // static |
| std::string ConfigurationPolicyHandler::ValueTypeToString( |
| base::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 {} |
| |
| void ConfigurationPolicyHandler::ApplyPolicySettingsWithParameters( |
| const PolicyMap& policies, |
| const PolicyHandlerParameters& parameters, |
| PrefValueMap* prefs) { |
| ApplyPolicySettings(policies, prefs); |
| } |
| |
| // TypeCheckingPolicyHandler implementation ------------------------------------ |
| |
| TypeCheckingPolicyHandler::TypeCheckingPolicyHandler( |
| const char* policy_name, |
| base::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 base::Value* value = NULL; |
| return CheckAndGetValue(policies, errors, &value); |
| } |
| |
| bool TypeCheckingPolicyHandler::CheckAndGetValue(const PolicyMap& policies, |
| PolicyErrorMap* errors, |
| const base::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; |
| } |
| |
| |
| // StringMappingListPolicyHandler implementation ----------------------------- |
| |
| StringMappingListPolicyHandler::MappingEntry::MappingEntry( |
| const char* policy_value, |
| std::unique_ptr<base::Value> map) |
| : enum_value(policy_value), mapped_value(std::move(map)) {} |
| |
| StringMappingListPolicyHandler::MappingEntry::~MappingEntry() {} |
| |
| StringMappingListPolicyHandler::StringMappingListPolicyHandler( |
| const char* policy_name, |
| const char* pref_path, |
| const GenerateMapCallback& callback) |
| : TypeCheckingPolicyHandler(policy_name, base::Value::TYPE_LIST), |
| pref_path_(pref_path), |
| map_getter_(callback) {} |
| |
| StringMappingListPolicyHandler::~StringMappingListPolicyHandler() {} |
| |
| bool StringMappingListPolicyHandler::CheckPolicySettings( |
| const PolicyMap& policies, |
| PolicyErrorMap* errors) { |
| const base::Value* value; |
| return CheckAndGetValue(policies, errors, &value) && |
| Convert(value, NULL, errors); |
| } |
| |
| void StringMappingListPolicyHandler::ApplyPolicySettings( |
| const PolicyMap& policies, |
| PrefValueMap* prefs) { |
| if (!pref_path_) |
| return; |
| const base::Value* value = policies.GetValue(policy_name()); |
| std::unique_ptr<base::ListValue> list(new base::ListValue()); |
| if (value && Convert(value, list.get(), NULL)) |
| prefs->SetValue(pref_path_, std::move(list)); |
| } |
| |
| bool StringMappingListPolicyHandler::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; |
| } |
| |
| std::unique_ptr<base::Value> mapped_value = Map(entry_value); |
| if (mapped_value) { |
| if (output) |
| output->Append(std::move(mapped_value)); |
| } else { |
| if (errors) { |
| errors->AddError(policy_name(), |
| entry - list_value->begin(), |
| IDS_POLICY_OUT_OF_RANGE_ERROR); |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| std::unique_ptr<base::Value> StringMappingListPolicyHandler::Map( |
| const std::string& entry_value) { |
| // Lazily generate the map of policy strings to mapped values. |
| if (map_.empty()) |
| map_getter_.Run(&map_); |
| |
| std::unique_ptr<base::Value> return_value; |
| for (ScopedVector<MappingEntry>::const_iterator it = map_.begin(); |
| it != map_.end(); ++it) { |
| const MappingEntry* mapping_entry = *it; |
| if (mapping_entry->enum_value == entry_value) { |
| return_value = base::WrapUnique(mapping_entry->mapped_value->DeepCopy()); |
| break; |
| } |
| } |
| return return_value; |
| } |
| |
| // 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->SetInteger(pref_path_, 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->SetDouble(pref_path_, static_cast<double>(percentage) / 100.); |
| } |
| |
| |
| // SimplePolicyHandler implementation ------------------------------------------ |
| |
| SimplePolicyHandler::SimplePolicyHandler( |
| const char* policy_name, |
| const char* pref_path, |
| base::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 base::Value* value = policies.GetValue(policy_name()); |
| if (value) |
| prefs->SetValue(pref_path_, value->CreateDeepCopy()); |
| } |
| |
| |
| // SchemaValidatingPolicyHandler implementation -------------------------------- |
| |
| SchemaValidatingPolicyHandler::SchemaValidatingPolicyHandler( |
| const char* policy_name, |
| Schema schema, |
| SchemaOnErrorStrategy strategy) |
| : policy_name_(policy_name), schema_(schema), strategy_(strategy) { |
| DCHECK(schema_.valid()); |
| } |
| |
| SchemaValidatingPolicyHandler::~SchemaValidatingPolicyHandler() { |
| } |
| |
| const char* SchemaValidatingPolicyHandler::policy_name() const { |
| return policy_name_; |
| } |
| |
| bool SchemaValidatingPolicyHandler::CheckPolicySettings( |
| const PolicyMap& policies, |
| PolicyErrorMap* errors) { |
| const base::Value* value = policies.GetValue(policy_name()); |
| if (!value) |
| return true; |
| |
| std::string error_path; |
| std::string error; |
| bool result = schema_.Validate(*value, strategy_, &error_path, &error); |
| |
| if (errors && !error.empty()) { |
| if (error_path.empty()) |
| error_path = "(ROOT)"; |
| errors->AddError(policy_name_, error_path, error); |
| } |
| |
| return result; |
| } |
| |
| bool SchemaValidatingPolicyHandler::CheckAndGetValue( |
| const PolicyMap& policies, |
| PolicyErrorMap* errors, |
| std::unique_ptr<base::Value>* output) { |
| const base::Value* value = policies.GetValue(policy_name()); |
| if (!value) |
| return true; |
| |
| output->reset(value->DeepCopy()); |
| std::string error_path; |
| std::string error; |
| bool result = |
| schema_.Normalize(output->get(), strategy_, &error_path, &error, NULL); |
| |
| if (errors && !error.empty()) { |
| if (error_path.empty()) |
| error_path = "(ROOT)"; |
| errors->AddError(policy_name_, error_path, error); |
| } |
| |
| return result; |
| } |
| |
| // SimpleSchemaValidatingPolicyHandler implementation -------------------------- |
| |
| SimpleSchemaValidatingPolicyHandler::SimpleSchemaValidatingPolicyHandler( |
| const char* policy_name, |
| const char* pref_path, |
| Schema schema, |
| SchemaOnErrorStrategy strategy, |
| RecommendedPermission recommended_permission, |
| MandatoryPermission mandatory_permission) |
| : SchemaValidatingPolicyHandler(policy_name, |
| schema.GetKnownProperty(policy_name), |
| strategy), |
| pref_path_(pref_path), |
| allow_recommended_(recommended_permission == RECOMMENDED_ALLOWED), |
| allow_mandatory_(mandatory_permission == MANDATORY_ALLOWED) { |
| } |
| |
| SimpleSchemaValidatingPolicyHandler::~SimpleSchemaValidatingPolicyHandler() { |
| } |
| |
| bool SimpleSchemaValidatingPolicyHandler::CheckPolicySettings( |
| const PolicyMap& policies, |
| PolicyErrorMap* errors) { |
| const PolicyMap::Entry* policy_entry = policies.Get(policy_name()); |
| if (!policy_entry) |
| return true; |
| if ((policy_entry->level == policy::POLICY_LEVEL_MANDATORY && |
| !allow_mandatory_) || |
| (policy_entry->level == policy::POLICY_LEVEL_RECOMMENDED && |
| !allow_recommended_)) { |
| if (errors) |
| errors->AddError(policy_name(), IDS_POLICY_LEVEL_ERROR); |
| return false; |
| } |
| |
| return SchemaValidatingPolicyHandler::CheckPolicySettings(policies, errors); |
| } |
| |
| void SimpleSchemaValidatingPolicyHandler::ApplyPolicySettings( |
| const PolicyMap& policies, |
| PrefValueMap* prefs) { |
| if (!pref_path_) |
| return; |
| const base::Value* value = policies.GetValue(policy_name()); |
| if (value) |
| prefs->SetValue(pref_path_, value->CreateDeepCopy()); |
| } |
| |
| // LegacyPoliciesDeprecatingPolicyHandler implementation ----------------------- |
| |
| // TODO(binjin): Add a new common base class for SchemaValidatingPolicyHandler |
| // and TypeCheckingPolicyHandler representing policy handlers for a single |
| // policy, and use it as the type of |new_policy_handler|. |
| // http://crbug.com/345299 |
| LegacyPoliciesDeprecatingPolicyHandler::LegacyPoliciesDeprecatingPolicyHandler( |
| ScopedVector<ConfigurationPolicyHandler> legacy_policy_handlers, |
| std::unique_ptr<SchemaValidatingPolicyHandler> new_policy_handler) |
| : legacy_policy_handlers_(std::move(legacy_policy_handlers)), |
| new_policy_handler_(std::move(new_policy_handler)) {} |
| |
| LegacyPoliciesDeprecatingPolicyHandler:: |
| ~LegacyPoliciesDeprecatingPolicyHandler() { |
| } |
| |
| bool LegacyPoliciesDeprecatingPolicyHandler::CheckPolicySettings( |
| const PolicyMap& policies, |
| PolicyErrorMap* errors) { |
| if (policies.Get(new_policy_handler_->policy_name())) { |
| return new_policy_handler_->CheckPolicySettings(policies, errors); |
| } else { |
| // The new policy is not set, fall back to legacy ones. |
| ScopedVector<ConfigurationPolicyHandler>::iterator handler; |
| bool valid_policy_found = false; |
| for (handler = legacy_policy_handlers_.begin(); |
| handler != legacy_policy_handlers_.end(); |
| ++handler) { |
| if ((*handler)->CheckPolicySettings(policies, errors)) |
| valid_policy_found = true; |
| } |
| return valid_policy_found; |
| } |
| } |
| |
| void LegacyPoliciesDeprecatingPolicyHandler::ApplyPolicySettingsWithParameters( |
| const policy::PolicyMap& policies, |
| const policy::PolicyHandlerParameters& parameters, |
| PrefValueMap* prefs) { |
| if (policies.Get(new_policy_handler_->policy_name())) { |
| new_policy_handler_->ApplyPolicySettingsWithParameters(policies, parameters, |
| prefs); |
| } else { |
| // The new policy is not set, fall back to legacy ones. |
| PolicyErrorMap scoped_errors; |
| ScopedVector<ConfigurationPolicyHandler>::iterator handler; |
| for (handler = legacy_policy_handlers_.begin(); |
| handler != legacy_policy_handlers_.end(); |
| ++handler) { |
| if ((*handler)->CheckPolicySettings(policies, &scoped_errors)) { |
| (*handler) |
| ->ApplyPolicySettingsWithParameters(policies, parameters, prefs); |
| } |
| } |
| } |
| } |
| void LegacyPoliciesDeprecatingPolicyHandler::ApplyPolicySettings( |
| const policy::PolicyMap& /* policies */, |
| PrefValueMap* /* prefs */) { |
| NOTREACHED(); |
| } |
| |
| } // namespace policy |