[NaCl SDK]: use standard __BEGIN_DECLS macros in sys/select.h
[chromium-blink-merge.git] / chromeos / login / auth / cryptohome_authenticator.cc
blobd00cf29f1aa14af10c3b2326b4ba179dd755a084
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"
8 #include "base/bind.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"
27 namespace chromeos {
29 namespace {
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);
50 return result.Pass();
53 // Records status and calls resolver->Resolve().
54 void TriggerResolve(AuthAttemptState* attempt,
55 scoped_refptr<CryptohomeAuthenticator> resolver,
56 bool success,
57 cryptohome::MountError return_code) {
58 attempt->RecordCryptohomeStatus(success, return_code);
59 resolver->Resolve();
62 // Records get hash status and calls resolver->Resolve().
63 void TriggerResolveHash(AuthAttemptState* attempt,
64 scoped_refptr<CryptohomeAuthenticator> resolver,
65 bool success,
66 const std::string& username_hash) {
67 if (success)
68 attempt->RecordUsernameHash(username_hash);
69 else
70 attempt->RecordUsernameHashFailed();
71 resolver->Resolve();
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,
79 bool success,
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",
90 false);
91 attempt->RecordCryptohomeStatus(false /* success */,
92 cryptohome::MOUNT_ERROR_KEY_FAILURE);
93 resolver->Resolve();
96 // Callback invoked when cryptohome's MountEx() method has finished.
97 void OnMount(AuthAttemptState* attempt,
98 scoped_refptr<CryptohomeAuthenticator> resolver,
99 bool success,
100 cryptohome::MountError return_code,
101 const std::string& mount_hash) {
102 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker("CryptohomeMount-End",
103 false);
104 attempt->RecordCryptohomeStatus(success, return_code);
105 if (success)
106 attempt->RecordUsernameHash(mount_hash);
107 else
108 attempt->RecordUsernameHashFailed();
109 resolver->Resolve();
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,
118 bool ephemeral,
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(),
135 std::string(),
136 cryptohome::PRIV_DEFAULT);
137 cryptohome::MountParameters mount(ephemeral);
138 if (create_if_nonexistent) {
139 mount.create_keys.push_back(cryptohome::KeyDefinition(
140 key->GetSecret(),
141 kCryptohomeGAIAKeyLabel,
142 cryptohome::PRIV_DEFAULT));
145 cryptohome::HomedirMethods::GetInstance()->MountEx(
146 cryptohome::Identification(attempt->user_context.GetUserID()),
147 cryptohome::Authorization(auth_key),
148 mount,
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,
157 bool ephemeral,
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,
165 system_salt);
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,
180 bool ephemeral,
181 bool create_if_nonexistent,
182 bool success,
183 cryptohome::MountError return_code,
184 ScopedVector<cryptohome::RetrievedKeyData> key_data) {
185 if (success) {
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) {
197 if ((*it)->number)
198 type.reset(new int64(*(*it)->number));
199 else
200 NOTREACHED();
201 } else if ((*it)->name == kKeyProviderDataSaltName) {
202 if ((*it)->bytes)
203 salt.reset(new std::string(*(*it)->bytes));
204 else
205 NOTREACHED();
209 if (type) {
210 if (*type < 0 || *type >= Key::KEY_TYPE_COUNT) {
211 LOG(ERROR) << "Invalid key type: " << *type;
212 RecordKeyErrorAndResolve(attempt, resolver);
213 return;
216 if (!salt) {
217 LOG(ERROR) << "Missing salt.";
218 RecordKeyErrorAndResolve(attempt, resolver);
219 return;
222 attempt->user_context.GetKey()->Transform(
223 static_cast<Key::KeyType>(*type),
224 *salt);
225 DoMount(attempt, resolver, ephemeral, create_if_nonexistent);
226 return;
228 } else {
229 LOG(ERROR) << "GetKeyDataEx() returned " << key_data.size()
230 << " entries.";
234 SystemSaltGetter::Get()->GetSystemSalt(base::Bind(&OnGetSystemSalt,
235 attempt,
236 resolver,
237 ephemeral,
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,
251 bool ephemeral,
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);
259 return;
262 cryptohome::HomedirMethods::GetInstance()->GetKeyDataEx(
263 cryptohome::Identification(attempt->user_context.GetUserID()),
264 kCryptohomeGAIAKeyLabel,
265 base::Bind(&OnGetKeyDataEx,
266 attempt,
267 resolver,
268 ephemeral,
269 create_if_nonexistent));
272 // Calls cryptohome's mount method for guest and also get the user hash from
273 // cryptohome.
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",
280 attempt,
281 resolver));
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,
290 int flags) {
291 cryptohome::AsyncMethodCaller::GetInstance()->AsyncMountPublic(
292 attempt->user_context.GetUserID(),
293 flags,
294 base::Bind(&TriggerResolveWithLoginTimeMarker,
295 "CryptohomeMountPublic-End",
296 attempt,
297 resolver));
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|
315 // from cryptohomed.
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",
326 attempt,
327 resolver));
328 } else {
329 caller->AsyncMigrateKey(attempt->user_context.GetUserID(),
330 new_key->GetSecret(),
331 old_key->GetSecret(),
332 base::Bind(&TriggerResolveWithLoginTimeMarker,
333 "CryptohomeMount-End",
334 attempt,
335 resolver));
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",
348 attempt,
349 resolver));
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(),
360 key->GetSecret(),
361 base::Bind(&TriggerResolve, attempt, resolver));
364 } // namespace
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(
384 Profile* profile,
385 const UserContext& user_context) {
386 authentication_profile_ = profile;
387 current_state_.reset(new AuthAttemptState(user_context,
388 user_manager::USER_TYPE_REGULAR,
389 false, // unlock
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,
406 true, // unlock
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
420 // parallel.
421 task_runner_->PostTask(
422 FROM_HERE,
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,
430 true, // unlock
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,
447 false, // unlock
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
460 // mode session.
461 current_state_.reset(
462 new AuthAttemptState(UserContext(chromeos::login::kRetailModeUserName),
463 user_manager::USER_TYPE_RETAIL_MODE,
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_.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,
478 false, // unlock
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,
493 false, // unlock
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,
513 false, // unlock
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);
522 } else {
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();
533 if (consumer_)
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;
546 if (consumer_)
547 consumer_->OnAuthSuccess(current_state_->user_context);
550 void CryptohomeAuthenticator::OnOffTheRecordAuthSuccess() {
551 DCHECK(task_runner_->RunsTasksOnCurrentThread());
552 chromeos::LoginEventRecorder::Get()->RecordAuthenticationSuccess();
553 if (consumer_)
554 consumer_->OnOffTheRecordAuthSuccess();
557 void CryptohomeAuthenticator::OnPasswordChangeDetected() {
558 DCHECK(task_runner_->RunsTasksOnCurrentThread());
559 if (consumer_)
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();
571 return;
573 chromeos::LoginEventRecorder::Get()->RecordAuthenticationFailure();
574 LOG(WARNING) << "Login failed: " << error.GetErrorString();
575 if (consumer_)
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(
584 base::Bind(&Migrate,
585 current_state_.get(),
586 scoped_refptr<CryptohomeAuthenticator>(this),
587 true,
588 old_password));
591 void CryptohomeAuthenticator::RemoveEncryptedData() {
592 remove_attempted_ = true;
593 current_state_->ResetCryptohomeStatus();
594 task_runner_->PostTask(
595 FROM_HERE,
596 base::Bind(&Remove,
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(
605 FROM_HERE,
606 base::Bind(&Remove,
607 current_state_.get(),
608 scoped_refptr<CryptohomeAuthenticator>(this)));
611 bool CryptohomeAuthenticator::VerifyOwner() {
612 if (owner_is_verified_)
613 return true;
614 // Check if policy data is fine and continue in safe mode if needed.
615 if (!IsSafeMode()) {
616 // Now we can continue with the login and report mount success.
617 user_can_login_ = true;
618 owner_is_verified_ = true;
619 return true;
622 CheckSafeModeOwnership(
623 current_state_->user_context,
624 base::Bind(&CryptohomeAuthenticator::OnOwnershipChecked, this));
625 return false;
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;
632 Resolve();
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;
640 switch (state) {
641 case CONTINUE:
642 case POSSIBLE_PW_CHANGE:
643 case NO_MOUNT:
644 // These are intermediate states; we need more info from a request that
645 // is still pending.
646 break;
647 case FAILED_MOUNT:
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(
652 FROM_HERE,
653 base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
654 this,
655 AuthFailure(AuthFailure::COULD_NOT_MOUNT_CRYPTOHOME)));
656 break;
657 case FAILED_REMOVE:
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(
662 FROM_HERE,
663 base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
664 this,
665 AuthFailure(AuthFailure::DATA_REMOVAL_FAILED)));
666 break;
667 case FAILED_TMPFS:
668 // In this case, we tried to mount a tmpfs for guest and failed.
669 task_runner_->PostTask(
670 FROM_HERE,
671 base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
672 this,
673 AuthFailure(AuthFailure::COULD_NOT_MOUNT_TMPFS)));
674 break;
675 case FAILED_TPM:
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,
681 this,
682 AuthFailure(AuthFailure::TPM_ERROR)));
683 break;
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(
688 FROM_HERE,
689 base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
690 this,
691 AuthFailure(AuthFailure::USERNAME_HASH_FAILED)));
692 break;
693 case REMOVED_DATA_AFTER_FAILURE:
694 remove_user_data_on_failure_ = false;
695 task_runner_->PostTask(FROM_HERE,
696 base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
697 this,
698 *delayed_login_failure_));
699 break;
700 case CREATE_NEW:
701 create_if_nonexistent = true;
702 case RECOVER_MOUNT:
703 current_state_->ResetCryptohomeStatus();
704 StartMount(current_state_.get(),
705 scoped_refptr<CryptohomeAuthenticator>(this),
706 false /*ephemeral*/,
707 create_if_nonexistent);
708 break;
709 case NEED_OLD_PW:
710 task_runner_->PostTask(
711 FROM_HERE,
712 base::Bind(&CryptohomeAuthenticator::OnPasswordChangeDetected, this));
713 break;
714 case ONLINE_FAILED:
715 case NEED_NEW_PW:
716 case HAVE_NEW_PW:
717 NOTREACHED() << "Using obsolete ClientLogin code path.";
718 break;
719 case OFFLINE_LOGIN:
720 VLOG(2) << "Offline login";
721 // Fall through.
722 case UNLOCK:
723 VLOG(2) << "Unlock";
724 // Fall through.
725 case ONLINE_LOGIN:
726 VLOG(2) << "Online login";
727 task_runner_->PostTask(
728 FROM_HERE, base::Bind(&CryptohomeAuthenticator::OnAuthSuccess, this));
729 break;
730 case DEMO_LOGIN:
731 VLOG(2) << "Retail mode login";
732 current_state_->user_context.SetIsUsingOAuth(false);
733 task_runner_->PostTask(
734 FROM_HERE,
735 base::Bind(&CryptohomeAuthenticator::OnRetailModeAuthSuccess, this));
736 break;
737 case GUEST_LOGIN:
738 task_runner_->PostTask(
739 FROM_HERE,
740 base::Bind(&CryptohomeAuthenticator::OnOffTheRecordAuthSuccess,
741 this));
742 break;
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));
748 break;
749 case SUPERVISED_USER_LOGIN:
750 current_state_->user_context.SetIsUsingOAuth(false);
751 task_runner_->PostTask(
752 FROM_HERE, base::Bind(&CryptohomeAuthenticator::OnAuthSuccess, this));
753 break;
754 case LOGIN_FAILED:
755 current_state_->ResetCryptohomeStatus();
756 task_runner_->PostTask(FROM_HERE,
757 base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
758 this,
759 current_state_->online_outcome()));
760 break;
761 case OWNER_REQUIRED: {
762 current_state_->ResetCryptohomeStatus();
763 bool success = false;
764 DBusThreadManager::Get()->GetCryptohomeClient()->Unmount(&success);
765 if (!success) {
766 // Maybe we should reboot immediately here?
767 LOG(ERROR) << "Couldn't unmount users home!";
769 task_runner_->PostTask(
770 FROM_HERE,
771 base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
772 this,
773 AuthFailure(AuthFailure::OWNER_REQUIRED)));
774 break;
776 default:
777 NOTREACHED();
778 break;
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()) {
793 return CONTINUE;
796 AuthState state = CONTINUE;
798 if (current_state_->cryptohome_outcome() &&
799 current_state_->username_hash_valid()) {
800 state = ResolveCryptohomeSuccessState();
801 } else {
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)
814 return state;
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.
824 return state;
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_)
833 return FAILED_TMPFS;
834 if (migrate_attempted_)
835 return NEED_OLD_PW;
836 if (check_key_attempted_)
837 return LOGIN_FAILED;
839 if (current_state_->cryptohome_code() ==
840 cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) {
841 // Critical TPM error detected, reboot needed.
842 return FAILED_TPM;
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.
860 return NO_MOUNT;
864 if (!current_state_->username_hash_valid())
865 return FAILED_USERNAME_HASH;
867 return FAILED_MOUNT;
870 CryptohomeAuthenticator::AuthState
871 CryptohomeAuthenticator::ResolveCryptohomeSuccessState() {
872 DCHECK(task_runner_->RunsTasksOnCurrentThread());
873 if (resync_attempted_)
874 return CREATE_NEW;
875 if (remove_attempted_)
876 return REMOVED_DATA_AFTER_FAILURE;
877 if (migrate_attempted_)
878 return RECOVER_MOUNT;
879 if (check_key_attempted_)
880 return UNLOCK;
882 if (current_state_->user_type == user_manager::USER_TYPE_GUEST)
883 return GUEST_LOGIN;
884 if (current_state_->user_type == user_manager::USER_TYPE_RETAIL_MODE)
885 return DEMO_LOGIN;
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;
893 if (!VerifyOwner())
894 return CONTINUE;
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:
904 return NEED_OLD_PW;
905 case NO_MOUNT:
906 return CREATE_NEW;
907 case OFFLINE_LOGIN:
908 return ONLINE_LOGIN;
909 default:
910 NOTREACHED();
911 return offline_state;
915 void CryptohomeAuthenticator::ResolveLoginCompletionStatus() {
916 // Shortcut online state resolution process.
917 current_state_->RecordOnlineLoginStatus(AuthFailure::AuthFailureNone());
918 Resolve();
921 void CryptohomeAuthenticator::SetOwnerState(bool owner_check_finished,
922 bool check_result) {
923 owner_is_verified_ = owner_check_finished;
924 user_can_login_ = check_result;
927 } // namespace chromeos