blob: ea90d6373928aa7e905e2ecd63142588fa9e3a4c [file] [log] [blame]
lukaszac285c9a2015-01-29 23:18:281// Copyright 2015 The Chromium Authors. All rights reserved.
[email protected]000d1f62012-07-24 01:56:542// 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
lukaszac285c9a2015-01-29 23:18:288#include "remoting/host/policy_watcher.h"
[email protected]000d1f62012-07-24 01:56:549
sergeyu1417e0132015-12-23 19:01:2210#include <utility>
11
[email protected]000d1f62012-07-24 01:56:5412#include "base/bind.h"
13#include "base/compiler_specific.h"
lukaszaa9376cd2015-01-28 20:29:0114#include "base/files/file_path.h"
[email protected]000d1f62012-07-24 01:56:5415#include "base/location.h"
dcheng0765c492016-04-06 22:41:5316#include "base/memory/ptr_util.h"
[email protected]000d1f62012-07-24 01:56:5417#include "base/single_thread_task_runner.h"
[email protected]000d1f62012-07-24 01:56:5418#include "base/values.h"
avic5960f32015-12-22 22:49:4819#include "build/build_config.h"
lukaszaa9376cd2015-01-28 20:29:0120#include "components/policy/core/common/async_policy_loader.h"
21#include "components/policy/core/common/async_policy_provider.h"
22#include "components/policy/core/common/policy_namespace.h"
23#include "components/policy/core/common/policy_service_impl.h"
24#include "components/policy/core/common/schema.h"
25#include "components/policy/core/common/schema_registry.h"
Lukasz Anforowicz2b91a4802015-01-16 22:39:4626#include "policy/policy_constants.h"
[email protected]11bb05a2012-09-01 03:05:2127#include "remoting/host/dns_blackhole_checker.h"
lukasza0d40d8a2015-03-03 18:36:2828#include "remoting/host/third_party_auth_config.h"
29#include "remoting/protocol/port_range.h"
[email protected]000d1f62012-07-24 01:56:5430
[email protected]158b2872012-11-13 10:08:3831#if !defined(NDEBUG)
32#include "base/json/json_reader.h"
33#endif
34
sergeyub2ae7e32015-01-30 23:33:2535#if defined(OS_WIN)
lukaszaa9376cd2015-01-28 20:29:0136#include "components/policy/core/common/policy_loader_win.h"
37#elif defined(OS_MACOSX)
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
[email protected]000d1f62012-07-24 01:56:5444namespace remoting {
[email protected]000d1f62012-07-24 01:56:5445
lukaszaa9376cd2015-01-28 20:29:0146namespace key = ::policy::key;
47
[email protected]000d1f62012-07-24 01:56:5448namespace {
[email protected]bf931a42012-11-10 19:07:0249
[email protected]bf931a42012-11-10 19:07:0250// Copies all policy values from one dictionary to another, using values from
lukaszae5d69ea2015-02-23 21:00:3151// |default_values| if they are not set in |from|.
dcheng0765c492016-04-06 22:41:5352std::unique_ptr<base::DictionaryValue> CopyValuesAndAddDefaults(
lukasza0d40d8a2015-03-03 18:36:2853 const base::DictionaryValue& from,
54 const base::DictionaryValue& default_values) {
dchengefaf1b112016-05-03 01:12:4955 std::unique_ptr<base::DictionaryValue> to(default_values.CreateDeepCopy());
lukasza0d40d8a2015-03-03 18:36:2856 for (base::DictionaryValue::Iterator i(default_values); !i.IsAtEnd();
lukaszac285c9a2015-01-29 23:18:2857 i.Advance()) {
sergeyuc5f104b2015-01-09 19:33:2458 const base::Value* value = nullptr;
[email protected]bf931a42012-11-10 19:07:0259
60 // If the policy isn't in |from|, use the default.
lukasza0d40d8a2015-03-03 18:36:2861 if (!from.Get(i.key(), &value)) {
[email protected]bf931a42012-11-10 19:07:0262 continue;
63 }
64
lukaszae5d69ea2015-02-23 21:00:3165 CHECK(value->IsType(i.value().GetType()));
dchengefaf1b112016-05-03 01:12:4966 to->Set(i.key(), value->CreateDeepCopy());
[email protected]b9612a52012-07-28 02:17:4867 }
[email protected]50409b32012-07-31 18:54:0268
sergeyu1417e0132015-12-23 19:01:2269 return to;
[email protected]000d1f62012-07-24 01:56:5470}
71
lukaszaa9376cd2015-01-28 20:29:0172policy::PolicyNamespace GetPolicyNamespace() {
73 return policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string());
74}
75
dcheng0765c492016-04-06 22:41:5376std::unique_ptr<policy::SchemaRegistry> CreateSchemaRegistry() {
lukaszae5d69ea2015-02-23 21:00:3177 // 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
dcheng0765c492016-04-06 22:41:5382 std::unique_ptr<policy::SchemaRegistry> schema_registry(
lukaszae5d69ea2015-02-23 21:00:3183 new policy::SchemaRegistry());
84 schema_registry->RegisterComponent(GetPolicyNamespace(), schema);
sergeyu1417e0132015-12-23 19:01:2285 return schema_registry;
lukaszae5d69ea2015-02-23 21:00:3186}
87
dcheng0765c492016-04-06 22:41:5388std::unique_ptr<base::DictionaryValue> CopyChromotingPoliciesIntoDictionary(
lukasza0d40d8a2015-03-03 18:36:2889 const policy::PolicyMap& current) {
90 const char kPolicyNameSubstring[] = "RemoteAccessHost";
dcheng0765c492016-04-06 22:41:5391 std::unique_ptr<base::DictionaryValue> policy_dict(
92 new base::DictionaryValue());
dcheng3b344bc22016-05-10 02:26:0993 for (const auto& entry : current) {
94 const std::string& key = entry.first;
95 const base::Value* value = entry.second.value.get();
lukasza0d40d8a2015-03-03 18:36:2896
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) {
dchengefaf1b112016-05-03 01:12:49102 policy_dict->Set(key, value->CreateDeepCopy());
lukasza0d40d8a2015-03-03 18:36:28103 }
104 }
105
sergeyu1417e0132015-12-23 19:01:22106 return policy_dict;
lukasza0d40d8a2015-03-03 18:36:28107}
108
109// Takes a dictionary containing only 1) recognized policy names and 2)
110// well-typed policy values and further verifies policy contents.
111bool 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
[email protected]000d1f62012-07-24 01:56:54139} // namespace
140
lukasza0fdd9512014-11-25 17:47:46141void PolicyWatcher::StartWatching(
142 const PolicyUpdatedCallback& policy_updated_callback,
143 const PolicyErrorCallback& policy_error_callback) {
sergeyub2ae7e32015-01-30 23:33:25144 DCHECK(CalledOnValidThread());
145 DCHECK(!policy_updated_callback.is_null());
146 DCHECK(!policy_error_callback.is_null());
147 DCHECK(policy_updated_callback_.is_null());
[email protected]000d1f62012-07-24 01:56:54148
lukasza0fdd9512014-11-25 17:47:46149 policy_updated_callback_ = policy_updated_callback;
150 policy_error_callback_ = policy_error_callback;
lukaszaa9376cd2015-01-28 20:29:01151
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 }
[email protected]000d1f62012-07-24 01:56:54159}
160
lukasza0fdd9512014-11-25 17:47:46161void PolicyWatcher::SignalPolicyError() {
lukaszafecb18b2015-02-24 01:04:12162 old_policies_->Clear();
lukasza0fdd9512014-11-25 17:47:46163 policy_error_callback_.Run();
164}
165
lukaszaa9376cd2015-01-28 20:29:01166PolicyWatcher::PolicyWatcher(
lukaszaa9376cd2015-01-28 20:29:01167 policy::PolicyService* policy_service,
dcheng0765c492016-04-06 22:41:53168 std::unique_ptr<policy::PolicyService> owned_policy_service,
169 std::unique_ptr<policy::ConfigurationPolicyProvider> owned_policy_provider,
170 std::unique_ptr<policy::SchemaRegistry> owned_schema_registry)
lukaszae5d69ea2015-02-23 21:00:31171 : old_policies_(new base::DictionaryValue()),
lukaszaa9376cd2015-01-28 20:29:01172 default_values_(new base::DictionaryValue()),
173 policy_service_(policy_service),
sergeyu1417e0132015-12-23 19:01:22174 owned_schema_registry_(std::move(owned_schema_registry)),
175 owned_policy_provider_(std::move(owned_policy_provider)),
176 owned_policy_service_(std::move(owned_policy_service)) {
lukaszae5d69ea2015-02-23 21:00:31177 DCHECK(policy_service_);
178 DCHECK(owned_schema_registry_);
179
lukaszaa9376cd2015-01-28 20:29:01180 // Initialize the default values for each policy.
181 default_values_->SetBoolean(key::kRemoteAccessHostFirewallTraversal, true);
lukaszaa9376cd2015-01-28 20:29:01182 default_values_->SetBoolean(key::kRemoteAccessHostRequireCurtain, false);
183 default_values_->SetBoolean(key::kRemoteAccessHostMatchUsername, false);
jamiewalchb438fb9d2016-02-08 23:20:12184 default_values_->SetString(key::kRemoteAccessHostClientDomain, std::string());
lukaszaa9376cd2015-01-28 20:29:01185 default_values_->SetString(key::kRemoteAccessHostDomain, std::string());
186 default_values_->SetString(key::kRemoteAccessHostTalkGadgetPrefix,
187 kDefaultHostTalkGadgetPrefix);
188 default_values_->SetString(key::kRemoteAccessHostTokenUrl, std::string());
189 default_values_->SetString(key::kRemoteAccessHostTokenValidationUrl,
190 std::string());
191 default_values_->SetString(
192 key::kRemoteAccessHostTokenValidationCertificateIssuer, std::string());
193 default_values_->SetBoolean(key::kRemoteAccessHostAllowClientPairing, true);
194 default_values_->SetBoolean(key::kRemoteAccessHostAllowGnubbyAuth, true);
195 default_values_->SetBoolean(key::kRemoteAccessHostAllowRelayedConnection,
196 true);
197 default_values_->SetString(key::kRemoteAccessHostUdpPortRange, "");
lukaszaa9376cd2015-01-28 20:29:01198}
199
200PolicyWatcher::~PolicyWatcher() {
sergeyub2ae7e32015-01-30 23:33:25201 // Stop observing |policy_service_| if StartWatching() has been called.
202 if (!policy_updated_callback_.is_null()) {
203 policy_service_->RemoveObserver(policy::POLICY_DOMAIN_CHROME, this);
204 }
205
lukaszaa9376cd2015-01-28 20:29:01206 if (owned_policy_provider_) {
207 owned_policy_provider_->Shutdown();
208 }
209}
210
lukaszae5d69ea2015-02-23 21:00:31211const policy::Schema* PolicyWatcher::GetPolicySchema() const {
212 return owned_schema_registry_->schema_map()->GetSchema(GetPolicyNamespace());
213}
214
lukasza0d40d8a2015-03-03 18:36:28215bool PolicyWatcher::NormalizePolicies(base::DictionaryValue* policy_dict) {
lukaszae5d69ea2015-02-23 21:00:31216 // Allowing unrecognized policy names allows presence of
217 // 1) comments (i.e. JSON of the form: { "_comment": "blah", ... }),
218 // 2) policies intended for future/newer versions of the host,
219 // 3) policies not supported on all OS-s (i.e. RemoteAccessHostMatchUsername
220 // is not supported on Windows and therefore policy_templates.json omits
221 // schema for this policy on this particular platform).
222 auto strategy = policy::SCHEMA_ALLOW_UNKNOWN_TOPLEVEL;
223
224 std::string path;
225 std::string error;
lukasza1ffc24b2015-02-23 23:28:03226 bool changed = false;
lukaszae5d69ea2015-02-23 21:00:31227 const policy::Schema* schema = GetPolicySchema();
lukasza0d40d8a2015-03-03 18:36:28228 if (schema->Normalize(policy_dict, strategy, &path, &error, &changed)) {
lukaszae5d69ea2015-02-23 21:00:31229 if (changed) {
230 LOG(WARNING) << "Unknown (unrecognized or unsupported) policy: " << path
231 << ": " << error;
232 }
lukasza0d40d8a2015-03-03 18:36:28233 return true;
lukaszae5d69ea2015-02-23 21:00:31234 } else {
235 LOG(ERROR) << "Invalid policy contents: " << path << ": " << error;
lukasza0d40d8a2015-03-03 18:36:28236 return false;
lukaszae5d69ea2015-02-23 21:00:31237 }
lukaszaa9376cd2015-01-28 20:29:01238}
239
lukasza0d40d8a2015-03-03 18:36:28240namespace {
241void CopyDictionaryValue(const base::DictionaryValue& from,
242 base::DictionaryValue& to,
243 std::string key) {
244 const base::Value* value;
245 if (from.Get(key, &value)) {
dchengefaf1b112016-05-03 01:12:49246 to.Set(key, value->CreateDeepCopy());
lukasza0d40d8a2015-03-03 18:36:28247 }
248}
249} // namespace
250
dcheng0765c492016-04-06 22:41:53251std::unique_ptr<base::DictionaryValue>
lukasza0d40d8a2015-03-03 18:36:28252PolicyWatcher::StoreNewAndReturnChangedPolicies(
dcheng0765c492016-04-06 22:41:53253 std::unique_ptr<base::DictionaryValue> new_policies) {
lukasza0d40d8a2015-03-03 18:36:28254 // Find the changed policies.
dcheng0765c492016-04-06 22:41:53255 std::unique_ptr<base::DictionaryValue> changed_policies(
lukasza0d40d8a2015-03-03 18:36:28256 new base::DictionaryValue());
257 base::DictionaryValue::Iterator iter(*new_policies);
258 while (!iter.IsAtEnd()) {
259 base::Value* old_policy;
260 if (!(old_policies_->Get(iter.key(), &old_policy) &&
261 old_policy->Equals(&iter.value()))) {
dchengefaf1b112016-05-03 01:12:49262 changed_policies->Set(iter.key(), iter.value().CreateDeepCopy());
lukasza0d40d8a2015-03-03 18:36:28263 }
264 iter.Advance();
265 }
266
267 // If one of ThirdPartyAuthConfig policies changed, we need to include all.
268 if (changed_policies->HasKey(key::kRemoteAccessHostTokenUrl) ||
269 changed_policies->HasKey(key::kRemoteAccessHostTokenValidationUrl) ||
270 changed_policies->HasKey(
271 key::kRemoteAccessHostTokenValidationCertificateIssuer)) {
272 CopyDictionaryValue(*new_policies, *changed_policies,
273 key::kRemoteAccessHostTokenUrl);
274 CopyDictionaryValue(*new_policies, *changed_policies,
275 key::kRemoteAccessHostTokenValidationUrl);
276 CopyDictionaryValue(*new_policies, *changed_policies,
277 key::kRemoteAccessHostTokenValidationCertificateIssuer);
278 }
279
280 // Save the new policies.
281 old_policies_.swap(new_policies);
282
sergeyu1417e0132015-12-23 19:01:22283 return changed_policies;
lukasza0d40d8a2015-03-03 18:36:28284}
285
286void PolicyWatcher::OnPolicyUpdated(const policy::PolicyNamespace& ns,
287 const policy::PolicyMap& previous,
288 const policy::PolicyMap& current) {
dcheng0765c492016-04-06 22:41:53289 std::unique_ptr<base::DictionaryValue> new_policies =
lukasza0d40d8a2015-03-03 18:36:28290 CopyChromotingPoliciesIntoDictionary(current);
291
292 // Check for mistyped values and get rid of unknown policies.
293 if (!NormalizePolicies(new_policies.get())) {
294 SignalPolicyError();
295 return;
296 }
297
298 // Use default values for any missing policies.
dcheng0765c492016-04-06 22:41:53299 std::unique_ptr<base::DictionaryValue> filled_policies =
lukasza0d40d8a2015-03-03 18:36:28300 CopyValuesAndAddDefaults(*new_policies, *default_values_);
301
302 // Limit reporting to only the policies that were changed.
dcheng0765c492016-04-06 22:41:53303 std::unique_ptr<base::DictionaryValue> changed_policies =
sergeyu1417e0132015-12-23 19:01:22304 StoreNewAndReturnChangedPolicies(std::move(filled_policies));
lukasza0d40d8a2015-03-03 18:36:28305 if (changed_policies->empty()) {
306 return;
307 }
308
309 // Verify that we are calling the callback with valid policies.
310 if (!VerifyWellformedness(*changed_policies)) {
311 SignalPolicyError();
312 return;
313 }
314
315 // Notify our client of the changed policies.
sergeyu1417e0132015-12-23 19:01:22316 policy_updated_callback_.Run(std::move(changed_policies));
lukasza0d40d8a2015-03-03 18:36:28317}
318
lukaszaa9376cd2015-01-28 20:29:01319void PolicyWatcher::OnPolicyServiceInitialized(policy::PolicyDomain domain) {
320 policy::PolicyNamespace ns = GetPolicyNamespace();
321 const policy::PolicyMap& current = policy_service_->GetPolicies(ns);
322 OnPolicyUpdated(ns, current, current);
323}
324
dcheng0765c492016-04-06 22:41:53325std::unique_ptr<PolicyWatcher> PolicyWatcher::CreateFromPolicyLoader(
326 std::unique_ptr<policy::AsyncPolicyLoader> async_policy_loader) {
327 std::unique_ptr<policy::SchemaRegistry> schema_registry =
328 CreateSchemaRegistry();
329 std::unique_ptr<policy::AsyncPolicyProvider> policy_provider(
lukaszaa9376cd2015-01-28 20:29:01330 new policy::AsyncPolicyProvider(schema_registry.get(),
sergeyu1417e0132015-12-23 19:01:22331 std::move(async_policy_loader)));
lukaszaa9376cd2015-01-28 20:29:01332 policy_provider->Init(schema_registry.get());
333
334 policy::PolicyServiceImpl::Providers providers;
335 providers.push_back(policy_provider.get());
dcheng0765c492016-04-06 22:41:53336 std::unique_ptr<policy::PolicyService> policy_service(
lukaszaa9376cd2015-01-28 20:29:01337 new policy::PolicyServiceImpl(providers));
338
339 policy::PolicyService* borrowed_policy_service = policy_service.get();
dcheng0765c492016-04-06 22:41:53340 return base::WrapUnique(new PolicyWatcher(
sergeyu1417e0132015-12-23 19:01:22341 borrowed_policy_service, std::move(policy_service),
342 std::move(policy_provider), std::move(schema_registry)));
lukaszaa9376cd2015-01-28 20:29:01343}
344
dcheng0765c492016-04-06 22:41:53345std::unique_ptr<PolicyWatcher> PolicyWatcher::Create(
lukaszaa9376cd2015-01-28 20:29:01346 policy::PolicyService* policy_service,
sergeyub2ae7e32015-01-30 23:33:25347 const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner) {
lukaszaa9376cd2015-01-28 20:29:01348#if defined(OS_CHROMEOS)
sergeyub2ae7e32015-01-30 23:33:25349 // On Chrome OS the PolicyService is owned by the browser.
lukaszaa9376cd2015-01-28 20:29:01350 DCHECK(policy_service);
dcheng0765c492016-04-06 22:41:53351 return base::WrapUnique(new PolicyWatcher(policy_service, nullptr, nullptr,
352 CreateSchemaRegistry()));
sergeyub2ae7e32015-01-30 23:33:25353#else // !defined(OS_CHROMEOS)
lukaszaa9376cd2015-01-28 20:29:01354 DCHECK(!policy_service);
sergeyub2ae7e32015-01-30 23:33:25355
356 // Create platform-specific PolicyLoader. Always read the Chrome policies
357 // (even on Chromium) so that policy enforcement can't be bypassed by running
358 // Chromium.
dcheng0765c492016-04-06 22:41:53359 std::unique_ptr<policy::AsyncPolicyLoader> policy_loader;
sergeyub2ae7e32015-01-30 23:33:25360#if defined(OS_WIN)
lukaszabccb49e2015-02-24 20:10:28361 policy_loader.reset(new policy::PolicyLoaderWin(
362 file_task_runner, L"SOFTWARE\\Policies\\Google\\Chrome",
363 nullptr)); // nullptr = don't use GPO / always read from the registry.
lukaszaa9376cd2015-01-28 20:29:01364#elif defined(OS_MACOSX)
365 CFStringRef bundle_id = CFSTR("com.google.Chrome");
sergeyub2ae7e32015-01-30 23:33:25366 policy_loader.reset(new policy::PolicyLoaderMac(
367 file_task_runner,
368 policy::PolicyLoaderMac::GetManagedPolicyPath(bundle_id),
369 new MacPreferences(), bundle_id));
lukaszaa9376cd2015-01-28 20:29:01370#elif defined(OS_POSIX) && !defined(OS_ANDROID)
sergeyub2ae7e32015-01-30 23:33:25371 policy_loader.reset(new policy::ConfigDirPolicyLoader(
372 file_task_runner,
373 base::FilePath(FILE_PATH_LITERAL("/etc/opt/chrome/policies")),
374 policy::POLICY_SCOPE_MACHINE));
lambroslambrou51e19b92016-04-13 21:30:41375#elif defined(OS_ANDROID)
376 NOTIMPLEMENTED();
lambroslambrou709327e2016-04-26 19:07:34377 policy::PolicyServiceImpl::Providers providers;
378 std::unique_ptr<policy::PolicyService> owned_policy_service(
379 new policy::PolicyServiceImpl(providers));
380 return base::WrapUnique(new PolicyWatcher(
381 owned_policy_service.get(), std::move(owned_policy_service), nullptr,
382 CreateSchemaRegistry()));
lukaszaa9376cd2015-01-28 20:29:01383#else
384#error OS that is not yet supported by PolicyWatcher code.
385#endif
sergeyub2ae7e32015-01-30 23:33:25386
sergeyu1417e0132015-12-23 19:01:22387 return PolicyWatcher::CreateFromPolicyLoader(std::move(policy_loader));
sergeyub2ae7e32015-01-30 23:33:25388#endif // !(OS_CHROMEOS)
lukaszaa9376cd2015-01-28 20:29:01389}
390
[email protected]000d1f62012-07-24 01:56:54391} // namespace remoting