]>
git.proxmox.com Git - ceph.git/blob - ceph/src/test/libcephfs/acl.cc
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
[262];
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
);