blob: 43236cc4bc7a546a3c8dec2c440025c4c903e22e [file] [log] [blame]
// Copyright (c) 2012 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/stateful_recovery.h"
#include <base/files/file_util.h>
#include <gtest/gtest.h>
#include "cryptohome/mock_platform.h"
#include "cryptohome/mock_service.h"
namespace cryptohome {
using std::string;
using std::ostringstream;
using ::testing::_;
using ::testing::DoAll;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::StrEq;
using ::testing::SetArgumentPointee;
TEST(StatefulRecovery, ValidRequestV1) {
MockPlatform platform;
MockService service;
std::string flag_content = "1";
EXPECT_CALL(platform, ReadFileToString(StatefulRecovery::kFlagFile, _))
.WillOnce(DoAll(SetArgumentPointee<1>(flag_content), Return(true)));
EXPECT_CALL(platform, CreateDirectory(StatefulRecovery::kRecoverDestination))
.WillOnce(Return(true));
EXPECT_CALL(platform, FirmwareWriteProtected())
.WillOnce(Return(false));
EXPECT_CALL(platform, StatVFS(StatefulRecovery::kRecoverSource, _))
.WillOnce(Return(true));
EXPECT_CALL(platform, WriteStringToFile(StatefulRecovery::kRecoverBlockUsage,
_))
.WillOnce(Return(true));
EXPECT_CALL(platform,
ReportFilesystemDetails(StatefulRecovery::kRecoverSource,
StatefulRecovery::kRecoverFilesystemDetails))
.WillOnce(Return(true));
EXPECT_CALL(platform, Copy(StatefulRecovery::kRecoverSource,
StatefulRecovery::kRecoverDestination))
.WillOnce(Return(true));
StatefulRecovery recovery(&platform, &service);
EXPECT_TRUE(recovery.Requested());
EXPECT_TRUE(recovery.Recover());
}
TEST(StatefulRecovery, ValidRequestV1WriteProtected) {
MockPlatform platform;
MockService service;
std::string flag_content = "1";
EXPECT_CALL(platform, ReadFileToString(StatefulRecovery::kFlagFile, _))
.WillOnce(DoAll(SetArgumentPointee<1>(flag_content), Return(true)));
EXPECT_CALL(platform, CreateDirectory(StatefulRecovery::kRecoverDestination))
.WillOnce(Return(true));
EXPECT_CALL(platform, FirmwareWriteProtected())
.WillOnce(Return(true));
StatefulRecovery recovery(&platform, &service);
EXPECT_TRUE(recovery.Requested());
EXPECT_FALSE(recovery.Recover());
}
TEST(StatefulRecovery, ValidRequestV2) {
MockPlatform platform;
MockService service;
gboolean result = true;
std::string user = "user@example.com";
std::string passkey = "abcd1234";
std::string flag_content = "2\n" + user + "\n" + passkey;
std::string mount_path = "/home/.shadow/hashhashash/mount";
EXPECT_CALL(platform, ReadFileToString(StatefulRecovery::kFlagFile, _))
.WillOnce(DoAll(SetArgumentPointee<1>(flag_content), Return(true)));
EXPECT_CALL(platform, CreateDirectory(StatefulRecovery::kRecoverDestination))
.WillOnce(Return(true));
// CopyUserContents
EXPECT_CALL(service, Mount(StrEq(user), StrEq(passkey), false, false,
_, _, _))
.WillOnce(DoAll(SetArgumentPointee<5>(result), Return(true)));
EXPECT_CALL(service, GetMountPointForUser(StrEq(user), _))
.WillOnce(DoAll(SetArgumentPointee<1>(mount_path), Return(true)));
EXPECT_CALL(platform, Copy(StrEq(mount_path),
StatefulRecovery::kRecoverDestination))
.WillOnce(Return(true));
EXPECT_CALL(service, UnmountForUser(StrEq(user), _, _))
.WillOnce(DoAll(SetArgumentPointee<1>(result), Return(true)));
EXPECT_CALL(service, IsOwner(_))
.WillOnce(Return(true));
EXPECT_CALL(platform, FirmwareWriteProtected())
.WillOnce(Return(true));
// CopyPartitionInfo
EXPECT_CALL(platform, StatVFS(StatefulRecovery::kRecoverSource, _))
.WillOnce(Return(true));
EXPECT_CALL(platform, WriteStringToFile(StatefulRecovery::kRecoverBlockUsage,
_))
.WillOnce(Return(true));
EXPECT_CALL(platform,
ReportFilesystemDetails(StatefulRecovery::kRecoverSource,
StatefulRecovery::kRecoverFilesystemDetails))
.WillOnce(Return(true));
// CopyPartitionContents
EXPECT_CALL(platform, Copy(StatefulRecovery::kRecoverSource,
StatefulRecovery::kRecoverDestination))
.WillOnce(Return(true));
StatefulRecovery recovery(&platform, &service);
EXPECT_TRUE(recovery.Requested());
EXPECT_TRUE(recovery.Recover());
}
TEST(StatefulRecovery, ValidRequestV2NotOwner) {
MockPlatform platform;
MockService service;
gboolean result = true;
std::string user = "user@example.com";
std::string passkey = "abcd1234";
std::string flag_content = "2\n" + user + "\n" + passkey;
std::string mount_path = "/home/.shadow/hashhashash/mount";
EXPECT_CALL(platform, ReadFileToString(StatefulRecovery::kFlagFile, _))
.WillOnce(DoAll(SetArgumentPointee<1>(flag_content), Return(true)));
EXPECT_CALL(platform, CreateDirectory(StatefulRecovery::kRecoverDestination))
.WillOnce(Return(true));
// CopyUserContents
EXPECT_CALL(service, Mount(StrEq(user), StrEq(passkey), false, false,
_, _, _))
.WillOnce(DoAll(SetArgumentPointee<5>(result), Return(true)));
EXPECT_CALL(service, GetMountPointForUser(StrEq(user), _))
.WillOnce(DoAll(SetArgumentPointee<1>(mount_path), Return(true)));
EXPECT_CALL(platform, Copy(StrEq(mount_path),
StatefulRecovery::kRecoverDestination))
.WillOnce(Return(true));
EXPECT_CALL(service, UnmountForUser(StrEq(user), _, _))
.WillOnce(DoAll(SetArgumentPointee<1>(result), Return(true)));
EXPECT_CALL(service, IsOwner(_))
.WillOnce(Return(false));
EXPECT_CALL(platform, FirmwareWriteProtected())
.WillOnce(Return(true));
StatefulRecovery recovery(&platform, &service);
EXPECT_TRUE(recovery.Requested());
EXPECT_TRUE(recovery.Recover());
}
TEST(StatefulRecovery, ValidRequestV2BadUser) {
MockPlatform platform;
MockService service;
gboolean result = true;
std::string user = "user@example.com";
std::string passkey = "abcd1234";
std::string flag_content = "2\n" + user + "\n" + passkey;
std::string mount_path = "/home/.shadow/hashhashash/mount";
EXPECT_CALL(platform, ReadFileToString(StatefulRecovery::kFlagFile, _))
.WillOnce(DoAll(SetArgumentPointee<1>(flag_content), Return(true)));
EXPECT_CALL(platform, CreateDirectory(StatefulRecovery::kRecoverDestination))
.WillOnce(Return(true));
// CopyUserContents
EXPECT_CALL(service, Mount(StrEq(user), StrEq(passkey), false, false,
_, _, _))
.WillOnce(DoAll(SetArgumentPointee<5>(result), Return(false)));
EXPECT_CALL(platform, FirmwareWriteProtected())
.WillOnce(Return(true));
StatefulRecovery recovery(&platform, &service);
EXPECT_TRUE(recovery.Requested());
EXPECT_FALSE(recovery.Recover());
}
TEST(StatefulRecovery, ValidRequestV2BadUserNotWriteProtected) {
MockPlatform platform;
MockService service;
gboolean result = true;
std::string user = "user@example.com";
std::string passkey = "abcd1234";
std::string flag_content = "2\n" + user + "\n" + passkey;
std::string mount_path = "/home/.shadow/hashhashash/mount";
EXPECT_CALL(platform, ReadFileToString(StatefulRecovery::kFlagFile, _))
.WillOnce(DoAll(SetArgumentPointee<1>(flag_content), Return(true)));
EXPECT_CALL(platform, CreateDirectory(StatefulRecovery::kRecoverDestination))
.WillOnce(Return(true));
// CopyUserContents
EXPECT_CALL(service, Mount(StrEq(user), StrEq(passkey), false, false,
_, _, _))
.WillOnce(DoAll(SetArgumentPointee<5>(result), Return(false)));
EXPECT_CALL(platform, FirmwareWriteProtected())
.WillOnce(Return(false));
// CopyPartitionInfo
EXPECT_CALL(platform, StatVFS(StatefulRecovery::kRecoverSource, _))
.WillOnce(Return(true));
EXPECT_CALL(platform, WriteStringToFile(StatefulRecovery::kRecoverBlockUsage,
_))
.WillOnce(Return(true));
EXPECT_CALL(platform,
ReportFilesystemDetails(StatefulRecovery::kRecoverSource,
StatefulRecovery::kRecoverFilesystemDetails))
.WillOnce(Return(true));
// CopyPartitionContents
EXPECT_CALL(platform, Copy(StatefulRecovery::kRecoverSource,
StatefulRecovery::kRecoverDestination))
.WillOnce(Return(true));
StatefulRecovery recovery(&platform, &service);
EXPECT_TRUE(recovery.Requested());
EXPECT_TRUE(recovery.Recover());
}
TEST(StatefulRecovery, ValidRequestV2NotOwnerNotWriteProtected) {
MockPlatform platform;
MockService service;
gboolean result = true;
std::string user = "user@example.com";
std::string passkey = "abcd1234";
std::string flag_content = "2\n" + user + "\n" + passkey;
std::string mount_path = "/home/.shadow/hashhashash/mount";
EXPECT_CALL(platform, ReadFileToString(StatefulRecovery::kFlagFile, _))
.WillOnce(DoAll(SetArgumentPointee<1>(flag_content), Return(true)));
EXPECT_CALL(platform, CreateDirectory(StatefulRecovery::kRecoverDestination))
.WillOnce(Return(true));
// CopyUserContents
EXPECT_CALL(service, Mount(StrEq(user), StrEq(passkey), false, false,
_, _, _))
.WillOnce(DoAll(SetArgumentPointee<5>(result), Return(true)));
EXPECT_CALL(service, GetMountPointForUser(StrEq(user), _))
.WillOnce(DoAll(SetArgumentPointee<1>(mount_path), Return(true)));
EXPECT_CALL(platform, Copy(StrEq(mount_path),
StatefulRecovery::kRecoverDestination))
.WillOnce(Return(true));
EXPECT_CALL(service, UnmountForUser(StrEq(user), _, _))
.WillOnce(DoAll(SetArgumentPointee<1>(result), Return(true)));
EXPECT_CALL(service, IsOwner(_))
.WillOnce(Return(false));
EXPECT_CALL(platform, FirmwareWriteProtected())
.WillOnce(Return(false));
// CopyPartitionInfo
EXPECT_CALL(platform, StatVFS(StatefulRecovery::kRecoverSource, _))
.WillOnce(Return(true));
EXPECT_CALL(platform, WriteStringToFile(StatefulRecovery::kRecoverBlockUsage,
_))
.WillOnce(Return(true));
EXPECT_CALL(platform,
ReportFilesystemDetails(StatefulRecovery::kRecoverSource,
StatefulRecovery::kRecoverFilesystemDetails))
.WillOnce(Return(true));
// CopyPartitionContents
EXPECT_CALL(platform, Copy(StatefulRecovery::kRecoverSource,
StatefulRecovery::kRecoverDestination))
.WillOnce(Return(true));
StatefulRecovery recovery(&platform, &service);
EXPECT_TRUE(recovery.Requested());
EXPECT_TRUE(recovery.Recover());
}
TEST(StatefulRecovery, InvalidFlagFileContents) {
MockPlatform platform;
MockService service;
std::string flag_content = "0 hello";
EXPECT_CALL(platform, ReadFileToString(StatefulRecovery::kFlagFile, _))
.WillOnce(DoAll(SetArgumentPointee<1>(flag_content), Return(true)));
StatefulRecovery recovery(&platform, &service);
EXPECT_FALSE(recovery.Requested());
EXPECT_FALSE(recovery.Recover());
}
TEST(StatefulRecovery, UnreadableFlagFile) {
MockPlatform platform;
MockService service;
EXPECT_CALL(platform, ReadFileToString(StatefulRecovery::kFlagFile, _))
.WillOnce(Return(false));
StatefulRecovery recovery(&platform, &service);
EXPECT_FALSE(recovery.Requested());
EXPECT_FALSE(recovery.Recover());
}
TEST(StatefulRecovery, UncopyableData) {
MockPlatform platform;
MockService service;
std::string flag_content = "1";
EXPECT_CALL(platform, ReadFileToString(StatefulRecovery::kFlagFile, _))
.WillOnce(DoAll(SetArgumentPointee<1>(flag_content), Return(true)));
EXPECT_CALL(platform, CreateDirectory(StatefulRecovery::kRecoverDestination))
.WillOnce(Return(true));
EXPECT_CALL(platform, FirmwareWriteProtected())
.WillOnce(Return(false));
EXPECT_CALL(platform, Copy(StatefulRecovery::kRecoverSource,
StatefulRecovery::kRecoverDestination))
.WillOnce(Return(false));
StatefulRecovery recovery(&platform, &service);
EXPECT_TRUE(recovery.Requested());
EXPECT_FALSE(recovery.Recover());
}
TEST(StatefulRecovery, DirectoryCreationFailure) {
MockPlatform platform;
MockService service;
std::string flag_content = "1";
EXPECT_CALL(platform, ReadFileToString(StatefulRecovery::kFlagFile, _))
.WillOnce(DoAll(SetArgumentPointee<1>(flag_content), Return(true)));
EXPECT_CALL(platform, CreateDirectory(StatefulRecovery::kRecoverDestination))
.WillOnce(Return(false));
StatefulRecovery recovery(&platform, &service);
EXPECT_TRUE(recovery.Requested());
EXPECT_FALSE(recovery.Recover());
}
TEST(StatefulRecovery, StatVFSFailure) {
MockPlatform platform;
MockService service;
std::string flag_content = "1";
EXPECT_CALL(platform, ReadFileToString(StatefulRecovery::kFlagFile, _))
.WillOnce(DoAll(SetArgumentPointee<1>(flag_content), Return(true)));
EXPECT_CALL(platform, CreateDirectory(StatefulRecovery::kRecoverDestination))
.WillOnce(Return(true));
EXPECT_CALL(platform, FirmwareWriteProtected())
.WillOnce(Return(false));
EXPECT_CALL(platform, Copy(StatefulRecovery::kRecoverSource,
StatefulRecovery::kRecoverDestination))
.WillOnce(Return(true));
EXPECT_CALL(platform, StatVFS(StatefulRecovery::kRecoverSource, _))
.WillOnce(Return(false));
StatefulRecovery recovery(&platform, &service);
EXPECT_TRUE(recovery.Requested());
EXPECT_FALSE(recovery.Recover());
}
TEST(StatefulRecovery, FilesystemDetailsFailure) {
MockPlatform platform;
MockService service;
std::string flag_content = "1";
EXPECT_CALL(platform, ReadFileToString(StatefulRecovery::kFlagFile, _))
.WillOnce(DoAll(SetArgumentPointee<1>(flag_content), Return(true)));
EXPECT_CALL(platform, CreateDirectory(StatefulRecovery::kRecoverDestination))
.WillOnce(Return(true));
EXPECT_CALL(platform, FirmwareWriteProtected())
.WillOnce(Return(false));
EXPECT_CALL(platform, Copy(StatefulRecovery::kRecoverSource,
StatefulRecovery::kRecoverDestination))
.WillOnce(Return(true));
EXPECT_CALL(platform, StatVFS(StatefulRecovery::kRecoverSource, _))
.WillOnce(Return(true));
EXPECT_CALL(platform, WriteStringToFile(StatefulRecovery::kRecoverBlockUsage,
_))
.WillOnce(Return(true));
EXPECT_CALL(platform,
ReportFilesystemDetails(StatefulRecovery::kRecoverSource,
StatefulRecovery::kRecoverFilesystemDetails))
.WillOnce(Return(false));
StatefulRecovery recovery(&platform, &service);
EXPECT_TRUE(recovery.Requested());
EXPECT_FALSE(recovery.Recover());
}
TEST(StatefulRecovery, MountsParseOk) {
Platform platform;
base::FilePath mtab;
FILE *fp;
std::string filesystem, device_in, device_out, mtab_path, mtab_contents;
filesystem = "/second/star/to/the/right";
device_in = "/dev/pan";
mtab_contents.append(device_in);
mtab_contents.append(" ");
mtab_contents.append(filesystem);
mtab_contents.append(" pixie default 0 0\n");
fp = base::CreateAndOpenTemporaryFile(&mtab);
ASSERT_TRUE(fp != NULL);
EXPECT_EQ(fwrite(mtab_contents.c_str(), mtab_contents.length(), 1, fp), 1);
EXPECT_EQ(fclose(fp), 0);
mtab_path = mtab.value();
platform.set_mtab_path(mtab_path);
/* Fails if item is missing. */
EXPECT_FALSE(platform.FindFilesystemDevice("monkey", &device_out));
/* Works normally. */
device_out.clear();
EXPECT_TRUE(platform.FindFilesystemDevice(filesystem, &device_out));
EXPECT_TRUE(device_out == device_in);
/* Trailing slashes are okay. */
filesystem += "///";
device_out.clear();
EXPECT_TRUE(platform.FindFilesystemDevice(filesystem, &device_out));
EXPECT_TRUE(device_out == device_in);
/* Clean up. */
EXPECT_TRUE(base::DeleteFile(mtab, false));
}
TEST(StatefulRecovery, UsageReportOk) {
Platform platform;
struct statvfs vfs;
/* Reporting on a valid location produces output. */
EXPECT_TRUE(platform.StatVFS("/", &vfs));
EXPECT_NE(vfs.f_blocks, 0);
/* Reporting on an invalid location fails. */
EXPECT_FALSE(platform.StatVFS("/this/is/very/wrong", &vfs));
/* TODO(keescook): mockable tune2fs, since it's not installed in chroot. */
}
} // namespace cryptohome