Update SplitString calls to new form
[chromium-blink-merge.git] / remoting / host / policy_watcher.cc
blob5ea71d9145eef66974c99eb9d388ce2676b615f4
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"
24 #include "remoting/host/third_party_auth_config.h"
25 #include "remoting/protocol/port_range.h"
27 #if !defined(NDEBUG)
28 #include "base/json/json_reader.h"
29 #endif
31 #if defined(OS_WIN)
32 #include "components/policy/core/common/policy_loader_win.h"
33 #elif defined(OS_MACOSX)
34 #include "components/policy/core/common/policy_loader_mac.h"
35 #include "components/policy/core/common/preferences_mac.h"
36 #elif defined(OS_POSIX) && !defined(OS_ANDROID)
37 #include "components/policy/core/common/config_dir_policy_loader.h"
38 #endif
40 namespace remoting {
42 namespace key = ::policy::key;
44 namespace {
46 // Copies all policy values from one dictionary to another, using values from
47 // |default_values| if they are not set in |from|.
48 scoped_ptr<base::DictionaryValue> CopyValuesAndAddDefaults(
49 const base::DictionaryValue& from,
50 const base::DictionaryValue& default_values) {
51 scoped_ptr<base::DictionaryValue> to(default_values.DeepCopy());
52 for (base::DictionaryValue::Iterator i(default_values); !i.IsAtEnd();
53 i.Advance()) {
54 const base::Value* value = nullptr;
56 // If the policy isn't in |from|, use the default.
57 if (!from.Get(i.key(), &value)) {
58 continue;
61 CHECK(value->IsType(i.value().GetType()));
62 to->Set(i.key(), value->DeepCopy());
65 #if !defined(NDEBUG)
66 // Replace values with those specified in DebugOverridePolicies, if present.
67 std::string policy_overrides;
68 if (from.GetString(key::kRemoteAccessHostDebugOverridePolicies,
69 &policy_overrides)) {
70 scoped_ptr<base::Value> value = base::JSONReader::Read(policy_overrides);
71 const base::DictionaryValue* override_values;
72 if (value && value->GetAsDictionary(&override_values)) {
73 to->MergeDictionary(override_values);
76 #endif // defined(NDEBUG)
78 return to.Pass();
81 policy::PolicyNamespace GetPolicyNamespace() {
82 return policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string());
85 scoped_ptr<policy::SchemaRegistry> CreateSchemaRegistry() {
86 // TODO(lukasza): Schema below should ideally only cover Chromoting-specific
87 // policies (expecting perf and maintanability improvement, but no functional
88 // impact).
89 policy::Schema schema = policy::Schema::Wrap(policy::GetChromeSchemaData());
91 scoped_ptr<policy::SchemaRegistry> schema_registry(
92 new policy::SchemaRegistry());
93 schema_registry->RegisterComponent(GetPolicyNamespace(), schema);
94 return schema_registry.Pass();
97 scoped_ptr<base::DictionaryValue> CopyChromotingPoliciesIntoDictionary(
98 const policy::PolicyMap& current) {
99 const char kPolicyNameSubstring[] = "RemoteAccessHost";
100 scoped_ptr<base::DictionaryValue> policy_dict(new base::DictionaryValue());
101 for (auto it = current.begin(); it != current.end(); ++it) {
102 const std::string& key = it->first;
103 const base::Value* value = it->second.value;
105 // Copying only Chromoting-specific policies helps avoid false alarms
106 // raised by NormalizePolicies below (such alarms shutdown the host).
107 // TODO(lukasza): Removing this somewhat brittle filtering will be possible
108 // after having separate, Chromoting-specific schema.
109 if (key.find(kPolicyNameSubstring) != std::string::npos) {
110 policy_dict->Set(key, value->DeepCopy());
114 return policy_dict.Pass();
117 // Takes a dictionary containing only 1) recognized policy names and 2)
118 // well-typed policy values and further verifies policy contents.
119 bool VerifyWellformedness(const base::DictionaryValue& changed_policies) {
120 // Verify ThirdPartyAuthConfig policy.
121 ThirdPartyAuthConfig not_used;
122 switch (ThirdPartyAuthConfig::Parse(changed_policies, &not_used)) {
123 case ThirdPartyAuthConfig::NoPolicy:
124 case ThirdPartyAuthConfig::ParsingSuccess:
125 break; // Well-formed.
126 case ThirdPartyAuthConfig::InvalidPolicy:
127 return false; // Malformed.
128 default:
129 NOTREACHED();
130 return false;
133 // Verify UdpPortRange policy.
134 std::string udp_port_range_string;
135 PortRange udp_port_range;
136 if (changed_policies.GetString(policy::key::kRemoteAccessHostUdpPortRange,
137 &udp_port_range_string)) {
138 if (!PortRange::Parse(udp_port_range_string, &udp_port_range)) {
139 return false;
143 // Report that all the policies were well-formed.
144 return true;
147 } // namespace
149 void PolicyWatcher::StartWatching(
150 const PolicyUpdatedCallback& policy_updated_callback,
151 const PolicyErrorCallback& policy_error_callback) {
152 DCHECK(CalledOnValidThread());
153 DCHECK(!policy_updated_callback.is_null());
154 DCHECK(!policy_error_callback.is_null());
155 DCHECK(policy_updated_callback_.is_null());
157 policy_updated_callback_ = policy_updated_callback;
158 policy_error_callback_ = policy_error_callback;
160 // Listen for future policy changes.
161 policy_service_->AddObserver(policy::POLICY_DOMAIN_CHROME, this);
163 // Process current policy state.
164 if (policy_service_->IsInitializationComplete(policy::POLICY_DOMAIN_CHROME)) {
165 OnPolicyServiceInitialized(policy::POLICY_DOMAIN_CHROME);
169 void PolicyWatcher::SignalPolicyError() {
170 old_policies_->Clear();
171 policy_error_callback_.Run();
174 PolicyWatcher::PolicyWatcher(
175 policy::PolicyService* policy_service,
176 scoped_ptr<policy::PolicyService> owned_policy_service,
177 scoped_ptr<policy::ConfigurationPolicyProvider> owned_policy_provider,
178 scoped_ptr<policy::SchemaRegistry> owned_schema_registry)
179 : old_policies_(new base::DictionaryValue()),
180 default_values_(new base::DictionaryValue()),
181 policy_service_(policy_service),
182 owned_schema_registry_(owned_schema_registry.Pass()),
183 owned_policy_provider_(owned_policy_provider.Pass()),
184 owned_policy_service_(owned_policy_service.Pass()) {
185 DCHECK(policy_service_);
186 DCHECK(owned_schema_registry_);
188 // Initialize the default values for each policy.
189 default_values_->SetBoolean(key::kRemoteAccessHostFirewallTraversal, true);
190 default_values_->SetBoolean(key::kRemoteAccessHostRequireCurtain, false);
191 default_values_->SetBoolean(key::kRemoteAccessHostMatchUsername, false);
192 default_values_->SetString(key::kRemoteAccessHostDomain, std::string());
193 default_values_->SetString(key::kRemoteAccessHostTalkGadgetPrefix,
194 kDefaultHostTalkGadgetPrefix);
195 default_values_->SetString(key::kRemoteAccessHostTokenUrl, std::string());
196 default_values_->SetString(key::kRemoteAccessHostTokenValidationUrl,
197 std::string());
198 default_values_->SetString(
199 key::kRemoteAccessHostTokenValidationCertificateIssuer, std::string());
200 default_values_->SetBoolean(key::kRemoteAccessHostAllowClientPairing, true);
201 default_values_->SetBoolean(key::kRemoteAccessHostAllowGnubbyAuth, true);
202 default_values_->SetBoolean(key::kRemoteAccessHostAllowRelayedConnection,
203 true);
204 default_values_->SetString(key::kRemoteAccessHostUdpPortRange, "");
205 #if !defined(NDEBUG)
206 default_values_->SetString(key::kRemoteAccessHostDebugOverridePolicies,
207 std::string());
208 #endif
211 PolicyWatcher::~PolicyWatcher() {
212 // Stop observing |policy_service_| if StartWatching() has been called.
213 if (!policy_updated_callback_.is_null()) {
214 policy_service_->RemoveObserver(policy::POLICY_DOMAIN_CHROME, this);
217 if (owned_policy_provider_) {
218 owned_policy_provider_->Shutdown();
222 const policy::Schema* PolicyWatcher::GetPolicySchema() const {
223 return owned_schema_registry_->schema_map()->GetSchema(GetPolicyNamespace());
226 bool PolicyWatcher::NormalizePolicies(base::DictionaryValue* policy_dict) {
227 // Allowing unrecognized policy names allows presence of
228 // 1) comments (i.e. JSON of the form: { "_comment": "blah", ... }),
229 // 2) policies intended for future/newer versions of the host,
230 // 3) policies not supported on all OS-s (i.e. RemoteAccessHostMatchUsername
231 // is not supported on Windows and therefore policy_templates.json omits
232 // schema for this policy on this particular platform).
233 auto strategy = policy::SCHEMA_ALLOW_UNKNOWN_TOPLEVEL;
235 std::string path;
236 std::string error;
237 bool changed = false;
238 const policy::Schema* schema = GetPolicySchema();
239 if (schema->Normalize(policy_dict, strategy, &path, &error, &changed)) {
240 if (changed) {
241 LOG(WARNING) << "Unknown (unrecognized or unsupported) policy: " << path
242 << ": " << error;
244 return true;
245 } else {
246 LOG(ERROR) << "Invalid policy contents: " << path << ": " << error;
247 return false;
251 namespace {
252 void CopyDictionaryValue(const base::DictionaryValue& from,
253 base::DictionaryValue& to,
254 std::string key) {
255 const base::Value* value;
256 if (from.Get(key, &value)) {
257 to.Set(key, value->DeepCopy());
260 } // namespace
262 scoped_ptr<base::DictionaryValue>
263 PolicyWatcher::StoreNewAndReturnChangedPolicies(
264 scoped_ptr<base::DictionaryValue> new_policies) {
265 // Find the changed policies.
266 scoped_ptr<base::DictionaryValue> changed_policies(
267 new base::DictionaryValue());
268 base::DictionaryValue::Iterator iter(*new_policies);
269 while (!iter.IsAtEnd()) {
270 base::Value* old_policy;
271 if (!(old_policies_->Get(iter.key(), &old_policy) &&
272 old_policy->Equals(&iter.value()))) {
273 changed_policies->Set(iter.key(), iter.value().DeepCopy());
275 iter.Advance();
278 // If one of ThirdPartyAuthConfig policies changed, we need to include all.
279 if (changed_policies->HasKey(key::kRemoteAccessHostTokenUrl) ||
280 changed_policies->HasKey(key::kRemoteAccessHostTokenValidationUrl) ||
281 changed_policies->HasKey(
282 key::kRemoteAccessHostTokenValidationCertificateIssuer)) {
283 CopyDictionaryValue(*new_policies, *changed_policies,
284 key::kRemoteAccessHostTokenUrl);
285 CopyDictionaryValue(*new_policies, *changed_policies,
286 key::kRemoteAccessHostTokenValidationUrl);
287 CopyDictionaryValue(*new_policies, *changed_policies,
288 key::kRemoteAccessHostTokenValidationCertificateIssuer);
291 // Save the new policies.
292 old_policies_.swap(new_policies);
294 return changed_policies.Pass();
297 void PolicyWatcher::OnPolicyUpdated(const policy::PolicyNamespace& ns,
298 const policy::PolicyMap& previous,
299 const policy::PolicyMap& current) {
300 scoped_ptr<base::DictionaryValue> new_policies =
301 CopyChromotingPoliciesIntoDictionary(current);
303 // Check for mistyped values and get rid of unknown policies.
304 if (!NormalizePolicies(new_policies.get())) {
305 SignalPolicyError();
306 return;
309 // Use default values for any missing policies.
310 scoped_ptr<base::DictionaryValue> filled_policies =
311 CopyValuesAndAddDefaults(*new_policies, *default_values_);
313 // Limit reporting to only the policies that were changed.
314 scoped_ptr<base::DictionaryValue> changed_policies =
315 StoreNewAndReturnChangedPolicies(filled_policies.Pass());
316 if (changed_policies->empty()) {
317 return;
320 // Verify that we are calling the callback with valid policies.
321 if (!VerifyWellformedness(*changed_policies)) {
322 SignalPolicyError();
323 return;
326 // Notify our client of the changed policies.
327 policy_updated_callback_.Run(changed_policies.Pass());
330 void PolicyWatcher::OnPolicyServiceInitialized(policy::PolicyDomain domain) {
331 policy::PolicyNamespace ns = GetPolicyNamespace();
332 const policy::PolicyMap& current = policy_service_->GetPolicies(ns);
333 OnPolicyUpdated(ns, current, current);
336 scoped_ptr<PolicyWatcher> PolicyWatcher::CreateFromPolicyLoader(
337 scoped_ptr<policy::AsyncPolicyLoader> async_policy_loader) {
338 scoped_ptr<policy::SchemaRegistry> schema_registry = CreateSchemaRegistry();
339 scoped_ptr<policy::AsyncPolicyProvider> policy_provider(
340 new policy::AsyncPolicyProvider(schema_registry.get(),
341 async_policy_loader.Pass()));
342 policy_provider->Init(schema_registry.get());
344 policy::PolicyServiceImpl::Providers providers;
345 providers.push_back(policy_provider.get());
346 scoped_ptr<policy::PolicyService> policy_service(
347 new policy::PolicyServiceImpl(providers));
349 policy::PolicyService* borrowed_policy_service = policy_service.get();
350 return make_scoped_ptr(
351 new PolicyWatcher(borrowed_policy_service, policy_service.Pass(),
352 policy_provider.Pass(), schema_registry.Pass()));
355 scoped_ptr<PolicyWatcher> PolicyWatcher::Create(
356 policy::PolicyService* policy_service,
357 const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner) {
358 #if defined(OS_CHROMEOS)
359 // On Chrome OS the PolicyService is owned by the browser.
360 DCHECK(policy_service);
361 return make_scoped_ptr(new PolicyWatcher(policy_service, nullptr, nullptr,
362 CreateSchemaRegistry()));
363 #else // !defined(OS_CHROMEOS)
364 DCHECK(!policy_service);
366 // Create platform-specific PolicyLoader. Always read the Chrome policies
367 // (even on Chromium) so that policy enforcement can't be bypassed by running
368 // Chromium.
369 scoped_ptr<policy::AsyncPolicyLoader> policy_loader;
370 #if defined(OS_WIN)
371 policy_loader.reset(new policy::PolicyLoaderWin(
372 file_task_runner, L"SOFTWARE\\Policies\\Google\\Chrome",
373 nullptr)); // nullptr = don't use GPO / always read from the registry.
374 #elif defined(OS_MACOSX)
375 CFStringRef bundle_id = CFSTR("com.google.Chrome");
376 policy_loader.reset(new policy::PolicyLoaderMac(
377 file_task_runner,
378 policy::PolicyLoaderMac::GetManagedPolicyPath(bundle_id),
379 new MacPreferences(), bundle_id));
380 #elif defined(OS_POSIX) && !defined(OS_ANDROID)
381 policy_loader.reset(new policy::ConfigDirPolicyLoader(
382 file_task_runner,
383 base::FilePath(FILE_PATH_LITERAL("/etc/opt/chrome/policies")),
384 policy::POLICY_SCOPE_MACHINE));
385 #else
386 #error OS that is not yet supported by PolicyWatcher code.
387 #endif
389 return PolicyWatcher::CreateFromPolicyLoader(policy_loader.Pass());
390 #endif // !(OS_CHROMEOS)
393 } // namespace remoting