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