1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <unistd.h>
18 
19 #include <gtest/gtest.h>
20 
21 #include <android-base/file.h>
22 
23 #if defined(__BIONIC__)
24 #include "../libc/bionic/grp_pwd_file.cpp"
25 
26 template <typename T>
27 class FileUnmapper {
28  public:
FileUnmapper(T & file)29   explicit FileUnmapper(T& file) : file_(file) {
30   }
~FileUnmapper()31   ~FileUnmapper() {
32     file_.Unmap();
33   }
34 
35  private:
36   T& file_;
37 };
38 
FindAndCheckPasswdEntry(PasswdFile * file,const char * name,uid_t uid,gid_t gid,const char * dir,const char * shell)39 void FindAndCheckPasswdEntry(PasswdFile* file, const char* name, uid_t uid, gid_t gid,
40                              const char* dir, const char* shell) {
41   passwd_state_t name_passwd_state;
42   ASSERT_TRUE(file->FindByName(name, &name_passwd_state)) << name;
43 
44   passwd& name_passwd = name_passwd_state.passwd_;
45   EXPECT_STREQ(name, name_passwd.pw_name);
46   EXPECT_EQ(nullptr, name_passwd.pw_passwd);
47   EXPECT_EQ(uid, name_passwd.pw_uid);
48   EXPECT_EQ(gid, name_passwd.pw_gid);
49   EXPECT_EQ(nullptr, name_passwd.pw_gecos);
50   EXPECT_STREQ(dir, name_passwd.pw_dir);
51   EXPECT_STREQ(shell, name_passwd.pw_shell);
52 
53   passwd_state_t id_passwd_state;
54   ASSERT_TRUE(file->FindById(uid, &id_passwd_state)) << uid;
55 
56   passwd& id_passwd = id_passwd_state.passwd_;
57   EXPECT_STREQ(name, id_passwd.pw_name);
58   EXPECT_EQ(nullptr, id_passwd.pw_passwd);
59   EXPECT_EQ(uid, id_passwd.pw_uid);
60   EXPECT_EQ(gid, id_passwd.pw_gid);
61   EXPECT_EQ(nullptr, id_passwd.pw_gecos);
62   EXPECT_STREQ(dir, id_passwd.pw_dir);
63   EXPECT_STREQ(shell, id_passwd.pw_shell);
64 }
65 
FindAndCheckGroupEntry(GroupFile * file,const char * name,gid_t gid)66 void FindAndCheckGroupEntry(GroupFile* file, const char* name, gid_t gid) {
67   group_state_t name_group_state;
68   ASSERT_TRUE(file->FindByName(name, &name_group_state)) << name;
69 
70   group& name_group = name_group_state.group_;
71   EXPECT_STREQ(name, name_group.gr_name);
72   EXPECT_EQ(nullptr, name_group.gr_passwd);
73   EXPECT_EQ(gid, name_group.gr_gid);
74   EXPECT_EQ(name_group.gr_name, name_group.gr_mem[0]);
75   EXPECT_EQ(nullptr, name_group.gr_mem[1]);
76 
77   group_state_t id_group_state;
78   ASSERT_TRUE(file->FindById(gid, &id_group_state)) << gid;
79 
80   group& id_group = id_group_state.group_;
81   EXPECT_STREQ(name, id_group.gr_name);
82   EXPECT_EQ(nullptr, id_group.gr_passwd);
83   EXPECT_EQ(gid, id_group.gr_gid);
84   EXPECT_EQ(id_group.gr_name, id_group.gr_mem[0]);
85   EXPECT_EQ(nullptr, id_group.gr_mem[1]);
86 }
87 
88 #endif  // __BIONIC__
89 
TEST(grp_pwd_file,passwd_file_one_entry)90 TEST(grp_pwd_file, passwd_file_one_entry) {
91 #if defined(__BIONIC__)
92   TemporaryFile file;
93   ASSERT_NE(-1, file.fd);
94   static const char test_string[] = "name:password:1:2:user_info:dir:shell\n";
95   write(file.fd, test_string, sizeof(test_string) - 1);
96 
97   PasswdFile passwd_file(file.path, nullptr);
98   FileUnmapper unmapper(passwd_file);
99 
100   FindAndCheckPasswdEntry(&passwd_file, "name", 1, 2, "dir", "shell");
101 
102   EXPECT_FALSE(passwd_file.FindByName("not_name", nullptr));
103   EXPECT_FALSE(passwd_file.FindById(3, nullptr));
104 
105 #else   // __BIONIC__
106   GTEST_SKIP() << "bionic-only test";
107 #endif  // __BIONIC__
108 }
109 
TEST(grp_pwd_file,group_file_one_entry)110 TEST(grp_pwd_file, group_file_one_entry) {
111 #if defined(__BIONIC__)
112   TemporaryFile file;
113   ASSERT_NE(-1, file.fd);
114   static const char test_string[] = "name:password:1:one,two,three\n";
115   write(file.fd, test_string, sizeof(test_string) - 1);
116 
117   GroupFile group_file(file.path, nullptr);
118   FileUnmapper unmapper(group_file);
119 
120   FindAndCheckGroupEntry(&group_file, "name", 1);
121 
122   EXPECT_FALSE(group_file.FindByName("not_name", nullptr));
123   EXPECT_FALSE(group_file.FindById(3, nullptr));
124 
125 #else   // __BIONIC__
126   GTEST_SKIP() << "bionic-only test";
127 #endif  // __BIONIC__
128 }
129 
TEST(grp_pwd_file,passwd_file_many_entries)130 TEST(grp_pwd_file, passwd_file_many_entries) {
131 #if defined(__BIONIC__)
132   TemporaryFile file;
133   ASSERT_NE(-1, file.fd);
134   static const char test_string[] =
135       "first:x:1:2::dir:shell\n"
136       "abc1::3:4::def:abc\n"
137       "abc2::5:4:abc::abc\n"
138       "abc3::7:4:abc:def:\n"
139       "abc4::9:4:::abc\n"
140       "abc5::11:4:abc:def:abc\n"
141       "middle-ish::13:4::/:/system/bin/sh\n"
142       "abc7::15:4:abc::\n"
143       "abc8::17:4:::\n"
144       "abc9::19:4:abc:def:abc\n"
145       "abc10::21:4:abc:def:abc\n"
146       "abc11::23:4:abc:def:abc\n"
147       "abc12::25:4:abc:def:abc\n"
148       "abc13::27:4:abc:def:abc\n"
149       "last::29:4::last_user_dir:last_user_shell\n";
150 
151   write(file.fd, test_string, sizeof(test_string) - 1);
152 
153   PasswdFile passwd_file(file.path, nullptr);
154   FileUnmapper unmapper(passwd_file);
155 
156   FindAndCheckPasswdEntry(&passwd_file, "first", 1, 2, "dir", "shell");
157   FindAndCheckPasswdEntry(&passwd_file, "middle-ish", 13, 4, "/", "/system/bin/sh");
158   FindAndCheckPasswdEntry(&passwd_file, "last", 29, 4, "last_user_dir", "last_user_shell");
159 
160   EXPECT_FALSE(passwd_file.FindByName("not_name", nullptr));
161   EXPECT_FALSE(passwd_file.FindById(50, nullptr));
162 
163 #else   // __BIONIC__
164   GTEST_SKIP() << "bionic-only test";
165 #endif  // __BIONIC__
166 }
167 
TEST(grp_pwd_file,group_file_many_entries)168 TEST(grp_pwd_file, group_file_many_entries) {
169 #if defined(__BIONIC__)
170   TemporaryFile file;
171   ASSERT_NE(-1, file.fd);
172   static const char test_string[] =
173       "first:password:1:one,two,three\n"
174       "abc:def:2:group1,group2,group3\n"
175       "abc:def:3:\n"
176       "abc:def:4:\n"
177       "abc:def:5:\n"
178       "middle-ish:def_a_password_that_is_over_32_characters_long:6:\n"
179       "abc:def:7:\n"
180       "abc:def:8:\n"
181       "abc:def:20:\n"
182       "abc:def:25:\n"
183       "abc:def:27:\n"
184       "abc:def:52:\n"
185       "last::800:\n";
186 
187   write(file.fd, test_string, sizeof(test_string) - 1);
188 
189   GroupFile group_file(file.path, nullptr);
190   FileUnmapper unmapper(group_file);
191 
192   FindAndCheckGroupEntry(&group_file, "first", 1);
193   FindAndCheckGroupEntry(&group_file, "middle-ish", 6);
194   FindAndCheckGroupEntry(&group_file, "last", 800);
195 
196   EXPECT_FALSE(group_file.FindByName("not_name", nullptr));
197   EXPECT_FALSE(group_file.FindById(799, nullptr));
198 
199 #else   // __BIONIC__
200   GTEST_SKIP() << "bionic-only test";
201 #endif  // __BIONIC__
202 }
203 
TEST(grp_pwd_file,passwd_file_required_prefix)204 TEST(grp_pwd_file, passwd_file_required_prefix) {
205 #if defined(__BIONIC__)
206   TemporaryFile file;
207   ASSERT_NE(-1, file.fd);
208   static const char test_string[] =
209       "name:password:1:2:user_info:dir:shell\n"
210       "vendor_name:password:3:4:user_info:dir:shell\n";
211   write(file.fd, test_string, sizeof(test_string) - 1);
212 
213   PasswdFile passwd_file(file.path, "vendor_");
214   FileUnmapper unmapper(passwd_file);
215 
216   EXPECT_FALSE(passwd_file.FindByName("name", nullptr));
217   EXPECT_FALSE(passwd_file.FindById(1, nullptr));
218 
219   FindAndCheckPasswdEntry(&passwd_file, "vendor_name", 3, 4, "dir", "shell");
220 
221 #else   // __BIONIC__
222   GTEST_SKIP() << "bionic-only test";
223 #endif  // __BIONIC__
224 }
225 
TEST(grp_pwd_file,group_file_required_prefix)226 TEST(grp_pwd_file, group_file_required_prefix) {
227 #if defined(__BIONIC__)
228   TemporaryFile file;
229   ASSERT_NE(-1, file.fd);
230   static const char test_string[] =
231       "name:password:1:one,two,three\n"
232       "vendor_name:password:2:one,two,three\n";
233   write(file.fd, test_string, sizeof(test_string) - 1);
234 
235   GroupFile group_file(file.path, "vendor_");
236   FileUnmapper unmapper(group_file);
237 
238   EXPECT_FALSE(group_file.FindByName("name", nullptr));
239   EXPECT_FALSE(group_file.FindById(1, nullptr));
240 
241   FindAndCheckGroupEntry(&group_file, "vendor_name", 2);
242 
243 #else   // __BIONIC__
244   GTEST_SKIP() << "bionic-only test";
245 #endif  // __BIONIC__
246 }
247