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 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 } 43 virtual ~StorePolicyOperation() { 44 signed_settings_helper_->CancelCallback(this); 45 } 46 47 // SignedSettingsHelper implementation: 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: 74 virtual void OnKeyUpdated() OVERRIDE { 75 UpdateUserCrosSettings(); 76 callback_->Run(chromeos::SignedSettings::SUCCESS); 77 delete this; 78 } 79 80 private: 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. 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 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 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 133 DevicePolicyCache::~DevicePolicyCache() { 134 signed_settings_helper_->CancelCallback(this); 135 } 136 137 void DevicePolicyCache::Load() { 138 signed_settings_helper_->StartRetrievePolicyOp(this); 139 } 140 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 179 void DevicePolicyCache::SetUnmanaged() { 180 LOG(WARNING) << "Tried to set DevicePolicyCache to 'unmanaged'!"; 181 // This is not supported for DevicePolicyCache. 182 } 183 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 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 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 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