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.
4
5 // Most of this code is copied from:
6 // src/chrome/browser/policy/asynchronous_policy_loader.{h,cc}
7
8 #include "remoting/host/policy_watcher.h"
9
10 #include <utility>
11
12 #include "base/bind.h"
13 #include "base/compiler_specific.h"
14 #include "base/files/file_path.h"
15 #include "base/location.h"
16 #include "base/logging.h"
17 #include "base/memory/ptr_util.h"
18 #include "base/single_thread_task_runner.h"
19 #include "base/values.h"
20 #include "build/build_config.h"
21 #include "components/policy/core/common/async_policy_loader.h"
22 #include "components/policy/core/common/async_policy_provider.h"
23 #include "components/policy/core/common/policy_namespace.h"
24 #include "components/policy/core/common/policy_service_impl.h"
25 #include "components/policy/core/common/schema.h"
26 #include "components/policy/core/common/schema_registry.h"
27 #include "components/policy/policy_constants.h"
28 #include "remoting/host/third_party_auth_config.h"
29 #include "remoting/protocol/port_range.h"
30
31 #if !defined(NDEBUG)
32 #include "base/json/json_reader.h"
33 #endif
34
35 #if defined(OS_WIN)
36 #include "components/policy/core/common/policy_loader_win.h"
37 #elif defined(OS_APPLE)
38 #include "components/policy/core/common/policy_loader_mac.h"
39 #include "components/policy/core/common/preferences_mac.h"
40 #elif defined(OS_POSIX) && !defined(OS_ANDROID)
41 #include "components/policy/core/common/config_dir_policy_loader.h"
42 #endif
43
44 namespace remoting {
45
46 namespace key = ::policy::key;
47
48 namespace {
49
50 // Copies all policy values from one dictionary to another, using values from
51 // |default_values| if they are not set in |from|.
CopyValuesAndAddDefaults(const base::DictionaryValue & from,const base::DictionaryValue & default_values)52 std::unique_ptr<base::DictionaryValue> CopyValuesAndAddDefaults(
53 const base::DictionaryValue& from,
54 const base::DictionaryValue& default_values) {
55 std::unique_ptr<base::DictionaryValue> to(default_values.CreateDeepCopy());
56 for (base::DictionaryValue::Iterator i(default_values); !i.IsAtEnd();
57 i.Advance()) {
58 const base::Value* value = nullptr;
59
60 // If the policy isn't in |from|, use the default.
61 if (!from.Get(i.key(), &value)) {
62 continue;
63 }
64
65 CHECK(value->type() == i.value().type());
66 to->Set(i.key(), value->CreateDeepCopy());
67 }
68
69 return to;
70 }
71
GetPolicyNamespace()72 policy::PolicyNamespace GetPolicyNamespace() {
73 return policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string());
74 }
75
CreateSchemaRegistry()76 std::unique_ptr<policy::SchemaRegistry> CreateSchemaRegistry() {
77 // TODO(lukasza): Schema below should ideally only cover Chromoting-specific
78 // policies (expecting perf and maintanability improvement, but no functional
79 // impact).
80 policy::Schema schema = policy::Schema::Wrap(policy::GetChromeSchemaData());
81
82 std::unique_ptr<policy::SchemaRegistry> schema_registry(
83 new policy::SchemaRegistry());
84 schema_registry->RegisterComponent(GetPolicyNamespace(), schema);
85 return schema_registry;
86 }
87
CopyChromotingPoliciesIntoDictionary(const policy::PolicyMap & current)88 std::unique_ptr<base::DictionaryValue> CopyChromotingPoliciesIntoDictionary(
89 const policy::PolicyMap& current) {
90 const char kPolicyNameSubstring[] = "RemoteAccessHost";
91 std::unique_ptr<base::DictionaryValue> policy_dict(
92 new base::DictionaryValue());
93 for (const auto& entry : current) {
94 const std::string& key = entry.first;
95 const base::Value* value = entry.second.value();
96
97 // Copying only Chromoting-specific policies helps avoid false alarms
98 // raised by NormalizePolicies below (such alarms shutdown the host).
99 // TODO(lukasza): Removing this somewhat brittle filtering will be possible
100 // after having separate, Chromoting-specific schema.
101 if (key.find(kPolicyNameSubstring) != std::string::npos) {
102 policy_dict->Set(key, value->CreateDeepCopy());
103 }
104 }
105
106 return policy_dict;
107 }
108
109 // Takes a dictionary containing only 1) recognized policy names and 2)
110 // well-typed policy values and further verifies policy contents.
VerifyWellformedness(const base::DictionaryValue & changed_policies)111 bool VerifyWellformedness(const base::DictionaryValue& changed_policies) {
112 // Verify ThirdPartyAuthConfig policy.
113 ThirdPartyAuthConfig not_used;
114 switch (ThirdPartyAuthConfig::Parse(changed_policies, ¬_used)) {
115 case ThirdPartyAuthConfig::NoPolicy:
116 case ThirdPartyAuthConfig::ParsingSuccess:
117 break; // Well-formed.
118 case ThirdPartyAuthConfig::InvalidPolicy:
119 return false; // Malformed.
120 default:
121 NOTREACHED();
122 return false;
123 }
124
125 // Verify UdpPortRange policy.
126 std::string udp_port_range_string;
127 PortRange udp_port_range;
128 if (changed_policies.GetString(policy::key::kRemoteAccessHostUdpPortRange,
129 &udp_port_range_string)) {
130 if (!PortRange::Parse(udp_port_range_string, &udp_port_range)) {
131 return false;
132 }
133 }
134
135 // Report that all the policies were well-formed.
136 return true;
137 }
138
139 } // namespace
140
StartWatching(const PolicyUpdatedCallback & policy_updated_callback,const PolicyErrorCallback & policy_error_callback)141 void PolicyWatcher::StartWatching(
142 const PolicyUpdatedCallback& policy_updated_callback,
143 const PolicyErrorCallback& policy_error_callback) {
144 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
145 DCHECK(!policy_updated_callback.is_null());
146 DCHECK(!policy_error_callback.is_null());
147 DCHECK(policy_updated_callback_.is_null());
148
149 policy_updated_callback_ = policy_updated_callback;
150 policy_error_callback_ = policy_error_callback;
151
152 // Listen for future policy changes.
153 policy_service_->AddObserver(policy::POLICY_DOMAIN_CHROME, this);
154
155 // Process current policy state.
156 if (policy_service_->IsInitializationComplete(policy::POLICY_DOMAIN_CHROME)) {
157 OnPolicyServiceInitialized(policy::POLICY_DOMAIN_CHROME);
158 }
159 }
160
GetCurrentPolicies()161 std::unique_ptr<base::DictionaryValue> PolicyWatcher::GetCurrentPolicies() {
162 return old_policies_->CreateDeepCopy();
163 }
164
GetDefaultPolicies()165 std::unique_ptr<base::DictionaryValue> PolicyWatcher::GetDefaultPolicies() {
166 auto result = std::make_unique<base::DictionaryValue>();
167 result->SetBoolean(key::kRemoteAccessHostFirewallTraversal, true);
168 result->SetBoolean(key::kRemoteAccessHostRequireCurtain, false);
169 result->SetBoolean(key::kRemoteAccessHostMatchUsername, false);
170 result->Set(key::kRemoteAccessHostClientDomainList,
171 std::make_unique<base::ListValue>());
172 result->Set(key::kRemoteAccessHostDomainList,
173 std::make_unique<base::ListValue>());
174 result->SetString(key::kRemoteAccessHostTokenUrl, std::string());
175 result->SetString(key::kRemoteAccessHostTokenValidationUrl, std::string());
176 result->SetString(key::kRemoteAccessHostTokenValidationCertificateIssuer,
177 std::string());
178 result->SetBoolean(key::kRemoteAccessHostAllowClientPairing, true);
179 result->SetBoolean(key::kRemoteAccessHostAllowGnubbyAuth, true);
180 result->SetBoolean(key::kRemoteAccessHostAllowRelayedConnection, true);
181 result->SetString(key::kRemoteAccessHostUdpPortRange, "");
182 result->SetBoolean(key::kRemoteAccessHostAllowUiAccessForRemoteAssistance,
183 false);
184 #if !defined(OS_CHROMEOS)
185 result->SetBoolean(key::kRemoteAccessHostAllowFileTransfer, true);
186 result->SetBoolean(key::kRemoteAccessHostEnableUserInterface, true);
187 #endif
188 return result;
189 }
190
SignalPolicyError()191 void PolicyWatcher::SignalPolicyError() {
192 old_policies_->Clear();
193 policy_error_callback_.Run();
194 }
195
PolicyWatcher(policy::PolicyService * policy_service,std::unique_ptr<policy::PolicyService> owned_policy_service,std::unique_ptr<policy::ConfigurationPolicyProvider> owned_policy_provider,std::unique_ptr<policy::SchemaRegistry> owned_schema_registry)196 PolicyWatcher::PolicyWatcher(
197 policy::PolicyService* policy_service,
198 std::unique_ptr<policy::PolicyService> owned_policy_service,
199 std::unique_ptr<policy::ConfigurationPolicyProvider> owned_policy_provider,
200 std::unique_ptr<policy::SchemaRegistry> owned_schema_registry)
201 : old_policies_(new base::DictionaryValue()),
202 default_values_(GetDefaultPolicies()),
203 policy_service_(policy_service),
204 owned_schema_registry_(std::move(owned_schema_registry)),
205 owned_policy_provider_(std::move(owned_policy_provider)),
206 owned_policy_service_(std::move(owned_policy_service)) {
207 DCHECK(policy_service_);
208 DCHECK(owned_schema_registry_);
209 }
210
~PolicyWatcher()211 PolicyWatcher::~PolicyWatcher() {
212 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
213 // Stop observing |policy_service_| if StartWatching() has been called.
214 if (!policy_updated_callback_.is_null()) {
215 policy_service_->RemoveObserver(policy::POLICY_DOMAIN_CHROME, this);
216 }
217
218 if (owned_policy_provider_) {
219 owned_policy_provider_->Shutdown();
220 }
221 }
222
GetPolicySchema() const223 const policy::Schema* PolicyWatcher::GetPolicySchema() const {
224 return owned_schema_registry_->schema_map()->GetSchema(GetPolicyNamespace());
225 }
226
NormalizePolicies(base::DictionaryValue * policy_dict)227 bool PolicyWatcher::NormalizePolicies(base::DictionaryValue* policy_dict) {
228 // Allowing unrecognized policy names allows presence of
229 // 1) comments (i.e. JSON of the form: { "_comment": "blah", ... }),
230 // 2) policies intended for future/newer versions of the host,
231 // 3) policies not supported on all OS-s (i.e. RemoteAccessHostMatchUsername
232 // is not supported on Windows and therefore policy_templates.json omits
233 // schema for this policy on this particular platform).
234 auto strategy = policy::SCHEMA_ALLOW_UNKNOWN;
235
236 std::string path;
237 std::string error;
238 bool changed = false;
239 const policy::Schema* schema = GetPolicySchema();
240 if (schema->Normalize(policy_dict, strategy, &path, &error, &changed)) {
241 if (changed) {
242 LOG(WARNING) << "Unknown (unrecognized or unsupported) policy: " << path
243 << ": " << error;
244 }
245 HandleDeprecatedPolicies(policy_dict);
246 return true;
247 } else {
248 LOG(ERROR) << "Invalid policy contents: " << path << ": " << error;
249 return false;
250 }
251 }
252
HandleDeprecatedPolicies(base::DictionaryValue * dict)253 void PolicyWatcher::HandleDeprecatedPolicies(base::DictionaryValue* dict) {
254 // RemoteAccessHostDomain
255 if (dict->HasKey(policy::key::kRemoteAccessHostDomain)) {
256 if (!dict->HasKey(policy::key::kRemoteAccessHostDomainList)) {
257 std::string domain;
258 dict->GetString(policy::key::kRemoteAccessHostDomain, &domain);
259 if (!domain.empty()) {
260 auto list = std::make_unique<base::ListValue>();
261 list->AppendString(domain);
262 dict->Set(policy::key::kRemoteAccessHostDomainList, std::move(list));
263 }
264 }
265 dict->Remove(policy::key::kRemoteAccessHostDomain, nullptr);
266 }
267
268 // RemoteAccessHostClientDomain
269 if (dict->HasKey(policy::key::kRemoteAccessHostClientDomain)) {
270 if (!dict->HasKey(policy::key::kRemoteAccessHostClientDomainList)) {
271 std::string domain;
272 dict->GetString(policy::key::kRemoteAccessHostClientDomain, &domain);
273 if (!domain.empty()) {
274 auto list = std::make_unique<base::ListValue>();
275 list->AppendString(domain);
276 dict->Set(policy::key::kRemoteAccessHostClientDomainList,
277 std::move(list));
278 }
279 }
280 dict->Remove(policy::key::kRemoteAccessHostClientDomain, nullptr);
281 }
282 }
283
284 namespace {
CopyDictionaryValue(const base::DictionaryValue & from,base::DictionaryValue & to,std::string key)285 void CopyDictionaryValue(const base::DictionaryValue& from,
286 base::DictionaryValue& to,
287 std::string key) {
288 const base::Value* value;
289 if (from.Get(key, &value)) {
290 to.Set(key, value->CreateDeepCopy());
291 }
292 }
293 } // namespace
294
295 std::unique_ptr<base::DictionaryValue>
StoreNewAndReturnChangedPolicies(std::unique_ptr<base::DictionaryValue> new_policies)296 PolicyWatcher::StoreNewAndReturnChangedPolicies(
297 std::unique_ptr<base::DictionaryValue> new_policies) {
298 // Find the changed policies.
299 std::unique_ptr<base::DictionaryValue> changed_policies(
300 new base::DictionaryValue());
301 base::DictionaryValue::Iterator iter(*new_policies);
302 while (!iter.IsAtEnd()) {
303 base::Value* old_policy;
304 if (!(old_policies_->Get(iter.key(), &old_policy) &&
305 old_policy->Equals(&iter.value()))) {
306 changed_policies->Set(iter.key(), iter.value().CreateDeepCopy());
307 }
308 iter.Advance();
309 }
310
311 // If one of ThirdPartyAuthConfig policies changed, we need to include all.
312 if (changed_policies->HasKey(key::kRemoteAccessHostTokenUrl) ||
313 changed_policies->HasKey(key::kRemoteAccessHostTokenValidationUrl) ||
314 changed_policies->HasKey(
315 key::kRemoteAccessHostTokenValidationCertificateIssuer)) {
316 CopyDictionaryValue(*new_policies, *changed_policies,
317 key::kRemoteAccessHostTokenUrl);
318 CopyDictionaryValue(*new_policies, *changed_policies,
319 key::kRemoteAccessHostTokenValidationUrl);
320 CopyDictionaryValue(*new_policies, *changed_policies,
321 key::kRemoteAccessHostTokenValidationCertificateIssuer);
322 }
323
324 // Save the new policies.
325 old_policies_.swap(new_policies);
326
327 return changed_policies;
328 }
329
OnPolicyUpdated(const policy::PolicyNamespace & ns,const policy::PolicyMap & previous,const policy::PolicyMap & current)330 void PolicyWatcher::OnPolicyUpdated(const policy::PolicyNamespace& ns,
331 const policy::PolicyMap& previous,
332 const policy::PolicyMap& current) {
333 std::unique_ptr<base::DictionaryValue> new_policies =
334 CopyChromotingPoliciesIntoDictionary(current);
335
336 // Check for mistyped values and get rid of unknown policies.
337 if (!NormalizePolicies(new_policies.get())) {
338 SignalPolicyError();
339 return;
340 }
341
342 // Use default values for any missing policies.
343 std::unique_ptr<base::DictionaryValue> filled_policies =
344 CopyValuesAndAddDefaults(*new_policies, *default_values_);
345
346 // Limit reporting to only the policies that were changed.
347 std::unique_ptr<base::DictionaryValue> changed_policies =
348 StoreNewAndReturnChangedPolicies(std::move(filled_policies));
349 if (changed_policies->empty()) {
350 return;
351 }
352
353 // Verify that we are calling the callback with valid policies.
354 if (!VerifyWellformedness(*changed_policies)) {
355 SignalPolicyError();
356 return;
357 }
358
359 // Notify our client of the changed policies.
360 policy_updated_callback_.Run(std::move(changed_policies));
361 }
362
OnPolicyServiceInitialized(policy::PolicyDomain domain)363 void PolicyWatcher::OnPolicyServiceInitialized(policy::PolicyDomain domain) {
364 policy::PolicyNamespace ns = GetPolicyNamespace();
365 const policy::PolicyMap& current = policy_service_->GetPolicies(ns);
366 OnPolicyUpdated(ns, current, current);
367 }
368
CreateFromPolicyLoader(std::unique_ptr<policy::AsyncPolicyLoader> async_policy_loader)369 std::unique_ptr<PolicyWatcher> PolicyWatcher::CreateFromPolicyLoader(
370 std::unique_ptr<policy::AsyncPolicyLoader> async_policy_loader) {
371 std::unique_ptr<policy::SchemaRegistry> schema_registry =
372 CreateSchemaRegistry();
373 std::unique_ptr<policy::AsyncPolicyProvider> policy_provider(
374 new policy::AsyncPolicyProvider(schema_registry.get(),
375 std::move(async_policy_loader)));
376 policy_provider->Init(schema_registry.get());
377
378 policy::PolicyServiceImpl::Providers providers;
379 providers.push_back(policy_provider.get());
380 std::unique_ptr<policy::PolicyServiceImpl> policy_service =
381 std::make_unique<policy::PolicyServiceImpl>(std::move(providers));
382
383 policy::PolicyService* borrowed_policy_service = policy_service.get();
384 return base::WrapUnique(new PolicyWatcher(
385 borrowed_policy_service, std::move(policy_service),
386 std::move(policy_provider), std::move(schema_registry)));
387 }
388
CreateWithPolicyService(policy::PolicyService * policy_service)389 std::unique_ptr<PolicyWatcher> PolicyWatcher::CreateWithPolicyService(
390 policy::PolicyService* policy_service) {
391 DCHECK(policy_service);
392 return base::WrapUnique(new PolicyWatcher(policy_service, nullptr, nullptr,
393 CreateSchemaRegistry()));
394 }
395
CreateWithTaskRunner(const scoped_refptr<base::SingleThreadTaskRunner> & file_task_runner)396 std::unique_ptr<PolicyWatcher> PolicyWatcher::CreateWithTaskRunner(
397 const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner) {
398 // Create platform-specific PolicyLoader. Always read the Chrome policies
399 // (even on Chromium) so that policy enforcement can't be bypassed by running
400 // Chromium.
401 std::unique_ptr<policy::AsyncPolicyLoader> policy_loader;
402 #if defined(OS_WIN)
403 policy_loader.reset(new policy::PolicyLoaderWin(
404 file_task_runner, L"SOFTWARE\\Policies\\Google\\Chrome"));
405 #elif defined(OS_APPLE)
406 CFStringRef bundle_id = CFSTR("com.google.Chrome");
407 policy_loader.reset(new policy::PolicyLoaderMac(
408 file_task_runner,
409 policy::PolicyLoaderMac::GetManagedPolicyPath(bundle_id),
410 new MacPreferences(), bundle_id));
411 #elif defined(OS_POSIX) && !defined(OS_ANDROID)
412 policy_loader.reset(new policy::ConfigDirPolicyLoader(
413 file_task_runner,
414 base::FilePath(FILE_PATH_LITERAL("/etc/opt/chrome/policies")),
415 policy::POLICY_SCOPE_MACHINE));
416 #elif defined(OS_ANDROID)
417 NOTIMPLEMENTED();
418 policy::PolicyServiceImpl::Providers providers;
419 std::unique_ptr<policy::PolicyService> owned_policy_service(
420 new policy::PolicyServiceImpl(providers));
421 return base::WrapUnique(new PolicyWatcher(
422 owned_policy_service.get(), std::move(owned_policy_service), nullptr,
423 CreateSchemaRegistry()));
424 #elif defined(OS_CHROMEOS)
425 NOTREACHED() << "CreateWithPolicyService() should be used on ChromeOS.";
426 return nullptr;
427 #else
428 #error OS that is not yet supported by PolicyWatcher code.
429 #endif
430
431 return PolicyWatcher::CreateFromPolicyLoader(std::move(policy_loader));
432 }
433
CreateFromPolicyLoaderForTesting(std::unique_ptr<policy::AsyncPolicyLoader> async_policy_loader)434 std::unique_ptr<PolicyWatcher> PolicyWatcher::CreateFromPolicyLoaderForTesting(
435 std::unique_ptr<policy::AsyncPolicyLoader> async_policy_loader) {
436 return CreateFromPolicyLoader(std::move(async_policy_loader));
437 }
438
439 } // namespace remoting
440