]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/libcephfs/access.cc
import ceph 14.2.5
[ceph.git] / ceph / src / test / libcephfs / access.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2011 New Dream Network
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15 #include "gtest/gtest.h"
16 #include "common/ceph_argparse.h"
17 #include "include/buffer.h"
18 #include "include/stringify.h"
19 #include "include/cephfs/libcephfs.h"
20 #include "include/rados/librados.h"
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <dirent.h>
27 #include <sys/uio.h>
28 #include <iostream>
29 #include <vector>
30 #include "json_spirit/json_spirit.h"
31
32 #ifdef __linux__
33 #include <limits.h>
34 #include <sys/xattr.h>
35 #endif
36
37
38 rados_t cluster;
39
40 string key;
41
42 int do_mon_command(string s, string *key)
43 {
44 char *outs, *outbuf;
45 size_t outs_len, outbuf_len;
46 const char *ss = s.c_str();
47 int r = rados_mon_command(cluster, (const char **)&ss, 1,
48 0, 0,
49 &outbuf, &outbuf_len,
50 &outs, &outs_len);
51 if (outbuf_len) {
52 string s(outbuf, outbuf_len);
53 std::cout << "out: " << s << std::endl;
54
55 // parse out the key
56 json_spirit::mValue v, k;
57 json_spirit::read_or_throw(s, v);
58 k = v.get_array()[0].get_obj().find("key")->second;
59 *key = k.get_str();
60 std::cout << "key: " << *key << std::endl;
61 free(outbuf);
62 } else {
63 return -EINVAL;
64 }
65 if (outs_len) {
66 string s(outs, outs_len);
67 std::cout << "outs: " << s << std::endl;
68 free(outs);
69 }
70 return r;
71 }
72
73 string get_unique_dir()
74 {
75 return string("/ceph_test_libcephfs_access.") + stringify(rand());
76 }
77
78 TEST(AccessTest, Foo) {
79 string dir = get_unique_dir();
80 string user = "libcephfs_foo_test." + stringify(rand());
81 // admin mount to set up test
82 struct ceph_mount_info *admin;
83 ASSERT_EQ(0, ceph_create(&admin, NULL));
84 ASSERT_EQ(0, ceph_conf_read_file(admin, NULL));
85 ASSERT_EQ(0, ceph_conf_parse_env(admin, NULL));
86 ASSERT_EQ(0, ceph_mount(admin, "/"));
87 ASSERT_EQ(0, ceph_mkdir(admin, dir.c_str(), 0755));
88
89 // create access key
90 string key;
91 ASSERT_EQ(0, do_mon_command(
92 "{\"prefix\": \"auth get-or-create\", \"entity\": \"client." + user + "\", "
93 "\"caps\": [\"mon\", \"allow *\", \"osd\", \"allow rw\", "
94 "\"mds\", \"allow rw\""
95 "], \"format\": \"json\"}", &key));
96
97 struct ceph_mount_info *cmount;
98 ASSERT_EQ(0, ceph_create(&cmount, user.c_str()));
99 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
100 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
101 ASSERT_EQ(0, ceph_conf_set(cmount, "key", key.c_str()));
102 ASSERT_EQ(0, ceph_mount(cmount, "/"));
103
104 ceph_shutdown(cmount);
105
106 // clean up
107 ASSERT_EQ(0, ceph_rmdir(admin, dir.c_str()));
108 ceph_shutdown(admin);
109 }
110
111 TEST(AccessTest, Path) {
112 string good = get_unique_dir();
113 string bad = get_unique_dir();
114 string user = "libcephfs_path_test." + stringify(rand());
115 struct ceph_mount_info *admin;
116 ASSERT_EQ(0, ceph_create(&admin, NULL));
117 ASSERT_EQ(0, ceph_conf_read_file(admin, NULL));
118 ASSERT_EQ(0, ceph_conf_parse_env(admin, NULL));
119 ASSERT_EQ(0, ceph_mount(admin, "/"));
120 ASSERT_EQ(0, ceph_mkdir(admin, good.c_str(), 0755));
121 ASSERT_EQ(0, ceph_mkdir(admin, string(good + "/p").c_str(), 0755));
122 ASSERT_EQ(0, ceph_mkdir(admin, bad.c_str(), 0755));
123 ASSERT_EQ(0, ceph_mkdir(admin, string(bad + "/p").c_str(), 0755));
124 int fd = ceph_open(admin, string(good + "/q").c_str(), O_CREAT|O_WRONLY, 0755);
125 ceph_close(admin, fd);
126 fd = ceph_open(admin, string(bad + "/q").c_str(), O_CREAT|O_WRONLY, 0755);
127 ceph_close(admin, fd);
128 fd = ceph_open(admin, string(bad + "/z").c_str(), O_CREAT|O_WRONLY, 0755);
129 ceph_write(admin, fd, "TEST FAILED", 11, 0);
130 ceph_close(admin, fd);
131
132 string key;
133 ASSERT_EQ(0, do_mon_command(
134 "{\"prefix\": \"auth get-or-create\", \"entity\": \"client." + user + "\", "
135 "\"caps\": [\"mon\", \"allow r\", \"osd\", \"allow rwx\", "
136 "\"mds\", \"allow r, allow rw path=" + good + "\""
137 "], \"format\": \"json\"}", &key));
138
139 struct ceph_mount_info *cmount;
140 ASSERT_EQ(0, ceph_create(&cmount, user.c_str()));
141 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
142 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
143 ASSERT_EQ(0, ceph_conf_set(cmount, "key", key.c_str()));
144 ASSERT_EQ(0, ceph_mount(cmount, "/"));
145
146 // allowed
147 ASSERT_GE(ceph_mkdir(cmount, string(good + "/x").c_str(), 0755), 0);
148 ASSERT_GE(ceph_rmdir(cmount, string(good + "/p").c_str()), 0);
149 ASSERT_GE(ceph_unlink(cmount, string(good + "/q").c_str()), 0);
150 fd = ceph_open(cmount, string(good + "/y").c_str(), O_CREAT|O_WRONLY, 0755);
151 ASSERT_GE(fd, 0);
152 ceph_write(cmount, fd, "bar", 3, 0);
153 ceph_close(cmount, fd);
154 ASSERT_GE(ceph_unlink(cmount, string(good + "/y").c_str()), 0);
155 ASSERT_GE(ceph_rmdir(cmount, string(good + "/x").c_str()), 0);
156
157 fd = ceph_open(cmount, string(bad + "/z").c_str(), O_RDONLY, 0644);
158 ASSERT_GE(fd, 0);
159 ceph_close(cmount, fd);
160
161 // not allowed
162 ASSERT_LT(ceph_mkdir(cmount, string(bad + "/x").c_str(), 0755), 0);
163 ASSERT_LT(ceph_rmdir(cmount, string(bad + "/p").c_str()), 0);
164 ASSERT_LT(ceph_unlink(cmount, string(bad + "/q").c_str()), 0);
165 fd = ceph_open(cmount, string(bad + "/y").c_str(), O_CREAT|O_WRONLY, 0755);
166 ASSERT_LT(fd, 0);
167
168 // unlink open file
169 fd = ceph_open(cmount, string(good + "/unlinkme").c_str(), O_CREAT|O_WRONLY, 0755);
170 ceph_unlink(cmount, string(good + "/unlinkme").c_str());
171 ASSERT_GE(ceph_write(cmount, fd, "foo", 3, 0), 0);
172 ASSERT_GE(ceph_fchmod(cmount, fd, 0777), 0);
173 ASSERT_GE(ceph_ftruncate(cmount, fd, 0), 0);
174 ASSERT_GE(ceph_fsetxattr(cmount, fd, "user.any", "bar", 3, 0), 0);
175 ceph_close(cmount, fd);
176
177 // rename open file
178 fd = ceph_open(cmount, string(good + "/renameme").c_str(), O_CREAT|O_WRONLY, 0755);
179 ASSERT_EQ(ceph_rename(admin, string(good + "/renameme").c_str(),
180 string(bad + "/asdf").c_str()), 0);
181 ASSERT_GE(ceph_write(cmount, fd, "foo", 3, 0), 0);
182 ASSERT_GE(ceph_fchmod(cmount, fd, 0777), -EACCES);
183 ASSERT_GE(ceph_ftruncate(cmount, fd, 0), -EACCES);
184 ASSERT_GE(ceph_fsetxattr(cmount, fd, "user.any", "bar", 3, 0), -EACCES);
185 ceph_close(cmount, fd);
186
187 ceph_shutdown(cmount);
188 ASSERT_EQ(0, ceph_unlink(admin, string(bad + "/q").c_str()));
189 ASSERT_EQ(0, ceph_unlink(admin, string(bad + "/z").c_str()));
190 ASSERT_EQ(0, ceph_rmdir(admin, string(bad + "/p").c_str()));
191 ASSERT_EQ(0, ceph_unlink(admin, string(bad + "/asdf").c_str()));
192 ASSERT_EQ(0, ceph_rmdir(admin, good.c_str()));
193 ASSERT_EQ(0, ceph_rmdir(admin, bad.c_str()));
194 ceph_shutdown(admin);
195 }
196
197 TEST(AccessTest, ReadOnly) {
198 string dir = get_unique_dir();
199 string dir2 = get_unique_dir();
200 string user = "libcephfs_readonly_test." + stringify(rand());
201 struct ceph_mount_info *admin;
202 ASSERT_EQ(0, ceph_create(&admin, NULL));
203 ASSERT_EQ(0, ceph_conf_read_file(admin, NULL));
204 ASSERT_EQ(0, ceph_conf_parse_env(admin, NULL));
205 ASSERT_EQ(0, ceph_mount(admin, "/"));
206 ASSERT_EQ(0, ceph_mkdir(admin, dir.c_str(), 0755));
207 int fd = ceph_open(admin, string(dir + "/out").c_str(), O_CREAT|O_WRONLY, 0755);
208 ceph_write(admin, fd, "foo", 3, 0);
209 ceph_close(admin,fd);
210
211 string key;
212 ASSERT_EQ(0, do_mon_command(
213 "{\"prefix\": \"auth get-or-create\", \"entity\": \"client." + user + "\", "
214 "\"caps\": [\"mon\", \"allow r\", \"osd\", \"allow rw\", "
215 "\"mds\", \"allow r\""
216 "], \"format\": \"json\"}", &key));
217
218 struct ceph_mount_info *cmount;
219 ASSERT_EQ(0, ceph_create(&cmount, user.c_str()));
220 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
221 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
222 ASSERT_EQ(0, ceph_conf_set(cmount, "key", key.c_str()));
223 ASSERT_EQ(0, ceph_mount(cmount, "/"));
224
225 // allowed
226 fd = ceph_open(cmount, string(dir + "/out").c_str(), O_RDONLY, 0644);
227 ASSERT_GE(fd, 0);
228 ceph_close(cmount,fd);
229
230 // not allowed
231 fd = ceph_open(cmount, string(dir + "/bar").c_str(), O_CREAT|O_WRONLY, 0755);
232 ASSERT_LT(fd, 0);
233 ASSERT_LT(ceph_mkdir(cmount, dir2.c_str(), 0755), 0);
234
235 ceph_shutdown(cmount);
236 ASSERT_EQ(0, ceph_unlink(admin, string(dir + "/out").c_str()));
237 ASSERT_EQ(0, ceph_rmdir(admin, dir.c_str()));
238 ceph_shutdown(admin);
239 }
240
241 TEST(AccessTest, User) {
242 string dir = get_unique_dir();
243 string user = "libcephfs_user_test." + stringify(rand());
244
245 // admin mount to set up test
246 struct ceph_mount_info *admin;
247 ASSERT_EQ(0, ceph_create(&admin, NULL));
248 ASSERT_EQ(0, ceph_conf_read_file(admin, NULL));
249 ASSERT_EQ(0, ceph_conf_parse_env(admin, NULL));
250 ASSERT_EQ(0, ceph_conf_set(admin, "client_permissions", "0"));
251 ASSERT_EQ(0, ceph_mount(admin, "/"));
252 ASSERT_EQ(0, ceph_mkdir(admin, dir.c_str(), 0755));
253
254 // create access key
255 string key;
256 ASSERT_EQ(0, do_mon_command(
257 "{\"prefix\": \"auth get-or-create\", \"entity\": \"client." + user + "\", "
258 "\"caps\": [\"mon\", \"allow *\", \"osd\", \"allow rw\", "
259 "\"mds\", \"allow rw uid=123 gids=456,789\""
260 "], \"format\": \"json\"}", &key));
261
262 struct ceph_mount_info *cmount;
263 ASSERT_EQ(0, ceph_create(&cmount, user.c_str()));
264 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
265 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
266 ASSERT_EQ(0, ceph_conf_set(cmount, "key", key.c_str()));
267 ASSERT_EQ(-EACCES, ceph_mount(cmount, "/"));
268 ASSERT_EQ(0, ceph_init(cmount));
269
270 UserPerm *perms = ceph_userperm_new(123, 456, 0, NULL);
271 ASSERT_NE(nullptr, perms);
272 ASSERT_EQ(0, ceph_mount_perms_set(cmount, perms));
273 ceph_userperm_destroy(perms);
274
275 ASSERT_EQ(0, ceph_conf_set(cmount, "client_permissions", "0"));
276 ASSERT_EQ(0, ceph_mount(cmount, "/"));
277
278 // user bits
279 ASSERT_EQ(0, ceph_chmod(admin, dir.c_str(), 0700));
280 ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 123, 456));
281 ASSERT_EQ(0, ceph_mkdir(cmount, string(dir + "/u1").c_str(), 0755));
282 ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 1, 456));
283 ASSERT_EQ(-EACCES, ceph_mkdir(cmount, string(dir + "/no").c_str(), 0755));
284
285 // group bits
286 ASSERT_EQ(0, ceph_chmod(admin, dir.c_str(), 0770));
287 ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 1, 456));
288 ASSERT_EQ(0, ceph_mkdir(cmount, string(dir + "/u2").c_str(), 0755));
289 ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 1, 2));
290 ASSERT_EQ(-EACCES, ceph_mkdir(cmount, string(dir + "/no").c_str(), 0755));
291
292 // user overrides group
293 ASSERT_EQ(0, ceph_chmod(admin, dir.c_str(), 0470));
294 ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 123, 456));
295 ASSERT_EQ(-EACCES, ceph_mkdir(cmount, string(dir + "/no").c_str(), 0755));
296
297 // other
298 ASSERT_EQ(0, ceph_chmod(admin, dir.c_str(), 0777));
299 ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 1, 1));
300 ASSERT_EQ(0, ceph_mkdir(cmount, string(dir + "/u3").c_str(), 0755));
301 ASSERT_EQ(0, ceph_chmod(admin, dir.c_str(), 0770));
302 ASSERT_EQ(-EACCES, ceph_mkdir(cmount, string(dir + "/no").c_str(), 0755));
303
304 // user and group overrides other
305 ASSERT_EQ(0, ceph_chmod(admin, dir.c_str(), 07));
306 ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 1, 456));
307 ASSERT_EQ(-EACCES, ceph_mkdir(cmount, string(dir + "/no").c_str(), 0755));
308 ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 123, 1));
309 ASSERT_EQ(-EACCES, ceph_mkdir(cmount, string(dir + "/no").c_str(), 0755));
310 ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 123, 456));
311 ASSERT_EQ(-EACCES, ceph_mkdir(cmount, string(dir + "/no").c_str(), 0755));
312
313 // chown and chgrp
314 ASSERT_EQ(0, ceph_chmod(admin, dir.c_str(), 0700));
315 ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 123, 456));
316 // FIXME: Re-enable these 789 tests once we can set multiple GIDs via libcephfs/config
317 // ASSERT_EQ(0, ceph_chown(cmount, dir.c_str(), 123, 789));
318 ASSERT_EQ(0, ceph_chown(cmount, dir.c_str(), 123, 456));
319 // ASSERT_EQ(0, ceph_chown(cmount, dir.c_str(), -1, 789));
320 ASSERT_EQ(0, ceph_chown(cmount, dir.c_str(), -1, 456));
321 ASSERT_EQ(-EACCES, ceph_chown(cmount, dir.c_str(), 123, 1));
322 ASSERT_EQ(-EACCES, ceph_chown(cmount, dir.c_str(), 1, 456));
323
324 ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 1, 1));
325 ASSERT_EQ(-EACCES, ceph_chown(cmount, dir.c_str(), 123, 456));
326 ASSERT_EQ(-EACCES, ceph_chown(cmount, dir.c_str(), 123, -1));
327 ASSERT_EQ(-EACCES, ceph_chown(cmount, dir.c_str(), -1, 456));
328
329 ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 1, 456));
330 ASSERT_EQ(-EACCES, ceph_chown(cmount, dir.c_str(), 123, 456));
331 ASSERT_EQ(-EACCES, ceph_chown(cmount, dir.c_str(), 123, -1));
332 ASSERT_EQ(-EACCES, ceph_chown(cmount, dir.c_str(), -1, 456));
333
334 ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 123, 1));
335 ASSERT_EQ(0, ceph_chown(cmount, dir.c_str(), -1, 456));
336 // ASSERT_EQ(0, ceph_chown(cmount, dir.c_str(), 123, 789));
337
338 ceph_shutdown(cmount);
339
340 // clean up
341 ASSERT_EQ(0, ceph_rmdir(admin, string(dir + "/u1").c_str()));
342 ASSERT_EQ(0, ceph_rmdir(admin, string(dir + "/u2").c_str()));
343 ASSERT_EQ(0, ceph_rmdir(admin, string(dir + "/u3").c_str()));
344 ASSERT_EQ(0, ceph_rmdir(admin, dir.c_str()));
345 ceph_shutdown(admin);
346 }
347
348 static int update_root_mode()
349 {
350 struct ceph_mount_info *admin;
351 int r = ceph_create(&admin, NULL);
352 if (r < 0)
353 return r;
354 ceph_conf_read_file(admin, NULL);
355 ceph_conf_parse_env(admin, NULL);
356 ceph_conf_set(admin, "client_permissions", "false");
357 r = ceph_mount(admin, "/");
358 if (r < 0)
359 goto out;
360 r = ceph_chmod(admin, "/", 0777);
361 out:
362 ceph_shutdown(admin);
363 return r;
364 }
365
366
367 int main(int argc, char **argv)
368 {
369 int r = update_root_mode();
370 if (r < 0)
371 exit(1);
372
373 ::testing::InitGoogleTest(&argc, argv);
374
375 srand(getpid());
376
377 r = rados_create(&cluster, NULL);
378 if (r < 0)
379 exit(1);
380
381 r = rados_conf_read_file(cluster, NULL);
382 if (r < 0)
383 exit(1);
384
385 rados_conf_parse_env(cluster, NULL);
386 r = rados_connect(cluster);
387 if (r < 0)
388 exit(1);
389
390 r = RUN_ALL_TESTS();
391
392 rados_shutdown(cluster);
393
394 return r;
395 }