1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*LINTLIBRARY*/
27
28 /*
29 * aclcheck(): check validity of an ACL
30 * A valid ACL is defined as follows:
31 * There must be exactly one USER_OBJ, GROUP_OBJ, and OTHER_OBJ entry.
32 * If there are any USER entries, then the user id must be unique.
33 * If there are any GROUP entries, then the group id must be unique.
34 * If there are any GROUP or USER entries, there must be exactly one
35 * CLASS_OBJ entry.
36 * The same rules apply to default ACL entries.
37 */
38
39 #include <errno.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <sys/types.h>
43 #include <sys/acl.h>
44 #include <aclutils.h>
45
46 struct entry {
47 int count;
48 uid_t *id;
49 };
50
51 struct entry_stat {
52 struct entry user_obj;
53 struct entry user;
54 struct entry group_obj;
55 struct entry group;
56 struct entry other_obj;
57 struct entry class_obj;
58 struct entry def_user_obj;
59 struct entry def_user;
60 struct entry def_group_obj;
61 struct entry def_group;
62 struct entry def_other_obj;
63 struct entry def_class_obj;
64 };
65
66 static void free_mem(struct entry_stat *);
67 static int check_dup(int, uid_t *, uid_t, struct entry_stat *);
68
69 static int
aclent_aclcheck(aclent_t * aclbufp,int nentries,int * which,int isdir)70 aclent_aclcheck(aclent_t *aclbufp, int nentries, int *which, int isdir)
71 {
72 struct entry_stat tally;
73 aclent_t *aclentp;
74 uid_t **idp;
75 int cnt;
76
77 *which = -1;
78 memset(&tally, '\0', sizeof (tally));
79
80 for (aclentp = aclbufp; nentries > 0; nentries--, aclentp++) {
81 switch (aclentp->a_type) {
82 case USER_OBJ:
83 /* check uniqueness */
84 if (tally.user_obj.count > 0) {
85 *which = (int)(aclentp - aclbufp);
86 (void) free_mem(&tally);
87 errno = EINVAL;
88 return (EACL_USER_ERROR);
89 }
90 tally.user_obj.count = 1;
91 break;
92
93 case GROUP_OBJ:
94 /* check uniqueness */
95 if (tally.group_obj.count > 0) {
96 *which = (int)(aclentp - aclbufp);
97 (void) free_mem(&tally);
98 errno = EINVAL;
99 return (EACL_GRP_ERROR);
100 }
101 tally.group_obj.count = 1;
102 break;
103
104 case OTHER_OBJ:
105 /* check uniqueness */
106 if (tally.other_obj.count > 0) {
107 *which = (int)(aclentp - aclbufp);
108 (void) free_mem(&tally);
109 errno = EINVAL;
110 return (EACL_OTHER_ERROR);
111 }
112 tally.other_obj.count = 1;
113 break;
114
115 case CLASS_OBJ:
116 /* check uniqueness */
117 if (tally.class_obj.count > 0) {
118 *which = (int)(aclentp - aclbufp);
119 (void) free_mem(&tally);
120 errno = EINVAL;
121 return (EACL_CLASS_ERROR);
122 }
123 tally.class_obj.count = 1;
124 break;
125
126 case USER:
127 case GROUP:
128 case DEF_USER:
129 case DEF_GROUP:
130 /* check duplicate */
131 if (aclentp->a_type == DEF_USER) {
132 cnt = (tally.def_user.count)++;
133 idp = &(tally.def_user.id);
134 } else if (aclentp->a_type == DEF_GROUP) {
135 cnt = (tally.def_group.count)++;
136 idp = &(tally.def_group.id);
137 } else if (aclentp->a_type == USER) {
138 cnt = (tally.user.count)++;
139 idp = &(tally.user.id);
140 } else {
141 cnt = (tally.group.count)++;
142 idp = &(tally.group.id);
143 }
144
145 if (cnt == 0) {
146 *idp = calloc(nentries, sizeof (uid_t));
147 if (*idp == NULL)
148 return (EACL_MEM_ERROR);
149 } else {
150 if (check_dup(cnt, *idp, aclentp->a_id,
151 &tally) == -1) {
152 *which = (int)(aclentp - aclbufp);
153 return (EACL_DUPLICATE_ERROR);
154 }
155 }
156 (*idp)[cnt] = aclentp->a_id;
157 break;
158
159 case DEF_USER_OBJ:
160 /* check uniqueness */
161 if (tally.def_user_obj.count > 0) {
162 *which = (int)(aclentp - aclbufp);
163 (void) free_mem(&tally);
164 errno = EINVAL;
165 return (EACL_USER_ERROR);
166 }
167 tally.def_user_obj.count = 1;
168 break;
169
170 case DEF_GROUP_OBJ:
171 /* check uniqueness */
172 if (tally.def_group_obj.count > 0) {
173 *which = (int)(aclentp - aclbufp);
174 (void) free_mem(&tally);
175 errno = EINVAL;
176 return (EACL_GRP_ERROR);
177 }
178 tally.def_group_obj.count = 1;
179 break;
180
181 case DEF_OTHER_OBJ:
182 /* check uniqueness */
183 if (tally.def_other_obj.count > 0) {
184 *which = (int)(aclentp - aclbufp);
185 (void) free_mem(&tally);
186 errno = EINVAL;
187 return (EACL_OTHER_ERROR);
188 }
189 tally.def_other_obj.count = 1;
190 break;
191
192 case DEF_CLASS_OBJ:
193 /* check uniqueness */
194 if (tally.def_class_obj.count > 0) {
195 *which = (int)(aclentp - aclbufp);
196 (void) free_mem(&tally);
197 errno = EINVAL;
198 return (EACL_CLASS_ERROR);
199 }
200 tally.def_class_obj.count = 1;
201 break;
202
203 default:
204 (void) free_mem(&tally);
205 errno = EINVAL;
206 *which = (int)(aclentp - aclbufp);
207 return (EACL_ENTRY_ERROR);
208 }
209 }
210 /* If there are group or user entries, there must be one class entry */
211 if (tally.user.count > 0 || tally.group.count > 0)
212 if (tally.class_obj.count != 1) {
213 (void) free_mem(&tally);
214 errno = EINVAL;
215 return (EACL_MISS_ERROR);
216 }
217 /* same is true for default entries */
218 if (tally.def_user.count > 0 || tally.def_group.count > 0)
219 if (tally.def_class_obj.count != 1) {
220 (void) free_mem(&tally);
221 errno = EINVAL;
222 return (EACL_MISS_ERROR);
223 }
224
225 /* there must be exactly one user_obj, group_obj, and other_obj entry */
226 if (tally.user_obj.count != 1 ||
227 tally.group_obj.count != 1 ||
228 tally.other_obj.count != 1) {
229 (void) free_mem(&tally);
230 errno = EINVAL;
231 return (EACL_MISS_ERROR);
232 }
233
234 /* has default? same rules apply to default entries */
235 if (tally.def_user.count > 0 || tally.def_user_obj.count > 0 ||
236 tally.def_group.count > 0 || tally.def_group_obj.count > 0 ||
237 tally.def_class_obj.count > 0 || tally.def_other_obj.count > 0) {
238
239 /*
240 * Can't have default ACL's on non-directories
241 */
242 if (isdir == 0) {
243 (void) free_mem(&tally);
244 errno = EINVAL;
245 return (EACL_INHERIT_NOTDIR);
246 }
247
248 if (tally.def_user_obj.count != 1 ||
249 tally.def_group_obj.count != 1 ||
250 tally.def_other_obj.count != 1) {
251 (void) free_mem(&tally);
252 errno = EINVAL;
253 return (EACL_MISS_ERROR);
254 }
255 }
256
257 (void) free_mem(&tally);
258 return (0);
259 }
260
261 int
aclcheck(aclent_t * aclbufp,int nentries,int * which)262 aclcheck(aclent_t *aclbufp, int nentries, int *which)
263 {
264 return (aclent_aclcheck(aclbufp, nentries, which, 1));
265 }
266
267
268 static void
free_mem(struct entry_stat * tallyp)269 free_mem(struct entry_stat *tallyp)
270 {
271 if ((tallyp->user).count > 0)
272 free((tallyp->user).id);
273 if ((tallyp->group).count > 0)
274 free((tallyp->group).id);
275 if ((tallyp->def_user).count > 0)
276 free((tallyp->def_user).id);
277 if ((tallyp->def_group).count > 0)
278 free((tallyp->def_group).id);
279 }
280
281 static int
check_dup(int count,uid_t * ids,uid_t newid,struct entry_stat * tallyp)282 check_dup(int count, uid_t *ids, uid_t newid, struct entry_stat *tallyp)
283 {
284 int i;
285
286 for (i = 0; i < count; i++) {
287 if (ids[i] == newid) {
288 errno = EINVAL;
289 (void) free_mem(tallyp);
290 return (-1);
291 }
292 }
293 return (0);
294 }
295
296 #define IFLAGS (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE| \
297 ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE)
298
299 static int
ace_aclcheck(acl_t * aclp,int isdir)300 ace_aclcheck(acl_t *aclp, int isdir)
301 {
302 ace_t *acep;
303 int i;
304 int error = 0;
305
306 /*
307 * step through all valid flags.
308 */
309
310 if (aclp->acl_cnt <= 0 || aclp->acl_cnt > MAX_ACL_ENTRIES)
311 return (EACL_COUNT_ERROR);
312
313 for (i = 0, acep = aclp->acl_aclp;
314 i != aclp->acl_cnt && error == 0; i++, acep++) {
315 switch (acep->a_flags & 0xf040) {
316 case 0:
317 case ACE_OWNER:
318 case ACE_EVERYONE:
319 case ACE_IDENTIFIER_GROUP:
320 case ACE_GROUP|ACE_IDENTIFIER_GROUP:
321 break;
322 default:
323 errno = EINVAL;
324 return (EACL_FLAGS_ERROR);
325 }
326
327 /*
328 * INHERIT_ONLY/NO_PROPAGATE need a to INHERIT_FILE
329 * or INHERIT_DIR also
330 */
331 if (acep->a_flags &
332 (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) {
333 if ((acep->a_flags & (ACE_FILE_INHERIT_ACE|
334 ACE_DIRECTORY_INHERIT_ACE)) == 0) {
335 errno = EINVAL;
336 return (EACL_INHERIT_ERROR);
337 }
338 break;
339 }
340
341 switch (acep->a_type) {
342 case ACE_ACCESS_ALLOWED_ACE_TYPE:
343 case ACE_ACCESS_DENIED_ACE_TYPE:
344 case ACE_SYSTEM_AUDIT_ACE_TYPE:
345 case ACE_SYSTEM_ALARM_ACE_TYPE:
346 break;
347 default:
348 errno = EINVAL;
349 return (EACL_ENTRY_ERROR);
350 }
351 if (acep->a_access_mask > ACE_ALL_PERMS) {
352 errno = EINVAL;
353 return (EACL_PERM_MASK_ERROR);
354 }
355 }
356
357 return (0);
358 }
359
360 int
acl_check(acl_t * aclp,int flag)361 acl_check(acl_t *aclp, int flag)
362 {
363 int error;
364 int where;
365
366 switch (aclp->acl_type) {
367 case ACLENT_T:
368 error = aclent_aclcheck(aclp->acl_aclp, aclp->acl_cnt,
369 &where, flag);
370 break;
371 case ACE_T:
372 error = ace_aclcheck(aclp, flag);
373 break;
374 default:
375 errno = EINVAL;
376 error = EACL_ENTRY_ERROR;
377 }
378 return (error);
379 }
380