Supervised user import: Listen for profile creation/deletion
[chromium-blink-merge.git] / chromeos / login / auth / cryptohome_authenticator.cc
blob00c79d47ca840227748319950fc58f422d6870b3
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/user_manager/user_type.h"
28 #include "third_party/cros_system_api/dbus/service_constants.h"
30 namespace chromeos {
32 namespace {
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);
53 return result.Pass();
56 // Records status and calls resolver->Resolve().
57 void TriggerResolve(const base::WeakPtr<AuthAttemptState>& attempt,
58 scoped_refptr<CryptohomeAuthenticator> resolver,
59 bool success,
60 cryptohome::MountError return_code) {
61 attempt->RecordCryptohomeStatus(success, return_code);
62 resolver->Resolve();
65 // Records get hash status and calls resolver->Resolve().
66 void TriggerResolveHash(const base::WeakPtr<AuthAttemptState>& attempt,
67 scoped_refptr<CryptohomeAuthenticator> resolver,
68 bool success,
69 const std::string& username_hash) {
70 if (success)
71 attempt->RecordUsernameHash(username_hash);
72 else
73 attempt->RecordUsernameHashFailed();
74 resolver->Resolve();
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,
82 bool success,
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",
93 false);
94 attempt->RecordCryptohomeStatus(false /* success */,
95 cryptohome::MOUNT_ERROR_KEY_FAILURE);
96 resolver->Resolve();
99 // Callback invoked when cryptohome's MountEx() method has finished.
100 void OnMount(const base::WeakPtr<AuthAttemptState>& attempt,
101 scoped_refptr<CryptohomeAuthenticator> resolver,
102 bool success,
103 cryptohome::MountError return_code,
104 const std::string& mount_hash) {
105 chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker("CryptohomeMount-End",
106 false);
107 attempt->RecordCryptohomeStatus(success, return_code);
108 if (success)
109 attempt->RecordUsernameHash(mount_hash);
110 else
111 attempt->RecordUsernameHashFailed();
112 resolver->Resolve();
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,
121 bool ephemeral,
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(),
138 std::string(),
139 cryptohome::PRIV_DEFAULT);
140 cryptohome::MountParameters mount(ephemeral);
141 if (create_if_nonexistent) {
142 mount.create_keys.push_back(cryptohome::KeyDefinition(
143 key->GetSecret(),
144 kCryptohomeGAIAKeyLabel,
145 cryptohome::PRIV_DEFAULT));
148 cryptohome::HomedirMethods::GetInstance()->MountEx(
149 cryptohome::Identification(attempt->user_context.GetUserID()),
150 cryptohome::Authorization(auth_key),
151 mount,
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,
160 bool ephemeral,
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,
168 system_salt);
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().
181 void OnGetKeyDataEx(
182 const base::WeakPtr<AuthAttemptState>& attempt,
183 scoped_refptr<CryptohomeAuthenticator> resolver,
184 bool ephemeral,
185 bool create_if_nonexistent,
186 bool success,
187 cryptohome::MountError return_code,
188 const std::vector<cryptohome::KeyDefinition>& key_definitions) {
189 if (success) {
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) {
201 if (it->number)
202 type.reset(new int64(*it->number));
203 else
204 NOTREACHED();
205 } else if (it->name == kKeyProviderDataSaltName) {
206 if (it->bytes)
207 salt.reset(new std::string(*it->bytes));
208 else
209 NOTREACHED();
213 if (type) {
214 if (*type < 0 || *type >= Key::KEY_TYPE_COUNT) {
215 LOG(ERROR) << "Invalid key type: " << *type;
216 RecordKeyErrorAndResolve(attempt, resolver);
217 return;
220 if (!salt) {
221 LOG(ERROR) << "Missing salt.";
222 RecordKeyErrorAndResolve(attempt, resolver);
223 return;
226 attempt->user_context.GetKey()->Transform(
227 static_cast<Key::KeyType>(*type),
228 *salt);
229 DoMount(attempt, resolver, ephemeral, create_if_nonexistent);
230 return;
232 } else {
233 LOG(ERROR) << "GetKeyDataEx() returned " << key_definitions.size()
234 << " entries.";
238 SystemSaltGetter::Get()->GetSystemSalt(base::Bind(&OnGetSystemSalt,
239 attempt,
240 resolver,
241 ephemeral,
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,
255 bool ephemeral,
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);
263 return;
266 cryptohome::HomedirMethods::GetInstance()->GetKeyDataEx(
267 cryptohome::Identification(attempt->user_context.GetUserID()),
268 kCryptohomeGAIAKeyLabel,
269 base::Bind(&OnGetKeyDataEx,
270 attempt,
271 resolver,
272 ephemeral,
273 create_if_nonexistent));
276 // Calls cryptohome's mount method for guest and also get the user hash from
277 // cryptohome.
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",
284 attempt,
285 resolver));
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,
294 int flags) {
295 cryptohome::AsyncMethodCaller::GetInstance()->AsyncMountPublic(
296 attempt->user_context.GetUserID(),
297 flags,
298 base::Bind(&TriggerResolveWithLoginTimeMarker,
299 "CryptohomeMountPublic-End",
300 attempt,
301 resolver));
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|
319 // from cryptohomed.
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",
330 attempt,
331 resolver));
332 } else {
333 caller->AsyncMigrateKey(attempt->user_context.GetUserID(),
334 new_key->GetSecret(),
335 old_key->GetSecret(),
336 base::Bind(&TriggerResolveWithLoginTimeMarker,
337 "CryptohomeMount-End",
338 attempt,
339 resolver));
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",
352 attempt,
353 resolver));
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(),
364 key->GetSecret(),
365 base::Bind(&TriggerResolve, attempt, resolver));
368 } // namespace
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 DCHECK_EQ(user_manager::USER_TYPE_REGULAR, user_context.GetUserType());
391 authentication_context_ = context;
392 current_state_.reset(new AuthAttemptState(user_context,
393 false, // unlock
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 DCHECK_EQ(user_manager::USER_TYPE_REGULAR, user_context.GetUserType());
407 authentication_context_ = context;
408 current_state_.reset(new AuthAttemptState(user_context,
409 true, // unlock
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
422 // parallel.
423 task_runner_->PostTask(
424 FROM_HERE,
425 base::Bind(&CryptohomeAuthenticator::ResolveLoginCompletionStatus, this));
428 void CryptohomeAuthenticator::AuthenticateToUnlock(
429 const UserContext& user_context) {
430 DCHECK_EQ(user_manager::USER_TYPE_REGULAR, user_context.GetUserType());
431 current_state_.reset(new AuthAttemptState(user_context,
432 true, // unlock
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 DCHECK_EQ(user_manager::USER_TYPE_SUPERVISED, user_context.GetUserType());
447 // TODO(nkostylev): Pass proper value for |user_is_new| or remove (not used).
448 current_state_.reset(new AuthAttemptState(user_context,
449 false, // unlock
450 false, // online_complete
451 false)); // user_is_new
452 remove_user_data_on_failure_ = false;
453 StartMount(current_state_->AsWeakPtr(),
454 scoped_refptr<CryptohomeAuthenticator>(this),
455 false /* ephemeral */, false /* create_if_nonexistent */);
458 void CryptohomeAuthenticator::LoginOffTheRecord() {
459 DCHECK(task_runner_->RunsTasksOnCurrentThread());
460 current_state_.reset(
461 new AuthAttemptState(UserContext(user_manager::USER_TYPE_GUEST,
462 chromeos::login::kGuestUserName),
463 false, // unlock
464 false, // online_complete
465 false)); // user_is_new
466 remove_user_data_on_failure_ = false;
467 ephemeral_mount_attempted_ = true;
468 MountGuestAndGetHash(current_state_->AsWeakPtr(),
469 scoped_refptr<CryptohomeAuthenticator>(this));
472 void CryptohomeAuthenticator::LoginAsPublicSession(
473 const UserContext& user_context) {
474 DCHECK(task_runner_->RunsTasksOnCurrentThread());
475 DCHECK_EQ(user_manager::USER_TYPE_PUBLIC_ACCOUNT, user_context.GetUserType());
477 current_state_.reset(
478 new AuthAttemptState(user_context,
479 false, // unlock
480 false, // online_complete
481 false)); // user_is_new
482 remove_user_data_on_failure_ = false;
483 ephemeral_mount_attempted_ = true;
484 StartMount(current_state_->AsWeakPtr(),
485 scoped_refptr<CryptohomeAuthenticator>(this), true /* ephemeral */,
486 true /* create_if_nonexistent */);
489 void CryptohomeAuthenticator::LoginAsKioskAccount(
490 const std::string& app_user_id,
491 bool use_guest_mount) {
492 DCHECK(task_runner_->RunsTasksOnCurrentThread());
494 const std::string user_id =
495 use_guest_mount ? chromeos::login::kGuestUserName : app_user_id;
496 current_state_.reset(new AuthAttemptState(
497 UserContext(user_manager::USER_TYPE_KIOSK_APP, user_id),
498 false, // unlock
499 false, // online_complete
500 false)); // user_is_new
502 remove_user_data_on_failure_ = true;
503 if (!use_guest_mount) {
504 MountPublic(current_state_->AsWeakPtr(),
505 scoped_refptr<CryptohomeAuthenticator>(this),
506 cryptohome::CREATE_IF_MISSING);
507 } else {
508 ephemeral_mount_attempted_ = true;
509 MountGuestAndGetHash(current_state_->AsWeakPtr(),
510 scoped_refptr<CryptohomeAuthenticator>(this));
514 void CryptohomeAuthenticator::OnAuthSuccess() {
515 DCHECK(task_runner_->RunsTasksOnCurrentThread());
516 VLOG(1) << "Login success";
517 // Send notification of success
518 chromeos::LoginEventRecorder::Get()->RecordAuthenticationSuccess();
520 base::AutoLock for_this_block(success_lock_);
521 already_reported_success_ = true;
523 if (consumer_)
524 consumer_->OnAuthSuccess(current_state_->user_context);
527 void CryptohomeAuthenticator::OnOffTheRecordAuthSuccess() {
528 DCHECK(task_runner_->RunsTasksOnCurrentThread());
529 chromeos::LoginEventRecorder::Get()->RecordAuthenticationSuccess();
530 if (consumer_)
531 consumer_->OnOffTheRecordAuthSuccess();
534 void CryptohomeAuthenticator::OnPasswordChangeDetected() {
535 DCHECK(task_runner_->RunsTasksOnCurrentThread());
536 if (consumer_)
537 consumer_->OnPasswordChangeDetected();
540 void CryptohomeAuthenticator::OnAuthFailure(const AuthFailure& error) {
541 DCHECK(task_runner_->RunsTasksOnCurrentThread());
543 // OnAuthFailure will be called again with the same |error|
544 // after the cryptohome has been removed.
545 if (remove_user_data_on_failure_) {
546 delayed_login_failure_ = &error;
547 RemoveEncryptedData();
548 return;
550 chromeos::LoginEventRecorder::Get()->RecordAuthenticationFailure();
551 LOG(WARNING) << "Login failed: " << error.GetErrorString();
552 if (consumer_)
553 consumer_->OnAuthFailure(error);
556 void CryptohomeAuthenticator::RecoverEncryptedData(
557 const std::string& old_password) {
558 migrate_attempted_ = true;
559 current_state_->ResetCryptohomeStatus();
560 SystemSaltGetter::Get()->GetSystemSalt(base::Bind(
561 &Migrate, current_state_->AsWeakPtr(),
562 scoped_refptr<CryptohomeAuthenticator>(this), true, old_password));
565 void CryptohomeAuthenticator::RemoveEncryptedData() {
566 remove_attempted_ = true;
567 current_state_->ResetCryptohomeStatus();
568 task_runner_->PostTask(
569 FROM_HERE, base::Bind(&Remove, current_state_->AsWeakPtr(),
570 scoped_refptr<CryptohomeAuthenticator>(this)));
573 void CryptohomeAuthenticator::ResyncEncryptedData() {
574 resync_attempted_ = true;
575 current_state_->ResetCryptohomeStatus();
576 task_runner_->PostTask(
577 FROM_HERE, base::Bind(&Remove, current_state_->AsWeakPtr(),
578 scoped_refptr<CryptohomeAuthenticator>(this)));
581 bool CryptohomeAuthenticator::VerifyOwner() {
582 if (owner_is_verified_)
583 return true;
584 // Check if policy data is fine and continue in safe mode if needed.
585 if (!IsSafeMode()) {
586 // Now we can continue with the login and report mount success.
587 user_can_login_ = true;
588 owner_is_verified_ = true;
589 return true;
592 CheckSafeModeOwnership(
593 current_state_->user_context,
594 base::Bind(&CryptohomeAuthenticator::OnOwnershipChecked, this));
595 return false;
598 void CryptohomeAuthenticator::OnOwnershipChecked(bool is_owner) {
599 // Now we can check if this user is the owner.
600 user_can_login_ = is_owner;
601 owner_is_verified_ = true;
602 Resolve();
605 void CryptohomeAuthenticator::Resolve() {
606 DCHECK(task_runner_->RunsTasksOnCurrentThread());
607 bool create_if_nonexistent = false;
608 CryptohomeAuthenticator::AuthState state = ResolveState();
609 VLOG(1) << "Resolved state to: " << state;
610 switch (state) {
611 case CONTINUE:
612 case POSSIBLE_PW_CHANGE:
613 case NO_MOUNT:
614 // These are intermediate states; we need more info from a request that
615 // is still pending.
616 break;
617 case FAILED_MOUNT:
618 // In this case, whether login succeeded or not, we can't log
619 // the user in because their data is horked. So, override with
620 // the appropriate failure.
621 task_runner_->PostTask(
622 FROM_HERE,
623 base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
624 this,
625 AuthFailure(AuthFailure::COULD_NOT_MOUNT_CRYPTOHOME)));
626 break;
627 case FAILED_REMOVE:
628 // In this case, we tried to remove the user's old cryptohome at her
629 // request, and the remove failed.
630 remove_user_data_on_failure_ = false;
631 task_runner_->PostTask(
632 FROM_HERE,
633 base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
634 this,
635 AuthFailure(AuthFailure::DATA_REMOVAL_FAILED)));
636 break;
637 case FAILED_TMPFS:
638 // In this case, we tried to mount a tmpfs for guest and failed.
639 task_runner_->PostTask(
640 FROM_HERE,
641 base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
642 this,
643 AuthFailure(AuthFailure::COULD_NOT_MOUNT_TMPFS)));
644 break;
645 case FAILED_TPM:
646 // In this case, we tried to create/mount cryptohome and failed
647 // because of the critical TPM error.
648 // Chrome will notify user and request reboot.
649 task_runner_->PostTask(FROM_HERE,
650 base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
651 this,
652 AuthFailure(AuthFailure::TPM_ERROR)));
653 break;
654 case FAILED_USERNAME_HASH:
655 // In this case, we failed the GetSanitizedUsername request to
656 // cryptohomed. This can happen for any login attempt.
657 task_runner_->PostTask(
658 FROM_HERE,
659 base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
660 this,
661 AuthFailure(AuthFailure::USERNAME_HASH_FAILED)));
662 break;
663 case REMOVED_DATA_AFTER_FAILURE:
664 remove_user_data_on_failure_ = false;
665 task_runner_->PostTask(FROM_HERE,
666 base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
667 this,
668 *delayed_login_failure_));
669 break;
670 case CREATE_NEW:
671 create_if_nonexistent = true;
672 case RECOVER_MOUNT:
673 current_state_->ResetCryptohomeStatus();
674 StartMount(current_state_->AsWeakPtr(),
675 scoped_refptr<CryptohomeAuthenticator>(this),
676 false /*ephemeral*/, create_if_nonexistent);
677 break;
678 case NEED_OLD_PW:
679 task_runner_->PostTask(
680 FROM_HERE,
681 base::Bind(&CryptohomeAuthenticator::OnPasswordChangeDetected, this));
682 break;
683 case ONLINE_FAILED:
684 case NEED_NEW_PW:
685 case HAVE_NEW_PW:
686 NOTREACHED() << "Using obsolete ClientLogin code path.";
687 break;
688 case OFFLINE_LOGIN:
689 VLOG(2) << "Offline login";
690 // Fall through.
691 case UNLOCK:
692 VLOG(2) << "Unlock";
693 // Fall through.
694 case ONLINE_LOGIN:
695 VLOG(2) << "Online login";
696 task_runner_->PostTask(
697 FROM_HERE, base::Bind(&CryptohomeAuthenticator::OnAuthSuccess, this));
698 break;
699 case GUEST_LOGIN:
700 task_runner_->PostTask(
701 FROM_HERE,
702 base::Bind(&CryptohomeAuthenticator::OnOffTheRecordAuthSuccess,
703 this));
704 break;
705 case KIOSK_ACCOUNT_LOGIN:
706 case PUBLIC_ACCOUNT_LOGIN:
707 current_state_->user_context.SetIsUsingOAuth(false);
708 task_runner_->PostTask(
709 FROM_HERE, base::Bind(&CryptohomeAuthenticator::OnAuthSuccess, this));
710 break;
711 case SUPERVISED_USER_LOGIN:
712 current_state_->user_context.SetIsUsingOAuth(false);
713 task_runner_->PostTask(
714 FROM_HERE, base::Bind(&CryptohomeAuthenticator::OnAuthSuccess, this));
715 break;
716 case LOGIN_FAILED:
717 current_state_->ResetCryptohomeStatus();
718 task_runner_->PostTask(FROM_HERE,
719 base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
720 this,
721 current_state_->online_outcome()));
722 break;
723 case OWNER_REQUIRED: {
724 current_state_->ResetCryptohomeStatus();
725 bool success = false;
726 DBusThreadManager::Get()->GetCryptohomeClient()->Unmount(&success);
727 if (!success) {
728 // Maybe we should reboot immediately here?
729 LOG(ERROR) << "Couldn't unmount users home!";
731 task_runner_->PostTask(
732 FROM_HERE,
733 base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
734 this,
735 AuthFailure(AuthFailure::OWNER_REQUIRED)));
736 break;
738 default:
739 NOTREACHED();
740 break;
744 CryptohomeAuthenticator::~CryptohomeAuthenticator() {
747 CryptohomeAuthenticator::AuthState CryptohomeAuthenticator::ResolveState() {
748 DCHECK(task_runner_->RunsTasksOnCurrentThread());
749 // If we haven't mounted the user's home dir yet or
750 // haven't got sanitized username value, we can't be done.
751 // We never get past here if any of these two cryptohome ops is still pending.
752 // This is an important invariant.
753 if (!current_state_->cryptohome_complete() ||
754 !current_state_->username_hash_obtained()) {
755 return CONTINUE;
758 AuthState state = CONTINUE;
760 if (current_state_->cryptohome_outcome() &&
761 current_state_->username_hash_valid()) {
762 state = ResolveCryptohomeSuccessState();
763 } else {
764 state = ResolveCryptohomeFailureState();
767 DCHECK(current_state_->cryptohome_complete()); // Ensure invariant holds.
768 migrate_attempted_ = false;
769 remove_attempted_ = false;
770 resync_attempted_ = false;
771 ephemeral_mount_attempted_ = false;
772 check_key_attempted_ = false;
774 if (state != POSSIBLE_PW_CHANGE && state != NO_MOUNT &&
775 state != OFFLINE_LOGIN)
776 return state;
778 if (current_state_->online_complete()) {
779 if (current_state_->online_outcome().reason() == AuthFailure::NONE) {
780 // Online attempt succeeded as well, so combine the results.
781 return ResolveOnlineSuccessState(state);
783 NOTREACHED() << "Using obsolete ClientLogin code path.";
785 // if online isn't complete yet, just return the offline result.
786 return state;
789 CryptohomeAuthenticator::AuthState
790 CryptohomeAuthenticator::ResolveCryptohomeFailureState() {
791 DCHECK(task_runner_->RunsTasksOnCurrentThread());
792 if (remove_attempted_ || resync_attempted_)
793 return FAILED_REMOVE;
794 if (ephemeral_mount_attempted_)
795 return FAILED_TMPFS;
796 if (migrate_attempted_)
797 return NEED_OLD_PW;
798 if (check_key_attempted_)
799 return LOGIN_FAILED;
801 if (current_state_->cryptohome_code() ==
802 cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) {
803 // Critical TPM error detected, reboot needed.
804 return FAILED_TPM;
807 // Return intermediate states in the following case:
808 // when there is an online result to use;
809 // This is the case after user finishes Gaia login;
810 if (current_state_->online_complete()) {
811 if (current_state_->cryptohome_code() ==
812 cryptohome::MOUNT_ERROR_KEY_FAILURE) {
813 // If we tried a mount but they used the wrong key, we may need to
814 // ask the user for her old password. We'll only know once we've
815 // done the online check.
816 return POSSIBLE_PW_CHANGE;
818 if (current_state_->cryptohome_code() ==
819 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST) {
820 // If we tried a mount but the user did not exist, then we should wait
821 // for online login to succeed and try again with the "create" flag set.
822 return NO_MOUNT;
826 if (!current_state_->username_hash_valid())
827 return FAILED_USERNAME_HASH;
829 return FAILED_MOUNT;
832 CryptohomeAuthenticator::AuthState
833 CryptohomeAuthenticator::ResolveCryptohomeSuccessState() {
834 DCHECK(task_runner_->RunsTasksOnCurrentThread());
835 if (resync_attempted_)
836 return CREATE_NEW;
837 if (remove_attempted_)
838 return REMOVED_DATA_AFTER_FAILURE;
839 if (migrate_attempted_)
840 return RECOVER_MOUNT;
841 if (check_key_attempted_)
842 return UNLOCK;
844 const user_manager::UserType user_type =
845 current_state_->user_context.GetUserType();
846 if (user_type == user_manager::USER_TYPE_GUEST)
847 return GUEST_LOGIN;
848 if (user_type == user_manager::USER_TYPE_PUBLIC_ACCOUNT)
849 return PUBLIC_ACCOUNT_LOGIN;
850 if (user_type == user_manager::USER_TYPE_KIOSK_APP)
851 return KIOSK_ACCOUNT_LOGIN;
852 if (user_type == user_manager::USER_TYPE_SUPERVISED)
853 return SUPERVISED_USER_LOGIN;
855 if (!VerifyOwner())
856 return CONTINUE;
857 return user_can_login_ ? OFFLINE_LOGIN : OWNER_REQUIRED;
860 CryptohomeAuthenticator::AuthState
861 CryptohomeAuthenticator::ResolveOnlineSuccessState(
862 CryptohomeAuthenticator::AuthState offline_state) {
863 DCHECK(task_runner_->RunsTasksOnCurrentThread());
864 switch (offline_state) {
865 case POSSIBLE_PW_CHANGE:
866 return NEED_OLD_PW;
867 case NO_MOUNT:
868 return CREATE_NEW;
869 case OFFLINE_LOGIN:
870 return ONLINE_LOGIN;
871 default:
872 NOTREACHED();
873 return offline_state;
877 void CryptohomeAuthenticator::ResolveLoginCompletionStatus() {
878 // Shortcut online state resolution process.
879 current_state_->RecordOnlineLoginStatus(AuthFailure::AuthFailureNone());
880 Resolve();
883 void CryptohomeAuthenticator::SetOwnerState(bool owner_check_finished,
884 bool check_result) {
885 owner_is_verified_ = owner_check_finished;
886 user_can_login_ = check_result;
889 } // namespace chromeos