1 // Copyright (c) 2011 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 #include "chrome/browser/policy/device_policy_cache.h"
6
7 #include "base/basictypes.h"
8 #include "base/compiler_specific.h"
9 #include "base/logging.h"
10 #include "base/task.h"
11 #include "base/values.h"
12 #include "chrome/browser/chromeos/cros_settings_names.h"
13 #include "chrome/browser/chromeos/login/ownership_service.h"
14 #include "chrome/browser/chromeos/login/signed_settings_helper.h"
15 #include "chrome/browser/chromeos/user_cros_settings_provider.h"
16 #include "chrome/browser/policy/configuration_policy_pref_store.h"
17 #include "chrome/browser/policy/device_policy_identity_strategy.h"
18 #include "chrome/browser/policy/enterprise_install_attributes.h"
19 #include "chrome/browser/policy/policy_map.h"
20 #include "chrome/browser/policy/proto/device_management_backend.pb.h"
21 #include "chrome/browser/policy/proto/device_management_constants.h"
22 #include "chrome/browser/policy/proto/device_management_local.pb.h"
23 #include "content/browser/browser_thread.h"
24 #include "policy/configuration_policy_type.h"
25
26 namespace {
27
28 // Stores policy, updates the owner key if required and reports the status
29 // through a callback.
30 class StorePolicyOperation : public chromeos::SignedSettingsHelper::Callback,
31 public chromeos::OwnerManager::KeyUpdateDelegate {
32 public:
33 typedef Callback1<chromeos::SignedSettings::ReturnCode>::Type Callback;
34
StorePolicyOperation(chromeos::SignedSettingsHelper * signed_settings_helper,const em::PolicyFetchResponse & policy,Callback * callback)35 StorePolicyOperation(chromeos::SignedSettingsHelper* signed_settings_helper,
36 const em::PolicyFetchResponse& policy,
37 Callback* callback)
38 : signed_settings_helper_(signed_settings_helper),
39 policy_(policy),
40 callback_(callback) {
41 signed_settings_helper_->StartStorePolicyOp(policy, this);
42 }
~StorePolicyOperation()43 virtual ~StorePolicyOperation() {
44 signed_settings_helper_->CancelCallback(this);
45 }
46
47 // SignedSettingsHelper implementation:
OnStorePolicyCompleted(chromeos::SignedSettings::ReturnCode code)48 virtual void OnStorePolicyCompleted(
49 chromeos::SignedSettings::ReturnCode code) OVERRIDE {
50 if (code != chromeos::SignedSettings::SUCCESS) {
51 callback_->Run(code);
52 delete this;
53 return;
54 }
55
56 if (policy_.has_new_public_key()) {
57 // The session manager has successfully done a key rotation. Replace the
58 // owner key also in chrome.
59 const std::string& new_key = policy_.new_public_key();
60 const std::vector<uint8> new_key_data(new_key.c_str(),
61 new_key.c_str() + new_key.size());
62 chromeos::OwnershipService::GetSharedInstance()->StartUpdateOwnerKey(
63 new_key_data, this);
64 return;
65 } else {
66 UpdateUserCrosSettings();
67 callback_->Run(chromeos::SignedSettings::SUCCESS);
68 delete this;
69 return;
70 }
71 }
72
73 // OwnerManager::KeyUpdateDelegate implementation:
OnKeyUpdated()74 virtual void OnKeyUpdated() OVERRIDE {
75 UpdateUserCrosSettings();
76 callback_->Run(chromeos::SignedSettings::SUCCESS);
77 delete this;
78 }
79
80 private:
UpdateUserCrosSettings()81 void UpdateUserCrosSettings() {
82 // TODO(mnissler): Find a better way. This is a hack that updates the
83 // UserCrosSettingsProvider's cache, since it is unable to notice we've
84 // updated policy information.
85 chromeos::UserCrosSettingsProvider().Reload();
86 }
87
88 chromeos::SignedSettingsHelper* signed_settings_helper_;
89 em::PolicyFetchResponse policy_;
90 scoped_ptr<Callback> callback_;
91
92 DISALLOW_COPY_AND_ASSIGN(StorePolicyOperation);
93 };
94
95 // Decodes a protobuf integer to an IntegerValue. The caller assumes ownership
96 // of the return Value*. Returns NULL in case the input value is out of bounds.
DecodeIntegerValue(google::protobuf::int64 value)97 Value* DecodeIntegerValue(google::protobuf::int64 value) {
98 if (value < std::numeric_limits<int>::min() ||
99 value > std::numeric_limits<int>::max()) {
100 LOG(WARNING) << "Integer value " << value
101 << " out of numeric limits, ignoring.";
102 return NULL;
103 }
104
105 return Value::CreateIntegerValue(static_cast<int>(value));
106 }
107
108 } // namespace
109
110 namespace policy {
111
DevicePolicyCache(DevicePolicyIdentityStrategy * identity_strategy,EnterpriseInstallAttributes * install_attributes)112 DevicePolicyCache::DevicePolicyCache(
113 DevicePolicyIdentityStrategy* identity_strategy,
114 EnterpriseInstallAttributes* install_attributes)
115 : identity_strategy_(identity_strategy),
116 install_attributes_(install_attributes),
117 signed_settings_helper_(chromeos::SignedSettingsHelper::Get()),
118 starting_up_(true),
119 ALLOW_THIS_IN_INITIALIZER_LIST(callback_factory_(this)) {
120 }
121
DevicePolicyCache(DevicePolicyIdentityStrategy * identity_strategy,EnterpriseInstallAttributes * install_attributes,chromeos::SignedSettingsHelper * signed_settings_helper)122 DevicePolicyCache::DevicePolicyCache(
123 DevicePolicyIdentityStrategy* identity_strategy,
124 EnterpriseInstallAttributes* install_attributes,
125 chromeos::SignedSettingsHelper* signed_settings_helper)
126 : identity_strategy_(identity_strategy),
127 install_attributes_(install_attributes),
128 signed_settings_helper_(signed_settings_helper),
129 starting_up_(true),
130 ALLOW_THIS_IN_INITIALIZER_LIST(callback_factory_(this)) {
131 }
132
~DevicePolicyCache()133 DevicePolicyCache::~DevicePolicyCache() {
134 signed_settings_helper_->CancelCallback(this);
135 }
136
Load()137 void DevicePolicyCache::Load() {
138 signed_settings_helper_->StartRetrievePolicyOp(this);
139 }
140
SetPolicy(const em::PolicyFetchResponse & policy)141 void DevicePolicyCache::SetPolicy(const em::PolicyFetchResponse& policy) {
142 DCHECK(!starting_up_);
143
144 // Make sure we have an enterprise device.
145 std::string registration_user(install_attributes_->GetRegistrationUser());
146 if (registration_user.empty()) {
147 LOG(WARNING) << "Refusing to accept policy on non-enterprise device.";
148 InformNotifier(CloudPolicySubsystem::LOCAL_ERROR,
149 CloudPolicySubsystem::POLICY_LOCAL_ERROR);
150 return;
151 }
152
153 // Check the user this policy is for against the device-locked name.
154 em::PolicyData policy_data;
155 if (!policy_data.ParseFromString(policy.policy_data())) {
156 LOG(WARNING) << "Invalid policy protobuf";
157 InformNotifier(CloudPolicySubsystem::LOCAL_ERROR,
158 CloudPolicySubsystem::POLICY_LOCAL_ERROR);
159 return;
160 }
161
162 if (registration_user != policy_data.username()) {
163 LOG(WARNING) << "Refusing policy blob for " << policy_data.username()
164 << " which doesn't match " << registration_user;
165 InformNotifier(CloudPolicySubsystem::LOCAL_ERROR,
166 CloudPolicySubsystem::POLICY_LOCAL_ERROR);
167 return;
168 }
169
170 set_last_policy_refresh_time(base::Time::NowFromSystemTime());
171
172 // Start a store operation.
173 new StorePolicyOperation(signed_settings_helper_,
174 policy,
175 callback_factory_.NewCallback(
176 &DevicePolicyCache::PolicyStoreOpCompleted));
177 }
178
SetUnmanaged()179 void DevicePolicyCache::SetUnmanaged() {
180 LOG(WARNING) << "Tried to set DevicePolicyCache to 'unmanaged'!";
181 // This is not supported for DevicePolicyCache.
182 }
183
OnRetrievePolicyCompleted(chromeos::SignedSettings::ReturnCode code,const em::PolicyFetchResponse & policy)184 void DevicePolicyCache::OnRetrievePolicyCompleted(
185 chromeos::SignedSettings::ReturnCode code,
186 const em::PolicyFetchResponse& policy) {
187 DCHECK(CalledOnValidThread());
188 if (starting_up_) {
189 starting_up_ = false;
190 if (code == chromeos::SignedSettings::NOT_FOUND ||
191 code == chromeos::SignedSettings::KEY_UNAVAILABLE ||
192 !policy.has_policy_data()) {
193 InformNotifier(CloudPolicySubsystem::UNENROLLED,
194 CloudPolicySubsystem::NO_DETAILS);
195 return;
196 }
197 em::PolicyData policy_data;
198 if (!policy_data.ParseFromString(policy.policy_data())) {
199 LOG(WARNING) << "Failed to parse PolicyData protobuf.";
200 InformNotifier(CloudPolicySubsystem::LOCAL_ERROR,
201 CloudPolicySubsystem::POLICY_LOCAL_ERROR);
202 return;
203 }
204 if (!policy_data.has_request_token() ||
205 policy_data.request_token().empty()) {
206 SetUnmanagedInternal(base::Time::NowFromSystemTime());
207 InformNotifier(CloudPolicySubsystem::UNMANAGED,
208 CloudPolicySubsystem::NO_DETAILS);
209 // TODO(jkummerow): Reminder: When we want to feed device-wide settings
210 // made by a local owner into this cache, we need to call
211 // SetPolicyInternal() here.
212 return;
213 }
214 if (!policy_data.has_username() || !policy_data.has_device_id()) {
215 InformNotifier(CloudPolicySubsystem::LOCAL_ERROR,
216 CloudPolicySubsystem::POLICY_LOCAL_ERROR);
217 return;
218 }
219 identity_strategy_->SetDeviceManagementCredentials(
220 policy_data.username(),
221 policy_data.device_id(),
222 policy_data.request_token());
223 SetPolicyInternal(policy, NULL, false);
224 } else { // In other words, starting_up_ == false.
225 if (code != chromeos::SignedSettings::SUCCESS) {
226 if (code == chromeos::SignedSettings::BAD_SIGNATURE) {
227 InformNotifier(CloudPolicySubsystem::LOCAL_ERROR,
228 CloudPolicySubsystem::SIGNATURE_MISMATCH);
229 } else {
230 InformNotifier(CloudPolicySubsystem::LOCAL_ERROR,
231 CloudPolicySubsystem::POLICY_LOCAL_ERROR);
232 }
233 return;
234 }
235 SetPolicyInternal(policy, NULL, false);
236 }
237 }
238
DecodePolicyData(const em::PolicyData & policy_data,PolicyMap * mandatory,PolicyMap * recommended)239 bool DevicePolicyCache::DecodePolicyData(const em::PolicyData& policy_data,
240 PolicyMap* mandatory,
241 PolicyMap* recommended) {
242 em::ChromeDeviceSettingsProto policy;
243 if (!policy.ParseFromString(policy_data.policy_value())) {
244 LOG(WARNING) << "Failed to parse ChromeDeviceSettingsProto.";
245 return false;
246 }
247 DecodeDevicePolicy(policy, mandatory, recommended);
248 return true;
249 }
250
PolicyStoreOpCompleted(chromeos::SignedSettings::ReturnCode code)251 void DevicePolicyCache::PolicyStoreOpCompleted(
252 chromeos::SignedSettings::ReturnCode code) {
253 DCHECK(CalledOnValidThread());
254 if (code != chromeos::SignedSettings::SUCCESS) {
255 if (code == chromeos::SignedSettings::BAD_SIGNATURE) {
256 InformNotifier(CloudPolicySubsystem::LOCAL_ERROR,
257 CloudPolicySubsystem::SIGNATURE_MISMATCH);
258 } else {
259 InformNotifier(CloudPolicySubsystem::LOCAL_ERROR,
260 CloudPolicySubsystem::POLICY_LOCAL_ERROR);
261 }
262 return;
263 }
264 signed_settings_helper_->StartRetrievePolicyOp(this);
265 }
266
267 // static
DecodeDevicePolicy(const em::ChromeDeviceSettingsProto & policy,PolicyMap * mandatory,PolicyMap * recommended)268 void DevicePolicyCache::DecodeDevicePolicy(
269 const em::ChromeDeviceSettingsProto& policy,
270 PolicyMap* mandatory,
271 PolicyMap* recommended) {
272 if (policy.has_policy_refresh_rate()) {
273 const em::DevicePolicyRefreshRateProto container =
274 policy.policy_refresh_rate();
275 if (container.has_policy_refresh_rate()) {
276 mandatory->Set(kPolicyPolicyRefreshRate,
277 DecodeIntegerValue(container.policy_refresh_rate()));
278 }
279 }
280
281 if (policy.has_device_proxy_settings()) {
282 const em::DeviceProxySettingsProto container =
283 policy.device_proxy_settings();
284 if (container.has_proxy_mode()) {
285 recommended->Set(kPolicyProxyMode,
286 Value::CreateStringValue(container.proxy_mode()));
287 }
288 if (container.has_proxy_server()) {
289 recommended->Set(kPolicyProxyServer,
290 Value::CreateStringValue(container.proxy_server()));
291 }
292 if (container.has_proxy_pac_url()) {
293 recommended->Set(kPolicyProxyPacUrl,
294 Value::CreateStringValue(container.proxy_pac_url()));
295 }
296 if (container.has_proxy_bypass_list()) {
297 recommended->Set(kPolicyProxyBypassList,
298 Value::CreateStringValue(container.proxy_bypass_list()));
299 }
300 }
301 }
302
303 } // namespace policy
304