1 // Copyright (c) 2012 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/parallel_authenticator.h" 6 7 #include "base/bind.h" 8 #include "base/command_line.h" 9 #include "base/files/file_path.h" 10 #include "base/logging.h" 11 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/string_util.h" 13 #include "chrome/browser/chrome_notification_types.h" 14 #include "chrome/browser/chromeos/boot_times_loader.h" 15 #include "chrome/browser/chromeos/cros/cert_library.h" 16 #include "chrome/browser/chromeos/login/authentication_notification_details.h" 17 #include "chrome/browser/chromeos/login/login_status_consumer.h" 18 #include "chrome/browser/chromeos/login/user.h" 19 #include "chrome/browser/chromeos/login/user_manager.h" 20 #include "chrome/browser/chromeos/settings/cros_settings.h" 21 #include "chrome/common/chrome_switches.h" 22 #include "chromeos/cryptohome/async_method_caller.h" 23 #include "chromeos/cryptohome/cryptohome_library.h" 24 #include "chromeos/dbus/cryptohome_client.h" 25 #include "chromeos/dbus/dbus_thread_manager.h" 26 #include "content/public/browser/browser_thread.h" 27 #include "content/public/browser/notification_service.h" 28 #include "crypto/sha2.h" 29 #include "google_apis/gaia/gaia_auth_util.h" 30 #include "third_party/cros_system_api/dbus/service_constants.h" 31 32 using content::BrowserThread; 33 34 namespace chromeos { 35 36 namespace { 37 38 // Length of password hashed with SHA-256. 39 const int kPasswordHashLength = 32; 40 41 // Records status and calls resolver->Resolve(). 42 void TriggerResolve(AuthAttemptState* attempt, 43 scoped_refptr<ParallelAuthenticator> resolver, 44 bool success, 45 cryptohome::MountError return_code) { 46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 47 attempt->RecordCryptohomeStatus(success, return_code); 48 resolver->Resolve(); 49 } 50 51 // Records get hash status and calls resolver->Resolve(). 52 void TriggerResolveHash(AuthAttemptState* attempt, 53 scoped_refptr<ParallelAuthenticator> resolver, 54 bool success, 55 const std::string& username_hash) { 56 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 57 attempt->RecordUsernameHash(username_hash); 58 resolver->Resolve(); 59 } 60 61 // Calls TriggerResolve while adding login time marker. 62 void TriggerResolveWithLoginTimeMarker( 63 const std::string& marker_name, 64 AuthAttemptState* attempt, 65 scoped_refptr<ParallelAuthenticator> resolver, 66 bool success, 67 cryptohome::MountError return_code) { 68 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(marker_name, false); 69 TriggerResolve(attempt, resolver, success, return_code); 70 } 71 72 // Calls cryptohome's mount method. 73 void Mount(AuthAttemptState* attempt, 74 scoped_refptr<ParallelAuthenticator> resolver, 75 int flags) { 76 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 77 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker( 78 "CryptohomeMount-Start", false); 79 // Set state that username_hash is requested here so that test implementation 80 // that returns directly would not generate 2 OnLoginSucces() calls. 81 attempt->UsernameHashRequested(); 82 cryptohome::AsyncMethodCaller::GetInstance()->AsyncMount( 83 attempt->user_context.username, 84 attempt->ascii_hash, 85 flags, 86 base::Bind(&TriggerResolveWithLoginTimeMarker, 87 "CryptohomeMount-End", 88 attempt, 89 resolver)); 90 cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername( 91 attempt->user_context.username, 92 base::Bind(&TriggerResolveHash, 93 attempt, 94 resolver)); 95 } 96 97 // Calls cryptohome's mount method for guest. 98 void MountGuest(AuthAttemptState* attempt, 99 scoped_refptr<ParallelAuthenticator> resolver) { 100 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 101 cryptohome::AsyncMethodCaller::GetInstance()->AsyncMountGuest( 102 base::Bind(&TriggerResolveWithLoginTimeMarker, 103 "CryptohomeMount-End", 104 attempt, 105 resolver)); 106 } 107 108 // Calls cryptohome's key migration method. 109 void Migrate(AuthAttemptState* attempt, 110 scoped_refptr<ParallelAuthenticator> resolver, 111 bool passing_old_hash, 112 const std::string& hash) { 113 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 114 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker( 115 "CryptohomeMigrate-Start", false); 116 cryptohome::AsyncMethodCaller* caller = 117 cryptohome::AsyncMethodCaller::GetInstance(); 118 if (passing_old_hash) { 119 caller->AsyncMigrateKey( 120 attempt->user_context.username, 121 hash, 122 attempt->ascii_hash, 123 base::Bind(&TriggerResolveWithLoginTimeMarker, 124 "CryptohomeMount-End", 125 attempt, 126 resolver)); 127 } else { 128 caller->AsyncMigrateKey( 129 attempt->user_context.username, 130 attempt->ascii_hash, 131 hash, 132 base::Bind(&TriggerResolveWithLoginTimeMarker, 133 "CryptohomeMount-End", 134 attempt, 135 resolver)); 136 } 137 } 138 139 // Calls cryptohome's remove method. 140 void Remove(AuthAttemptState* attempt, 141 scoped_refptr<ParallelAuthenticator> resolver) { 142 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 143 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker( 144 "CryptohomeRemove-Start", false); 145 cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove( 146 attempt->user_context.username, 147 base::Bind(&TriggerResolveWithLoginTimeMarker, 148 "CryptohomeRemove-End", 149 attempt, 150 resolver)); 151 } 152 153 // Calls cryptohome's key check method. 154 void CheckKey(AuthAttemptState* attempt, 155 scoped_refptr<ParallelAuthenticator> resolver) { 156 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 157 cryptohome::AsyncMethodCaller::GetInstance()->AsyncCheckKey( 158 attempt->user_context.username, 159 attempt->ascii_hash, 160 base::Bind(&TriggerResolve, attempt, resolver)); 161 } 162 163 // Returns hash of |password|, salted with the system salt. 164 std::string HashPassword(const std::string& password) { 165 // Get salt, ascii encode, update sha with that, then update with ascii 166 // of password, then end. 167 std::string ascii_salt = CryptohomeLibrary::Get()->GetSystemSalt(); 168 char passhash_buf[kPasswordHashLength]; 169 170 // Hash salt and password 171 crypto::SHA256HashString(ascii_salt + password, 172 &passhash_buf, sizeof(passhash_buf)); 173 174 // Only want the top half for 'weak' hashing so that the passphrase is not 175 // immediately exposed even if the output is reversed. 176 const int encoded_length = sizeof(passhash_buf) / 2; 177 178 return StringToLowerASCII(base::HexEncode( 179 reinterpret_cast<const void*>(passhash_buf), encoded_length)); 180 } 181 182 } // namespace 183 184 ParallelAuthenticator::ParallelAuthenticator(LoginStatusConsumer* consumer) 185 : Authenticator(consumer), 186 migrate_attempted_(false), 187 remove_attempted_(false), 188 ephemeral_mount_attempted_(false), 189 check_key_attempted_(false), 190 already_reported_success_(false), 191 owner_is_verified_(false), 192 user_can_login_(false), 193 using_oauth_(true) { 194 } 195 196 void ParallelAuthenticator::AuthenticateToLogin( 197 Profile* profile, 198 const UserContext& user_context) { 199 std::string canonicalized = gaia::CanonicalizeEmail(user_context.username); 200 authentication_profile_ = profile; 201 current_state_.reset( 202 new AuthAttemptState( 203 UserContext(canonicalized, 204 user_context.password, 205 user_context.auth_code), 206 HashPassword(user_context.password), 207 std::string(), // login_token, not used. 208 std::string(), // login_captcha, not used. 209 User::USER_TYPE_REGULAR, 210 !UserManager::Get()->IsKnownUser(canonicalized))); 211 // Reset the verified flag. 212 owner_is_verified_ = false; 213 214 BrowserThread::PostTask( 215 BrowserThread::UI, FROM_HERE, 216 base::Bind(&Mount, 217 current_state_.get(), 218 scoped_refptr<ParallelAuthenticator>(this), 219 cryptohome::MOUNT_FLAGS_NONE)); 220 // ClientLogin authentication check should happen immediately here. 221 // We should not try OAuthLogin check until the profile loads. 222 if (!using_oauth_) { 223 // Initiate ClientLogin-based post authentication. 224 current_online_.reset(new OnlineAttempt(current_state_.get(), 225 this)); 226 current_online_->Initiate(profile); 227 } 228 } 229 230 void ParallelAuthenticator::CompleteLogin(Profile* profile, 231 const UserContext& user_context) { 232 std::string canonicalized = gaia::CanonicalizeEmail(user_context.username); 233 authentication_profile_ = profile; 234 current_state_.reset( 235 new AuthAttemptState( 236 UserContext(canonicalized, 237 user_context.password, 238 user_context.auth_code), 239 HashPassword(user_context.password), 240 !UserManager::Get()->IsKnownUser(canonicalized))); 241 242 // Reset the verified flag. 243 owner_is_verified_ = false; 244 245 BrowserThread::PostTask( 246 BrowserThread::UI, FROM_HERE, 247 base::Bind(&Mount, 248 current_state_.get(), 249 scoped_refptr<ParallelAuthenticator>(this), 250 cryptohome::MOUNT_FLAGS_NONE)); 251 252 if (!using_oauth_) { 253 // Test automation needs to disable oauth, but that leads to other 254 // services not being able to fetch a token, leading to browser crashes. 255 // So initiate ClientLogin-based post authentication. 256 // TODO(xiyuan): This should not be required. 257 // Context: http://crbug.com/201374 258 current_online_.reset(new OnlineAttempt(current_state_.get(), 259 this)); 260 current_online_->Initiate(profile); 261 } else { 262 // For login completion from extension, we just need to resolve the current 263 // auth attempt state, the rest of OAuth related tasks will be done in 264 // parallel. 265 BrowserThread::PostTask( 266 BrowserThread::UI, FROM_HERE, 267 base::Bind(&ParallelAuthenticator::ResolveLoginCompletionStatus, this)); 268 } 269 } 270 271 void ParallelAuthenticator::AuthenticateToUnlock( 272 const UserContext& user_context) { 273 current_state_.reset( 274 new AuthAttemptState( 275 gaia::CanonicalizeEmail(user_context.username), 276 HashPassword(user_context.password))); 277 check_key_attempted_ = true; 278 BrowserThread::PostTask( 279 BrowserThread::UI, FROM_HERE, 280 base::Bind(&CheckKey, 281 current_state_.get(), 282 scoped_refptr<ParallelAuthenticator>(this))); 283 } 284 285 void ParallelAuthenticator::LoginAsLocallyManagedUser( 286 const UserContext& user_context) { 287 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 288 // TODO(nkostylev): Pass proper value for |user_is_new| or remove (not used). 289 current_state_.reset( 290 new AuthAttemptState(user_context, 291 HashPassword(user_context.password), 292 "", // login_token 293 "", // login_captcha 294 User::USER_TYPE_LOCALLY_MANAGED, 295 false)); 296 Mount(current_state_.get(), 297 scoped_refptr<ParallelAuthenticator>(this), 298 cryptohome::MOUNT_FLAGS_NONE); 299 } 300 301 void ParallelAuthenticator::LoginRetailMode() { 302 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 303 // Note: |kRetailModeUserEMail| is used in other places to identify a retail 304 // mode session. 305 current_state_.reset(new AuthAttemptState( 306 UserContext(UserManager::kRetailModeUserName, 307 std::string(), // password 308 std::string()), // auth_code 309 std::string(), // ascii_hash 310 std::string(), // login_token 311 std::string(), // login_captcha 312 User::USER_TYPE_RETAIL_MODE, 313 false)); 314 ephemeral_mount_attempted_ = true; 315 MountGuest(current_state_.get(), 316 scoped_refptr<ParallelAuthenticator>(this)); 317 } 318 319 void ParallelAuthenticator::LoginOffTheRecord() { 320 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 321 current_state_.reset(new AuthAttemptState( 322 UserContext(UserManager::kGuestUserName, // username 323 std::string(), // password 324 std::string()), // auth_code 325 std::string(), // ascii_hash 326 std::string(), // login_token 327 std::string(), // login_captcha 328 User::USER_TYPE_GUEST, 329 false)); 330 ephemeral_mount_attempted_ = true; 331 MountGuest(current_state_.get(), 332 scoped_refptr<ParallelAuthenticator>(this)); 333 } 334 335 void ParallelAuthenticator::LoginAsPublicAccount(const std::string& username) { 336 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 337 current_state_.reset(new AuthAttemptState( 338 UserContext(username, 339 std::string(), // password 340 std::string()), // auth_code 341 std::string(), // ascii_hash 342 std::string(), // login_token 343 std::string(), // login_captcha 344 User::USER_TYPE_PUBLIC_ACCOUNT, 345 false)); 346 ephemeral_mount_attempted_ = true; 347 Mount(current_state_.get(), 348 scoped_refptr<ParallelAuthenticator>(this), 349 cryptohome::CREATE_IF_MISSING | cryptohome::ENSURE_EPHEMERAL); 350 } 351 352 void ParallelAuthenticator::OnRetailModeLoginSuccess() { 353 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 354 VLOG(1) << "Retail mode login success"; 355 // Send notification of success 356 AuthenticationNotificationDetails details(true); 357 content::NotificationService::current()->Notify( 358 chrome::NOTIFICATION_LOGIN_AUTHENTICATION, 359 content::NotificationService::AllSources(), 360 content::Details<AuthenticationNotificationDetails>(&details)); 361 if (consumer_) 362 consumer_->OnRetailModeLoginSuccess(current_state_->user_context); 363 } 364 365 void ParallelAuthenticator::OnLoginSuccess(bool request_pending) { 366 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 367 VLOG(1) << "Login success"; 368 // Send notification of success 369 AuthenticationNotificationDetails details(true); 370 content::NotificationService::current()->Notify( 371 chrome::NOTIFICATION_LOGIN_AUTHENTICATION, 372 content::NotificationService::AllSources(), 373 content::Details<AuthenticationNotificationDetails>(&details)); 374 { 375 base::AutoLock for_this_block(success_lock_); 376 already_reported_success_ = true; 377 } 378 if (consumer_) 379 consumer_->OnLoginSuccess(current_state_->user_context, 380 request_pending, 381 using_oauth_); 382 } 383 384 void ParallelAuthenticator::OnOffTheRecordLoginSuccess() { 385 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 386 // Send notification of success 387 AuthenticationNotificationDetails details(true); 388 content::NotificationService::current()->Notify( 389 chrome::NOTIFICATION_LOGIN_AUTHENTICATION, 390 content::NotificationService::AllSources(), 391 content::Details<AuthenticationNotificationDetails>(&details)); 392 if (consumer_) 393 consumer_->OnOffTheRecordLoginSuccess(); 394 } 395 396 void ParallelAuthenticator::OnPasswordChangeDetected() { 397 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 398 if (consumer_) 399 consumer_->OnPasswordChangeDetected(); 400 } 401 402 void ParallelAuthenticator::OnLoginFailure(const LoginFailure& error) { 403 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 404 // Send notification of failure 405 AuthenticationNotificationDetails details(false); 406 content::NotificationService::current()->Notify( 407 chrome::NOTIFICATION_LOGIN_AUTHENTICATION, 408 content::NotificationService::AllSources(), 409 content::Details<AuthenticationNotificationDetails>(&details)); 410 LOG(WARNING) << "Login failed: " << error.GetErrorString(); 411 if (consumer_) 412 consumer_->OnLoginFailure(error); 413 } 414 415 void ParallelAuthenticator::RecoverEncryptedData( 416 const std::string& old_password) { 417 std::string old_hash = HashPassword(old_password); 418 migrate_attempted_ = true; 419 current_state_->ResetCryptohomeStatus(); 420 BrowserThread::PostTask( 421 BrowserThread::UI, FROM_HERE, 422 base::Bind(&Migrate, 423 current_state_.get(), 424 scoped_refptr<ParallelAuthenticator>(this), 425 true, 426 old_hash)); 427 } 428 429 void ParallelAuthenticator::ResyncEncryptedData() { 430 remove_attempted_ = true; 431 current_state_->ResetCryptohomeStatus(); 432 BrowserThread::PostTask( 433 BrowserThread::UI, FROM_HERE, 434 base::Bind(&Remove, 435 current_state_.get(), 436 scoped_refptr<ParallelAuthenticator>(this))); 437 } 438 439 bool ParallelAuthenticator::VerifyOwner() { 440 if (owner_is_verified_) 441 return true; 442 // Check if policy data is fine and continue in safe mode if needed. 443 bool is_safe_mode = false; 444 CrosSettings::Get()->GetBoolean(kPolicyMissingMitigationMode, &is_safe_mode); 445 if (!is_safe_mode) { 446 // Now we can continue with the login and report mount success. 447 user_can_login_ = true; 448 owner_is_verified_ = true; 449 return true; 450 } 451 // Now we can continue reading the private key. 452 DeviceSettingsService::Get()->SetUsername( 453 current_state_->user_context.username); 454 DeviceSettingsService::Get()->GetOwnershipStatusAsync( 455 base::Bind(&ParallelAuthenticator::OnOwnershipChecked, this)); 456 return false; 457 } 458 459 void ParallelAuthenticator::OnOwnershipChecked( 460 DeviceSettingsService::OwnershipStatus status, 461 bool is_owner) { 462 // Now we can check if this user is the owner. 463 user_can_login_ = is_owner; 464 owner_is_verified_ = true; 465 Resolve(); 466 } 467 468 void ParallelAuthenticator::Resolve() { 469 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 470 bool request_pending = false; 471 int mount_flags = cryptohome::MOUNT_FLAGS_NONE; 472 ParallelAuthenticator::AuthState state = ResolveState(); 473 VLOG(1) << "Resolved state to: " << state; 474 switch (state) { 475 case CONTINUE: 476 case POSSIBLE_PW_CHANGE: 477 case NO_MOUNT: 478 // These are intermediate states; we need more info from a request that 479 // is still pending. 480 break; 481 case FAILED_MOUNT: 482 // In this case, whether login succeeded or not, we can't log 483 // the user in because their data is horked. So, override with 484 // the appropriate failure. 485 BrowserThread::PostTask( 486 BrowserThread::UI, FROM_HERE, 487 base::Bind(&ParallelAuthenticator::OnLoginFailure, this, 488 LoginFailure(LoginFailure::COULD_NOT_MOUNT_CRYPTOHOME))); 489 break; 490 case FAILED_REMOVE: 491 // In this case, we tried to remove the user's old cryptohome at her 492 // request, and the remove failed. 493 BrowserThread::PostTask( 494 BrowserThread::UI, FROM_HERE, 495 base::Bind(&ParallelAuthenticator::OnLoginFailure, this, 496 LoginFailure(LoginFailure::DATA_REMOVAL_FAILED))); 497 break; 498 case FAILED_TMPFS: 499 // In this case, we tried to mount a tmpfs for guest and failed. 500 BrowserThread::PostTask( 501 BrowserThread::UI, FROM_HERE, 502 base::Bind(&ParallelAuthenticator::OnLoginFailure, this, 503 LoginFailure(LoginFailure::COULD_NOT_MOUNT_TMPFS))); 504 break; 505 case FAILED_TPM: 506 // In this case, we tried to create/mount cryptohome and failed 507 // because of the critical TPM error. 508 // Chrome will notify user and request reboot. 509 BrowserThread::PostTask( 510 BrowserThread::UI, FROM_HERE, 511 base::Bind(&ParallelAuthenticator::OnLoginFailure, this, 512 LoginFailure(LoginFailure::TPM_ERROR))); 513 break; 514 case CREATE_NEW: 515 mount_flags |= cryptohome::CREATE_IF_MISSING; 516 case RECOVER_MOUNT: 517 current_state_->ResetCryptohomeStatus(); 518 BrowserThread::PostTask( 519 BrowserThread::UI, FROM_HERE, 520 base::Bind(&Mount, 521 current_state_.get(), 522 scoped_refptr<ParallelAuthenticator>(this), 523 mount_flags)); 524 break; 525 case NEED_OLD_PW: 526 BrowserThread::PostTask( 527 BrowserThread::UI, FROM_HERE, 528 base::Bind(&ParallelAuthenticator::OnPasswordChangeDetected, this)); 529 break; 530 case ONLINE_FAILED: 531 case NEED_NEW_PW: 532 case HAVE_NEW_PW: 533 NOTREACHED() << "Using obsolete ClientLogin code path."; 534 break; 535 case OFFLINE_LOGIN: 536 VLOG(2) << "Offline login"; 537 // Marking request_pending to false when using OAuth because OAuth related 538 // tasks are performed after user profile is mounted and are not performed 539 // by ParallelAuthenticator. 540 // TODO(xiyuan): Revert this when we support Gaia in lock screen and 541 // start to use ParallelAuthenticator's VerifyOAuth1AccessToken again. 542 request_pending = using_oauth_ ? 543 false : 544 !current_state_->online_complete(); 545 // Fall through. 546 case UNLOCK: 547 VLOG(2) << "Unlock"; 548 // Fall through. 549 case ONLINE_LOGIN: 550 VLOG(2) << "Online login"; 551 BrowserThread::PostTask( 552 BrowserThread::UI, FROM_HERE, 553 base::Bind(&ParallelAuthenticator::OnLoginSuccess, this, 554 request_pending)); 555 break; 556 case DEMO_LOGIN: 557 VLOG(2) << "Retail mode login"; 558 using_oauth_ = false; 559 BrowserThread::PostTask( 560 BrowserThread::UI, FROM_HERE, 561 base::Bind(&ParallelAuthenticator::OnRetailModeLoginSuccess, this)); 562 break; 563 case GUEST_LOGIN: 564 BrowserThread::PostTask( 565 BrowserThread::UI, FROM_HERE, 566 base::Bind(&ParallelAuthenticator::OnOffTheRecordLoginSuccess, this)); 567 break; 568 case PUBLIC_ACCOUNT_LOGIN: 569 using_oauth_ = false; 570 BrowserThread::PostTask( 571 BrowserThread::UI, FROM_HERE, 572 base::Bind(&ParallelAuthenticator::OnLoginSuccess, this, false)); 573 break; 574 case LOCALLY_MANAGED_USER_LOGIN: 575 using_oauth_ = false; 576 // TODO(nkostylev): Figure out whether there's need to call 577 // a separate success method here. 578 BrowserThread::PostTask( 579 BrowserThread::UI, FROM_HERE, 580 base::Bind(&ParallelAuthenticator::OnLoginSuccess, this, false)); 581 break; 582 case LOGIN_FAILED: 583 current_state_->ResetCryptohomeStatus(); 584 BrowserThread::PostTask(BrowserThread::UI, 585 FROM_HERE, 586 base::Bind( 587 &ParallelAuthenticator::OnLoginFailure, 588 this, 589 current_state_->online_outcome())); 590 break; 591 case OWNER_REQUIRED: { 592 current_state_->ResetCryptohomeStatus(); 593 bool success = false; 594 DBusThreadManager::Get()->GetCryptohomeClient()->Unmount(&success); 595 if (!success) { 596 // Maybe we should reboot immediately here? 597 LOG(ERROR) << "Couldn't unmount users home!"; 598 } 599 BrowserThread::PostTask(BrowserThread::UI, 600 FROM_HERE, 601 base::Bind( 602 &ParallelAuthenticator::OnLoginFailure, 603 this, 604 LoginFailure(LoginFailure::OWNER_REQUIRED))); 605 break; 606 } 607 default: 608 NOTREACHED(); 609 break; 610 } 611 } 612 613 ParallelAuthenticator::~ParallelAuthenticator() {} 614 615 ParallelAuthenticator::AuthState ParallelAuthenticator::ResolveState() { 616 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 617 // If we haven't mounted the user's home dir yet or 618 // haven't got sanitized username value, we can't be done. 619 // We never get past here if any of these two cryptohome ops is still pending. 620 // This is an important invariant. 621 if (!current_state_->cryptohome_complete() || 622 !current_state_->username_hash_obtained()) { 623 return CONTINUE; 624 } 625 626 AuthState state = CONTINUE; 627 628 if (current_state_->cryptohome_outcome()) 629 state = ResolveCryptohomeSuccessState(); 630 else 631 state = ResolveCryptohomeFailureState(); 632 633 DCHECK(current_state_->cryptohome_complete()); // Ensure invariant holds. 634 migrate_attempted_ = false; 635 remove_attempted_ = false; 636 ephemeral_mount_attempted_ = false; 637 check_key_attempted_ = false; 638 639 if (state != POSSIBLE_PW_CHANGE && 640 state != NO_MOUNT && 641 state != OFFLINE_LOGIN) 642 return state; 643 644 if (current_state_->online_complete()) { 645 if (current_state_->online_outcome().reason() == LoginFailure::NONE) { 646 // Online attempt succeeded as well, so combine the results. 647 return ResolveOnlineSuccessState(state); 648 } 649 NOTREACHED() << "Using obsolete ClientLogin code path."; 650 } 651 // if online isn't complete yet, just return the offline result. 652 return state; 653 } 654 655 ParallelAuthenticator::AuthState 656 ParallelAuthenticator::ResolveCryptohomeFailureState() { 657 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 658 if (remove_attempted_) 659 return FAILED_REMOVE; 660 if (ephemeral_mount_attempted_) 661 return FAILED_TMPFS; 662 if (migrate_attempted_) 663 return NEED_OLD_PW; 664 if (check_key_attempted_) 665 return LOGIN_FAILED; 666 667 if (current_state_->cryptohome_code() == 668 cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) { 669 // Critical TPM error detected, reboot needed. 670 return FAILED_TPM; 671 } 672 673 // Return intermediate states in the following cases: 674 // 1. When there is a parallel online attempt to resolve them later; 675 // This is the case with legacy ClientLogin flow; 676 // 2. When there is an online result to use; 677 // This is the case after user finishes Gaia login; 678 if (current_online_.get() || current_state_->online_complete()) { 679 if (current_state_->cryptohome_code() == 680 cryptohome::MOUNT_ERROR_KEY_FAILURE) { 681 // If we tried a mount but they used the wrong key, we may need to 682 // ask the user for her old password. We'll only know once we've 683 // done the online check. 684 return POSSIBLE_PW_CHANGE; 685 } 686 if (current_state_->cryptohome_code() == 687 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST) { 688 // If we tried a mount but the user did not exist, then we should wait 689 // for online login to succeed and try again with the "create" flag set. 690 return NO_MOUNT; 691 } 692 } 693 694 return FAILED_MOUNT; 695 } 696 697 ParallelAuthenticator::AuthState 698 ParallelAuthenticator::ResolveCryptohomeSuccessState() { 699 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 700 if (remove_attempted_) 701 return CREATE_NEW; 702 if (migrate_attempted_) 703 return RECOVER_MOUNT; 704 if (check_key_attempted_) 705 return UNLOCK; 706 707 if (current_state_->user_type == User::USER_TYPE_GUEST) 708 return GUEST_LOGIN; 709 if (current_state_->user_type == User::USER_TYPE_RETAIL_MODE) 710 return DEMO_LOGIN; 711 if (current_state_->user_type == User::USER_TYPE_PUBLIC_ACCOUNT) 712 return PUBLIC_ACCOUNT_LOGIN; 713 if (current_state_->user_type == User::USER_TYPE_LOCALLY_MANAGED) 714 return LOCALLY_MANAGED_USER_LOGIN; 715 716 if (!VerifyOwner()) 717 return CONTINUE; 718 return user_can_login_ ? OFFLINE_LOGIN : OWNER_REQUIRED; 719 } 720 721 ParallelAuthenticator::AuthState 722 ParallelAuthenticator::ResolveOnlineSuccessState( 723 ParallelAuthenticator::AuthState offline_state) { 724 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 725 switch (offline_state) { 726 case POSSIBLE_PW_CHANGE: 727 return NEED_OLD_PW; 728 case NO_MOUNT: 729 return CREATE_NEW; 730 case OFFLINE_LOGIN: 731 return ONLINE_LOGIN; 732 default: 733 NOTREACHED(); 734 return offline_state; 735 } 736 } 737 738 void ParallelAuthenticator::ResolveLoginCompletionStatus() { 739 // Shortcut online state resolution process. 740 current_state_->RecordOnlineLoginStatus(LoginFailure::LoginFailureNone()); 741 Resolve(); 742 } 743 744 void ParallelAuthenticator::SetOwnerState(bool owner_check_finished, 745 bool check_result) { 746 owner_is_verified_ = owner_check_finished; 747 user_can_login_ = check_result; 748 } 749 750 } // namespace chromeos 751