Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / client / posix_acl.cc
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
10 int 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
78 int 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
119 int 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
181 int 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
222 int 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
274 check_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   }
286 check_perm:
287   if ((perm & want) == want)
288     return 0;
289   return -EACCES;
290 }