Home | History | Annotate | Download | only in chromeos
      1 // Copyright (c) 2011 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/user_cros_settings_provider.h"
      6 
      7 #include <map>
      8 #include <set>
      9 
     10 #include "base/hash_tables.h"
     11 #include "base/logging.h"
     12 #include "base/memory/singleton.h"
     13 #include "base/string_util.h"
     14 #include "base/task.h"
     15 #include "base/values.h"
     16 #include "chrome/browser/browser_process.h"
     17 #include "chrome/browser/chromeos/cros/cros_library.h"
     18 #include "chrome/browser/chromeos/cros/login_library.h"
     19 #include "chrome/browser/chromeos/cros/network_library.h"
     20 #include "chrome/browser/chromeos/cros_settings.h"
     21 #include "chrome/browser/chromeos/cros_settings_names.h"
     22 #include "chrome/browser/chromeos/login/ownership_service.h"
     23 #include "chrome/browser/chromeos/login/user_manager.h"
     24 #include "chrome/browser/prefs/pref_service.h"
     25 #include "chrome/browser/prefs/scoped_user_pref_update.h"
     26 #include "content/browser/browser_thread.h"
     27 
     28 namespace chromeos {
     29 
     30 namespace {
     31 
     32 const char kTrueIncantation[] = "true";
     33 const char kFalseIncantation[] = "false";
     34 const char kTrustedSuffix[] = "/trusted";
     35 
     36 // For all our boolean settings following is applicable:
     37 // true is default permissive value and false is safe prohibitic value.
     38 // Exception: kSignedDataRoamingEnabled which has default value of false.
     39 const char* kBooleanSettings[] = {
     40   kAccountsPrefAllowNewUser,
     41   kAccountsPrefAllowGuest,
     42   kAccountsPrefShowUserNamesOnSignIn,
     43   kSignedDataRoamingEnabled,
     44 };
     45 
     46 const char* kStringSettings[] = {
     47   kDeviceOwner
     48 };
     49 
     50 const char* kListSettings[] = {
     51   kAccountsPrefUsers
     52 };
     53 
     54 bool IsControlledBooleanSetting(const std::string& pref_path) {
     55   // TODO(nkostylev): Using std::find for 4 value array generates this warning
     56   // in chroot stl_algo.h:231: error: array subscript is above array bounds.
     57   // GCC 4.4.3
     58   return (pref_path == kAccountsPrefAllowNewUser) ||
     59          (pref_path == kAccountsPrefAllowGuest) ||
     60          (pref_path == kAccountsPrefShowUserNamesOnSignIn) ||
     61          (pref_path == kSignedDataRoamingEnabled);
     62 }
     63 
     64 bool IsControlledStringSetting(const std::string& pref_path) {
     65   return std::find(kStringSettings,
     66                    kStringSettings + arraysize(kStringSettings),
     67                    pref_path) !=
     68       kStringSettings + arraysize(kStringSettings);
     69 }
     70 
     71 bool IsControlledListSetting(const std::string& pref_path) {
     72   return std::find(kListSettings,
     73                    kListSettings + arraysize(kListSettings),
     74                    pref_path) !=
     75       kListSettings + arraysize(kListSettings);
     76 }
     77 
     78 void RegisterSetting(PrefService* local_state, const std::string& pref_path) {
     79   local_state->RegisterBooleanPref((pref_path + kTrustedSuffix).c_str(),
     80                                    false);
     81   if (IsControlledBooleanSetting(pref_path)) {
     82     if (pref_path == kSignedDataRoamingEnabled)
     83       local_state->RegisterBooleanPref(pref_path.c_str(), false);
     84     else
     85       local_state->RegisterBooleanPref(pref_path.c_str(), true);
     86   } else if (IsControlledStringSetting(pref_path)) {
     87     local_state->RegisterStringPref(pref_path.c_str(), "");
     88   } else {
     89     DCHECK(IsControlledListSetting(pref_path));
     90     local_state->RegisterListPref(pref_path.c_str());
     91   }
     92 }
     93 
     94 // Create a settings boolean value with "managed" and "disabled" property.
     95 // "managed" property is true if the setting is managed by administrator.
     96 // "disabled" property is true if the UI for the setting should be disabled.
     97 Value* CreateSettingsBooleanValue(bool value, bool managed, bool disabled) {
     98   DictionaryValue* dict = new DictionaryValue;
     99   dict->Set("value", Value::CreateBooleanValue(value));
    100   dict->Set("managed", Value::CreateBooleanValue(managed));
    101   dict->Set("disabled", Value::CreateBooleanValue(disabled));
    102   return dict;
    103 }
    104 
    105 enum UseValue {
    106   USE_VALUE_SUPPLIED,
    107   USE_VALUE_DEFAULT
    108 };
    109 
    110 void UpdateCacheBool(const std::string& name,
    111                      bool value,
    112                      UseValue use_value) {
    113   PrefService* prefs = g_browser_process->local_state();
    114   if (use_value == USE_VALUE_DEFAULT)
    115     prefs->ClearPref(name.c_str());
    116   else
    117     prefs->SetBoolean(name.c_str(), value);
    118   prefs->ScheduleSavePersistentPrefs();
    119 }
    120 
    121 void UpdateCacheString(const std::string& name,
    122                        const std::string& value,
    123                        UseValue use_value) {
    124   PrefService* prefs = g_browser_process->local_state();
    125   if (use_value == USE_VALUE_DEFAULT)
    126     prefs->ClearPref(name.c_str());
    127   else
    128     prefs->SetString(name.c_str(), value);
    129   prefs->ScheduleSavePersistentPrefs();
    130 }
    131 
    132 bool GetUserWhitelist(ListValue* user_list) {
    133   PrefService* prefs = g_browser_process->local_state();
    134   DCHECK(!prefs->IsManagedPreference(kAccountsPrefUsers));
    135 
    136   std::vector<std::string> whitelist;
    137   if (!SignedSettings::EnumerateWhitelist(&whitelist)) {
    138     LOG(WARNING) << "Failed to retrieve user whitelist.";
    139     return false;
    140   }
    141 
    142   ListPrefUpdate cached_whitelist_update(prefs, kAccountsPrefUsers);
    143   cached_whitelist_update->Clear();
    144 
    145   const UserManager::User& self = UserManager::Get()->logged_in_user();
    146   bool is_owner = UserManager::Get()->current_user_is_owner();
    147 
    148   for (size_t i = 0; i < whitelist.size(); ++i) {
    149     const std::string& email = whitelist[i];
    150 
    151     if (user_list) {
    152       DictionaryValue* user = new DictionaryValue;
    153       user->SetString("email", email);
    154       user->SetString("name", "");
    155       user->SetBoolean("owner", is_owner && email == self.email());
    156       user_list->Append(user);
    157     }
    158 
    159     cached_whitelist_update->Append(Value::CreateStringValue(email));
    160   }
    161 
    162   prefs->ScheduleSavePersistentPrefs();
    163   return true;
    164 }
    165 
    166 class UserCrosSettingsTrust : public SignedSettingsHelper::Callback {
    167  public:
    168   static UserCrosSettingsTrust* GetInstance() {
    169     return Singleton<UserCrosSettingsTrust>::get();
    170   }
    171 
    172   // Working horse for UserCrosSettingsProvider::RequestTrusted* family.
    173   bool RequestTrustedEntity(const std::string& name) {
    174     OwnershipService::Status ownership_status =
    175         ownership_service_->GetStatus(false);
    176     if (ownership_status == OwnershipService::OWNERSHIP_NONE)
    177       return true;
    178     PrefService* prefs = g_browser_process->local_state();
    179     if (prefs->IsManagedPreference(name.c_str()))
    180       return true;
    181     if (ownership_status == OwnershipService::OWNERSHIP_TAKEN) {
    182       DCHECK(g_browser_process);
    183       PrefService* prefs = g_browser_process->local_state();
    184       DCHECK(prefs);
    185       if (prefs->GetBoolean((name + kTrustedSuffix).c_str()))
    186         return true;
    187     }
    188     return false;
    189   }
    190 
    191   bool RequestTrustedEntity(const std::string& name, Task* callback) {
    192     if (RequestTrustedEntity(name)) {
    193       delete callback;
    194       return true;
    195     } else {
    196       if (callback)
    197         callbacks_[name].push_back(callback);
    198       return false;
    199     }
    200   }
    201 
    202   void Reload() {
    203     for (size_t i = 0; i < arraysize(kBooleanSettings); ++i)
    204       StartFetchingSetting(kBooleanSettings[i]);
    205     for (size_t i = 0; i < arraysize(kStringSettings); ++i)
    206       StartFetchingSetting(kStringSettings[i]);
    207   }
    208 
    209   void Set(const std::string& path, Value* in_value) {
    210     PrefService* prefs = g_browser_process->local_state();
    211     DCHECK(!prefs->IsManagedPreference(path.c_str()));
    212 
    213     if (!UserManager::Get()->current_user_is_owner()) {
    214       LOG(WARNING) << "Changing settings from non-owner, setting=" << path;
    215 
    216       // Revert UI change.
    217       CrosSettings::Get()->FireObservers(path.c_str());
    218       return;
    219     }
    220 
    221     if (IsControlledBooleanSetting(path)) {
    222       bool bool_value = false;
    223       if (in_value->GetAsBoolean(&bool_value)) {
    224         OnBooleanPropertyChange(path, bool_value);
    225         std::string value = bool_value ? kTrueIncantation : kFalseIncantation;
    226         SignedSettingsHelper::Get()->StartStorePropertyOp(path, value, this);
    227         UpdateCacheBool(path, bool_value, USE_VALUE_SUPPLIED);
    228 
    229         VLOG(1) << "Set cros setting " << path << "=" << value;
    230       }
    231     } else if (path == kDeviceOwner) {
    232       VLOG(1) << "Setting owner is not supported. Please use "
    233                  "'UpdateCachedOwner' instead.";
    234     } else if (path == kAccountsPrefUsers) {
    235       VLOG(1) << "Setting user whitelist is not implemented.  Please use "
    236                  "whitelist/unwhitelist instead.";
    237     } else {
    238       LOG(WARNING) << "Try to set unhandled cros setting " << path;
    239     }
    240   }
    241 
    242  private:
    243   // upper bound for number of retries to fetch a signed setting.
    244   static const int kNumRetriesLimit = 9;
    245 
    246   UserCrosSettingsTrust()
    247       : ownership_service_(OwnershipService::GetSharedInstance()),
    248         retries_left_(kNumRetriesLimit) {
    249     // Start prefetching Boolean and String preferences.
    250     Reload();
    251   }
    252 
    253   ~UserCrosSettingsTrust() {
    254     if (BrowserThread::CurrentlyOn(BrowserThread::UI) &&
    255         CrosLibrary::Get()->EnsureLoaded()) {
    256       // Cancels all pending callbacks from us.
    257       SignedSettingsHelper::Get()->CancelCallback(this);
    258     }
    259   }
    260 
    261   // Called right before boolean property is changed.
    262   void OnBooleanPropertyChange(const std::string& path, bool new_value) {
    263     if (path == kSignedDataRoamingEnabled) {
    264       if (!CrosLibrary::Get()->EnsureLoaded())
    265         return;
    266 
    267       NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary();
    268       cros->SetCellularDataRoamingAllowed(new_value);
    269     }
    270   }
    271 
    272   // Called right after signed value was checked.
    273   void OnBooleanPropertyRetrieve(const std::string& path,
    274                                  bool value,
    275                                  UseValue use_value) {
    276     if (path == kSignedDataRoamingEnabled) {
    277       if (!CrosLibrary::Get()->EnsureLoaded())
    278         return;
    279 
    280       NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary();
    281       const NetworkDevice* cellular = cros->FindCellularDevice();
    282       if (cellular) {
    283         bool device_value = cellular->data_roaming_allowed();
    284         bool new_value = (use_value == USE_VALUE_SUPPLIED) ? value : false;
    285         if (device_value != new_value)
    286           cros->SetCellularDataRoamingAllowed(new_value);
    287       }
    288     }
    289   }
    290 
    291   void StartFetchingSetting(const std::string& name) {
    292     DCHECK(g_browser_process);
    293     PrefService* prefs = g_browser_process->local_state();
    294     if (!prefs)
    295       return;
    296     // Do not trust before fetching complete.
    297     prefs->ClearPref((name + kTrustedSuffix).c_str());
    298     prefs->ScheduleSavePersistentPrefs();
    299     if (CrosLibrary::Get()->EnsureLoaded()) {
    300       SignedSettingsHelper::Get()->StartRetrieveProperty(name, this);
    301     }
    302   }
    303 
    304   // Implementation of SignedSettingsHelper::Callback.
    305   virtual void OnRetrievePropertyCompleted(SignedSettings::ReturnCode code,
    306                                            const std::string& name,
    307                                            const std::string& value) {
    308     if (!IsControlledBooleanSetting(name) && !IsControlledStringSetting(name)) {
    309       NOTREACHED();
    310       return;
    311     }
    312 
    313     bool is_owned = ownership_service_->GetStatus(true) ==
    314         OwnershipService::OWNERSHIP_TAKEN;
    315     PrefService* prefs = g_browser_process->local_state();
    316     switch (code) {
    317       case SignedSettings::SUCCESS:
    318       case SignedSettings::NOT_FOUND:
    319       case SignedSettings::KEY_UNAVAILABLE: {
    320         bool fallback_to_default = !is_owned
    321             || (code == SignedSettings::NOT_FOUND);
    322         DCHECK(fallback_to_default || code == SignedSettings::SUCCESS);
    323         if (fallback_to_default)
    324           VLOG(1) << "Going default for cros setting " << name;
    325         else
    326           VLOG(1) << "Retrieved cros setting " << name << "=" << value;
    327         if (IsControlledBooleanSetting(name)) {
    328           OnBooleanPropertyRetrieve(name, (value == kTrueIncantation),
    329               fallback_to_default ? USE_VALUE_DEFAULT : USE_VALUE_SUPPLIED);
    330           UpdateCacheBool(name, (value == kTrueIncantation),
    331               fallback_to_default ? USE_VALUE_DEFAULT : USE_VALUE_SUPPLIED);
    332         } else if (IsControlledStringSetting(name)) {
    333           UpdateCacheString(name, value,
    334               fallback_to_default ? USE_VALUE_DEFAULT : USE_VALUE_SUPPLIED);
    335         }
    336         break;
    337       }
    338       case SignedSettings::OPERATION_FAILED:
    339       default: {
    340         DCHECK(code == SignedSettings::OPERATION_FAILED);
    341         DCHECK(is_owned);
    342         LOG(ERROR) << "On owned device: failed to retrieve cros "
    343                       "setting, name=" << name;
    344         if (retries_left_ > 0) {
    345           retries_left_ -= 1;
    346           StartFetchingSetting(name);
    347           return;
    348         }
    349         LOG(ERROR) << "No retries left";
    350         if (IsControlledBooleanSetting(name)) {
    351           // For boolean settings we can just set safe (false) values
    352           // and continue as trusted.
    353           OnBooleanPropertyRetrieve(name, false, USE_VALUE_SUPPLIED);
    354           UpdateCacheBool(name, false, USE_VALUE_SUPPLIED);
    355         } else {
    356           prefs->ClearPref((name + kTrustedSuffix).c_str());
    357           return;
    358         }
    359         break;
    360       }
    361     }
    362     prefs->SetBoolean((name + kTrustedSuffix).c_str(), true);
    363     {
    364       std::vector<Task*>& callbacks_vector = callbacks_[name];
    365       for (size_t i = 0; i < callbacks_vector.size(); ++i)
    366         MessageLoop::current()->PostTask(FROM_HERE, callbacks_vector[i]);
    367       callbacks_vector.clear();
    368     }
    369     if (code == SignedSettings::SUCCESS)
    370       CrosSettings::Get()->FireObservers(name.c_str());
    371   }
    372 
    373   // Implementation of SignedSettingsHelper::Callback.
    374   virtual void OnStorePropertyCompleted(SignedSettings::ReturnCode code,
    375                                         const std::string& name,
    376                                         const std::string& value) {
    377     VLOG(1) << "Store cros setting " << name << "=" << value << ", code="
    378             << code;
    379 
    380     // Reload the setting if store op fails.
    381     if (code != SignedSettings::SUCCESS)
    382       SignedSettingsHelper::Get()->StartRetrieveProperty(name, this);
    383   }
    384 
    385   // Implementation of SignedSettingsHelper::Callback.
    386   virtual void OnWhitelistCompleted(SignedSettings::ReturnCode code,
    387                                     const std::string& email) {
    388     VLOG(1) << "Add " << email << " to whitelist, code=" << code;
    389 
    390     // Reload the whitelist on settings op failure.
    391     if (code != SignedSettings::SUCCESS)
    392       CrosSettings::Get()->FireObservers(kAccountsPrefUsers);
    393   }
    394 
    395   // Implementation of SignedSettingsHelper::Callback.
    396   virtual void OnUnwhitelistCompleted(SignedSettings::ReturnCode code,
    397                                       const std::string& email) {
    398     VLOG(1) << "Remove " << email << " from whitelist, code=" << code;
    399 
    400     // Reload the whitelist on settings op failure.
    401     if (code != SignedSettings::SUCCESS)
    402       CrosSettings::Get()->FireObservers(kAccountsPrefUsers);
    403   }
    404 
    405   // Pending callbacks that need to be invoked after settings verification.
    406   base::hash_map< std::string, std::vector< Task* > > callbacks_;
    407 
    408   OwnershipService* ownership_service_;
    409 
    410   // In order to guard against occasional failure to fetch a property
    411   // we allow for some number of retries.
    412   int retries_left_;
    413 
    414   friend class SignedSettingsHelper;
    415   friend struct DefaultSingletonTraits<UserCrosSettingsTrust>;
    416 
    417   DISALLOW_COPY_AND_ASSIGN(UserCrosSettingsTrust);
    418 };
    419 
    420 }  // namespace
    421 
    422 }  // namespace chromeos
    423 
    424 // We want to use NewRunnableMethod with this class but need to disable
    425 // reference counting since it is singleton.
    426 DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::UserCrosSettingsTrust);
    427 
    428 namespace chromeos {
    429 
    430 UserCrosSettingsProvider::UserCrosSettingsProvider() {
    431   // Trigger prefetching of settings.
    432   UserCrosSettingsTrust::GetInstance();
    433 }
    434 
    435 // static
    436 void UserCrosSettingsProvider::RegisterPrefs(PrefService* local_state) {
    437   for (size_t i = 0; i < arraysize(kBooleanSettings); ++i)
    438     RegisterSetting(local_state, kBooleanSettings[i]);
    439   for (size_t i = 0; i < arraysize(kStringSettings); ++i)
    440     RegisterSetting(local_state, kStringSettings[i]);
    441   for (size_t i = 0; i < arraysize(kListSettings); ++i)
    442     RegisterSetting(local_state, kListSettings[i]);
    443 }
    444 
    445 bool UserCrosSettingsProvider::RequestTrustedAllowGuest(Task* callback) {
    446   return UserCrosSettingsTrust::GetInstance()->RequestTrustedEntity(
    447       kAccountsPrefAllowGuest, callback);
    448 }
    449 
    450 bool UserCrosSettingsProvider::RequestTrustedAllowNewUser(Task* callback) {
    451   return UserCrosSettingsTrust::GetInstance()->RequestTrustedEntity(
    452       kAccountsPrefAllowNewUser, callback);
    453 }
    454 
    455 bool UserCrosSettingsProvider::RequestTrustedShowUsersOnSignin(Task* callback) {
    456   return UserCrosSettingsTrust::GetInstance()->RequestTrustedEntity(
    457       kAccountsPrefShowUserNamesOnSignIn, callback);
    458 }
    459 
    460 bool UserCrosSettingsProvider::RequestTrustedDataRoamingEnabled(
    461     Task* callback) {
    462   return UserCrosSettingsTrust::GetInstance()->RequestTrustedEntity(
    463       kSignedDataRoamingEnabled, callback);
    464 }
    465 
    466 bool UserCrosSettingsProvider::RequestTrustedOwner(Task* callback) {
    467   return UserCrosSettingsTrust::GetInstance()->RequestTrustedEntity(
    468       kDeviceOwner, callback);
    469 }
    470 
    471 void UserCrosSettingsProvider::Reload() {
    472   UserCrosSettingsTrust::GetInstance()->Reload();
    473 }
    474 
    475 // static
    476 bool UserCrosSettingsProvider::cached_allow_guest() {
    477   // Trigger prefetching if singleton object still does not exist.
    478   UserCrosSettingsTrust::GetInstance();
    479   return g_browser_process->local_state()->GetBoolean(kAccountsPrefAllowGuest);
    480 }
    481 
    482 // static
    483 bool UserCrosSettingsProvider::cached_allow_new_user() {
    484   // Trigger prefetching if singleton object still does not exist.
    485   UserCrosSettingsTrust::GetInstance();
    486   return g_browser_process->local_state()->GetBoolean(
    487       kAccountsPrefAllowNewUser);
    488 }
    489 
    490 // static
    491 bool UserCrosSettingsProvider::cached_data_roaming_enabled() {
    492   // Trigger prefetching if singleton object still does not exist.
    493   UserCrosSettingsTrust::GetInstance();
    494   return g_browser_process->local_state()->GetBoolean(
    495       kSignedDataRoamingEnabled);
    496 }
    497 
    498 // static
    499 bool UserCrosSettingsProvider::cached_show_users_on_signin() {
    500   // Trigger prefetching if singleton object still does not exist.
    501   UserCrosSettingsTrust::GetInstance();
    502   return g_browser_process->local_state()->GetBoolean(
    503       kAccountsPrefShowUserNamesOnSignIn);
    504 }
    505 
    506 // static
    507 const ListValue* UserCrosSettingsProvider::cached_whitelist() {
    508   PrefService* prefs = g_browser_process->local_state();
    509   const ListValue* cached_users = prefs->GetList(kAccountsPrefUsers);
    510   if (!prefs->IsManagedPreference(kAccountsPrefUsers)) {
    511     if (cached_users == NULL) {
    512       // Update whitelist cache.
    513       GetUserWhitelist(NULL);
    514       cached_users = prefs->GetList(kAccountsPrefUsers);
    515     }
    516   }
    517   if (cached_users == NULL) {
    518     NOTREACHED();
    519     cached_users = new ListValue;
    520   }
    521   return cached_users;
    522 }
    523 
    524 // static
    525 std::string UserCrosSettingsProvider::cached_owner() {
    526   // Trigger prefetching if singleton object still does not exist.
    527   UserCrosSettingsTrust::GetInstance();
    528   if (!g_browser_process || !g_browser_process->local_state())
    529     return std::string();
    530   return g_browser_process->local_state()->GetString(kDeviceOwner);
    531 }
    532 
    533 // static
    534 bool UserCrosSettingsProvider::IsEmailInCachedWhitelist(
    535     const std::string& email) {
    536   const ListValue* whitelist = cached_whitelist();
    537   if (whitelist) {
    538     StringValue email_value(email);
    539     for (ListValue::const_iterator i(whitelist->begin());
    540         i != whitelist->end(); ++i) {
    541       if ((*i)->Equals(&email_value))
    542         return true;
    543     }
    544   }
    545   return false;
    546 }
    547 
    548 void UserCrosSettingsProvider::DoSet(const std::string& path,
    549                                      Value* in_value) {
    550   UserCrosSettingsTrust::GetInstance()->Set(path, in_value);
    551 }
    552 
    553 bool UserCrosSettingsProvider::Get(const std::string& path,
    554                                    Value** out_value) const {
    555   if (IsControlledBooleanSetting(path)) {
    556     PrefService* prefs = g_browser_process->local_state();
    557     *out_value = CreateSettingsBooleanValue(
    558         prefs->GetBoolean(path.c_str()),
    559         prefs->IsManagedPreference(path.c_str()),
    560         !UserManager::Get()->current_user_is_owner());
    561     return true;
    562   } else if (path == kAccountsPrefUsers) {
    563     ListValue* user_list = new ListValue;
    564     GetUserWhitelist(user_list);
    565     *out_value = user_list;
    566     return true;
    567   }
    568 
    569   return false;
    570 }
    571 
    572 bool UserCrosSettingsProvider::HandlesSetting(const std::string& path) {
    573   return ::StartsWithASCII(path, "cros.accounts.", true) ||
    574       ::StartsWithASCII(path, "cros.signed.", true);
    575 }
    576 
    577 void UserCrosSettingsProvider::WhitelistUser(const std::string& email) {
    578   SignedSettingsHelper::Get()->StartWhitelistOp(
    579       email, true, UserCrosSettingsTrust::GetInstance());
    580   PrefService* prefs = g_browser_process->local_state();
    581   ListPrefUpdate cached_whitelist_update(prefs, kAccountsPrefUsers);
    582   cached_whitelist_update->Append(Value::CreateStringValue(email));
    583   prefs->ScheduleSavePersistentPrefs();
    584 }
    585 
    586 void UserCrosSettingsProvider::UnwhitelistUser(const std::string& email) {
    587   SignedSettingsHelper::Get()->StartWhitelistOp(
    588       email, false, UserCrosSettingsTrust::GetInstance());
    589 
    590   PrefService* prefs = g_browser_process->local_state();
    591   ListPrefUpdate cached_whitelist_update(prefs, kAccountsPrefUsers);
    592   StringValue email_value(email);
    593   if (cached_whitelist_update->Remove(email_value) != -1)
    594     prefs->ScheduleSavePersistentPrefs();
    595 }
    596 
    597 // static
    598 void UserCrosSettingsProvider::UpdateCachedOwner(const std::string& email) {
    599   UpdateCacheString(kDeviceOwner, email, USE_VALUE_SUPPLIED);
    600 }
    601 
    602 }  // namespace chromeos
    603