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