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/login/user_manager.h" 6 7 #include "base/command_line.h" 8 #include "base/compiler_specific.h" 9 #include "base/file_path.h" 10 #include "base/file_util.h" 11 #include "base/lazy_instance.h" 12 #include "base/logging.h" 13 #include "base/path_service.h" 14 #include "base/string_util.h" 15 #include "base/stringprintf.h" 16 #include "base/time.h" 17 #include "base/utf_string_conversions.h" 18 #include "base/values.h" 19 #include "crypto/nss_util.h" 20 #include "chrome/browser/browser_process.h" 21 #include "chrome/browser/chromeos/cros/cros_library.h" 22 #include "chrome/browser/chromeos/cros/cryptohome_library.h" 23 #include "chrome/browser/chromeos/cros/input_method_library.h" 24 #include "chrome/browser/chromeos/login/default_user_images.h" 25 #include "chrome/browser/chromeos/login/login_display.h" 26 #include "chrome/browser/chromeos/login/ownership_service.h" 27 #include "chrome/browser/chromeos/user_cros_settings_provider.h" 28 #include "chrome/browser/chromeos/wm_ipc.h" 29 #include "chrome/browser/defaults.h" 30 #include "chrome/browser/prefs/pref_service.h" 31 #include "chrome/browser/prefs/scoped_user_pref_update.h" 32 #include "chrome/common/chrome_paths.h" 33 #include "chrome/common/chrome_switches.h" 34 #include "content/browser/browser_thread.h" 35 #include "content/common/notification_service.h" 36 #include "content/common/notification_type.h" 37 #include "ui/base/resource/resource_bundle.h" 38 #include "ui/gfx/codec/png_codec.h" 39 40 namespace chromeos { 41 42 namespace { 43 44 // A vector pref of the users who have logged into the device. 45 const char kLoggedInUsers[] = "LoggedInUsers"; 46 // A dictionary that maps usernames to file paths to their images. 47 const char kUserImages[] = "UserImages"; 48 49 // Incognito user is represented by an empty string (since some code already 50 // depends on that and it's hard to figure out what). 51 const char kGuestUser[] = ""; 52 53 base::LazyInstance<UserManager> g_user_manager(base::LINKER_INITIALIZED); 54 55 // Stores path to the image in local state. Runs on UI thread. 56 void SavePathToLocalState(const std::string& username, 57 const std::string& image_path) { 58 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 59 PrefService* local_state = g_browser_process->local_state(); 60 DictionaryPrefUpdate images_update(local_state, kUserImages); 61 images_update->SetWithoutPathExpansion(username, new StringValue(image_path)); 62 DVLOG(1) << "Saving path to user image in Local State."; 63 local_state->SavePersistentPrefs(); 64 } 65 66 // Saves image to file with specified path. Runs on FILE thread. 67 // Posts task for saving image path to local state on UI thread. 68 void SaveImageToFile(const SkBitmap& image, 69 const FilePath& image_path, 70 const std::string& username) { 71 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 72 std::vector<unsigned char> encoded_image; 73 if (!gfx::PNGCodec::EncodeBGRASkBitmap(image, true, &encoded_image)) { 74 LOG(ERROR) << "Failed to PNG encode the image."; 75 return; 76 } 77 78 if (file_util::WriteFile(image_path, 79 reinterpret_cast<char*>(&encoded_image[0]), 80 encoded_image.size()) == -1) { 81 LOG(ERROR) << "Failed to save image to file."; 82 return; 83 } 84 85 BrowserThread::PostTask( 86 BrowserThread::UI, 87 FROM_HERE, 88 NewRunnableFunction(&SavePathToLocalState, 89 username, image_path.value())); 90 } 91 92 // Deletes user's image file. Runs on FILE thread. 93 void DeleteUserImage(const FilePath& image_path) { 94 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 95 if (!file_util::Delete(image_path, false)) { 96 LOG(ERROR) << "Failed to remove user image."; 97 return; 98 } 99 } 100 101 // Updates current user ownership on UI thread. 102 void UpdateOwnership(bool is_owner) { 103 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 104 105 g_user_manager.Get().set_current_user_is_owner(is_owner); 106 NotificationService::current()->Notify(NotificationType::OWNERSHIP_CHECKED, 107 NotificationService::AllSources(), 108 NotificationService::NoDetails()); 109 if (is_owner) { 110 // Also update cached value. 111 UserCrosSettingsProvider::UpdateCachedOwner( 112 g_user_manager.Get().logged_in_user().email()); 113 } 114 } 115 116 // Checks current user's ownership on file thread. 117 void CheckOwnership() { 118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 119 bool is_owner = OwnershipService::GetSharedInstance()->CurrentUserIsOwner(); 120 VLOG(1) << "Current user " << (is_owner ? "is owner" : "is not owner"); 121 122 g_user_manager.Get().set_current_user_is_owner(is_owner); 123 124 // UserManager should be accessed only on UI thread. 125 BrowserThread::PostTask( 126 BrowserThread::UI, 127 FROM_HERE, 128 NewRunnableFunction(&UpdateOwnership, is_owner)); 129 } 130 131 // Used to handle the asynchronous response of deleting a cryptohome directory. 132 class RemoveAttempt : public CryptohomeLibrary::Delegate { 133 public: 134 // Creates new remove attempt for the given user. Note, |delegate| can 135 // be NULL. 136 RemoveAttempt(const std::string& user_email, 137 chromeos::RemoveUserDelegate* delegate) 138 : user_email_(user_email), 139 delegate_(delegate), 140 method_factory_(this) { 141 RemoveUser(); 142 } 143 144 void RemoveUser() { 145 // Owner is not allowed to be removed from the device. 146 // Must not proceed without signature verification. 147 UserCrosSettingsProvider user_settings; 148 bool trusted_owner_available = user_settings.RequestTrustedOwner( 149 method_factory_.NewRunnableMethod(&RemoveAttempt::RemoveUser)); 150 if (!trusted_owner_available) { 151 // Value of owner email is still not verified. 152 // Another attempt will be invoked after verification completion. 153 return; 154 } 155 if (user_email_ == UserCrosSettingsProvider::cached_owner()) { 156 // Owner is not allowed to be removed from the device. Probably on 157 // the stack, so deffer the deletion. 158 MessageLoop::current()->DeleteSoon(FROM_HERE, this); 159 return; 160 } 161 162 if (delegate_) 163 delegate_->OnBeforeUserRemoved(user_email_); 164 165 chromeos::UserManager::Get()->RemoveUserFromList(user_email_); 166 RemoveUserCryptohome(); 167 168 if (delegate_) 169 delegate_->OnUserRemoved(user_email_); 170 } 171 172 void RemoveUserCryptohome() { 173 if (CrosLibrary::Get()->EnsureLoaded()) { 174 CrosLibrary::Get()->GetCryptohomeLibrary()->AsyncRemove(user_email_, 175 this); 176 } 177 } 178 179 void OnComplete(bool success, int return_code) { 180 // Log the error, but there's not much we can do. 181 if (!success) { 182 VLOG(1) << "Removal of cryptohome for " << user_email_ 183 << " failed, return code: " << return_code; 184 } 185 delete this; 186 } 187 188 private: 189 std::string user_email_; 190 chromeos::RemoveUserDelegate* delegate_; 191 192 // Factory of callbacks. 193 ScopedRunnableMethodFactory<RemoveAttempt> method_factory_; 194 195 DISALLOW_COPY_AND_ASSIGN(RemoveAttempt); 196 }; 197 198 } // namespace 199 200 UserManager::User::User() { 201 image_ = *ResourceBundle::GetSharedInstance().GetBitmapNamed( 202 kDefaultImageResources[0]); 203 } 204 205 UserManager::User::~User() {} 206 207 std::string UserManager::User::GetDisplayName() const { 208 size_t i = email_.find('@'); 209 if (i == 0 || i == std::string::npos) { 210 return email_; 211 } 212 return email_.substr(0, i); 213 } 214 215 std::string UserManager::User::GetNameTooltip() const { 216 const std::string& user_email = email(); 217 size_t at_pos = user_email.rfind('@'); 218 if (at_pos == std::string::npos) { 219 NOTREACHED(); 220 return std::string(); 221 } 222 size_t domain_start = at_pos + 1; 223 std::string domain = user_email.substr(domain_start, 224 user_email.length() - domain_start); 225 return base::StringPrintf("%s (%s)", 226 GetDisplayName().c_str(), 227 domain.c_str()); 228 } 229 230 // static 231 UserManager* UserManager::Get() { 232 // Not thread-safe. 233 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 234 return &g_user_manager.Get(); 235 } 236 237 // static 238 void UserManager::RegisterPrefs(PrefService* local_state) { 239 local_state->RegisterListPref(kLoggedInUsers); 240 local_state->RegisterDictionaryPref(kUserImages); 241 } 242 243 std::vector<UserManager::User> UserManager::GetUsers() const { 244 std::vector<User> users; 245 if (!g_browser_process) 246 return users; 247 248 PrefService* local_state = g_browser_process->local_state(); 249 const ListValue* prefs_users = local_state->GetList(kLoggedInUsers); 250 const DictionaryValue* prefs_images = local_state->GetDictionary(kUserImages); 251 252 if (prefs_users) { 253 for (ListValue::const_iterator it = prefs_users->begin(); 254 it != prefs_users->end(); 255 ++it) { 256 std::string email; 257 if ((*it)->GetAsString(&email)) { 258 User user; 259 user.set_email(email); 260 UserImages::const_iterator image_it = user_images_.find(email); 261 std::string image_path; 262 if (image_it == user_images_.end()) { 263 if (prefs_images && 264 prefs_images->GetStringWithoutPathExpansion(email, &image_path)) { 265 int default_image_id = kDefaultImagesCount; 266 if (IsDefaultImagePath(image_path, &default_image_id)) { 267 DCHECK(default_image_id < kDefaultImagesCount); 268 int resource_id = kDefaultImageResources[default_image_id]; 269 user.set_image( 270 *ResourceBundle::GetSharedInstance().GetBitmapNamed( 271 resource_id)); 272 user_images_[email] = user.image(); 273 } else { 274 // Insert the default image so we don't send another request if 275 // GetUsers is called twice. 276 user_images_[email] = user.image(); 277 image_loader_->Start(email, image_path, false); 278 } 279 } 280 } else { 281 user.set_image(image_it->second); 282 } 283 users.push_back(user); 284 } 285 } 286 } 287 return users; 288 } 289 290 void UserManager::OffTheRecordUserLoggedIn() { 291 user_is_logged_in_ = true; 292 logged_in_user_ = User(); 293 logged_in_user_.set_email(kGuestUser); 294 NotifyOnLogin(); 295 } 296 297 void UserManager::UserLoggedIn(const std::string& email) { 298 if (email == kGuestUser) { 299 OffTheRecordUserLoggedIn(); 300 return; 301 } 302 303 if (!IsKnownUser(email)) { 304 current_user_is_new_ = true; 305 browser_defaults::skip_restore = true; 306 } 307 308 // Get a copy of the current users. 309 std::vector<User> users = GetUsers(); 310 311 // Clear the prefs view of the users. 312 PrefService* prefs = g_browser_process->local_state(); 313 ListPrefUpdate prefs_users_update(prefs, kLoggedInUsers); 314 prefs_users_update->Clear(); 315 316 user_is_logged_in_ = true; 317 logged_in_user_ = User(); 318 logged_in_user_.set_email(email); 319 320 // Make sure this user is first. 321 prefs_users_update->Append(Value::CreateStringValue(email)); 322 for (std::vector<User>::iterator it = users.begin(); 323 it != users.end(); 324 ++it) { 325 std::string user_email = it->email(); 326 // Skip the most recent user. 327 if (email != user_email) { 328 prefs_users_update->Append(Value::CreateStringValue(user_email)); 329 } else { 330 logged_in_user_ = *it; 331 } 332 } 333 prefs->SavePersistentPrefs(); 334 NotifyOnLogin(); 335 if (current_user_is_new_) 336 SetDefaultUserImage(email); 337 } 338 339 void UserManager::RemoveUser(const std::string& email, 340 RemoveUserDelegate* delegate) { 341 // Get a copy of the current users. 342 std::vector<User> users = GetUsers(); 343 344 // Sanity check: we must not remove single user. This check may seem 345 // redundant at a first sight because this single user must be an owner and 346 // we perform special check later in order not to remove an owner. However 347 // due to non-instant nature of ownership assignment this later check may 348 // sometimes fail. See http://crosbug.com/12723 349 if (users.size() < 2) 350 return; 351 352 bool user_found = false; 353 for (size_t i = 0; !user_found && i < users.size(); ++i) 354 user_found = (email == users[i].email()); 355 if (!user_found) 356 return; 357 358 // |RemoveAttempt| deletes itself when done. 359 new RemoveAttempt(email, delegate); 360 } 361 362 void UserManager::RemoveUserFromList(const std::string& email) { 363 // Get a copy of the current users. 364 std::vector<User> users = GetUsers(); 365 366 // Clear the prefs view of the users. 367 PrefService* prefs = g_browser_process->local_state(); 368 ListPrefUpdate prefs_users_update(prefs, kLoggedInUsers); 369 prefs_users_update->Clear(); 370 371 for (std::vector<User>::iterator it = users.begin(); 372 it != users.end(); 373 ++it) { 374 std::string user_email = it->email(); 375 // Skip user that we would like to delete. 376 if (email != user_email) 377 prefs_users_update->Append(Value::CreateStringValue(user_email)); 378 } 379 380 DictionaryPrefUpdate prefs_images_update(prefs, kUserImages); 381 std::string image_path_string; 382 prefs_images_update->GetStringWithoutPathExpansion(email, &image_path_string); 383 prefs_images_update->RemoveWithoutPathExpansion(email, NULL); 384 385 prefs->SavePersistentPrefs(); 386 387 int default_image_id = kDefaultImagesCount; 388 if (!IsDefaultImagePath(image_path_string, &default_image_id)) { 389 FilePath image_path(image_path_string); 390 BrowserThread::PostTask( 391 BrowserThread::FILE, 392 FROM_HERE, 393 NewRunnableFunction(&DeleteUserImage, 394 image_path)); 395 } 396 } 397 398 bool UserManager::IsKnownUser(const std::string& email) { 399 std::vector<User> users = GetUsers(); 400 for (std::vector<User>::iterator it = users.begin(); 401 it < users.end(); 402 ++it) { 403 if (it->email() == email) 404 return true; 405 } 406 407 return false; 408 } 409 410 const UserManager::User& UserManager::logged_in_user() const { 411 return logged_in_user_; 412 } 413 414 void UserManager::SetLoggedInUserImage(const SkBitmap& image) { 415 if (logged_in_user_.email().empty()) 416 return; 417 OnImageLoaded(logged_in_user_.email(), image, false); 418 } 419 420 void UserManager::LoadLoggedInUserImage(const FilePath& path) { 421 if (logged_in_user_.email().empty()) 422 return; 423 image_loader_->Start(logged_in_user_.email(), path.value(), true); 424 } 425 426 void UserManager::SaveUserImage(const std::string& username, 427 const SkBitmap& image) { 428 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 429 FilePath image_path = GetImagePathForUser(username); 430 DVLOG(1) << "Saving user image to " << image_path.value(); 431 432 BrowserThread::PostTask( 433 BrowserThread::FILE, 434 FROM_HERE, 435 NewRunnableFunction(&SaveImageToFile, 436 image, image_path, username)); 437 } 438 439 void UserManager::SaveUserImagePath(const std::string& username, 440 const std::string& image_path) { 441 SavePathToLocalState(username, image_path); 442 } 443 444 void UserManager::SetDefaultUserImage(const std::string& username) { 445 if (!g_browser_process) 446 return; 447 448 PrefService* local_state = g_browser_process->local_state(); 449 DCHECK(local_state); 450 const ListValue* prefs_users = local_state->GetList(kLoggedInUsers); 451 DCHECK(prefs_users); 452 const DictionaryValue* prefs_images = 453 local_state->GetDictionary(kUserImages); 454 DCHECK(prefs_images); 455 456 // We want to distribute default images between users uniformly so that if 457 // there're more users with red image, we won't add red one for sure. 458 // Thus we count how many default images of each color are used and choose 459 // the first color with minimal usage. 460 std::vector<int> colors_count(kDefaultImagesCount, 0); 461 for (ListValue::const_iterator it = prefs_users->begin(); 462 it != prefs_users->end(); 463 ++it) { 464 std::string email; 465 if ((*it)->GetAsString(&email)) { 466 std::string image_path; 467 int default_image_id = kDefaultImagesCount; 468 if (prefs_images->GetStringWithoutPathExpansion(email, &image_path) && 469 IsDefaultImagePath(image_path, &default_image_id)) { 470 DCHECK(default_image_id < kDefaultImagesCount); 471 ++colors_count[default_image_id]; 472 } 473 } 474 } 475 std::vector<int>::const_iterator min_it = 476 std::min_element(colors_count.begin(), colors_count.end()); 477 int selected_id = min_it - colors_count.begin(); 478 std::string user_image_path = 479 GetDefaultImagePath(selected_id); 480 int resource_id = kDefaultImageResources[selected_id]; 481 SkBitmap user_image = *ResourceBundle::GetSharedInstance().GetBitmapNamed( 482 resource_id); 483 484 SavePathToLocalState(username, user_image_path); 485 SetLoggedInUserImage(user_image); 486 } 487 488 int UserManager::GetUserDefaultImageIndex(const std::string& username) { 489 if (!g_browser_process) 490 return -1; 491 492 PrefService* local_state = g_browser_process->local_state(); 493 const DictionaryValue* prefs_images = local_state->GetDictionary(kUserImages); 494 495 if (!prefs_images) 496 return -1; 497 498 std::string image_path; 499 if (!prefs_images->GetStringWithoutPathExpansion(username, &image_path)) 500 return -1; 501 502 int image_id = kDefaultImagesCount; 503 if (!IsDefaultImagePath(image_path, &image_id)) 504 return -1; 505 return image_id; 506 } 507 508 void UserManager::OnImageLoaded(const std::string& username, 509 const SkBitmap& image, 510 bool should_save_image) { 511 DVLOG(1) << "Loaded image for " << username; 512 user_images_[username] = image; 513 User user; 514 user.set_email(username); 515 user.set_image(image); 516 if (logged_in_user_.email() == username) 517 logged_in_user_.set_image(image); 518 if (should_save_image) 519 SaveUserImage(username, image); 520 NotificationService::current()->Notify( 521 NotificationType::LOGIN_USER_IMAGE_CHANGED, 522 Source<UserManager>(this), 523 Details<const User>(&user)); 524 } 525 526 bool UserManager::IsLoggedInAsGuest() const { 527 return logged_in_user().email() == kGuestUser; 528 } 529 530 // Private constructor and destructor. Do nothing. 531 UserManager::UserManager() 532 : ALLOW_THIS_IN_INITIALIZER_LIST(image_loader_(new UserImageLoader(this))), 533 current_user_is_owner_(false), 534 current_user_is_new_(false), 535 user_is_logged_in_(false) { 536 registrar_.Add(this, NotificationType::OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED, 537 NotificationService::AllSources()); 538 } 539 540 UserManager::~UserManager() { 541 image_loader_->set_delegate(NULL); 542 } 543 544 FilePath UserManager::GetImagePathForUser(const std::string& username) { 545 std::string filename = username + ".png"; 546 FilePath user_data_dir; 547 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); 548 return user_data_dir.AppendASCII(filename); 549 } 550 551 class RealTPMTokenInfoDelegate : public crypto::TPMTokenInfoDelegate { 552 public: 553 RealTPMTokenInfoDelegate(); 554 virtual ~RealTPMTokenInfoDelegate(); 555 virtual bool IsTokenReady() const; 556 virtual void GetTokenInfo(std::string* token_name, 557 std::string* user_pin) const; 558 }; 559 560 RealTPMTokenInfoDelegate::RealTPMTokenInfoDelegate() {} 561 RealTPMTokenInfoDelegate::~RealTPMTokenInfoDelegate() {} 562 563 bool RealTPMTokenInfoDelegate::IsTokenReady() const { 564 return CrosLibrary::Get()->GetCryptohomeLibrary()->Pkcs11IsTpmTokenReady(); 565 } 566 567 void RealTPMTokenInfoDelegate::GetTokenInfo(std::string* token_name, 568 std::string* user_pin) const { 569 std::string local_token_name; 570 std::string local_user_pin; 571 CrosLibrary::Get()->GetCryptohomeLibrary()->Pkcs11GetTpmTokenInfo( 572 &local_token_name, &local_user_pin); 573 if (token_name) 574 *token_name = local_token_name; 575 if (user_pin) 576 *user_pin = local_user_pin; 577 } 578 579 void UserManager::NotifyOnLogin() { 580 NotificationService::current()->Notify( 581 NotificationType::LOGIN_USER_CHANGED, 582 Source<UserManager>(this), 583 Details<const User>(&logged_in_user_)); 584 585 chromeos::CrosLibrary::Get()->GetInputMethodLibrary()-> 586 SetDeferImeStartup(false); 587 // Shut down the IME so that it will reload the user's settings. 588 chromeos::CrosLibrary::Get()->GetInputMethodLibrary()-> 589 StopInputMethodDaemon(); 590 // Let the window manager know that we're logged in now. 591 WmIpc::instance()->SetLoggedInProperty(true); 592 // Ensure we've opened the real user's key/certificate database. 593 crypto::OpenPersistentNSSDB(); 594 595 // Only load the Opencryptoki library into NSS if we have this switch. 596 // TODO(gspencer): Remove this switch once cryptohomed work is finished: 597 // http://crosbug.com/12295 and http://crosbug.com/12304 598 if (CommandLine::ForCurrentProcess()->HasSwitch( 599 switches::kLoadOpencryptoki)) { 600 crypto::EnableTPMTokenForNSS(new RealTPMTokenInfoDelegate()); 601 } 602 603 // Schedules current user ownership check on file thread. 604 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 605 NewRunnableFunction(&CheckOwnership)); 606 } 607 608 void UserManager::Observe(NotificationType type, 609 const NotificationSource& source, 610 const NotificationDetails& details) { 611 if (type == NotificationType::OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED) { 612 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 613 NewRunnableFunction(&CheckOwnership)); 614 } 615 } 616 617 bool UserManager::current_user_is_owner() const { 618 base::AutoLock lk(current_user_is_owner_lock_); 619 return current_user_is_owner_; 620 } 621 622 void UserManager::set_current_user_is_owner(bool current_user_is_owner) { 623 base::AutoLock lk(current_user_is_owner_lock_); 624 current_user_is_owner_ = current_user_is_owner; 625 } 626 627 } // namespace chromeos 628