1 // Copyright 2015 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.
5 // Most of this code is copied from:
6 // src/chrome/browser/policy/asynchronous_policy_loader.{h,cc}
8 #include "remoting/host/policy_watcher.h"
10 #include "base/bind.h"
11 #include "base/compiler_specific.h"
12 #include "base/files/file_path.h"
13 #include "base/location.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/values.h"
16 #include "components/policy/core/common/async_policy_loader.h"
17 #include "components/policy/core/common/async_policy_provider.h"
18 #include "components/policy/core/common/policy_namespace.h"
19 #include "components/policy/core/common/policy_service_impl.h"
20 #include "components/policy/core/common/schema.h"
21 #include "components/policy/core/common/schema_registry.h"
22 #include "policy/policy_constants.h"
23 #include "remoting/host/dns_blackhole_checker.h"
26 #include "base/json/json_reader.h"
30 #include "components/policy/core/common/policy_loader_win.h"
31 #elif defined(OS_MACOSX)
32 #include "components/policy/core/common/policy_loader_mac.h"
33 #include "components/policy/core/common/preferences_mac.h"
34 #elif defined(OS_POSIX) && !defined(OS_ANDROID)
35 #include "components/policy/core/common/config_dir_policy_loader.h"
40 namespace key
= ::policy::key
;
44 // Copies all policy values from one dictionary to another, using values from
45 // |default| if they are not set in |from|, or values from |bad_type_values| if
46 // the value in |from| has the wrong type.
47 scoped_ptr
<base::DictionaryValue
> CopyGoodValuesAndAddDefaults(
48 const base::DictionaryValue
* from
,
49 const base::DictionaryValue
* default_values
,
50 const base::DictionaryValue
* bad_type_values
) {
51 scoped_ptr
<base::DictionaryValue
> to(default_values
->DeepCopy());
52 for (base::DictionaryValue::Iterator
i(*default_values
); !i
.IsAtEnd();
54 const base::Value
* value
= nullptr;
56 // If the policy isn't in |from|, use the default.
57 if (!from
->Get(i
.key(), &value
)) {
61 // If the policy is the wrong type, use the value from |bad_type_values|.
62 if (!value
->IsType(i
.value().GetType())) {
63 CHECK(bad_type_values
->Get(i
.key(), &value
));
66 to
->Set(i
.key(), value
->DeepCopy());
70 // Replace values with those specified in DebugOverridePolicies, if present.
71 std::string policy_overrides
;
72 if (from
->GetString(key::kRemoteAccessHostDebugOverridePolicies
,
74 scoped_ptr
<base::Value
> value(base::JSONReader::Read(policy_overrides
));
75 const base::DictionaryValue
* override_values
;
76 if (value
&& value
->GetAsDictionary(&override_values
)) {
77 to
->MergeDictionary(override_values
);
80 #endif // defined(NDEBUG)
85 policy::PolicyNamespace
GetPolicyNamespace() {
86 return policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME
, std::string());
91 void PolicyWatcher::StartWatching(
92 const PolicyUpdatedCallback
& policy_updated_callback
,
93 const PolicyErrorCallback
& policy_error_callback
) {
94 DCHECK(CalledOnValidThread());
95 DCHECK(!policy_updated_callback
.is_null());
96 DCHECK(!policy_error_callback
.is_null());
97 DCHECK(policy_updated_callback_
.is_null());
99 policy_updated_callback_
= policy_updated_callback
;
100 policy_error_callback_
= policy_error_callback
;
102 // Listen for future policy changes.
103 policy_service_
->AddObserver(policy::POLICY_DOMAIN_CHROME
, this);
105 // Process current policy state.
106 if (policy_service_
->IsInitializationComplete(policy::POLICY_DOMAIN_CHROME
)) {
107 OnPolicyServiceInitialized(policy::POLICY_DOMAIN_CHROME
);
111 void PolicyWatcher::UpdatePolicies(
112 const base::DictionaryValue
* new_policies_raw
) {
113 DCHECK(CalledOnValidThread());
115 transient_policy_error_retry_counter_
= 0;
117 // Use default values for any missing policies.
118 scoped_ptr
<base::DictionaryValue
> new_policies
= CopyGoodValuesAndAddDefaults(
119 new_policies_raw
, default_values_
.get(), bad_type_values_
.get());
121 // Find the changed policies.
122 scoped_ptr
<base::DictionaryValue
> changed_policies(
123 new base::DictionaryValue());
124 base::DictionaryValue::Iterator
iter(*new_policies
);
125 while (!iter
.IsAtEnd()) {
126 base::Value
* old_policy
;
127 if (!(old_policies_
->Get(iter
.key(), &old_policy
) &&
128 old_policy
->Equals(&iter
.value()))) {
129 changed_policies
->Set(iter
.key(), iter
.value().DeepCopy());
134 // Save the new policies.
135 old_policies_
.swap(new_policies
);
137 // Notify our client of the changed policies.
138 if (!changed_policies
->empty()) {
139 policy_updated_callback_
.Run(changed_policies
.Pass());
143 void PolicyWatcher::SignalPolicyError() {
144 transient_policy_error_retry_counter_
= 0;
145 policy_error_callback_
.Run();
148 void PolicyWatcher::SignalTransientPolicyError() {
149 const int kMaxRetryCount
= 5;
150 transient_policy_error_retry_counter_
+= 1;
151 if (transient_policy_error_retry_counter_
>= kMaxRetryCount
) {
156 PolicyWatcher::PolicyWatcher(
157 policy::PolicyService
* policy_service
,
158 scoped_ptr
<policy::PolicyService
> owned_policy_service
,
159 scoped_ptr
<policy::ConfigurationPolicyProvider
> owned_policy_provider
,
160 scoped_ptr
<policy::SchemaRegistry
> owned_schema_registry
)
161 : transient_policy_error_retry_counter_(0),
162 old_policies_(new base::DictionaryValue()),
163 default_values_(new base::DictionaryValue()),
164 policy_service_(policy_service
),
165 owned_schema_registry_(owned_schema_registry
.Pass()),
166 owned_policy_provider_(owned_policy_provider
.Pass()),
167 owned_policy_service_(owned_policy_service
.Pass()) {
168 // Initialize the default values for each policy.
169 default_values_
->SetBoolean(key::kRemoteAccessHostFirewallTraversal
, true);
170 default_values_
->SetBoolean(key::kRemoteAccessHostRequireTwoFactor
, false);
171 default_values_
->SetBoolean(key::kRemoteAccessHostRequireCurtain
, false);
172 default_values_
->SetBoolean(key::kRemoteAccessHostMatchUsername
, false);
173 default_values_
->SetString(key::kRemoteAccessHostDomain
, std::string());
174 default_values_
->SetString(key::kRemoteAccessHostTalkGadgetPrefix
,
175 kDefaultHostTalkGadgetPrefix
);
176 default_values_
->SetString(key::kRemoteAccessHostTokenUrl
, std::string());
177 default_values_
->SetString(key::kRemoteAccessHostTokenValidationUrl
,
179 default_values_
->SetString(
180 key::kRemoteAccessHostTokenValidationCertificateIssuer
, std::string());
181 default_values_
->SetBoolean(key::kRemoteAccessHostAllowClientPairing
, true);
182 default_values_
->SetBoolean(key::kRemoteAccessHostAllowGnubbyAuth
, true);
183 default_values_
->SetBoolean(key::kRemoteAccessHostAllowRelayedConnection
,
185 default_values_
->SetString(key::kRemoteAccessHostUdpPortRange
, "");
187 default_values_
->SetString(key::kRemoteAccessHostDebugOverridePolicies
,
191 // Initialize the fall-back values to use for unreadable policies.
192 // For most policies these match the defaults.
193 bad_type_values_
.reset(default_values_
->DeepCopy());
194 bad_type_values_
->SetBoolean(key::kRemoteAccessHostFirewallTraversal
, false);
195 bad_type_values_
->SetBoolean(key::kRemoteAccessHostAllowRelayedConnection
,
199 PolicyWatcher::~PolicyWatcher() {
200 // Stop observing |policy_service_| if StartWatching() has been called.
201 if (!policy_updated_callback_
.is_null()) {
202 policy_service_
->RemoveObserver(policy::POLICY_DOMAIN_CHROME
, this);
205 if (owned_policy_provider_
) {
206 owned_policy_provider_
->Shutdown();
210 void PolicyWatcher::OnPolicyUpdated(const policy::PolicyNamespace
& ns
,
211 const policy::PolicyMap
& previous
,
212 const policy::PolicyMap
& current
) {
213 scoped_ptr
<base::DictionaryValue
> policy_dict(new base::DictionaryValue());
214 for (auto it
= current
.begin(); it
!= current
.end(); ++it
) {
215 // TODO(lukasza): Use policy::Schema::Normalize() for schema verification.
216 policy_dict
->Set(it
->first
, it
->second
.value
->DeepCopy());
218 UpdatePolicies(policy_dict
.get());
221 void PolicyWatcher::OnPolicyServiceInitialized(policy::PolicyDomain domain
) {
222 policy::PolicyNamespace ns
= GetPolicyNamespace();
223 const policy::PolicyMap
& current
= policy_service_
->GetPolicies(ns
);
224 OnPolicyUpdated(ns
, current
, current
);
227 scoped_ptr
<PolicyWatcher
> PolicyWatcher::CreateFromPolicyLoader(
228 scoped_ptr
<policy::AsyncPolicyLoader
> async_policy_loader
) {
229 // TODO(lukasza): Schema below should ideally only cover Chromoting-specific
230 // policies (expecting perf and maintanability improvement, but no functional
232 policy::Schema schema
= policy::Schema::Wrap(policy::GetChromeSchemaData());
234 scoped_ptr
<policy::SchemaRegistry
> schema_registry(
235 new policy::SchemaRegistry());
236 schema_registry
->RegisterComponent(GetPolicyNamespace(), schema
);
238 scoped_ptr
<policy::AsyncPolicyProvider
> policy_provider(
239 new policy::AsyncPolicyProvider(schema_registry
.get(),
240 async_policy_loader
.Pass()));
241 policy_provider
->Init(schema_registry
.get());
243 policy::PolicyServiceImpl::Providers providers
;
244 providers
.push_back(policy_provider
.get());
245 scoped_ptr
<policy::PolicyService
> policy_service(
246 new policy::PolicyServiceImpl(providers
));
248 policy::PolicyService
* borrowed_policy_service
= policy_service
.get();
249 return make_scoped_ptr(
250 new PolicyWatcher(borrowed_policy_service
, policy_service
.Pass(),
251 policy_provider
.Pass(), schema_registry
.Pass()));
254 scoped_ptr
<PolicyWatcher
> PolicyWatcher::Create(
255 policy::PolicyService
* policy_service
,
256 const scoped_refptr
<base::SingleThreadTaskRunner
>& file_task_runner
) {
257 #if defined(OS_CHROMEOS)
258 // On Chrome OS the PolicyService is owned by the browser.
259 DCHECK(policy_service
);
260 return make_scoped_ptr(
261 new PolicyWatcher(policy_service
, nullptr, nullptr, nullptr));
262 #else // !defined(OS_CHROMEOS)
263 DCHECK(!policy_service
);
265 // Create platform-specific PolicyLoader. Always read the Chrome policies
266 // (even on Chromium) so that policy enforcement can't be bypassed by running
268 scoped_ptr
<policy::AsyncPolicyLoader
> policy_loader
;
270 policy_loader
= policy::PolicyLoaderWin::Create(
271 file_task_runner
, L
"SOFTWARE\\Policies\\Google\\Chrome");
272 #elif defined(OS_MACOSX)
273 CFStringRef bundle_id
= CFSTR("com.google.Chrome");
274 policy_loader
.reset(new policy::PolicyLoaderMac(
276 policy::PolicyLoaderMac::GetManagedPolicyPath(bundle_id
),
277 new MacPreferences(), bundle_id
));
278 #elif defined(OS_POSIX) && !defined(OS_ANDROID)
279 policy_loader
.reset(new policy::ConfigDirPolicyLoader(
281 base::FilePath(FILE_PATH_LITERAL("/etc/opt/chrome/policies")),
282 policy::POLICY_SCOPE_MACHINE
));
284 #error OS that is not yet supported by PolicyWatcher code.
287 return PolicyWatcher::CreateFromPolicyLoader(policy_loader
.Pass());
288 #endif // !(OS_CHROMEOS)
291 } // namespace remoting