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