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