blob: da4d203363a749defe70093de3a48134f35c7f0d [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>
13#include <gmock/gmock.h>
14#include <gtest/gtest.h>
15
16#include "cros-disks/fuse_mounter.h"
17#include "cros-disks/mount_options.h"
18#include "cros-disks/platform.h"
19#include "cros-disks/uri.h"
20
21using std::string;
22using std::vector;
23using testing::DoAll;
24using testing::Eq;
25using testing::HasSubstr;
26using testing::Not;
27using testing::Return;
28using testing::SetArgPointee;
29using testing::StrEq;
30using testing::_;
31
32namespace cros_disks {
33
34namespace {
35
36const uid_t kMountUID = 200;
37const gid_t kMountGID = 201;
38const uid_t kFilesUID = 700;
39const uid_t kFilesGID = 701;
40const uid_t kFilesAccessGID = 1501;
41const base::FilePath kWorkingDir("/wkdir");
42const base::FilePath kMountDir("/mnt");
43const Uri kSomeSource("sshfs", "src");
44
45// Mock Platform implementation for testing.
46class MockPlatform : public Platform {
47 public:
48 MockPlatform() = default;
49
50 bool GetUserAndGroupId(const string& user,
51 uid_t* user_id,
52 gid_t* group_id) const override {
53 if (user == "fuse-sshfs") {
54 if (user_id)
55 *user_id = kMountUID;
56 if (group_id)
57 *group_id = kMountGID;
58 return true;
59 }
60 if (user == FUSEHelper::kFilesUser) {
61 if (user_id)
62 *user_id = kFilesUID;
63 if (group_id)
64 *group_id = kFilesGID;
65 return true;
66 }
67 return false;
68 }
69
70 bool GetGroupId(const string& group, gid_t* group_id) const override {
71 if (group == FUSEHelper::kFilesGroup) {
72 if (group_id)
73 *group_id = kFilesAccessGID;
74 return true;
75 }
76 return false;
77 }
78
Sergei Datsenkobcd8e462018-04-20 15:44:56 +100079 MOCK_CONST_METHOD3(SetOwnership,
80 bool(const string& path, uid_t user_id, gid_t group_id));
81 MOCK_CONST_METHOD2(SetPermissions, bool(const string& path, mode_t mode));
Sergei Datsenkoad2cb6a2018-05-15 17:34:26 +100082 MOCK_CONST_METHOD3(WriteFile,
83 int(const string& path, const char* data, int size));
Sergei Datsenkobcd8e462018-04-20 15:44:56 +100084};
85
86} // namespace
87
88class SshfsHelperTest : public ::testing::Test {
89 public:
90 SshfsHelperTest() : helper_(&platform_) {
91 ON_CALL(platform_, SetOwnership(_, kMountUID, getgid()))
92 .WillByDefault(Return(true));
93 ON_CALL(platform_, SetPermissions(_, 0770)).WillByDefault(Return(true));
Sergei Datsenkoad2cb6a2018-05-15 17:34:26 +100094 ON_CALL(platform_, WriteFile(_, _, _)).WillByDefault(Return(-1));
Sergei Datsenkobcd8e462018-04-20 15:44:56 +100095 }
96
97 protected:
98 MockPlatform platform_;
99 SshfsHelper helper_;
100};
101
102// Verifies that CreateMounter creates mounter in a simple case.
103TEST_F(SshfsHelperTest, CreateMounter_SimpleOptions) {
104 auto mounter = helper_.CreateMounter(kWorkingDir, kSomeSource, kMountDir, {});
105 EXPECT_EQ("sshfs", mounter->filesystem_type());
106 EXPECT_EQ("src", mounter->source_path());
107 EXPECT_EQ("/mnt", mounter->target_path());
108 string opts = mounter->mount_options().ToString();
109 EXPECT_THAT(opts, HasSubstr("BatchMode=yes"));
110 EXPECT_THAT(opts, HasSubstr("PasswordAuthentication=no"));
111 EXPECT_THAT(opts, HasSubstr("KbdInteractiveAuthentication=no"));
Joel Hockey1a00fef2018-07-26 20:25:39 -0700112 EXPECT_THAT(opts, HasSubstr("follow_symlinks"));
Sergei Datsenkobcd8e462018-04-20 15:44:56 +1000113 EXPECT_THAT(opts, HasSubstr("allow_other"));
114 EXPECT_THAT(opts, HasSubstr("default_permissions"));
115 EXPECT_THAT(opts, HasSubstr("uid=700"));
116 EXPECT_THAT(opts, HasSubstr("gid=1501"));
117}
118
Sergei Datsenkoad2cb6a2018-05-15 17:34:26 +1000119// Verifies that CreateMounter writes files to the working dir when provided.
120TEST_F(SshfsHelperTest, CreateMounter_WriteFiles) {
121 EXPECT_CALL(platform_, WriteFile("/wkdir/id", StrEq("some key"), 8))
122 .WillOnce(Return(8));
123 EXPECT_CALL(platform_, WriteFile("/wkdir/known_hosts", StrEq("some host"), 9))
124 .WillOnce(Return(9));
125 EXPECT_CALL(platform_, SetPermissions("/wkdir/id", 0600))
Sergei Datsenkobcd8e462018-04-20 15:44:56 +1000126 .WillOnce(Return(true));
Sergei Datsenkoad2cb6a2018-05-15 17:34:26 +1000127 EXPECT_CALL(platform_, SetPermissions("/wkdir/known_hosts", 0600))
Sergei Datsenkobcd8e462018-04-20 15:44:56 +1000128 .WillOnce(Return(true));
129 EXPECT_CALL(platform_, SetPermissions("/wkdir", 0770)).WillOnce(Return(true));
Sergei Datsenkoad2cb6a2018-05-15 17:34:26 +1000130 EXPECT_CALL(platform_, SetOwnership("/wkdir/id", kMountUID, kMountGID))
Sergei Datsenkobcd8e462018-04-20 15:44:56 +1000131 .WillOnce(Return(true));
Sergei Datsenkoad2cb6a2018-05-15 17:34:26 +1000132 EXPECT_CALL(platform_,
133 SetOwnership("/wkdir/known_hosts", kMountUID, kMountGID))
Sergei Datsenkobcd8e462018-04-20 15:44:56 +1000134 .WillOnce(Return(true));
135 EXPECT_CALL(platform_, SetOwnership("/wkdir", kMountUID, getgid()))
136 .WillOnce(Return(true));
137 auto mounter = helper_.CreateMounter(
138 kWorkingDir, kSomeSource, kMountDir,
Sergei Datsenkoad2cb6a2018-05-15 17:34:26 +1000139 {"IdentityBase64=c29tZSBrZXk=", "UserKnownHostsBase64=c29tZSBob3N0",
140 "IdentityFile=/foo/bar", "UserKnownHostsFile=/foo/baz",
Sergei Datsenko1aa55362018-05-14 15:19:27 +1000141 "HostName=localhost", "Port=2222"});
Sergei Datsenkobcd8e462018-04-20 15:44:56 +1000142 string opts = mounter->mount_options().ToString();
Sergei Datsenkoad2cb6a2018-05-15 17:34:26 +1000143 EXPECT_THAT(opts, HasSubstr("IdentityFile=/wkdir/id"));
144 EXPECT_THAT(opts, HasSubstr("UserKnownHostsFile=/wkdir/known_hosts"));
Sergei Datsenko1aa55362018-05-14 15:19:27 +1000145 EXPECT_THAT(opts, HasSubstr("HostName=localhost"));
146 EXPECT_THAT(opts, HasSubstr("Port=2222"));
Sergei Datsenkoad2cb6a2018-05-15 17:34:26 +1000147 EXPECT_THAT(opts, Not(HasSubstr("Base64")));
148 EXPECT_THAT(opts, Not(HasSubstr("c29tZSB")));
Sergei Datsenkobcd8e462018-04-20 15:44:56 +1000149 EXPECT_THAT(opts, Not(HasSubstr("/foo/bar")));
150 EXPECT_THAT(opts, Not(HasSubstr("/foo/baz")));
151}
152
Sergei Datsenkobcd8e462018-04-20 15:44:56 +1000153// Verifies that CanMount correctly identifies handleable URIs.
154TEST_F(SshfsHelperTest, CanMount) {
155 EXPECT_TRUE(helper_.CanMount(Uri::Parse("sshfs://foo")));
156 EXPECT_FALSE(helper_.CanMount(Uri::Parse("sshfss://foo")));
157 EXPECT_FALSE(helper_.CanMount(Uri::Parse("ssh://foo")));
158 EXPECT_FALSE(helper_.CanMount(Uri::Parse("sshfs://")));
159}
160
161// Verifies that GetTargetSuffix escapes unwanted chars in URI.
162TEST_F(SshfsHelperTest, GetTargetSuffix) {
163 EXPECT_EQ("foo", helper_.GetTargetSuffix(Uri::Parse("sshfs://foo")));
164 EXPECT_EQ("usr@host_com:",
165 helper_.GetTargetSuffix(Uri::Parse("sshfs://usr@host.com:")));
166 EXPECT_EQ("host:$some$path$__",
167 helper_.GetTargetSuffix(Uri::Parse("sshfs://host:/some/path/..")));
168}
169
170} // namespace cros_disks