device_settings_provider.cc revision 5e3f23d412006dc4db4e659864679f29341e113f
1// Copyright (c) 2012 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/chromeos/settings/device_settings_provider.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/callback.h"
10#include "base/command_line.h"
11#include "base/logging.h"
12#include "base/metrics/histogram.h"
13#include "base/prefs/pref_service.h"
14#include "base/strings/string_util.h"
15#include "base/threading/thread_restrictions.h"
16#include "base/values.h"
17#include "chrome/browser/browser_process.h"
18#include "chrome/browser/chromeos/cros/cros_library.h"
19#include "chrome/browser/chromeos/cros/network_library.h"
20#include "chrome/browser/chromeos/policy/device_local_account.h"
21#include "chrome/browser/chromeos/settings/cros_settings.h"
22#include "chrome/browser/chromeos/settings/cros_settings_names.h"
23#include "chrome/browser/chromeos/settings/device_settings_cache.h"
24#include "chrome/browser/policy/browser_policy_connector.h"
25#include "chrome/browser/policy/cloud/cloud_policy_constants.h"
26#include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
27#include "chrome/browser/ui/options/options_util.h"
28#include "chrome/installer/util/google_update_settings.h"
29#include "chromeos/chromeos_switches.h"
30
31using google::protobuf::RepeatedField;
32using google::protobuf::RepeatedPtrField;
33
34namespace em = enterprise_management;
35
36namespace chromeos {
37
38namespace {
39
40// List of settings handled by the DeviceSettingsProvider.
41const char* kKnownSettings[] = {
42  kAccountsPrefAllowGuest,
43  kAccountsPrefAllowNewUser,
44  kAccountsPrefDeviceLocalAccounts,
45  kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled,
46  kAccountsPrefDeviceLocalAccountAutoLoginDelay,
47  kAccountsPrefDeviceLocalAccountAutoLoginId,
48  kAccountsPrefEphemeralUsersEnabled,
49  kAccountsPrefShowUserNamesOnSignIn,
50  kAccountsPrefUsers,
51  kAllowRedeemChromeOsRegistrationOffers,
52  kAllowedConnectionTypesForUpdate,
53  kAppPack,
54  kDeviceAttestationEnabled,
55  kDeviceOwner,
56  kIdleLogoutTimeout,
57  kIdleLogoutWarningDuration,
58  kPolicyMissingMitigationMode,
59  kReleaseChannel,
60  kReleaseChannelDelegated,
61  kReportDeviceActivityTimes,
62  kReportDeviceBootMode,
63  kReportDeviceLocation,
64  kReportDeviceVersionInfo,
65  kScreenSaverExtensionId,
66  kScreenSaverTimeout,
67  kSignedDataRoamingEnabled,
68  kStartUpFlags,
69  kStartUpUrls,
70  kStatsReportingPref,
71  kSystemTimezonePolicy,
72  kUpdateDisabled,
73  kVariationsRestrictParameter,
74};
75
76// Legacy policy file location. Used to detect migration from pre v12 ChromeOS.
77const char kLegacyPolicyFile[] = "/var/lib/whitelist/preferences";
78
79bool HasOldMetricsFile() {
80  // TODO(pastarmovj): Remove this once migration is not needed anymore.
81  // If the value is not set we should try to migrate legacy consent file.
82  // Loading consent file state causes us to do blocking IO on UI thread.
83  // Temporarily allow it until we fix http://crbug.com/62626
84  base::ThreadRestrictions::ScopedAllowIO allow_io;
85  return GoogleUpdateSettings::GetCollectStatsConsent();
86}
87
88}  // namespace
89
90DeviceSettingsProvider::DeviceSettingsProvider(
91    const NotifyObserversCallback& notify_cb,
92    DeviceSettingsService* device_settings_service)
93    : CrosSettingsProvider(notify_cb),
94      device_settings_service_(device_settings_service),
95      trusted_status_(TEMPORARILY_UNTRUSTED),
96      ownership_status_(device_settings_service_->GetOwnershipStatus()),
97      store_callback_factory_(this) {
98  device_settings_service_->AddObserver(this);
99
100  if (!UpdateFromService()) {
101    // Make sure we have at least the cache data immediately.
102    RetrieveCachedData();
103  }
104}
105
106DeviceSettingsProvider::~DeviceSettingsProvider() {
107  device_settings_service_->RemoveObserver(this);
108}
109
110// static
111bool DeviceSettingsProvider::IsDeviceSetting(const std::string& name) {
112  const char** end = kKnownSettings + arraysize(kKnownSettings);
113  return std::find(kKnownSettings, end, name) != end;
114}
115
116void DeviceSettingsProvider::DoSet(const std::string& path,
117                                   const base::Value& in_value) {
118  // Make sure that either the current user is the device owner or the
119  // device doesn't have an owner yet.
120  if (!(device_settings_service_->HasPrivateOwnerKey() ||
121        ownership_status_ == DeviceSettingsService::OWNERSHIP_NONE)) {
122    LOG(WARNING) << "Changing settings from non-owner, setting=" << path;
123
124    // Revert UI change.
125    NotifyObservers(path);
126    return;
127  }
128
129  if (IsDeviceSetting(path)) {
130    pending_changes_.push_back(PendingQueueElement(path, in_value.DeepCopy()));
131    if (!store_callback_factory_.HasWeakPtrs())
132      SetInPolicy();
133  } else {
134    NOTREACHED() << "Try to set unhandled cros setting " << path;
135  }
136}
137
138void DeviceSettingsProvider::OwnershipStatusChanged() {
139  DeviceSettingsService::OwnershipStatus new_ownership_status =
140      device_settings_service_->GetOwnershipStatus();
141
142  // If the device just became owned, write the settings accumulated in the
143  // cache to device settings proper. It is important that writing only happens
144  // in this case, as during normal operation, the contents of the cache should
145  // never overwrite actual device settings.
146  if (new_ownership_status == DeviceSettingsService::OWNERSHIP_TAKEN &&
147      ownership_status_ == DeviceSettingsService::OWNERSHIP_NONE &&
148      device_settings_service_->HasPrivateOwnerKey()) {
149    // There shouldn't be any pending writes, since the cache writes are all
150    // immediate.
151    DCHECK(!store_callback_factory_.HasWeakPtrs());
152
153    // Apply the locally-accumulated device settings on top of the initial
154    // settings from the service and write back the result.
155    if (device_settings_service_->device_settings()) {
156      em::ChromeDeviceSettingsProto new_settings(
157          *device_settings_service_->device_settings());
158      new_settings.MergeFrom(device_settings_);
159      device_settings_.Swap(&new_settings);
160    }
161    StoreDeviceSettings();
162  }
163
164  // The owner key might have become available, allowing migration to happen.
165  AttemptMigration();
166
167  ownership_status_ = new_ownership_status;
168}
169
170void DeviceSettingsProvider::DeviceSettingsUpdated() {
171  if (!store_callback_factory_.HasWeakPtrs())
172    UpdateAndProceedStoring();
173}
174
175void DeviceSettingsProvider::RetrieveCachedData() {
176  em::PolicyData policy_data;
177  if (!device_settings_cache::Retrieve(&policy_data,
178                                       g_browser_process->local_state()) ||
179      !device_settings_.ParseFromString(policy_data.policy_value())) {
180    VLOG(1) << "Can't retrieve temp store, possibly not created yet.";
181  }
182
183  UpdateValuesCache(policy_data, device_settings_, trusted_status_);
184}
185
186void DeviceSettingsProvider::SetInPolicy() {
187  if (pending_changes_.empty()) {
188    NOTREACHED();
189    return;
190  }
191
192  if (RequestTrustedEntity() != TRUSTED) {
193    // Re-sync device settings before proceeding.
194    device_settings_service_->Load();
195    return;
196  }
197
198  std::string prop(pending_changes_.front().first);
199  scoped_ptr<base::Value> value(pending_changes_.front().second);
200  pending_changes_.pop_front();
201
202  trusted_status_ = TEMPORARILY_UNTRUSTED;
203  if (prop == kAccountsPrefAllowNewUser) {
204    em::AllowNewUsersProto* allow =
205        device_settings_.mutable_allow_new_users();
206    bool allow_value;
207    if (value->GetAsBoolean(&allow_value))
208      allow->set_allow_new_users(allow_value);
209    else
210      NOTREACHED();
211  } else if (prop == kAccountsPrefAllowGuest) {
212    em::GuestModeEnabledProto* guest =
213        device_settings_.mutable_guest_mode_enabled();
214    bool guest_value;
215    if (value->GetAsBoolean(&guest_value))
216      guest->set_guest_mode_enabled(guest_value);
217    else
218      NOTREACHED();
219  } else if (prop == kAccountsPrefShowUserNamesOnSignIn) {
220    em::ShowUserNamesOnSigninProto* show =
221        device_settings_.mutable_show_user_names();
222    bool show_value;
223    if (value->GetAsBoolean(&show_value))
224      show->set_show_user_names(show_value);
225    else
226      NOTREACHED();
227  } else if (prop == kAccountsPrefDeviceLocalAccounts) {
228    em::DeviceLocalAccountsProto* device_local_accounts =
229        device_settings_.mutable_device_local_accounts();
230    device_local_accounts->clear_account();
231    const base::ListValue* accounts_list = NULL;
232    if (value->GetAsList(&accounts_list)) {
233      for (base::ListValue::const_iterator entry(accounts_list->begin());
234           entry != accounts_list->end(); ++entry) {
235        const base::DictionaryValue* entry_dict = NULL;
236        if ((*entry)->GetAsDictionary(&entry_dict)) {
237          em::DeviceLocalAccountInfoProto* account =
238              device_local_accounts->add_account();
239          std::string account_id;
240          if (entry_dict->GetStringWithoutPathExpansion(
241                  kAccountsPrefDeviceLocalAccountsKeyId, &account_id)) {
242            account->set_account_id(account_id);
243          }
244          int type;
245          if (entry_dict->GetIntegerWithoutPathExpansion(
246                  kAccountsPrefDeviceLocalAccountsKeyType, &type)) {
247            account->set_type(
248                static_cast<em::DeviceLocalAccountInfoProto::AccountType>(
249                    type));
250          }
251          std::string kiosk_app_id;
252          if (entry_dict->GetStringWithoutPathExpansion(
253                  kAccountsPrefDeviceLocalAccountsKeyKioskAppId,
254                  &kiosk_app_id)) {
255            account->mutable_kiosk_app()->set_app_id(kiosk_app_id);
256          }
257          std::string kiosk_app_update_url;
258          if (entry_dict->GetStringWithoutPathExpansion(
259                  kAccountsPrefDeviceLocalAccountsKeyKioskAppUpdateURL,
260                  &kiosk_app_update_url)) {
261            account->mutable_kiosk_app()->set_update_url(kiosk_app_update_url);
262          }
263        } else {
264          NOTREACHED();
265        }
266      }
267    } else {
268      NOTREACHED();
269    }
270  } else if (prop == kAccountsPrefDeviceLocalAccountAutoLoginId) {
271    em::DeviceLocalAccountsProto* device_local_accounts =
272        device_settings_.mutable_device_local_accounts();
273    std::string id;
274    if (value->GetAsString(&id))
275      device_local_accounts->set_auto_login_id(id);
276    else
277      NOTREACHED();
278  } else if (prop == kAccountsPrefDeviceLocalAccountAutoLoginDelay) {
279    em::DeviceLocalAccountsProto* device_local_accounts =
280        device_settings_.mutable_device_local_accounts();
281    int delay;
282    if (value->GetAsInteger(&delay))
283      device_local_accounts->set_auto_login_delay(delay);
284    else
285      NOTREACHED();
286  } else if (prop == kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled) {
287    em::DeviceLocalAccountsProto* device_local_accounts =
288        device_settings_.mutable_device_local_accounts();
289    bool enabled;
290    if (value->GetAsBoolean(&enabled))
291      device_local_accounts->set_enable_auto_login_bailout(enabled);
292    else
293      NOTREACHED();
294  } else if (prop == kSignedDataRoamingEnabled) {
295    em::DataRoamingEnabledProto* roam =
296        device_settings_.mutable_data_roaming_enabled();
297    bool roaming_value = false;
298    if (value->GetAsBoolean(&roaming_value))
299      roam->set_data_roaming_enabled(roaming_value);
300    else
301      NOTREACHED();
302    ApplyRoamingSetting(roaming_value);
303  } else if (prop == kReleaseChannel) {
304    em::ReleaseChannelProto* release_channel =
305        device_settings_.mutable_release_channel();
306    std::string channel_value;
307    if (value->GetAsString(&channel_value))
308      release_channel->set_release_channel(channel_value);
309    else
310      NOTREACHED();
311  } else if (prop == kStatsReportingPref) {
312    em::MetricsEnabledProto* metrics =
313        device_settings_.mutable_metrics_enabled();
314    bool metrics_value = false;
315    if (value->GetAsBoolean(&metrics_value))
316      metrics->set_metrics_enabled(metrics_value);
317    else
318      NOTREACHED();
319    ApplyMetricsSetting(false, metrics_value);
320  } else if (prop == kAccountsPrefUsers) {
321    em::UserWhitelistProto* whitelist_proto =
322        device_settings_.mutable_user_whitelist();
323    whitelist_proto->clear_user_whitelist();
324    const base::ListValue* users;
325    if (value->GetAsList(&users)) {
326      for (base::ListValue::const_iterator i = users->begin();
327           i != users->end(); ++i) {
328        std::string email;
329        if ((*i)->GetAsString(&email))
330          whitelist_proto->add_user_whitelist(email);
331      }
332    }
333  } else if (prop == kAccountsPrefEphemeralUsersEnabled) {
334    em::EphemeralUsersEnabledProto* ephemeral_users_enabled =
335        device_settings_.mutable_ephemeral_users_enabled();
336    bool ephemeral_users_enabled_value = false;
337    if (value->GetAsBoolean(&ephemeral_users_enabled_value)) {
338      ephemeral_users_enabled->set_ephemeral_users_enabled(
339          ephemeral_users_enabled_value);
340    } else {
341      NOTREACHED();
342    }
343  } else if (prop == kAllowRedeemChromeOsRegistrationOffers) {
344    em::AllowRedeemChromeOsRegistrationOffersProto* allow_redeem_offers =
345        device_settings_.mutable_allow_redeem_offers();
346    bool allow_redeem_offers_value;
347    if (value->GetAsBoolean(&allow_redeem_offers_value)) {
348      allow_redeem_offers->set_allow_redeem_offers(
349          allow_redeem_offers_value);
350    } else {
351      NOTREACHED();
352    }
353  } else if (prop == kStartUpFlags) {
354    em::StartUpFlagsProto* flags_proto =
355        device_settings_.mutable_start_up_flags();
356    flags_proto->Clear();
357    const base::ListValue* flags;
358    if (value->GetAsList(&flags)) {
359      for (base::ListValue::const_iterator i = flags->begin();
360           i != flags->end(); ++i) {
361        std::string flag;
362        if ((*i)->GetAsString(&flag))
363          flags_proto->add_flags(flag);
364      }
365    }
366  } else {
367    // The remaining settings don't support Set(), since they are not
368    // intended to be customizable by the user:
369    //   kAppPack
370    //   kDeviceAttestationEnabled
371    //   kDeviceOwner
372    //   kIdleLogoutTimeout
373    //   kIdleLogoutWarningDuration
374    //   kReleaseChannelDelegated
375    //   kReportDeviceVersionInfo
376    //   kReportDeviceActivityTimes
377    //   kReportDeviceBootMode
378    //   kReportDeviceLocation
379    //   kScreenSaverExtensionId
380    //   kScreenSaverTimeout
381    //   kStartUpUrls
382    //   kSystemTimezonePolicy
383    //   kVariationsRestrictParameter
384
385    LOG(FATAL) << "Device setting " << prop << " is read-only.";
386  }
387
388  em::PolicyData data;
389  data.set_username(device_settings_service_->GetUsername());
390  CHECK(device_settings_.SerializeToString(data.mutable_policy_value()));
391
392  // Set the cache to the updated value.
393  UpdateValuesCache(data, device_settings_, trusted_status_);
394
395  if (ownership_status_ == DeviceSettingsService::OWNERSHIP_TAKEN) {
396    StoreDeviceSettings();
397  } else {
398    if (!device_settings_cache::Store(data, g_browser_process->local_state()))
399      LOG(ERROR) << "Couldn't store to the temp storage.";
400
401    // OnStorePolicyCompleted won't get called in this case so proceed with any
402    // pending operations immediately.
403    if (!pending_changes_.empty())
404      SetInPolicy();
405  }
406}
407
408void DeviceSettingsProvider::DecodeLoginPolicies(
409    const em::ChromeDeviceSettingsProto& policy,
410    PrefValueMap* new_values_cache) const {
411  // For all our boolean settings the following is applicable:
412  // true is default permissive value and false is safe prohibitive value.
413  // Exceptions:
414  //   kSignedDataRoamingEnabled has a default value of false.
415  //   kAccountsPrefEphemeralUsersEnabled has a default value of false.
416  if (policy.has_allow_new_users() &&
417      policy.allow_new_users().has_allow_new_users()) {
418    if (policy.allow_new_users().allow_new_users()) {
419      // New users allowed, user whitelist ignored.
420      new_values_cache->SetBoolean(kAccountsPrefAllowNewUser, true);
421    } else {
422      // New users not allowed, enforce user whitelist if present.
423      new_values_cache->SetBoolean(kAccountsPrefAllowNewUser,
424                                   !policy.has_user_whitelist());
425    }
426  } else {
427    // No configured allow-new-users value, enforce whitelist if non-empty.
428    new_values_cache->SetBoolean(
429        kAccountsPrefAllowNewUser,
430        policy.user_whitelist().user_whitelist_size() == 0);
431  }
432
433  new_values_cache->SetBoolean(
434      kAccountsPrefAllowGuest,
435      !policy.has_guest_mode_enabled() ||
436      !policy.guest_mode_enabled().has_guest_mode_enabled() ||
437      policy.guest_mode_enabled().guest_mode_enabled());
438
439  new_values_cache->SetBoolean(
440      kAccountsPrefShowUserNamesOnSignIn,
441      !policy.has_show_user_names() ||
442      !policy.show_user_names().has_show_user_names() ||
443      policy.show_user_names().show_user_names());
444
445  new_values_cache->SetBoolean(
446      kAccountsPrefEphemeralUsersEnabled,
447      policy.has_ephemeral_users_enabled() &&
448      policy.ephemeral_users_enabled().has_ephemeral_users_enabled() &&
449      policy.ephemeral_users_enabled().ephemeral_users_enabled());
450
451  base::ListValue* list = new base::ListValue();
452  const em::UserWhitelistProto& whitelist_proto = policy.user_whitelist();
453  const RepeatedPtrField<std::string>& whitelist =
454      whitelist_proto.user_whitelist();
455  for (RepeatedPtrField<std::string>::const_iterator it = whitelist.begin();
456       it != whitelist.end(); ++it) {
457    list->Append(new base::StringValue(*it));
458  }
459  new_values_cache->SetValue(kAccountsPrefUsers, list);
460
461  scoped_ptr<base::ListValue> account_list(new base::ListValue());
462  CommandLine* command_line = CommandLine::ForCurrentProcess();
463  if (!command_line->HasSwitch(switches::kDisableLocalAccounts)) {
464    const em::DeviceLocalAccountsProto device_local_accounts_proto =
465        policy.device_local_accounts();
466    const RepeatedPtrField<em::DeviceLocalAccountInfoProto>& accounts =
467        device_local_accounts_proto.account();
468    RepeatedPtrField<em::DeviceLocalAccountInfoProto>::const_iterator entry;
469    for (entry = accounts.begin(); entry != accounts.end(); ++entry) {
470      scoped_ptr<base::DictionaryValue> entry_dict(new base::DictionaryValue());
471      if (entry->has_type()) {
472        if (entry->has_account_id()) {
473          entry_dict->SetStringWithoutPathExpansion(
474              kAccountsPrefDeviceLocalAccountsKeyId, entry->account_id());
475        }
476        entry_dict->SetIntegerWithoutPathExpansion(
477            kAccountsPrefDeviceLocalAccountsKeyType, entry->type());
478        if (entry->kiosk_app().has_app_id()) {
479          entry_dict->SetStringWithoutPathExpansion(
480              kAccountsPrefDeviceLocalAccountsKeyKioskAppId,
481              entry->kiosk_app().app_id());
482        }
483        if (entry->kiosk_app().has_update_url()) {
484          entry_dict->SetStringWithoutPathExpansion(
485              kAccountsPrefDeviceLocalAccountsKeyKioskAppUpdateURL,
486              entry->kiosk_app().update_url());
487        }
488      } else if (entry->has_deprecated_public_session_id()) {
489        // Deprecated public session specification.
490        entry_dict->SetStringWithoutPathExpansion(
491            kAccountsPrefDeviceLocalAccountsKeyId,
492            entry->deprecated_public_session_id());
493        entry_dict->SetIntegerWithoutPathExpansion(
494            kAccountsPrefDeviceLocalAccountsKeyType,
495            policy::DeviceLocalAccount::TYPE_PUBLIC_SESSION);
496      }
497      account_list->Append(entry_dict.release());
498    }
499  }
500  new_values_cache->SetValue(kAccountsPrefDeviceLocalAccounts,
501                             account_list.release());
502
503  if (policy.has_device_local_accounts()) {
504    if (policy.device_local_accounts().has_auto_login_id()) {
505      new_values_cache->SetString(
506          kAccountsPrefDeviceLocalAccountAutoLoginId,
507          policy.device_local_accounts().auto_login_id());
508    }
509    if (policy.device_local_accounts().has_auto_login_delay()) {
510      new_values_cache->SetInteger(
511          kAccountsPrefDeviceLocalAccountAutoLoginDelay,
512          policy.device_local_accounts().auto_login_delay());
513    }
514  }
515
516  new_values_cache->SetBoolean(
517      kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled,
518      policy.device_local_accounts().enable_auto_login_bailout());
519
520  if (policy.has_start_up_flags()) {
521    base::ListValue* list = new base::ListValue();
522    const em::StartUpFlagsProto& flags_proto = policy.start_up_flags();
523    const RepeatedPtrField<std::string>& flags = flags_proto.flags();
524    for (RepeatedPtrField<std::string>::const_iterator it = flags.begin();
525         it != flags.end(); ++it) {
526      list->Append(new base::StringValue(*it));
527    }
528    new_values_cache->SetValue(kStartUpFlags, list);
529  }
530}
531
532void DeviceSettingsProvider::DecodeKioskPolicies(
533    const em::ChromeDeviceSettingsProto& policy,
534    PrefValueMap* new_values_cache) const {
535  if (policy.has_forced_logout_timeouts()) {
536    if (policy.forced_logout_timeouts().has_idle_logout_timeout()) {
537      new_values_cache->SetInteger(
538          kIdleLogoutTimeout,
539          policy.forced_logout_timeouts().idle_logout_timeout());
540    }
541
542    if (policy.forced_logout_timeouts().has_idle_logout_warning_duration()) {
543      new_values_cache->SetInteger(
544          kIdleLogoutWarningDuration,
545          policy.forced_logout_timeouts().idle_logout_warning_duration());
546    }
547  }
548
549  if (policy.has_login_screen_saver()) {
550    if (policy.login_screen_saver().has_screen_saver_timeout()) {
551      new_values_cache->SetInteger(
552          kScreenSaverTimeout,
553          policy.login_screen_saver().screen_saver_timeout());
554    }
555
556    if (policy.login_screen_saver().has_screen_saver_extension_id()) {
557      new_values_cache->SetString(
558          kScreenSaverExtensionId,
559          policy.login_screen_saver().screen_saver_extension_id());
560    }
561  }
562
563  if (policy.has_app_pack()) {
564    typedef RepeatedPtrField<em::AppPackEntryProto> proto_type;
565    base::ListValue* list = new base::ListValue;
566    const proto_type& app_pack = policy.app_pack().app_pack();
567    for (proto_type::const_iterator it = app_pack.begin();
568         it != app_pack.end(); ++it) {
569      base::DictionaryValue* entry = new base::DictionaryValue;
570      if (it->has_extension_id()) {
571        entry->SetStringWithoutPathExpansion(kAppPackKeyExtensionId,
572                                             it->extension_id());
573      }
574      if (it->has_update_url()) {
575        entry->SetStringWithoutPathExpansion(kAppPackKeyUpdateUrl,
576                                             it->update_url());
577      }
578      list->Append(entry);
579    }
580    new_values_cache->SetValue(kAppPack, list);
581  }
582
583  if (policy.has_start_up_urls()) {
584    base::ListValue* list = new base::ListValue();
585    const em::StartUpUrlsProto& urls_proto = policy.start_up_urls();
586    const RepeatedPtrField<std::string>& urls = urls_proto.start_up_urls();
587    for (RepeatedPtrField<std::string>::const_iterator it = urls.begin();
588         it != urls.end(); ++it) {
589      list->Append(new base::StringValue(*it));
590    }
591    new_values_cache->SetValue(kStartUpUrls, list);
592  }
593}
594
595void DeviceSettingsProvider::DecodeNetworkPolicies(
596    const em::ChromeDeviceSettingsProto& policy,
597    PrefValueMap* new_values_cache) const {
598  new_values_cache->SetBoolean(
599      kSignedDataRoamingEnabled,
600      policy.has_data_roaming_enabled() &&
601      policy.data_roaming_enabled().has_data_roaming_enabled() &&
602      policy.data_roaming_enabled().data_roaming_enabled());
603}
604
605void DeviceSettingsProvider::DecodeAutoUpdatePolicies(
606    const em::ChromeDeviceSettingsProto& policy,
607    PrefValueMap* new_values_cache) const {
608  if (!policy.has_auto_update_settings())
609    return;
610  const em::AutoUpdateSettingsProto& au_settings_proto =
611      policy.auto_update_settings();
612  if (au_settings_proto.has_update_disabled()) {
613    new_values_cache->SetBoolean(kUpdateDisabled,
614                                 au_settings_proto.update_disabled());
615  }
616  const RepeatedField<int>& allowed_connection_types =
617      au_settings_proto.allowed_connection_types();
618  base::ListValue* list = new base::ListValue();
619  for (RepeatedField<int>::const_iterator i = allowed_connection_types.begin(),
620           e = allowed_connection_types.end(); i != e; ++i) {
621    list->Append(new base::FundamentalValue(*i));
622  }
623  new_values_cache->SetValue(kAllowedConnectionTypesForUpdate, list);
624}
625
626void DeviceSettingsProvider::DecodeReportingPolicies(
627    const em::ChromeDeviceSettingsProto& policy,
628    PrefValueMap* new_values_cache) const {
629  if (policy.has_device_reporting()) {
630    if (policy.device_reporting().has_report_version_info()) {
631      new_values_cache->SetBoolean(
632          kReportDeviceVersionInfo,
633          policy.device_reporting().report_version_info());
634    }
635    if (policy.device_reporting().has_report_activity_times()) {
636      new_values_cache->SetBoolean(
637          kReportDeviceActivityTimes,
638          policy.device_reporting().report_activity_times());
639    }
640    if (policy.device_reporting().has_report_boot_mode()) {
641      new_values_cache->SetBoolean(
642          kReportDeviceBootMode,
643          policy.device_reporting().report_boot_mode());
644    }
645    // Device location reporting needs to pass privacy review before it can be
646    // enabled. crosbug.com/24681
647    // if (policy.device_reporting().has_report_location()) {
648    //   new_values_cache->SetBoolean(
649    //       kReportDeviceLocation,
650    //       policy.device_reporting().report_location());
651    // }
652  }
653}
654
655void DeviceSettingsProvider::DecodeGenericPolicies(
656    const em::ChromeDeviceSettingsProto& policy,
657    PrefValueMap* new_values_cache) const {
658  if (policy.has_metrics_enabled()) {
659    new_values_cache->SetBoolean(kStatsReportingPref,
660                                 policy.metrics_enabled().metrics_enabled());
661  } else {
662    new_values_cache->SetBoolean(kStatsReportingPref, HasOldMetricsFile());
663  }
664
665  if (!policy.has_release_channel() ||
666      !policy.release_channel().has_release_channel()) {
667    // Default to an invalid channel (will be ignored).
668    new_values_cache->SetString(kReleaseChannel, "");
669  } else {
670    new_values_cache->SetString(kReleaseChannel,
671                                policy.release_channel().release_channel());
672  }
673
674  new_values_cache->SetBoolean(
675      kReleaseChannelDelegated,
676      policy.has_release_channel() &&
677      policy.release_channel().has_release_channel_delegated() &&
678      policy.release_channel().release_channel_delegated());
679
680  if (policy.has_system_timezone()) {
681    if (policy.system_timezone().has_timezone()) {
682      new_values_cache->SetString(
683          kSystemTimezonePolicy,
684          policy.system_timezone().timezone());
685    }
686  }
687
688  if (policy.has_allow_redeem_offers()) {
689    new_values_cache->SetBoolean(
690        kAllowRedeemChromeOsRegistrationOffers,
691        policy.allow_redeem_offers().allow_redeem_offers());
692  } else {
693    new_values_cache->SetBoolean(
694        kAllowRedeemChromeOsRegistrationOffers,
695        true);
696  }
697
698  if (policy.has_variations_parameter()) {
699    new_values_cache->SetString(
700        kVariationsRestrictParameter,
701        policy.variations_parameter().parameter());
702  }
703
704  new_values_cache->SetBoolean(
705      kDeviceAttestationEnabled,
706      policy.attestation_settings().attestation_enabled());
707}
708
709void DeviceSettingsProvider::UpdateValuesCache(
710    const em::PolicyData& policy_data,
711    const em::ChromeDeviceSettingsProto& settings,
712    TrustedStatus trusted_status) {
713  PrefValueMap new_values_cache;
714
715  if (policy_data.has_username() && !policy_data.has_request_token())
716    new_values_cache.SetString(kDeviceOwner, policy_data.username());
717
718  DecodeLoginPolicies(settings, &new_values_cache);
719  DecodeKioskPolicies(settings, &new_values_cache);
720  DecodeNetworkPolicies(settings, &new_values_cache);
721  DecodeAutoUpdatePolicies(settings, &new_values_cache);
722  DecodeReportingPolicies(settings, &new_values_cache);
723  DecodeGenericPolicies(settings, &new_values_cache);
724
725  // Collect all notifications but send them only after we have swapped the
726  // cache so that if somebody actually reads the cache will be already valid.
727  std::vector<std::string> notifications;
728  // Go through the new values and verify in the old ones.
729  PrefValueMap::iterator iter = new_values_cache.begin();
730  for (; iter != new_values_cache.end(); ++iter) {
731    const base::Value* old_value;
732    if (!values_cache_.GetValue(iter->first, &old_value) ||
733        !old_value->Equals(iter->second)) {
734      notifications.push_back(iter->first);
735    }
736  }
737  // Now check for values that have been removed from the policy blob.
738  for (iter = values_cache_.begin(); iter != values_cache_.end(); ++iter) {
739    const base::Value* value;
740    if (!new_values_cache.GetValue(iter->first, &value))
741      notifications.push_back(iter->first);
742  }
743  // Swap and notify.
744  values_cache_.Swap(&new_values_cache);
745  trusted_status_ = trusted_status;
746  for (size_t i = 0; i < notifications.size(); ++i)
747    NotifyObservers(notifications[i]);
748}
749
750void DeviceSettingsProvider::ApplyMetricsSetting(bool use_file,
751                                                 bool new_value) {
752  // TODO(pastarmovj): Remove this once migration is not needed anymore.
753  // If the value is not set we should try to migrate legacy consent file.
754  if (use_file) {
755    new_value = HasOldMetricsFile();
756    // Make sure the values will get eventually written to the policy file.
757    migration_values_.SetValue(kStatsReportingPref,
758                               base::Value::CreateBooleanValue(new_value));
759    AttemptMigration();
760    LOG(INFO) << "No metrics policy set will revert to checking "
761              << "consent file which is "
762              << (new_value ? "on." : "off.");
763    UMA_HISTOGRAM_COUNTS("DeviceSettings.MetricsMigrated", 1);
764  }
765  VLOG(1) << "Metrics policy is being set to : " << new_value
766          << "(use file : " << use_file << ")";
767  // TODO(pastarmovj): Remove this once we don't need to regenerate the
768  // consent file for the GUID anymore.
769  OptionsUtil::ResolveMetricsReportingEnabled(new_value);
770}
771
772void DeviceSettingsProvider::ApplyRoamingSetting(bool new_value) {
773  if (!CrosLibrary::Get())
774    return;  // May not be initialized in tests.
775  NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary();
776  const NetworkDevice* cellular = cros->FindCellularDevice();
777  if (cellular) {
778    bool device_value = cellular->data_roaming_allowed();
779    if (!device_value && cros->IsCellularAlwaysInRoaming()) {
780      // If operator requires roaming always enabled, ignore supplied value
781      // and set data roaming allowed in true always.
782      cros->SetCellularDataRoamingAllowed(true);
783    } else if (device_value != new_value) {
784      cros->SetCellularDataRoamingAllowed(new_value);
785    }
786  }
787}
788
789void DeviceSettingsProvider::ApplySideEffects(
790    const em::ChromeDeviceSettingsProto& settings) {
791  // First migrate metrics settings as needed.
792  if (settings.has_metrics_enabled())
793    ApplyMetricsSetting(false, settings.metrics_enabled().metrics_enabled());
794  else
795    ApplyMetricsSetting(true, false);
796
797  // Next set the roaming setting as needed.
798  ApplyRoamingSetting(
799      settings.has_data_roaming_enabled() ?
800          settings.data_roaming_enabled().data_roaming_enabled() :
801          false);
802}
803
804bool DeviceSettingsProvider::MitigateMissingPolicy() {
805  // First check if the device has been owned already and if not exit
806  // immediately.
807  if (g_browser_process->browser_policy_connector()->GetDeviceMode() !=
808          policy::DEVICE_MODE_CONSUMER) {
809    return false;
810  }
811
812  // If we are here the policy file were corrupted or missing. This can happen
813  // because we are migrating Pre R11 device to the new secure policies or there
814  // was an attempt to circumvent policy system. In this case we should populate
815  // the policy cache with "safe-mode" defaults which should allow the owner to
816  // log in but lock the device for anyone else until the policy blob has been
817  // recreated by the session manager.
818  LOG(ERROR) << "Corruption of the policy data has been detected."
819             << "Switching to \"safe-mode\" policies until the owner logs in "
820             << "to regenerate the policy data.";
821
822  device_settings_.Clear();
823  device_settings_.mutable_allow_new_users()->set_allow_new_users(true);
824  device_settings_.mutable_guest_mode_enabled()->set_guest_mode_enabled(true);
825  em::PolicyData empty_policy_data;
826  UpdateValuesCache(empty_policy_data, device_settings_, TRUSTED);
827  values_cache_.SetBoolean(kPolicyMissingMitigationMode, true);
828
829  return true;
830}
831
832const base::Value* DeviceSettingsProvider::Get(const std::string& path) const {
833  if (IsDeviceSetting(path)) {
834    const base::Value* value;
835    if (values_cache_.GetValue(path, &value))
836      return value;
837  } else {
838    NOTREACHED() << "Trying to get non cros setting.";
839  }
840
841  return NULL;
842}
843
844DeviceSettingsProvider::TrustedStatus
845    DeviceSettingsProvider::PrepareTrustedValues(const base::Closure& cb) {
846  TrustedStatus status = RequestTrustedEntity();
847  if (status == TEMPORARILY_UNTRUSTED && !cb.is_null())
848    callbacks_.push_back(cb);
849  return status;
850}
851
852bool DeviceSettingsProvider::HandlesSetting(const std::string& path) const {
853  return IsDeviceSetting(path);
854}
855
856DeviceSettingsProvider::TrustedStatus
857    DeviceSettingsProvider::RequestTrustedEntity() {
858  if (ownership_status_ == DeviceSettingsService::OWNERSHIP_NONE)
859    return TRUSTED;
860  return trusted_status_;
861}
862
863void DeviceSettingsProvider::UpdateAndProceedStoring() {
864  // Re-sync the cache from the service.
865  UpdateFromService();
866
867  // Trigger the next change if necessary.
868  if (trusted_status_ == TRUSTED && !pending_changes_.empty())
869    SetInPolicy();
870}
871
872bool DeviceSettingsProvider::UpdateFromService() {
873  bool settings_loaded = false;
874  switch (device_settings_service_->status()) {
875    case DeviceSettingsService::STORE_SUCCESS: {
876      const em::PolicyData* policy_data =
877          device_settings_service_->policy_data();
878      const em::ChromeDeviceSettingsProto* device_settings =
879          device_settings_service_->device_settings();
880      if (policy_data && device_settings) {
881        if (!device_settings_cache::Store(*policy_data,
882                                          g_browser_process->local_state())) {
883          LOG(ERROR) << "Couldn't update the local state cache.";
884        }
885        UpdateValuesCache(*policy_data, *device_settings, TRUSTED);
886        device_settings_ = *device_settings;
887
888        // TODO(pastarmovj): Make those side effects responsibility of the
889        // respective subsystems.
890        ApplySideEffects(*device_settings);
891
892        settings_loaded = true;
893      } else {
894        // Initial policy load is still pending.
895        trusted_status_ = TEMPORARILY_UNTRUSTED;
896      }
897      break;
898    }
899    case DeviceSettingsService::STORE_NO_POLICY:
900      if (MitigateMissingPolicy())
901        break;
902      // fall through.
903    case DeviceSettingsService::STORE_KEY_UNAVAILABLE:
904      VLOG(1) << "No policies present yet, will use the temp storage.";
905      trusted_status_ = PERMANENTLY_UNTRUSTED;
906      break;
907    case DeviceSettingsService::STORE_POLICY_ERROR:
908    case DeviceSettingsService::STORE_VALIDATION_ERROR:
909    case DeviceSettingsService::STORE_INVALID_POLICY:
910    case DeviceSettingsService::STORE_OPERATION_FAILED:
911      LOG(ERROR) << "Failed to retrieve cros policies. Reason: "
912                 << device_settings_service_->status();
913      trusted_status_ = PERMANENTLY_UNTRUSTED;
914      break;
915    case DeviceSettingsService::STORE_TEMP_VALIDATION_ERROR:
916      // The policy has failed to validate due to temporary error but it might
917      // take a long time until we recover so behave as it is a permanent error.
918      LOG(ERROR) << "Failed to retrieve cros policies because a temporary "
919                 << "validation error has occurred. Retrying might succeed.";
920      trusted_status_ = PERMANENTLY_UNTRUSTED;
921      break;
922  }
923
924  // Notify the observers we are done.
925  std::vector<base::Closure> callbacks;
926  callbacks.swap(callbacks_);
927  for (size_t i = 0; i < callbacks.size(); ++i)
928    callbacks[i].Run();
929
930  return settings_loaded;
931}
932
933void DeviceSettingsProvider::StoreDeviceSettings() {
934  // Mute all previous callbacks to guarantee the |pending_changes_| queue is
935  // processed serially.
936  store_callback_factory_.InvalidateWeakPtrs();
937
938  device_settings_service_->SignAndStore(
939      scoped_ptr<em::ChromeDeviceSettingsProto>(
940          new em::ChromeDeviceSettingsProto(device_settings_)),
941      base::Bind(&DeviceSettingsProvider::UpdateAndProceedStoring,
942                 store_callback_factory_.GetWeakPtr()));
943}
944
945void DeviceSettingsProvider::AttemptMigration() {
946  if (device_settings_service_->HasPrivateOwnerKey()) {
947    PrefValueMap::const_iterator i;
948    for (i = migration_values_.begin(); i != migration_values_.end(); ++i)
949      DoSet(i->first, *i->second);
950    migration_values_.Clear();
951  }
952}
953
954}  // namespace chromeos
955