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