blob: 3616bc1d4ec4d87efb7529665ac1988da317cf66 [file] [log] [blame]
Sergei Datsenkobcd8e462018-04-20 15:44:56 +10001// Copyright 2018 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "cros-disks/sshfs_helper.h"
6
7#include <string>
8#include <vector>
9
10#include <base/strings/string_split.h>
11#include <base/strings/string_util.h>
12#include <base/strings/stringprintf.h>
Sergei Datsenkoa910bba2019-06-18 13:31:59 +100013#include <brillo/process_reaper.h>
Sergei Datsenkobcd8e462018-04-20 15:44:56 +100014#include <gmock/gmock.h>
15#include <gtest/gtest.h>
16
17#include "cros-disks/fuse_mounter.h"
18#include "cros-disks/mount_options.h"
19#include "cros-disks/platform.h"
20#include "cros-disks/uri.h"
21
Sergei Datsenkobcd8e462018-04-20 15:44:56 +100022using testing::DoAll;
23using testing::Eq;
24using testing::HasSubstr;
25using testing::Not;
26using testing::Return;
27using testing::SetArgPointee;
28using testing::StrEq;
29using testing::_;
30
31namespace cros_disks {
32
33namespace {
34
35const uid_t kMountUID = 200;
36const gid_t kMountGID = 201;
37const uid_t kFilesUID = 700;
38const uid_t kFilesGID = 701;
39const uid_t kFilesAccessGID = 1501;
40const base::FilePath kWorkingDir("/wkdir");
41const base::FilePath kMountDir("/mnt");
42const Uri kSomeSource("sshfs", "src");
43
44// Mock Platform implementation for testing.
45class MockPlatform : public Platform {
46 public:
47 MockPlatform() = default;
48
Ben Chan213c6d92019-04-10 16:21:52 -070049 bool GetUserAndGroupId(const std::string& user,
Sergei Datsenkobcd8e462018-04-20 15:44:56 +100050 uid_t* user_id,
51 gid_t* group_id) const override {
52 if (user == "fuse-sshfs") {
53 if (user_id)
54 *user_id = kMountUID;
55 if (group_id)
56 *group_id = kMountGID;
57 return true;
58 }
59 if (user == FUSEHelper::kFilesUser) {
60 if (user_id)
61 *user_id = kFilesUID;
62 if (group_id)
63 *group_id = kFilesGID;
64 return true;
65 }
66 return false;
67 }
68
Ben Chan213c6d92019-04-10 16:21:52 -070069 bool GetGroupId(const std::string& group, gid_t* group_id) const override {
Sergei Datsenkobcd8e462018-04-20 15:44:56 +100070 if (group == FUSEHelper::kFilesGroup) {
71 if (group_id)
72 *group_id = kFilesAccessGID;
73 return true;
74 }
75 return false;
76 }
77
Sergei Datsenkobcd8e462018-04-20 15:44:56 +100078 MOCK_CONST_METHOD3(SetOwnership,
Ben Chan213c6d92019-04-10 16:21:52 -070079 bool(const std::string& path,
80 uid_t user_id,
81 gid_t group_id));
82 MOCK_CONST_METHOD2(SetPermissions,
83 bool(const std::string& path, mode_t mode));
Sergei Datsenkoad2cb6a2018-05-15 17:34:26 +100084 MOCK_CONST_METHOD3(WriteFile,
Ben Chan213c6d92019-04-10 16:21:52 -070085 int(const std::string& path, const char* data, int size));
Sergei Datsenkobcd8e462018-04-20 15:44:56 +100086};
87
88} // namespace
89
90class SshfsHelperTest : public ::testing::Test {
91 public:
Sergei Datsenkoa910bba2019-06-18 13:31:59 +100092 SshfsHelperTest() : helper_(&platform_, &process_reaper_) {
Sergei Datsenkobcd8e462018-04-20 15:44:56 +100093 ON_CALL(platform_, SetOwnership(_, kMountUID, getgid()))
94 .WillByDefault(Return(true));
95 ON_CALL(platform_, SetPermissions(_, 0770)).WillByDefault(Return(true));
Sergei Datsenkoad2cb6a2018-05-15 17:34:26 +100096 ON_CALL(platform_, WriteFile(_, _, _)).WillByDefault(Return(-1));
Sergei Datsenkobcd8e462018-04-20 15:44:56 +100097 }
98
99 protected:
100 MockPlatform platform_;
Sergei Datsenkoa910bba2019-06-18 13:31:59 +1000101 brillo::ProcessReaper process_reaper_;
Sergei Datsenkobcd8e462018-04-20 15:44:56 +1000102 SshfsHelper helper_;
103};
104
105// Verifies that CreateMounter creates mounter in a simple case.
106TEST_F(SshfsHelperTest, CreateMounter_SimpleOptions) {
107 auto mounter = helper_.CreateMounter(kWorkingDir, kSomeSource, kMountDir, {});
108 EXPECT_EQ("sshfs", mounter->filesystem_type());
Sergei Datsenko3cf72cb2019-04-01 11:27:50 +1100109 EXPECT_EQ("src", mounter->source());
110 EXPECT_EQ("/mnt", mounter->target_path().value());
Ben Chan213c6d92019-04-10 16:21:52 -0700111 std::string opts = mounter->mount_options().ToString();
Sergei Datsenkobcd8e462018-04-20 15:44:56 +1000112 EXPECT_THAT(opts, HasSubstr("BatchMode=yes"));
113 EXPECT_THAT(opts, HasSubstr("PasswordAuthentication=no"));
114 EXPECT_THAT(opts, HasSubstr("KbdInteractiveAuthentication=no"));
Joel Hockey1a00fef2018-07-26 20:25:39 -0700115 EXPECT_THAT(opts, HasSubstr("follow_symlinks"));
Sergei Datsenkobcd8e462018-04-20 15:44:56 +1000116 EXPECT_THAT(opts, HasSubstr("uid=700"));
117 EXPECT_THAT(opts, HasSubstr("gid=1501"));
118}
119
Sergei Datsenkoad2cb6a2018-05-15 17:34:26 +1000120// Verifies that CreateMounter writes files to the working dir when provided.
121TEST_F(SshfsHelperTest, CreateMounter_WriteFiles) {
122 EXPECT_CALL(platform_, WriteFile("/wkdir/id", StrEq("some key"), 8))
123 .WillOnce(Return(8));
124 EXPECT_CALL(platform_, WriteFile("/wkdir/known_hosts", StrEq("some host"), 9))
125 .WillOnce(Return(9));
126 EXPECT_CALL(platform_, SetPermissions("/wkdir/id", 0600))
Sergei Datsenkobcd8e462018-04-20 15:44:56 +1000127 .WillOnce(Return(true));
Sergei Datsenkoad2cb6a2018-05-15 17:34:26 +1000128 EXPECT_CALL(platform_, SetPermissions("/wkdir/known_hosts", 0600))
Sergei Datsenkobcd8e462018-04-20 15:44:56 +1000129 .WillOnce(Return(true));
130 EXPECT_CALL(platform_, SetPermissions("/wkdir", 0770)).WillOnce(Return(true));
Sergei Datsenkoad2cb6a2018-05-15 17:34:26 +1000131 EXPECT_CALL(platform_, SetOwnership("/wkdir/id", kMountUID, kMountGID))
Sergei Datsenkobcd8e462018-04-20 15:44:56 +1000132 .WillOnce(Return(true));
Sergei Datsenkoad2cb6a2018-05-15 17:34:26 +1000133 EXPECT_CALL(platform_,
134 SetOwnership("/wkdir/known_hosts", kMountUID, kMountGID))
Sergei Datsenkobcd8e462018-04-20 15:44:56 +1000135 .WillOnce(Return(true));
136 EXPECT_CALL(platform_, SetOwnership("/wkdir", kMountUID, getgid()))
137 .WillOnce(Return(true));
138 auto mounter = helper_.CreateMounter(
139 kWorkingDir, kSomeSource, kMountDir,
Sergei Datsenkoad2cb6a2018-05-15 17:34:26 +1000140 {"IdentityBase64=c29tZSBrZXk=", "UserKnownHostsBase64=c29tZSBob3N0",
141 "IdentityFile=/foo/bar", "UserKnownHostsFile=/foo/baz",
Sergei Datsenko1aa55362018-05-14 15:19:27 +1000142 "HostName=localhost", "Port=2222"});
Ben Chan213c6d92019-04-10 16:21:52 -0700143 std::string opts = mounter->mount_options().ToString();
Sergei Datsenkoad2cb6a2018-05-15 17:34:26 +1000144 EXPECT_THAT(opts, HasSubstr("IdentityFile=/wkdir/id"));
145 EXPECT_THAT(opts, HasSubstr("UserKnownHostsFile=/wkdir/known_hosts"));
Sergei Datsenko1aa55362018-05-14 15:19:27 +1000146 EXPECT_THAT(opts, HasSubstr("HostName=localhost"));
147 EXPECT_THAT(opts, HasSubstr("Port=2222"));
Sergei Datsenkoad2cb6a2018-05-15 17:34:26 +1000148 EXPECT_THAT(opts, Not(HasSubstr("Base64")));
149 EXPECT_THAT(opts, Not(HasSubstr("c29tZSB")));
Sergei Datsenkobcd8e462018-04-20 15:44:56 +1000150 EXPECT_THAT(opts, Not(HasSubstr("/foo/bar")));
151 EXPECT_THAT(opts, Not(HasSubstr("/foo/baz")));
152}
153
Sergei Datsenkobcd8e462018-04-20 15:44:56 +1000154// Verifies that CanMount correctly identifies handleable URIs.
155TEST_F(SshfsHelperTest, CanMount) {
156 EXPECT_TRUE(helper_.CanMount(Uri::Parse("sshfs://foo")));
157 EXPECT_FALSE(helper_.CanMount(Uri::Parse("sshfss://foo")));
158 EXPECT_FALSE(helper_.CanMount(Uri::Parse("ssh://foo")));
159 EXPECT_FALSE(helper_.CanMount(Uri::Parse("sshfs://")));
160}
161
162// Verifies that GetTargetSuffix escapes unwanted chars in URI.
163TEST_F(SshfsHelperTest, GetTargetSuffix) {
164 EXPECT_EQ("foo", helper_.GetTargetSuffix(Uri::Parse("sshfs://foo")));
165 EXPECT_EQ("usr@host_com:",
166 helper_.GetTargetSuffix(Uri::Parse("sshfs://usr@host.com:")));
167 EXPECT_EQ("host:$some$path$__",
168 helper_.GetTargetSuffix(Uri::Parse("sshfs://host:/some/path/..")));
169}
170
171} // namespace cros_disks