]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/libcephfs/acl.cc
import ceph quincy 17.2.6
[ceph.git] / ceph / src / test / libcephfs / acl.cc
CommitLineData
7c673cae
FG
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#include "include/types.h"
15#include "gtest/gtest.h"
16#include "include/cephfs/libcephfs.h"
17#include "include/ceph_fs.h"
18#include "client/posix_acl.h"
19#include <errno.h>
20#include <fcntl.h>
21#include <unistd.h>
22#include <sys/types.h>
23#include <sys/stat.h>
eafe8130 24#ifdef __linux__
7c673cae 25#include <sys/xattr.h>
eafe8130 26#endif
7c673cae
FG
27
28static size_t acl_ea_size(int count)
29{
30 return sizeof(acl_ea_header) + count * sizeof(acl_ea_entry);
31}
32
33static int acl_ea_count(size_t size)
34{
35 if (size < sizeof(acl_ea_header))
36 return -1;
37 size -= sizeof(acl_ea_header);
38 if (size % sizeof(acl_ea_entry))
39 return -1;
40 return size / sizeof(acl_ea_entry);
41}
42
43static int check_acl_and_mode(const void *buf, size_t size, mode_t mode)
44{
45 const acl_ea_entry *group_entry = NULL, *mask_entry = NULL;
46 const acl_ea_header *header = reinterpret_cast<const acl_ea_header*>(buf);
47 const acl_ea_entry *entry = header->a_entries;
48 int count = (size - sizeof(*header)) / sizeof(*entry);
49 for (int i = 0; i < count; ++i) {
50 __u16 tag = entry->e_tag;
51 __u16 perm = entry->e_perm;
52 switch(tag) {
53 case ACL_USER_OBJ:
54 if (perm != ((mode >> 6) & 7))
55 return -EINVAL;
56 break;
57 case ACL_USER:
58 case ACL_GROUP:
59 break;
60 case ACL_GROUP_OBJ:
61 group_entry = entry;
62 break;
63 case ACL_OTHER:
64 if (perm != (mode & 7))
65 return -EINVAL;
66 break;
67 case ACL_MASK:
68 mask_entry = entry;
69 break;
70 default:
71 return -EIO;
72 }
73 ++entry;
74 }
75 if (mask_entry) {
76 __u16 perm = mask_entry->e_perm;
77 if (perm != ((mode >> 3) & 7))
78 return -EINVAL;
79 } else {
80 if (!group_entry)
81 return -EIO;
82 __u16 perm = group_entry->e_perm;
83 if (perm != ((mode >> 3) & 7))
84 return -EINVAL;
85 }
86 return 0;
87}
88
89static int generate_test_acl(void *buf, size_t size, mode_t mode)
90{
91 if (acl_ea_count(size) != 5)
92 return -1;
93 acl_ea_header *header = reinterpret_cast<acl_ea_header*>(buf);
94 header->a_version = (__u32)ACL_EA_VERSION;
95 acl_ea_entry *entry = header->a_entries;
96 entry->e_tag = ACL_USER_OBJ;
97 entry->e_perm = (mode >> 6) & 7;
98 ++entry;
99 entry->e_tag = ACL_USER;
100 entry->e_perm = 7;
101 entry->e_id = getuid();
102 ++entry;
103 entry->e_tag = ACL_GROUP_OBJ;
104 entry->e_perm = (mode >> 3) & 7;
105 ++entry;
106 entry->e_tag = ACL_MASK;
107 entry->e_perm = 7;
108 ++entry;
109 entry->e_tag = ACL_OTHER;
110 entry->e_perm = mode & 7;
111 return 0;
112}
113
114static int generate_empty_acl(void *buf, size_t size, mode_t mode)
115{
116
117 if (acl_ea_count(size) != 3)
118 return -1;
119 acl_ea_header *header = reinterpret_cast<acl_ea_header*>(buf);
120 header->a_version = (__u32)ACL_EA_VERSION;
121 acl_ea_entry *entry = header->a_entries;
122 entry->e_tag = ACL_USER_OBJ;
123 entry->e_perm = (mode >> 6) & 7;
124 ++entry;
125 entry->e_tag = ACL_GROUP_OBJ;
126 entry->e_perm = (mode >> 3) & 7;
127 ++entry;
128 entry->e_tag = ACL_OTHER;
129 entry->e_perm = mode & 7;
130 return 0;
131}
132
133TEST(ACL, SetACL) {
134 struct ceph_mount_info *cmount;
135 ASSERT_EQ(0, ceph_create(&cmount, NULL));
136 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
137 ASSERT_EQ(0, ceph_mount(cmount, "/"));
138 ASSERT_EQ(0, ceph_conf_set(cmount, "client_acl_type", "posix_acl"));
139 ASSERT_EQ(0, ceph_conf_set(cmount, "client_permissions", "0"));
140
141 char test_file[256];
142 sprintf(test_file, "file1_setacl_%d", getpid());
143
144 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0600);
145 ASSERT_GT(fd, 0);
146 // change ownership to nobody -- we assume nobody exists and id is always 65534
147 ASSERT_EQ(ceph_fchown(cmount, fd, 65534, 65534), 0);
148
149 ASSERT_EQ(0, ceph_conf_set(cmount, "client_permissions", "1"));
150 ASSERT_EQ(ceph_open(cmount, test_file, O_RDWR, 0), -EACCES);
151 ASSERT_EQ(0, ceph_conf_set(cmount, "client_permissions", "0"));
152
153 size_t acl_buf_size = acl_ea_size(5);
154 void *acl_buf = malloc(acl_buf_size);
155 ASSERT_EQ(generate_test_acl(acl_buf, acl_buf_size, 0750), 0);
156
157 // can't set default acl for non-directory
158 ASSERT_EQ(ceph_fsetxattr(cmount, fd, ACL_EA_DEFAULT, acl_buf, acl_buf_size, 0), -EACCES);
159 ASSERT_EQ(ceph_fsetxattr(cmount, fd, ACL_EA_ACCESS, acl_buf, acl_buf_size, 0), 0);
160
161 int tmpfd = ceph_open(cmount, test_file, O_RDWR, 0);
162 ASSERT_GT(tmpfd, 0);
163 ceph_close(cmount, tmpfd);
164
165 struct ceph_statx stx;
166 ASSERT_EQ(ceph_fstatx(cmount, fd, &stx, CEPH_STATX_MODE, 0), 0);
167 // mode was modified according to ACL
168 ASSERT_EQ(stx.stx_mode & 0777u, 0770u);
169 ASSERT_EQ(check_acl_and_mode(acl_buf, acl_buf_size, stx.stx_mode), 0);
170
171 acl_buf_size = acl_ea_size(3);
172 // setting ACL that is equivalent to file mode
173 ASSERT_EQ(generate_empty_acl(acl_buf, acl_buf_size, 0600), 0);
174 ASSERT_EQ(ceph_fsetxattr(cmount, fd, ACL_EA_ACCESS, acl_buf, acl_buf_size, 0), 0);
175 // ACL was deleted
176 ASSERT_EQ(ceph_fgetxattr(cmount, fd, ACL_EA_ACCESS, NULL, 0), -ENODATA);
177
178 ASSERT_EQ(ceph_fstatx(cmount, fd, &stx, CEPH_STATX_MODE, 0), 0);
179 // mode was modified according to ACL
180 ASSERT_EQ(stx.stx_mode & 0777u, 0600u);
181
182 free(acl_buf);
183 ceph_close(cmount, fd);
184 ceph_shutdown(cmount);
185}
186
187TEST(ACL, Chmod) {
188 struct ceph_mount_info *cmount;
189 ASSERT_EQ(0, ceph_create(&cmount, NULL));
190 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
191 ASSERT_EQ(0, ceph_mount(cmount, "/"));
192 ASSERT_EQ(0, ceph_conf_set(cmount, "client_acl_type", "posix_acl"));
193
194 char test_file[256];
195 sprintf(test_file, "file1_acl_chmod_%d", getpid());
196
197 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0600);
198 ASSERT_GT(fd, 0);
199
200 int acl_buf_size = acl_ea_size(5);
201 void *acl_buf = malloc(acl_buf_size);
202 ASSERT_EQ(generate_test_acl(acl_buf, acl_buf_size, 0775), 0);
203 ASSERT_EQ(ceph_fsetxattr(cmount, fd, ACL_EA_ACCESS, acl_buf, acl_buf_size, 0), 0);
204
205 struct ceph_statx stx;
206 ASSERT_EQ(ceph_fstatx(cmount, fd, &stx, CEPH_STATX_MODE, 0), 0);
207 // mode was updated according to ACL
208 ASSERT_EQ(stx.stx_mode & 0777u, 0775u);
209
210 // change mode
211 ASSERT_EQ(ceph_fchmod(cmount, fd, 0640), 0);
212
213 ASSERT_EQ(ceph_fstatx(cmount, fd, &stx, CEPH_STATX_MODE, 0), 0);
214 ASSERT_EQ(stx.stx_mode & 0777u, 0640u);
215
216 // ACL was updated according to mode
217 ASSERT_EQ(ceph_fgetxattr(cmount, fd, ACL_EA_ACCESS, acl_buf, acl_buf_size), acl_buf_size);
218 ASSERT_EQ(check_acl_and_mode(acl_buf, acl_buf_size, stx.stx_mode), 0);
219
220 free(acl_buf);
221 ceph_close(cmount, fd);
222 ceph_shutdown(cmount);
223}
224
225TEST(ACL, DefaultACL) {
226 struct ceph_mount_info *cmount;
227 ASSERT_EQ(0, ceph_create(&cmount, NULL));
228 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
229 ASSERT_EQ(0, ceph_mount(cmount, "/"));
230 ASSERT_EQ(0, ceph_conf_set(cmount, "client_acl_type", "posix_acl"));
231
232 int acl_buf_size = acl_ea_size(5);
233 void *acl1_buf = malloc(acl_buf_size);
234 void *acl2_buf = malloc(acl_buf_size);
235
236 ASSERT_EQ(generate_test_acl(acl1_buf, acl_buf_size, 0750), 0);
237
238 char test_dir1[256];
239 sprintf(test_dir1, "dir1_acl_default_%d", getpid());
240 ASSERT_EQ(ceph_mkdir(cmount, test_dir1, 0750), 0);
241
242 // set default acl
243 ASSERT_EQ(ceph_setxattr(cmount, test_dir1, ACL_EA_DEFAULT, acl1_buf, acl_buf_size, 0), 0);
244
11fdf7f2 245 char test_dir2[262];
7c673cae
FG
246 sprintf(test_dir2, "%s/dir2", test_dir1);
247 ASSERT_EQ(ceph_mkdir(cmount, test_dir2, 0755), 0);
248
249 // inherit default acl
250 ASSERT_EQ(ceph_getxattr(cmount, test_dir2, ACL_EA_DEFAULT, acl2_buf, acl_buf_size), acl_buf_size);
251 ASSERT_EQ(memcmp(acl1_buf, acl2_buf, acl_buf_size), 0);
252
253 // mode and ACL are updated
254 ASSERT_EQ(ceph_getxattr(cmount, test_dir2, ACL_EA_ACCESS, acl2_buf, acl_buf_size), acl_buf_size);
255 {
256 struct ceph_statx stx;
257 ASSERT_EQ(ceph_statx(cmount, test_dir2, &stx, CEPH_STATX_MODE, 0), 0);
258 // other bits of mode &= acl other perm
259 ASSERT_EQ(stx.stx_mode & 0777u, 0750u);
260 ASSERT_EQ(check_acl_and_mode(acl2_buf, acl_buf_size, stx.stx_mode), 0);
261 }
262
11fdf7f2 263 char test_file1[262];
7c673cae
FG
264 sprintf(test_file1, "%s/file1", test_dir1);
265 int fd = ceph_open(cmount, test_file1, O_CREAT|O_RDWR, 0666);
266 ASSERT_GT(fd, 0);
267
268 // no default acl
269 ASSERT_EQ(ceph_fgetxattr(cmount, fd, ACL_EA_DEFAULT, NULL, 0), -ENODATA);
270
271 // mode and ACL are updated
272 ASSERT_EQ(ceph_fgetxattr(cmount, fd, ACL_EA_ACCESS, acl2_buf, acl_buf_size), acl_buf_size);
273 {
274 struct ceph_statx stx;
275 ASSERT_EQ(ceph_statx(cmount, test_file1, &stx, CEPH_STATX_MODE, 0), 0);
276 // other bits of mode &= acl other perm
277 ASSERT_EQ(stx.stx_mode & 0777u, 0660u);
278 ASSERT_EQ(check_acl_and_mode(acl2_buf, acl_buf_size, stx.stx_mode), 0);
279 }
280
281 free(acl1_buf);
282 free(acl2_buf);
39ae355f
TL
283 ASSERT_EQ(ceph_unlink(cmount, test_file1), 0);
284 ASSERT_EQ(ceph_rmdir(cmount, test_dir2), 0);
285 ASSERT_EQ(ceph_rmdir(cmount, test_dir1), 0);
7c673cae
FG
286 ceph_close(cmount, fd);
287 ceph_shutdown(cmount);
288}
289
290TEST(ACL, Disabled) {
291 struct ceph_mount_info *cmount;
292 ASSERT_EQ(0, ceph_create(&cmount, NULL));
293 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
294 ASSERT_EQ(0, ceph_mount(cmount, "/"));
295 ASSERT_EQ(0, ceph_conf_set(cmount, "client_acl_type", ""));
296
297 size_t acl_buf_size = acl_ea_size(3);
298 void *acl_buf = malloc(acl_buf_size);
299 ASSERT_EQ(generate_empty_acl(acl_buf, acl_buf_size, 0755), 0);
300
301 char test_dir[256];
302 sprintf(test_dir, "dir1_acl_disabled_%d", getpid());
303 ASSERT_EQ(ceph_mkdir(cmount, test_dir, 0750), 0);
304
305 ASSERT_EQ(ceph_setxattr(cmount, test_dir, ACL_EA_DEFAULT, acl_buf, acl_buf_size, 0), -EOPNOTSUPP);
306 ASSERT_EQ(ceph_setxattr(cmount, test_dir, ACL_EA_ACCESS, acl_buf, acl_buf_size, 0), -EOPNOTSUPP);
307 ASSERT_EQ(ceph_getxattr(cmount, test_dir, ACL_EA_DEFAULT, acl_buf, acl_buf_size), -EOPNOTSUPP);
308 ASSERT_EQ(ceph_getxattr(cmount, test_dir, ACL_EA_ACCESS, acl_buf, acl_buf_size), -EOPNOTSUPP);
309
310 free(acl_buf);
311 ceph_shutdown(cmount);
312}
39ae355f
TL
313
314TEST(ACL, SnapdirACL) {
315 struct ceph_mount_info *cmount;
316 ASSERT_EQ(0, ceph_create(&cmount, NULL));
317 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
318 ASSERT_EQ(0, ceph_mount(cmount, "/"));
319 ASSERT_EQ(0, ceph_conf_set(cmount, "client_acl_type", "posix_acl"));
320
321 int acl_buf_size = acl_ea_size(5);
322 void *acl1_buf = malloc(acl_buf_size);
323 void *acl2_buf = malloc(acl_buf_size);
324 void *acl3_buf = malloc(acl_buf_size);
325
326 ASSERT_EQ(generate_test_acl(acl1_buf, acl_buf_size, 0750), 0);
327
328 char test_dir1[256];
329 sprintf(test_dir1, "dir1_acl_default_%d", getpid());
330 ASSERT_EQ(ceph_mkdir(cmount, test_dir1, 0750), 0);
331
332 // set default acl
333 ASSERT_EQ(ceph_setxattr(cmount, test_dir1, ACL_EA_DEFAULT, acl1_buf, acl_buf_size, 0), 0);
334
335 char test_dir2[262];
336 sprintf(test_dir2, "%s/dir2", test_dir1);
337 ASSERT_EQ(ceph_mkdir(cmount, test_dir2, 0755), 0);
338
339 // inherit default acl
340 ASSERT_EQ(ceph_getxattr(cmount, test_dir2, ACL_EA_DEFAULT, acl2_buf, acl_buf_size), acl_buf_size);
341 ASSERT_EQ(memcmp(acl1_buf, acl2_buf, acl_buf_size), 0);
342
343 char test_dir2_snapdir[512];
344 sprintf(test_dir2_snapdir, "%s/dir2/.snap", test_dir1);
345
346 // inherit default acl
347 ASSERT_EQ(ceph_getxattr(cmount, test_dir2_snapdir, ACL_EA_DEFAULT, acl3_buf, acl_buf_size), acl_buf_size);
348 ASSERT_EQ(memcmp(acl2_buf, acl3_buf, acl_buf_size), 0);
349
350 memset(acl2_buf, 0, acl_buf_size);
351 memset(acl3_buf, 0, acl_buf_size);
352
353 ASSERT_EQ(ceph_getxattr(cmount, test_dir2, ACL_EA_ACCESS, acl2_buf, acl_buf_size), acl_buf_size);
354 ASSERT_EQ(ceph_getxattr(cmount, test_dir2_snapdir, ACL_EA_ACCESS, acl3_buf, acl_buf_size), acl_buf_size);
355 ASSERT_EQ(memcmp(acl2_buf, acl3_buf, acl_buf_size), 0);
356
357 free(acl1_buf);
358 free(acl2_buf);
359 free(acl3_buf);
360 ASSERT_EQ(ceph_rmdir(cmount, test_dir2), 0);
361 ASSERT_EQ(ceph_rmdir(cmount, test_dir1), 0);
362 ceph_shutdown(cmount);
363}