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