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