]> git.proxmox.com Git - ceph.git/blob - ceph/src/client/posix_acl.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / client / posix_acl.cc
1 #include "include/compat.h"
2 #include "include/types.h"
3 #include "include/fs_types.h"
4 #include <sys/stat.h>
5 #include "posix_acl.h"
6 #include "UserPerm.h"
7
8 int posix_acl_check(const void *xattr, size_t size)
9 {
10 const acl_ea_header *header;
11 if (size < sizeof(*header))
12 return -1;
13 header = reinterpret_cast<const acl_ea_header*>(xattr);
14 ceph_le32 expected_version;
15 expected_version = ACL_EA_VERSION;
16 if (header->a_version != expected_version)
17 return -1;
18
19 const acl_ea_entry *entry = header->a_entries;
20 size -= sizeof(*header);
21 if (size % sizeof(*entry))
22 return -1;
23
24 int count = size / sizeof(*entry);
25 if (count == 0)
26 return 0;
27
28 int state = ACL_USER_OBJ;
29 int needs_mask = 0;
30 for (int i = 0; i < count; ++i) {
31 __u16 tag = entry->e_tag;
32 switch(tag) {
33 case ACL_USER_OBJ:
34 if (state == ACL_USER_OBJ) {
35 state = ACL_USER;
36 break;
37 }
38 return -1;
39 case ACL_USER:
40 if (state != ACL_USER)
41 return -1;
42 needs_mask = 1;
43 break;
44 case ACL_GROUP_OBJ:
45 if (state == ACL_USER) {
46 state = ACL_GROUP;
47 break;
48 }
49 return -1;
50 case ACL_GROUP:
51 if (state != ACL_GROUP)
52 return -1;
53 needs_mask = 1;
54 break;
55 case ACL_MASK:
56 if (state != ACL_GROUP)
57 return -1;
58 state = ACL_OTHER;
59 break;
60 case ACL_OTHER:
61 if (state == ACL_OTHER ||
62 (state == ACL_GROUP && !needs_mask)) {
63 state = 0;
64 break;
65 }
66 // fall-thru
67 default:
68 return -1;
69 }
70 ++entry;
71 }
72
73 return state == 0 ? count : -1;
74 }
75
76 int posix_acl_equiv_mode(const void *xattr, size_t size, mode_t *mode_p)
77 {
78 if (posix_acl_check(xattr, size) < 0)
79 return -CEPHFS_EINVAL;
80
81 int not_equiv = 0;
82 mode_t mode = 0;
83
84 const acl_ea_header *header = reinterpret_cast<const acl_ea_header*>(xattr);
85 const acl_ea_entry *entry = header->a_entries;
86 int count = (size - sizeof(*header)) / sizeof(*entry);
87 for (int i = 0; i < count; ++i) {
88 __u16 tag = entry->e_tag;
89 __u16 perm = entry->e_perm;
90 switch(tag) {
91 case ACL_USER_OBJ:
92 mode |= (perm & S_IRWXO) << 6;
93 break;
94 case ACL_GROUP_OBJ:
95 mode |= (perm & S_IRWXO) << 3;
96 break;
97 case ACL_OTHER:
98 mode |= perm & S_IRWXO;
99 break;
100 case ACL_MASK:
101 mode = (mode & ~S_IRWXG) | ((perm & S_IRWXO) << 3);
102 /* fall through */
103 case ACL_USER:
104 case ACL_GROUP:
105 not_equiv = 1;
106 break;
107 default:
108 return -CEPHFS_EINVAL;
109 }
110 ++entry;
111 }
112 if (mode_p)
113 *mode_p = (*mode_p & ~ACCESSPERMS) | mode;
114 return not_equiv;
115 }
116
117 int posix_acl_inherit_mode(bufferptr& acl, mode_t *mode_p)
118 {
119 if (posix_acl_check(acl.c_str(), acl.length()) <= 0)
120 return -CEPHFS_EIO;
121
122 acl_ea_entry *group_entry = NULL, *mask_entry = NULL;
123 mode_t mode = *mode_p;
124 int not_equiv = 0;
125
126 acl_ea_header *header = reinterpret_cast<acl_ea_header*>(acl.c_str());
127 acl_ea_entry *entry = header->a_entries;
128 int count = (acl.length() - sizeof(*header)) / sizeof(*entry);
129 for (int i = 0; i < count; ++i) {
130 __u16 tag = entry->e_tag;
131 __u16 perm = entry->e_perm;
132 switch(tag) {
133 case ACL_USER_OBJ:
134 perm &= (mode >> 6) | ~S_IRWXO;
135 mode &= (perm << 6) | ~S_IRWXU;
136 entry->e_perm = perm;
137 break;
138 case ACL_USER:
139 case ACL_GROUP:
140 not_equiv = 1;
141 break;
142 case ACL_GROUP_OBJ:
143 group_entry = entry;
144 break;
145 case ACL_OTHER:
146 perm &= mode | ~S_IRWXO;
147 mode &= perm | ~S_IRWXO;
148 entry->e_perm = perm;
149 break;
150 case ACL_MASK:
151 mask_entry = entry;
152 not_equiv = 1;
153 break;
154 default:
155 return -CEPHFS_EIO;
156
157 }
158 ++entry;
159 }
160
161 if (mask_entry) {
162 __u16 perm = mask_entry->e_perm;
163 perm &= (mode >> 3) | ~S_IRWXO;
164 mode &= (perm << 3) | ~S_IRWXG;
165 mask_entry->e_perm = perm;
166 } else {
167 if (!group_entry)
168 return -CEPHFS_EIO;
169 __u16 perm = group_entry->e_perm;
170 perm &= (mode >> 3) | ~S_IRWXO;
171 mode &= (perm << 3) | ~S_IRWXG;
172 group_entry->e_perm = perm;
173 }
174
175 *mode_p = (*mode_p & ~ACCESSPERMS) | mode;
176 return not_equiv;
177 }
178
179 int posix_acl_access_chmod(bufferptr& acl, mode_t mode)
180 {
181 if (posix_acl_check(acl.c_str(), acl.length()) <= 0)
182 return -CEPHFS_EIO;
183
184 acl_ea_entry *group_entry = NULL, *mask_entry = NULL;
185
186 acl_ea_header *header = reinterpret_cast<acl_ea_header*>(acl.c_str());
187 acl_ea_entry *entry = header->a_entries;
188 int count = (acl.length() - sizeof(*header)) / sizeof(*entry);
189 for (int i = 0; i < count; ++i) {
190 __u16 tag = entry->e_tag;
191 switch(tag) {
192 case ACL_USER_OBJ:
193 entry->e_perm = (mode & S_IRWXU) >> 6;
194 break;
195 case ACL_GROUP_OBJ:
196 group_entry = entry;
197 break;
198 case ACL_MASK:
199 mask_entry = entry;
200 break;
201 case ACL_OTHER:
202 entry->e_perm = mode & S_IRWXO;
203 break;
204 default:
205 break;
206 }
207 ++entry;
208 }
209
210 if (mask_entry) {
211 mask_entry->e_perm = (mode & S_IRWXG) >> 3;
212 } else {
213 if (!group_entry)
214 return -CEPHFS_EIO;
215 group_entry->e_perm = (mode & S_IRWXG) >> 3;
216 }
217 return 0;
218 }
219
220 int posix_acl_permits(const bufferptr& acl, uid_t i_uid, gid_t i_gid,
221 const UserPerm& perms, unsigned want)
222 {
223 if (posix_acl_check(acl.c_str(), acl.length()) < 0)
224 return -CEPHFS_EIO;
225
226 const acl_ea_header *header = reinterpret_cast<const acl_ea_header*>(acl.c_str());
227 const acl_ea_entry *entry = header->a_entries;
228 const acl_ea_entry *next_entry;
229 __u16 perm, tag;
230 __u32 id;
231 int group_found = 0;
232 int idx;
233 int count = (acl.length() - sizeof(*header)) / sizeof(*entry);
234 for (idx = 0; idx < count; ++idx) {
235 tag = entry->e_tag;
236 perm = entry->e_perm;
237 switch(tag) {
238 case ACL_USER_OBJ:
239 if (i_uid == perms.uid())
240 goto check_perm;
241 break;
242 case ACL_USER:
243 id = entry->e_id;
244 if (id == perms.uid())
245 goto check_mask;
246 break;
247 case ACL_GROUP_OBJ:
248 /* fall through */
249 case ACL_GROUP:
250 id = (tag == ACL_GROUP_OBJ) ? i_gid : entry->e_id;
251 if (perms.gid_in_groups(id)) {
252 group_found = 1;
253 if ((perm & want) == want)
254 goto check_mask;
255 }
256 break;
257 case ACL_MASK:
258 break;
259 case ACL_OTHER:
260 if (group_found)
261 return -CEPHFS_EACCES;
262 else
263 goto check_perm;
264 break;
265 default:
266 return -CEPHFS_EIO;
267 }
268 ++entry;
269 }
270 return -CEPHFS_EIO;
271
272 check_mask:
273 next_entry = entry + 1;
274 for (++idx; idx < count; ++idx) {
275 tag = next_entry->e_tag;
276 if (tag == ACL_MASK) {
277 __u16 mask = next_entry->e_perm;
278 if ((perm & mask & want) == want)
279 return 0;
280 return -CEPHFS_EACCES;
281 }
282 ++next_entry;
283 }
284 check_perm:
285 if ((perm & want) == want)
286 return 0;
287 return -CEPHFS_EACCES;
288 }