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