Avi Drissman | d6cdf9b | 2022-09-15 19:52:53 | [diff] [blame] | 1 | // Copyright 2015 The Chromium Authors |
simonmorris@chromium.org | 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 | |
lukasza | c285c9a | 2015-01-29 23:18:28 | [diff] [blame] | 5 | #ifndef REMOTING_HOST_POLICY_WATCHER_H_ |
| 6 | #define REMOTING_HOST_POLICY_WATCHER_H_ |
simonmorris@chromium.org | 000d1f6 | 2012-07-24 01:56:54 | [diff] [blame] | 7 | |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 8 | #include <memory> |
| 9 | |
Avi Drissman | 135261e | 2023-01-11 22:43:15 | [diff] [blame] | 10 | #include "base/functional/callback.h" |
Keishi Hattori | 0e45c02 | 2021-11-27 09:25:52 | [diff] [blame] | 11 | #include "base/memory/raw_ptr.h" |
Lei Zhang | b2710ea | 2022-11-07 20:45:14 | [diff] [blame] | 12 | #include "base/memory/scoped_refptr.h" |
gab | bf77513a | 2017-06-01 14:35:34 | [diff] [blame] | 13 | #include "base/sequence_checker.h" |
Morten Stenshorne | 4654b9c | 2022-08-31 14:12:50 | [diff] [blame] | 14 | #include "base/values.h" |
Joe Downing | 21478b5d | 2021-10-25 16:50:22 | [diff] [blame] | 15 | #include "build/build_config.h" |
lukasza | a9376cd | 2015-01-28 20:29:01 | [diff] [blame] | 16 | #include "components/policy/core/common/policy_service.h" |
simonmorris@chromium.org | 000d1f6 | 2012-07-24 01:56:54 | [diff] [blame] | 17 | |
Xiaohan Wang | 453b3867 | 2022-01-13 20:02:44 | [diff] [blame] | 18 | #if BUILDFLAG(IS_WIN) |
Joe Downing | 21478b5d | 2021-10-25 16:50:22 | [diff] [blame] | 19 | #include "base/win/registry.h" |
| 20 | #endif |
| 21 | |
simonmorris@chromium.org | 000d1f6 | 2012-07-24 01:56:54 | [diff] [blame] | 22 | namespace base { |
| 23 | class SingleThreadTaskRunner; |
simonmorris@chromium.org | 000d1f6 | 2012-07-24 01:56:54 | [diff] [blame] | 24 | } // namespace base |
| 25 | |
lukasza | d5a6bda | 2015-01-17 00:43:25 | [diff] [blame] | 26 | namespace policy { |
lukasza | a9376cd | 2015-01-28 20:29:01 | [diff] [blame] | 27 | class AsyncPolicyLoader; |
| 28 | class ConfigurationPolicyProvider; |
Yann Dago | f101f66 | 2021-08-20 02:22:37 | [diff] [blame] | 29 | class ManagementService; |
lukasza | e5d69ea | 2015-02-23 21:00:31 | [diff] [blame] | 30 | class Schema; |
lukasza | a9376cd | 2015-01-28 20:29:01 | [diff] [blame] | 31 | class SchemaRegistry; |
lukasza | d5a6bda | 2015-01-17 00:43:25 | [diff] [blame] | 32 | } // namespace policy |
| 33 | |
simonmorris@chromium.org | 000d1f6 | 2012-07-24 01:56:54 | [diff] [blame] | 34 | namespace remoting { |
simonmorris@chromium.org | 000d1f6 | 2012-07-24 01:56:54 | [diff] [blame] | 35 | |
sergeyu | b2ae7e3 | 2015-01-30 23:33:25 | [diff] [blame] | 36 | // Watches for changes to the managed remote access host policies. |
gab | bf77513a | 2017-06-01 14:35:34 | [diff] [blame] | 37 | class PolicyWatcher : public policy::PolicyService::Observer { |
simonmorris@chromium.org | 000d1f6 | 2012-07-24 01:56:54 | [diff] [blame] | 38 | public: |
| 39 | // Called first with all policies, and subsequently with any changed policies. |
Yuwei Huang | 2390bd16 | 2024-02-19 09:30:10 | [diff] [blame^] | 40 | // Policies that are unchanged will be absent in the returned dictionary. |
| 41 | // If a policy has no default value but is unset, it will be an empty Value, |
| 42 | // i.e., of type NONE. |
Lei Zhang | dea94ed | 2023-10-06 21:04:58 | [diff] [blame] | 43 | using PolicyUpdatedCallback = |
| 44 | base::RepeatingCallback<void(base::Value::Dict)>; |
lukasza | 0fdd951 | 2014-11-25 17:47:46 | [diff] [blame] | 45 | |
| 46 | // Called after detecting malformed policies. |
Lei Zhang | dea94ed | 2023-10-06 21:04:58 | [diff] [blame] | 47 | using PolicyErrorCallback = base::RepeatingCallback<void()>; |
simonmorris@chromium.org | 000d1f6 | 2012-07-24 01:56:54 | [diff] [blame] | 48 | |
Peter Boström | e9178e4 | 2021-09-22 18:11:49 | [diff] [blame] | 49 | PolicyWatcher(const PolicyWatcher&) = delete; |
| 50 | PolicyWatcher& operator=(const PolicyWatcher&) = delete; |
| 51 | |
lukasza | a9376cd | 2015-01-28 20:29:01 | [diff] [blame] | 52 | ~PolicyWatcher() override; |
simonmorris@chromium.org | 000d1f6 | 2012-07-24 01:56:54 | [diff] [blame] | 53 | |
lukasza | 0fdd951 | 2014-11-25 17:47:46 | [diff] [blame] | 54 | // This guarantees that the |policy_updated_callback| is called at least once |
| 55 | // with the current policies. After that, |policy_updated_callback| will be |
| 56 | // called whenever a change to any policy is detected. It will then be called |
| 57 | // only with the changed policies. |
| 58 | // |
| 59 | // |policy_error_callback| will be called when malformed policies are detected |
| 60 | // (i.e. wrong type of policy value, or unparseable files under |
Lei Zhang | 2ccc622d | 2023-10-11 19:07:47 | [diff] [blame] | 61 | // $POLICY_PATH/managed). |
lukasza | 0fdd951 | 2014-11-25 17:47:46 | [diff] [blame] | 62 | // When called, the |policy_error_callback| is responsible for mitigating the |
| 63 | // security risk of running with incorrectly formulated policies (by either |
| 64 | // shutting down or locking down the host). |
| 65 | // After calling |policy_error_callback| PolicyWatcher will continue watching |
| 66 | // for policy changes and will call |policy_updated_callback| when the error |
| 67 | // is recovered from and may call |policy_error_callback| when new errors are |
| 68 | // found. |
| 69 | virtual void StartWatching( |
| 70 | const PolicyUpdatedCallback& policy_updated_callback, |
| 71 | const PolicyErrorCallback& policy_error_callback); |
simonmorris@chromium.org | 000d1f6 | 2012-07-24 01:56:54 | [diff] [blame] | 72 | |
jamiewalch | c96bfee | 2017-05-11 17:10:59 | [diff] [blame] | 73 | // Return the current policies. If the policies have not yet been read, or if |
Joe Downing | dcd2bb5 | 2020-12-15 16:20:09 | [diff] [blame] | 74 | // an error occurred, the returned dictionary will be empty. The dictionary |
| 75 | // returned is the union of |platform_policies_| and |default_values_|. |
Morten Stenshorne | 4654b9c | 2022-08-31 14:12:50 | [diff] [blame] | 76 | base::Value::Dict GetEffectivePolicies(); |
jamiewalch | cf2cc68 | 2017-05-06 00:51:47 | [diff] [blame] | 77 | |
Joe Downing | dcd2bb5 | 2020-12-15 16:20:09 | [diff] [blame] | 78 | // Return the set of policies which have been explicitly set on the machine. |
| 79 | // If the policies have not yet been read, no policies have been set, or if |
| 80 | // an error occurred, the returned dictionary will be empty. |
Morten Stenshorne | 4654b9c | 2022-08-31 14:12:50 | [diff] [blame] | 81 | base::Value::Dict GetPlatformPolicies(); |
Joe Downing | dcd2bb5 | 2020-12-15 16:20:09 | [diff] [blame] | 82 | |
| 83 | // Return the default policy values. |
Morten Stenshorne | 4654b9c | 2022-08-31 14:12:50 | [diff] [blame] | 84 | static base::Value::Dict GetDefaultPolicies(); |
jamiewalch | cf2cc68 | 2017-05-06 00:51:47 | [diff] [blame] | 85 | |
lukasza | d5a6bda | 2015-01-17 00:43:25 | [diff] [blame] | 86 | // Specify a |policy_service| to borrow (on Chrome OS, from the browser |
Joe Downing | 734d015 | 2017-07-18 02:56:16 | [diff] [blame] | 87 | // process). PolicyWatcher must be used on the thread on which it is created. |
| 88 | // |policy_service| is called on the same thread. |
lukasza | d5a6bda | 2015-01-17 00:43:25 | [diff] [blame] | 89 | // |
Joe Downing | 734d015 | 2017-07-18 02:56:16 | [diff] [blame] | 90 | // When |policy_service| is specified then BrowserThread::UI is used for |
| 91 | // PolicyUpdatedCallback and PolicyErrorCallback. |
| 92 | static std::unique_ptr<PolicyWatcher> CreateWithPolicyService( |
| 93 | policy::PolicyService* policy_service); |
| 94 | |
| 95 | // Construct and a new PolicyService for non-ChromeOS platforms. |
| 96 | // PolicyWatcher must be used on the thread on which it is created. |
lukasza | d5a6bda | 2015-01-17 00:43:25 | [diff] [blame] | 97 | // |
Joe Downing | 734d015 | 2017-07-18 02:56:16 | [diff] [blame] | 98 | // |file_task_runner| is used for reading the policy from files / registry / |
| 99 | // preferences (which are blocking operations). |file_task_runner| should be |
| 100 | // of TYPE_IO type. |
| 101 | static std::unique_ptr<PolicyWatcher> CreateWithTaskRunner( |
Yann Dago | f101f66 | 2021-08-20 02:22:37 | [diff] [blame] | 102 | const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner, |
| 103 | policy::ManagementService* management_service); |
simonmorris@chromium.org | 000d1f6 | 2012-07-24 01:56:54 | [diff] [blame] | 104 | |
rkjnsn | d0aa1e5 | 2017-03-30 00:17:28 | [diff] [blame] | 105 | // Creates a PolicyWatcher from the given loader instead of loading the policy |
| 106 | // from the default location. |
| 107 | // |
| 108 | // This can be used with FakeAsyncPolicyLoader to test policy handling of |
| 109 | // other components. |
| 110 | static std::unique_ptr<PolicyWatcher> CreateFromPolicyLoaderForTesting( |
| 111 | std::unique_ptr<policy::AsyncPolicyLoader> async_policy_loader); |
| 112 | |
lukasza | a9376cd | 2015-01-28 20:29:01 | [diff] [blame] | 113 | private: |
| 114 | friend class PolicyWatcherTest; |
simonmorris@chromium.org | 000d1f6 | 2012-07-24 01:56:54 | [diff] [blame] | 115 | |
lukasza | e5d69ea | 2015-02-23 21:00:31 | [diff] [blame] | 116 | // Gets Chromoting schema stored inside |owned_schema_registry_|. |
| 117 | const policy::Schema* GetPolicySchema() const; |
| 118 | |
rkjnsn | 10cd268 | 2017-04-28 22:04:01 | [diff] [blame] | 119 | // Normalizes policies using Schema::Normalize and converts deprecated |
| 120 | // policies. |
| 121 | // |
Joe Downing | dcd2bb5 | 2020-12-15 16:20:09 | [diff] [blame] | 122 | // - Returns false if |dict| is invalid, e.g. contains mistyped policy values. |
lukasza | 0d40d8a | 2015-03-03 18:36:28 | [diff] [blame] | 123 | // - Returns true if |dict| was valid or got normalized. |
Morten Stenshorne | 4654b9c | 2022-08-31 14:12:50 | [diff] [blame] | 124 | bool NormalizePolicies(base::Value* dict); |
lukasza | 0d40d8a | 2015-03-03 18:36:28 | [diff] [blame] | 125 | |
rkjnsn | 10cd268 | 2017-04-28 22:04:01 | [diff] [blame] | 126 | // Converts each deprecated policy to its replacement if and only if the |
| 127 | // replacement policy is not set, and removes deprecated policied from dict. |
Morten Stenshorne | 4654b9c | 2022-08-31 14:12:50 | [diff] [blame] | 128 | void HandleDeprecatedPolicies(base::Value::Dict* dict); |
rkjnsn | 10cd268 | 2017-04-28 22:04:01 | [diff] [blame] | 129 | |
Joe Downing | dcd2bb5 | 2020-12-15 16:20:09 | [diff] [blame] | 130 | // Stores |new_policies| into |effective_policies_|. Returns dictionary with |
| 131 | // items from |new_policies| that are different from the old |
| 132 | // |effective_policies_|. |
Morten Stenshorne | 4654b9c | 2022-08-31 14:12:50 | [diff] [blame] | 133 | base::Value::Dict StoreNewAndReturnChangedPolicies( |
| 134 | base::Value::Dict new_policies); |
lukasza | 0d40d8a | 2015-03-03 18:36:28 | [diff] [blame] | 135 | |
lukasza | 0fdd951 | 2014-11-25 17:47:46 | [diff] [blame] | 136 | // Signals policy error to the registered |PolicyErrorCallback|. |
| 137 | void SignalPolicyError(); |
| 138 | |
lukasza | a9376cd | 2015-01-28 20:29:01 | [diff] [blame] | 139 | // |policy_service_task_runner| is the task runner where it is safe |
| 140 | // to call |policy_service_| methods and where we expect to get callbacks |
| 141 | // from |policy_service_|. |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 142 | PolicyWatcher(policy::PolicyService* policy_service, |
| 143 | std::unique_ptr<policy::PolicyService> owned_policy_service, |
| 144 | std::unique_ptr<policy::ConfigurationPolicyProvider> |
| 145 | owned_policy_provider, |
| 146 | std::unique_ptr<policy::SchemaRegistry> owned_schema_registry); |
lukasza | 56dd1e9 | 2015-01-24 02:09:19 | [diff] [blame] | 147 | |
lukasza | a9376cd | 2015-01-28 20:29:01 | [diff] [blame] | 148 | // Creates PolicyWatcher that wraps the owned |async_policy_loader| with an |
| 149 | // appropriate PolicySchema. |
| 150 | // |
| 151 | // |policy_service_task_runner| is passed through to the constructor of |
| 152 | // PolicyWatcher. |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 153 | static std::unique_ptr<PolicyWatcher> CreateFromPolicyLoader( |
| 154 | std::unique_ptr<policy::AsyncPolicyLoader> async_policy_loader); |
simonmorris@chromium.org | b9612a5 | 2012-07-28 02:17:48 | [diff] [blame] | 155 | |
lukasza | a9376cd | 2015-01-28 20:29:01 | [diff] [blame] | 156 | // PolicyService::Observer interface. |
| 157 | void OnPolicyUpdated(const policy::PolicyNamespace& ns, |
| 158 | const policy::PolicyMap& previous, |
| 159 | const policy::PolicyMap& current) override; |
| 160 | void OnPolicyServiceInitialized(policy::PolicyDomain domain) override; |
| 161 | |
Xiaohan Wang | 453b3867 | 2022-01-13 20:02:44 | [diff] [blame] | 162 | #if BUILDFLAG(IS_WIN) |
Joe Downing | 21478b5d | 2021-10-25 16:50:22 | [diff] [blame] | 163 | void WatchForRegistryChanges(); |
| 164 | #endif |
| 165 | |
lukasza | 0fdd951 | 2014-11-25 17:47:46 | [diff] [blame] | 166 | PolicyUpdatedCallback policy_updated_callback_; |
| 167 | PolicyErrorCallback policy_error_callback_; |
simonmorris@chromium.org | 000d1f6 | 2012-07-24 01:56:54 | [diff] [blame] | 168 | |
Joe Downing | dcd2bb5 | 2020-12-15 16:20:09 | [diff] [blame] | 169 | // The combined set of policies (|platform_policies_| + |default_values_|) |
| 170 | // which define the effective policy set. |
Morten Stenshorne | 4654b9c | 2022-08-31 14:12:50 | [diff] [blame] | 171 | base::Value::Dict effective_policies_; |
Joe Downing | dcd2bb5 | 2020-12-15 16:20:09 | [diff] [blame] | 172 | |
| 173 | // The policies which have had their values explicitly set via a policy entry. |
Morten Stenshorne | 4654b9c | 2022-08-31 14:12:50 | [diff] [blame] | 174 | base::Value::Dict platform_policies_; |
Joe Downing | dcd2bb5 | 2020-12-15 16:20:09 | [diff] [blame] | 175 | |
| 176 | // The set of policy values to use if a policy has not been explicitly set. |
Morten Stenshorne | 4654b9c | 2022-08-31 14:12:50 | [diff] [blame] | 177 | base::Value::Dict default_values_; |
simonmorris@chromium.org | 000d1f6 | 2012-07-24 01:56:54 | [diff] [blame] | 178 | |
lukasza | a9376cd | 2015-01-28 20:29:01 | [diff] [blame] | 179 | // Order of fields below is important to ensure destruction takes object |
| 180 | // dependencies into account: |
Tom Sepez | 61a1e831 | 2023-04-06 23:26:30 | [diff] [blame] | 181 | // - |policy_service_| may be |owned_policy_service_|. |
lukasza | a9376cd | 2015-01-28 20:29:01 | [diff] [blame] | 182 | // - |owned_policy_service_| uses |owned_policy_provider_| |
| 183 | // - |owned_policy_provider_| uses |owned_schema_registry_| |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 184 | std::unique_ptr<policy::SchemaRegistry> owned_schema_registry_; |
| 185 | std::unique_ptr<policy::ConfigurationPolicyProvider> owned_policy_provider_; |
| 186 | std::unique_ptr<policy::PolicyService> owned_policy_service_; |
Tom Sepez | 61a1e831 | 2023-04-06 23:26:30 | [diff] [blame] | 187 | raw_ptr<policy::PolicyService> policy_service_; |
lukasza | a9376cd | 2015-01-28 20:29:01 | [diff] [blame] | 188 | |
Xiaohan Wang | 453b3867 | 2022-01-13 20:02:44 | [diff] [blame] | 189 | #if BUILDFLAG(IS_WIN) |
Joe Downing | 21478b5d | 2021-10-25 16:50:22 | [diff] [blame] | 190 | // |policy_key_| relies on |policy_service_| to notify the host of policy |
| 191 | // changes. Make sure |policy_key_| is destroyed to prevent any notifications |
| 192 | // from firing while the above objects are being torn down. |
| 193 | base::win::RegKey policy_key_; |
| 194 | #endif |
| 195 | |
gab | bf77513a | 2017-06-01 14:35:34 | [diff] [blame] | 196 | SEQUENCE_CHECKER(sequence_checker_); |
simonmorris@chromium.org | 000d1f6 | 2012-07-24 01:56:54 | [diff] [blame] | 197 | }; |
| 198 | |
simonmorris@chromium.org | 000d1f6 | 2012-07-24 01:56:54 | [diff] [blame] | 199 | } // namespace remoting |
| 200 | |
lukasza | c285c9a | 2015-01-29 23:18:28 | [diff] [blame] | 201 | #endif // REMOTING_HOST_POLICY_WATCHER_H_ |