blob: da1de58e06a4ad0622f27b95c3d71dbbbdb79435 [file] [log] [blame]
// Copyright (c) 2009-2010 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.
// Unit tests for Mount.
#include "mount.h"
#include <openssl/sha.h>
#include <pwd.h>
#include <string.h> // For memset(), memcpy()
#include <stdlib.h>
#include <sys/types.h>
#include <base/file_path.h>
#include <base/file_util.h>
#include <base/logging.h>
#include <chromeos/utility.h>
#include <gtest/gtest.h>
#include "crypto.h"
#include "secure_blob.h"
#include "username_passkey.h"
#include "make_tests.h"
#include "mock_platform.h"
#include "mock_tpm.h"
#include "mock_user_session.h"
#include "vault_keyset.h"
#include "vault_keyset.pb.h"
namespace cryptohome {
using std::string;
using ::testing::Return;
using ::testing::_;
using ::testing::NiceMock;
const char kImageDir[] = "test_image_dir";
const char kSkelDir[] = "test_image_dir/skel";
const char kHomeDir[] = "alt_test_home_dir";
const char kAltImageDir[] = "alt_test_image_dir";
class MountTest : public ::testing::Test {
public:
MountTest() { }
virtual ~MountTest() { }
void SetUp() {
LoadSystemSalt(kImageDir);
}
void LoadSystemSalt(const char* str_image_path) {
FilePath image_dir(str_image_path);
FilePath path = image_dir.Append("salt");
ASSERT_TRUE(file_util::PathExists(path)) << path.value()
<< " does not exist!";
int64 file_size;
ASSERT_TRUE(file_util::GetFileSize(path, &file_size))
<< "Could not get size of "
<< path.value();
char* buf = new char[file_size];
int data_read = file_util::ReadFile(path, buf, file_size);
system_salt_.assign(buf, buf + data_read);
delete buf;
}
bool LoadSerializedKeyset(const std::string& key_path,
cryptohome::SerializedVaultKeyset* serialized) {
cryptohome::SecureBlob contents;
if (!cryptohome::Mount::LoadFileBytes(FilePath(key_path), &contents)) {
return false;
}
return serialized->ParseFromArray(
static_cast<const unsigned char*>(&contents[0]), contents.size());
}
void GetKeysetBlob(const SerializedVaultKeyset& serialized,
SecureBlob* blob) {
SecureBlob local_wrapped_keyset(serialized.wrapped_keyset().length());
serialized.wrapped_keyset().copy(
static_cast<char*>(local_wrapped_keyset.data()),
serialized.wrapped_keyset().length(), 0);
blob->swap(local_wrapped_keyset);
}
protected:
// Protected for trivial access
chromeos::Blob system_salt_;
private:
DISALLOW_COPY_AND_ASSIGN(MountTest);
};
TEST_F(MountTest, BadInitTest) {
// create a Mount instance that points to a bad shadow root
Mount mount;
NiceMock<MockTpm> tpm;
mount.get_crypto()->set_tpm(&tpm);
mount.set_shadow_root("/dev/null");
mount.set_skel_source(kSkelDir);
mount.set_use_tpm(false);
cryptohome::SecureBlob passkey;
cryptohome::Crypto::PasswordToPasskey(kDefaultUsers[0].password,
system_salt_, &passkey);
UsernamePasskey up(kDefaultUsers[0].username, passkey);
EXPECT_FALSE(mount.Init());
ASSERT_FALSE(mount.TestCredentials(up));
}
TEST_F(MountTest, GoodDecryptTest) {
// create a Mount instance that points to a good shadow root, test that it
// properly authenticates against the first key.
Mount mount;
NiceMock<MockTpm> tpm;
mount.get_crypto()->set_tpm(&tpm);
mount.set_shadow_root(kImageDir);
mount.set_skel_source(kSkelDir);
mount.set_use_tpm(false);
mount.set_fallback_to_scrypt(true);
cryptohome::SecureBlob passkey;
cryptohome::Crypto::PasswordToPasskey(kDefaultUsers[1].password,
system_salt_, &passkey);
UsernamePasskey up(kDefaultUsers[1].username, passkey);
EXPECT_TRUE(mount.Init());
ASSERT_TRUE(mount.TestCredentials(up));
}
TEST_F(MountTest, TestCredsDoesNotReSave) {
// create a Mount instance that points to a good shadow root, test that it
// properly authenticates against the first key.
Mount mount;
NiceMock<MockTpm> tpm;
mount.get_crypto()->set_tpm(&tpm);
mount.set_shadow_root(kImageDir);
mount.set_skel_source(kSkelDir);
mount.set_use_tpm(false);
mount.set_fallback_to_scrypt(true);
cryptohome::SecureBlob passkey;
cryptohome::Crypto::PasswordToPasskey(kDefaultUsers[2].password,
system_salt_, &passkey);
UsernamePasskey up(kDefaultUsers[2].username, passkey);
EXPECT_TRUE(mount.Init());
// Make sure the keyset is not scrypt wrapped
std::string key_path = mount.GetUserKeyFile(up);
cryptohome::SerializedVaultKeyset serialized;
ASSERT_TRUE(LoadSerializedKeyset(key_path, &serialized));
ASSERT_EQ(0, (serialized.flags() &
cryptohome::SerializedVaultKeyset::SCRYPT_WRAPPED));
ASSERT_TRUE(mount.TestCredentials(up));
// Make sure the keyset is still not scrypt wrapped
cryptohome::SerializedVaultKeyset serialized2;
ASSERT_TRUE(LoadSerializedKeyset(key_path, &serialized2));
ASSERT_EQ(0, (serialized2.flags() &
cryptohome::SerializedVaultKeyset::SCRYPT_WRAPPED));
}
TEST_F(MountTest, CurrentCredentialsTest) {
// create a Mount instance that points to a good shadow root, test that it
// properly authenticates against the first key
Mount mount;
NiceMock<MockTpm> tpm;
mount.get_crypto()->set_tpm(&tpm);
mount.set_shadow_root(kImageDir);
mount.set_skel_source(kSkelDir);
mount.set_use_tpm(false);
cryptohome::SecureBlob passkey;
cryptohome::Crypto::PasswordToPasskey(kDefaultUsers[3].password,
system_salt_, &passkey);
UsernamePasskey up(kDefaultUsers[3].username, passkey);
EXPECT_TRUE(mount.Init());
NiceMock<MockUserSession> user_session;
Crypto crypto;
user_session.Init(&crypto, SecureBlob());
user_session.SetUser(up);
mount.set_current_user(&user_session);
EXPECT_CALL(user_session, CheckUser(_))
.WillOnce(Return(true));
EXPECT_CALL(user_session, Verify(_))
.WillOnce(Return(true));
ASSERT_TRUE(mount.TestCredentials(up));
}
TEST_F(MountTest, BadDecryptTest) {
// create a Mount instance that points to a good shadow root, test that it
// properly denies access with a bad passkey
Mount mount;
NiceMock<MockTpm> tpm;
mount.get_crypto()->set_tpm(&tpm);
mount.set_shadow_root(kImageDir);
mount.set_skel_source(kSkelDir);
mount.set_use_tpm(false);
cryptohome::SecureBlob passkey;
cryptohome::Crypto::PasswordToPasskey("bogus", system_salt_, &passkey);
UsernamePasskey up(kDefaultUsers[4].username, passkey);
EXPECT_TRUE(mount.Init());
ASSERT_FALSE(mount.TestCredentials(up));
}
TEST_F(MountTest, CreateCryptohomeTest) {
// creates a cryptohome and tests credentials
Mount mount;
NiceMock<MockTpm> tpm;
mount.get_crypto()->set_tpm(&tpm);
mount.set_shadow_root(kImageDir);
mount.set_skel_source(kSkelDir);
mount.set_use_tpm(false);
mount.set_set_vault_ownership(false);
// Test user at index 5 was not created by the test data
cryptohome::SecureBlob passkey;
cryptohome::Crypto::PasswordToPasskey(kDefaultUsers[5].password,
system_salt_, &passkey);
UsernamePasskey up(kDefaultUsers[5].username, passkey);
EXPECT_TRUE(mount.Init());
bool created;
ASSERT_TRUE(mount.EnsureCryptohome(up, Mount::MountArgs(), &created));
ASSERT_TRUE(created);
FilePath image_dir(kImageDir);
FilePath user_path = image_dir.Append(up.GetObfuscatedUsername(system_salt_));
FilePath key_path = user_path.Append("master.0");
FilePath vault_path = user_path.Append("vault");
ASSERT_TRUE(file_util::PathExists(key_path));
ASSERT_TRUE(file_util::PathExists(vault_path));
ASSERT_TRUE(mount.TestCredentials(up));
}
TEST_F(MountTest, GoodReDecryptTest) {
// create a Mount instance that points to a good shadow root, test that it
// properly re-authenticates against the first key
Mount mount;
NiceMock<MockTpm> tpm;
mount.get_crypto()->set_tpm(&tpm);
mount.set_use_tpm(false);
mount.set_shadow_root(kImageDir);
mount.set_skel_source(kSkelDir);
mount.set_use_tpm(false);
cryptohome::SecureBlob passkey;
cryptohome::Crypto::PasswordToPasskey(kDefaultUsers[6].password,
system_salt_, &passkey);
UsernamePasskey up(kDefaultUsers[6].username, passkey);
EXPECT_TRUE(mount.Init());
// Make sure the keyset is not scrypt wrapped
std::string key_path = mount.GetUserKeyFile(up);
cryptohome::SerializedVaultKeyset serialized;
ASSERT_TRUE(LoadSerializedKeyset(key_path, &serialized));
ASSERT_EQ(0, (serialized.flags() &
cryptohome::SerializedVaultKeyset::SCRYPT_WRAPPED));
// Call DecryptVaultKeyset first, allowing migration (the test data is not
// scrypt nor TPM wrapped) to a scrypt-wrapped keyset
VaultKeyset vault_keyset;
Mount::MountError error;
ASSERT_TRUE(mount.DecryptVaultKeyset(up, true, &vault_keyset, &serialized,
&error));
// Make sure the keyset is now scrypt wrapped
cryptohome::SerializedVaultKeyset serialized2;
ASSERT_TRUE(LoadSerializedKeyset(key_path, &serialized2));
ASSERT_EQ(SerializedVaultKeyset::SCRYPT_WRAPPED,
(serialized2.flags() &
cryptohome::SerializedVaultKeyset::SCRYPT_WRAPPED));
ASSERT_TRUE(mount.TestCredentials(up));
}
TEST_F(MountTest, MigrateTest) {
// create a Mount instance that points to a good shadow root, test that it
// will migrate an old style key
Mount mount;
NiceMock<MockTpm> tpm;
mount.get_crypto()->set_tpm(&tpm);
mount.set_shadow_root(kImageDir);
mount.set_skel_source(kSkelDir);
mount.set_use_tpm(false);
// Test user at index 7 was created using the old style
cryptohome::SecureBlob passkey;
cryptohome::Crypto::PasswordToPasskey(kDefaultUsers[7].password,
system_salt_, &passkey);
UsernamePasskey up(kDefaultUsers[7].username, passkey);
EXPECT_TRUE(mount.Init());
// Make sure the keyset is not scrypt wrapped
std::string salt_path = mount.GetUserSaltFile(up);
ASSERT_TRUE(file_util::PathExists(FilePath(salt_path)));
// Call DecryptVaultKeyset first, allowing migration (the test data is not
// scrypt nor TPM wrapped) to a scrypt-wrapped keyset
VaultKeyset vault_keyset;
SerializedVaultKeyset serialized;
Mount::MountError error;
ASSERT_TRUE(mount.DecryptVaultKeyset(up, true, &vault_keyset, &serialized,
&error));
// Make sure the salt path no longer exists
ASSERT_FALSE(file_util::PathExists(FilePath(salt_path)));
// Make sure the keyset is now scrypt wrapped
std::string key_path = mount.GetUserKeyFile(up);
ASSERT_TRUE(LoadSerializedKeyset(key_path, &serialized));
ASSERT_EQ(SerializedVaultKeyset::SCRYPT_WRAPPED,
(serialized.flags() &
cryptohome::SerializedVaultKeyset::SCRYPT_WRAPPED));
ASSERT_TRUE(mount.TestCredentials(up));
}
TEST_F(MountTest, SystemSaltTest) {
// checks that cryptohome reads the system salt
Mount mount;
NiceMock<MockTpm> tpm;
mount.get_crypto()->set_tpm(&tpm);
mount.set_shadow_root(kImageDir);
mount.set_skel_source(kSkelDir);
mount.set_use_tpm(false);
EXPECT_TRUE(mount.Init());
chromeos::Blob system_salt;
mount.GetSystemSalt(&system_salt);
ASSERT_TRUE((system_salt.size() == system_salt_.size()));
ASSERT_EQ(0, memcmp(&system_salt[0], &system_salt_[0],
system_salt.size()));
}
TEST_F(MountTest, MountCryptohome) {
// checks that cryptohome tries to mount successfully, and tests that the
// tracked directories are created/replaced as expected
Mount mount;
NiceMock<MockTpm> tpm;
mount.get_crypto()->set_tpm(&tpm);
mount.set_shadow_root(kImageDir);
mount.set_skel_source(kSkelDir);
mount.set_use_tpm(false);
NiceMock<MockPlatform> platform;
mount.set_platform(&platform);
EXPECT_TRUE(mount.Init());
cryptohome::SecureBlob passkey;
cryptohome::Crypto::PasswordToPasskey(kDefaultUsers[10].password,
system_salt_, &passkey);
UsernamePasskey up(kDefaultUsers[10].username, passkey);
EXPECT_CALL(platform, Mount(_, _, _, _))
.WillRepeatedly(Return(true));
Mount::MountError error;
ASSERT_TRUE(mount.MountCryptohome(up, Mount::MountArgs(), &error));
FilePath image_dir(kImageDir);
FilePath user_path = image_dir.Append(up.GetObfuscatedUsername(system_salt_));
FilePath vault_path = user_path.Append("vault");
FilePath subdir_path = vault_path.Append(kCacheDir);
ASSERT_TRUE(file_util::PathExists(subdir_path));
}
TEST_F(MountTest, MountCryptohomeNoChange) {
// checks that cryptohome doesn't by default re-save the cryptohome when an
// identical list of tracked directories is passed in
Mount mount;
NiceMock<MockTpm> tpm;
mount.get_crypto()->set_tpm(&tpm);
mount.set_shadow_root(kImageDir);
mount.set_skel_source(kSkelDir);
mount.set_use_tpm(false);
NiceMock<MockPlatform> platform;
mount.set_platform(&platform);
EXPECT_TRUE(mount.Init());
cryptohome::SecureBlob passkey;
cryptohome::Crypto::PasswordToPasskey(kDefaultUsers[11].password,
system_salt_, &passkey);
UsernamePasskey up(kDefaultUsers[11].username, passkey);
VaultKeyset vault_keyset;
SerializedVaultKeyset serialized;
Mount::MountError error;
ASSERT_TRUE(mount.DecryptVaultKeyset(up, true, &vault_keyset, &serialized,
&error));
EXPECT_CALL(platform, Mount(_, _, _, _))
.WillOnce(Return(true));
ASSERT_TRUE(mount.MountCryptohome(up, Mount::MountArgs(), &error));
// Make sure the keyset now has only one tracked directory, "Cache"
SerializedVaultKeyset new_serialized;
ASSERT_TRUE(mount.DecryptVaultKeyset(up, true, &vault_keyset, &new_serialized,
&error));
FilePath image_dir(kImageDir);
FilePath user_path = image_dir.Append(up.GetObfuscatedUsername(system_salt_));
FilePath vault_path = user_path.Append("vault");
FilePath subdir_path = vault_path.Append(kCacheDir);
ASSERT_TRUE(file_util::PathExists(subdir_path));
SecureBlob lhs;
GetKeysetBlob(serialized, &lhs);
SecureBlob rhs;
GetKeysetBlob(new_serialized, &rhs);
ASSERT_EQ(lhs.size(), rhs.size());
ASSERT_EQ(0, memcmp(lhs.data(), rhs.data(), lhs.size()));
}
TEST_F(MountTest, MountCryptohomeNoCreate) {
// checks that doesn't create the cryptohome for the user on Mount without
// being told to do so.
Mount mount;
NiceMock<MockTpm> tpm;
mount.get_crypto()->set_tpm(&tpm);
mount.set_shadow_root(kImageDir);
mount.set_skel_source(kSkelDir);
mount.set_use_tpm(false);
NiceMock<MockPlatform> platform;
mount.set_platform(&platform);
EXPECT_TRUE(mount.Init());
// Test user at index 12 hasn't been created
cryptohome::SecureBlob passkey;
cryptohome::Crypto::PasswordToPasskey(kDefaultUsers[12].password,
system_salt_, &passkey);
UsernamePasskey up(kDefaultUsers[12].username, passkey);
EXPECT_CALL(platform, Mount(_, _, _, _))
.WillOnce(Return(true));
Mount::MountArgs mount_args;
mount_args.create_if_missing = false;
Mount::MountError error;
ASSERT_FALSE(mount.MountCryptohome(up, mount_args, &error));
ASSERT_EQ(Mount::MOUNT_ERROR_USER_DOES_NOT_EXIST, error);
FilePath image_dir(kImageDir);
FilePath user_path = image_dir.Append(up.GetObfuscatedUsername(system_salt_));
FilePath vault_path = user_path.Append("vault");
ASSERT_FALSE(file_util::PathExists(vault_path));
mount_args.create_if_missing = true;
ASSERT_TRUE(mount.MountCryptohome(up, mount_args, &error));
ASSERT_TRUE(file_util::PathExists(vault_path));
FilePath subdir_path = vault_path.Append(kCacheDir);
ASSERT_TRUE(file_util::PathExists(subdir_path));
}
TEST_F(MountTest, RemoveSubdirectories) {
// checks that cryptohome can delete tracked subdirectories
LoadSystemSalt(kAltImageDir);
Mount mount;
NiceMock<MockTpm> tpm;
mount.get_crypto()->set_tpm(&tpm);
mount.set_shadow_root(kAltImageDir);
mount.set_skel_source(kSkelDir);
mount.set_use_tpm(false);
NiceMock<MockPlatform> platform;
mount.set_platform(&platform);
EXPECT_TRUE(mount.Init());
cryptohome::SecureBlob passkey;
cryptohome::Crypto::PasswordToPasskey(kAlternateUsers[0].password,
system_salt_, &passkey);
UsernamePasskey up(kAlternateUsers[0].username, passkey);
EXPECT_CALL(platform, Mount(_, _, _, _))
.WillRepeatedly(Return(true));
EXPECT_CALL(platform, Unmount(_, _, _))
.WillRepeatedly(Return(true));
Mount::MountError error;
EXPECT_TRUE(mount.MountCryptohome(up, Mount::MountArgs(), &error));
FilePath image_dir(kAltImageDir);
FilePath user_path = image_dir.Append(up.GetObfuscatedUsername(system_salt_));
FilePath vault_path = user_path.Append("vault");
FilePath subdir_path = vault_path.Append(kCacheDir);
ASSERT_TRUE(file_util::PathExists(subdir_path));
NiceMock<MockPlatform> platform_mounted;
mount.set_platform(&platform_mounted);
// Make sure the directory is not deleted if the vault is mounted
EXPECT_CALL(platform_mounted, IsDirectoryMounted(_))
.WillRepeatedly(Return(true));
EXPECT_CALL(platform_mounted, IsDirectoryMountedWith(_, _))
.WillRepeatedly(Return(true));
EXPECT_CALL(platform_mounted, Mount(_, _, _, _))
.WillRepeatedly(Return(true));
EXPECT_CALL(platform_mounted, Unmount(_, _, _))
.WillRepeatedly(Return(true));
mount.CleanUnmountedTrackedSubdirectories();
ASSERT_TRUE(file_util::PathExists(subdir_path));
mount.UnmountCryptohome();
NiceMock<MockPlatform> platform_unmounted;
mount.set_platform(&platform_unmounted);
// Make sure the directory is not deleted if the vault is mounted
EXPECT_CALL(platform_unmounted, IsDirectoryMounted(_))
.WillRepeatedly(Return(false));
EXPECT_CALL(platform_unmounted, IsDirectoryMountedWith(_, _))
.WillRepeatedly(Return(false));
EXPECT_CALL(platform_unmounted, Mount(_, _, _, _))
.WillRepeatedly(Return(true));
EXPECT_CALL(platform_unmounted, Unmount(_, _, _))
.WillRepeatedly(Return(true));
mount.CleanUnmountedTrackedSubdirectories();
ASSERT_FALSE(file_util::PathExists(subdir_path));
}
TEST_F(MountTest, MigrationOfTrackedDirs) {
// Checks that old cryptohomes (without pass-through tracked
// directories) migrate when Mount()ed.
LoadSystemSalt(kImageDir);
Mount mount;
NiceMock<MockTpm> tpm;
mount.get_crypto()->set_tpm(&tpm);
mount.set_shadow_root(kImageDir);
mount.set_use_tpm(false);
NiceMock<MockPlatform> platform;
mount.set_platform(&platform);
EXPECT_TRUE(mount.Init());
cryptohome::SecureBlob passkey;
cryptohome::Crypto::PasswordToPasskey(kDefaultUsers[8].password,
system_salt_, &passkey);
UsernamePasskey up(kDefaultUsers[8].username, passkey);
// As we don't have real mount in the test, immagine its output (home)
// directory.
FilePath home_dir(kHomeDir);
file_util::CreateDirectory(home_dir);
mount.set_home_dir(home_dir.value());
// Pretend that mounted cryptohome already had non-pass-through
// subdirs "Cache" and "Downloads".
FilePath cache_dir(home_dir.Append(kCacheDir));
FilePath downloads_dir(home_dir.Append(kDownloadsDir));
file_util::CreateDirectory(cache_dir);
file_util::CreateDirectory(downloads_dir);
// And they are not empty.
const string contents = "Hello world!!!";
file_util::WriteFile(cache_dir.Append("cached_file"),
contents.c_str(), contents.length());
file_util::WriteFile(downloads_dir.Append("downloaded_file"),
contents.c_str(), contents.length());
// Even have subdirectories.
FilePath cache_subdir(cache_dir.Append("cache_subdir"));
FilePath downloads_subdir(downloads_dir.Append("downloads_subdir"));
file_util::CreateDirectory(cache_subdir);
file_util::CreateDirectory(downloads_subdir);
file_util::WriteFile(cache_subdir.Append("cached_file"),
contents.c_str(), contents.length());
file_util::WriteFile(downloads_subdir.Append("downloaded_file"),
contents.c_str(), contents.length());
// Now Mount().
EXPECT_CALL(platform, Mount(_, _, _, _))
.WillRepeatedly(Return(true));
Mount::MountError error;
EXPECT_TRUE(mount.MountCryptohome(up, Mount::MountArgs(), &error));
// Check that vault path now have pass-through version of tracked dirs.
FilePath image_dir(kImageDir);
FilePath user_path = image_dir.Append(up.GetObfuscatedUsername(system_salt_));
FilePath vault_path = user_path.Append("vault");
ASSERT_TRUE(file_util::PathExists(vault_path.Append(kCacheDir)));
ASSERT_TRUE(file_util::PathExists(vault_path.Append(kDownloadsDir)));
// Check that vault path does not contain user data unencrypted.
// Note, that if we had real mount, we would see encrypted file names there;
// but with our mock mount, we must see empty directories.
EXPECT_TRUE(file_util::IsDirectoryEmpty(vault_path.Append(kCacheDir)));
EXPECT_TRUE(file_util::IsDirectoryEmpty(vault_path.Append(kDownloadsDir)));
// Check that Cache is clear (because it does not need migration) so
// it should not appear in a home dir.
EXPECT_FALSE(file_util::PathExists(cache_dir));
// Check that Downloads is completely migrated.
string tested;
EXPECT_TRUE(file_util::PathExists(downloads_dir));
EXPECT_TRUE(file_util::ReadFileToString(
downloads_dir.Append("downloaded_file"), &tested));
EXPECT_EQ(contents, tested);
EXPECT_TRUE(file_util::PathExists(downloads_subdir));
tested.clear();
EXPECT_TRUE(file_util::ReadFileToString(
downloads_subdir.Append("downloaded_file"), &tested));
EXPECT_EQ(contents, tested);
// Check that we did not leave any litter.
file_util::Delete(downloads_dir, true);
EXPECT_TRUE(file_util::IsDirectoryEmpty(home_dir));
}
TEST_F(MountTest, DoAutomaticFreeDiskSpaceControl) {
// Checks that DoAutomaticFreeDiskSpaceControl() does the clean-up
// if free disk space is low.
LoadSystemSalt(kAltImageDir);
Mount mount;
NiceMock<MockTpm> tpm;
mount.get_crypto()->set_tpm(&tpm);
mount.set_shadow_root(kAltImageDir);
mount.set_use_tpm(false);
NiceMock<MockPlatform> platform;
mount.set_platform(&platform);
EXPECT_TRUE(mount.Init());
// For every user, prepare cryptohome contents.
const string contents = "some crypted contets";
FilePath image_dir(kAltImageDir);
FilePath vault_path[kAlternateUserCount];
FilePath cache_dir[kAlternateUserCount];
FilePath cache_subdir[kAlternateUserCount];
for (size_t user = 0; user < kAlternateUserCount; user ++) {
cryptohome::SecureBlob passkey;
cryptohome::Crypto::PasswordToPasskey(kAlternateUsers[user].password,
system_salt_, &passkey);
UsernamePasskey up(kAlternateUsers[user].username, passkey);
vault_path[user] = image_dir
.Append(up.GetObfuscatedUsername(system_salt_))
.Append("vault");
// Let their Cache dirs be filled with some data.
cache_dir[user] = vault_path[user].Append(kCacheDir);
file_util::CreateDirectory(cache_dir[user]);
file_util::WriteFile(cache_dir[user].Append("cached_file"),
contents.c_str(), contents.length());
cache_subdir[user] = cache_dir[user].Append("cache_subdir");
file_util::CreateDirectory(cache_subdir[user]);
file_util::WriteFile(cache_subdir[user].Append("cached_file"),
contents.c_str(), contents.length());
}
// Firstly, pretend we have lots of free space.
EXPECT_CALL(platform, AmountOfFreeDiskSpace(_))
.WillRepeatedly(Return(kMinFreeSpace + 1));
// DoAutomaticFreeDiskSpaceControl() must do nothing.
mount.DoAutomaticFreeDiskSpaceControl();
// Check that Cache is not changed.
for (size_t user = 0; user < kAlternateUserCount; user ++) {
string tested;
EXPECT_TRUE(file_util::PathExists(cache_dir[user]));
EXPECT_TRUE(file_util::ReadFileToString(
cache_dir[user].Append("cached_file"), &tested));
EXPECT_EQ(contents, tested);
EXPECT_TRUE(file_util::PathExists(cache_subdir[user]));
tested.clear();
EXPECT_TRUE(file_util::ReadFileToString(
cache_subdir[user].Append("cached_file"), &tested));
EXPECT_EQ(contents, tested);
}
// Now pretend we have lack of free space.
EXPECT_CALL(platform, AmountOfFreeDiskSpace(_))
.WillRepeatedly(Return(kMinFreeSpace - 1));
// DoAutomaticFreeDiskSpaceControl() must do the clean-up..
mount.DoAutomaticFreeDiskSpaceControl();
// Cache must be empty (and may even be deleted).
for (size_t user = 0; user < kAlternateUserCount; user ++) {
EXPECT_TRUE(file_util::IsDirectoryEmpty(cache_dir[user]));
EXPECT_TRUE(file_util::PathExists(cache_dir[user]));
// Check that we did not leave any litter.
file_util::Delete(cache_dir[user], true);
EXPECT_TRUE(file_util::IsDirectoryEmpty(vault_path[user]));
}
}
} // namespace cryptohome