Home | History | Annotate | Download | only in policy
      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