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