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
28namespace chromeos {
29
30namespace {
31
32const char kTrueIncantation[] = "true";
33const char kFalseIncantation[] = "false";
34const 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.
39const char* kBooleanSettings[] = {
40  kAccountsPrefAllowNewUser,
41  kAccountsPrefAllowGuest,
42  kAccountsPrefShowUserNamesOnSignIn,
43  kSignedDataRoamingEnabled,
44};
45
46const char* kStringSettings[] = {
47  kDeviceOwner
48};
49
50const char* kListSettings[] = {
51  kAccountsPrefUsers
52};
53
54bool 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
64bool IsControlledStringSetting(const std::string& pref_path) {
65  return std::find(kStringSettings,
66                   kStringSettings + arraysize(kStringSettings),
67                   pref_path) !=
68      kStringSettings + arraysize(kStringSettings);
69}
70
71bool IsControlledListSetting(const std::string& pref_path) {
72  return std::find(kListSettings,
73                   kListSettings + arraysize(kListSettings),
74                   pref_path) !=
75      kListSettings + arraysize(kListSettings);
76}
77
78void 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.
97Value* 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
105enum UseValue {
106  USE_VALUE_SUPPLIED,
107  USE_VALUE_DEFAULT
108};
109
110void 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
121void 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
132bool 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
166class 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.
426DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::UserCrosSettingsTrust);
427
428namespace chromeos {
429
430UserCrosSettingsProvider::UserCrosSettingsProvider() {
431  // Trigger prefetching of settings.
432  UserCrosSettingsTrust::GetInstance();
433}
434
435// static
436void 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
445bool UserCrosSettingsProvider::RequestTrustedAllowGuest(Task* callback) {
446  return UserCrosSettingsTrust::GetInstance()->RequestTrustedEntity(
447      kAccountsPrefAllowGuest, callback);
448}
449
450bool UserCrosSettingsProvider::RequestTrustedAllowNewUser(Task* callback) {
451  return UserCrosSettingsTrust::GetInstance()->RequestTrustedEntity(
452      kAccountsPrefAllowNewUser, callback);
453}
454
455bool UserCrosSettingsProvider::RequestTrustedShowUsersOnSignin(Task* callback) {
456  return UserCrosSettingsTrust::GetInstance()->RequestTrustedEntity(
457      kAccountsPrefShowUserNamesOnSignIn, callback);
458}
459
460bool UserCrosSettingsProvider::RequestTrustedDataRoamingEnabled(
461    Task* callback) {
462  return UserCrosSettingsTrust::GetInstance()->RequestTrustedEntity(
463      kSignedDataRoamingEnabled, callback);
464}
465
466bool UserCrosSettingsProvider::RequestTrustedOwner(Task* callback) {
467  return UserCrosSettingsTrust::GetInstance()->RequestTrustedEntity(
468      kDeviceOwner, callback);
469}
470
471void UserCrosSettingsProvider::Reload() {
472  UserCrosSettingsTrust::GetInstance()->Reload();
473}
474
475// static
476bool 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
483bool 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
491bool 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
499bool 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
507const 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
525std::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
534bool 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
548void UserCrosSettingsProvider::DoSet(const std::string& path,
549                                     Value* in_value) {
550  UserCrosSettingsTrust::GetInstance()->Set(path, in_value);
551}
552
553bool 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
572bool UserCrosSettingsProvider::HandlesSetting(const std::string& path) {
573  return ::StartsWithASCII(path, "cros.accounts.", true) ||
574      ::StartsWithASCII(path, "cros.signed.", true);
575}
576
577void 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
586void 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
598void UserCrosSettingsProvider::UpdateCachedOwner(const std::string& email) {
599  UpdateCacheString(kDeviceOwner, email, USE_VALUE_SUPPLIED);
600}
601
602}  // namespace chromeos
603