1// Copyright 2014 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 "chromeos/login/auth/cryptohome_authenticator.h" 6 7#include <vector> 8 9#include "base/basictypes.h" 10#include "base/bind.h" 11#include "base/files/file_path.h" 12#include "base/location.h" 13#include "base/logging.h" 14#include "chromeos/cryptohome/async_method_caller.h" 15#include "chromeos/cryptohome/cryptohome_parameters.h" 16#include "chromeos/cryptohome/homedir_methods.h" 17#include "chromeos/cryptohome/system_salt_getter.h" 18#include "chromeos/dbus/cryptohome_client.h" 19#include "chromeos/dbus/dbus_thread_manager.h" 20#include "chromeos/login/auth/auth_status_consumer.h" 21#include "chromeos/login/auth/key.h" 22#include "chromeos/login/auth/user_context.h" 23#include "chromeos/login/login_state.h" 24#include "chromeos/login/user_names.h" 25#include "chromeos/login_event_recorder.h" 26#include "components/user_manager/user_type.h" 27#include "third_party/cros_system_api/dbus/service_constants.h" 28 29namespace chromeos { 30 31namespace { 32 33// The label used for the key derived from the user's GAIA credentials. 34const char kCryptohomeGAIAKeyLabel[] = "gaia"; 35 36// The name under which the type of key generated from the user's GAIA 37// credentials is stored. 38const char kKeyProviderDataTypeName[] = "type"; 39 40// The name under which the salt used to generate a key from the user's GAIA 41// credentials is stored. 42const char kKeyProviderDataSaltName[] = "salt"; 43 44// Hashes |key| with |system_salt| if it its type is KEY_TYPE_PASSWORD_PLAIN. 45// Returns the keys unmodified otherwise. 46scoped_ptr<Key> TransformKeyIfNeeded(const Key& key, 47 const std::string& system_salt) { 48 scoped_ptr<Key> result(new Key(key)); 49 if (result->GetKeyType() == Key::KEY_TYPE_PASSWORD_PLAIN) 50 result->Transform(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF, system_salt); 51 52 return result.Pass(); 53} 54 55// Records status and calls resolver->Resolve(). 56void TriggerResolve(AuthAttemptState* attempt, 57 scoped_refptr<CryptohomeAuthenticator> resolver, 58 bool success, 59 cryptohome::MountError return_code) { 60 attempt->RecordCryptohomeStatus(success, return_code); 61 resolver->Resolve(); 62} 63 64// Records get hash status and calls resolver->Resolve(). 65void TriggerResolveHash(AuthAttemptState* attempt, 66 scoped_refptr<CryptohomeAuthenticator> resolver, 67 bool success, 68 const std::string& username_hash) { 69 if (success) 70 attempt->RecordUsernameHash(username_hash); 71 else 72 attempt->RecordUsernameHashFailed(); 73 resolver->Resolve(); 74} 75 76// Calls TriggerResolve while adding login time marker. 77void TriggerResolveWithLoginTimeMarker( 78 const std::string& marker_name, 79 AuthAttemptState* attempt, 80 scoped_refptr<CryptohomeAuthenticator> resolver, 81 bool success, 82 cryptohome::MountError return_code) { 83 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(marker_name, false); 84 TriggerResolve(attempt, resolver, success, return_code); 85} 86 87// Records an error in accessing the user's cryptohome with the given key and 88// calls resolver->Resolve() after adding a login time marker. 89void RecordKeyErrorAndResolve(AuthAttemptState* attempt, 90 scoped_refptr<CryptohomeAuthenticator> resolver) { 91 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker("CryptohomeMount-End", 92 false); 93 attempt->RecordCryptohomeStatus(false /* success */, 94 cryptohome::MOUNT_ERROR_KEY_FAILURE); 95 resolver->Resolve(); 96} 97 98// Callback invoked when cryptohome's MountEx() method has finished. 99void OnMount(AuthAttemptState* attempt, 100 scoped_refptr<CryptohomeAuthenticator> resolver, 101 bool success, 102 cryptohome::MountError return_code, 103 const std::string& mount_hash) { 104 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker("CryptohomeMount-End", 105 false); 106 attempt->RecordCryptohomeStatus(success, return_code); 107 if (success) 108 attempt->RecordUsernameHash(mount_hash); 109 else 110 attempt->RecordUsernameHashFailed(); 111 resolver->Resolve(); 112} 113 114// Calls cryptohome's MountEx() method. The key in |attempt->user_context| must 115// not be a plain text password. If the user provided a plain text password, 116// that password must be transformed to another key type (by salted hashing) 117// before calling this method. 118void DoMount(AuthAttemptState* attempt, 119 scoped_refptr<CryptohomeAuthenticator> resolver, 120 bool ephemeral, 121 bool create_if_nonexistent) { 122 const Key* key = attempt->user_context.GetKey(); 123 // If the |key| is a plain text password, crash rather than attempting to 124 // mount the cryptohome with a plain text password. 125 CHECK_NE(Key::KEY_TYPE_PASSWORD_PLAIN, key->GetKeyType()); 126 127 // Set state that username_hash is requested here so that test implementation 128 // that returns directly would not generate 2 OnLoginSucces() calls. 129 attempt->UsernameHashRequested(); 130 131 // Set the authentication's key label to an empty string, which is a wildcard 132 // allowing any key to match. This is necessary because cryptohomes created by 133 // Chrome OS M38 and older will have a legacy key with no label while those 134 // created by Chrome OS M39 and newer will have a key with the label 135 // kCryptohomeGAIAKeyLabel. 136 const cryptohome::KeyDefinition auth_key(key->GetSecret(), 137 std::string(), 138 cryptohome::PRIV_DEFAULT); 139 cryptohome::MountParameters mount(ephemeral); 140 if (create_if_nonexistent) { 141 mount.create_keys.push_back(cryptohome::KeyDefinition( 142 key->GetSecret(), 143 kCryptohomeGAIAKeyLabel, 144 cryptohome::PRIV_DEFAULT)); 145 } 146 147 cryptohome::HomedirMethods::GetInstance()->MountEx( 148 cryptohome::Identification(attempt->user_context.GetUserID()), 149 cryptohome::Authorization(auth_key), 150 mount, 151 base::Bind(&OnMount, attempt, resolver)); 152} 153 154// Callback invoked when the system salt has been retrieved. Transforms the key 155// in |attempt->user_context| using Chrome's default hashing algorithm and the 156// system salt, then calls MountEx(). 157void OnGetSystemSalt(AuthAttemptState* attempt, 158 scoped_refptr<CryptohomeAuthenticator> resolver, 159 bool ephemeral, 160 bool create_if_nonexistent, 161 const std::string& system_salt) { 162 DCHECK_EQ(Key::KEY_TYPE_PASSWORD_PLAIN, 163 attempt->user_context.GetKey()->GetKeyType()); 164 165 attempt->user_context.GetKey()->Transform( 166 Key::KEY_TYPE_SALTED_SHA256_TOP_HALF, 167 system_salt); 168 169 DoMount(attempt, resolver, ephemeral, create_if_nonexistent); 170} 171 172// Callback invoked when cryptohome's GetKeyDataEx() method has finished. 173// * If GetKeyDataEx() returned metadata indicating the hashing algorithm and 174// salt that were used to generate the key for this user's cryptohome, 175// transforms the key in |attempt->user_context| with the same parameters. 176// * Otherwise, starts the retrieval of the system salt so that the key in 177// |attempt->user_context| can be transformed with Chrome's default hashing 178// algorithm and the system salt. 179// The resulting key is then passed to cryptohome's MountEx(). 180void OnGetKeyDataEx( 181 AuthAttemptState* attempt, 182 scoped_refptr<CryptohomeAuthenticator> resolver, 183 bool ephemeral, 184 bool create_if_nonexistent, 185 bool success, 186 cryptohome::MountError return_code, 187 const std::vector<cryptohome::KeyDefinition>& key_definitions) { 188 if (success) { 189 if (key_definitions.size() == 1) { 190 const cryptohome::KeyDefinition& key_definition = key_definitions.front(); 191 DCHECK_EQ(kCryptohomeGAIAKeyLabel, key_definition.label); 192 193 // Extract the key type and salt from |key_definition|, if present. 194 scoped_ptr<int64> type; 195 scoped_ptr<std::string> salt; 196 for (std::vector<cryptohome::KeyDefinition::ProviderData>:: 197 const_iterator it = key_definition.provider_data.begin(); 198 it != key_definition.provider_data.end(); ++it) { 199 if (it->name == kKeyProviderDataTypeName) { 200 if (it->number) 201 type.reset(new int64(*it->number)); 202 else 203 NOTREACHED(); 204 } else if (it->name == kKeyProviderDataSaltName) { 205 if (it->bytes) 206 salt.reset(new std::string(*it->bytes)); 207 else 208 NOTREACHED(); 209 } 210 } 211 212 if (type) { 213 if (*type < 0 || *type >= Key::KEY_TYPE_COUNT) { 214 LOG(ERROR) << "Invalid key type: " << *type; 215 RecordKeyErrorAndResolve(attempt, resolver); 216 return; 217 } 218 219 if (!salt) { 220 LOG(ERROR) << "Missing salt."; 221 RecordKeyErrorAndResolve(attempt, resolver); 222 return; 223 } 224 225 attempt->user_context.GetKey()->Transform( 226 static_cast<Key::KeyType>(*type), 227 *salt); 228 DoMount(attempt, resolver, ephemeral, create_if_nonexistent); 229 return; 230 } 231 } else { 232 LOG(ERROR) << "GetKeyDataEx() returned " << key_definitions.size() 233 << " entries."; 234 } 235 } 236 237 SystemSaltGetter::Get()->GetSystemSalt(base::Bind(&OnGetSystemSalt, 238 attempt, 239 resolver, 240 ephemeral, 241 create_if_nonexistent)); 242} 243 244// Starts the process that will mount a user's cryptohome. 245// * If the key in |attempt->user_context| is not a plain text password, 246// cryptohome's MountEx() method is called directly with the key. 247// * Otherwise, the key must be transformed (by salted hashing) before being 248// passed to MountEx(). In that case, cryptohome's GetKeyDataEx() method is 249// called to retrieve metadata indicating the hashing algorithm and salt that 250// were used to generate the key for this user's cryptohome and the key is 251// transformed accordingly before calling MountEx(). 252void StartMount(AuthAttemptState* attempt, 253 scoped_refptr<CryptohomeAuthenticator> resolver, 254 bool ephemeral, 255 bool create_if_nonexistent) { 256 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker( 257 "CryptohomeMount-Start", false); 258 259 if (attempt->user_context.GetKey()->GetKeyType() != 260 Key::KEY_TYPE_PASSWORD_PLAIN) { 261 DoMount(attempt, resolver, ephemeral, create_if_nonexistent); 262 return; 263 } 264 265 cryptohome::HomedirMethods::GetInstance()->GetKeyDataEx( 266 cryptohome::Identification(attempt->user_context.GetUserID()), 267 kCryptohomeGAIAKeyLabel, 268 base::Bind(&OnGetKeyDataEx, 269 attempt, 270 resolver, 271 ephemeral, 272 create_if_nonexistent)); 273} 274 275// Calls cryptohome's mount method for guest and also get the user hash from 276// cryptohome. 277void MountGuestAndGetHash(AuthAttemptState* attempt, 278 scoped_refptr<CryptohomeAuthenticator> resolver) { 279 attempt->UsernameHashRequested(); 280 cryptohome::AsyncMethodCaller::GetInstance()->AsyncMountGuest( 281 base::Bind(&TriggerResolveWithLoginTimeMarker, 282 "CryptohomeMount-End", 283 attempt, 284 resolver)); 285 cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername( 286 attempt->user_context.GetUserID(), 287 base::Bind(&TriggerResolveHash, attempt, resolver)); 288} 289 290// Calls cryptohome's MountPublic method 291void MountPublic(AuthAttemptState* attempt, 292 scoped_refptr<CryptohomeAuthenticator> resolver, 293 int flags) { 294 cryptohome::AsyncMethodCaller::GetInstance()->AsyncMountPublic( 295 attempt->user_context.GetUserID(), 296 flags, 297 base::Bind(&TriggerResolveWithLoginTimeMarker, 298 "CryptohomeMountPublic-End", 299 attempt, 300 resolver)); 301 cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername( 302 attempt->user_context.GetUserID(), 303 base::Bind(&TriggerResolveHash, attempt, resolver)); 304} 305 306// Calls cryptohome's key migration method. 307void Migrate(AuthAttemptState* attempt, 308 scoped_refptr<CryptohomeAuthenticator> resolver, 309 bool passing_old_hash, 310 const std::string& old_password, 311 const std::string& system_salt) { 312 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker( 313 "CryptohomeMigrate-Start", false); 314 cryptohome::AsyncMethodCaller* caller = 315 cryptohome::AsyncMethodCaller::GetInstance(); 316 317 // TODO(bartfab): Retrieve the hashing algorithm and salt to use for |old_key| 318 // from cryptohomed. 319 scoped_ptr<Key> old_key = 320 TransformKeyIfNeeded(Key(old_password), system_salt); 321 scoped_ptr<Key> new_key = 322 TransformKeyIfNeeded(*attempt->user_context.GetKey(), system_salt); 323 if (passing_old_hash) { 324 caller->AsyncMigrateKey(attempt->user_context.GetUserID(), 325 old_key->GetSecret(), 326 new_key->GetSecret(), 327 base::Bind(&TriggerResolveWithLoginTimeMarker, 328 "CryptohomeMount-End", 329 attempt, 330 resolver)); 331 } else { 332 caller->AsyncMigrateKey(attempt->user_context.GetUserID(), 333 new_key->GetSecret(), 334 old_key->GetSecret(), 335 base::Bind(&TriggerResolveWithLoginTimeMarker, 336 "CryptohomeMount-End", 337 attempt, 338 resolver)); 339 } 340} 341 342// Calls cryptohome's remove method. 343void Remove(AuthAttemptState* attempt, 344 scoped_refptr<CryptohomeAuthenticator> resolver) { 345 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker( 346 "CryptohomeRemove-Start", false); 347 cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove( 348 attempt->user_context.GetUserID(), 349 base::Bind(&TriggerResolveWithLoginTimeMarker, 350 "CryptohomeRemove-End", 351 attempt, 352 resolver)); 353} 354 355// Calls cryptohome's key check method. 356void CheckKey(AuthAttemptState* attempt, 357 scoped_refptr<CryptohomeAuthenticator> resolver, 358 const std::string& system_salt) { 359 scoped_ptr<Key> key = 360 TransformKeyIfNeeded(*attempt->user_context.GetKey(), system_salt); 361 cryptohome::AsyncMethodCaller::GetInstance()->AsyncCheckKey( 362 attempt->user_context.GetUserID(), 363 key->GetSecret(), 364 base::Bind(&TriggerResolve, attempt, resolver)); 365} 366 367} // namespace 368 369CryptohomeAuthenticator::CryptohomeAuthenticator( 370 scoped_refptr<base::TaskRunner> task_runner, 371 AuthStatusConsumer* consumer) 372 : Authenticator(consumer), 373 task_runner_(task_runner), 374 migrate_attempted_(false), 375 remove_attempted_(false), 376 resync_attempted_(false), 377 ephemeral_mount_attempted_(false), 378 check_key_attempted_(false), 379 already_reported_success_(false), 380 owner_is_verified_(false), 381 user_can_login_(false), 382 remove_user_data_on_failure_(false), 383 delayed_login_failure_(NULL) { 384} 385 386void CryptohomeAuthenticator::AuthenticateToLogin( 387 Profile* profile, 388 const UserContext& user_context) { 389 authentication_profile_ = profile; 390 current_state_.reset(new AuthAttemptState(user_context, 391 user_manager::USER_TYPE_REGULAR, 392 false, // unlock 393 false, // online_complete 394 !IsKnownUser(user_context))); 395 // Reset the verified flag. 396 owner_is_verified_ = false; 397 398 StartMount(current_state_.get(), 399 scoped_refptr<CryptohomeAuthenticator>(this), 400 false /* ephemeral */, 401 false /* create_if_nonexistent */); 402} 403 404void CryptohomeAuthenticator::CompleteLogin(Profile* profile, 405 const UserContext& user_context) { 406 authentication_profile_ = profile; 407 current_state_.reset(new AuthAttemptState(user_context, 408 user_manager::USER_TYPE_REGULAR, 409 true, // unlock 410 false, // online_complete 411 !IsKnownUser(user_context))); 412 413 // Reset the verified flag. 414 owner_is_verified_ = false; 415 416 StartMount(current_state_.get(), 417 scoped_refptr<CryptohomeAuthenticator>(this), 418 false /* ephemeral */, 419 false /* create_if_nonexistent */); 420 421 // For login completion from extension, we just need to resolve the current 422 // auth attempt state, the rest of OAuth related tasks will be done in 423 // parallel. 424 task_runner_->PostTask( 425 FROM_HERE, 426 base::Bind(&CryptohomeAuthenticator::ResolveLoginCompletionStatus, this)); 427} 428 429void CryptohomeAuthenticator::AuthenticateToUnlock( 430 const UserContext& user_context) { 431 current_state_.reset(new AuthAttemptState(user_context, 432 user_manager::USER_TYPE_REGULAR, 433 true, // unlock 434 true, // online_complete 435 false)); // user_is_new 436 remove_user_data_on_failure_ = false; 437 check_key_attempted_ = true; 438 SystemSaltGetter::Get()->GetSystemSalt( 439 base::Bind(&CheckKey, 440 current_state_.get(), 441 scoped_refptr<CryptohomeAuthenticator>(this))); 442} 443 444void CryptohomeAuthenticator::LoginAsSupervisedUser( 445 const UserContext& user_context) { 446 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 447 // TODO(nkostylev): Pass proper value for |user_is_new| or remove (not used). 448 current_state_.reset(new AuthAttemptState(user_context, 449 user_manager::USER_TYPE_SUPERVISED, 450 false, // unlock 451 false, // online_complete 452 false)); // user_is_new 453 remove_user_data_on_failure_ = false; 454 StartMount(current_state_.get(), 455 scoped_refptr<CryptohomeAuthenticator>(this), 456 false /* ephemeral */, 457 false /* create_if_nonexistent */); 458} 459 460void CryptohomeAuthenticator::LoginRetailMode() { 461 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 462 // Note: |kRetailModeUserEMail| is used in other places to identify a retail 463 // mode session. 464 current_state_.reset( 465 new AuthAttemptState(UserContext(chromeos::login::kRetailModeUserName), 466 user_manager::USER_TYPE_RETAIL_MODE, 467 false, // unlock 468 false, // online_complete 469 false)); // user_is_new 470 remove_user_data_on_failure_ = false; 471 ephemeral_mount_attempted_ = true; 472 MountGuestAndGetHash(current_state_.get(), 473 scoped_refptr<CryptohomeAuthenticator>(this)); 474} 475 476void CryptohomeAuthenticator::LoginOffTheRecord() { 477 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 478 current_state_.reset( 479 new AuthAttemptState(UserContext(chromeos::login::kGuestUserName), 480 user_manager::USER_TYPE_GUEST, 481 false, // unlock 482 false, // online_complete 483 false)); // user_is_new 484 remove_user_data_on_failure_ = false; 485 ephemeral_mount_attempted_ = true; 486 MountGuestAndGetHash(current_state_.get(), 487 scoped_refptr<CryptohomeAuthenticator>(this)); 488} 489 490void CryptohomeAuthenticator::LoginAsPublicSession( 491 const UserContext& user_context) { 492 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 493 current_state_.reset( 494 new AuthAttemptState(user_context, 495 user_manager::USER_TYPE_PUBLIC_ACCOUNT, 496 false, // unlock 497 false, // online_complete 498 false)); // user_is_new 499 remove_user_data_on_failure_ = false; 500 ephemeral_mount_attempted_ = true; 501 StartMount(current_state_.get(), 502 scoped_refptr<CryptohomeAuthenticator>(this), 503 true /* ephemeral */, 504 true /* create_if_nonexistent */); 505} 506 507void CryptohomeAuthenticator::LoginAsKioskAccount( 508 const std::string& app_user_id, 509 bool use_guest_mount) { 510 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 511 512 const std::string user_id = 513 use_guest_mount ? chromeos::login::kGuestUserName : app_user_id; 514 current_state_.reset(new AuthAttemptState(UserContext(user_id), 515 user_manager::USER_TYPE_KIOSK_APP, 516 false, // unlock 517 false, // online_complete 518 false)); // user_is_new 519 520 remove_user_data_on_failure_ = true; 521 if (!use_guest_mount) { 522 MountPublic(current_state_.get(), 523 scoped_refptr<CryptohomeAuthenticator>(this), 524 cryptohome::CREATE_IF_MISSING); 525 } else { 526 ephemeral_mount_attempted_ = true; 527 MountGuestAndGetHash(current_state_.get(), 528 scoped_refptr<CryptohomeAuthenticator>(this)); 529 } 530} 531 532void CryptohomeAuthenticator::OnRetailModeAuthSuccess() { 533 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 534 VLOG(1) << "Retail mode login success"; 535 chromeos::LoginEventRecorder::Get()->RecordAuthenticationSuccess(); 536 if (consumer_) 537 consumer_->OnRetailModeAuthSuccess(current_state_->user_context); 538} 539 540void CryptohomeAuthenticator::OnAuthSuccess() { 541 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 542 VLOG(1) << "Login success"; 543 // Send notification of success 544 chromeos::LoginEventRecorder::Get()->RecordAuthenticationSuccess(); 545 { 546 base::AutoLock for_this_block(success_lock_); 547 already_reported_success_ = true; 548 } 549 if (consumer_) 550 consumer_->OnAuthSuccess(current_state_->user_context); 551} 552 553void CryptohomeAuthenticator::OnOffTheRecordAuthSuccess() { 554 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 555 chromeos::LoginEventRecorder::Get()->RecordAuthenticationSuccess(); 556 if (consumer_) 557 consumer_->OnOffTheRecordAuthSuccess(); 558} 559 560void CryptohomeAuthenticator::OnPasswordChangeDetected() { 561 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 562 if (consumer_) 563 consumer_->OnPasswordChangeDetected(); 564} 565 566void CryptohomeAuthenticator::OnAuthFailure(const AuthFailure& error) { 567 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 568 569 // OnAuthFailure will be called again with the same |error| 570 // after the cryptohome has been removed. 571 if (remove_user_data_on_failure_) { 572 delayed_login_failure_ = &error; 573 RemoveEncryptedData(); 574 return; 575 } 576 chromeos::LoginEventRecorder::Get()->RecordAuthenticationFailure(); 577 LOG(WARNING) << "Login failed: " << error.GetErrorString(); 578 if (consumer_) 579 consumer_->OnAuthFailure(error); 580} 581 582void CryptohomeAuthenticator::RecoverEncryptedData( 583 const std::string& old_password) { 584 migrate_attempted_ = true; 585 current_state_->ResetCryptohomeStatus(); 586 SystemSaltGetter::Get()->GetSystemSalt( 587 base::Bind(&Migrate, 588 current_state_.get(), 589 scoped_refptr<CryptohomeAuthenticator>(this), 590 true, 591 old_password)); 592} 593 594void CryptohomeAuthenticator::RemoveEncryptedData() { 595 remove_attempted_ = true; 596 current_state_->ResetCryptohomeStatus(); 597 task_runner_->PostTask( 598 FROM_HERE, 599 base::Bind(&Remove, 600 current_state_.get(), 601 scoped_refptr<CryptohomeAuthenticator>(this))); 602} 603 604void CryptohomeAuthenticator::ResyncEncryptedData() { 605 resync_attempted_ = true; 606 current_state_->ResetCryptohomeStatus(); 607 task_runner_->PostTask( 608 FROM_HERE, 609 base::Bind(&Remove, 610 current_state_.get(), 611 scoped_refptr<CryptohomeAuthenticator>(this))); 612} 613 614bool CryptohomeAuthenticator::VerifyOwner() { 615 if (owner_is_verified_) 616 return true; 617 // Check if policy data is fine and continue in safe mode if needed. 618 if (!IsSafeMode()) { 619 // Now we can continue with the login and report mount success. 620 user_can_login_ = true; 621 owner_is_verified_ = true; 622 return true; 623 } 624 625 CheckSafeModeOwnership( 626 current_state_->user_context, 627 base::Bind(&CryptohomeAuthenticator::OnOwnershipChecked, this)); 628 return false; 629} 630 631void CryptohomeAuthenticator::OnOwnershipChecked(bool is_owner) { 632 // Now we can check if this user is the owner. 633 user_can_login_ = is_owner; 634 owner_is_verified_ = true; 635 Resolve(); 636} 637 638void CryptohomeAuthenticator::Resolve() { 639 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 640 bool create_if_nonexistent = false; 641 CryptohomeAuthenticator::AuthState state = ResolveState(); 642 VLOG(1) << "Resolved state to: " << state; 643 switch (state) { 644 case CONTINUE: 645 case POSSIBLE_PW_CHANGE: 646 case NO_MOUNT: 647 // These are intermediate states; we need more info from a request that 648 // is still pending. 649 break; 650 case FAILED_MOUNT: 651 // In this case, whether login succeeded or not, we can't log 652 // the user in because their data is horked. So, override with 653 // the appropriate failure. 654 task_runner_->PostTask( 655 FROM_HERE, 656 base::Bind(&CryptohomeAuthenticator::OnAuthFailure, 657 this, 658 AuthFailure(AuthFailure::COULD_NOT_MOUNT_CRYPTOHOME))); 659 break; 660 case FAILED_REMOVE: 661 // In this case, we tried to remove the user's old cryptohome at her 662 // request, and the remove failed. 663 remove_user_data_on_failure_ = false; 664 task_runner_->PostTask( 665 FROM_HERE, 666 base::Bind(&CryptohomeAuthenticator::OnAuthFailure, 667 this, 668 AuthFailure(AuthFailure::DATA_REMOVAL_FAILED))); 669 break; 670 case FAILED_TMPFS: 671 // In this case, we tried to mount a tmpfs for guest and failed. 672 task_runner_->PostTask( 673 FROM_HERE, 674 base::Bind(&CryptohomeAuthenticator::OnAuthFailure, 675 this, 676 AuthFailure(AuthFailure::COULD_NOT_MOUNT_TMPFS))); 677 break; 678 case FAILED_TPM: 679 // In this case, we tried to create/mount cryptohome and failed 680 // because of the critical TPM error. 681 // Chrome will notify user and request reboot. 682 task_runner_->PostTask(FROM_HERE, 683 base::Bind(&CryptohomeAuthenticator::OnAuthFailure, 684 this, 685 AuthFailure(AuthFailure::TPM_ERROR))); 686 break; 687 case FAILED_USERNAME_HASH: 688 // In this case, we failed the GetSanitizedUsername request to 689 // cryptohomed. This can happen for any login attempt. 690 task_runner_->PostTask( 691 FROM_HERE, 692 base::Bind(&CryptohomeAuthenticator::OnAuthFailure, 693 this, 694 AuthFailure(AuthFailure::USERNAME_HASH_FAILED))); 695 break; 696 case REMOVED_DATA_AFTER_FAILURE: 697 remove_user_data_on_failure_ = false; 698 task_runner_->PostTask(FROM_HERE, 699 base::Bind(&CryptohomeAuthenticator::OnAuthFailure, 700 this, 701 *delayed_login_failure_)); 702 break; 703 case CREATE_NEW: 704 create_if_nonexistent = true; 705 case RECOVER_MOUNT: 706 current_state_->ResetCryptohomeStatus(); 707 StartMount(current_state_.get(), 708 scoped_refptr<CryptohomeAuthenticator>(this), 709 false /*ephemeral*/, 710 create_if_nonexistent); 711 break; 712 case NEED_OLD_PW: 713 task_runner_->PostTask( 714 FROM_HERE, 715 base::Bind(&CryptohomeAuthenticator::OnPasswordChangeDetected, this)); 716 break; 717 case ONLINE_FAILED: 718 case NEED_NEW_PW: 719 case HAVE_NEW_PW: 720 NOTREACHED() << "Using obsolete ClientLogin code path."; 721 break; 722 case OFFLINE_LOGIN: 723 VLOG(2) << "Offline login"; 724 // Fall through. 725 case UNLOCK: 726 VLOG(2) << "Unlock"; 727 // Fall through. 728 case ONLINE_LOGIN: 729 VLOG(2) << "Online login"; 730 task_runner_->PostTask( 731 FROM_HERE, base::Bind(&CryptohomeAuthenticator::OnAuthSuccess, this)); 732 break; 733 case DEMO_LOGIN: 734 VLOG(2) << "Retail mode login"; 735 current_state_->user_context.SetIsUsingOAuth(false); 736 task_runner_->PostTask( 737 FROM_HERE, 738 base::Bind(&CryptohomeAuthenticator::OnRetailModeAuthSuccess, this)); 739 break; 740 case GUEST_LOGIN: 741 task_runner_->PostTask( 742 FROM_HERE, 743 base::Bind(&CryptohomeAuthenticator::OnOffTheRecordAuthSuccess, 744 this)); 745 break; 746 case KIOSK_ACCOUNT_LOGIN: 747 case PUBLIC_ACCOUNT_LOGIN: 748 current_state_->user_context.SetIsUsingOAuth(false); 749 task_runner_->PostTask( 750 FROM_HERE, base::Bind(&CryptohomeAuthenticator::OnAuthSuccess, this)); 751 break; 752 case SUPERVISED_USER_LOGIN: 753 current_state_->user_context.SetIsUsingOAuth(false); 754 task_runner_->PostTask( 755 FROM_HERE, base::Bind(&CryptohomeAuthenticator::OnAuthSuccess, this)); 756 break; 757 case LOGIN_FAILED: 758 current_state_->ResetCryptohomeStatus(); 759 task_runner_->PostTask(FROM_HERE, 760 base::Bind(&CryptohomeAuthenticator::OnAuthFailure, 761 this, 762 current_state_->online_outcome())); 763 break; 764 case OWNER_REQUIRED: { 765 current_state_->ResetCryptohomeStatus(); 766 bool success = false; 767 DBusThreadManager::Get()->GetCryptohomeClient()->Unmount(&success); 768 if (!success) { 769 // Maybe we should reboot immediately here? 770 LOG(ERROR) << "Couldn't unmount users home!"; 771 } 772 task_runner_->PostTask( 773 FROM_HERE, 774 base::Bind(&CryptohomeAuthenticator::OnAuthFailure, 775 this, 776 AuthFailure(AuthFailure::OWNER_REQUIRED))); 777 break; 778 } 779 default: 780 NOTREACHED(); 781 break; 782 } 783} 784 785CryptohomeAuthenticator::~CryptohomeAuthenticator() { 786} 787 788CryptohomeAuthenticator::AuthState CryptohomeAuthenticator::ResolveState() { 789 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 790 // If we haven't mounted the user's home dir yet or 791 // haven't got sanitized username value, we can't be done. 792 // We never get past here if any of these two cryptohome ops is still pending. 793 // This is an important invariant. 794 if (!current_state_->cryptohome_complete() || 795 !current_state_->username_hash_obtained()) { 796 return CONTINUE; 797 } 798 799 AuthState state = CONTINUE; 800 801 if (current_state_->cryptohome_outcome() && 802 current_state_->username_hash_valid()) { 803 state = ResolveCryptohomeSuccessState(); 804 } else { 805 state = ResolveCryptohomeFailureState(); 806 } 807 808 DCHECK(current_state_->cryptohome_complete()); // Ensure invariant holds. 809 migrate_attempted_ = false; 810 remove_attempted_ = false; 811 resync_attempted_ = false; 812 ephemeral_mount_attempted_ = false; 813 check_key_attempted_ = false; 814 815 if (state != POSSIBLE_PW_CHANGE && state != NO_MOUNT && 816 state != OFFLINE_LOGIN) 817 return state; 818 819 if (current_state_->online_complete()) { 820 if (current_state_->online_outcome().reason() == AuthFailure::NONE) { 821 // Online attempt succeeded as well, so combine the results. 822 return ResolveOnlineSuccessState(state); 823 } 824 NOTREACHED() << "Using obsolete ClientLogin code path."; 825 } 826 // if online isn't complete yet, just return the offline result. 827 return state; 828} 829 830CryptohomeAuthenticator::AuthState 831CryptohomeAuthenticator::ResolveCryptohomeFailureState() { 832 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 833 if (remove_attempted_ || resync_attempted_) 834 return FAILED_REMOVE; 835 if (ephemeral_mount_attempted_) 836 return FAILED_TMPFS; 837 if (migrate_attempted_) 838 return NEED_OLD_PW; 839 if (check_key_attempted_) 840 return LOGIN_FAILED; 841 842 if (current_state_->cryptohome_code() == 843 cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) { 844 // Critical TPM error detected, reboot needed. 845 return FAILED_TPM; 846 } 847 848 // Return intermediate states in the following case: 849 // when there is an online result to use; 850 // This is the case after user finishes Gaia login; 851 if (current_state_->online_complete()) { 852 if (current_state_->cryptohome_code() == 853 cryptohome::MOUNT_ERROR_KEY_FAILURE) { 854 // If we tried a mount but they used the wrong key, we may need to 855 // ask the user for her old password. We'll only know once we've 856 // done the online check. 857 return POSSIBLE_PW_CHANGE; 858 } 859 if (current_state_->cryptohome_code() == 860 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST) { 861 // If we tried a mount but the user did not exist, then we should wait 862 // for online login to succeed and try again with the "create" flag set. 863 return NO_MOUNT; 864 } 865 } 866 867 if (!current_state_->username_hash_valid()) 868 return FAILED_USERNAME_HASH; 869 870 return FAILED_MOUNT; 871} 872 873CryptohomeAuthenticator::AuthState 874CryptohomeAuthenticator::ResolveCryptohomeSuccessState() { 875 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 876 if (resync_attempted_) 877 return CREATE_NEW; 878 if (remove_attempted_) 879 return REMOVED_DATA_AFTER_FAILURE; 880 if (migrate_attempted_) 881 return RECOVER_MOUNT; 882 if (check_key_attempted_) 883 return UNLOCK; 884 885 if (current_state_->user_type == user_manager::USER_TYPE_GUEST) 886 return GUEST_LOGIN; 887 if (current_state_->user_type == user_manager::USER_TYPE_RETAIL_MODE) 888 return DEMO_LOGIN; 889 if (current_state_->user_type == user_manager::USER_TYPE_PUBLIC_ACCOUNT) 890 return PUBLIC_ACCOUNT_LOGIN; 891 if (current_state_->user_type == user_manager::USER_TYPE_KIOSK_APP) 892 return KIOSK_ACCOUNT_LOGIN; 893 if (current_state_->user_type == user_manager::USER_TYPE_SUPERVISED) 894 return SUPERVISED_USER_LOGIN; 895 896 if (!VerifyOwner()) 897 return CONTINUE; 898 return user_can_login_ ? OFFLINE_LOGIN : OWNER_REQUIRED; 899} 900 901CryptohomeAuthenticator::AuthState 902CryptohomeAuthenticator::ResolveOnlineSuccessState( 903 CryptohomeAuthenticator::AuthState offline_state) { 904 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 905 switch (offline_state) { 906 case POSSIBLE_PW_CHANGE: 907 return NEED_OLD_PW; 908 case NO_MOUNT: 909 return CREATE_NEW; 910 case OFFLINE_LOGIN: 911 return ONLINE_LOGIN; 912 default: 913 NOTREACHED(); 914 return offline_state; 915 } 916} 917 918void CryptohomeAuthenticator::ResolveLoginCompletionStatus() { 919 // Shortcut online state resolution process. 920 current_state_->RecordOnlineLoginStatus(AuthFailure::AuthFailureNone()); 921 Resolve(); 922} 923 924void CryptohomeAuthenticator::SetOwnerState(bool owner_check_finished, 925 bool check_result) { 926 owner_is_verified_ = owner_check_finished; 927 user_can_login_ = check_result; 928} 929 930} // namespace chromeos 931