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 "base/memory/weak_ptr.h"
15 #include "chromeos/cryptohome/async_method_caller.h"
16 #include "chromeos/cryptohome/cryptohome_parameters.h"
17 #include "chromeos/cryptohome/homedir_methods.h"
18 #include "chromeos/cryptohome/system_salt_getter.h"
19 #include "chromeos/dbus/cryptohome_client.h"
20 #include "chromeos/dbus/dbus_thread_manager.h"
21 #include "chromeos/login/auth/auth_status_consumer.h"
22 #include "chromeos/login/auth/key.h"
23 #include "chromeos/login/auth/user_context.h"
24 #include "chromeos/login/login_state.h"
25 #include "chromeos/login/user_names.h"
26 #include "chromeos/login_event_recorder.h"
27 #include "components/user_manager/user_type.h"
28 #include "third_party/cros_system_api/dbus/service_constants.h"
34 // The label used for the key derived from the user's GAIA credentials.
35 const char kCryptohomeGAIAKeyLabel
[] = "gaia";
37 // The name under which the type of key generated from the user's GAIA
38 // credentials is stored.
39 const char kKeyProviderDataTypeName
[] = "type";
41 // The name under which the salt used to generate a key from the user's GAIA
42 // credentials is stored.
43 const char kKeyProviderDataSaltName
[] = "salt";
45 // Hashes |key| with |system_salt| if it its type is KEY_TYPE_PASSWORD_PLAIN.
46 // Returns the keys unmodified otherwise.
47 scoped_ptr
<Key
> TransformKeyIfNeeded(const Key
& key
,
48 const std::string
& system_salt
) {
49 scoped_ptr
<Key
> result(new Key(key
));
50 if (result
->GetKeyType() == Key::KEY_TYPE_PASSWORD_PLAIN
)
51 result
->Transform(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF
, system_salt
);
56 // Records status and calls resolver->Resolve().
57 void TriggerResolve(const base::WeakPtr
<AuthAttemptState
>& attempt
,
58 scoped_refptr
<CryptohomeAuthenticator
> resolver
,
60 cryptohome::MountError return_code
) {
61 attempt
->RecordCryptohomeStatus(success
, return_code
);
65 // Records get hash status and calls resolver->Resolve().
66 void TriggerResolveHash(const base::WeakPtr
<AuthAttemptState
>& attempt
,
67 scoped_refptr
<CryptohomeAuthenticator
> resolver
,
69 const std::string
& username_hash
) {
71 attempt
->RecordUsernameHash(username_hash
);
73 attempt
->RecordUsernameHashFailed();
77 // Calls TriggerResolve while adding login time marker.
78 void TriggerResolveWithLoginTimeMarker(
79 const std::string
& marker_name
,
80 const base::WeakPtr
<AuthAttemptState
>& attempt
,
81 scoped_refptr
<CryptohomeAuthenticator
> resolver
,
83 cryptohome::MountError return_code
) {
84 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(marker_name
, false);
85 TriggerResolve(attempt
, resolver
, success
, return_code
);
88 // Records an error in accessing the user's cryptohome with the given key and
89 // calls resolver->Resolve() after adding a login time marker.
90 void RecordKeyErrorAndResolve(const base::WeakPtr
<AuthAttemptState
>& attempt
,
91 scoped_refptr
<CryptohomeAuthenticator
> resolver
) {
92 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker("CryptohomeMount-End",
94 attempt
->RecordCryptohomeStatus(false /* success */,
95 cryptohome::MOUNT_ERROR_KEY_FAILURE
);
99 // Callback invoked when cryptohome's MountEx() method has finished.
100 void OnMount(const base::WeakPtr
<AuthAttemptState
>& attempt
,
101 scoped_refptr
<CryptohomeAuthenticator
> resolver
,
103 cryptohome::MountError return_code
,
104 const std::string
& mount_hash
) {
105 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker("CryptohomeMount-End",
107 attempt
->RecordCryptohomeStatus(success
, return_code
);
109 attempt
->RecordUsernameHash(mount_hash
);
111 attempt
->RecordUsernameHashFailed();
115 // Calls cryptohome's MountEx() method. The key in |attempt->user_context| must
116 // not be a plain text password. If the user provided a plain text password,
117 // that password must be transformed to another key type (by salted hashing)
118 // before calling this method.
119 void DoMount(const base::WeakPtr
<AuthAttemptState
>& attempt
,
120 scoped_refptr
<CryptohomeAuthenticator
> resolver
,
122 bool create_if_nonexistent
) {
123 const Key
* key
= attempt
->user_context
.GetKey();
124 // If the |key| is a plain text password, crash rather than attempting to
125 // mount the cryptohome with a plain text password.
126 CHECK_NE(Key::KEY_TYPE_PASSWORD_PLAIN
, key
->GetKeyType());
128 // Set state that username_hash is requested here so that test implementation
129 // that returns directly would not generate 2 OnLoginSucces() calls.
130 attempt
->UsernameHashRequested();
132 // Set the authentication's key label to an empty string, which is a wildcard
133 // allowing any key to match. This is necessary because cryptohomes created by
134 // Chrome OS M38 and older will have a legacy key with no label while those
135 // created by Chrome OS M39 and newer will have a key with the label
136 // kCryptohomeGAIAKeyLabel.
137 const cryptohome::KeyDefinition
auth_key(key
->GetSecret(),
139 cryptohome::PRIV_DEFAULT
);
140 cryptohome::MountParameters
mount(ephemeral
);
141 if (create_if_nonexistent
) {
142 mount
.create_keys
.push_back(cryptohome::KeyDefinition(
144 kCryptohomeGAIAKeyLabel
,
145 cryptohome::PRIV_DEFAULT
));
148 cryptohome::HomedirMethods::GetInstance()->MountEx(
149 cryptohome::Identification(attempt
->user_context
.GetUserID()),
150 cryptohome::Authorization(auth_key
),
152 base::Bind(&OnMount
, attempt
, resolver
));
155 // Callback invoked when the system salt has been retrieved. Transforms the key
156 // in |attempt->user_context| using Chrome's default hashing algorithm and the
157 // system salt, then calls MountEx().
158 void OnGetSystemSalt(const base::WeakPtr
<AuthAttemptState
>& attempt
,
159 scoped_refptr
<CryptohomeAuthenticator
> resolver
,
161 bool create_if_nonexistent
,
162 const std::string
& system_salt
) {
163 DCHECK_EQ(Key::KEY_TYPE_PASSWORD_PLAIN
,
164 attempt
->user_context
.GetKey()->GetKeyType());
166 attempt
->user_context
.GetKey()->Transform(
167 Key::KEY_TYPE_SALTED_SHA256_TOP_HALF
,
170 DoMount(attempt
, resolver
, ephemeral
, create_if_nonexistent
);
173 // Callback invoked when cryptohome's GetKeyDataEx() method has finished.
174 // * If GetKeyDataEx() returned metadata indicating the hashing algorithm and
175 // salt that were used to generate the key for this user's cryptohome,
176 // transforms the key in |attempt->user_context| with the same parameters.
177 // * Otherwise, starts the retrieval of the system salt so that the key in
178 // |attempt->user_context| can be transformed with Chrome's default hashing
179 // algorithm and the system salt.
180 // The resulting key is then passed to cryptohome's MountEx().
182 const base::WeakPtr
<AuthAttemptState
>& attempt
,
183 scoped_refptr
<CryptohomeAuthenticator
> resolver
,
185 bool create_if_nonexistent
,
187 cryptohome::MountError return_code
,
188 const std::vector
<cryptohome::KeyDefinition
>& key_definitions
) {
190 if (key_definitions
.size() == 1) {
191 const cryptohome::KeyDefinition
& key_definition
= key_definitions
.front();
192 DCHECK_EQ(kCryptohomeGAIAKeyLabel
, key_definition
.label
);
194 // Extract the key type and salt from |key_definition|, if present.
195 scoped_ptr
<int64
> type
;
196 scoped_ptr
<std::string
> salt
;
197 for (std::vector
<cryptohome::KeyDefinition::ProviderData
>::
198 const_iterator it
= key_definition
.provider_data
.begin();
199 it
!= key_definition
.provider_data
.end(); ++it
) {
200 if (it
->name
== kKeyProviderDataTypeName
) {
202 type
.reset(new int64(*it
->number
));
205 } else if (it
->name
== kKeyProviderDataSaltName
) {
207 salt
.reset(new std::string(*it
->bytes
));
214 if (*type
< 0 || *type
>= Key::KEY_TYPE_COUNT
) {
215 LOG(ERROR
) << "Invalid key type: " << *type
;
216 RecordKeyErrorAndResolve(attempt
, resolver
);
221 LOG(ERROR
) << "Missing salt.";
222 RecordKeyErrorAndResolve(attempt
, resolver
);
226 attempt
->user_context
.GetKey()->Transform(
227 static_cast<Key::KeyType
>(*type
),
229 DoMount(attempt
, resolver
, ephemeral
, create_if_nonexistent
);
233 LOG(ERROR
) << "GetKeyDataEx() returned " << key_definitions
.size()
238 SystemSaltGetter::Get()->GetSystemSalt(base::Bind(&OnGetSystemSalt
,
242 create_if_nonexistent
));
245 // Starts the process that will mount a user's cryptohome.
246 // * If the key in |attempt->user_context| is not a plain text password,
247 // cryptohome's MountEx() method is called directly with the key.
248 // * Otherwise, the key must be transformed (by salted hashing) before being
249 // passed to MountEx(). In that case, cryptohome's GetKeyDataEx() method is
250 // called to retrieve metadata indicating the hashing algorithm and salt that
251 // were used to generate the key for this user's cryptohome and the key is
252 // transformed accordingly before calling MountEx().
253 void StartMount(const base::WeakPtr
<AuthAttemptState
>& attempt
,
254 scoped_refptr
<CryptohomeAuthenticator
> resolver
,
256 bool create_if_nonexistent
) {
257 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(
258 "CryptohomeMount-Start", false);
260 if (attempt
->user_context
.GetKey()->GetKeyType() !=
261 Key::KEY_TYPE_PASSWORD_PLAIN
) {
262 DoMount(attempt
, resolver
, ephemeral
, create_if_nonexistent
);
266 cryptohome::HomedirMethods::GetInstance()->GetKeyDataEx(
267 cryptohome::Identification(attempt
->user_context
.GetUserID()),
268 kCryptohomeGAIAKeyLabel
,
269 base::Bind(&OnGetKeyDataEx
,
273 create_if_nonexistent
));
276 // Calls cryptohome's mount method for guest and also get the user hash from
278 void MountGuestAndGetHash(const base::WeakPtr
<AuthAttemptState
>& attempt
,
279 scoped_refptr
<CryptohomeAuthenticator
> resolver
) {
280 attempt
->UsernameHashRequested();
281 cryptohome::AsyncMethodCaller::GetInstance()->AsyncMountGuest(
282 base::Bind(&TriggerResolveWithLoginTimeMarker
,
283 "CryptohomeMount-End",
286 cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername(
287 attempt
->user_context
.GetUserID(),
288 base::Bind(&TriggerResolveHash
, attempt
, resolver
));
291 // Calls cryptohome's MountPublic method
292 void MountPublic(const base::WeakPtr
<AuthAttemptState
>& attempt
,
293 scoped_refptr
<CryptohomeAuthenticator
> resolver
,
295 cryptohome::AsyncMethodCaller::GetInstance()->AsyncMountPublic(
296 attempt
->user_context
.GetUserID(),
298 base::Bind(&TriggerResolveWithLoginTimeMarker
,
299 "CryptohomeMountPublic-End",
302 cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername(
303 attempt
->user_context
.GetUserID(),
304 base::Bind(&TriggerResolveHash
, attempt
, resolver
));
307 // Calls cryptohome's key migration method.
308 void Migrate(const base::WeakPtr
<AuthAttemptState
>& attempt
,
309 scoped_refptr
<CryptohomeAuthenticator
> resolver
,
310 bool passing_old_hash
,
311 const std::string
& old_password
,
312 const std::string
& system_salt
) {
313 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(
314 "CryptohomeMigrate-Start", false);
315 cryptohome::AsyncMethodCaller
* caller
=
316 cryptohome::AsyncMethodCaller::GetInstance();
318 // TODO(bartfab): Retrieve the hashing algorithm and salt to use for |old_key|
320 scoped_ptr
<Key
> old_key
=
321 TransformKeyIfNeeded(Key(old_password
), system_salt
);
322 scoped_ptr
<Key
> new_key
=
323 TransformKeyIfNeeded(*attempt
->user_context
.GetKey(), system_salt
);
324 if (passing_old_hash
) {
325 caller
->AsyncMigrateKey(attempt
->user_context
.GetUserID(),
326 old_key
->GetSecret(),
327 new_key
->GetSecret(),
328 base::Bind(&TriggerResolveWithLoginTimeMarker
,
329 "CryptohomeMount-End",
333 caller
->AsyncMigrateKey(attempt
->user_context
.GetUserID(),
334 new_key
->GetSecret(),
335 old_key
->GetSecret(),
336 base::Bind(&TriggerResolveWithLoginTimeMarker
,
337 "CryptohomeMount-End",
343 // Calls cryptohome's remove method.
344 void Remove(const base::WeakPtr
<AuthAttemptState
>& attempt
,
345 scoped_refptr
<CryptohomeAuthenticator
> resolver
) {
346 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(
347 "CryptohomeRemove-Start", false);
348 cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove(
349 attempt
->user_context
.GetUserID(),
350 base::Bind(&TriggerResolveWithLoginTimeMarker
,
351 "CryptohomeRemove-End",
356 // Calls cryptohome's key check method.
357 void CheckKey(const base::WeakPtr
<AuthAttemptState
>& attempt
,
358 scoped_refptr
<CryptohomeAuthenticator
> resolver
,
359 const std::string
& system_salt
) {
360 scoped_ptr
<Key
> key
=
361 TransformKeyIfNeeded(*attempt
->user_context
.GetKey(), system_salt
);
362 cryptohome::AsyncMethodCaller::GetInstance()->AsyncCheckKey(
363 attempt
->user_context
.GetUserID(),
365 base::Bind(&TriggerResolve
, attempt
, resolver
));
370 CryptohomeAuthenticator::CryptohomeAuthenticator(
371 scoped_refptr
<base::TaskRunner
> task_runner
,
372 AuthStatusConsumer
* consumer
)
373 : Authenticator(consumer
),
374 task_runner_(task_runner
),
375 migrate_attempted_(false),
376 remove_attempted_(false),
377 resync_attempted_(false),
378 ephemeral_mount_attempted_(false),
379 check_key_attempted_(false),
380 already_reported_success_(false),
381 owner_is_verified_(false),
382 user_can_login_(false),
383 remove_user_data_on_failure_(false),
384 delayed_login_failure_(NULL
) {
387 void CryptohomeAuthenticator::AuthenticateToLogin(
388 content::BrowserContext
* context
,
389 const UserContext
& user_context
) {
390 authentication_context_
= context
;
391 current_state_
.reset(new AuthAttemptState(user_context
,
392 user_manager::USER_TYPE_REGULAR
,
394 false, // online_complete
395 !IsKnownUser(user_context
)));
396 // Reset the verified flag.
397 owner_is_verified_
= false;
399 StartMount(current_state_
->AsWeakPtr(),
400 scoped_refptr
<CryptohomeAuthenticator
>(this),
401 false /* ephemeral */, false /* create_if_nonexistent */);
404 void CryptohomeAuthenticator::CompleteLogin(content::BrowserContext
* context
,
405 const UserContext
& user_context
) {
406 authentication_context_
= context
;
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_
->AsWeakPtr(),
417 scoped_refptr
<CryptohomeAuthenticator
>(this),
418 false /* ephemeral */, false /* create_if_nonexistent */);
420 // For login completion from extension, we just need to resolve the current
421 // auth attempt state, the rest of OAuth related tasks will be done in
423 task_runner_
->PostTask(
425 base::Bind(&CryptohomeAuthenticator::ResolveLoginCompletionStatus
, this));
428 void CryptohomeAuthenticator::AuthenticateToUnlock(
429 const UserContext
& user_context
) {
430 current_state_
.reset(new AuthAttemptState(user_context
,
431 user_manager::USER_TYPE_REGULAR
,
433 true, // online_complete
434 false)); // user_is_new
435 remove_user_data_on_failure_
= false;
436 check_key_attempted_
= true;
437 SystemSaltGetter::Get()->GetSystemSalt(
438 base::Bind(&CheckKey
, current_state_
->AsWeakPtr(),
439 scoped_refptr
<CryptohomeAuthenticator
>(this)));
442 void CryptohomeAuthenticator::LoginAsSupervisedUser(
443 const UserContext
& user_context
) {
444 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
445 // TODO(nkostylev): Pass proper value for |user_is_new| or remove (not used).
446 current_state_
.reset(new AuthAttemptState(user_context
,
447 user_manager::USER_TYPE_SUPERVISED
,
449 false, // online_complete
450 false)); // user_is_new
451 remove_user_data_on_failure_
= false;
452 StartMount(current_state_
->AsWeakPtr(),
453 scoped_refptr
<CryptohomeAuthenticator
>(this),
454 false /* ephemeral */, false /* create_if_nonexistent */);
457 void CryptohomeAuthenticator::LoginOffTheRecord() {
458 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
459 current_state_
.reset(
460 new AuthAttemptState(UserContext(chromeos::login::kGuestUserName
),
461 user_manager::USER_TYPE_GUEST
,
463 false, // online_complete
464 false)); // user_is_new
465 remove_user_data_on_failure_
= false;
466 ephemeral_mount_attempted_
= true;
467 MountGuestAndGetHash(current_state_
->AsWeakPtr(),
468 scoped_refptr
<CryptohomeAuthenticator
>(this));
471 void CryptohomeAuthenticator::LoginAsPublicSession(
472 const UserContext
& user_context
) {
473 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
474 current_state_
.reset(
475 new AuthAttemptState(user_context
,
476 user_manager::USER_TYPE_PUBLIC_ACCOUNT
,
478 false, // online_complete
479 false)); // user_is_new
480 remove_user_data_on_failure_
= false;
481 ephemeral_mount_attempted_
= true;
482 StartMount(current_state_
->AsWeakPtr(),
483 scoped_refptr
<CryptohomeAuthenticator
>(this), true /* ephemeral */,
484 true /* create_if_nonexistent */);
487 void CryptohomeAuthenticator::LoginAsKioskAccount(
488 const std::string
& app_user_id
,
489 bool use_guest_mount
) {
490 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
492 const std::string user_id
=
493 use_guest_mount
? chromeos::login::kGuestUserName
: app_user_id
;
494 current_state_
.reset(new AuthAttemptState(UserContext(user_id
),
495 user_manager::USER_TYPE_KIOSK_APP
,
497 false, // online_complete
498 false)); // user_is_new
500 remove_user_data_on_failure_
= true;
501 if (!use_guest_mount
) {
502 MountPublic(current_state_
->AsWeakPtr(),
503 scoped_refptr
<CryptohomeAuthenticator
>(this),
504 cryptohome::CREATE_IF_MISSING
);
506 ephemeral_mount_attempted_
= true;
507 MountGuestAndGetHash(current_state_
->AsWeakPtr(),
508 scoped_refptr
<CryptohomeAuthenticator
>(this));
512 void CryptohomeAuthenticator::OnAuthSuccess() {
513 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
514 VLOG(1) << "Login success";
515 // Send notification of success
516 chromeos::LoginEventRecorder::Get()->RecordAuthenticationSuccess();
518 base::AutoLock
for_this_block(success_lock_
);
519 already_reported_success_
= true;
522 consumer_
->OnAuthSuccess(current_state_
->user_context
);
525 void CryptohomeAuthenticator::OnOffTheRecordAuthSuccess() {
526 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
527 chromeos::LoginEventRecorder::Get()->RecordAuthenticationSuccess();
529 consumer_
->OnOffTheRecordAuthSuccess();
532 void CryptohomeAuthenticator::OnPasswordChangeDetected() {
533 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
535 consumer_
->OnPasswordChangeDetected();
538 void CryptohomeAuthenticator::OnAuthFailure(const AuthFailure
& error
) {
539 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
541 // OnAuthFailure will be called again with the same |error|
542 // after the cryptohome has been removed.
543 if (remove_user_data_on_failure_
) {
544 delayed_login_failure_
= &error
;
545 RemoveEncryptedData();
548 chromeos::LoginEventRecorder::Get()->RecordAuthenticationFailure();
549 LOG(WARNING
) << "Login failed: " << error
.GetErrorString();
551 consumer_
->OnAuthFailure(error
);
554 void CryptohomeAuthenticator::RecoverEncryptedData(
555 const std::string
& old_password
) {
556 migrate_attempted_
= true;
557 current_state_
->ResetCryptohomeStatus();
558 SystemSaltGetter::Get()->GetSystemSalt(base::Bind(
559 &Migrate
, current_state_
->AsWeakPtr(),
560 scoped_refptr
<CryptohomeAuthenticator
>(this), true, old_password
));
563 void CryptohomeAuthenticator::RemoveEncryptedData() {
564 remove_attempted_
= true;
565 current_state_
->ResetCryptohomeStatus();
566 task_runner_
->PostTask(
567 FROM_HERE
, base::Bind(&Remove
, current_state_
->AsWeakPtr(),
568 scoped_refptr
<CryptohomeAuthenticator
>(this)));
571 void CryptohomeAuthenticator::ResyncEncryptedData() {
572 resync_attempted_
= true;
573 current_state_
->ResetCryptohomeStatus();
574 task_runner_
->PostTask(
575 FROM_HERE
, base::Bind(&Remove
, current_state_
->AsWeakPtr(),
576 scoped_refptr
<CryptohomeAuthenticator
>(this)));
579 bool CryptohomeAuthenticator::VerifyOwner() {
580 if (owner_is_verified_
)
582 // Check if policy data is fine and continue in safe mode if needed.
584 // Now we can continue with the login and report mount success.
585 user_can_login_
= true;
586 owner_is_verified_
= true;
590 CheckSafeModeOwnership(
591 current_state_
->user_context
,
592 base::Bind(&CryptohomeAuthenticator::OnOwnershipChecked
, this));
596 void CryptohomeAuthenticator::OnOwnershipChecked(bool is_owner
) {
597 // Now we can check if this user is the owner.
598 user_can_login_
= is_owner
;
599 owner_is_verified_
= true;
603 void CryptohomeAuthenticator::Resolve() {
604 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
605 bool create_if_nonexistent
= false;
606 CryptohomeAuthenticator::AuthState state
= ResolveState();
607 VLOG(1) << "Resolved state to: " << state
;
610 case POSSIBLE_PW_CHANGE
:
612 // These are intermediate states; we need more info from a request that
616 // In this case, whether login succeeded or not, we can't log
617 // the user in because their data is horked. So, override with
618 // the appropriate failure.
619 task_runner_
->PostTask(
621 base::Bind(&CryptohomeAuthenticator::OnAuthFailure
,
623 AuthFailure(AuthFailure::COULD_NOT_MOUNT_CRYPTOHOME
)));
626 // In this case, we tried to remove the user's old cryptohome at her
627 // request, and the remove failed.
628 remove_user_data_on_failure_
= false;
629 task_runner_
->PostTask(
631 base::Bind(&CryptohomeAuthenticator::OnAuthFailure
,
633 AuthFailure(AuthFailure::DATA_REMOVAL_FAILED
)));
636 // In this case, we tried to mount a tmpfs for guest and failed.
637 task_runner_
->PostTask(
639 base::Bind(&CryptohomeAuthenticator::OnAuthFailure
,
641 AuthFailure(AuthFailure::COULD_NOT_MOUNT_TMPFS
)));
644 // In this case, we tried to create/mount cryptohome and failed
645 // because of the critical TPM error.
646 // Chrome will notify user and request reboot.
647 task_runner_
->PostTask(FROM_HERE
,
648 base::Bind(&CryptohomeAuthenticator::OnAuthFailure
,
650 AuthFailure(AuthFailure::TPM_ERROR
)));
652 case FAILED_USERNAME_HASH
:
653 // In this case, we failed the GetSanitizedUsername request to
654 // cryptohomed. This can happen for any login attempt.
655 task_runner_
->PostTask(
657 base::Bind(&CryptohomeAuthenticator::OnAuthFailure
,
659 AuthFailure(AuthFailure::USERNAME_HASH_FAILED
)));
661 case REMOVED_DATA_AFTER_FAILURE
:
662 remove_user_data_on_failure_
= false;
663 task_runner_
->PostTask(FROM_HERE
,
664 base::Bind(&CryptohomeAuthenticator::OnAuthFailure
,
666 *delayed_login_failure_
));
669 create_if_nonexistent
= true;
671 current_state_
->ResetCryptohomeStatus();
672 StartMount(current_state_
->AsWeakPtr(),
673 scoped_refptr
<CryptohomeAuthenticator
>(this),
674 false /*ephemeral*/, create_if_nonexistent
);
677 task_runner_
->PostTask(
679 base::Bind(&CryptohomeAuthenticator::OnPasswordChangeDetected
, this));
684 NOTREACHED() << "Using obsolete ClientLogin code path.";
687 VLOG(2) << "Offline login";
693 VLOG(2) << "Online login";
694 task_runner_
->PostTask(
695 FROM_HERE
, base::Bind(&CryptohomeAuthenticator::OnAuthSuccess
, this));
698 task_runner_
->PostTask(
700 base::Bind(&CryptohomeAuthenticator::OnOffTheRecordAuthSuccess
,
703 case KIOSK_ACCOUNT_LOGIN
:
704 case PUBLIC_ACCOUNT_LOGIN
:
705 current_state_
->user_context
.SetIsUsingOAuth(false);
706 task_runner_
->PostTask(
707 FROM_HERE
, base::Bind(&CryptohomeAuthenticator::OnAuthSuccess
, this));
709 case SUPERVISED_USER_LOGIN
:
710 current_state_
->user_context
.SetIsUsingOAuth(false);
711 task_runner_
->PostTask(
712 FROM_HERE
, base::Bind(&CryptohomeAuthenticator::OnAuthSuccess
, this));
715 current_state_
->ResetCryptohomeStatus();
716 task_runner_
->PostTask(FROM_HERE
,
717 base::Bind(&CryptohomeAuthenticator::OnAuthFailure
,
719 current_state_
->online_outcome()));
721 case OWNER_REQUIRED
: {
722 current_state_
->ResetCryptohomeStatus();
723 bool success
= false;
724 DBusThreadManager::Get()->GetCryptohomeClient()->Unmount(&success
);
726 // Maybe we should reboot immediately here?
727 LOG(ERROR
) << "Couldn't unmount users home!";
729 task_runner_
->PostTask(
731 base::Bind(&CryptohomeAuthenticator::OnAuthFailure
,
733 AuthFailure(AuthFailure::OWNER_REQUIRED
)));
742 CryptohomeAuthenticator::~CryptohomeAuthenticator() {
745 CryptohomeAuthenticator::AuthState
CryptohomeAuthenticator::ResolveState() {
746 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
747 // If we haven't mounted the user's home dir yet or
748 // haven't got sanitized username value, we can't be done.
749 // We never get past here if any of these two cryptohome ops is still pending.
750 // This is an important invariant.
751 if (!current_state_
->cryptohome_complete() ||
752 !current_state_
->username_hash_obtained()) {
756 AuthState state
= CONTINUE
;
758 if (current_state_
->cryptohome_outcome() &&
759 current_state_
->username_hash_valid()) {
760 state
= ResolveCryptohomeSuccessState();
762 state
= ResolveCryptohomeFailureState();
765 DCHECK(current_state_
->cryptohome_complete()); // Ensure invariant holds.
766 migrate_attempted_
= false;
767 remove_attempted_
= false;
768 resync_attempted_
= false;
769 ephemeral_mount_attempted_
= false;
770 check_key_attempted_
= false;
772 if (state
!= POSSIBLE_PW_CHANGE
&& state
!= NO_MOUNT
&&
773 state
!= OFFLINE_LOGIN
)
776 if (current_state_
->online_complete()) {
777 if (current_state_
->online_outcome().reason() == AuthFailure::NONE
) {
778 // Online attempt succeeded as well, so combine the results.
779 return ResolveOnlineSuccessState(state
);
781 NOTREACHED() << "Using obsolete ClientLogin code path.";
783 // if online isn't complete yet, just return the offline result.
787 CryptohomeAuthenticator::AuthState
788 CryptohomeAuthenticator::ResolveCryptohomeFailureState() {
789 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
790 if (remove_attempted_
|| resync_attempted_
)
791 return FAILED_REMOVE
;
792 if (ephemeral_mount_attempted_
)
794 if (migrate_attempted_
)
796 if (check_key_attempted_
)
799 if (current_state_
->cryptohome_code() ==
800 cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT
) {
801 // Critical TPM error detected, reboot needed.
805 // Return intermediate states in the following case:
806 // when there is an online result to use;
807 // This is the case after user finishes Gaia login;
808 if (current_state_
->online_complete()) {
809 if (current_state_
->cryptohome_code() ==
810 cryptohome::MOUNT_ERROR_KEY_FAILURE
) {
811 // If we tried a mount but they used the wrong key, we may need to
812 // ask the user for her old password. We'll only know once we've
813 // done the online check.
814 return POSSIBLE_PW_CHANGE
;
816 if (current_state_
->cryptohome_code() ==
817 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST
) {
818 // If we tried a mount but the user did not exist, then we should wait
819 // for online login to succeed and try again with the "create" flag set.
824 if (!current_state_
->username_hash_valid())
825 return FAILED_USERNAME_HASH
;
830 CryptohomeAuthenticator::AuthState
831 CryptohomeAuthenticator::ResolveCryptohomeSuccessState() {
832 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
833 if (resync_attempted_
)
835 if (remove_attempted_
)
836 return REMOVED_DATA_AFTER_FAILURE
;
837 if (migrate_attempted_
)
838 return RECOVER_MOUNT
;
839 if (check_key_attempted_
)
842 if (current_state_
->user_type
== user_manager::USER_TYPE_GUEST
)
844 if (current_state_
->user_type
== user_manager::USER_TYPE_PUBLIC_ACCOUNT
)
845 return PUBLIC_ACCOUNT_LOGIN
;
846 if (current_state_
->user_type
== user_manager::USER_TYPE_KIOSK_APP
)
847 return KIOSK_ACCOUNT_LOGIN
;
848 if (current_state_
->user_type
== user_manager::USER_TYPE_SUPERVISED
)
849 return SUPERVISED_USER_LOGIN
;
853 return user_can_login_
? OFFLINE_LOGIN
: OWNER_REQUIRED
;
856 CryptohomeAuthenticator::AuthState
857 CryptohomeAuthenticator::ResolveOnlineSuccessState(
858 CryptohomeAuthenticator::AuthState offline_state
) {
859 DCHECK(task_runner_
->RunsTasksOnCurrentThread());
860 switch (offline_state
) {
861 case POSSIBLE_PW_CHANGE
:
869 return offline_state
;
873 void CryptohomeAuthenticator::ResolveLoginCompletionStatus() {
874 // Shortcut online state resolution process.
875 current_state_
->RecordOnlineLoginStatus(AuthFailure::AuthFailureNone());
879 void CryptohomeAuthenticator::SetOwnerState(bool owner_check_finished
,
881 owner_is_verified_
= owner_check_finished
;
882 user_can_login_
= check_result
;
885 } // namespace chromeos