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