blob: c90c153c538d684a832a97a605396339d731fec8 [file] [log] [blame]
// Copyright 2021 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.
#include <cryptohome/storage/cryptohome_vault.h>
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include <base/logging.h>
#include <base/notreached.h>
#include <dbus/cryptohome/dbus-constants.h>
#include "cryptohome/cryptohome_metrics.h"
#include "cryptohome/filesystem_layout.h"
#include "cryptohome/platform.h"
#include "cryptohome/storage/encrypted_container/encrypted_container.h"
#include "cryptohome/storage/encrypted_container/filesystem_key.h"
#include "cryptohome/storage/mount_constants.h"
namespace cryptohome {
CryptohomeVault::CryptohomeVault(
const std::string& obfuscated_username,
std::unique_ptr<EncryptedContainer> container,
std::unique_ptr<EncryptedContainer> migrating_container,
std::unique_ptr<EncryptedContainer> cache_container,
std::vector<std::unique_ptr<EncryptedContainer>> application_containers,
Platform* platform)
: obfuscated_username_(obfuscated_username),
container_(std::move(container)),
migrating_container_(std::move(migrating_container)),
cache_container_(std::move(cache_container)),
application_containers_(std::move(application_containers)),
platform_(platform) {}
// Teardown the vault on object destruction.
CryptohomeVault::~CryptohomeVault() {
std::ignore = Teardown();
}
MountError CryptohomeVault::Setup(const FileSystemKey& filesystem_key) {
if (!platform_->ClearUserKeyring()) {
LOG(ERROR) << "Failed to clear user keyring";
}
if (!platform_->SetupProcessKeyring()) {
LOG(ERROR) << "Failed to set up a process keyring.";
return MOUNT_ERROR_SETUP_PROCESS_KEYRING_FAILED;
}
// If there is a migrating data container, we need to set up the existing
// data container.
if (!container_->Setup(filesystem_key)) {
LOG(ERROR) << "Failed to setup container.";
// TODO(sarthakkukreti): MOUNT_ERROR_KEYRING_FAILED should be replaced with
// a more specific type.
return MOUNT_ERROR_KEYRING_FAILED;
}
// If migration is allowed, set up the migrating container, depending on
// whether it has already been set up or not.
if (migrating_container_ && !migrating_container_->Setup(filesystem_key)) {
LOG(ERROR) << "Failed to setup migrating container.";
// TODO(sarthakkukreti): MOUNT_ERROR_KEYRING_FAILED should be replaced
// with a more specific type.
return MOUNT_ERROR_KEYRING_FAILED;
}
// If we are mounting a dm-crypt cryptohome, setup a separate cache container.
if (cache_container_ && !cache_container_->Setup(filesystem_key)) {
LOG(ERROR) << "Failed to setup cache container.";
// TODO(sarthakkukreti): MOUNT_ERROR_KEYRING_FAILED should be replaced
// with a more specific type.
return MOUNT_ERROR_KEYRING_FAILED;
}
for (auto& container : application_containers_) {
if (!container->Setup(filesystem_key)) {
LOG(ERROR) << "Failed to setup an application container.";
// TODO(sarthakkukreti): MOUNT_ERROR_KEYRING_FAILED should be replaced
// with a more specific type.
return MOUNT_ERROR_KEYRING_FAILED;
}
}
if (container_->GetType() == EncryptedContainerType::kEphemeral) {
// Do not create /home/.shadow/<hash>/mount for ephemeral.
return MOUNT_ERROR_NONE;
}
base::FilePath mount_point = GetUserMountDirectory(obfuscated_username_);
if (!platform_->CreateDirectory(mount_point)) {
PLOG(ERROR) << "User mount directory creation failed for "
<< mount_point.value();
return MOUNT_ERROR_DIR_CREATION_FAILED;
}
// During migration, the existing ecryptfs container is mounted at
// |temporary_mount_point|.
if (migrating_container_) {
base::FilePath temporary_mount_point =
GetUserTemporaryMountDirectory(obfuscated_username_);
if (!platform_->CreateDirectory(temporary_mount_point)) {
PLOG(ERROR) << "User temporary mount directory creation failed for "
<< temporary_mount_point.value();
return MOUNT_ERROR_DIR_CREATION_FAILED;
}
}
// For valid cache containers, create the cache mount directory.
if (cache_container_) {
base::FilePath cache_mount_point =
GetDmcryptUserCacheDirectory(obfuscated_username_);
if (!platform_->CreateDirectory(cache_mount_point)) {
PLOG(ERROR) << "Cache mount directory creation failed for "
<< cache_mount_point.value();
return MOUNT_ERROR_DIR_CREATION_FAILED;
}
}
return MOUNT_ERROR_NONE;
}
void CryptohomeVault::ReportVaultEncryptionType() {
EncryptedContainerType type = migrating_container_
? migrating_container_->GetType()
: container_->GetType();
switch (type) {
case EncryptedContainerType::kDmcrypt:
ReportHomedirEncryptionType(HomedirEncryptionType::kDmcrypt);
break;
case EncryptedContainerType::kEcryptfs:
ReportHomedirEncryptionType(HomedirEncryptionType::kEcryptfs);
break;
case EncryptedContainerType::kFscrypt:
ReportHomedirEncryptionType(HomedirEncryptionType::kDircrypto);
break;
case EncryptedContainerType::kEphemeral:
// Not an encrypted vault
break;
default:
// We're only interested in encrypted home directories.
NOTREACHED() << "Unknown homedir encryption type: "
<< static_cast<int>(type);
break;
}
}
MountType CryptohomeVault::GetMountType() {
EncryptedContainerType type = container_->GetType();
switch (type) {
case EncryptedContainerType::kEcryptfs:
if (migrating_container_ &&
migrating_container_->GetType() == EncryptedContainerType::kFscrypt) {
return MountType::ECRYPTFS_TO_DIR_CRYPTO;
}
if (migrating_container_ &&
migrating_container_->GetType() == EncryptedContainerType::kDmcrypt) {
return MountType::ECRYPTFS_TO_DMCRYPT;
}
return MountType::ECRYPTFS;
case EncryptedContainerType::kFscrypt:
if (migrating_container_) {
return MountType::DIR_CRYPTO_TO_DMCRYPT;
}
return MountType::DIR_CRYPTO;
case EncryptedContainerType::kDmcrypt:
return MountType::DMCRYPT;
case EncryptedContainerType::kEphemeral:
return MountType::EPHEMERAL;
default:
return MountType::NONE;
}
}
bool CryptohomeVault::SetLazyTeardownWhenUnused() {
bool ret = true;
if (!container_->SetLazyTeardownWhenUnused()) {
LOG(ERROR) << "Failed to set lazy teardown for container";
ret = false;
}
if (migrating_container_ &&
!migrating_container_->SetLazyTeardownWhenUnused()) {
LOG(ERROR) << "Failed to set lazy teardown for migrating container";
ret = false;
}
if (cache_container_ && !cache_container_->SetLazyTeardownWhenUnused()) {
LOG(ERROR) << "Failed to set lazy teardown for cache container";
ret = false;
}
// TODO(b:225769250, dlunev): figure out lazy teardown for non-mounted
// application containers.
return ret;
}
bool CryptohomeVault::Teardown() {
bool ret = true;
if (!container_->Teardown()) {
LOG(ERROR) << "Failed to teardown container";
ret = false;
}
if (migrating_container_ && !migrating_container_->Teardown()) {
LOG(ERROR) << "Failed to teardown migrating container";
ret = false;
}
if (cache_container_ && !cache_container_->Teardown()) {
LOG(ERROR) << "Failed to teardown cache container";
ret = false;
}
for (auto& container : application_containers_) {
if (!container->Teardown()) {
LOG(ERROR) << "Failed to teardown application container";
ret = false;
}
}
return ret;
}
bool CryptohomeVault::Purge() {
bool ret = true;
if (container_->Exists() && !container_->Purge()) {
LOG(ERROR) << "Failed to purge container";
ret = false;
}
if (migrating_container_ && migrating_container_->Exists() &&
!migrating_container_->Purge()) {
LOG(ERROR) << "Failed to purge migrating container";
ret = false;
}
if (cache_container_ && cache_container_->Exists() &&
!cache_container_->Purge()) {
LOG(ERROR) << "Failed to purge cache container";
ret = false;
}
for (auto& container : application_containers_) {
if (container->Exists() && !container->Purge()) {
LOG(ERROR) << "Failed to purge application container";
ret = false;
}
}
return ret;
}
bool CryptohomeVault::PurgeCacheContainer() {
if (!cache_container_)
return false;
if (cache_container_->Exists() && !cache_container_->Purge())
return false;
return true;
}
} // namespace cryptohome