15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/login/auth/cryptohome_authenticator.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/files/file_path.h"
12b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/location.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
14b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "chromeos/cryptohome/async_method_caller.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/cryptohome/cryptohome_parameters.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/cryptohome/homedir_methods.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/cryptohome/system_salt_getter.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromeos/dbus/cryptohome_client.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/dbus/dbus_thread_manager.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromeos/login/auth/auth_status_consumer.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/login/auth/key.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromeos/login/auth/user_context.h"
23b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "chromeos/login/login_state.h"
2468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "chromeos/login/user_names.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromeos/login_event_recorder.h"
2668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "components/user_manager/user_type.h"
2768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "third_party/cros_system_api/dbus/service_constants.h"
2868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chromeos {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The label used for the key derived from the user's GAIA credentials.
34b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)const char kCryptohomeGAIAKeyLabel[] = "gaia";
35b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
36b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// The name under which the type of key generated from the user's GAIA
37b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// credentials is stored.
38b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)const char kKeyProviderDataTypeName[] = "type";
39b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
40b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// The name under which the salt used to generate a key from the user's GAIA
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// credentials is stored.
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kKeyProviderDataSaltName[] = "salt";
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Hashes |key| with |system_salt| if it its type is KEY_TYPE_PASSWORD_PLAIN.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the keys unmodified otherwise.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<Key> TransformKeyIfNeeded(const Key& key,
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const std::string& system_salt) {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<Key> result(new Key(key));
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result->GetKeyType() == Key::KEY_TYPE_PASSWORD_PLAIN)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->Transform(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF, system_salt);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result.Pass();
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Records status and calls resolver->Resolve().
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TriggerResolve(AuthAttemptState* attempt,
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    scoped_refptr<CryptohomeAuthenticator> resolver,
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    bool success,
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    cryptohome::MountError return_code) {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  attempt->RecordCryptohomeStatus(success, return_code);
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resolver->Resolve();
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Records get hash status and calls resolver->Resolve().
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TriggerResolveHash(AuthAttemptState* attempt,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        scoped_refptr<CryptohomeAuthenticator> resolver,
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        bool success,
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        const std::string& username_hash) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (success)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    attempt->RecordUsernameHash(username_hash);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    attempt->RecordUsernameHashFailed();
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resolver->Resolve();
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Calls TriggerResolve while adding login time marker.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TriggerResolveWithLoginTimeMarker(
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& marker_name,
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AuthAttemptState* attempt,
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<CryptohomeAuthenticator> resolver,
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool success,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cryptohome::MountError return_code) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(marker_name, false);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TriggerResolve(attempt, resolver, success, return_code);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Records an error in accessing the user's cryptohome with the given key and
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// calls resolver->Resolve() after adding a login time marker.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RecordKeyErrorAndResolve(AuthAttemptState* attempt,
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              scoped_refptr<CryptohomeAuthenticator> resolver) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker("CryptohomeMount-End",
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                          false);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  attempt->RecordCryptohomeStatus(false /* success */,
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  cryptohome::MOUNT_ERROR_KEY_FAILURE);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resolver->Resolve();
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Callback invoked when cryptohome's MountEx() method has finished.
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OnMount(AuthAttemptState* attempt,
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             scoped_refptr<CryptohomeAuthenticator> resolver,
101bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch             bool success,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             cryptohome::MountError return_code,
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             const std::string& mount_hash) {
104bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker("CryptohomeMount-End",
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                          false);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  attempt->RecordCryptohomeStatus(success, return_code);
107bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  if (success)
108bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    attempt->RecordUsernameHash(mount_hash);
109bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  else
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    attempt->RecordUsernameHashFailed();
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resolver->Resolve();
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Calls cryptohome's MountEx() method. The key in |attempt->user_context| must
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// not be a plain text password. If the user provided a plain text password,
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that password must be transformed to another key type (by salted hashing)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// before calling this method.
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DoMount(AuthAttemptState* attempt,
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             scoped_refptr<CryptohomeAuthenticator> resolver,
120b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             bool ephemeral,
121b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)             bool create_if_nonexistent) {
122b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  const Key* key = attempt->user_context.GetKey();
123b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // If the |key| is a plain text password, crash rather than attempting to
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // mount the cryptohome with a plain text password.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_NE(Key::KEY_TYPE_PASSWORD_PLAIN, key->GetKeyType());
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set state that username_hash is requested here so that test implementation
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that returns directly would not generate 2 OnLoginSucces() calls.
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  attempt->UsernameHashRequested();
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the authentication's key label to an empty string, which is a wildcard
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // allowing any key to match. This is necessary because cryptohomes created by
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Chrome OS M38 and older will have a legacy key with no label while those
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // created by Chrome OS M39 and newer will have a key with the label
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // kCryptohomeGAIAKeyLabel.
13668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const cryptohome::KeyDefinition auth_key(key->GetSecret(),
13768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                           std::string(),
13868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                           cryptohome::PRIV_DEFAULT);
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cryptohome::MountParameters mount(ephemeral);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (create_if_nonexistent) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mount.create_keys.push_back(cryptohome::KeyDefinition(
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        key->GetSecret(),
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        kCryptohomeGAIAKeyLabel,
144b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        cryptohome::PRIV_DEFAULT));
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
146b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cryptohome::HomedirMethods::GetInstance()->MountEx(
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cryptohome::Identification(attempt->user_context.GetUserID()),
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cryptohome::Authorization(auth_key),
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mount,
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&OnMount, attempt, resolver));
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Callback invoked when the system salt has been retrieved. Transforms the key
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in |attempt->user_context| using Chrome's default hashing algorithm and the
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// system salt, then calls MountEx().
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OnGetSystemSalt(AuthAttemptState* attempt,
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    scoped_refptr<CryptohomeAuthenticator> resolver,
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    bool ephemeral,
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    bool create_if_nonexistent,
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    const std::string& system_salt) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(Key::KEY_TYPE_PASSWORD_PLAIN,
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            attempt->user_context.GetKey()->GetKeyType());
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  attempt->user_context.GetKey()->Transform(
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Key::KEY_TYPE_SALTED_SHA256_TOP_HALF,
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      system_salt);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DoMount(attempt, resolver, ephemeral, create_if_nonexistent);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Callback invoked when cryptohome's GetKeyDataEx() method has finished.
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * If GetKeyDataEx() returned metadata indicating the hashing algorithm and
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   salt that were used to generate the key for this user's cryptohome,
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   transforms the key in |attempt->user_context| with the same parameters.
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Otherwise, starts the retrieval of the system salt so that the key in
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   |attempt->user_context| can be transformed with Chrome's default hashing
178bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch//   algorithm and the system salt.
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The resulting key is then passed to cryptohome's MountEx().
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OnGetKeyDataEx(
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AuthAttemptState* attempt,
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<CryptohomeAuthenticator> resolver,
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool ephemeral,
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool create_if_nonexistent,
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool success,
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cryptohome::MountError return_code,
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<cryptohome::KeyDefinition>& key_definitions) {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (success) {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (key_definitions.size() == 1) {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const cryptohome::KeyDefinition& key_definition = key_definitions.front();
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK_EQ(kCryptohomeGAIAKeyLabel, key_definition.label);
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Extract the key type and salt from |key_definition|, if present.
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_ptr<int64> type;
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_ptr<std::string> salt;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (std::vector<cryptohome::KeyDefinition::ProviderData>::
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               const_iterator it = key_definition.provider_data.begin();
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           it != key_definition.provider_data.end(); ++it) {
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (it->name == kKeyProviderDataTypeName) {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (it->number)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            type.reset(new int64(*it->number));
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          else
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            NOTREACHED();
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else if (it->name == kKeyProviderDataSaltName) {
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (it->bytes)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            salt.reset(new std::string(*it->bytes));
207bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch          else
208bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch            NOTREACHED();
209bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch        }
210bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      }
211bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
212bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      if (type) {
213bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch        if (*type < 0 || *type >= Key::KEY_TYPE_COUNT) {
214bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch          LOG(ERROR) << "Invalid key type: " << *type;
215bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch          RecordKeyErrorAndResolve(attempt, resolver);
216bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch          return;
217bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch        }
218bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
219bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch        if (!salt) {
220bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch          LOG(ERROR) << "Missing salt.";
221bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch          RecordKeyErrorAndResolve(attempt, resolver);
222bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch          return;
223bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch        }
224bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
225bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch        attempt->user_context.GetKey()->Transform(
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            static_cast<Key::KeyType>(*type),
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            *salt);
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DoMount(attempt, resolver, ephemeral, create_if_nonexistent);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "GetKeyDataEx() returned " << key_definitions.size()
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << " entries.";
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SystemSaltGetter::Get()->GetSystemSalt(base::Bind(&OnGetSystemSalt,
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                    attempt,
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                    resolver,
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                    ephemeral,
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                    create_if_nonexistent));
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Starts the process that will mount a user's cryptohome.
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * If the key in |attempt->user_context| is not a plain text password,
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   cryptohome's MountEx() method is called directly with the key.
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Otherwise, the key must be transformed (by salted hashing) before being
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   passed to MountEx(). In that case, cryptohome's GetKeyDataEx() method is
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   called to retrieve metadata indicating the hashing algorithm and salt that
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   were used to generate the key for this user's cryptohome and the key is
251bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch//   transformed accordingly before calling MountEx().
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StartMount(AuthAttemptState* attempt,
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                scoped_refptr<CryptohomeAuthenticator> resolver,
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                bool ephemeral,
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                bool create_if_nonexistent) {
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "CryptohomeMount-Start", false);
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (attempt->user_context.GetKey()->GetKeyType() !=
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          Key::KEY_TYPE_PASSWORD_PLAIN) {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DoMount(attempt, resolver, ephemeral, create_if_nonexistent);
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cryptohome::HomedirMethods::GetInstance()->GetKeyDataEx(
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cryptohome::Identification(attempt->user_context.GetUserID()),
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kCryptohomeGAIAKeyLabel,
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&OnGetKeyDataEx,
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 attempt,
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 resolver,
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 ephemeral,
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 create_if_nonexistent));
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Calls cryptohome's mount method for guest and also get the user hash from
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// cryptohome.
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MountGuestAndGetHash(AuthAttemptState* attempt,
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          scoped_refptr<CryptohomeAuthenticator> resolver) {
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  attempt->UsernameHashRequested();
280b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  cryptohome::AsyncMethodCaller::GetInstance()->AsyncMountGuest(
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&TriggerResolveWithLoginTimeMarker,
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 "CryptohomeMount-End",
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 attempt,
284b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                 resolver));
285b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername(
286b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      attempt->user_context.GetUserID(),
287bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      base::Bind(&TriggerResolveHash, attempt, resolver));
288bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Calls cryptohome's MountPublic method
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MountPublic(AuthAttemptState* attempt,
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 scoped_refptr<CryptohomeAuthenticator> resolver,
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 int flags) {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cryptohome::AsyncMethodCaller::GetInstance()->AsyncMountPublic(
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      attempt->user_context.GetUserID(),
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      flags,
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&TriggerResolveWithLoginTimeMarker,
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 "CryptohomeMountPublic-End",
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 attempt,
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 resolver));
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername(
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      attempt->user_context.GetUserID(),
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&TriggerResolveHash, attempt, resolver));
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Calls cryptohome's key migration method.
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Migrate(AuthAttemptState* attempt,
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             scoped_refptr<CryptohomeAuthenticator> resolver,
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             bool passing_old_hash,
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             const std::string& old_password,
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             const std::string& system_salt) {
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "CryptohomeMigrate-Start", false);
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cryptohome::AsyncMethodCaller* caller =
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cryptohome::AsyncMethodCaller::GetInstance();
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(bartfab): Retrieve the hashing algorithm and salt to use for |old_key|
318bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // from cryptohomed.
319bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  scoped_ptr<Key> old_key =
320bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      TransformKeyIfNeeded(Key(old_password), system_salt);
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<Key> new_key =
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TransformKeyIfNeeded(*attempt->user_context.GetKey(), system_salt);
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (passing_old_hash) {
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    caller->AsyncMigrateKey(attempt->user_context.GetUserID(),
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            old_key->GetSecret(),
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            new_key->GetSecret(),
32790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                            base::Bind(&TriggerResolveWithLoginTimeMarker,
32890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                       "CryptohomeMount-End",
32990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                       attempt,
33090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                       resolver));
33190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  } else {
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    caller->AsyncMigrateKey(attempt->user_context.GetUserID(),
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            new_key->GetSecret(),
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            old_key->GetSecret(),
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            base::Bind(&TriggerResolveWithLoginTimeMarker,
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       "CryptohomeMount-End",
337b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                       attempt,
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       resolver));
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Calls cryptohome's remove method.
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Remove(AuthAttemptState* attempt,
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            scoped_refptr<CryptohomeAuthenticator> resolver) {
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker(
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "CryptohomeRemove-Start", false);
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove(
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      attempt->user_context.GetUserID(),
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&TriggerResolveWithLoginTimeMarker,
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 "CryptohomeRemove-End",
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 attempt,
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 resolver));
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Calls cryptohome's key check method.
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CheckKey(AuthAttemptState* attempt,
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              scoped_refptr<CryptohomeAuthenticator> resolver,
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              const std::string& system_salt) {
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<Key> key =
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TransformKeyIfNeeded(*attempt->user_context.GetKey(), system_salt);
361b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  cryptohome::AsyncMethodCaller::GetInstance()->AsyncCheckKey(
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      attempt->user_context.GetUserID(),
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      key->GetSecret(),
364bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      base::Bind(&TriggerResolve, attempt, resolver));
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
369b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)CryptohomeAuthenticator::CryptohomeAuthenticator(
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::TaskRunner> task_runner,
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AuthStatusConsumer* consumer)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : Authenticator(consumer),
373bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      task_runner_(task_runner),
374bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      migrate_attempted_(false),
375bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      remove_attempted_(false),
376bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      resync_attempted_(false),
377bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      ephemeral_mount_attempted_(false),
378bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      check_key_attempted_(false),
379bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      already_reported_success_(false),
380bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      owner_is_verified_(false),
381bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      user_can_login_(false),
382bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      remove_user_data_on_failure_(false),
383bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      delayed_login_failure_(NULL) {
384bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CryptohomeAuthenticator::AuthenticateToLogin(
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Profile* profile,
388    const UserContext& user_context) {
389  authentication_profile_ = profile;
390  current_state_.reset(new AuthAttemptState(user_context,
391                                            user_manager::USER_TYPE_REGULAR,
392                                            false,  // unlock
393                                            false,  // online_complete
394                                            !IsKnownUser(user_context)));
395  // Reset the verified flag.
396  owner_is_verified_ = false;
397
398  StartMount(current_state_.get(),
399             scoped_refptr<CryptohomeAuthenticator>(this),
400             false /* ephemeral */,
401             false /* create_if_nonexistent */);
402}
403
404void CryptohomeAuthenticator::CompleteLogin(Profile* profile,
405                                            const UserContext& user_context) {
406  authentication_profile_ = profile;
407  current_state_.reset(new AuthAttemptState(user_context,
408                                            user_manager::USER_TYPE_REGULAR,
409                                            true,   // unlock
410                                            false,  // online_complete
411                                            !IsKnownUser(user_context)));
412
413  // Reset the verified flag.
414  owner_is_verified_ = false;
415
416  StartMount(current_state_.get(),
417             scoped_refptr<CryptohomeAuthenticator>(this),
418             false /* ephemeral */,
419             false /* create_if_nonexistent */);
420
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));
427}
428
429void CryptohomeAuthenticator::AuthenticateToUnlock(
430    const UserContext& user_context) {
431  current_state_.reset(new AuthAttemptState(user_context,
432                                            user_manager::USER_TYPE_REGULAR,
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,
440                 current_state_.get(),
441                 scoped_refptr<CryptohomeAuthenticator>(this)));
442}
443
444void CryptohomeAuthenticator::LoginAsSupervisedUser(
445    const UserContext& user_context) {
446  DCHECK(task_runner_->RunsTasksOnCurrentThread());
447  // TODO(nkostylev): Pass proper value for |user_is_new| or remove (not used).
448  current_state_.reset(new AuthAttemptState(user_context,
449                                            user_manager::USER_TYPE_SUPERVISED,
450                                            false,    // unlock
451                                            false,    // online_complete
452                                            false));  // user_is_new
453  remove_user_data_on_failure_ = false;
454  StartMount(current_state_.get(),
455             scoped_refptr<CryptohomeAuthenticator>(this),
456             false /* ephemeral */,
457             false /* create_if_nonexistent */);
458}
459
460void CryptohomeAuthenticator::LoginRetailMode() {
461  DCHECK(task_runner_->RunsTasksOnCurrentThread());
462  // Note: |kRetailModeUserEMail| is used in other places to identify a retail
463  // mode session.
464  current_state_.reset(
465      new AuthAttemptState(UserContext(chromeos::login::kRetailModeUserName),
466                           user_manager::USER_TYPE_RETAIL_MODE,
467                           false,    // unlock
468                           false,    // online_complete
469                           false));  // user_is_new
470  remove_user_data_on_failure_ = false;
471  ephemeral_mount_attempted_ = true;
472  MountGuestAndGetHash(current_state_.get(),
473                       scoped_refptr<CryptohomeAuthenticator>(this));
474}
475
476void CryptohomeAuthenticator::LoginOffTheRecord() {
477  DCHECK(task_runner_->RunsTasksOnCurrentThread());
478  current_state_.reset(
479      new AuthAttemptState(UserContext(chromeos::login::kGuestUserName),
480                           user_manager::USER_TYPE_GUEST,
481                           false,    // unlock
482                           false,    // online_complete
483                           false));  // user_is_new
484  remove_user_data_on_failure_ = false;
485  ephemeral_mount_attempted_ = true;
486  MountGuestAndGetHash(current_state_.get(),
487                       scoped_refptr<CryptohomeAuthenticator>(this));
488}
489
490void CryptohomeAuthenticator::LoginAsPublicSession(
491    const UserContext& user_context) {
492  DCHECK(task_runner_->RunsTasksOnCurrentThread());
493  current_state_.reset(
494      new AuthAttemptState(user_context,
495                           user_manager::USER_TYPE_PUBLIC_ACCOUNT,
496                           false,    // unlock
497                           false,    // online_complete
498                           false));  // user_is_new
499  remove_user_data_on_failure_ = false;
500  ephemeral_mount_attempted_ = true;
501  StartMount(current_state_.get(),
502             scoped_refptr<CryptohomeAuthenticator>(this),
503             true /* ephemeral */,
504             true /* create_if_nonexistent */);
505}
506
507void CryptohomeAuthenticator::LoginAsKioskAccount(
508    const std::string& app_user_id,
509    bool use_guest_mount) {
510  DCHECK(task_runner_->RunsTasksOnCurrentThread());
511
512  const std::string user_id =
513      use_guest_mount ? chromeos::login::kGuestUserName : app_user_id;
514  current_state_.reset(new AuthAttemptState(UserContext(user_id),
515                                            user_manager::USER_TYPE_KIOSK_APP,
516                                            false,    // unlock
517                                            false,    // online_complete
518                                            false));  // user_is_new
519
520  remove_user_data_on_failure_ = true;
521  if (!use_guest_mount) {
522    MountPublic(current_state_.get(),
523                scoped_refptr<CryptohomeAuthenticator>(this),
524                cryptohome::CREATE_IF_MISSING);
525  } else {
526    ephemeral_mount_attempted_ = true;
527    MountGuestAndGetHash(current_state_.get(),
528                         scoped_refptr<CryptohomeAuthenticator>(this));
529  }
530}
531
532void CryptohomeAuthenticator::OnRetailModeAuthSuccess() {
533  DCHECK(task_runner_->RunsTasksOnCurrentThread());
534  VLOG(1) << "Retail mode login success";
535  chromeos::LoginEventRecorder::Get()->RecordAuthenticationSuccess();
536  if (consumer_)
537    consumer_->OnRetailModeAuthSuccess(current_state_->user_context);
538}
539
540void CryptohomeAuthenticator::OnAuthSuccess() {
541  DCHECK(task_runner_->RunsTasksOnCurrentThread());
542  VLOG(1) << "Login success";
543  // Send notification of success
544  chromeos::LoginEventRecorder::Get()->RecordAuthenticationSuccess();
545  {
546    base::AutoLock for_this_block(success_lock_);
547    already_reported_success_ = true;
548  }
549  if (consumer_)
550    consumer_->OnAuthSuccess(current_state_->user_context);
551}
552
553void CryptohomeAuthenticator::OnOffTheRecordAuthSuccess() {
554  DCHECK(task_runner_->RunsTasksOnCurrentThread());
555  chromeos::LoginEventRecorder::Get()->RecordAuthenticationSuccess();
556  if (consumer_)
557    consumer_->OnOffTheRecordAuthSuccess();
558}
559
560void CryptohomeAuthenticator::OnPasswordChangeDetected() {
561  DCHECK(task_runner_->RunsTasksOnCurrentThread());
562  if (consumer_)
563    consumer_->OnPasswordChangeDetected();
564}
565
566void CryptohomeAuthenticator::OnAuthFailure(const AuthFailure& error) {
567  DCHECK(task_runner_->RunsTasksOnCurrentThread());
568
569  // OnAuthFailure will be called again with the same |error|
570  // after the cryptohome has been removed.
571  if (remove_user_data_on_failure_) {
572    delayed_login_failure_ = &error;
573    RemoveEncryptedData();
574    return;
575  }
576  chromeos::LoginEventRecorder::Get()->RecordAuthenticationFailure();
577  LOG(WARNING) << "Login failed: " << error.GetErrorString();
578  if (consumer_)
579    consumer_->OnAuthFailure(error);
580}
581
582void CryptohomeAuthenticator::RecoverEncryptedData(
583    const std::string& old_password) {
584  migrate_attempted_ = true;
585  current_state_->ResetCryptohomeStatus();
586  SystemSaltGetter::Get()->GetSystemSalt(
587      base::Bind(&Migrate,
588                 current_state_.get(),
589                 scoped_refptr<CryptohomeAuthenticator>(this),
590                 true,
591                 old_password));
592}
593
594void CryptohomeAuthenticator::RemoveEncryptedData() {
595  remove_attempted_ = true;
596  current_state_->ResetCryptohomeStatus();
597  task_runner_->PostTask(
598      FROM_HERE,
599      base::Bind(&Remove,
600                 current_state_.get(),
601                 scoped_refptr<CryptohomeAuthenticator>(this)));
602}
603
604void CryptohomeAuthenticator::ResyncEncryptedData() {
605  resync_attempted_ = true;
606  current_state_->ResetCryptohomeStatus();
607  task_runner_->PostTask(
608      FROM_HERE,
609      base::Bind(&Remove,
610                 current_state_.get(),
611                 scoped_refptr<CryptohomeAuthenticator>(this)));
612}
613
614bool CryptohomeAuthenticator::VerifyOwner() {
615  if (owner_is_verified_)
616    return true;
617  // Check if policy data is fine and continue in safe mode if needed.
618  if (!IsSafeMode()) {
619    // Now we can continue with the login and report mount success.
620    user_can_login_ = true;
621    owner_is_verified_ = true;
622    return true;
623  }
624
625  CheckSafeModeOwnership(
626      current_state_->user_context,
627      base::Bind(&CryptohomeAuthenticator::OnOwnershipChecked, this));
628  return false;
629}
630
631void CryptohomeAuthenticator::OnOwnershipChecked(bool is_owner) {
632  // Now we can check if this user is the owner.
633  user_can_login_ = is_owner;
634  owner_is_verified_ = true;
635  Resolve();
636}
637
638void CryptohomeAuthenticator::Resolve() {
639  DCHECK(task_runner_->RunsTasksOnCurrentThread());
640  bool create_if_nonexistent = false;
641  CryptohomeAuthenticator::AuthState state = ResolveState();
642  VLOG(1) << "Resolved state to: " << state;
643  switch (state) {
644    case CONTINUE:
645    case POSSIBLE_PW_CHANGE:
646    case NO_MOUNT:
647      // These are intermediate states; we need more info from a request that
648      // is still pending.
649      break;
650    case FAILED_MOUNT:
651      // In this case, whether login succeeded or not, we can't log
652      // the user in because their data is horked.  So, override with
653      // the appropriate failure.
654      task_runner_->PostTask(
655          FROM_HERE,
656          base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
657                     this,
658                     AuthFailure(AuthFailure::COULD_NOT_MOUNT_CRYPTOHOME)));
659      break;
660    case FAILED_REMOVE:
661      // In this case, we tried to remove the user's old cryptohome at her
662      // request, and the remove failed.
663      remove_user_data_on_failure_ = false;
664      task_runner_->PostTask(
665          FROM_HERE,
666          base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
667                     this,
668                     AuthFailure(AuthFailure::DATA_REMOVAL_FAILED)));
669      break;
670    case FAILED_TMPFS:
671      // In this case, we tried to mount a tmpfs for guest and failed.
672      task_runner_->PostTask(
673          FROM_HERE,
674          base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
675                     this,
676                     AuthFailure(AuthFailure::COULD_NOT_MOUNT_TMPFS)));
677      break;
678    case FAILED_TPM:
679      // In this case, we tried to create/mount cryptohome and failed
680      // because of the critical TPM error.
681      // Chrome will notify user and request reboot.
682      task_runner_->PostTask(FROM_HERE,
683                             base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
684                                        this,
685                                        AuthFailure(AuthFailure::TPM_ERROR)));
686      break;
687    case FAILED_USERNAME_HASH:
688      // In this case, we failed the GetSanitizedUsername request to
689      // cryptohomed. This can happen for any login attempt.
690      task_runner_->PostTask(
691          FROM_HERE,
692          base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
693                     this,
694                     AuthFailure(AuthFailure::USERNAME_HASH_FAILED)));
695      break;
696    case REMOVED_DATA_AFTER_FAILURE:
697      remove_user_data_on_failure_ = false;
698      task_runner_->PostTask(FROM_HERE,
699                             base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
700                                        this,
701                                        *delayed_login_failure_));
702      break;
703    case CREATE_NEW:
704      create_if_nonexistent = true;
705    case RECOVER_MOUNT:
706      current_state_->ResetCryptohomeStatus();
707      StartMount(current_state_.get(),
708                 scoped_refptr<CryptohomeAuthenticator>(this),
709                 false /*ephemeral*/,
710                 create_if_nonexistent);
711      break;
712    case NEED_OLD_PW:
713      task_runner_->PostTask(
714          FROM_HERE,
715          base::Bind(&CryptohomeAuthenticator::OnPasswordChangeDetected, this));
716      break;
717    case ONLINE_FAILED:
718    case NEED_NEW_PW:
719    case HAVE_NEW_PW:
720      NOTREACHED() << "Using obsolete ClientLogin code path.";
721      break;
722    case OFFLINE_LOGIN:
723      VLOG(2) << "Offline login";
724    // Fall through.
725    case UNLOCK:
726      VLOG(2) << "Unlock";
727    // Fall through.
728    case ONLINE_LOGIN:
729      VLOG(2) << "Online login";
730      task_runner_->PostTask(
731          FROM_HERE, base::Bind(&CryptohomeAuthenticator::OnAuthSuccess, this));
732      break;
733    case DEMO_LOGIN:
734      VLOG(2) << "Retail mode login";
735      current_state_->user_context.SetIsUsingOAuth(false);
736      task_runner_->PostTask(
737          FROM_HERE,
738          base::Bind(&CryptohomeAuthenticator::OnRetailModeAuthSuccess, this));
739      break;
740    case GUEST_LOGIN:
741      task_runner_->PostTask(
742          FROM_HERE,
743          base::Bind(&CryptohomeAuthenticator::OnOffTheRecordAuthSuccess,
744                     this));
745      break;
746    case KIOSK_ACCOUNT_LOGIN:
747    case PUBLIC_ACCOUNT_LOGIN:
748      current_state_->user_context.SetIsUsingOAuth(false);
749      task_runner_->PostTask(
750          FROM_HERE, base::Bind(&CryptohomeAuthenticator::OnAuthSuccess, this));
751      break;
752    case SUPERVISED_USER_LOGIN:
753      current_state_->user_context.SetIsUsingOAuth(false);
754      task_runner_->PostTask(
755          FROM_HERE, base::Bind(&CryptohomeAuthenticator::OnAuthSuccess, this));
756      break;
757    case LOGIN_FAILED:
758      current_state_->ResetCryptohomeStatus();
759      task_runner_->PostTask(FROM_HERE,
760                             base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
761                                        this,
762                                        current_state_->online_outcome()));
763      break;
764    case OWNER_REQUIRED: {
765      current_state_->ResetCryptohomeStatus();
766      bool success = false;
767      DBusThreadManager::Get()->GetCryptohomeClient()->Unmount(&success);
768      if (!success) {
769        // Maybe we should reboot immediately here?
770        LOG(ERROR) << "Couldn't unmount users home!";
771      }
772      task_runner_->PostTask(
773          FROM_HERE,
774          base::Bind(&CryptohomeAuthenticator::OnAuthFailure,
775                     this,
776                     AuthFailure(AuthFailure::OWNER_REQUIRED)));
777      break;
778    }
779    default:
780      NOTREACHED();
781      break;
782  }
783}
784
785CryptohomeAuthenticator::~CryptohomeAuthenticator() {
786}
787
788CryptohomeAuthenticator::AuthState CryptohomeAuthenticator::ResolveState() {
789  DCHECK(task_runner_->RunsTasksOnCurrentThread());
790  // If we haven't mounted the user's home dir yet or
791  // haven't got sanitized username value, we can't be done.
792  // We never get past here if any of these two cryptohome ops is still pending.
793  // This is an important invariant.
794  if (!current_state_->cryptohome_complete() ||
795      !current_state_->username_hash_obtained()) {
796    return CONTINUE;
797  }
798
799  AuthState state = CONTINUE;
800
801  if (current_state_->cryptohome_outcome() &&
802      current_state_->username_hash_valid()) {
803    state = ResolveCryptohomeSuccessState();
804  } else {
805    state = ResolveCryptohomeFailureState();
806  }
807
808  DCHECK(current_state_->cryptohome_complete());  // Ensure invariant holds.
809  migrate_attempted_ = false;
810  remove_attempted_ = false;
811  resync_attempted_ = false;
812  ephemeral_mount_attempted_ = false;
813  check_key_attempted_ = false;
814
815  if (state != POSSIBLE_PW_CHANGE && state != NO_MOUNT &&
816      state != OFFLINE_LOGIN)
817    return state;
818
819  if (current_state_->online_complete()) {
820    if (current_state_->online_outcome().reason() == AuthFailure::NONE) {
821      // Online attempt succeeded as well, so combine the results.
822      return ResolveOnlineSuccessState(state);
823    }
824    NOTREACHED() << "Using obsolete ClientLogin code path.";
825  }
826  // if online isn't complete yet, just return the offline result.
827  return state;
828}
829
830CryptohomeAuthenticator::AuthState
831CryptohomeAuthenticator::ResolveCryptohomeFailureState() {
832  DCHECK(task_runner_->RunsTasksOnCurrentThread());
833  if (remove_attempted_ || resync_attempted_)
834    return FAILED_REMOVE;
835  if (ephemeral_mount_attempted_)
836    return FAILED_TMPFS;
837  if (migrate_attempted_)
838    return NEED_OLD_PW;
839  if (check_key_attempted_)
840    return LOGIN_FAILED;
841
842  if (current_state_->cryptohome_code() ==
843      cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) {
844    // Critical TPM error detected, reboot needed.
845    return FAILED_TPM;
846  }
847
848  // Return intermediate states in the following case:
849  // when there is an online result to use;
850  // This is the case after user finishes Gaia login;
851  if (current_state_->online_complete()) {
852    if (current_state_->cryptohome_code() ==
853        cryptohome::MOUNT_ERROR_KEY_FAILURE) {
854      // If we tried a mount but they used the wrong key, we may need to
855      // ask the user for her old password.  We'll only know once we've
856      // done the online check.
857      return POSSIBLE_PW_CHANGE;
858    }
859    if (current_state_->cryptohome_code() ==
860        cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST) {
861      // If we tried a mount but the user did not exist, then we should wait
862      // for online login to succeed and try again with the "create" flag set.
863      return NO_MOUNT;
864    }
865  }
866
867  if (!current_state_->username_hash_valid())
868    return FAILED_USERNAME_HASH;
869
870  return FAILED_MOUNT;
871}
872
873CryptohomeAuthenticator::AuthState
874CryptohomeAuthenticator::ResolveCryptohomeSuccessState() {
875  DCHECK(task_runner_->RunsTasksOnCurrentThread());
876  if (resync_attempted_)
877    return CREATE_NEW;
878  if (remove_attempted_)
879    return REMOVED_DATA_AFTER_FAILURE;
880  if (migrate_attempted_)
881    return RECOVER_MOUNT;
882  if (check_key_attempted_)
883    return UNLOCK;
884
885  if (current_state_->user_type == user_manager::USER_TYPE_GUEST)
886    return GUEST_LOGIN;
887  if (current_state_->user_type == user_manager::USER_TYPE_RETAIL_MODE)
888    return DEMO_LOGIN;
889  if (current_state_->user_type == user_manager::USER_TYPE_PUBLIC_ACCOUNT)
890    return PUBLIC_ACCOUNT_LOGIN;
891  if (current_state_->user_type == user_manager::USER_TYPE_KIOSK_APP)
892    return KIOSK_ACCOUNT_LOGIN;
893  if (current_state_->user_type == user_manager::USER_TYPE_SUPERVISED)
894    return SUPERVISED_USER_LOGIN;
895
896  if (!VerifyOwner())
897    return CONTINUE;
898  return user_can_login_ ? OFFLINE_LOGIN : OWNER_REQUIRED;
899}
900
901CryptohomeAuthenticator::AuthState
902CryptohomeAuthenticator::ResolveOnlineSuccessState(
903    CryptohomeAuthenticator::AuthState offline_state) {
904  DCHECK(task_runner_->RunsTasksOnCurrentThread());
905  switch (offline_state) {
906    case POSSIBLE_PW_CHANGE:
907      return NEED_OLD_PW;
908    case NO_MOUNT:
909      return CREATE_NEW;
910    case OFFLINE_LOGIN:
911      return ONLINE_LOGIN;
912    default:
913      NOTREACHED();
914      return offline_state;
915  }
916}
917
918void CryptohomeAuthenticator::ResolveLoginCompletionStatus() {
919  // Shortcut online state resolution process.
920  current_state_->RecordOnlineLoginStatus(AuthFailure::AuthFailureNone());
921  Resolve();
922}
923
924void CryptohomeAuthenticator::SetOwnerState(bool owner_check_finished,
925                                            bool check_result) {
926  owner_is_verified_ = owner_check_finished;
927  user_can_login_ = check_result;
928}
929
930}  // namespace chromeos
931