blob: ec33c5f8888e8289c747e474a33d6fb61f6e1f48 [file] [log] [blame]
// Copyright 2020 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "smbfs/smbfs_bootstrap_impl.h"
#include <memory>
#include <utility>
#include <vector>
#include <base/check.h>
#include <base/files/file_util.h>
#include <base/files/scoped_file.h>
#include <base/files/scoped_temp_dir.h>
#include <base/test/bind.h>
#include <base/test/task_environment.h>
#include <base/test/test_future.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <mojo/core/embedder/embedder.h>
#include <mojo/public/cpp/bindings/pending_remote.h>
#include <mojo/public/cpp/bindings/pending_receiver.h>
#include <mojo/public/cpp/bindings/remote.h>
#include <mojo/public/cpp/bindings/receiver.h>
#include <mojo/public/cpp/system/platform_handle.h>
#include <libpasswordprovider/password.h>
#include "smbfs/smb_filesystem.h"
#include "smbfs/smbfs_impl.h"
namespace smbfs {
namespace {
using ::testing::_;
using ::testing::Return;
using ::testing::Unused;
using ::testing::WithArg;
const char kSharePath[] = "smb://server/share";
const char kWorkgroup[] = "my-workgroup";
const char kUsername[] = "my-username";
const char kPassword[] = "my-super-secret-password";
const char kKerberosGuid[] = "1234-5678-my-guid";
const char kAccountHash[] = "00112233445566778899aa";
class MockSmbFilesystemDelegate : public SmbFilesystem::Delegate {
public:
MOCK_METHOD(void,
RequestCredentials,
(RequestCredentialsCallback),
(override));
};
class MockSmbFilesystem : public SmbFilesystem {
public:
MockSmbFilesystem() : SmbFilesystem(&delegate_, kSharePath) {}
MOCK_METHOD(ConnectError, EnsureConnected, (), (override));
MOCK_METHOD(void,
SetResolvedAddress,
(const std::vector<uint8_t>&),
(override));
private:
MockSmbFilesystemDelegate delegate_;
};
class MockBootstrapDelegate : public SmbFsBootstrapImpl::Delegate {
public:
MOCK_METHOD(void,
SetupKerberos,
(mojom::KerberosConfigPtr,
base::OnceCallback<void(bool success)>),
(override));
MOCK_METHOD(void, OnPasswordFilePathSet, (const base::FilePath&), (override));
};
class MockSmbFsDelegate : public mojom::SmbFsDelegate {
public:
explicit MockSmbFsDelegate(
mojo::PendingReceiver<mojom::SmbFsDelegate> receiver)
: receiver_(this, std::move(receiver)) {}
MOCK_METHOD(void,
RequestCredentials,
(RequestCredentialsCallback),
(override));
private:
mojo::Receiver<mojom::SmbFsDelegate> receiver_;
};
std::unique_ptr<password_provider::Password> MakePassword(
const std::string& password) {
int fds[2];
CHECK(base::CreateLocalNonBlockingPipe(fds));
base::ScopedFD read_fd(fds[0]);
base::ScopedFD write_fd(fds[1]);
CHECK(base::WriteFileDescriptor(write_fd.get(), password));
return password_provider::Password::CreateFromFileDescriptor(read_fd.get(),
password.size());
}
class TestSmbFsBootstrapImpl : public testing::Test {
public:
void SetUp() override {
ResetDelegate();
ASSERT_TRUE(daemon_store_dir_.CreateUniqueTempDir());
}
void ResetDelegate() {
smbfs_delegate_.reset();
mock_smbfs_delegate_ = std::make_unique<MockSmbFsDelegate>(
smbfs_delegate_.InitWithNewPipeAndPassReceiver());
}
void MountShareWithSuccess(
const mojo::Remote<mojom::SmbFsBootstrap>& bootstrap,
mojom::MountOptionsPtr mount_options) {
base::test::TestFuture<mojom::MountError,
::mojo::PendingRemote<mojom::SmbFs>>
future;
bootstrap->MountShare(std::move(mount_options), std::move(smbfs_delegate_),
future.GetCallback());
EXPECT_EQ(future.Get<0>(), mojom::MountError::kOk);
EXPECT_TRUE(future.Get<1>());
}
void MountShareWithError(const mojo::Remote<mojom::SmbFsBootstrap>& bootstrap,
mojom::MountOptionsPtr mount_options,
mojom::MountError expected_error) {
base::test::TestFuture<mojom::MountError,
::mojo::PendingRemote<mojom::SmbFs>>
future;
bootstrap->MountShare(std::move(mount_options), std::move(smbfs_delegate_),
future.GetCallback());
EXPECT_EQ(future.Get<0>(), expected_error);
EXPECT_FALSE(future.Get<1>());
}
protected:
base::test::TaskEnvironment task_environment{
base::test::TaskEnvironment::ThreadingMode::MAIN_THREAD_ONLY,
base::test::TaskEnvironment::MainThreadType::IO};
MockBootstrapDelegate mock_delegate_;
mojo::PendingRemote<mojom::SmbFsDelegate> smbfs_delegate_;
std::unique_ptr<MockSmbFsDelegate> mock_smbfs_delegate_;
base::ScopedTempDir daemon_store_dir_;
};
TEST_F(TestSmbFsBootstrapImpl, GuestAuth) {
mojo::Remote<mojom::SmbFsBootstrap> bootstrap;
auto fs_factory = base::BindLambdaForTesting(
[](SmbFilesystem::Options options) -> std::unique_ptr<SmbFilesystem> {
EXPECT_EQ(options.share_path, kSharePath);
EXPECT_FALSE(options.allow_ntlm);
EXPECT_TRUE(options.credentials->workgroup.empty());
EXPECT_TRUE(options.credentials->username.empty());
EXPECT_FALSE(options.credentials->password);
std::unique_ptr<MockSmbFilesystem> fs =
std::make_unique<MockSmbFilesystem>();
EXPECT_CALL(*fs, EnsureConnected())
.WillOnce(Return(SmbFilesystem::ConnectError::kOk));
EXPECT_CALL(*fs, SetResolvedAddress(std::vector<uint8_t>({1, 2, 3, 4})))
.Times(1);
return fs;
});
SmbFsBootstrapImpl boostrap_impl(bootstrap.BindNewPipeAndPassReceiver(),
fs_factory, &mock_delegate_,
daemon_store_dir_.GetPath());
bool bootstrap_done = false;
boostrap_impl.Start(base::BindLambdaForTesting(
[&bootstrap_done](std::unique_ptr<SmbFilesystem> fs,
mojo::PendingReceiver<mojom::SmbFs> smbfs_receiver,
mojo::PendingRemote<mojom::SmbFsDelegate> delegate) {
EXPECT_TRUE(fs);
bootstrap_done = true;
}));
mojom::MountOptionsPtr mount_options = mojom::MountOptions::New();
mount_options->share_path = kSharePath;
mount_options->resolved_host =
mojom::IPAddress::New(std::vector<uint8_t>({1, 2, 3, 4}));
MountShareWithSuccess(bootstrap, std::move(mount_options));
EXPECT_TRUE(bootstrap_done);
}
TEST_F(TestSmbFsBootstrapImpl, UsernamePasswordAuth) {
mojo::Remote<mojom::SmbFsBootstrap> bootstrap;
auto fs_factory = base::BindLambdaForTesting(
[](SmbFilesystem::Options options) -> std::unique_ptr<SmbFilesystem> {
EXPECT_EQ(options.share_path, kSharePath);
EXPECT_TRUE(options.allow_ntlm);
EXPECT_EQ(options.credentials->workgroup, kWorkgroup);
EXPECT_EQ(options.credentials->username, kUsername);
EXPECT_EQ(options.credentials->password->GetRaw(),
std::string(kPassword));
std::unique_ptr<MockSmbFilesystem> fs =
std::make_unique<MockSmbFilesystem>();
EXPECT_CALL(*fs, EnsureConnected())
.WillOnce(Return(SmbFilesystem::ConnectError::kOk));
EXPECT_CALL(*fs, SetResolvedAddress(_)).Times(0);
return fs;
});
SmbFsBootstrapImpl boostrap_impl(bootstrap.BindNewPipeAndPassReceiver(),
fs_factory, &mock_delegate_,
daemon_store_dir_.GetPath());
bool bootstrap_done = false;
boostrap_impl.Start(base::BindLambdaForTesting(
[&bootstrap_done](std::unique_ptr<SmbFilesystem> fs,
mojo::PendingReceiver<mojom::SmbFs> smbfs_receiver,
mojo::PendingRemote<mojom::SmbFsDelegate> delegate) {
EXPECT_TRUE(fs);
bootstrap_done = true;
}));
mojom::MountOptionsPtr mount_options = mojom::MountOptions::New();
mount_options->share_path = kSharePath;
mount_options->workgroup = kWorkgroup;
mount_options->username = kUsername;
mount_options->password = MakePassword(kPassword);
mount_options->allow_ntlm = true;
MountShareWithSuccess(bootstrap, std::move(mount_options));
EXPECT_TRUE(bootstrap_done);
}
TEST_F(TestSmbFsBootstrapImpl, KerberosAuth) {
mojo::Remote<mojom::SmbFsBootstrap> bootstrap;
auto fs_factory = base::BindLambdaForTesting(
[](SmbFilesystem::Options options) -> std::unique_ptr<SmbFilesystem> {
EXPECT_EQ(options.share_path, kSharePath);
EXPECT_FALSE(options.allow_ntlm);
EXPECT_EQ(options.credentials->workgroup, kWorkgroup);
EXPECT_EQ(options.credentials->username, kUsername);
EXPECT_FALSE(options.credentials->password);
std::unique_ptr<MockSmbFilesystem> fs =
std::make_unique<MockSmbFilesystem>();
EXPECT_CALL(*fs, EnsureConnected())
.WillOnce(Return(SmbFilesystem::ConnectError::kOk));
EXPECT_CALL(*fs, SetResolvedAddress(_)).Times(0);
return fs;
});
SmbFsBootstrapImpl boostrap_impl(bootstrap.BindNewPipeAndPassReceiver(),
fs_factory, &mock_delegate_,
daemon_store_dir_.GetPath());
EXPECT_CALL(mock_delegate_, SetupKerberos(_, _))
.WillOnce([](mojom::KerberosConfigPtr config,
base::OnceCallback<void(bool success)> callback) {
EXPECT_EQ(config->source, mojom::KerberosConfig::Source::kKerberos);
EXPECT_EQ(config->identity, kKerberosGuid);
std::move(callback).Run(true);
});
bool bootstrap_done = false;
boostrap_impl.Start(base::BindLambdaForTesting(
[&bootstrap_done](std::unique_ptr<SmbFilesystem> fs,
mojo::PendingReceiver<mojom::SmbFs> smbfs_receiver,
mojo::PendingRemote<mojom::SmbFsDelegate> delegate) {
EXPECT_TRUE(fs);
bootstrap_done = true;
}));
mojom::MountOptionsPtr mount_options = mojom::MountOptions::New();
mount_options->share_path = kSharePath;
mount_options->workgroup = kWorkgroup;
mount_options->username = kUsername;
mount_options->kerberos_config = mojom::KerberosConfig::New(
mojom::KerberosConfig::Source::kKerberos, kKerberosGuid);
// These two options will be ignored when Kerberos is being used.
mount_options->password = MakePassword(kPassword);
mount_options->resolved_host =
mojom::IPAddress::New(std::vector<uint8_t>({1, 2, 3, 4}));
MountShareWithSuccess(bootstrap, std::move(mount_options));
EXPECT_TRUE(bootstrap_done);
}
TEST_F(TestSmbFsBootstrapImpl, SkipConnect) {
mojo::Remote<mojom::SmbFsBootstrap> bootstrap;
auto fs_factory = base::BindLambdaForTesting(
[](SmbFilesystem::Options options) -> std::unique_ptr<SmbFilesystem> {
EXPECT_EQ(options.share_path, kSharePath);
EXPECT_FALSE(options.allow_ntlm);
std::unique_ptr<MockSmbFilesystem> fs =
std::make_unique<MockSmbFilesystem>();
// Expect that EnsureConnected() is never called when skip_connect mount
// option is set.
EXPECT_CALL(*fs, EnsureConnected()).Times(0);
return fs;
});
SmbFsBootstrapImpl boostrap_impl(bootstrap.BindNewPipeAndPassReceiver(),
fs_factory, &mock_delegate_,
daemon_store_dir_.GetPath());
bool bootstrap_done = false;
boostrap_impl.Start(base::BindLambdaForTesting(
[&bootstrap_done](std::unique_ptr<SmbFilesystem> fs,
mojo::PendingReceiver<mojom::SmbFs> smbfs_receiver,
mojo::PendingRemote<mojom::SmbFsDelegate> delegate) {
EXPECT_TRUE(fs);
bootstrap_done = true;
}));
mojom::MountOptionsPtr mount_options = mojom::MountOptions::New();
mount_options->share_path = kSharePath;
mount_options->skip_connect = true;
MountShareWithSuccess(bootstrap, std::move(mount_options));
EXPECT_TRUE(bootstrap_done);
}
TEST_F(TestSmbFsBootstrapImpl, Disconnect) {
mojo::Remote<mojom::SmbFsBootstrap> bootstrap;
auto fs_factory = base::BindLambdaForTesting(
[](SmbFilesystem::Options options) -> std::unique_ptr<SmbFilesystem> {
// FAIL() can only be used in a function that returns void.
ADD_FAILURE();
return nullptr;
});
SmbFsBootstrapImpl boostrap_impl(bootstrap.BindNewPipeAndPassReceiver(),
fs_factory, &mock_delegate_,
daemon_store_dir_.GetPath());
base::test::TestFuture<std::unique_ptr<SmbFilesystem>,
mojo::PendingReceiver<mojom::SmbFs>,
mojo::PendingRemote<mojom::SmbFsDelegate>>
future;
boostrap_impl.Start(future.GetCallback());
bootstrap.reset();
EXPECT_FALSE(future.Get<0>());
}
TEST_F(TestSmbFsBootstrapImpl, InvalidPath) {
mojo::Remote<mojom::SmbFsBootstrap> bootstrap;
auto fs_factory = base::BindLambdaForTesting(
[](SmbFilesystem::Options options) -> std::unique_ptr<SmbFilesystem> {
ADD_FAILURE();
return nullptr;
});
SmbFsBootstrapImpl boostrap_impl(bootstrap.BindNewPipeAndPassReceiver(),
fs_factory, &mock_delegate_,
daemon_store_dir_.GetPath());
boostrap_impl.Start(base::BindOnce(
[](std::unique_ptr<SmbFilesystem> fs,
mojo::PendingReceiver<mojom::SmbFs> smbfs,
mojo::PendingRemote<mojom::SmbFsDelegate> delegate) { FAIL(); }));
mojom::MountOptionsPtr mount_options = mojom::MountOptions::New();
mount_options->share_path = "bad-path";
MountShareWithError(bootstrap, std::move(mount_options),
mojom::MountError::kInvalidUrl);
}
TEST_F(TestSmbFsBootstrapImpl, KerberosSetupFailure) {
mojo::Remote<mojom::SmbFsBootstrap> bootstrap;
auto fs_factory = base::BindLambdaForTesting(
[](SmbFilesystem::Options options) -> std::unique_ptr<SmbFilesystem> {
ADD_FAILURE();
return nullptr;
});
SmbFsBootstrapImpl boostrap_impl(bootstrap.BindNewPipeAndPassReceiver(),
fs_factory, &mock_delegate_,
daemon_store_dir_.GetPath());
EXPECT_CALL(mock_delegate_, SetupKerberos(_, _))
.WillOnce([](mojom::KerberosConfigPtr config,
base::OnceCallback<void(bool success)> callback) {
std::move(callback).Run(false);
});
boostrap_impl.Start(base::BindOnce(
[](std::unique_ptr<SmbFilesystem> fs,
mojo::PendingReceiver<mojom::SmbFs> smbfs,
mojo::PendingRemote<mojom::SmbFsDelegate> delegate) { FAIL(); }));
mojom::MountOptionsPtr mount_options = mojom::MountOptions::New();
mount_options->share_path = kSharePath;
mount_options->workgroup = kWorkgroup;
mount_options->username = kUsername;
mount_options->kerberos_config = mojom::KerberosConfig::New(
mojom::KerberosConfig::Source::kKerberos, kKerberosGuid);
MountShareWithError(bootstrap, std::move(mount_options),
mojom::MountError::kUnknown);
}
TEST_F(TestSmbFsBootstrapImpl, ConnectionAuthFailure) {
mojo::Remote<mojom::SmbFsBootstrap> bootstrap;
auto fs_factory = base::BindLambdaForTesting(
[](SmbFilesystem::Options options) -> std::unique_ptr<SmbFilesystem> {
EXPECT_EQ(options.share_path, kSharePath);
std::unique_ptr<MockSmbFilesystem> fs =
std::make_unique<MockSmbFilesystem>();
EXPECT_CALL(*fs, EnsureConnected())
.WillOnce(Return(SmbFilesystem::ConnectError::kAccessDenied));
return fs;
});
SmbFsBootstrapImpl boostrap_impl(bootstrap.BindNewPipeAndPassReceiver(),
fs_factory, &mock_delegate_,
daemon_store_dir_.GetPath());
boostrap_impl.Start(base::BindOnce(
[](std::unique_ptr<SmbFilesystem> fs,
mojo::PendingReceiver<mojom::SmbFs> smbfs,
mojo::PendingRemote<mojom::SmbFsDelegate> delegate) { FAIL(); }));
mojom::MountOptionsPtr mount_options = mojom::MountOptions::New();
mount_options->share_path = kSharePath;
MountShareWithError(bootstrap, std::move(mount_options),
mojom::MountError::kAccessDenied);
}
TEST_F(TestSmbFsBootstrapImpl, UnsupportedProtocolSmb1) {
mojo::Remote<mojom::SmbFsBootstrap> bootstrap;
auto fs_factory = base::BindLambdaForTesting(
[](SmbFilesystem::Options options) -> std::unique_ptr<SmbFilesystem> {
EXPECT_EQ(options.share_path, kSharePath);
std::unique_ptr<MockSmbFilesystem> fs =
std::make_unique<MockSmbFilesystem>();
EXPECT_CALL(*fs, EnsureConnected())
.WillOnce(Return(SmbFilesystem::ConnectError::kSmb1Unsupported));
return fs;
});
SmbFsBootstrapImpl boostrap_impl(bootstrap.BindNewPipeAndPassReceiver(),
fs_factory, &mock_delegate_,
daemon_store_dir_.GetPath());
boostrap_impl.Start(base::BindOnce(
[](std::unique_ptr<SmbFilesystem> fs,
mojo::PendingReceiver<mojom::SmbFs> smbfs,
mojo::PendingRemote<mojom::SmbFsDelegate> delegate) { FAIL(); }));
mojom::MountOptionsPtr mount_options = mojom::MountOptions::New();
mount_options->share_path = kSharePath;
MountShareWithError(bootstrap, std::move(mount_options),
mojom::MountError::kInvalidProtocol);
}
TEST_F(TestSmbFsBootstrapImpl, SaveRestorePassword) {
const std::vector<uint8_t> salt(
mojom::CredentialStorageOptions::kMinSaltLength, 'a');
const base::FilePath user_directory =
daemon_store_dir_.GetPath().Append(kAccountHash);
ASSERT_TRUE(base::CreateDirectory(user_directory));
EXPECT_TRUE(base::IsDirectoryEmpty(user_directory));
{
mojo::Remote<mojom::SmbFsBootstrap> bootstrap;
auto fs_factory = base::BindLambdaForTesting(
[](SmbFilesystem::Options options) -> std::unique_ptr<SmbFilesystem> {
std::unique_ptr<MockSmbFilesystem> fs =
std::make_unique<MockSmbFilesystem>();
EXPECT_CALL(*fs, EnsureConnected())
.WillOnce(Return(SmbFilesystem::ConnectError::kOk));
return fs;
});
EXPECT_CALL(mock_delegate_, OnPasswordFilePathSet(_))
.WillOnce([user_directory](const base::FilePath& path) {
EXPECT_TRUE(user_directory.IsParent(path));
});
SmbFsBootstrapImpl boostrap_impl(bootstrap.BindNewPipeAndPassReceiver(),
fs_factory, &mock_delegate_,
daemon_store_dir_.GetPath());
boostrap_impl.Start(base::BindLambdaForTesting(
[](std::unique_ptr<SmbFilesystem> fs,
mojo::PendingReceiver<mojom::SmbFs> smbfs,
mojo::PendingRemote<mojom::SmbFsDelegate> delegate) {
EXPECT_TRUE(fs);
}));
mojom::MountOptionsPtr mount_options = mojom::MountOptions::New();
mount_options->share_path = kSharePath;
mount_options->workgroup = kWorkgroup;
mount_options->username = kUsername;
mount_options->password = MakePassword(kPassword);
mount_options->credential_storage_options =
mojom::CredentialStorageOptions::New(kAccountHash, salt);
MountShareWithSuccess(bootstrap, std::move(mount_options));
}
// There should be a file in the user's daemon-store directory.
EXPECT_FALSE(base::IsDirectoryEmpty(user_directory));
// Since the file's name and contents are obfuscated, don't check them
// directly. Instead, do another mount operation which uses the saved
// password.
{
mojo::Remote<mojom::SmbFsBootstrap> bootstrap;
auto fs_factory = base::BindLambdaForTesting(
[](SmbFilesystem::Options options) -> std::unique_ptr<SmbFilesystem> {
EXPECT_EQ(options.credentials->workgroup, kWorkgroup);
EXPECT_EQ(options.credentials->username, kUsername);
EXPECT_EQ(options.credentials->password->GetRaw(),
std::string(kPassword));
std::unique_ptr<MockSmbFilesystem> fs =
std::make_unique<MockSmbFilesystem>();
EXPECT_CALL(*fs, EnsureConnected())
.WillOnce(Return(SmbFilesystem::ConnectError::kOk));
return fs;
});
EXPECT_CALL(mock_delegate_, OnPasswordFilePathSet(_))
.WillOnce([user_directory](const base::FilePath& path) {
EXPECT_TRUE(user_directory.IsParent(path));
});
SmbFsBootstrapImpl boostrap_impl(bootstrap.BindNewPipeAndPassReceiver(),
fs_factory, &mock_delegate_,
daemon_store_dir_.GetPath());
boostrap_impl.Start(base::BindLambdaForTesting(
[](std::unique_ptr<SmbFilesystem> fs,
mojo::PendingReceiver<mojom::SmbFs> smbfs,
mojo::PendingRemote<mojom::SmbFsDelegate> delegate) {
EXPECT_TRUE(fs);
}));
mojom::MountOptionsPtr mount_options = mojom::MountOptions::New();
mount_options->share_path = kSharePath;
mount_options->workgroup = kWorkgroup;
mount_options->username = kUsername;
// When there's no password field, implicitly restore the password from a
// file.
mount_options->credential_storage_options =
mojom::CredentialStorageOptions::New(kAccountHash, salt);
ResetDelegate();
MountShareWithSuccess(bootstrap, std::move(mount_options));
}
}
TEST_F(TestSmbFsBootstrapImpl, NoSavePasswordOnMountFailure) {
const std::vector<uint8_t> salt(
mojom::CredentialStorageOptions::kMinSaltLength, 'a');
const base::FilePath user_directory =
daemon_store_dir_.GetPath().Append(kAccountHash);
ASSERT_TRUE(base::CreateDirectory(user_directory));
EXPECT_TRUE(base::IsDirectoryEmpty(user_directory));
{
mojo::Remote<mojom::SmbFsBootstrap> bootstrap;
auto fs_factory = base::BindLambdaForTesting(
[](SmbFilesystem::Options options) -> std::unique_ptr<SmbFilesystem> {
std::unique_ptr<MockSmbFilesystem> fs =
std::make_unique<MockSmbFilesystem>();
EXPECT_CALL(*fs, EnsureConnected())
.WillOnce(Return(SmbFilesystem::ConnectError::kAccessDenied));
return fs;
});
SmbFsBootstrapImpl boostrap_impl(bootstrap.BindNewPipeAndPassReceiver(),
fs_factory, &mock_delegate_,
daemon_store_dir_.GetPath());
boostrap_impl.Start(base::BindLambdaForTesting(
[](std::unique_ptr<SmbFilesystem> fs,
mojo::PendingReceiver<mojom::SmbFs> smbfs,
mojo::PendingRemote<mojom::SmbFsDelegate> delegate) {
EXPECT_TRUE(fs);
}));
mojom::MountOptionsPtr mount_options = mojom::MountOptions::New();
mount_options->share_path = kSharePath;
mount_options->workgroup = kWorkgroup;
mount_options->username = kUsername;
mount_options->password = MakePassword(kPassword);
mount_options->credential_storage_options =
mojom::CredentialStorageOptions::New(kAccountHash, salt);
MountShareWithError(bootstrap, std::move(mount_options),
mojom::MountError::kAccessDenied);
}
// There should be no files in the user's daemon-store.
EXPECT_TRUE(base::IsDirectoryEmpty(user_directory));
}
} // namespace
} // namespace smbfs