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.
5 #include "chromeos/login/auth/cryptohome_authenticator.h"
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"
33 // The label used for the key derived from the user's GAIA credentials.
34 const char kCryptohomeGAIAKeyLabel[] = "gaia";
36 // The name under which the type of key generated from the user's GAIA
37 // credentials is stored.
38 const char kKeyProviderDataTypeName[] = "type";
40 // The name under which the salt used to generate a key from the user's GAIA
41 // credentials is stored.
42 const char kKeyProviderDataSaltName[] = "salt";
44 // Hashes |key| with |system_salt| if it its type is KEY_TYPE_PASSWORD_PLAIN.
45 // Returns the keys unmodified otherwise.
46 scoped_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);
55 // Records status and calls resolver->Resolve().
56 void TriggerResolve(AuthAttemptState* attempt,
57 scoped_refptr<CryptohomeAuthenticator> resolver,
59 cryptohome::MountError return_code) {
60 attempt->RecordCryptohomeStatus(success, return_code);
64 // Records get hash status and calls resolver->Resolve().
65 void TriggerResolveHash(AuthAttemptState* attempt,
66 scoped_refptr<CryptohomeAuthenticator> resolver,
68 const std::string& username_hash) {
70 attempt->RecordUsernameHash(username_hash);
72 attempt->RecordUsernameHashFailed();
76 // Calls TriggerResolve while adding login time marker.
77 void TriggerResolveWithLoginTimeMarker(
78 const std::string& marker_name,
79 AuthAttemptState* attempt,
80 scoped_refptr<CryptohomeAuthenticator> resolver,
82 cryptohome::MountError return_code) {
83 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(marker_name, false);
84 TriggerResolve(attempt, resolver, success, return_code);
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.
89 void RecordKeyErrorAndResolve(AuthAttemptState* attempt,
90 scoped_refptr<CryptohomeAuthenticator> resolver) {
91 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker("CryptohomeMount-End",
93 attempt->RecordCryptohomeStatus(false /* success */,
94 cryptohome::MOUNT_ERROR_KEY_FAILURE);
98 // Callback invoked when cryptohome's MountEx() method has finished.
99 void OnMount(AuthAttemptState* attempt,
100 scoped_refptr<CryptohomeAuthenticator> resolver,
102 cryptohome::MountError return_code,
103 const std::string& mount_hash) {
104 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker("CryptohomeMount-End",
106 attempt->RecordCryptohomeStatus(success, return_code);
108 attempt->RecordUsernameHash(mount_hash);
110 attempt->RecordUsernameHashFailed();
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.
118 void DoMount(AuthAttemptState* attempt,
119 scoped_refptr<CryptohomeAuthenticator> resolver,
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());
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();
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(),
138 cryptohome::PRIV_DEFAULT);
139 cryptohome::MountParameters mount(ephemeral);
140 if (create_if_nonexistent) {
141 mount.create_keys.push_back(cryptohome::KeyDefinition(
143 kCryptohomeGAIAKeyLabel,
144 cryptohome::PRIV_DEFAULT));
147 cryptohome::HomedirMethods::GetInstance()->MountEx(
148 cryptohome::Identification(attempt->user_context.GetUserID()),
149 cryptohome::Authorization(auth_key),
151 base::Bind(&OnMount, attempt, resolver));
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().
157 void OnGetSystemSalt(AuthAttemptState* attempt,
158 scoped_refptr<CryptohomeAuthenticator> resolver,
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());
165 attempt->user_context.GetKey()->Transform(
166 Key::KEY_TYPE_SALTED_SHA256_TOP_HALF,
169 DoMount(attempt, resolver, ephemeral, create_if_nonexistent);
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().
181 AuthAttemptState* attempt,
182 scoped_refptr<CryptohomeAuthenticator> resolver,
184 bool create_if_nonexistent,
186 cryptohome::MountError return_code,
187 const std::vector<cryptohome::KeyDefinition>& key_definitions) {
189 if (key_definitions.size() == 1) {
190 const cryptohome::KeyDefinition& key_definition = key_definitions.front();
191 DCHECK_EQ(kCryptohomeGAIAKeyLabel, key_definition.label);
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) {
201 type.reset(new int64(*it->number));
204 } else if (it->name == kKeyProviderDataSaltName) {
206 salt.reset(new std::string(*it->bytes));
213 if (*type < 0 || *type >= Key::KEY_TYPE_COUNT) {
214 LOG(ERROR) << "Invalid key type: " << *type;
215 RecordKeyErrorAndResolve(attempt, resolver);
220 LOG(ERROR) << "Missing salt.";
221 RecordKeyErrorAndResolve(attempt, resolver);
225 attempt->user_context.GetKey()->Transform(
226 static_cast<Key::KeyType>(*type),
228 DoMount(attempt, resolver, ephemeral, create_if_nonexistent);
232 LOG(ERROR) << "GetKeyDataEx() returned " << key_definitions.size()
237 SystemSaltGetter::Get()->GetSystemSalt(base::Bind(&OnGetSystemSalt,
241 create_if_nonexistent));
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().
252 void StartMount(AuthAttemptState* attempt,
253 scoped_refptr<CryptohomeAuthenticator> resolver,
255 bool create_if_nonexistent) {
256 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(
257 "CryptohomeMount-Start", false);
259 if (attempt->user_context.GetKey()->GetKeyType() !=
260 Key::KEY_TYPE_PASSWORD_PLAIN) {
261 DoMount(attempt, resolver, ephemeral, create_if_nonexistent);
265 cryptohome::HomedirMethods::GetInstance()->GetKeyDataEx(
266 cryptohome::Identification(attempt->user_context.GetUserID()),
267 kCryptohomeGAIAKeyLabel,
268 base::Bind(&OnGetKeyDataEx,
272 create_if_nonexistent));
275 // Calls cryptohome's mount method for guest and also get the user hash from
277 void MountGuestAndGetHash(AuthAttemptState* attempt,
278 scoped_refptr<CryptohomeAuthenticator> resolver) {
279 attempt->UsernameHashRequested();
280 cryptohome::AsyncMethodCaller::GetInstance()->AsyncMountGuest(
281 base::Bind(&TriggerResolveWithLoginTimeMarker,
282 "CryptohomeMount-End",
285 cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername(
286 attempt->user_context.GetUserID(),
287 base::Bind(&TriggerResolveHash, attempt, resolver));
290 // Calls cryptohome's MountPublic method
291 void MountPublic(AuthAttemptState* attempt,
292 scoped_refptr<CryptohomeAuthenticator> resolver,
294 cryptohome::AsyncMethodCaller::GetInstance()->AsyncMountPublic(
295 attempt->user_context.GetUserID(),
297 base::Bind(&TriggerResolveWithLoginTimeMarker,
298 "CryptohomeMountPublic-End",
301 cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername(
302 attempt->user_context.GetUserID(),
303 base::Bind(&TriggerResolveHash, attempt, resolver));
306 // Calls cryptohome's key migration method.
307 void 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();
317 // TODO(bartfab): Retrieve the hashing algorithm and salt to use for |old_key|
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",
332 caller->AsyncMigrateKey(attempt->user_context.GetUserID(),
333 new_key->GetSecret(),
334 old_key->GetSecret(),
335 base::Bind(&TriggerResolveWithLoginTimeMarker,
336 "CryptohomeMount-End",
342 // Calls cryptohome's remove method.
343 void 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",
355 // Calls cryptohome's key check method.
356 void 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(),
364 base::Bind(&TriggerResolve, attempt, resolver));
369 CryptohomeAuthenticator::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) {
386 void CryptohomeAuthenticator::AuthenticateToLogin(
388 const UserContext& user_context) {
389 authentication_profile_ = profile;
390 current_state_.reset(new AuthAttemptState(user_context,
391 user_manager::USER_TYPE_REGULAR,
393 false, // online_complete
394 !IsKnownUser(user_context)));
395 // Reset the verified flag.
396 owner_is_verified_ = false;
398 StartMount(current_state_.get(),
399 scoped_refptr<CryptohomeAuthenticator>(this),
400 false /* ephemeral */,
401 false /* create_if_nonexistent */);
404 void 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,
410 false, // online_complete
411 !IsKnownUser(user_context)));
413 // Reset the verified flag.
414 owner_is_verified_ = false;
416 StartMount(current_state_.get(),
417 scoped_refptr<CryptohomeAuthenticator>(this),
418 false /* ephemeral */,
419 false /* create_if_nonexistent */);
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
424 task_runner_->PostTask(
426 base::Bind(&CryptohomeAuthenticator::ResolveLoginCompletionStatus, this));
429 void CryptohomeAuthenticator::AuthenticateToUnlock(
430 const UserContext& user_context) {
431 current_state_.reset(new AuthAttemptState(user_context,
432 user_manager::USER_TYPE_REGULAR,
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)));
444 void 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,
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 */);
460 void CryptohomeAuthenticator::LoginRetailMode() {
461 DCHECK(task_runner_->RunsTasksOnCurrentThread());
462 // Note: |kRetailModeUserEMail| is used in other places to identify a retail
464 current_state_.reset(
465 new AuthAttemptState(UserContext(chromeos::login::kRetailModeUserName),
466 user_manager::USER_TYPE_RETAIL_MODE,
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));
476 void CryptohomeAuthenticator::LoginOffTheRecord() {
477 DCHECK(task_runner_->RunsTasksOnCurrentThread());
478 current_state_.reset(
479 new AuthAttemptState(UserContext(chromeos::login::kGuestUserName),
480 user_manager::USER_TYPE_GUEST,
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));
490 void 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,
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 */);
507 void CryptohomeAuthenticator::LoginAsKioskAccount(
508 const std::string& app_user_id,
509 bool use_guest_mount) {
510 DCHECK(task_runner_->RunsTasksOnCurrentThread());
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,
517 false, // online_complete
518 false)); // user_is_new
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);
526 ephemeral_mount_attempted_ = true;
527 MountGuestAndGetHash(current_state_.get(),
528 scoped_refptr<CryptohomeAuthenticator>(this));
532 void CryptohomeAuthenticator::OnRetailModeAuthSuccess() {
533 DCHECK(task_runner_->RunsTasksOnCurrentThread());
534 VLOG(1) << "Retail mode login success";
535 chromeos::LoginEventRecorder::Get()->RecordAuthenticationSuccess();
537 consumer_->OnRetailModeAuthSuccess(current_state_->user_context);
540 void CryptohomeAuthenticator::OnAuthSuccess() {
541 DCHECK(task_runner_->RunsTasksOnCurrentThread());
542 VLOG(1) << "Login success";
543 // Send notification of success
544 chromeos::LoginEventRecorder::Get()->RecordAuthenticationSuccess();
546 base::AutoLock for_this_block(success_lock_);
547 already_reported_success_ = true;
550 consumer_->OnAuthSuccess(current_state_->user_context);
553 void CryptohomeAuthenticator::OnOffTheRecordAuthSuccess() {
554 DCHECK(task_runner_->RunsTasksOnCurrentThread());
555 chromeos::LoginEventRecorder::Get()->RecordAuthenticationSuccess();
557 consumer_->OnOffTheRecordAuthSuccess();
560 void CryptohomeAuthenticator::OnPasswordChangeDetected() {
561 DCHECK(task_runner_->RunsTasksOnCurrentThread());
563 consumer_->OnPasswordChangeDetected();
566 void CryptohomeAuthenticator::OnAuthFailure(const AuthFailure& error) {
567 DCHECK(task_runner_->RunsTasksOnCurrentThread());
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();
576 chromeos::LoginEventRecorder::Get()->RecordAuthenticationFailure();
577 LOG(WARNING) << "Login failed: " << error.GetErrorString();
579 consumer_->OnAuthFailure(error);
582 void CryptohomeAuthenticator::RecoverEncryptedData(
583 const std::string& old_password) {
584 migrate_attempted_ = true;
585 current_state_->ResetCryptohomeStatus();
586 SystemSaltGetter::Get()->GetSystemSalt(
588 current_state_.get(),
589 scoped_refptr<CryptohomeAuthenticator>(this),
594 void CryptohomeAuthenticator::RemoveEncryptedData() {
595 remove_attempted_ = true;
596 current_state_->ResetCryptohomeStatus();
597 task_runner_->PostTask(
600 current_state_.get(),
601 scoped_refptr<CryptohomeAuthenticator>(this)));
604 void CryptohomeAuthenticator::ResyncEncryptedData() {
605 resync_attempted_ = true;
606 current_state_->ResetCryptohomeStatus();
607 task_runner_->PostTask(
610 current_state_.get(),
611 scoped_refptr<CryptohomeAuthenticator>(this)));
614 bool CryptohomeAuthenticator::VerifyOwner() {
615 if (owner_is_verified_)
617 // Check if policy data is fine and continue in safe mode if needed.
619 // Now we can continue with the login and report mount success.
620 user_can_login_ = true;
621 owner_is_verified_ = true;
625 CheckSafeModeOwnership(
626 current_state_->user_context,
627 base::Bind(&CryptohomeAuthenticator::OnOwnershipChecked, this));
631 void 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;
638 void 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;
645 case POSSIBLE_PW_CHANGE:
647 // These are intermediate states; we need more info from a request that
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(
656 base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
658 AuthFailure(AuthFailure::COULD_NOT_MOUNT_CRYPTOHOME)));
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(
666 base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
668 AuthFailure(AuthFailure::DATA_REMOVAL_FAILED)));
671 // In this case, we tried to mount a tmpfs for guest and failed.
672 task_runner_->PostTask(
674 base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
676 AuthFailure(AuthFailure::COULD_NOT_MOUNT_TMPFS)));
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,
685 AuthFailure(AuthFailure::TPM_ERROR)));
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(
692 base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
694 AuthFailure(AuthFailure::USERNAME_HASH_FAILED)));
696 case REMOVED_DATA_AFTER_FAILURE:
697 remove_user_data_on_failure_ = false;
698 task_runner_->PostTask(FROM_HERE,
699 base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
701 *delayed_login_failure_));
704 create_if_nonexistent = true;
706 current_state_->ResetCryptohomeStatus();
707 StartMount(current_state_.get(),
708 scoped_refptr<CryptohomeAuthenticator>(this),
710 create_if_nonexistent);
713 task_runner_->PostTask(
715 base::Bind(&CryptohomeAuthenticator::OnPasswordChangeDetected, this));
720 NOTREACHED() << "Using obsolete ClientLogin code path.";
723 VLOG(2) << "Offline login";
729 VLOG(2) << "Online login";
730 task_runner_->PostTask(
731 FROM_HERE, base::Bind(&CryptohomeAuthenticator::OnAuthSuccess, this));
734 VLOG(2) << "Retail mode login";
735 current_state_->user_context.SetIsUsingOAuth(false);
736 task_runner_->PostTask(
738 base::Bind(&CryptohomeAuthenticator::OnRetailModeAuthSuccess, this));
741 task_runner_->PostTask(
743 base::Bind(&CryptohomeAuthenticator::OnOffTheRecordAuthSuccess,
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));
752 case SUPERVISED_USER_LOGIN:
753 current_state_->user_context.SetIsUsingOAuth(false);
754 task_runner_->PostTask(
755 FROM_HERE, base::Bind(&CryptohomeAuthenticator::OnAuthSuccess, this));
758 current_state_->ResetCryptohomeStatus();
759 task_runner_->PostTask(FROM_HERE,
760 base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
762 current_state_->online_outcome()));
764 case OWNER_REQUIRED: {
765 current_state_->ResetCryptohomeStatus();
766 bool success = false;
767 DBusThreadManager::Get()->GetCryptohomeClient()->Unmount(&success);
769 // Maybe we should reboot immediately here?
770 LOG(ERROR) << "Couldn't unmount users home!";
772 task_runner_->PostTask(
774 base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
776 AuthFailure(AuthFailure::OWNER_REQUIRED)));
785 CryptohomeAuthenticator::~CryptohomeAuthenticator() {
788 CryptohomeAuthenticator::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()) {
799 AuthState state = CONTINUE;
801 if (current_state_->cryptohome_outcome() &&
802 current_state_->username_hash_valid()) {
803 state = ResolveCryptohomeSuccessState();
805 state = ResolveCryptohomeFailureState();
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;
815 if (state != POSSIBLE_PW_CHANGE && state != NO_MOUNT &&
816 state != OFFLINE_LOGIN)
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);
824 NOTREACHED() << "Using obsolete ClientLogin code path.";
826 // if online isn't complete yet, just return the offline result.
830 CryptohomeAuthenticator::AuthState
831 CryptohomeAuthenticator::ResolveCryptohomeFailureState() {
832 DCHECK(task_runner_->RunsTasksOnCurrentThread());
833 if (remove_attempted_ || resync_attempted_)
834 return FAILED_REMOVE;
835 if (ephemeral_mount_attempted_)
837 if (migrate_attempted_)
839 if (check_key_attempted_)
842 if (current_state_->cryptohome_code() ==
843 cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) {
844 // Critical TPM error detected, reboot needed.
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;
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.
867 if (!current_state_->username_hash_valid())
868 return FAILED_USERNAME_HASH;
873 CryptohomeAuthenticator::AuthState
874 CryptohomeAuthenticator::ResolveCryptohomeSuccessState() {
875 DCHECK(task_runner_->RunsTasksOnCurrentThread());
876 if (resync_attempted_)
878 if (remove_attempted_)
879 return REMOVED_DATA_AFTER_FAILURE;
880 if (migrate_attempted_)
881 return RECOVER_MOUNT;
882 if (check_key_attempted_)
885 if (current_state_->user_type == user_manager::USER_TYPE_GUEST)
887 if (current_state_->user_type == user_manager::USER_TYPE_RETAIL_MODE)
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;
898 return user_can_login_ ? OFFLINE_LOGIN : OWNER_REQUIRED;
901 CryptohomeAuthenticator::AuthState
902 CryptohomeAuthenticator::ResolveOnlineSuccessState(
903 CryptohomeAuthenticator::AuthState offline_state) {
904 DCHECK(task_runner_->RunsTasksOnCurrentThread());
905 switch (offline_state) {
906 case POSSIBLE_PW_CHANGE:
914 return offline_state;
918 void CryptohomeAuthenticator::ResolveLoginCompletionStatus() {
919 // Shortcut online state resolution process.
920 current_state_->RecordOnlineLoginStatus(AuthFailure::AuthFailureNone());
924 void CryptohomeAuthenticator::SetOwnerState(bool owner_check_finished,
926 owner_is_verified_ = owner_check_finished;
927 user_can_login_ = check_result;
930 } // namespace chromeos