diff options
Diffstat (limited to 'chrome/browser/chromeos/settings/device_settings_provider.cc')
-rw-r--r-- | chrome/browser/chromeos/settings/device_settings_provider.cc | 748 |
1 files changed, 748 insertions, 0 deletions
diff --git a/chrome/browser/chromeos/settings/device_settings_provider.cc b/chrome/browser/chromeos/settings/device_settings_provider.cc new file mode 100644 index 0000000..0c1432e --- /dev/null +++ b/chrome/browser/chromeos/settings/device_settings_provider.cc @@ -0,0 +1,748 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/settings/device_settings_provider.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/callback.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/string_util.h" +#include "base/threading/thread_restrictions.h" +#include "base/values.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/cros/network_library.h" +#include "chrome/browser/chromeos/login/user_manager.h" +#include "chrome/browser/chromeos/settings/cros_settings.h" +#include "chrome/browser/chromeos/settings/cros_settings_names.h" +#include "chrome/browser/chromeos/settings/signed_settings_cache.h" +#include "chrome/browser/chromeos/settings/signed_settings_helper.h" +#include "chrome/browser/policy/app_pack_updater.h" +#include "chrome/browser/policy/browser_policy_connector.h" +#include "chrome/browser/policy/cloud_policy_constants.h" +#include "chrome/browser/policy/proto/chrome_device_policy.pb.h" +#include "chrome/browser/ui/options/options_util.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/installer/util/google_update_settings.h" +#include "content/public/browser/notification_service.h" + +using google::protobuf::RepeatedPtrField; + +namespace em = enterprise_management; + +namespace chromeos { + +namespace { + +// List of settings handled by the DeviceSettingsProvider. +const char* kKnownSettings[] = { + kAccountsPrefAllowGuest, + kAccountsPrefAllowNewUser, + kAccountsPrefEphemeralUsersEnabled, + kAccountsPrefShowUserNamesOnSignIn, + kAccountsPrefUsers, + kAppPack, + kDeviceOwner, + kIdleLogoutTimeout, + kIdleLogoutWarningDuration, + kPolicyMissingMitigationMode, + kReleaseChannel, + kReleaseChannelDelegated, + kReportDeviceActivityTimes, + kReportDeviceBootMode, + kReportDeviceLocation, + kReportDeviceVersionInfo, + kScreenSaverExtensionId, + kScreenSaverTimeout, + kSettingProxyEverywhere, + kSignedDataRoamingEnabled, + kStartUpUrls, + kStatsReportingPref, +}; + +// Upper bound for number of retries to fetch a signed setting. +static const int kNumRetriesLimit = 9; + +// Legacy policy file location. Used to detect migration from pre v12 ChromeOS. +const char kLegacyPolicyFile[] = "/var/lib/whitelist/preferences"; + +bool IsControlledSetting(const std::string& pref_path) { + const char** end = kKnownSettings + arraysize(kKnownSettings); + return std::find(kKnownSettings, end, pref_path) != end; +} + +bool HasOldMetricsFile() { + // TODO(pastarmovj): Remove this once migration is not needed anymore. + // If the value is not set we should try to migrate legacy consent file. + // Loading consent file state causes us to do blocking IO on UI thread. + // Temporarily allow it until we fix http://crbug.com/62626 + base::ThreadRestrictions::ScopedAllowIO allow_io; + return GoogleUpdateSettings::GetCollectStatsConsent(); +} + +} // namespace + +DeviceSettingsProvider::DeviceSettingsProvider( + const NotifyObserversCallback& notify_cb, + SignedSettingsHelper* signed_settings_helper) + : CrosSettingsProvider(notify_cb), + signed_settings_helper_(signed_settings_helper), + ownership_status_(OwnershipService::GetSharedInstance()->GetStatus(true)), + migration_helper_(new SignedSettingsMigrationHelper()), + retries_left_(kNumRetriesLimit), + trusted_status_(TEMPORARILY_UNTRUSTED) { + // Register for notification when ownership is taken so that we can update + // the |ownership_status_| and reload if needed. + registrar_.Add(this, chrome::NOTIFICATION_OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED, + content::NotificationService::AllSources()); + // Make sure we have at least the cache data immediately. + RetrieveCachedData(); + // Start prefetching preferences. + Reload(); +} + +DeviceSettingsProvider::~DeviceSettingsProvider() { +} + +void DeviceSettingsProvider::Reload() { + // While fetching we can't trust the cache anymore. + trusted_status_ = TEMPORARILY_UNTRUSTED; + if (ownership_status_ == OwnershipService::OWNERSHIP_NONE) { + RetrieveCachedData(); + } else { + // Retrieve the real data. + signed_settings_helper_->StartRetrievePolicyOp( + base::Bind(&DeviceSettingsProvider::OnRetrievePolicyCompleted, + base::Unretained(this))); + } +} + +void DeviceSettingsProvider::DoSet(const std::string& path, + const base::Value& in_value) { + if (!UserManager::Get()->IsCurrentUserOwner() && + ownership_status_ != OwnershipService::OWNERSHIP_NONE) { + LOG(WARNING) << "Changing settings from non-owner, setting=" << path; + + // Revert UI change. + NotifyObservers(path); + return; + } + + if (IsControlledSetting(path)) { + pending_changes_.push_back(PendingQueueElement(path, in_value.DeepCopy())); + if (pending_changes_.size() == 1) + SetInPolicy(); + } else { + NOTREACHED() << "Try to set unhandled cros setting " << path; + } +} + +void DeviceSettingsProvider::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + if (type == chrome::NOTIFICATION_OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED) { + // Reload the policy blob once the owner key has been loaded or updated. + ownership_status_ = OwnershipService::OWNERSHIP_TAKEN; + Reload(); + } +} + +const em::PolicyData DeviceSettingsProvider::policy() const { + return policy_; +} + +void DeviceSettingsProvider::RetrieveCachedData() { + // If there is no owner yet, this function will pull the policy cache from the + // temp storage and use that instead. + em::PolicyData policy; + if (!signed_settings_cache::Retrieve(&policy, + g_browser_process->local_state())) { + VLOG(1) << "Can't retrieve temp store possibly not created yet."; + // Prepare empty data for the case we don't have temp cache yet. + policy.set_policy_type(kDevicePolicyType); + em::ChromeDeviceSettingsProto pol; + policy.set_policy_value(pol.SerializeAsString()); + } + + policy_ = policy; + UpdateValuesCache(); +} + +void DeviceSettingsProvider::SetInPolicy() { + if (pending_changes_.empty()) { + NOTREACHED(); + return; + } + + const std::string& prop = pending_changes_[0].first; + base::Value* value = pending_changes_[0].second; + if (prop == kDeviceOwner) { + // Just store it in the memory cache without trusted checks or persisting. + std::string owner; + if (value->GetAsString(&owner)) { + policy_.set_username(owner); + // In this case the |value_cache_| takes the ownership of |value|. + values_cache_.SetValue(prop, value); + NotifyObservers(prop); + // We can't trust this value anymore until we reload the real username. + trusted_status_ = TEMPORARILY_UNTRUSTED; + pending_changes_.erase(pending_changes_.begin()); + if (!pending_changes_.empty()) + SetInPolicy(); + } else { + NOTREACHED(); + } + return; + } + + if (RequestTrustedEntity() != TRUSTED) { + // Otherwise we should first reload and apply on top of that. + signed_settings_helper_->StartRetrievePolicyOp( + base::Bind(&DeviceSettingsProvider::FinishSetInPolicy, + base::Unretained(this))); + return; + } + + trusted_status_ = TEMPORARILY_UNTRUSTED; + em::PolicyData data = policy(); + em::ChromeDeviceSettingsProto pol; + pol.ParseFromString(data.policy_value()); + if (prop == kAccountsPrefAllowNewUser) { + em::AllowNewUsersProto* allow = pol.mutable_allow_new_users(); + bool allow_value; + if (value->GetAsBoolean(&allow_value)) + allow->set_allow_new_users(allow_value); + else + NOTREACHED(); + } else if (prop == kAccountsPrefAllowGuest) { + em::GuestModeEnabledProto* guest = pol.mutable_guest_mode_enabled(); + bool guest_value; + if (value->GetAsBoolean(&guest_value)) + guest->set_guest_mode_enabled(guest_value); + else + NOTREACHED(); + } else if (prop == kAccountsPrefShowUserNamesOnSignIn) { + em::ShowUserNamesOnSigninProto* show = pol.mutable_show_user_names(); + bool show_value; + if (value->GetAsBoolean(&show_value)) + show->set_show_user_names(show_value); + else + NOTREACHED(); + } else if (prop == kSignedDataRoamingEnabled) { + em::DataRoamingEnabledProto* roam = pol.mutable_data_roaming_enabled(); + bool roaming_value = false; + if (value->GetAsBoolean(&roaming_value)) + roam->set_data_roaming_enabled(roaming_value); + else + NOTREACHED(); + ApplyRoamingSetting(roaming_value); + } else if (prop == kSettingProxyEverywhere) { + // TODO(cmasone): NOTIMPLEMENTED() once http://crosbug.com/13052 is fixed. + std::string proxy_value; + if (value->GetAsString(&proxy_value)) { + bool success = + pol.mutable_device_proxy_settings()->ParseFromString(proxy_value); + DCHECK(success); + } else { + NOTREACHED(); + } + } else if (prop == kReleaseChannel) { + em::ReleaseChannelProto* release_channel = pol.mutable_release_channel(); + std::string channel_value; + if (value->GetAsString(&channel_value)) + release_channel->set_release_channel(channel_value); + else + NOTREACHED(); + } else if (prop == kStatsReportingPref) { + em::MetricsEnabledProto* metrics = pol.mutable_metrics_enabled(); + bool metrics_value = false; + if (value->GetAsBoolean(&metrics_value)) + metrics->set_metrics_enabled(metrics_value); + else + NOTREACHED(); + ApplyMetricsSetting(false, metrics_value); + } else if (prop == kAccountsPrefUsers) { + em::UserWhitelistProto* whitelist_proto = pol.mutable_user_whitelist(); + whitelist_proto->clear_user_whitelist(); + base::ListValue& users = static_cast<base::ListValue&>(*value); + for (base::ListValue::const_iterator i = users.begin(); + i != users.end(); ++i) { + std::string email; + if ((*i)->GetAsString(&email)) + whitelist_proto->add_user_whitelist(email.c_str()); + } + } else if (prop == kAccountsPrefEphemeralUsersEnabled) { + em::EphemeralUsersEnabledProto* ephemeral_users_enabled = + pol.mutable_ephemeral_users_enabled(); + bool ephemeral_users_enabled_value = false; + if (value->GetAsBoolean(&ephemeral_users_enabled_value)) + ephemeral_users_enabled->set_ephemeral_users_enabled( + ephemeral_users_enabled_value); + else + NOTREACHED(); + } else { + // The remaining settings don't support Set(), since they are not + // intended to be customizable by the user: + // kAppPack + // kIdleLogoutTimeout + // kIdleLogoutWarningDuration + // kReleaseChannelDelegated + // kReportDeviceVersionInfo + // kReportDeviceActivityTimes + // kReportDeviceBootMode + // kReportDeviceLocation + // kScreenSaverExtensionId + // kScreenSaverTimeout + // kStartUpUrls + + NOTREACHED(); + } + data.set_policy_value(pol.SerializeAsString()); + // Set the cache to the updated value. + policy_ = data; + UpdateValuesCache(); + + if (!signed_settings_cache::Store(data, g_browser_process->local_state())) + LOG(ERROR) << "Couldn't store to the temp storage."; + + if (ownership_status_ == OwnershipService::OWNERSHIP_TAKEN) { + em::PolicyFetchResponse policy_envelope; + policy_envelope.set_policy_data(policy_.SerializeAsString()); + signed_settings_helper_->StartStorePolicyOp( + policy_envelope, + base::Bind(&DeviceSettingsProvider::OnStorePolicyCompleted, + base::Unretained(this))); + } else { + // OnStorePolicyCompleted won't get called in this case so proceed with any + // pending operations immediately. + delete pending_changes_[0].second; + pending_changes_.erase(pending_changes_.begin()); + if (!pending_changes_.empty()) + SetInPolicy(); + } +} + +void DeviceSettingsProvider::FinishSetInPolicy( + SignedSettings::ReturnCode code, + const em::PolicyFetchResponse& policy) { + if (code != SignedSettings::SUCCESS) { + LOG(ERROR) << "Can't serialize to policy error code: " << code; + Reload(); + return; + } + // Update the internal caches and set the trusted flag to true so that we + // can pass the trustedness check in the second call to SetInPolicy. + OnRetrievePolicyCompleted(code, policy); + + SetInPolicy(); +} + +void DeviceSettingsProvider::DecodeLoginPolicies( + const em::ChromeDeviceSettingsProto& policy, + PrefValueMap* new_values_cache) const { + // For all our boolean settings the following is applicable: + // true is default permissive value and false is safe prohibitive value. + // Exceptions: + // kSignedDataRoamingEnabled has a default value of false. + // kAccountsPrefEphemeralUsersEnabled has a default value of false. + if (policy.has_allow_new_users() && + policy.allow_new_users().has_allow_new_users() && + policy.allow_new_users().allow_new_users()) { + // New users allowed, user_whitelist() ignored. + new_values_cache->SetBoolean(kAccountsPrefAllowNewUser, true); + } else if (!policy.has_user_whitelist()) { + // If we have the allow_new_users bool, and it is true, we honor that above. + // In all other cases (don't have it, have it and it is set to false, etc), + // We will honor the user_whitelist() if it is there and populated. + // Otherwise we default to allowing new users. + new_values_cache->SetBoolean(kAccountsPrefAllowNewUser, true); + } else { + new_values_cache->SetBoolean( + kAccountsPrefAllowNewUser, + policy.user_whitelist().user_whitelist_size() == 0); + } + + new_values_cache->SetBoolean( + kAccountsPrefAllowGuest, + !policy.has_guest_mode_enabled() || + !policy.guest_mode_enabled().has_guest_mode_enabled() || + policy.guest_mode_enabled().guest_mode_enabled()); + + new_values_cache->SetBoolean( + kAccountsPrefShowUserNamesOnSignIn, + !policy.has_show_user_names() || + !policy.show_user_names().has_show_user_names() || + policy.show_user_names().show_user_names()); + + new_values_cache->SetBoolean( + kAccountsPrefEphemeralUsersEnabled, + policy.has_ephemeral_users_enabled() && + policy.ephemeral_users_enabled().has_ephemeral_users_enabled() && + policy.ephemeral_users_enabled().ephemeral_users_enabled()); + + base::ListValue* list = new base::ListValue(); + const em::UserWhitelistProto& whitelist_proto = policy.user_whitelist(); + const RepeatedPtrField<std::string>& whitelist = + whitelist_proto.user_whitelist(); + for (RepeatedPtrField<std::string>::const_iterator it = whitelist.begin(); + it != whitelist.end(); ++it) { + list->Append(base::Value::CreateStringValue(*it)); + } + new_values_cache->SetValue(kAccountsPrefUsers, list); +} + +void DeviceSettingsProvider::DecodeKioskPolicies( + const em::ChromeDeviceSettingsProto& policy, + PrefValueMap* new_values_cache) const { + if (policy.has_forced_logout_timeouts()) { + if (policy.forced_logout_timeouts().has_idle_logout_timeout()) { + new_values_cache->SetInteger( + kIdleLogoutTimeout, + policy.forced_logout_timeouts().idle_logout_timeout()); + } + + if (policy.forced_logout_timeouts().has_idle_logout_warning_duration()) { + new_values_cache->SetInteger( + kIdleLogoutWarningDuration, + policy.forced_logout_timeouts().idle_logout_warning_duration()); + } + } + + if (policy.has_login_screen_saver()) { + if (policy.login_screen_saver().has_screen_saver_timeout()) { + new_values_cache->SetInteger( + kScreenSaverTimeout, + policy.login_screen_saver().screen_saver_timeout()); + } + + if (policy.login_screen_saver().has_screen_saver_extension_id()) { + new_values_cache->SetString( + kScreenSaverExtensionId, + policy.login_screen_saver().screen_saver_extension_id()); + } + } + + if (policy.has_app_pack()) { + typedef RepeatedPtrField<em::AppPackEntryProto> proto_type; + base::ListValue* list = new base::ListValue; + const proto_type& app_pack = policy.app_pack().app_pack(); + for (proto_type::const_iterator it = app_pack.begin(); + it != app_pack.end(); ++it) { + base::DictionaryValue* entry = new base::DictionaryValue; + if (it->has_extension_id()) { + entry->SetString(policy::AppPackUpdater::kExtensionId, + it->extension_id()); + } + if (it->has_update_url()) + entry->SetString(policy::AppPackUpdater::kUpdateUrl, it->update_url()); + list->Append(entry); + } + new_values_cache->SetValue(kAppPack, list); + } + + if (policy.has_start_up_urls()) { + base::ListValue* list = new base::ListValue(); + const em::StartUpUrlsProto& urls_proto = policy.start_up_urls(); + const RepeatedPtrField<std::string>& urls = urls_proto.start_up_urls(); + for (RepeatedPtrField<std::string>::const_iterator it = urls.begin(); + it != urls.end(); ++it) { + list->Append(base::Value::CreateStringValue(*it)); + } + new_values_cache->SetValue(kStartUpUrls, list); + } +} + +void DeviceSettingsProvider::DecodeNetworkPolicies( + const em::ChromeDeviceSettingsProto& policy, + PrefValueMap* new_values_cache) const { + new_values_cache->SetBoolean( + kSignedDataRoamingEnabled, + policy.has_data_roaming_enabled() && + policy.data_roaming_enabled().has_data_roaming_enabled() && + policy.data_roaming_enabled().data_roaming_enabled()); + + // TODO(cmasone): NOTIMPLEMENTED() once http://crosbug.com/13052 is fixed. + std::string serialized; + if (policy.has_device_proxy_settings() && + policy.device_proxy_settings().SerializeToString(&serialized)) { + new_values_cache->SetString(kSettingProxyEverywhere, serialized); + } +} + +void DeviceSettingsProvider::DecodeReportingPolicies( + const em::ChromeDeviceSettingsProto& policy, + PrefValueMap* new_values_cache) const { + if (policy.has_device_reporting()) { + if (policy.device_reporting().has_report_version_info()) { + new_values_cache->SetBoolean( + kReportDeviceVersionInfo, + policy.device_reporting().report_version_info()); + } + if (policy.device_reporting().has_report_activity_times()) { + new_values_cache->SetBoolean( + kReportDeviceActivityTimes, + policy.device_reporting().report_activity_times()); + } + if (policy.device_reporting().has_report_boot_mode()) { + new_values_cache->SetBoolean( + kReportDeviceBootMode, + policy.device_reporting().report_boot_mode()); + } + // Device location reporting needs to pass privacy review before it can be + // enabled. crosbug.com/24681 + // if (policy.device_reporting().has_report_location()) { + // new_values_cache->SetBoolean( + // kReportDeviceLocation, + // policy.device_reporting().report_location()); + // } + } +} + +void DeviceSettingsProvider::DecodeGenericPolicies( + const em::ChromeDeviceSettingsProto& policy, + PrefValueMap* new_values_cache) const { + if (policy.has_metrics_enabled()) { + new_values_cache->SetBoolean(kStatsReportingPref, + policy.metrics_enabled().metrics_enabled()); + } else { + new_values_cache->SetBoolean(kStatsReportingPref, HasOldMetricsFile()); + } + + if (!policy.has_release_channel() || + !policy.release_channel().has_release_channel()) { + // Default to an invalid channel (will be ignored). + new_values_cache->SetString(kReleaseChannel, ""); + } else { + new_values_cache->SetString(kReleaseChannel, + policy.release_channel().release_channel()); + } + + new_values_cache->SetBoolean( + kReleaseChannelDelegated, + policy.has_release_channel() && + policy.release_channel().has_release_channel_delegated() && + policy.release_channel().release_channel_delegated()); +} + +void DeviceSettingsProvider::UpdateValuesCache() { + const em::PolicyData data = policy(); + PrefValueMap new_values_cache; + + if (data.has_username() && !data.has_request_token()) + new_values_cache.SetString(kDeviceOwner, data.username()); + + em::ChromeDeviceSettingsProto pol; + pol.ParseFromString(data.policy_value()); + + DecodeLoginPolicies(pol, &new_values_cache); + DecodeKioskPolicies(pol, &new_values_cache); + DecodeNetworkPolicies(pol, &new_values_cache); + DecodeReportingPolicies(pol, &new_values_cache); + DecodeGenericPolicies(pol, &new_values_cache); + + // Collect all notifications but send them only after we have swapped the + // cache so that if somebody actually reads the cache will be already valid. + std::vector<std::string> notifications; + // Go through the new values and verify in the old ones. + PrefValueMap::iterator iter = new_values_cache.begin(); + for (; iter != new_values_cache.end(); ++iter) { + const base::Value* old_value; + if (!values_cache_.GetValue(iter->first, &old_value) || + !old_value->Equals(iter->second)) { + notifications.push_back(iter->first); + } + } + // Now check for values that have been removed from the policy blob. + for (iter = values_cache_.begin(); iter != values_cache_.end(); ++iter) { + const base::Value* value; + if (!new_values_cache.GetValue(iter->first, &value)) + notifications.push_back(iter->first); + } + // Swap and notify. + values_cache_.Swap(&new_values_cache); + for (size_t i = 0; i < notifications.size(); ++i) + NotifyObservers(notifications[i]); +} + +void DeviceSettingsProvider::ApplyMetricsSetting(bool use_file, + bool new_value) const { + // TODO(pastarmovj): Remove this once migration is not needed anymore. + // If the value is not set we should try to migrate legacy consent file. + if (use_file) { + new_value = HasOldMetricsFile(); + // Make sure the values will get eventually written to the policy file. + migration_helper_->AddMigrationValue( + kStatsReportingPref, base::Value::CreateBooleanValue(new_value)); + migration_helper_->MigrateValues(); + LOG(INFO) << "No metrics policy set will revert to checking " + << "consent file which is " + << (new_value ? "on." : "off."); + } + VLOG(1) << "Metrics policy is being set to : " << new_value + << "(use file : " << use_file << ")"; + // TODO(pastarmovj): Remove this once we don't need to regenerate the + // consent file for the GUID anymore. + OptionsUtil::ResolveMetricsReportingEnabled(new_value); +} + +void DeviceSettingsProvider::ApplyRoamingSetting(bool new_value) const { + NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); + const NetworkDevice* cellular = cros->FindCellularDevice(); + if (cellular) { + bool device_value = cellular->data_roaming_allowed(); + if (!device_value && cros->IsCellularAlwaysInRoaming()) { + // If operator requires roaming always enabled, ignore supplied value + // and set data roaming allowed in true always. + cros->SetCellularDataRoamingAllowed(true); + } else if (device_value != new_value) { + cros->SetCellularDataRoamingAllowed(new_value); + } + } +} + +void DeviceSettingsProvider::ApplySideEffects() const { + const em::PolicyData data = policy(); + em::ChromeDeviceSettingsProto pol; + pol.ParseFromString(data.policy_value()); + // First migrate metrics settings as needed. + if (pol.has_metrics_enabled()) + ApplyMetricsSetting(false, pol.metrics_enabled().metrics_enabled()); + else + ApplyMetricsSetting(true, false); + // Next set the roaming setting as needed. + ApplyRoamingSetting(pol.has_data_roaming_enabled() ? + pol.data_roaming_enabled().data_roaming_enabled() : false); +} + +bool DeviceSettingsProvider::MitigateMissingPolicy() { + // First check if the device has been owned already and if not exit + // immediately. + if (g_browser_process->browser_policy_connector()->GetDeviceMode() != + policy::DEVICE_MODE_CONSUMER) { + return false; + } + + // If we are here the policy file were corrupted or missing. This can happen + // because we are migrating Pre R11 device to the new secure policies or there + // was an attempt to circumvent policy system. In this case we should populate + // the policy cache with "safe-mode" defaults which should allow the owner to + // log in but lock the device for anyone else until the policy blob has been + // recreated by the session manager. + LOG(ERROR) << "Corruption of the policy data has been detected." + << "Switching to \"safe-mode\" policies until the owner logs in " + << "to regenerate the policy data."; + values_cache_.SetBoolean(kAccountsPrefAllowNewUser, true); + values_cache_.SetBoolean(kAccountsPrefAllowGuest, true); + values_cache_.SetBoolean(kPolicyMissingMitigationMode, true); + trusted_status_ = TRUSTED; + // Make sure we will recreate the policy once the owner logs in. + // Any value not in this list will be left to the default which is fine as + // we repopulate the whitelist with the owner and all other existing users + // every time the owner enables whitelist filtering on the UI. + migration_helper_->AddMigrationValue( + kAccountsPrefAllowNewUser, base::Value::CreateBooleanValue(true)); + migration_helper_->MigrateValues(); + return true; +} + +const base::Value* DeviceSettingsProvider::Get(const std::string& path) const { + if (IsControlledSetting(path)) { + const base::Value* value; + if (values_cache_.GetValue(path, &value)) + return value; + } else { + NOTREACHED() << "Trying to get non cros setting."; + } + + return NULL; +} + +DeviceSettingsProvider::TrustedStatus + DeviceSettingsProvider::PrepareTrustedValues(const base::Closure& cb) { + TrustedStatus status = RequestTrustedEntity(); + if (status == TEMPORARILY_UNTRUSTED && !cb.is_null()) + callbacks_.push_back(cb); + return status; +} + +bool DeviceSettingsProvider::HandlesSetting(const std::string& path) const { + return IsControlledSetting(path); +} + +DeviceSettingsProvider::TrustedStatus + DeviceSettingsProvider::RequestTrustedEntity() { + if (ownership_status_ == OwnershipService::OWNERSHIP_NONE) + return TRUSTED; + return trusted_status_; +} + +void DeviceSettingsProvider::OnStorePolicyCompleted( + SignedSettings::ReturnCode code) { + // In any case reload the policy cache to now. + if (code != SignedSettings::SUCCESS) + Reload(); + else + trusted_status_ = TRUSTED; + + // Clear the finished task and proceed with any other stores that could be + // pending by now. + delete pending_changes_[0].second; + pending_changes_.erase(pending_changes_.begin()); + if (!pending_changes_.empty()) + SetInPolicy(); +} + +void DeviceSettingsProvider::OnRetrievePolicyCompleted( + SignedSettings::ReturnCode code, + const em::PolicyFetchResponse& policy_data) { + VLOG(1) << "OnRetrievePolicyCompleted. Error code: " << code + << ", trusted status : " << trusted_status_ + << ", ownership status : " << ownership_status_; + switch (code) { + case SignedSettings::SUCCESS: { + DCHECK(policy_data.has_policy_data()); + policy_.ParseFromString(policy_data.policy_data()); + signed_settings_cache::Store(policy(), + g_browser_process->local_state()); + UpdateValuesCache(); + trusted_status_ = TRUSTED; + // TODO(pastarmovj): Make those side effects responsibility of the + // respective subsystems. + ApplySideEffects(); + break; + } + case SignedSettings::NOT_FOUND: + if (MitigateMissingPolicy()) + break; + case SignedSettings::KEY_UNAVAILABLE: { + if (ownership_status_ != OwnershipService::OWNERSHIP_TAKEN) + NOTREACHED() << "No policies present yet, will use the temp storage."; + trusted_status_ = PERMANENTLY_UNTRUSTED; + break; + } + case SignedSettings::BAD_SIGNATURE: + case SignedSettings::OPERATION_FAILED: { + LOG(ERROR) << "Failed to retrieve cros policies. Reason:" << code; + if (retries_left_ > 0) { + trusted_status_ = TEMPORARILY_UNTRUSTED; + retries_left_ -= 1; + Reload(); + return; + } + LOG(ERROR) << "No retries left"; + trusted_status_ = PERMANENTLY_UNTRUSTED; + break; + } + } + // Notify the observers we are done. + std::vector<base::Closure> callbacks; + callbacks.swap(callbacks_); + for (size_t i = 0; i < callbacks.size(); ++i) + callbacks[i].Run(); +} + +} // namespace chromeos |