• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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