1// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/policy/policy_domain_descriptor.h"
6
7#include "base/logging.h"
8#include "base/stl_util.h"
9#include "base/values.h"
10#include "chrome/browser/policy/policy_bundle.h"
11#include "chrome/browser/policy/policy_map.h"
12#include "chrome/common/policy/policy_schema.h"
13
14namespace policy {
15
16namespace {
17
18bool Matches(const PolicySchema* schema, const base::Value& value) {
19  if (!schema) {
20    // Schema not found, invalid entry.
21    return false;
22  }
23
24  if (!value.IsType(schema->type()))
25    return false;
26
27  const base::DictionaryValue* dict = NULL;
28  const base::ListValue* list = NULL;
29  if (value.GetAsDictionary(&dict)) {
30    for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd();
31         it.Advance()) {
32      if (!Matches(schema->GetSchemaForProperty(it.key()), it.value()))
33        return false;
34    }
35  } else if (value.GetAsList(&list)) {
36    for (base::ListValue::const_iterator it = list->begin();
37         it != list->end(); ++it) {
38      if (!*it || !Matches(schema->GetSchemaForItems(), **it))
39        return false;
40    }
41  }
42
43  return true;
44}
45
46}  // namespace
47
48PolicyDomainDescriptor::PolicyDomainDescriptor(PolicyDomain domain)
49    : domain_(domain) {}
50
51void PolicyDomainDescriptor::RegisterComponent(
52    const std::string& component_id,
53    scoped_ptr<PolicySchema> schema) {
54  const PolicySchema*& entry = schema_map_[component_id];
55  delete entry;
56  entry = schema.release();
57}
58
59void PolicyDomainDescriptor::FilterBundle(PolicyBundle* bundle) const {
60  // Chrome policies are not filtered, so that typos appear in about:policy.
61  DCHECK_NE(POLICY_DOMAIN_CHROME, domain_);
62
63  for (PolicyBundle::iterator it_bundle = bundle->begin();
64       it_bundle != bundle->end(); ++it_bundle) {
65    const PolicyNamespace& ns = it_bundle->first;
66    if (ns.domain != domain_)
67      continue;
68
69    SchemaMap::const_iterator it_schema = schema_map_.find(ns.component_id);
70    if (it_schema == schema_map_.end()) {
71      // Component ID not found.
72      it_bundle->second->Clear();
73      continue;
74    }
75
76    // TODO(joaodasilva): if a component is registered but doesn't have a schema
77    // then its policies aren't filtered. This behavior is enabled for M29 to
78    // allow a graceful update of the Legacy Browser Support extension; it'll
79    // be removed for M30. http://crbug.com/240704
80    if (!it_schema->second)
81      continue;
82
83    const PolicySchema* component_schema = it_schema->second;
84    PolicyMap* map = it_bundle->second;
85    for (PolicyMap::const_iterator it_map = map->begin();
86         it_map != map->end();) {
87      const std::string& policy_name = it_map->first;
88      const base::Value* policy_value = it_map->second.value;
89      const PolicySchema* policy_schema =
90          component_schema->GetSchemaForProperty(policy_name);
91      ++it_map;
92      if (!policy_value || !Matches(policy_schema, *policy_value))
93        map->Erase(policy_name);
94    }
95  }
96}
97
98PolicyDomainDescriptor::~PolicyDomainDescriptor() {
99  STLDeleteValues(&schema_map_);
100}
101
102}  // namespace policy
103