1 // Copyright (c) 2012 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 "components/policy/core/common/policy_service_impl.h"
6 
7 #include <stddef.h>
8 
9 #include <algorithm>
10 #include <utility>
11 
12 #include "base/bind.h"
13 #include "base/location.h"
14 #include "base/macros.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/threading/thread_task_runner_handle.h"
17 #include "base/values.h"
18 #include "components/policy/core/common/policy_bundle.h"
19 #include "components/policy/core/common/policy_map.h"
20 #include "components/policy/core/common/policy_types.h"
21 #include "components/policy/policy_constants.h"
22 
23 namespace policy {
24 
25 namespace {
26 
27 const char* kProxyPolicies[] = {
28   key::kProxyMode,
29   key::kProxyServerMode,
30   key::kProxyServer,
31   key::kProxyPacUrl,
32   key::kProxyBypassList,
33 };
34 
35 // Maps the separate policies for proxy settings into a single Dictionary
36 // policy. This allows to keep the logic of merging policies from different
37 // sources simple, as all separate proxy policies should be considered as a
38 // single whole during merging.
RemapProxyPolicies(PolicyMap * policies)39 void RemapProxyPolicies(PolicyMap* policies) {
40   // The highest (level, scope) pair for an existing proxy policy is determined
41   // first, and then only policies with those exact attributes are merged.
42   PolicyMap::Entry current_priority;  // Defaults to the lowest priority.
43   PolicySource inherited_source = POLICY_SOURCE_ENTERPRISE_DEFAULT;
44   std::unique_ptr<base::DictionaryValue> proxy_settings(
45       new base::DictionaryValue);
46   for (size_t i = 0; i < arraysize(kProxyPolicies); ++i) {
47     const PolicyMap::Entry* entry = policies->Get(kProxyPolicies[i]);
48     if (entry) {
49       if (entry->has_higher_priority_than(current_priority)) {
50         proxy_settings->Clear();
51         current_priority = entry->DeepCopy();
52         if (entry->source > inherited_source)  // Higher priority?
53           inherited_source = entry->source;
54       }
55       if (!entry->has_higher_priority_than(current_priority) &&
56           !current_priority.has_higher_priority_than(*entry)) {
57         proxy_settings->Set(kProxyPolicies[i], entry->value->CreateDeepCopy());
58       }
59       policies->Erase(kProxyPolicies[i]);
60     }
61   }
62   // Sets the new |proxy_settings| if kProxySettings isn't set yet, or if the
63   // new priority is higher.
64   const PolicyMap::Entry* existing = policies->Get(key::kProxySettings);
65   if (!proxy_settings->empty() &&
66       (!existing || current_priority.has_higher_priority_than(*existing))) {
67     policies->Set(key::kProxySettings, current_priority.level,
68                   current_priority.scope, inherited_source,
69                   std::move(proxy_settings), nullptr);
70   }
71 }
72 
73 }  // namespace
74 
PolicyServiceImpl(Providers providers)75 PolicyServiceImpl::PolicyServiceImpl(Providers providers)
76     : update_task_ptr_factory_(this) {
77   providers_ = std::move(providers);
78   for (int domain = 0; domain < POLICY_DOMAIN_SIZE; ++domain)
79     initialization_complete_[domain] = true;
80   for (auto* provider : providers_) {
81     provider->AddObserver(this);
82     for (int domain = 0; domain < POLICY_DOMAIN_SIZE; ++domain) {
83       initialization_complete_[domain] &=
84           provider->IsInitializationComplete(static_cast<PolicyDomain>(domain));
85     }
86   }
87   // There are no observers yet, but calls to GetPolicies() should already get
88   // the processed policy values.
89   MergeAndTriggerUpdates();
90 }
91 
~PolicyServiceImpl()92 PolicyServiceImpl::~PolicyServiceImpl() {
93   DCHECK(thread_checker_.CalledOnValidThread());
94   for (auto* provider : providers_)
95     provider->RemoveObserver(this);
96 }
97 
AddObserver(PolicyDomain domain,PolicyService::Observer * observer)98 void PolicyServiceImpl::AddObserver(PolicyDomain domain,
99                                     PolicyService::Observer* observer) {
100   DCHECK(thread_checker_.CalledOnValidThread());
101   std::unique_ptr<Observers>& list = observers_[domain];
102   if (!list)
103     list = std::make_unique<Observers>();
104   list->AddObserver(observer);
105 }
106 
RemoveObserver(PolicyDomain domain,PolicyService::Observer * observer)107 void PolicyServiceImpl::RemoveObserver(PolicyDomain domain,
108                                        PolicyService::Observer* observer) {
109   DCHECK(thread_checker_.CalledOnValidThread());
110   auto it = observers_.find(domain);
111   if (it == observers_.end()) {
112     NOTREACHED();
113     return;
114   }
115   it->second->RemoveObserver(observer);
116   if (!it->second->might_have_observers()) {
117     observers_.erase(it);
118   }
119 }
120 
GetPolicies(const PolicyNamespace & ns) const121 const PolicyMap& PolicyServiceImpl::GetPolicies(
122     const PolicyNamespace& ns) const {
123   DCHECK(thread_checker_.CalledOnValidThread());
124   return policy_bundle_.Get(ns);
125 }
126 
IsInitializationComplete(PolicyDomain domain) const127 bool PolicyServiceImpl::IsInitializationComplete(PolicyDomain domain) const {
128   DCHECK(thread_checker_.CalledOnValidThread());
129   DCHECK(domain >= 0 && domain < POLICY_DOMAIN_SIZE);
130   return initialization_complete_[domain];
131 }
132 
RefreshPolicies(const base::Closure & callback)133 void PolicyServiceImpl::RefreshPolicies(const base::Closure& callback) {
134   DCHECK(thread_checker_.CalledOnValidThread());
135 
136   if (!callback.is_null())
137     refresh_callbacks_.push_back(callback);
138 
139   if (providers_.empty()) {
140     // Refresh is immediately complete if there are no providers. See the note
141     // on OnUpdatePolicy() about why this is a posted task.
142     update_task_ptr_factory_.InvalidateWeakPtrs();
143     base::ThreadTaskRunnerHandle::Get()->PostTask(
144         FROM_HERE, base::Bind(&PolicyServiceImpl::MergeAndTriggerUpdates,
145                               update_task_ptr_factory_.GetWeakPtr()));
146   } else {
147     // Some providers might invoke OnUpdatePolicy synchronously while handling
148     // RefreshPolicies. Mark all as pending before refreshing.
149     for (auto* provider : providers_)
150       refresh_pending_.insert(provider);
151     for (auto* provider : providers_)
152       provider->RefreshPolicies();
153   }
154 }
155 
OnUpdatePolicy(ConfigurationPolicyProvider * provider)156 void PolicyServiceImpl::OnUpdatePolicy(ConfigurationPolicyProvider* provider) {
157   DCHECK_EQ(1, std::count(providers_.begin(), providers_.end(), provider));
158   refresh_pending_.erase(provider);
159 
160   // Note: a policy change may trigger further policy changes in some providers.
161   // For example, disabling SigninAllowed would cause the CloudPolicyManager to
162   // drop all its policies, which makes this method enter again for that
163   // provider.
164   //
165   // Therefore this update is posted asynchronously, to prevent reentrancy in
166   // MergeAndTriggerUpdates. Also, cancel a pending update if there is any,
167   // since both will produce the same PolicyBundle.
168   update_task_ptr_factory_.InvalidateWeakPtrs();
169   base::ThreadTaskRunnerHandle::Get()->PostTask(
170       FROM_HERE, base::Bind(&PolicyServiceImpl::MergeAndTriggerUpdates,
171                             update_task_ptr_factory_.GetWeakPtr()));
172 }
173 
NotifyNamespaceUpdated(const PolicyNamespace & ns,const PolicyMap & previous,const PolicyMap & current)174 void PolicyServiceImpl::NotifyNamespaceUpdated(
175     const PolicyNamespace& ns,
176     const PolicyMap& previous,
177     const PolicyMap& current) {
178   DCHECK(thread_checker_.CalledOnValidThread());
179   auto iterator = observers_.find(ns.domain);
180   if (iterator != observers_.end()) {
181     for (auto& observer : *iterator->second)
182       observer.OnPolicyUpdated(ns, previous, current);
183   }
184 }
185 
MergeAndTriggerUpdates()186 void PolicyServiceImpl::MergeAndTriggerUpdates() {
187   // Merge from each provider in their order of priority.
188   const PolicyNamespace chrome_namespace(POLICY_DOMAIN_CHROME, std::string());
189   PolicyBundle bundle;
190   for (auto* provider : providers_) {
191     PolicyBundle provided_bundle;
192     provided_bundle.CopyFrom(provider->policies());
193     RemapProxyPolicies(&provided_bundle.Get(chrome_namespace));
194     bundle.MergeFrom(provided_bundle);
195   }
196 
197   // Swap first, so that observers that call GetPolicies() see the current
198   // values.
199   policy_bundle_.Swap(&bundle);
200 
201   // Only notify observers of namespaces that have been modified.
202   const PolicyMap kEmpty;
203   PolicyBundle::const_iterator it_new = policy_bundle_.begin();
204   PolicyBundle::const_iterator end_new = policy_bundle_.end();
205   PolicyBundle::const_iterator it_old = bundle.begin();
206   PolicyBundle::const_iterator end_old = bundle.end();
207   while (it_new != end_new && it_old != end_old) {
208     if (it_new->first < it_old->first) {
209       // A new namespace is available.
210       NotifyNamespaceUpdated(it_new->first, kEmpty, *it_new->second);
211       ++it_new;
212     } else if (it_old->first < it_new->first) {
213       // A previously available namespace is now gone.
214       NotifyNamespaceUpdated(it_old->first, *it_old->second, kEmpty);
215       ++it_old;
216     } else {
217       if (!it_new->second->Equals(*it_old->second)) {
218         // An existing namespace's policies have changed.
219         NotifyNamespaceUpdated(it_new->first, *it_old->second, *it_new->second);
220       }
221       ++it_new;
222       ++it_old;
223     }
224   }
225 
226   // Send updates for the remaining new namespaces, if any.
227   for (; it_new != end_new; ++it_new)
228     NotifyNamespaceUpdated(it_new->first, kEmpty, *it_new->second);
229 
230   // Sends updates for the remaining removed namespaces, if any.
231   for (; it_old != end_old; ++it_old)
232     NotifyNamespaceUpdated(it_old->first, *it_old->second, kEmpty);
233 
234   CheckInitializationComplete();
235   CheckRefreshComplete();
236 }
237 
CheckInitializationComplete()238 void PolicyServiceImpl::CheckInitializationComplete() {
239   DCHECK(thread_checker_.CalledOnValidThread());
240 
241   // Check if all the providers just became initialized for each domain; if so,
242   // notify that domain's observers.
243   for (int domain = 0; domain < POLICY_DOMAIN_SIZE; ++domain) {
244     if (initialization_complete_[domain])
245       continue;
246 
247     PolicyDomain policy_domain = static_cast<PolicyDomain>(domain);
248 
249     bool all_complete = true;
250     for (auto* provider : providers_) {
251       if (!provider->IsInitializationComplete(policy_domain)) {
252         all_complete = false;
253         break;
254       }
255     }
256     if (all_complete) {
257       initialization_complete_[domain] = true;
258       auto iter = observers_.find(policy_domain);
259       if (iter != observers_.end()) {
260         for (auto& observer : *iter->second)
261           observer.OnPolicyServiceInitialized(policy_domain);
262       }
263     }
264   }
265 }
266 
CheckRefreshComplete()267 void PolicyServiceImpl::CheckRefreshComplete() {
268   // Invoke all the callbacks if a refresh has just fully completed.
269   if (refresh_pending_.empty() && !refresh_callbacks_.empty()) {
270     std::vector<base::Closure> callbacks;
271     callbacks.swap(refresh_callbacks_);
272     std::vector<base::Closure>::iterator it;
273     for (it = callbacks.begin(); it != callbacks.end(); ++it)
274       it->Run();
275   }
276 }
277 
278 }  // namespace policy
279