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"
7 #include "base/basictypes.h"
9 #include "base/files/file_path.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "chromeos/cryptohome/async_method_caller.h"
13 #include "chromeos/cryptohome/cryptohome_parameters.h"
14 #include "chromeos/cryptohome/homedir_methods.h"
15 #include "chromeos/cryptohome/system_salt_getter.h"
16 #include "chromeos/dbus/cryptohome_client.h"
17 #include "chromeos/dbus/dbus_thread_manager.h"
18 #include "chromeos/login/auth/auth_status_consumer.h"
19 #include "chromeos/login/auth/key.h"
20 #include "chromeos/login/auth/user_context.h"
21 #include "chromeos/login/login_state.h"
22 #include "chromeos/login/user_names.h"
23 #include "chromeos/login_event_recorder.h"
24 #include "components/user_manager/user_type.h"
25 #include "third_party/cros_system_api/dbus/service_constants.h"
31 // The label used for the key derived from the user's GAIA credentials.
32 const char kCryptohomeGAIAKeyLabel
[] = "gaia";
34 // The name under which the type of key generated from the user's GAIA
35 // credentials is stored.
36 const char kKeyProviderDataTypeName
[] = "type";
38 // The name under which the salt used to generate a key from the user's GAIA
39 // credentials is stored.
40 const char kKeyProviderDataSaltName
[] = "salt";
42 // Hashes |key| with |system_salt| if it its type is KEY_TYPE_PASSWORD_PLAIN.
43 // Returns the keys unmodified otherwise.
44 scoped_ptr
<Key
> TransformKeyIfNeeded(const Key
& key
,
45 const std::string
& system_salt
) {
46 scoped_ptr
<Key
> result(new Key(key
));
47 if (result
->GetKeyType() == Key::KEY_TYPE_PASSWORD_PLAIN
)
48 result
->Transform(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF
, system_salt
);
53 // Records status and calls resolver->Resolve().
54 void TriggerResolve(AuthAttemptState
* attempt
,
55 scoped_refptr
<CryptohomeAuthenticator
> resolver
,
57 cryptohome::MountError return_code
) {
58 attempt
->RecordCryptohomeStatus(success
, return_code
);
62 // Records get hash status and calls resolver->Resolve().
63 void TriggerResolveHash(AuthAttemptState
* attempt
,
64 scoped_refptr
<CryptohomeAuthenticator
> resolver
,
66 const std::string
& username_hash
) {
68 attempt
->RecordUsernameHash(username_hash
);
70 attempt
->RecordUsernameHashFailed();
74 // Calls TriggerResolve while adding login time marker.
75 void TriggerResolveWithLoginTimeMarker(
76 const std::string
& marker_name
,
77 AuthAttemptState
* attempt
,
78 scoped_refptr
<CryptohomeAuthenticator
> resolver
,
80 cryptohome::MountError return_code
) {
81 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(marker_name
, false);
82 TriggerResolve(attempt
, resolver
, success
, return_code
);
85 // Records an error in accessing the user's cryptohome with the given key and
86 // calls resolver->Resolve() after adding a login time marker.
87 void RecordKeyErrorAndResolve(AuthAttemptState
* attempt
,
88 scoped_refptr
<CryptohomeAuthenticator
> resolver
) {
89 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker("CryptohomeMount-End",
91 attempt
->RecordCryptohomeStatus(false /* success */,
92 cryptohome::MOUNT_ERROR_KEY_FAILURE
);
96 // Callback invoked when cryptohome's MountEx() method has finished.
97 void OnMount(AuthAttemptState
* attempt
,
98 scoped_refptr
<CryptohomeAuthenticator
> resolver
,
100 cryptohome::MountError return_code
,
101 const std::string
& mount_hash
) {
102 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker("CryptohomeMount-End",
104 attempt
->RecordCryptohomeStatus(success
, return_code
);
106 attempt
->RecordUsernameHash(mount_hash
);
108 attempt
->RecordUsernameHashFailed();
112 // Calls cryptohome's MountEx() method. The key in |attempt->user_context| must
113 // not be a plain text password. If the user provided a plain text password,
114 // that password must be transformed to another key type (by salted hashing)
115 // before calling this method.
116 void DoMount(AuthAttemptState
* attempt
,
117 scoped_refptr
<CryptohomeAuthenticator
> resolver
,
119 bool create_if_nonexistent
) {
120 const Key
* key
= attempt
->user_context
.GetKey();
121 // If the |key| is a plain text password, crash rather than attempting to
122 // mount the cryptohome with a plain text password.
123 CHECK_NE(Key::KEY_TYPE_PASSWORD_PLAIN
, key
->GetKeyType());
125 // Set state that username_hash is requested here so that test implementation
126 // that returns directly would not generate 2 OnLoginSucces() calls.
127 attempt
->UsernameHashRequested();
129 // Set the authentication's key label to an empty string, which is a wildcard
130 // allowing any key to match. This is necessary because cryptohomes created by
131 // Chrome OS M38 and older will have a legacy key with no label while those
132 // created by Chrome OS M39 and newer will have a key with the label
133 // kCryptohomeGAIAKeyLabel.
134 const cryptohome::KeyDefinition
auth_key(key
->GetSecret(),
136 cryptohome::PRIV_DEFAULT
);
137 cryptohome::MountParameters
mount(ephemeral
);
138 if (create_if_nonexistent
) {
139 mount
.create_keys
.push_back(cryptohome::KeyDefinition(
141 kCryptohomeGAIAKeyLabel
,
142 cryptohome::PRIV_DEFAULT
));
145 cryptohome::HomedirMethods::GetInstance()->MountEx(
146 cryptohome::Identification(attempt
->user_context
.GetUserID()),
147 cryptohome::Authorization(auth_key
),
149 base::Bind(&OnMount
, attempt
, resolver
));
152 // Callback invoked when the system salt has been retrieved. Transforms the key
153 // in |attempt->user_context| using Chrome's default hashing algorithm and the
154 // system salt, then calls MountEx().
155 void OnGetSystemSalt(AuthAttemptState
* attempt
,
156 scoped_refptr
<CryptohomeAuthenticator
> resolver
,
158 bool create_if_nonexistent
,
159 const std::string
& system_salt
) {
160 DCHECK_EQ(Key::KEY_TYPE_PASSWORD_PLAIN
,
161 attempt
->user_context
.GetKey()->GetKeyType());
163 attempt
->user_context
.GetKey()->Transform(
164 Key::KEY_TYPE_SALTED_SHA256_TOP_HALF
,
167 DoMount(attempt
, resolver
, ephemeral
, create_if_nonexistent
);
170 // Callback invoked when cryptohome's GetKeyDataEx() method has finished.
171 // * If GetKeyDataEx() returned metadata indicating the hashing algorithm and
172 // salt that were used to generate the key for this user's cryptohome,
173 // transforms the key in |attempt->user_context| with the same parameters.
174 // * Otherwise, starts the retrieval of the system salt so that the key in
175 // |attempt->user_context| can be transformed with Chrome's default hashing
176 // algorithm and the system salt.
177 // The resulting key is then passed to cryptohome's MountEx().
178 void OnGetKeyDataEx(AuthAttemptState
* attempt
,
179 scoped_refptr
<CryptohomeAuthenticator
> resolver
,
181 bool create_if_nonexistent
,
183 cryptohome::MountError return_code
,
184 ScopedVector
<cryptohome::RetrievedKeyData
> key_data
) {
186 if (key_data
.size() == 1) {
187 cryptohome::RetrievedKeyData
* key_data_entry
= key_data
.front();
188 DCHECK_EQ(kCryptohomeGAIAKeyLabel
, key_data_entry
->label
);
190 // Extract the key type and salt from |key_data|, if present.
191 scoped_ptr
<int64
> type
;
192 scoped_ptr
<std::string
> salt
;
193 for (ScopedVector
<cryptohome::RetrievedKeyData::ProviderData
>::
194 const_iterator it
= key_data_entry
->provider_data
.begin();
195 it
!= key_data_entry
->provider_data
.end(); ++it
) {
196 if ((*it
)->name
== kKeyProviderDataTypeName
) {
198 type
.reset(new int64(*(*it
)->number
));
201 } else if ((*it
)->name
== kKeyProviderDataSaltName
) {
203 salt
.reset(new std::string(*(*it
)->bytes
));
210 if (*type
< 0 || *type
>= Key::KEY_TYPE_COUNT
) {
211 LOG(ERROR
) << "Invalid key type: " << *type
;
212 RecordKeyErrorAndResolve(attempt
, resolver
);
217 LOG(ERROR
) << "Missing salt.";
218 RecordKeyErrorAndResolve(attempt
, resolver
);
222 attempt
->user_context
.GetKey()->Transform(
223 static_cast<Key::KeyType
>(*type
),
225 DoMount(attempt
, resolver
, ephemeral
, create_if_nonexistent
);
229 LOG(ERROR
) << "GetKeyDataEx() returned " << key_data
.size()
234 SystemSaltGetter::Get()->GetSystemSalt(base::Bind(&OnGetSystemSalt
,
238 create_if_nonexistent
));
241 // Starts the process that will mount a user's cryptohome.
242 // * If the key in |attempt->user_context| is not a plain text password,
243 // cryptohome's MountEx() method is called directly with the key.
244 // * Otherwise, the key must be transformed (by salted hashing) before being
245 // passed to MountEx(). In that case, cryptohome's GetKeyDataEx() method is
246 // called to retrieve metadata indicating the hashing algorithm and salt that
247 // were used to generate the key for this user's cryptohome and the key is
248 // transformed accordingly before calling MountEx().
249 void StartMount(AuthAttemptState
* attempt
,
250 scoped_refptr
<CryptohomeAuthenticator
> resolver
,
252 bool create_if_nonexistent
) {
253 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(
254 "CryptohomeMount-Start", false);
256 if (attempt
->user_context
.GetKey()->GetKeyType() !=
257 Key::KEY_TYPE_PASSWORD_PLAIN
) {
258 DoMount(attempt
, resolver
, ephemeral
, create_if_nonexistent
);
262 cryptohome::HomedirMethods::GetInstance()->GetKeyDataEx(
263 cryptohome::Identification(attempt
->user_context
.GetUserID()),
264 kCryptohomeGAIAKeyLabel
,
265 base::Bind(&OnGetKeyDataEx
,
269 create_if_nonexistent
));
272 // Calls cryptohome's mount method for guest and also get the user hash from
274 void MountGuestAndGetHash(AuthAttemptState
* attempt
,
275 scoped_refptr
<CryptohomeAuthenticator
> resolver
) {
276 attempt
->UsernameHashRequested();
277 cryptohome::AsyncMethodCaller::GetInstance()->AsyncMountGuest(
278 base::Bind(&TriggerResolveWithLoginTimeMarker
,
279 "CryptohomeMount-End",
282 cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername(
283 attempt
->user_context
.GetUserID(),
284 base::Bind(&TriggerResolveHash
, attempt
, resolver
));
287 // Calls cryptohome's MountPublic method
288 void MountPublic(AuthAttemptState
* attempt
,
289 scoped_refptr
<CryptohomeAuthenticator
> resolver
,
291 cryptohome::AsyncMethodCaller::GetInstance()->AsyncMountPublic(
292 attempt
->user_context
.GetUserID(),
294 base::Bind(&TriggerResolveWithLoginTimeMarker
,
295 "CryptohomeMountPublic-End",
298 cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername(
299 attempt
->user_context
.GetUserID(),
300 base::Bind(&TriggerResolveHash
, attempt
, resolver
));
303 // Calls cryptohome's key migration method.
304 void Migrate(AuthAttemptState
* attempt
,
305 scoped_refptr
<CryptohomeAuthenticator
> resolver
,
306 bool passing_old_hash
,
307 const std::string
& old_password
,
308 const std::string
& system_salt
) {
309 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(
310 "CryptohomeMigrate-Start", false);
311 cryptohome::AsyncMethodCaller
* caller
=
312 cryptohome::AsyncMethodCaller::GetInstance();
314 // TODO(bartfab): Retrieve the hashing algorithm and salt to use for |old_key|
316 scoped_ptr
<Key
> old_key
=
317 TransformKeyIfNeeded(Key(old_password
), system_salt
);
318 scoped_ptr
<Key
> new_key
=
319 TransformKeyIfNeeded(*attempt
->user_context
.GetKey(), system_salt
);
320 if (passing_old_hash
) {
321 caller
->AsyncMigrateKey(attempt
->user_context
.GetUserID(),
322 old_key
->GetSecret(),
323 new_key
->GetSecret(),
324 base::Bind(&TriggerResolveWithLoginTimeMarker
,
325 "CryptohomeMount-End",
329 caller
->AsyncMigrateKey(attempt
->user_context
.GetUserID(),
330 new_key
->GetSecret(),
331 old_key
->GetSecret(),
332 base::Bind(&TriggerResolveWithLoginTimeMarker
,
333 "CryptohomeMount-End",
339 // Calls cryptohome's remove method.
340 void Remove(AuthAttemptState
* attempt
,
341 scoped_refptr
<CryptohomeAuthenticator
> resolver
) {
342 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(
343 "CryptohomeRemove-Start", false);
344 cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove(
345 attempt
->user_context
.GetUserID(),
346 base::Bind(&TriggerResolveWithLoginTimeMarker
,
347 "CryptohomeRemove-End",
352 // Calls cryptohome's key check method.
353 void CheckKey(AuthAttemptState
* attempt
,
354 scoped_refptr
<CryptohomeAuthenticator
> resolver
,
355 const std::string
& system_salt
) {
356 scoped_ptr
<Key
> key
=
357 TransformKeyIfNeeded(*attempt
->user_context
.GetKey(), system_salt
);
358 cryptohome::AsyncMethodCaller::GetInstance()->AsyncCheckKey(
359 attempt
->user_context
.GetUserID(),
361 base::Bind(&TriggerResolve
, attempt
, resolver
));
366 CryptohomeAuthenticator::CryptohomeAuthenticator(
367 scoped_refptr
<base::TaskRunner
> task_runner
,
368 AuthStatusConsumer
* consumer
)
369 : Authenticator(consumer
),
370 task_runner_(task_runner
),
371 migrate_attempted_(false),
372 remove_attempted_(false),
373 resync_attempted_(false),
374 ephemeral_mount_attempted_(false),
375 check_key_attempted_(false),
376 already_reported_success_(false),
377 owner_is_verified_(false),
378 user_can_login_(false),
379 remove_user_data_on_failure_(false),
380 delayed_login_failure_(NULL
) {
383 void CryptohomeAuthenticator::AuthenticateToLogin(
385 const UserContext
& user_context
) {
386 authentication_profile_
= profile
;
387 current_state_
.reset(new AuthAttemptState(user_context
,
388 user_manager::USER_TYPE_REGULAR
,
390 false, // online_complete
391 !IsKnownUser(user_context
)));
392 // Reset the verified flag.
393 owner_is_verified_
= false;
395 StartMount(current_state_
.get(),
396 scoped_refptr
<CryptohomeAuthenticator
>(this),
397 false /* ephemeral */,
398 false /* create_if_nonexistent */);
401 void CryptohomeAuthenticator::CompleteLogin(Profile
* profile
,
402 const UserContext
& user_context
) {
403 authentication_profile_
= profile
;
404 current_state_
.reset(new AuthAttemptState(user_context
,
405 user_manager::USER_TYPE_REGULAR
,
407 false, // online_complete
408 !IsKnownUser(user_context
)));
410 // Reset the verified flag.
411 owner_is_verified_
= false;
413 StartMount(current_state_
.get(),
414 scoped_refptr
<CryptohomeAuthenticator
>(this),
415 false /* ephemeral */,
416 false /* create_if_nonexistent */);
418 // For login completion from extension, we just need to resolve the current
419 // auth attempt state, the rest of OAuth related tasks will be done in
421 task_runner_
->PostTask(
423 base::Bind(&CryptohomeAuthenticator::ResolveLoginCompletionStatus
, this));
426 void CryptohomeAuthenticator::AuthenticateToUnlock(
427 const UserContext
& user_context
) {
428 current_state_
.reset(new AuthAttemptState(user_context
,
429 user_manager::USER_TYPE_REGULAR
,
431 true, // online_complete
432 false)); // user_is_new
433 remove_user_data_on_failure_
= false;
434 check_key_attempted_
= true;
435 SystemSaltGetter::Get()->GetSystemSalt(
436 base::Bind(&CheckKey
,
437 current_state_
.get(),
438 scoped_refptr
<CryptohomeAuthenticator
>(this)));
441 void CryptohomeAuthenticator::LoginAsSupervisedUser(
442 const UserContext
& user_context
) {
443 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
444 // TODO(nkostylev): Pass proper value for |user_is_new| or remove (not used).
445 current_state_
.reset(new AuthAttemptState(user_context
,
446 user_manager::USER_TYPE_SUPERVISED
,
448 false, // online_complete
449 false)); // user_is_new
450 remove_user_data_on_failure_
= false;
451 StartMount(current_state_
.get(),
452 scoped_refptr
<CryptohomeAuthenticator
>(this),
453 false /* ephemeral */,
454 false /* create_if_nonexistent */);
457 void CryptohomeAuthenticator::LoginRetailMode() {
458 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
459 // Note: |kRetailModeUserEMail| is used in other places to identify a retail
461 current_state_
.reset(
462 new AuthAttemptState(UserContext(chromeos::login::kRetailModeUserName
),
463 user_manager::USER_TYPE_RETAIL_MODE
,
465 false, // online_complete
466 false)); // user_is_new
467 remove_user_data_on_failure_
= false;
468 ephemeral_mount_attempted_
= true;
469 MountGuestAndGetHash(current_state_
.get(),
470 scoped_refptr
<CryptohomeAuthenticator
>(this));
473 void CryptohomeAuthenticator::LoginOffTheRecord() {
474 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
475 current_state_
.reset(
476 new AuthAttemptState(UserContext(chromeos::login::kGuestUserName
),
477 user_manager::USER_TYPE_GUEST
,
479 false, // online_complete
480 false)); // user_is_new
481 remove_user_data_on_failure_
= false;
482 ephemeral_mount_attempted_
= true;
483 MountGuestAndGetHash(current_state_
.get(),
484 scoped_refptr
<CryptohomeAuthenticator
>(this));
487 void CryptohomeAuthenticator::LoginAsPublicSession(
488 const UserContext
& user_context
) {
489 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
490 current_state_
.reset(
491 new AuthAttemptState(user_context
,
492 user_manager::USER_TYPE_PUBLIC_ACCOUNT
,
494 false, // online_complete
495 false)); // user_is_new
496 remove_user_data_on_failure_
= false;
497 ephemeral_mount_attempted_
= true;
498 StartMount(current_state_
.get(),
499 scoped_refptr
<CryptohomeAuthenticator
>(this),
500 true /* ephemeral */,
501 true /* create_if_nonexistent */);
504 void CryptohomeAuthenticator::LoginAsKioskAccount(
505 const std::string
& app_user_id
,
506 bool use_guest_mount
) {
507 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
509 const std::string user_id
=
510 use_guest_mount
? chromeos::login::kGuestUserName
: app_user_id
;
511 current_state_
.reset(new AuthAttemptState(UserContext(user_id
),
512 user_manager::USER_TYPE_KIOSK_APP
,
514 false, // online_complete
515 false)); // user_is_new
517 remove_user_data_on_failure_
= true;
518 if (!use_guest_mount
) {
519 MountPublic(current_state_
.get(),
520 scoped_refptr
<CryptohomeAuthenticator
>(this),
521 cryptohome::CREATE_IF_MISSING
);
523 ephemeral_mount_attempted_
= true;
524 MountGuestAndGetHash(current_state_
.get(),
525 scoped_refptr
<CryptohomeAuthenticator
>(this));
529 void CryptohomeAuthenticator::OnRetailModeAuthSuccess() {
530 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
531 VLOG(1) << "Retail mode login success";
532 chromeos::LoginEventRecorder::Get()->RecordAuthenticationSuccess();
534 consumer_
->OnRetailModeAuthSuccess(current_state_
->user_context
);
537 void CryptohomeAuthenticator::OnAuthSuccess() {
538 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
539 VLOG(1) << "Login success";
540 // Send notification of success
541 chromeos::LoginEventRecorder::Get()->RecordAuthenticationSuccess();
543 base::AutoLock
for_this_block(success_lock_
);
544 already_reported_success_
= true;
547 consumer_
->OnAuthSuccess(current_state_
->user_context
);
550 void CryptohomeAuthenticator::OnOffTheRecordAuthSuccess() {
551 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
552 chromeos::LoginEventRecorder::Get()->RecordAuthenticationSuccess();
554 consumer_
->OnOffTheRecordAuthSuccess();
557 void CryptohomeAuthenticator::OnPasswordChangeDetected() {
558 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
560 consumer_
->OnPasswordChangeDetected();
563 void CryptohomeAuthenticator::OnAuthFailure(const AuthFailure
& error
) {
564 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
566 // OnAuthFailure will be called again with the same |error|
567 // after the cryptohome has been removed.
568 if (remove_user_data_on_failure_
) {
569 delayed_login_failure_
= &error
;
570 RemoveEncryptedData();
573 chromeos::LoginEventRecorder::Get()->RecordAuthenticationFailure();
574 LOG(WARNING
) << "Login failed: " << error
.GetErrorString();
576 consumer_
->OnAuthFailure(error
);
579 void CryptohomeAuthenticator::RecoverEncryptedData(
580 const std::string
& old_password
) {
581 migrate_attempted_
= true;
582 current_state_
->ResetCryptohomeStatus();
583 SystemSaltGetter::Get()->GetSystemSalt(
585 current_state_
.get(),
586 scoped_refptr
<CryptohomeAuthenticator
>(this),
591 void CryptohomeAuthenticator::RemoveEncryptedData() {
592 remove_attempted_
= true;
593 current_state_
->ResetCryptohomeStatus();
594 task_runner_
->PostTask(
597 current_state_
.get(),
598 scoped_refptr
<CryptohomeAuthenticator
>(this)));
601 void CryptohomeAuthenticator::ResyncEncryptedData() {
602 resync_attempted_
= true;
603 current_state_
->ResetCryptohomeStatus();
604 task_runner_
->PostTask(
607 current_state_
.get(),
608 scoped_refptr
<CryptohomeAuthenticator
>(this)));
611 bool CryptohomeAuthenticator::VerifyOwner() {
612 if (owner_is_verified_
)
614 // Check if policy data is fine and continue in safe mode if needed.
616 // Now we can continue with the login and report mount success.
617 user_can_login_
= true;
618 owner_is_verified_
= true;
622 CheckSafeModeOwnership(
623 current_state_
->user_context
,
624 base::Bind(&CryptohomeAuthenticator::OnOwnershipChecked
, this));
628 void CryptohomeAuthenticator::OnOwnershipChecked(bool is_owner
) {
629 // Now we can check if this user is the owner.
630 user_can_login_
= is_owner
;
631 owner_is_verified_
= true;
635 void CryptohomeAuthenticator::Resolve() {
636 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
637 bool create_if_nonexistent
= false;
638 CryptohomeAuthenticator::AuthState state
= ResolveState();
639 VLOG(1) << "Resolved state to: " << state
;
642 case POSSIBLE_PW_CHANGE
:
644 // These are intermediate states; we need more info from a request that
648 // In this case, whether login succeeded or not, we can't log
649 // the user in because their data is horked. So, override with
650 // the appropriate failure.
651 task_runner_
->PostTask(
653 base::Bind(&CryptohomeAuthenticator::OnAuthFailure
,
655 AuthFailure(AuthFailure::COULD_NOT_MOUNT_CRYPTOHOME
)));
658 // In this case, we tried to remove the user's old cryptohome at her
659 // request, and the remove failed.
660 remove_user_data_on_failure_
= false;
661 task_runner_
->PostTask(
663 base::Bind(&CryptohomeAuthenticator::OnAuthFailure
,
665 AuthFailure(AuthFailure::DATA_REMOVAL_FAILED
)));
668 // In this case, we tried to mount a tmpfs for guest and failed.
669 task_runner_
->PostTask(
671 base::Bind(&CryptohomeAuthenticator::OnAuthFailure
,
673 AuthFailure(AuthFailure::COULD_NOT_MOUNT_TMPFS
)));
676 // In this case, we tried to create/mount cryptohome and failed
677 // because of the critical TPM error.
678 // Chrome will notify user and request reboot.
679 task_runner_
->PostTask(FROM_HERE
,
680 base::Bind(&CryptohomeAuthenticator::OnAuthFailure
,
682 AuthFailure(AuthFailure::TPM_ERROR
)));
684 case FAILED_USERNAME_HASH
:
685 // In this case, we failed the GetSanitizedUsername request to
686 // cryptohomed. This can happen for any login attempt.
687 task_runner_
->PostTask(
689 base::Bind(&CryptohomeAuthenticator::OnAuthFailure
,
691 AuthFailure(AuthFailure::USERNAME_HASH_FAILED
)));
693 case REMOVED_DATA_AFTER_FAILURE
:
694 remove_user_data_on_failure_
= false;
695 task_runner_
->PostTask(FROM_HERE
,
696 base::Bind(&CryptohomeAuthenticator::OnAuthFailure
,
698 *delayed_login_failure_
));
701 create_if_nonexistent
= true;
703 current_state_
->ResetCryptohomeStatus();
704 StartMount(current_state_
.get(),
705 scoped_refptr
<CryptohomeAuthenticator
>(this),
707 create_if_nonexistent
);
710 task_runner_
->PostTask(
712 base::Bind(&CryptohomeAuthenticator::OnPasswordChangeDetected
, this));
717 NOTREACHED() << "Using obsolete ClientLogin code path.";
720 VLOG(2) << "Offline login";
726 VLOG(2) << "Online login";
727 task_runner_
->PostTask(
728 FROM_HERE
, base::Bind(&CryptohomeAuthenticator::OnAuthSuccess
, this));
731 VLOG(2) << "Retail mode login";
732 current_state_
->user_context
.SetIsUsingOAuth(false);
733 task_runner_
->PostTask(
735 base::Bind(&CryptohomeAuthenticator::OnRetailModeAuthSuccess
, this));
738 task_runner_
->PostTask(
740 base::Bind(&CryptohomeAuthenticator::OnOffTheRecordAuthSuccess
,
743 case KIOSK_ACCOUNT_LOGIN
:
744 case PUBLIC_ACCOUNT_LOGIN
:
745 current_state_
->user_context
.SetIsUsingOAuth(false);
746 task_runner_
->PostTask(
747 FROM_HERE
, base::Bind(&CryptohomeAuthenticator::OnAuthSuccess
, this));
749 case SUPERVISED_USER_LOGIN
:
750 current_state_
->user_context
.SetIsUsingOAuth(false);
751 task_runner_
->PostTask(
752 FROM_HERE
, base::Bind(&CryptohomeAuthenticator::OnAuthSuccess
, this));
755 current_state_
->ResetCryptohomeStatus();
756 task_runner_
->PostTask(FROM_HERE
,
757 base::Bind(&CryptohomeAuthenticator::OnAuthFailure
,
759 current_state_
->online_outcome()));
761 case OWNER_REQUIRED
: {
762 current_state_
->ResetCryptohomeStatus();
763 bool success
= false;
764 DBusThreadManager::Get()->GetCryptohomeClient()->Unmount(&success
);
766 // Maybe we should reboot immediately here?
767 LOG(ERROR
) << "Couldn't unmount users home!";
769 task_runner_
->PostTask(
771 base::Bind(&CryptohomeAuthenticator::OnAuthFailure
,
773 AuthFailure(AuthFailure::OWNER_REQUIRED
)));
782 CryptohomeAuthenticator::~CryptohomeAuthenticator() {
785 CryptohomeAuthenticator::AuthState
CryptohomeAuthenticator::ResolveState() {
786 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
787 // If we haven't mounted the user's home dir yet or
788 // haven't got sanitized username value, we can't be done.
789 // We never get past here if any of these two cryptohome ops is still pending.
790 // This is an important invariant.
791 if (!current_state_
->cryptohome_complete() ||
792 !current_state_
->username_hash_obtained()) {
796 AuthState state
= CONTINUE
;
798 if (current_state_
->cryptohome_outcome() &&
799 current_state_
->username_hash_valid()) {
800 state
= ResolveCryptohomeSuccessState();
802 state
= ResolveCryptohomeFailureState();
805 DCHECK(current_state_
->cryptohome_complete()); // Ensure invariant holds.
806 migrate_attempted_
= false;
807 remove_attempted_
= false;
808 resync_attempted_
= false;
809 ephemeral_mount_attempted_
= false;
810 check_key_attempted_
= false;
812 if (state
!= POSSIBLE_PW_CHANGE
&& state
!= NO_MOUNT
&&
813 state
!= OFFLINE_LOGIN
)
816 if (current_state_
->online_complete()) {
817 if (current_state_
->online_outcome().reason() == AuthFailure::NONE
) {
818 // Online attempt succeeded as well, so combine the results.
819 return ResolveOnlineSuccessState(state
);
821 NOTREACHED() << "Using obsolete ClientLogin code path.";
823 // if online isn't complete yet, just return the offline result.
827 CryptohomeAuthenticator::AuthState
828 CryptohomeAuthenticator::ResolveCryptohomeFailureState() {
829 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
830 if (remove_attempted_
|| resync_attempted_
)
831 return FAILED_REMOVE
;
832 if (ephemeral_mount_attempted_
)
834 if (migrate_attempted_
)
836 if (check_key_attempted_
)
839 if (current_state_
->cryptohome_code() ==
840 cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT
) {
841 // Critical TPM error detected, reboot needed.
845 // Return intermediate states in the following case:
846 // when there is an online result to use;
847 // This is the case after user finishes Gaia login;
848 if (current_state_
->online_complete()) {
849 if (current_state_
->cryptohome_code() ==
850 cryptohome::MOUNT_ERROR_KEY_FAILURE
) {
851 // If we tried a mount but they used the wrong key, we may need to
852 // ask the user for her old password. We'll only know once we've
853 // done the online check.
854 return POSSIBLE_PW_CHANGE
;
856 if (current_state_
->cryptohome_code() ==
857 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST
) {
858 // If we tried a mount but the user did not exist, then we should wait
859 // for online login to succeed and try again with the "create" flag set.
864 if (!current_state_
->username_hash_valid())
865 return FAILED_USERNAME_HASH
;
870 CryptohomeAuthenticator::AuthState
871 CryptohomeAuthenticator::ResolveCryptohomeSuccessState() {
872 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
873 if (resync_attempted_
)
875 if (remove_attempted_
)
876 return REMOVED_DATA_AFTER_FAILURE
;
877 if (migrate_attempted_
)
878 return RECOVER_MOUNT
;
879 if (check_key_attempted_
)
882 if (current_state_
->user_type
== user_manager::USER_TYPE_GUEST
)
884 if (current_state_
->user_type
== user_manager::USER_TYPE_RETAIL_MODE
)
886 if (current_state_
->user_type
== user_manager::USER_TYPE_PUBLIC_ACCOUNT
)
887 return PUBLIC_ACCOUNT_LOGIN
;
888 if (current_state_
->user_type
== user_manager::USER_TYPE_KIOSK_APP
)
889 return KIOSK_ACCOUNT_LOGIN
;
890 if (current_state_
->user_type
== user_manager::USER_TYPE_SUPERVISED
)
891 return SUPERVISED_USER_LOGIN
;
895 return user_can_login_
? OFFLINE_LOGIN
: OWNER_REQUIRED
;
898 CryptohomeAuthenticator::AuthState
899 CryptohomeAuthenticator::ResolveOnlineSuccessState(
900 CryptohomeAuthenticator::AuthState offline_state
) {
901 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
902 switch (offline_state
) {
903 case POSSIBLE_PW_CHANGE
:
911 return offline_state
;
915 void CryptohomeAuthenticator::ResolveLoginCompletionStatus() {
916 // Shortcut online state resolution process.
917 current_state_
->RecordOnlineLoginStatus(AuthFailure::AuthFailureNone());
921 void CryptohomeAuthenticator::SetOwnerState(bool owner_check_finished
,
923 owner_is_verified_
= owner_check_finished
;
924 user_can_login_
= check_result
;
927 } // namespace chromeos