device_settings_provider.cc revision a93a17c8d99d686bd4a1511e5504e5e6cc9fcadf
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/settings/cros_settings.h"
21#include "chrome/browser/chromeos/settings/cros_settings_names.h"
22#include "chrome/browser/chromeos/settings/device_settings_cache.h"
23#include "chrome/browser/policy/browser_policy_connector.h"
24#include "chrome/browser/policy/cloud/cloud_policy_constants.h"
25#include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
26#include "chrome/browser/ui/options/options_util.h"
27#include "chrome/installer/util/google_update_settings.h"
28#include "chromeos/chromeos_switches.h"
29
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  kAccountsPrefEphemeralUsersEnabled,
47  kAccountsPrefShowUserNamesOnSignIn,
48  kAccountsPrefUsers,
49  kAllowRedeemChromeOsRegistrationOffers,
50  kAppPack,
51  kDeviceAttestationEnabled,
52  kDeviceOwner,
53  kIdleLogoutTimeout,
54  kIdleLogoutWarningDuration,
55  kPolicyMissingMitigationMode,
56  kReleaseChannel,
57  kReleaseChannelDelegated,
58  kReportDeviceActivityTimes,
59  kReportDeviceBootMode,
60  kReportDeviceLocation,
61  kReportDeviceVersionInfo,
62  kScreenSaverExtensionId,
63  kScreenSaverTimeout,
64  kSettingProxyEverywhere,
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 == kSettingProxyEverywhere) {
301    // TODO(cmasone): NOTIMPLEMENTED() once http://crosbug.com/13052 is fixed.
302    std::string proxy_value;
303    if (value->GetAsString(&proxy_value)) {
304      bool success =
305          device_settings_.mutable_device_proxy_settings()->ParseFromString(
306              proxy_value);
307      DCHECK(success);
308    } else {
309      NOTREACHED();
310    }
311  } else if (prop == kReleaseChannel) {
312    em::ReleaseChannelProto* release_channel =
313        device_settings_.mutable_release_channel();
314    std::string channel_value;
315    if (value->GetAsString(&channel_value))
316      release_channel->set_release_channel(channel_value);
317    else
318      NOTREACHED();
319  } else if (prop == kStatsReportingPref) {
320    em::MetricsEnabledProto* metrics =
321        device_settings_.mutable_metrics_enabled();
322    bool metrics_value = false;
323    if (value->GetAsBoolean(&metrics_value))
324      metrics->set_metrics_enabled(metrics_value);
325    else
326      NOTREACHED();
327    ApplyMetricsSetting(false, metrics_value);
328  } else if (prop == kAccountsPrefUsers) {
329    em::UserWhitelistProto* whitelist_proto =
330        device_settings_.mutable_user_whitelist();
331    whitelist_proto->clear_user_whitelist();
332    const base::ListValue* users;
333    if (value->GetAsList(&users)) {
334      for (base::ListValue::const_iterator i = users->begin();
335           i != users->end(); ++i) {
336        std::string email;
337        if ((*i)->GetAsString(&email))
338          whitelist_proto->add_user_whitelist(email);
339      }
340    }
341  } else if (prop == kAccountsPrefEphemeralUsersEnabled) {
342    em::EphemeralUsersEnabledProto* ephemeral_users_enabled =
343        device_settings_.mutable_ephemeral_users_enabled();
344    bool ephemeral_users_enabled_value = false;
345    if (value->GetAsBoolean(&ephemeral_users_enabled_value)) {
346      ephemeral_users_enabled->set_ephemeral_users_enabled(
347          ephemeral_users_enabled_value);
348    } else {
349      NOTREACHED();
350    }
351  } else if (prop == kAllowRedeemChromeOsRegistrationOffers) {
352    em::AllowRedeemChromeOsRegistrationOffersProto* allow_redeem_offers =
353        device_settings_.mutable_allow_redeem_offers();
354    bool allow_redeem_offers_value;
355    if (value->GetAsBoolean(&allow_redeem_offers_value)) {
356      allow_redeem_offers->set_allow_redeem_offers(
357          allow_redeem_offers_value);
358    } else {
359      NOTREACHED();
360    }
361  } else if (prop == kStartUpFlags) {
362    em::StartUpFlagsProto* flags_proto =
363        device_settings_.mutable_start_up_flags();
364    flags_proto->Clear();
365    const base::ListValue* flags;
366    if (value->GetAsList(&flags)) {
367      for (base::ListValue::const_iterator i = flags->begin();
368           i != flags->end(); ++i) {
369        std::string flag;
370        if ((*i)->GetAsString(&flag))
371          flags_proto->add_flags(flag);
372      }
373    }
374  } else {
375    // The remaining settings don't support Set(), since they are not
376    // intended to be customizable by the user:
377    //   kAppPack
378    //   kDeviceAttestationEnabled
379    //   kDeviceOwner
380    //   kIdleLogoutTimeout
381    //   kIdleLogoutWarningDuration
382    //   kReleaseChannelDelegated
383    //   kReportDeviceVersionInfo
384    //   kReportDeviceActivityTimes
385    //   kReportDeviceBootMode
386    //   kReportDeviceLocation
387    //   kScreenSaverExtensionId
388    //   kScreenSaverTimeout
389    //   kStartUpUrls
390    //   kSystemTimezonePolicy
391    //   kVariationsRestrictParameter
392
393    LOG(FATAL) << "Device setting " << prop << " is read-only.";
394  }
395
396  em::PolicyData data;
397  data.set_username(device_settings_service_->GetUsername());
398  CHECK(device_settings_.SerializeToString(data.mutable_policy_value()));
399
400  // Set the cache to the updated value.
401  UpdateValuesCache(data, device_settings_, trusted_status_);
402
403  if (ownership_status_ == DeviceSettingsService::OWNERSHIP_TAKEN) {
404    StoreDeviceSettings();
405  } else {
406    if (!device_settings_cache::Store(data, g_browser_process->local_state()))
407      LOG(ERROR) << "Couldn't store to the temp storage.";
408
409    // OnStorePolicyCompleted won't get called in this case so proceed with any
410    // pending operations immediately.
411    if (!pending_changes_.empty())
412      SetInPolicy();
413  }
414}
415
416void DeviceSettingsProvider::DecodeLoginPolicies(
417    const em::ChromeDeviceSettingsProto& policy,
418    PrefValueMap* new_values_cache) const {
419  // For all our boolean settings the following is applicable:
420  // true is default permissive value and false is safe prohibitive value.
421  // Exceptions:
422  //   kSignedDataRoamingEnabled has a default value of false.
423  //   kAccountsPrefEphemeralUsersEnabled has a default value of false.
424  if (policy.has_allow_new_users() &&
425      policy.allow_new_users().has_allow_new_users()) {
426    if (policy.allow_new_users().allow_new_users()) {
427      // New users allowed, user whitelist ignored.
428      new_values_cache->SetBoolean(kAccountsPrefAllowNewUser, true);
429    } else {
430      // New users not allowed, enforce user whitelist if present.
431      new_values_cache->SetBoolean(kAccountsPrefAllowNewUser,
432                                   !policy.has_user_whitelist());
433    }
434  } else {
435    // No configured allow-new-users value, enforce whitelist if non-empty.
436    new_values_cache->SetBoolean(
437        kAccountsPrefAllowNewUser,
438        policy.user_whitelist().user_whitelist_size() == 0);
439  }
440
441  new_values_cache->SetBoolean(
442      kAccountsPrefAllowGuest,
443      !policy.has_guest_mode_enabled() ||
444      !policy.guest_mode_enabled().has_guest_mode_enabled() ||
445      policy.guest_mode_enabled().guest_mode_enabled());
446
447  new_values_cache->SetBoolean(
448      kAccountsPrefShowUserNamesOnSignIn,
449      !policy.has_show_user_names() ||
450      !policy.show_user_names().has_show_user_names() ||
451      policy.show_user_names().show_user_names());
452
453  new_values_cache->SetBoolean(
454      kAccountsPrefEphemeralUsersEnabled,
455      policy.has_ephemeral_users_enabled() &&
456      policy.ephemeral_users_enabled().has_ephemeral_users_enabled() &&
457      policy.ephemeral_users_enabled().ephemeral_users_enabled());
458
459  base::ListValue* list = new base::ListValue();
460  const em::UserWhitelistProto& whitelist_proto = policy.user_whitelist();
461  const RepeatedPtrField<std::string>& whitelist =
462      whitelist_proto.user_whitelist();
463  for (RepeatedPtrField<std::string>::const_iterator it = whitelist.begin();
464       it != whitelist.end(); ++it) {
465    list->Append(new base::StringValue(*it));
466  }
467  new_values_cache->SetValue(kAccountsPrefUsers, list);
468
469  scoped_ptr<base::ListValue> account_list(new base::ListValue());
470  CommandLine* command_line = CommandLine::ForCurrentProcess();
471  if (!command_line->HasSwitch(switches::kDisableLocalAccounts)) {
472    const em::DeviceLocalAccountsProto device_local_accounts_proto =
473        policy.device_local_accounts();
474    const RepeatedPtrField<em::DeviceLocalAccountInfoProto>& accounts =
475        device_local_accounts_proto.account();
476    RepeatedPtrField<em::DeviceLocalAccountInfoProto>::const_iterator entry;
477    for (entry = accounts.begin(); entry != accounts.end(); ++entry) {
478      scoped_ptr<base::DictionaryValue> entry_dict(new base::DictionaryValue());
479      if (entry->has_type()) {
480        if (entry->has_account_id()) {
481          entry_dict->SetStringWithoutPathExpansion(
482              kAccountsPrefDeviceLocalAccountsKeyId, entry->account_id());
483        }
484        entry_dict->SetIntegerWithoutPathExpansion(
485            kAccountsPrefDeviceLocalAccountsKeyType, entry->type());
486        if (entry->kiosk_app().has_app_id()) {
487          entry_dict->SetStringWithoutPathExpansion(
488              kAccountsPrefDeviceLocalAccountsKeyKioskAppId,
489              entry->kiosk_app().app_id());
490        }
491        if (entry->kiosk_app().has_update_url()) {
492          entry_dict->SetStringWithoutPathExpansion(
493              kAccountsPrefDeviceLocalAccountsKeyKioskAppUpdateURL,
494              entry->kiosk_app().update_url());
495        }
496      } else if (entry->has_deprecated_public_session_id()) {
497        // Deprecated public session specification.
498        entry_dict->SetStringWithoutPathExpansion(
499            kAccountsPrefDeviceLocalAccountsKeyId,
500            entry->deprecated_public_session_id());
501        entry_dict->SetIntegerWithoutPathExpansion(
502            kAccountsPrefDeviceLocalAccountsKeyType,
503            DEVICE_LOCAL_ACCOUNT_TYPE_PUBLIC_SESSION);
504      }
505      account_list->Append(entry_dict.release());
506    }
507  }
508  new_values_cache->SetValue(kAccountsPrefDeviceLocalAccounts,
509                             account_list.release());
510
511  if (policy.has_device_local_accounts()) {
512    if (policy.device_local_accounts().has_auto_login_id()) {
513      new_values_cache->SetString(
514          kAccountsPrefDeviceLocalAccountAutoLoginId,
515          policy.device_local_accounts().auto_login_id());
516    }
517    if (policy.device_local_accounts().has_auto_login_delay()) {
518      new_values_cache->SetInteger(
519          kAccountsPrefDeviceLocalAccountAutoLoginDelay,
520          policy.device_local_accounts().auto_login_delay());
521    }
522  }
523
524  new_values_cache->SetBoolean(
525      kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled,
526      policy.device_local_accounts().enable_auto_login_bailout());
527
528  if (policy.has_start_up_flags()) {
529    base::ListValue* list = new base::ListValue();
530    const em::StartUpFlagsProto& flags_proto = policy.start_up_flags();
531    const RepeatedPtrField<std::string>& flags = flags_proto.flags();
532    for (RepeatedPtrField<std::string>::const_iterator it = flags.begin();
533         it != flags.end(); ++it) {
534      list->Append(new base::StringValue(*it));
535    }
536    new_values_cache->SetValue(kStartUpFlags, list);
537  }
538}
539
540void DeviceSettingsProvider::DecodeKioskPolicies(
541    const em::ChromeDeviceSettingsProto& policy,
542    PrefValueMap* new_values_cache) const {
543  if (policy.has_forced_logout_timeouts()) {
544    if (policy.forced_logout_timeouts().has_idle_logout_timeout()) {
545      new_values_cache->SetInteger(
546          kIdleLogoutTimeout,
547          policy.forced_logout_timeouts().idle_logout_timeout());
548    }
549
550    if (policy.forced_logout_timeouts().has_idle_logout_warning_duration()) {
551      new_values_cache->SetInteger(
552          kIdleLogoutWarningDuration,
553          policy.forced_logout_timeouts().idle_logout_warning_duration());
554    }
555  }
556
557  if (policy.has_login_screen_saver()) {
558    if (policy.login_screen_saver().has_screen_saver_timeout()) {
559      new_values_cache->SetInteger(
560          kScreenSaverTimeout,
561          policy.login_screen_saver().screen_saver_timeout());
562    }
563
564    if (policy.login_screen_saver().has_screen_saver_extension_id()) {
565      new_values_cache->SetString(
566          kScreenSaverExtensionId,
567          policy.login_screen_saver().screen_saver_extension_id());
568    }
569  }
570
571  if (policy.has_app_pack()) {
572    typedef RepeatedPtrField<em::AppPackEntryProto> proto_type;
573    base::ListValue* list = new base::ListValue;
574    const proto_type& app_pack = policy.app_pack().app_pack();
575    for (proto_type::const_iterator it = app_pack.begin();
576         it != app_pack.end(); ++it) {
577      base::DictionaryValue* entry = new base::DictionaryValue;
578      if (it->has_extension_id()) {
579        entry->SetStringWithoutPathExpansion(kAppPackKeyExtensionId,
580                                             it->extension_id());
581      }
582      if (it->has_update_url()) {
583        entry->SetStringWithoutPathExpansion(kAppPackKeyUpdateUrl,
584                                             it->update_url());
585      }
586      list->Append(entry);
587    }
588    new_values_cache->SetValue(kAppPack, list);
589  }
590
591  if (policy.has_start_up_urls()) {
592    base::ListValue* list = new base::ListValue();
593    const em::StartUpUrlsProto& urls_proto = policy.start_up_urls();
594    const RepeatedPtrField<std::string>& urls = urls_proto.start_up_urls();
595    for (RepeatedPtrField<std::string>::const_iterator it = urls.begin();
596         it != urls.end(); ++it) {
597      list->Append(new base::StringValue(*it));
598    }
599    new_values_cache->SetValue(kStartUpUrls, list);
600  }
601}
602
603void DeviceSettingsProvider::DecodeNetworkPolicies(
604    const em::ChromeDeviceSettingsProto& policy,
605    PrefValueMap* new_values_cache) const {
606  new_values_cache->SetBoolean(
607      kSignedDataRoamingEnabled,
608      policy.has_data_roaming_enabled() &&
609      policy.data_roaming_enabled().has_data_roaming_enabled() &&
610      policy.data_roaming_enabled().data_roaming_enabled());
611
612  // TODO(cmasone): NOTIMPLEMENTED() once http://crosbug.com/13052 is fixed.
613  std::string serialized;
614  if (policy.has_device_proxy_settings() &&
615      policy.device_proxy_settings().SerializeToString(&serialized)) {
616    new_values_cache->SetString(kSettingProxyEverywhere, serialized);
617  }
618}
619
620void DeviceSettingsProvider::DecodeReportingPolicies(
621    const em::ChromeDeviceSettingsProto& policy,
622    PrefValueMap* new_values_cache) const {
623  if (policy.has_device_reporting()) {
624    if (policy.device_reporting().has_report_version_info()) {
625      new_values_cache->SetBoolean(
626          kReportDeviceVersionInfo,
627          policy.device_reporting().report_version_info());
628    }
629    if (policy.device_reporting().has_report_activity_times()) {
630      new_values_cache->SetBoolean(
631          kReportDeviceActivityTimes,
632          policy.device_reporting().report_activity_times());
633    }
634    if (policy.device_reporting().has_report_boot_mode()) {
635      new_values_cache->SetBoolean(
636          kReportDeviceBootMode,
637          policy.device_reporting().report_boot_mode());
638    }
639    // Device location reporting needs to pass privacy review before it can be
640    // enabled. crosbug.com/24681
641    // if (policy.device_reporting().has_report_location()) {
642    //   new_values_cache->SetBoolean(
643    //       kReportDeviceLocation,
644    //       policy.device_reporting().report_location());
645    // }
646  }
647}
648
649void DeviceSettingsProvider::DecodeGenericPolicies(
650    const em::ChromeDeviceSettingsProto& policy,
651    PrefValueMap* new_values_cache) const {
652  if (policy.has_metrics_enabled()) {
653    new_values_cache->SetBoolean(kStatsReportingPref,
654                                 policy.metrics_enabled().metrics_enabled());
655  } else {
656    new_values_cache->SetBoolean(kStatsReportingPref, HasOldMetricsFile());
657  }
658
659  if (!policy.has_release_channel() ||
660      !policy.release_channel().has_release_channel()) {
661    // Default to an invalid channel (will be ignored).
662    new_values_cache->SetString(kReleaseChannel, "");
663  } else {
664    new_values_cache->SetString(kReleaseChannel,
665                                policy.release_channel().release_channel());
666  }
667
668  new_values_cache->SetBoolean(
669      kReleaseChannelDelegated,
670      policy.has_release_channel() &&
671      policy.release_channel().has_release_channel_delegated() &&
672      policy.release_channel().release_channel_delegated());
673
674  if (policy.has_system_timezone()) {
675    if (policy.system_timezone().has_timezone()) {
676      new_values_cache->SetString(
677          kSystemTimezonePolicy,
678          policy.system_timezone().timezone());
679    }
680  }
681
682  if (policy.has_allow_redeem_offers()) {
683    new_values_cache->SetBoolean(
684        kAllowRedeemChromeOsRegistrationOffers,
685        policy.allow_redeem_offers().allow_redeem_offers());
686  } else {
687    new_values_cache->SetBoolean(
688        kAllowRedeemChromeOsRegistrationOffers,
689        true);
690  }
691
692  if (policy.has_variations_parameter()) {
693    new_values_cache->SetString(
694        kVariationsRestrictParameter,
695        policy.variations_parameter().parameter());
696  }
697
698  new_values_cache->SetBoolean(
699      kDeviceAttestationEnabled,
700      policy.attestation_settings().attestation_enabled());
701}
702
703void DeviceSettingsProvider::UpdateValuesCache(
704    const em::PolicyData& policy_data,
705    const em::ChromeDeviceSettingsProto& settings,
706    TrustedStatus trusted_status) {
707  PrefValueMap new_values_cache;
708
709  if (policy_data.has_username() && !policy_data.has_request_token())
710    new_values_cache.SetString(kDeviceOwner, policy_data.username());
711
712  DecodeLoginPolicies(settings, &new_values_cache);
713  DecodeKioskPolicies(settings, &new_values_cache);
714  DecodeNetworkPolicies(settings, &new_values_cache);
715  DecodeReportingPolicies(settings, &new_values_cache);
716  DecodeGenericPolicies(settings, &new_values_cache);
717
718  // Collect all notifications but send them only after we have swapped the
719  // cache so that if somebody actually reads the cache will be already valid.
720  std::vector<std::string> notifications;
721  // Go through the new values and verify in the old ones.
722  PrefValueMap::iterator iter = new_values_cache.begin();
723  for (; iter != new_values_cache.end(); ++iter) {
724    const base::Value* old_value;
725    if (!values_cache_.GetValue(iter->first, &old_value) ||
726        !old_value->Equals(iter->second)) {
727      notifications.push_back(iter->first);
728    }
729  }
730  // Now check for values that have been removed from the policy blob.
731  for (iter = values_cache_.begin(); iter != values_cache_.end(); ++iter) {
732    const base::Value* value;
733    if (!new_values_cache.GetValue(iter->first, &value))
734      notifications.push_back(iter->first);
735  }
736  // Swap and notify.
737  values_cache_.Swap(&new_values_cache);
738  trusted_status_ = trusted_status;
739  for (size_t i = 0; i < notifications.size(); ++i)
740    NotifyObservers(notifications[i]);
741}
742
743void DeviceSettingsProvider::ApplyMetricsSetting(bool use_file,
744                                                 bool new_value) {
745  // TODO(pastarmovj): Remove this once migration is not needed anymore.
746  // If the value is not set we should try to migrate legacy consent file.
747  if (use_file) {
748    new_value = HasOldMetricsFile();
749    // Make sure the values will get eventually written to the policy file.
750    migration_values_.SetValue(kStatsReportingPref,
751                               base::Value::CreateBooleanValue(new_value));
752    AttemptMigration();
753    LOG(INFO) << "No metrics policy set will revert to checking "
754              << "consent file which is "
755              << (new_value ? "on." : "off.");
756    UMA_HISTOGRAM_COUNTS("DeviceSettings.MetricsMigrated", 1);
757  }
758  VLOG(1) << "Metrics policy is being set to : " << new_value
759          << "(use file : " << use_file << ")";
760  // TODO(pastarmovj): Remove this once we don't need to regenerate the
761  // consent file for the GUID anymore.
762  OptionsUtil::ResolveMetricsReportingEnabled(new_value);
763}
764
765void DeviceSettingsProvider::ApplyRoamingSetting(bool new_value) {
766  if (!CrosLibrary::Get())
767    return;  // May not be initialized in tests.
768  NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary();
769  const NetworkDevice* cellular = cros->FindCellularDevice();
770  if (cellular) {
771    bool device_value = cellular->data_roaming_allowed();
772    if (!device_value && cros->IsCellularAlwaysInRoaming()) {
773      // If operator requires roaming always enabled, ignore supplied value
774      // and set data roaming allowed in true always.
775      cros->SetCellularDataRoamingAllowed(true);
776    } else if (device_value != new_value) {
777      cros->SetCellularDataRoamingAllowed(new_value);
778    }
779  }
780}
781
782void DeviceSettingsProvider::ApplySideEffects(
783    const em::ChromeDeviceSettingsProto& settings) {
784  // First migrate metrics settings as needed.
785  if (settings.has_metrics_enabled())
786    ApplyMetricsSetting(false, settings.metrics_enabled().metrics_enabled());
787  else
788    ApplyMetricsSetting(true, false);
789
790  // Next set the roaming setting as needed.
791  ApplyRoamingSetting(
792      settings.has_data_roaming_enabled() ?
793          settings.data_roaming_enabled().data_roaming_enabled() :
794          false);
795}
796
797bool DeviceSettingsProvider::MitigateMissingPolicy() {
798  // First check if the device has been owned already and if not exit
799  // immediately.
800  if (g_browser_process->browser_policy_connector()->GetDeviceMode() !=
801          policy::DEVICE_MODE_CONSUMER) {
802    return false;
803  }
804
805  // If we are here the policy file were corrupted or missing. This can happen
806  // because we are migrating Pre R11 device to the new secure policies or there
807  // was an attempt to circumvent policy system. In this case we should populate
808  // the policy cache with "safe-mode" defaults which should allow the owner to
809  // log in but lock the device for anyone else until the policy blob has been
810  // recreated by the session manager.
811  LOG(ERROR) << "Corruption of the policy data has been detected."
812             << "Switching to \"safe-mode\" policies until the owner logs in "
813             << "to regenerate the policy data.";
814
815  device_settings_.Clear();
816  device_settings_.mutable_allow_new_users()->set_allow_new_users(true);
817  device_settings_.mutable_guest_mode_enabled()->set_guest_mode_enabled(true);
818  em::PolicyData empty_policy_data;
819  UpdateValuesCache(empty_policy_data, device_settings_, TRUSTED);
820  values_cache_.SetBoolean(kPolicyMissingMitigationMode, true);
821
822  return true;
823}
824
825const base::Value* DeviceSettingsProvider::Get(const std::string& path) const {
826  if (IsDeviceSetting(path)) {
827    const base::Value* value;
828    if (values_cache_.GetValue(path, &value))
829      return value;
830  } else {
831    NOTREACHED() << "Trying to get non cros setting.";
832  }
833
834  return NULL;
835}
836
837DeviceSettingsProvider::TrustedStatus
838    DeviceSettingsProvider::PrepareTrustedValues(const base::Closure& cb) {
839  TrustedStatus status = RequestTrustedEntity();
840  if (status == TEMPORARILY_UNTRUSTED && !cb.is_null())
841    callbacks_.push_back(cb);
842  return status;
843}
844
845bool DeviceSettingsProvider::HandlesSetting(const std::string& path) const {
846  return IsDeviceSetting(path);
847}
848
849DeviceSettingsProvider::TrustedStatus
850    DeviceSettingsProvider::RequestTrustedEntity() {
851  if (ownership_status_ == DeviceSettingsService::OWNERSHIP_NONE)
852    return TRUSTED;
853  return trusted_status_;
854}
855
856void DeviceSettingsProvider::UpdateAndProceedStoring() {
857  // Re-sync the cache from the service.
858  UpdateFromService();
859
860  // Trigger the next change if necessary.
861  if (trusted_status_ == TRUSTED && !pending_changes_.empty())
862    SetInPolicy();
863}
864
865bool DeviceSettingsProvider::UpdateFromService() {
866  bool settings_loaded = false;
867  switch (device_settings_service_->status()) {
868    case DeviceSettingsService::STORE_SUCCESS: {
869      const em::PolicyData* policy_data =
870          device_settings_service_->policy_data();
871      const em::ChromeDeviceSettingsProto* device_settings =
872          device_settings_service_->device_settings();
873      if (policy_data && device_settings) {
874        if (!device_settings_cache::Store(*policy_data,
875                                          g_browser_process->local_state())) {
876          LOG(ERROR) << "Couldn't update the local state cache.";
877        }
878        UpdateValuesCache(*policy_data, *device_settings, TRUSTED);
879        device_settings_ = *device_settings;
880
881        // TODO(pastarmovj): Make those side effects responsibility of the
882        // respective subsystems.
883        ApplySideEffects(*device_settings);
884
885        settings_loaded = true;
886      } else {
887        // Initial policy load is still pending.
888        trusted_status_ = TEMPORARILY_UNTRUSTED;
889      }
890      break;
891    }
892    case DeviceSettingsService::STORE_NO_POLICY:
893      if (MitigateMissingPolicy())
894        break;
895      // fall through.
896    case DeviceSettingsService::STORE_KEY_UNAVAILABLE:
897      VLOG(1) << "No policies present yet, will use the temp storage.";
898      trusted_status_ = PERMANENTLY_UNTRUSTED;
899      break;
900    case DeviceSettingsService::STORE_POLICY_ERROR:
901    case DeviceSettingsService::STORE_VALIDATION_ERROR:
902    case DeviceSettingsService::STORE_INVALID_POLICY:
903    case DeviceSettingsService::STORE_OPERATION_FAILED:
904      LOG(ERROR) << "Failed to retrieve cros policies. Reason: "
905                 << device_settings_service_->status();
906      trusted_status_ = PERMANENTLY_UNTRUSTED;
907      break;
908    case DeviceSettingsService::STORE_TEMP_VALIDATION_ERROR:
909      // The policy has failed to validate due to temporary error but it might
910      // take a long time until we recover so behave as it is a permanent error.
911      LOG(ERROR) << "Failed to retrieve cros policies because a temporary "
912                 << "validation error has occurred. Retrying might succeed.";
913      trusted_status_ = PERMANENTLY_UNTRUSTED;
914      break;
915  }
916
917  // Notify the observers we are done.
918  std::vector<base::Closure> callbacks;
919  callbacks.swap(callbacks_);
920  for (size_t i = 0; i < callbacks.size(); ++i)
921    callbacks[i].Run();
922
923  return settings_loaded;
924}
925
926void DeviceSettingsProvider::StoreDeviceSettings() {
927  // Mute all previous callbacks to guarantee the |pending_changes_| queue is
928  // processed serially.
929  store_callback_factory_.InvalidateWeakPtrs();
930
931  device_settings_service_->SignAndStore(
932      scoped_ptr<em::ChromeDeviceSettingsProto>(
933          new em::ChromeDeviceSettingsProto(device_settings_)),
934      base::Bind(&DeviceSettingsProvider::UpdateAndProceedStoring,
935                 store_callback_factory_.GetWeakPtr()));
936}
937
938void DeviceSettingsProvider::AttemptMigration() {
939  if (device_settings_service_->HasPrivateOwnerKey()) {
940    PrefValueMap::const_iterator i;
941    for (i = migration_values_.begin(); i != migration_values_.end(); ++i)
942      DoSet(i->first, *i->second);
943    migration_values_.Clear();
944  }
945}
946
947}  // namespace chromeos
948