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, &not_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