1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2011 New Dream Network
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.
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"
22 #include <sys/types.h>
24 #include <sys/xattr.h>
26 static size_t acl_ea_size(int count)
28 return sizeof(acl_ea_header) + count * sizeof(acl_ea_entry);
31 static int acl_ea_count(size_t size)
33 if (size < sizeof(acl_ea_header))
35 size -= sizeof(acl_ea_header);
36 if (size % sizeof(acl_ea_entry))
38 return size / sizeof(acl_ea_entry);
41 static int check_acl_and_mode(const void *buf, size_t size, mode_t mode)
43 const acl_ea_entry *group_entry = NULL, *mask_entry = NULL;
44 const acl_ea_header *header = reinterpret_cast<const acl_ea_header*>(buf);
45 const acl_ea_entry *entry = header->a_entries;
46 int count = (size - sizeof(*header)) / sizeof(*entry);
47 for (int i = 0; i < count; ++i) {
48 __u16 tag = entry->e_tag;
49 __u16 perm = entry->e_perm;
52 if (perm != ((mode >> 6) & 7))
62 if (perm != (mode & 7))
74 __u16 perm = mask_entry->e_perm;
75 if (perm != ((mode >> 3) & 7))
80 __u16 perm = group_entry->e_perm;
81 if (perm != ((mode >> 3) & 7))
87 static int generate_test_acl(void *buf, size_t size, mode_t mode)
89 if (acl_ea_count(size) != 5)
91 acl_ea_header *header = reinterpret_cast<acl_ea_header*>(buf);
92 header->a_version = (__u32)ACL_EA_VERSION;
93 acl_ea_entry *entry = header->a_entries;
94 entry->e_tag = ACL_USER_OBJ;
95 entry->e_perm = (mode >> 6) & 7;
97 entry->e_tag = ACL_USER;
99 entry->e_id = getuid();
101 entry->e_tag = ACL_GROUP_OBJ;
102 entry->e_perm = (mode >> 3) & 7;
104 entry->e_tag = ACL_MASK;
107 entry->e_tag = ACL_OTHER;
108 entry->e_perm = mode & 7;
112 static int generate_empty_acl(void *buf, size_t size, mode_t mode)
115 if (acl_ea_count(size) != 3)
117 acl_ea_header *header = reinterpret_cast<acl_ea_header*>(buf);
118 header->a_version = (__u32)ACL_EA_VERSION;
119 acl_ea_entry *entry = header->a_entries;
120 entry->e_tag = ACL_USER_OBJ;
121 entry->e_perm = (mode >> 6) & 7;
123 entry->e_tag = ACL_GROUP_OBJ;
124 entry->e_perm = (mode >> 3) & 7;
126 entry->e_tag = ACL_OTHER;
127 entry->e_perm = mode & 7;
132 struct ceph_mount_info *cmount;
133 ASSERT_EQ(0, ceph_create(&cmount, NULL));
134 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
135 ASSERT_EQ(0, ceph_mount(cmount, "/"));
136 ASSERT_EQ(0, ceph_conf_set(cmount, "client_acl_type", "posix_acl"));
137 ASSERT_EQ(0, ceph_conf_set(cmount, "client_permissions", "0"));
140 sprintf(test_file, "file1_setacl_%d", getpid());
142 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0600);
144 // change ownership to nobody -- we assume nobody exists and id is always 65534
145 ASSERT_EQ(ceph_fchown(cmount, fd, 65534, 65534), 0);
147 ASSERT_EQ(0, ceph_conf_set(cmount, "client_permissions", "1"));
148 ASSERT_EQ(ceph_open(cmount, test_file, O_RDWR, 0), -EACCES);
149 ASSERT_EQ(0, ceph_conf_set(cmount, "client_permissions", "0"));
151 size_t acl_buf_size = acl_ea_size(5);
152 void *acl_buf = malloc(acl_buf_size);
153 ASSERT_EQ(generate_test_acl(acl_buf, acl_buf_size, 0750), 0);
155 // can't set default acl for non-directory
156 ASSERT_EQ(ceph_fsetxattr(cmount, fd, ACL_EA_DEFAULT, acl_buf, acl_buf_size, 0), -EACCES);
157 ASSERT_EQ(ceph_fsetxattr(cmount, fd, ACL_EA_ACCESS, acl_buf, acl_buf_size, 0), 0);
159 int tmpfd = ceph_open(cmount, test_file, O_RDWR, 0);
161 ceph_close(cmount, tmpfd);
163 struct ceph_statx stx;
164 ASSERT_EQ(ceph_fstatx(cmount, fd, &stx, CEPH_STATX_MODE, 0), 0);
165 // mode was modified according to ACL
166 ASSERT_EQ(stx.stx_mode & 0777u, 0770u);
167 ASSERT_EQ(check_acl_and_mode(acl_buf, acl_buf_size, stx.stx_mode), 0);
169 acl_buf_size = acl_ea_size(3);
170 // setting ACL that is equivalent to file mode
171 ASSERT_EQ(generate_empty_acl(acl_buf, acl_buf_size, 0600), 0);
172 ASSERT_EQ(ceph_fsetxattr(cmount, fd, ACL_EA_ACCESS, acl_buf, acl_buf_size, 0), 0);
174 ASSERT_EQ(ceph_fgetxattr(cmount, fd, ACL_EA_ACCESS, NULL, 0), -ENODATA);
176 ASSERT_EQ(ceph_fstatx(cmount, fd, &stx, CEPH_STATX_MODE, 0), 0);
177 // mode was modified according to ACL
178 ASSERT_EQ(stx.stx_mode & 0777u, 0600u);
181 ceph_close(cmount, fd);
182 ceph_shutdown(cmount);
186 struct ceph_mount_info *cmount;
187 ASSERT_EQ(0, ceph_create(&cmount, NULL));
188 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
189 ASSERT_EQ(0, ceph_mount(cmount, "/"));
190 ASSERT_EQ(0, ceph_conf_set(cmount, "client_acl_type", "posix_acl"));
193 sprintf(test_file, "file1_acl_chmod_%d", getpid());
195 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0600);
198 int acl_buf_size = acl_ea_size(5);
199 void *acl_buf = malloc(acl_buf_size);
200 ASSERT_EQ(generate_test_acl(acl_buf, acl_buf_size, 0775), 0);
201 ASSERT_EQ(ceph_fsetxattr(cmount, fd, ACL_EA_ACCESS, acl_buf, acl_buf_size, 0), 0);
203 struct ceph_statx stx;
204 ASSERT_EQ(ceph_fstatx(cmount, fd, &stx, CEPH_STATX_MODE, 0), 0);
205 // mode was updated according to ACL
206 ASSERT_EQ(stx.stx_mode & 0777u, 0775u);
209 ASSERT_EQ(ceph_fchmod(cmount, fd, 0640), 0);
211 ASSERT_EQ(ceph_fstatx(cmount, fd, &stx, CEPH_STATX_MODE, 0), 0);
212 ASSERT_EQ(stx.stx_mode & 0777u, 0640u);
214 // ACL was updated according to mode
215 ASSERT_EQ(ceph_fgetxattr(cmount, fd, ACL_EA_ACCESS, acl_buf, acl_buf_size), acl_buf_size);
216 ASSERT_EQ(check_acl_and_mode(acl_buf, acl_buf_size, stx.stx_mode), 0);
219 ceph_close(cmount, fd);
220 ceph_shutdown(cmount);
223 TEST(ACL, DefaultACL) {
224 struct ceph_mount_info *cmount;
225 ASSERT_EQ(0, ceph_create(&cmount, NULL));
226 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
227 ASSERT_EQ(0, ceph_mount(cmount, "/"));
228 ASSERT_EQ(0, ceph_conf_set(cmount, "client_acl_type", "posix_acl"));
230 int acl_buf_size = acl_ea_size(5);
231 void *acl1_buf = malloc(acl_buf_size);
232 void *acl2_buf = malloc(acl_buf_size);
234 ASSERT_EQ(generate_test_acl(acl1_buf, acl_buf_size, 0750), 0);
237 sprintf(test_dir1, "dir1_acl_default_%d", getpid());
238 ASSERT_EQ(ceph_mkdir(cmount, test_dir1, 0750), 0);
241 ASSERT_EQ(ceph_setxattr(cmount, test_dir1, ACL_EA_DEFAULT, acl1_buf, acl_buf_size, 0), 0);
244 sprintf(test_dir2, "%s/dir2", test_dir1);
245 ASSERT_EQ(ceph_mkdir(cmount, test_dir2, 0755), 0);
247 // inherit default acl
248 ASSERT_EQ(ceph_getxattr(cmount, test_dir2, ACL_EA_DEFAULT, acl2_buf, acl_buf_size), acl_buf_size);
249 ASSERT_EQ(memcmp(acl1_buf, acl2_buf, acl_buf_size), 0);
251 // mode and ACL are updated
252 ASSERT_EQ(ceph_getxattr(cmount, test_dir2, ACL_EA_ACCESS, acl2_buf, acl_buf_size), acl_buf_size);
254 struct ceph_statx stx;
255 ASSERT_EQ(ceph_statx(cmount, test_dir2, &stx, CEPH_STATX_MODE, 0), 0);
256 // other bits of mode &= acl other perm
257 ASSERT_EQ(stx.stx_mode & 0777u, 0750u);
258 ASSERT_EQ(check_acl_and_mode(acl2_buf, acl_buf_size, stx.stx_mode), 0);
261 char test_file1[256];
262 sprintf(test_file1, "%s/file1", test_dir1);
263 int fd = ceph_open(cmount, test_file1, O_CREAT|O_RDWR, 0666);
267 ASSERT_EQ(ceph_fgetxattr(cmount, fd, ACL_EA_DEFAULT, NULL, 0), -ENODATA);
269 // mode and ACL are updated
270 ASSERT_EQ(ceph_fgetxattr(cmount, fd, ACL_EA_ACCESS, acl2_buf, acl_buf_size), acl_buf_size);
272 struct ceph_statx stx;
273 ASSERT_EQ(ceph_statx(cmount, test_file1, &stx, CEPH_STATX_MODE, 0), 0);
274 // other bits of mode &= acl other perm
275 ASSERT_EQ(stx.stx_mode & 0777u, 0660u);
276 ASSERT_EQ(check_acl_and_mode(acl2_buf, acl_buf_size, stx.stx_mode), 0);
281 ceph_close(cmount, fd);
282 ceph_shutdown(cmount);
285 TEST(ACL, Disabled) {
286 struct ceph_mount_info *cmount;
287 ASSERT_EQ(0, ceph_create(&cmount, NULL));
288 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
289 ASSERT_EQ(0, ceph_mount(cmount, "/"));
290 ASSERT_EQ(0, ceph_conf_set(cmount, "client_acl_type", ""));
292 size_t acl_buf_size = acl_ea_size(3);
293 void *acl_buf = malloc(acl_buf_size);
294 ASSERT_EQ(generate_empty_acl(acl_buf, acl_buf_size, 0755), 0);
297 sprintf(test_dir, "dir1_acl_disabled_%d", getpid());
298 ASSERT_EQ(ceph_mkdir(cmount, test_dir, 0750), 0);
300 ASSERT_EQ(ceph_setxattr(cmount, test_dir, ACL_EA_DEFAULT, acl_buf, acl_buf_size, 0), -EOPNOTSUPP);
301 ASSERT_EQ(ceph_setxattr(cmount, test_dir, ACL_EA_ACCESS, acl_buf, acl_buf_size, 0), -EOPNOTSUPP);
302 ASSERT_EQ(ceph_getxattr(cmount, test_dir, ACL_EA_DEFAULT, acl_buf, acl_buf_size), -EOPNOTSUPP);
303 ASSERT_EQ(ceph_getxattr(cmount, test_dir, ACL_EA_ACCESS, acl_buf, acl_buf_size), -EOPNOTSUPP);
306 ceph_shutdown(cmount);