blob: 503e7d3bb7cc7d11b1a659888cab055d14dd4268 [file] [log] [blame]
// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CRYPTOHOME_USERDATAAUTH_H_
#define CRYPTOHOME_USERDATAAUTH_H_
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <base/check.h>
#include <base/files/file_path.h>
#include <base/location.h>
#include <base/threading/thread.h>
#include <base/unguessable_token.h>
#include <brillo/secure_blob.h>
#include <dbus/bus.h>
#include <tpm_manager/client/tpm_manager_utility.h>
#include <tpm_manager/proto_bindings/tpm_manager.pb.h>
#include <tpm_manager-client/tpm_manager/dbus-proxies.h>
#include "cryptohome/auth_session.h"
#include "cryptohome/challenge_credentials/challenge_credentials_helper.h"
#include "cryptohome/cleanup/low_disk_space_handler.h"
#include "cryptohome/credentials.h"
#include "cryptohome/crypto.h"
#include "cryptohome/fingerprint_manager.h"
#include "cryptohome/firmware_management_parameters.h"
#include "cryptohome/install_attributes.h"
#include "cryptohome/key_challenge_service_factory.h"
#include "cryptohome/key_challenge_service_factory_impl.h"
#include "cryptohome/keyset_management.h"
#include "cryptohome/pkcs11_init.h"
#include "cryptohome/platform.h"
#include "cryptohome/storage/arc_disk_quota.h"
#include "cryptohome/storage/homedirs.h"
#include "cryptohome/storage/mount.h"
#include "cryptohome/storage/mount_factory.h"
#include "cryptohome/user_session.h"
#include "cryptohome/UserDataAuth.pb.h"
namespace cryptohome {
class UserDataAuth {
public:
// TestThreadId used to indicate the thread type.
enum class TestThreadId {
kOriginThread,
kMountThread,
};
UserDataAuth();
~UserDataAuth();
// Note that this function must be called from the thread that created this
// object, so that |origin_task_runner_| is initialized correctly.
bool Initialize();
// This is the initialization function that is called after DBus is connected
// and set_dbus() has been called. Usually Initialize() is called before this
// method.
bool PostDBusInitialize();
// =============== Mount Related Public DBus API ===============
// Methods below are used directly by the DBus interface
// If username is empty, returns true if any mount is mounted, otherwise,
// returns true if the mount associated with the given |username| is mounted.
// For |is_ephemeral_out|, if no username is given, then is_ephemeral_out is
// set to true when any mount is ephemeral. Otherwise, is_ephemeral_out is set
// to true when the mount associated with the given |username| is mounted in
// an ephemeral manner. If nullptr is passed in for is_ephemeral_out, then it
// won't be touched. Ephemeral mount means that the content of the mount is
// cleared once the user logs out.
bool IsMounted(const std::string& username = "",
bool* is_ephemeral_out = nullptr);
// Returns true if the mount that corresponds to the username is mounted,
// false otherwise. If that mount is ephemeral, then is_ephemeral_out is set
// to true, false otherwise. If nullptr is passed in for is_ephemeral_out,
// then it won't be touched. Ephemeral mount means that the content of the
// mount is cleared once the user logs out.
bool IsMountedForUser(const std::string& username,
bool* is_ephemeral_out = nullptr);
// Calling this function will unmount all mounted cryptohomes. It'll return
// true if all mounts are cleanly unmounted.
// Note: This must only be called on mount thread
bool Unmount();
// This function will attempt to mount the requested user's home directory, as
// specified in |request|. Once that's done, it'll call |on_done| to notify
// the result. Note that there's no guarantee on whether |on_done| is called
// before or after this function returns.
void DoMount(
user_data_auth::MountRequest request,
base::OnceCallback<void(const user_data_auth::MountReply&)> on_done);
// Calling this method will kick start the migration to Dircrypto format (from
// eCryptfs). |request| contains the account whose cryptohome to migrate, and
// what whether minimal migration is to be performed. See definition of
// message StartMigrateToDircryptoRequest for more information on minimal
// migration. |progress_callback| is a callback that will be called whenever
// there's progress update from the migration, or if the migration
// completes/fails.
void StartMigrateToDircrypto(
const user_data_auth::StartMigrateToDircryptoRequest& request,
base::RepeatingCallback<
void(const user_data_auth::DircryptoMigrationProgress&)>
progress_callback);
// Determine if the account specified by |account| needs to do Dircrypto
// migration. Returns CRYPTOHOME_ERROR_NOT_SET if the query is successful, and
// the result is stored in |result| (true for migration needed). Otherwise, an
// error code is returned and result is in an undefined state.
user_data_auth::CryptohomeErrorCode NeedsDircryptoMigration(
const cryptohome::AccountIdentifier& account, bool* result);
// Return the size of the user's home directory in number of bytes. If the
// |account| given is non-existent, then 0 is returned.
// Negative values are reserved for future cases whereby we need to do some
// form of error reporting.
int64_t GetAccountDiskUsage(const cryptohome::AccountIdentifier& account);
// =============== Mount Related Public Utilities ===============
// Called during initialization (and on mount events) to ensure old mounts
// are marked for unmount when possible by the kernel. Returns true if any
// mounts were stale and not cleaned up (because of open files).
// Note: This must only be called on mount thread
//
// Parameters
// - force: if true, unmounts all existing shadow mounts.
// if false, unmounts shadows mounts with no open files.
bool CleanUpStaleMounts(bool force);
// Calling this function will reset the TPM context of every mount, that is,
// it'll force a reload of all cryptohome key that is associated with mounts.
void ResetAllTPMContext();
// Set the |force_ecryptfs_| variable, if true, all mounts will use eCryptfs
// for encryption. If eCryptfs is not used, then dircrypto (the ext4
// directory encryption mechanism) is used. Note that this is usually used in
// main() because there's a command line switch for selecting dircrypto or
// eCryptfs.
void set_force_ecryptfs(bool force_ecryptfs) {
force_ecryptfs_ = force_ecryptfs;
}
// Enable version 2 of fscrypt interface.
void set_fscrypt_v2(bool enable_v2) { fscrypt_v2_ = enable_v2; }
// Set the |legacy_mount_| variable. For more information on legacy_mount_,
// see comment of Mount::MountLegacyHome(). Note that this is usually used in
// main() because there's a command line switch for selecting this.
void set_legacy_mount(bool legacy) { legacy_mount_ = legacy; }
// Set |bind_mount_downloads_|. The variable is passed to Mount to define
// whether the Downloads/ directory shall be bind mounted.
void set_bind_mount_downloads(bool bind) { bind_mount_downloads_ = bind; }
// Set thresholds for automatic disk cleanup.
void set_cleanup_threshold(uint64_t cleanup_threshold);
void set_aggressive_cleanup_threshold(uint64_t aggressive_cleanup_threshold);
void set_target_free_space(uint64_t target_free_space);
// Set the |low_disk_space_callback_| variable. This is usually called by the
// DBus adaptor.
void SetLowDiskSpaceCallback(
const base::RepeatingCallback<void(uint64_t)>& callback);
// =============== Key Related Public Utilities ===============
// Add the key specified in the request, and return a CryptohomeErrorCode to
// indicate the status of adding the key. If CryptohomeErrorCode is
// CRYPTOHOME_ERROR_NOT_SET, then the key is successfully added.
user_data_auth::CryptohomeErrorCode AddKey(
const user_data_auth::AddKeyRequest request);
// Add a data restore key, and save the key in |key_out|. If
// CRYPTOHOME_ERROR_NOT_SET is returned, then the key is added and |key_out|
// is valid.
user_data_auth::CryptohomeErrorCode AddDataRestoreKey(
const user_data_auth::AddDataRestoreKeyRequest request,
brillo::SecureBlob* key_out);
// Check the key given in |request| again the currently mounted directories
// and other credentials. |on_done| is called once the operation is completed,
// and the error code is CRYPTOHOME_ERROR_NOT_SET if the key is found. Note
// that this method is asynchronous.
void CheckKey(
const user_data_auth::CheckKeyRequest& request,
base::OnceCallback<void(user_data_auth::CryptohomeErrorCode)> on_done);
// Remove the key given in |request.key| with the authorization given in
// |request.authorization_request|. Returns CRYPTOHOME_ERROR_NOT_SET if the
// key is successfully removed, returns other Error Code if not.
user_data_auth::CryptohomeErrorCode RemoveKey(
const user_data_auth::RemoveKeyRequest request);
// Remove all keys under the account specified by |request.account_id| except
// those listed in |request.exempt_key_data| (only the label).
// |request.authorization_request| contains the authorization to authorize
// this change. Returns CRYPTOHOME_ERROR_NOT_SET if the operation is
// successful.
user_data_auth::CryptohomeErrorCode MassRemoveKeys(
const user_data_auth::MassRemoveKeysRequest request);
// List the keys stored in |homedirs_|. If CRYPTOHOME_ERROR_NOT_SET is
// returned, then |labels_out| contains the label of the keys. Otherwise, the
// content of |labels_out| is undefined.
user_data_auth::CryptohomeErrorCode ListKeys(
const user_data_auth::ListKeysRequest& request,
std::vector<std::string>* labels_out);
// Get the KeyData associated with key that have the label specified in
// |request.key.data.label|. If there's an error processing this request, then
// an error code will be returned, and |found|/|data_out| will be untouched.
// If there's no key with the lable found, then no error will be returned, and
// |found| will be set to false. Otherwise, the key's keydata will be written
// to |data_out| and |found| will be set to true. Note that KeyData is
// actually the key's metadata.
user_data_auth::CryptohomeErrorCode GetKeyData(
const user_data_auth::GetKeyDataRequest& request,
cryptohome::KeyData* data_out,
bool* found);
// This will migrate, or rather say, change the underlying secret that is used
// to protect the user's home directory. The home directory key to change is
// specified by |request.account_id|, the change is authorized by
// |request.authorization_request| and the new secret is specified by
// |request.secret|. This function will return CRYPTOHOME_ERROR_NOT_SET if the
// operation is successful, and other error code if it failed.
user_data_auth::CryptohomeErrorCode MigrateKey(
const user_data_auth::MigrateKeyRequest& request);
// Remove the cryptohome (user's home directory) specified in
// |request.identifier|. If removed successfully, then return
// CRYPTOHOME_ERROR_NOT_SET, otherwise, some error code is returned.
user_data_auth::CryptohomeErrorCode Remove(
const user_data_auth::RemoveRequest& request);
// Rename the cryptohome (user's home directory) specified by
// |request.id_from| to |request.id_to|. If renamed successfully, then return
// CRYPTOHOME_ERROR_NOT_SET, otherwise, some error code is returned.
user_data_auth::CryptohomeErrorCode Rename(
const user_data_auth::RenameRequest& request);
// Return true if we support low entropy credential.
bool IsLowEntropyCredentialSupported();
// =============== ARC Quota Related Public Methods ===============
// Return true is ARC Disk Quota is supported, false otherwise.
bool IsArcQuotaSupported();
// Return the current disk usage for an android uid (a shifted uid) in bytes.
// Will return a negative number if the request fails. See
// cryptohome/arc_disk_quota.h for more details.
int64_t GetCurrentSpaceForArcUid(uid_t android_uid);
// Return the current disk usage for an android gid (a shifted gid) in bytes.
// Will return a negative number if the request fails. See
// cryptohome/arc_disk_quota.h for more details.
int64_t GetCurrentSpaceForArcGid(uid_t android_gid);
// Return the current disk usage for an android project id in bytes.
// Will return a negative number if the request fails. See
// cryptohome/arc_disk_quota.h for more details.
int64_t GetCurrentSpaceForArcProjectId(int project_id);
// Sets the project ID to the file/directory pointed by path.
// See cryptohome/arc_disk_quota.h for more details.
bool SetProjectId(int project_id,
user_data_auth::SetProjectIdAllowedPathType parent_path,
const FilePath& child_path,
const cryptohome::AccountIdentifier& account);
// Sets the project ID of a media_rw_data_file.
// See cryptohome/arc_disk_quota.h for more details.
bool SetMediaRWDataFileProjectId(int project_id, int fd, int* out_error);
// =============== PKCS#11 Related Public Methods ===============
// This initializes the PKCS#11 for a particular mount. Note that this is
// used mostly internally, by Mount related functions to bring up the PKCS#11
// functionalities after mounting.
void InitializePkcs11(UserSession* mount);
// Returns true if and only if PKCS#11 tokens are ready for all mounts.
bool Pkcs11IsTpmTokenReady();
// Return the information regarding a token. If username is empty, then system
// token's information is given. Otherwise, the corresponding user token
// information is given. Note that this function doesn't check if the given
// username is valid or not. If a non-existent user is given, then the result
// is undefined.
// Note that if this method fails to get the slot associated with the token,
// then -1 will be supplied for slot.
user_data_auth::TpmTokenInfo Pkcs11GetTpmTokenInfo(
const std::string& username);
// Calling this method will remove PKCS#11 tokens on all mounts.
// Note that this should only be called from mount thread.
void Pkcs11Terminate();
// Calling this method will restore all the tokens to chaps.
// Note that this should only be called from mount thread.
void Pkcs11RestoreTpmTokens();
// =============== Install Attributes Related Public Methods ===============
// Retrieve the key value pair in install attributes with the key of |name|,
// and return its value in |data_out|. Returns true if and only if the key
// value pair is successfully retrieved. If false is returned, then
// |data_out|'s content is undefined.
bool InstallAttributesGet(const std::string& name,
std::vector<uint8_t>* data_out);
// Insert the key value pair (name, data) into install attributes. Return true
// if and only if the key value pair is successfully inserted.
bool InstallAttributesSet(const std::string& name,
const std::vector<uint8_t>& data);
// Finalize the install attributes. Return true if and only if the install
// attributes is finalized.
bool InstallAttributesFinalize();
// Get the number of key value pair stored in install attributes.
int InstallAttributesCount();
// Return true if and only if the attribute storage is securely stored, that
// is, if the system TPM/Lockbox is being used.
bool InstallAttributesIsSecure();
// Return the current status of the install attributes.
InstallAttributes::Status InstallAttributesGetStatus();
// Convert the InstallAttributes::Status enum to
// user_data_auth::InstallAttributesState protobuf enum.
static user_data_auth::InstallAttributesState
InstallAttributesStatusToProtoEnum(InstallAttributes::Status status);
// =============== Install Attributes Related Utilities ===============
// Return true if this device is enterprise owned.
bool IsEnterpriseOwned() {
AssertOnMountThread();
return enterprise_owned_;
}
// ============= Fingerprint Auth Related Public Methods ==============
// Start fingerprint auth session asynchronously for the user specified in
// |request|, and call |on_done|.
void StartFingerprintAuthSession(
const user_data_auth::StartFingerprintAuthSessionRequest& request,
base::OnceCallback<void(
const user_data_auth::StartFingerprintAuthSessionReply&)> on_done);
// End the current fingerprint auth session.
void EndFingerprintAuthSession();
user_data_auth::GetWebAuthnSecretReply GetWebAuthnSecret(
const user_data_auth::GetWebAuthnSecretRequest& request);
// ========= Firmware Management Parameters Related Public Methods =========
// Retrieve the firmware management parameters. Returns
// CRYPTOHOME_ERROR_NOT_SET if successful, and in that case, |fwmp| will be
// filled with the firmware management parameters. Otherwise, an error code is
// returned and |fwmp|'s content is undefined.
user_data_auth::CryptohomeErrorCode GetFirmwareManagementParameters(
user_data_auth::FirmwareManagementParameters* fwmp);
// Set the firmware management parameters to the value given in |fwmp|.
// Returns CRYPTOHOME_ERROR_NOT_SET if the operation is successful, and other
// error code if it failed.
user_data_auth::CryptohomeErrorCode SetFirmwareManagementParameters(
const user_data_auth::FirmwareManagementParameters& fwmp);
// Remove the firmware management parameters, that is, undefine its NVRAM
// space (if defined). Return true if and only if the firmware management
// parameters are gone
bool RemoveFirmwareManagementParameters();
// =============== Miscellaneous Public APIs ===============
// Retrieve the current system salt. This method call is always successful.
// Note that this should never be called before Initialize() is successful,
// otherwise an assertion will fail.
const brillo::SecureBlob& GetSystemSalt();
// Update the current user activity timestamp for all mounts. time_shift_sec
// is the time, expressed in number of seconds since the last user activity.
// For instance, if the unix timestamp now is x, if this value is 5, then the
// last user activity happened at x-5 unix timestamp.
// This method will return true if the update is successful for all mounts.
// Note that negative |time_shift_sec| values are reserved and should not be
// used.
bool UpdateCurrentUserActivityTimestamp(int time_shift_sec);
// Calling this method will prevent another user from logging in later by
// extending PCR, causing PCR-bound VKKs to be inaccessible. This is used by
// ARC++. |account_id| contains the user that we'll lock to before reboot.
user_data_auth::CryptohomeErrorCode LockToSingleUserMountUntilReboot(
const cryptohome::AccountIdentifier& account_id);
// Retrieve the RSU Device ID, return true if and only if |rsu_device_id| is
// set to the RSU Device ID.
bool GetRsuDeviceId(std::string* rsu_device_id);
// Return true iff powerwash is required. i.e. cannot unseal with user auth.
bool RequiresPowerwash();
// Returns true if and only if the loaded device policy specifies an owner
// user.
bool OwnerUserExists();
// Get a JSON string that represents various state of this service.
// Note: This can only be called on mount thread.
std::string GetStatusString();
// =============== Miscellaneous ===============
// This is called by OwnershipCallback when there's any update on ownership
// status of the TPM.
// Note: This can only be called on mount thread.
void OwnershipCallback(bool status, bool took_ownership);
// Set the current dbus connection, this is usually used by the dbus daemon
// object that owns the instance of this object. During testing, the test
// fixture might call this for dependency injection.
void set_dbus(scoped_refptr<::dbus::Bus> bus) { bus_ = bus; }
// Set the current dbus connection for mount thread, this is usually used by
// the dbus daemon object that owns the instance of this object. During
// testing, the test fixture might call this for dependency injection.
// Note that it is the responsibility of the caller to cleanup/destroy the Bus
// object during destruction.
void set_mount_thread_dbus(scoped_refptr<::dbus::Bus> bus) {
mount_thread_bus_ = bus;
}
// ================= Threading Utilities ==================
// Returns true if we are currently running on the origin thread
bool IsOnOriginThread() const {
// Note that this function should not rely on |origin_task_runner_| because
// it may be unavailable when this function is first called by
// UserDataAuth::Initialize()
if (!mount_thread_ && mount_task_runner_) {
return current_thread_id_for_test_ == TestThreadId::kOriginThread;
}
return base::PlatformThread::CurrentId() == origin_thread_id_;
}
// Returns true if we are currently running on the mount thread
bool IsOnMountThread() const {
if (!mount_thread_) {
return current_thread_id_for_test_ == TestThreadId::kMountThread;
}
// GetThreadId blocks if the thread is not started yet.
return mount_thread_->IsRunning() &&
base::PlatformThread::CurrentId() == mount_thread_->GetThreadId();
}
// DCHECK if we are running on the origin thread. Will have no effect
// in production.
void AssertOnOriginThread() const { DCHECK(IsOnOriginThread()); }
// DCHECK if we are running on the mount thread. Will have no effect
// in production.
void AssertOnMountThread() const { DCHECK(IsOnMountThread()); }
// Post Task to origin thread. For the caller, from_here is usually FROM_HERE
// macro, while task is a callback function to be posted. Will return true if
// the task may be run sometime in the future, false if it will definitely not
// run. Specify |delay| if you want the task to be deferred for |delay| amount
// of time.
bool PostTaskToOriginThread(const base::Location& from_here,
base::OnceClosure task,
const base::TimeDelta& delay = base::TimeDelta());
// Post Task to mount thread. For the caller, from_here is usually FROM_HERE
// macro, while task is a callback function to be posted. Will return true if
// the task may be run sometime in the future, false if it will definitely not
// run. Specify |delay| if you want the task to be deferred for |delay| amount
// of time.
bool PostTaskToMountThread(const base::Location& from_here,
base::OnceClosure task,
const base::TimeDelta& delay = base::TimeDelta());
// ================= Testing Utilities ==================
// Note that all functions below in this section should only be used for unit
// testing purpose only.
// Override |crypto_| for testing purpose
void set_crypto(cryptohome::Crypto* crypto) { crypto_ = crypto; }
// Override |keyset_management_| for testing purpose
void set_keyset_management(KeysetManagement* value) {
keyset_management_ = value;
}
// Override |homedirs_| for testing purpose
void set_homedirs(cryptohome::HomeDirs* homedirs) { homedirs_ = homedirs; }
// Override |tpm_| for testing purpose
void set_tpm(Tpm* tpm) { tpm_ = tpm; }
// Override |cryptohome_keys_manager_| for testing purpose
void set_cryptohome_keys_manager(
CryptohomeKeysManager* cryptohome_keys_manager) {
cryptohome_keys_manager_ = cryptohome_keys_manager;
}
// Override |tpm_manager_util_| for testing purpose
void set_tpm_manager_util_(tpm_manager::TpmManagerUtility* tpm_manager_util) {
tpm_manager_util_ = tpm_manager_util;
}
// Override |platform_| for testing purpose
void set_platform(cryptohome::Platform* platform) { platform_ = platform; }
// override |chaps_client_| for testing purpose
void set_chaps_client(chaps::TokenManagerClient* chaps_client) {
chaps_client_ = chaps_client;
}
// Override |install_attrs_| for testing purpose
void set_install_attrs(InstallAttributes* install_attrs) {
install_attrs_ = install_attrs;
}
// Override |arc_disk_quota_| for testing purpose
void set_arc_disk_quota(cryptohome::ArcDiskQuota* arc_disk_quota) {
arc_disk_quota_ = arc_disk_quota;
}
// Override |pkcs11_init_| for testing purpose
void set_pkcs11_init(Pkcs11Init* pkcs11_init) { pkcs11_init_ = pkcs11_init; }
// Override |firmware_management_parameters_| for testing purpose
void set_firmware_management_parameters(FirmwareManagementParameters* fwmp) {
firmware_management_parameters_ = fwmp;
}
// Override |fingerprint_manager_| for testing purpose
void set_fingerprint_manager(FingerprintManager* fingerprint_manager) {
fingerprint_manager_ = fingerprint_manager;
}
// Override |mount_factory_| for testing purpose
void set_mount_factory(MountFactory* mount_factory) {
mount_factory_ = mount_factory;
}
// Override |challenge_credentials_helper_| for testing purpose
void set_challenge_credentials_helper(
ChallengeCredentialsHelper* challenge_credentials_helper) {
challenge_credentials_helper_ = challenge_credentials_helper;
}
// Override |key_challenge_service_factory_| for testing purpose
void set_key_challenge_service_factory(
KeyChallengeServiceFactory* key_challenge_service_factory) {
key_challenge_service_factory_ = key_challenge_service_factory;
}
// Override |origin_task_runner_| for testing purpose
void set_origin_task_runner(
scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner) {
origin_task_runner_ = origin_task_runner;
}
// Override |mount_task_runner_| for testing purpose
void set_mount_task_runner(
scoped_refptr<base::SingleThreadTaskRunner> mount_task_runner) {
mount_task_runner_ = mount_task_runner;
}
// Override |current_thread_id_for_test_| for testing purpose
void set_current_thread_id_for_test(TestThreadId current_thread_id_for_test) {
current_thread_id_for_test_ = current_thread_id_for_test;
}
// Retrieve the current thread id, for testing purpose only.
TestThreadId get_current_thread_id_for_test() {
return current_thread_id_for_test_;
}
// Override |low_disk_space_handler_| for testing purpose
void set_low_disk_space_handler(LowDiskSpaceHandler* low_disk_space_handler) {
low_disk_space_handler_ = low_disk_space_handler;
}
// Retrieve the session associated with the given user, for testing purpose
// only.
UserSession* get_session_for_user(const std::string& username) {
if (sessions_.count(username) == 0)
return nullptr;
return sessions_[username].get();
}
// Associate a particular session object |session| with the username
// |username| for testing purpose
void set_session_for_user(const std::string& username, UserSession* session) {
sessions_[username] = session;
}
// Override the time between each run of UploadAlertsDataCallback() for
// testing. This is so that we can finish the unit test in a shorter time.
void set_upload_alerts_period_ms(int value) {
upload_alerts_period_ms_ = value;
}
bool StartAuthSession(
user_data_auth::StartAuthSessionRequest request,
base::OnceCallback<void(const user_data_auth::StartAuthSessionReply&)>
on_done);
bool AddCredentials(
user_data_auth::AddCredentialsRequest request,
base::OnceCallback<void(const user_data_auth::AddCredentialsReply&)>
on_done);
bool AuthenticateAuthSession(
user_data_auth::AuthenticateAuthSessionRequest request,
base::OnceCallback<
void(const user_data_auth::AuthenticateAuthSessionReply&)> on_done);
private:
// base::Thread subclass so we can implement CleanUp.
class MountThread : public base::Thread {
public:
explicit MountThread(const std::string& name, UserDataAuth* uda)
: base::Thread(name), uda_(uda) {
CHECK(uda_);
}
MountThread(const MountThread&) = delete;
MountThread& operator=(const MountThread&) = delete;
~MountThread() override { Stop(); }
private:
void CleanUp() override { uda_->ShutdownTask(); }
UserDataAuth* const uda_;
};
// Shutdown to be run on the worker thread.
void ShutdownTask();
// Note: In Service class (the class that this class is refactored from),
// there is a initialize_tpm_ member variable, but it is almost unused and
// always set to true there, so in this class, if we are migrating any code
// from Service class and initialize_tpm_ is used there, then we'll just
// assume it's true and not have a initialize_tpm_ variable here.
// This create a dbus connection whose origin thread is UserDataAuth's mount
// thread.
void CreateMountThreadDBus();
// =============== Mount Related Utilities ===============
// Returns the UserSession object associated with the given username
scoped_refptr<UserSession> GetUserSession(const std::string& username);
// Filters out active mounts from |mounts|, populating |active_mounts| set.
// If |include_busy_mount| is false, then stale mounts with open files and
// mount points connected to children of the mount source will be treated as
// active mount, and be moved from |mounts| to |active_mounts|. Otherwise, all
// stale mounts are included in |mounts|. Returns true if |include_busy_mount|
// is true and there's at least one stale mount with open file(s) and treated
// as active mount during the process.
bool FilterActiveMounts(
std::multimap<const base::FilePath, const base::FilePath>* mounts,
std::multimap<const base::FilePath, const base::FilePath>* active_mounts,
bool include_busy_mount);
// Populates |mounts| with ephemeral cryptohome mount points.
void GetEphemeralLoopDevicesMounts(
std::multimap<const base::FilePath, const base::FilePath>* mounts);
// Unload any user pkcs11 tokens _not_ belonging to one of the mounts in
// |exclude|. This is used to clean up any stale loaded tokens after a
// cryptohome crash.
// Note that system tokens are not affected.
bool UnloadPkcs11Tokens(const std::vector<base::FilePath>& exclude);
// Safely empties the MountMap and may request unmounting. If |unmount| is
// true, the return value will reflect if all mounts unmounted cleanly or not.
// That is, it'll be true if all unmounts are clean and successful.
// Note: This must only be called on mount thread
bool RemoveAllMounts(bool unmount);
// Calling this function will try to ensure that |public_mount_salt_| is ready
// to use. If it's not ready, we'll generate it. Returns true if
// |public_mount_salt_| is ready.
bool CreatePublicMountSaltIfNeeded();
// Gets passkey for |public_mount_id|. Returns true if a passkey is generated
// successfully. Otherwise, returns false.
bool GetPublicMountPassKey(const std::string& public_mount_id,
std::string* public_mount_passkey);
// Determines whether the mount request should be ephemeral. On error, returns
// false and sets the error code in |error|. Otherwise, returns true and fills
// the result in |is_ephemeral|.
bool GetShouldMountAsEphemeral(
const std::string& account_id,
bool is_ephemeral_mount_requested,
bool has_create_request,
bool* is_ephemeral,
user_data_auth::CryptohomeErrorCode* error) const;
// Returns either and existing or a newly created UserSession, if not present.
scoped_refptr<UserSession> GetOrCreateUserSession(
const std::string& username);
// Builds the PCR restrictions to be applied to the challenge-protected vault
// keyset.
void GetChallengeCredentialsPcrRestrictions(
const std::string& obfuscated_username,
std::vector<std::map<uint32_t, brillo::Blob>>* pcr_restrictions);
// Safely removes the reference to the UserSession from. This method returns
// true if as a result of the operation there is no reference to a session of
// the given user (including if it was absent in the first place).
bool RemoveUserSession(const std::string& username);
// Calling this method will mount the home directory for guest users.
// This is usually called by DoMount(). Note that this method is asynchronous,
// and will call |on_done| exactly once to deliver the result regardless of
// whether the operation is successful.
void MountGuest(
base::OnceCallback<void(const user_data_auth::MountReply&)> on_done);
// Performs the lazy part of the initialization that is required for
// performing operations with challenge-response keys. Returns whether
// succeeded.
bool InitForChallengeResponseAuth(
user_data_auth::CryptohomeErrorCode* error_code);
// This is a utility function used by DoMount(). It is called if the request
// mounting operation requires challenge response authentication. i.e. The key
// for the storage is sealed.
void DoChallengeResponseMount(
const user_data_auth::MountRequest& request,
const Mount::MountArgs& mount_args,
base::OnceCallback<void(const user_data_auth::MountReply&)> on_done);
// This is a utility function used by DoChallengeResponseMount(), and is
// called once we're done doing challenge response authentication.
void OnChallengeResponseMountCredentialsObtained(
const user_data_auth::MountRequest& request,
const Mount::MountArgs mount_args,
base::OnceCallback<void(const user_data_auth::MountReply&)> on_done,
std::unique_ptr<Credentials> credentials);
// This is a utility function used by DoMount(). It is called either by
// DoMount() (when using password for authentication.), or by
// OnChallengeResponseMountCredentialsObtained() (when using challenge
// response authentication.).
void ContinueMountWithCredentials(
const user_data_auth::MountRequest& request,
std::unique_ptr<Credentials> credentials,
const Mount::MountArgs& mount_args,
base::OnceCallback<void(const user_data_auth::MountReply&)> on_done);
// Called on Mount thread. This triggers the credentials verification steps
// that are specific to challenge-response keys, going through
// {TryLightweightChallengeResponseCheckKeyEx(),
// OnLightweightChallengeResponseCheckKeyExDone()} and/or
// {DoFullChallengeResponseCheckKeyEx(),
// OnFullChallengeResponseCheckKeyExDone()}.
void DoChallengeResponseCheckKey(
const user_data_auth::CheckKeyRequest& request,
base::OnceCallback<void(user_data_auth::CryptohomeErrorCode)> on_done);
void TryLightweightChallengeResponseCheckKey(
const user_data_auth::CheckKeyRequest& request,
base::OnceCallback<void(user_data_auth::CryptohomeErrorCode)> on_done);
void OnLightweightChallengeResponseCheckKeyDone(
const user_data_auth::CheckKeyRequest& request,
base::OnceCallback<void(user_data_auth::CryptohomeErrorCode)> on_done,
bool is_key_valid);
void DoFullChallengeResponseCheckKey(
const user_data_auth::CheckKeyRequest& request,
base::OnceCallback<void(user_data_auth::CryptohomeErrorCode)> on_done);
void OnFullChallengeResponseCheckKeyDone(
base::OnceCallback<void(user_data_auth::CryptohomeErrorCode)> on_done,
std::unique_ptr<Credentials> credentials);
// ================ Fingerprint Auth Related Methods ==================
// Called on Mount thread. This creates a dbus proxy for Biometrics Daemon
// and connects to signals.
void CreateFingerprintManager();
// Called on Mount thread when fingerprint auth session starts or fails to
// start.
void OnFingerprintStartAuthSessionResp(
base::OnceCallback<void(
const user_data_auth::StartFingerprintAuthSessionReply&)> on_done,
bool success);
// Called on Mount thread. Scheduled by CheckKey(). Callback for one
// fingerprint scan. Completes fingerprint CheckKey by running |on_done|.
void CompleteFingerprintCheckKey(
base::OnceCallback<void(const user_data_auth::CryptohomeErrorCode)>
on_done,
FingerprintScanStatus status);
// =============== Periodic Maintenance Related Methods ===============
// Called periodically on Mount thread to detect low disk space and emit a
// signal if detected. This also does various cleanup task.
void LowDiskCallback();
// This is called periodically, and does some routine cleanups. Currently this
// free disk space consumed by unused cryptohomes and reset the dictionary
// attack mitigation.
void DoAutoCleanup();
// Does what its name suggests. Usually called by DoAutoCleanup().
void ResetDictionaryAttackMitigation();
// This method uploads the TPM Alerts data UMA.
void UploadAlertsDataCallback();
// This method takes entropy from the TPM and seeds it to /dev/urandom.
void SeedUrandom();
// =============== PKCS#11 Related Utilities ===============
// This is called when TPM is enabled and owned, so that we can continue
// the initialization of any PKCS#11 that was paused because TPM wasn't
// ready.
void ResumeAllPkcs11Initialization();
// =============== Install Attributes Related Utilities ===============
// Set whether this device is enterprise owned. Calling this method will have
// effect on all currently mounted mounts. This can only be called on
// mount_thread_.
void SetEnterpriseOwned(bool enterprise_owned);
// Detect whether this device is enterprise owned, and call
// SetEnterpriseOwned(). This can only be called on origin thread.
void DetectEnterpriseOwnership();
// Call this method to initialize the install attributes functionality. This
// can only be called on origin thread.
void InitializeInstallAttributes();
// Calling this method will finalize the install attributes if we current have
// a non-guest mount mounted. This can only be called on mount thread.
void FinalizeInstallAttributesIfMounted();
// =============== Signal Related Utilities/Callback ===============
// This is called whenever the signal handlers for signals on tpm_manager's
// interface is registered/connected. This is only used by the signal handler
// registration function in tpm_manager's generated D-Bus proxy.
void OnTpmManagerSignalConnected(const std::string& interface,
const std::string& signal,
bool success);
// This is called whenever the OwnershipTaken signal is emitted by
// tpm_manager. This will notify |tpm_| about the emitted signal.
// Note: The caller of it may neither origin thread nor mount thread.
void OnOwnershipTakenSignal();
// =============== Stateful Recovery related Helpers ===============
// This is a utility function for stateful recovery functionality to call when
// it wants to mount a user's home directory. The user specified by
// |username|'s home is mounted with |passkey|, and if successfully mounted,
// the function returns true and set |out_home_path| to the mounted home.
// Otherwise, return false. Note that this function must log any error itself,
// no logging will be done by the caller.
bool StatefulRecoveryMount(const std::string& username,
const std::string& passkey,
FilePath* out_home_path);
// This is a utility function for stateful recovery to unmount all user's home
// directories. It'll return true if all the user's home directories are
// successfully unmounted. Otherwise, it'll return false. Note that this
// function must log any error itself, no logging will be done by the caller.
bool StatefulRecoveryUnmount();
// This is a utility function for stateful recovery to check if a user is the
// owner. It'll return true if the user specified by |username| is the owner,
// and false otherwise.
bool StatefulRecoveryIsOwner(const std::string& username);
// Creates and initialized MountObject for user
scoped_refptr<Mount> CreateMount(const std::string& username);
// Ensures BootLockbox is finalized;
void EnsureBootLockboxFinalized();
// =============== Auth Session Related Helpers ===============
void RemoveAuthSessionWithToken(const base::UnguessableToken& token);
// =============== Threading Related Variables ===============
// The task runner that belongs to the thread that created this UserDataAuth
// object. Currently, this is required to be the same as the dbus thread's
// task runner.
scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
// The thread ID of the thread that created this UserDataAuth object.
// Currently, this is required to be th esame as the dbus thread's task
// runner.
base::PlatformThreadId origin_thread_id_;
// The thread for performing long running, or mount related operations
std::unique_ptr<MountThread> mount_thread_;
// The task runner that belongs to the mount thread.
scoped_refptr<base::SingleThreadTaskRunner> mount_task_runner_;
// This variable is used only for unit testing purpose. We could use this to
// know current task is running on origin thread or mount thread.
TestThreadId current_thread_id_for_test_ = TestThreadId::kOriginThread;
// =============== Basic Utilities Related Variables ===============
// The system salt that is used for obfuscating the username
brillo::SecureBlob system_salt_;
// The object for accessing the TPM
// Note that TPM doesn't use the unique_ptr for default pattern, since the tpm
// is a singleton - we don't want it getting destroyed when we are.
Tpm* tpm_;
// The default cryptohome key loader object
std::unique_ptr<CryptohomeKeysManager> default_cryptohome_keys_manager_;
// The cryptohome key loader object
CryptohomeKeysManager* cryptohome_keys_manager_;
tpm_manager::TpmManagerUtility* tpm_manager_util_;
// The default platform object for accessing platform related functionalities
std::unique_ptr<cryptohome::Platform> default_platform_;
// The actual platform object used by this class, usually set to
// default_platform_, but can be overridden for testing
cryptohome::Platform* platform_;
// The default crypto object for performing cryptographic operations
std::unique_ptr<cryptohome::Crypto> default_crypto_;
// The actual crypto object used by this class, usually set to
// default_crypto_, but can be overridden for testing
cryptohome::Crypto* crypto_;
// The default token manager client for accessing chapsd's PKCS#11 interface
std::unique_ptr<chaps::TokenManagerClient> default_chaps_client_;
// The actual token manager client used by this class, usually set to
// default_chaps_client_, but can be overridden for testing.
chaps::TokenManagerClient* chaps_client_;
// A dbus connection, this is used by any code in this class that needs access
// to the system DBus and accesses it on the origin thread.
scoped_refptr<::dbus::Bus> bus_;
// A dbus connection, this is used by any code in this class that needs access
// to the system DBus and accesses it on the mount thread. Such as when
// creating an instance of KeyChallengeService.
scoped_refptr<::dbus::Bus> mount_thread_bus_;
// The default PKCS#11 init object that is used to supply some PKCS#11 related
// information.
std::unique_ptr<Pkcs11Init> default_pkcs11_init_;
// The actual PKCS#11 init object that is used by this class, but can be
// overridden for testing.
Pkcs11Init* pkcs11_init_;
// The default Firmware Management Parameters object for accessing any
// Firmware Management Parameters related functionalities.
std::unique_ptr<FirmwareManagementParameters>
default_firmware_management_params_;
// The actual Firmware Management Parameters object that is used by this
// class, but can be overridden for testing.
FirmwareManagementParameters* firmware_management_parameters_;
// The default Fingerprint Manager object for fingerprint authentication.
std::unique_ptr<FingerprintManager> default_fingerprint_manager_;
// The actual Fingerprint Manager object that is used by this class, but
// can be overridden for testing.
FingerprintManager* fingerprint_manager_;
// The amount of time in between each run of UploadAlertsDataCallback()
int upload_alerts_period_ms_;
// This is set to true iff OwnershipCallback has run.
bool ownership_callback_has_run_;
// =============== Install Attributes Related Variables ===============
// The default install attributes object, for accessing install attributes
// related functionality.
std::unique_ptr<cryptohome::InstallAttributes> default_install_attrs_;
// The actual install attributes object used by this class, usually set to
// |default_install_attrs_|, but can be overridden for testing. This object
// should only be accessed on the origin thread.
cryptohome::InstallAttributes* install_attrs_;
// Whether this device is an enterprise owned device. Write access should only
// happen on mount thread.
bool enterprise_owned_;
// =============== Mount Related Variables ===============
// Note: In Service class (the class that this class is refactored from),
// there is a mounts_lock_ lock for inserting/removal of mounts_ map. However,
// in this class, all accesses to mounts_ should happen on the mount thread,
// so no lock is needed.
// This is an unused variable that's lifted over from service.cc. It is kept
// here for the purpose of keeping the code in userdatauth.h/.cc as close as
// possible to the version in service.cc.
bool reported_pkcs11_init_fail_;
// This holds a timestamp for each user that is the time that the user was
// active.
std::unique_ptr<UserOldestActivityTimestampCache> user_timestamp_cache_;
// The homedirs_ object in normal operation
std::unique_ptr<HomeDirs> default_homedirs_;
// This holds the object that records informations about the homedirs.
// This is usually set to default_homedirs_, but can be overridden for
// testing.
// This is to be accessed from the mount thread only because there's no
// guarantee on thread safety of the HomeDirs object.
HomeDirs* homedirs_;
// The keyset_management_ object in normal operation.
std::unique_ptr<KeysetManagement> default_keyset_management_;
// This holds the object that records information about the
// keyset_management. This is usually set to default_keyset_management_, but
// can be overridden for testing. This is to be accessed from the mount thread
// only because there's no guarantee on thread safety of the HomeDirs object.
KeysetManagement* keyset_management_;
// Defines a type for tracking Mount objects for each user by username.
typedef std::map<const std::string, scoped_refptr<UserSession>>
UserSessionMap;
// Records the UserSession objects associated with each username.
// This and its content should only be accessed from the mount thread.
// TODO(b/126022424): Verify that this access paradigm doesn't cause
// measurable performance impact.
UserSessionMap sessions_;
// The low_disk_space_handler_ object in normal operation
std::unique_ptr<LowDiskSpaceHandler> default_low_disk_space_handler_;
// This holds the object that checks for low disk space and performs disk
// cleanup.
// This is to be accessed from the mount thread only because there's no
// guarantee on thread safety of the HomeDirs object.
LowDiskSpaceHandler* low_disk_space_handler_;
// TODO(dlunev): This three variables are a hack to pass cleanup parameters
// from main to the actual object. The reason it is done like this is that
// the object is created in UserDataAuth::Initialize, which is called from the
// daemonization function, but they are attempted to be set from the main,
// before the daemonization. Once service.cc is gone, we shall refactor the
// whole initialization process of UserDataAuth to avoid such hacks.
uint64_t disk_cleanup_threshold_;
uint64_t disk_cleanup_aggressive_threshold_;
uint64_t disk_cleanup_target_free_space_;
// The default mount factory instance that is used for creating Mount objects.
std::unique_ptr<cryptohome::MountFactory> default_mount_factory_;
// The mount factory instance that is actually used by this class to create
// Mount object. This is usually |default_mount_factory_|, but can be
// overridden for testing.
cryptohome::MountFactory* mount_factory_;
// This holds the salt that is used to derive the passkey for public mounts.
brillo::SecureBlob public_mount_salt_;
// Default challenge credential helper utility object. This object is required
// for doing a challenge response style login, and is only lazily created when
// mounting a mount that requires challenge response login type is performed.
std::unique_ptr<ChallengeCredentialsHelper>
default_challenge_credentials_helper_;
// Actual challenge credential helper utility object used by this class.
// Usually set to |default_challenge_credentials_helper_|, but can be
// overridden for testing.
ChallengeCredentialsHelper* challenge_credentials_helper_ = nullptr;
// Default factory of key challenge services. This object is required for
// doing a challenge response style login.
KeyChallengeServiceFactoryImpl default_key_challenge_service_factory_;
// Actual factory of key challenge services that is used by this class.
// Usually set to |default_key_challenge_service_factory_|, but can be
// overridden for testing.
KeyChallengeServiceFactory* key_challenge_service_factory_ =
&default_key_challenge_service_factory_;
// Guest user's username.
std::string guest_user_;
// Force the use of eCryptfs. If eCryptfs is not used, then dircrypto (the
// ext4 directory encryption) is used.
bool force_ecryptfs_;
// Force v2 version for fscrypt interface.
bool fscrypt_v2_;
// Whether we are using legacy mount. See Mount::MountLegacyHome()'s comment
// for more information.
bool legacy_mount_;
// Whether Downloads/ should be bind mounted.
bool bind_mount_downloads_;
// The default ARC Disk Quota object. This is used to provide Quota related
// information function for ARC.
std::unique_ptr<ArcDiskQuota> default_arc_disk_quota_;
// The actual ARC Disk Quota object used by this class. Usually set to
// default_arc_disk_quota_, but can be overridden for testing.
ArcDiskQuota* arc_disk_quota_;
// Defines a type for tracking Auth Sessions by token.
typedef std::map<const base::UnguessableToken, std::unique_ptr<AuthSession>>
AuthSessionMap;
AuthSessionMap auth_sessions_;
// A counter to count the number of parallel tasks on mount thread.
// Recorded when a requests comes in. Counts of 1 will not reported.
std::atomic<int> parallel_task_count_ = 0;
friend class UserDataAuthExTest;
FRIEND_TEST(UserDataAuthExTest, StartAuthSession);
};
} // namespace cryptohome
#endif // CRYPTOHOME_USERDATAAUTH_H_