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