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