10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*7057Smarks * Common Development and Distribution License (the "License").
6*7057Smarks * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*7057Smarks * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23789Sahrens * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
270Sstevel@tonic-gate /*LINTLIBRARY*/
280Sstevel@tonic-gate
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate * aclcheck(): check validity of an ACL
310Sstevel@tonic-gate * A valid ACL is defined as follows:
320Sstevel@tonic-gate * There must be exactly one USER_OBJ, GROUP_OBJ, and OTHER_OBJ entry.
330Sstevel@tonic-gate * If there are any USER entries, then the user id must be unique.
340Sstevel@tonic-gate * If there are any GROUP entries, then the group id must be unique.
350Sstevel@tonic-gate * If there are any GROUP or USER entries, there must be exactly one
360Sstevel@tonic-gate * CLASS_OBJ entry.
370Sstevel@tonic-gate * The same rules apply to default ACL entries.
380Sstevel@tonic-gate */
390Sstevel@tonic-gate
400Sstevel@tonic-gate #include <errno.h>
410Sstevel@tonic-gate #include <stdlib.h>
420Sstevel@tonic-gate #include <string.h>
430Sstevel@tonic-gate #include <sys/types.h>
440Sstevel@tonic-gate #include <sys/acl.h>
45789Sahrens #include <aclutils.h>
460Sstevel@tonic-gate
470Sstevel@tonic-gate struct entry {
480Sstevel@tonic-gate int count;
490Sstevel@tonic-gate uid_t *id;
500Sstevel@tonic-gate };
510Sstevel@tonic-gate
520Sstevel@tonic-gate struct entry_stat {
530Sstevel@tonic-gate struct entry user_obj;
540Sstevel@tonic-gate struct entry user;
550Sstevel@tonic-gate struct entry group_obj;
560Sstevel@tonic-gate struct entry group;
570Sstevel@tonic-gate struct entry other_obj;
580Sstevel@tonic-gate struct entry class_obj;
590Sstevel@tonic-gate struct entry def_user_obj;
600Sstevel@tonic-gate struct entry def_user;
610Sstevel@tonic-gate struct entry def_group_obj;
620Sstevel@tonic-gate struct entry def_group;
630Sstevel@tonic-gate struct entry def_other_obj;
640Sstevel@tonic-gate struct entry def_class_obj;
650Sstevel@tonic-gate };
660Sstevel@tonic-gate
670Sstevel@tonic-gate static void free_mem(struct entry_stat *);
680Sstevel@tonic-gate static int check_dup(int, uid_t *, uid_t, struct entry_stat *);
690Sstevel@tonic-gate
70789Sahrens static int
aclent_aclcheck(aclent_t * aclbufp,int nentries,int * which,int isdir)71789Sahrens aclent_aclcheck(aclent_t *aclbufp, int nentries, int *which, int isdir)
720Sstevel@tonic-gate {
730Sstevel@tonic-gate struct entry_stat tally;
740Sstevel@tonic-gate aclent_t *aclentp;
750Sstevel@tonic-gate uid_t **idp;
760Sstevel@tonic-gate int cnt;
770Sstevel@tonic-gate
780Sstevel@tonic-gate *which = -1;
790Sstevel@tonic-gate memset(&tally, '\0', sizeof (tally));
800Sstevel@tonic-gate
810Sstevel@tonic-gate for (aclentp = aclbufp; nentries > 0; nentries--, aclentp++) {
820Sstevel@tonic-gate switch (aclentp->a_type) {
830Sstevel@tonic-gate case USER_OBJ:
840Sstevel@tonic-gate /* check uniqueness */
850Sstevel@tonic-gate if (tally.user_obj.count > 0) {
86789Sahrens *which = (int)(aclentp - aclbufp);
870Sstevel@tonic-gate (void) free_mem(&tally);
880Sstevel@tonic-gate errno = EINVAL;
89789Sahrens return (EACL_USER_ERROR);
900Sstevel@tonic-gate }
910Sstevel@tonic-gate tally.user_obj.count = 1;
920Sstevel@tonic-gate break;
930Sstevel@tonic-gate
940Sstevel@tonic-gate case GROUP_OBJ:
950Sstevel@tonic-gate /* check uniqueness */
960Sstevel@tonic-gate if (tally.group_obj.count > 0) {
97789Sahrens *which = (int)(aclentp - aclbufp);
980Sstevel@tonic-gate (void) free_mem(&tally);
990Sstevel@tonic-gate errno = EINVAL;
100789Sahrens return (EACL_GRP_ERROR);
1010Sstevel@tonic-gate }
1020Sstevel@tonic-gate tally.group_obj.count = 1;
1030Sstevel@tonic-gate break;
1040Sstevel@tonic-gate
1050Sstevel@tonic-gate case OTHER_OBJ:
1060Sstevel@tonic-gate /* check uniqueness */
1070Sstevel@tonic-gate if (tally.other_obj.count > 0) {
108789Sahrens *which = (int)(aclentp - aclbufp);
1090Sstevel@tonic-gate (void) free_mem(&tally);
1100Sstevel@tonic-gate errno = EINVAL;
111789Sahrens return (EACL_OTHER_ERROR);
1120Sstevel@tonic-gate }
1130Sstevel@tonic-gate tally.other_obj.count = 1;
1140Sstevel@tonic-gate break;
1150Sstevel@tonic-gate
1160Sstevel@tonic-gate case CLASS_OBJ:
1170Sstevel@tonic-gate /* check uniqueness */
1180Sstevel@tonic-gate if (tally.class_obj.count > 0) {
119789Sahrens *which = (int)(aclentp - aclbufp);
1200Sstevel@tonic-gate (void) free_mem(&tally);
1210Sstevel@tonic-gate errno = EINVAL;
122789Sahrens return (EACL_CLASS_ERROR);
1230Sstevel@tonic-gate }
1240Sstevel@tonic-gate tally.class_obj.count = 1;
1250Sstevel@tonic-gate break;
1260Sstevel@tonic-gate
1270Sstevel@tonic-gate case USER:
1280Sstevel@tonic-gate case GROUP:
1290Sstevel@tonic-gate case DEF_USER:
1300Sstevel@tonic-gate case DEF_GROUP:
1310Sstevel@tonic-gate /* check duplicate */
1320Sstevel@tonic-gate if (aclentp->a_type == DEF_USER) {
1330Sstevel@tonic-gate cnt = (tally.def_user.count)++;
1340Sstevel@tonic-gate idp = &(tally.def_user.id);
1350Sstevel@tonic-gate } else if (aclentp->a_type == DEF_GROUP) {
1360Sstevel@tonic-gate cnt = (tally.def_group.count)++;
1370Sstevel@tonic-gate idp = &(tally.def_group.id);
1380Sstevel@tonic-gate } else if (aclentp->a_type == USER) {
1390Sstevel@tonic-gate cnt = (tally.user.count)++;
1400Sstevel@tonic-gate idp = &(tally.user.id);
1410Sstevel@tonic-gate } else {
1420Sstevel@tonic-gate cnt = (tally.group.count)++;
1430Sstevel@tonic-gate idp = &(tally.group.id);
1440Sstevel@tonic-gate }
1450Sstevel@tonic-gate
1460Sstevel@tonic-gate if (cnt == 0) {
1470Sstevel@tonic-gate *idp = calloc(nentries, sizeof (uid_t));
1480Sstevel@tonic-gate if (*idp == NULL)
149789Sahrens return (EACL_MEM_ERROR);
1500Sstevel@tonic-gate } else {
1510Sstevel@tonic-gate if (check_dup(cnt, *idp, aclentp->a_id,
1520Sstevel@tonic-gate &tally) == -1) {
153789Sahrens *which = (int)(aclentp - aclbufp);
154789Sahrens return (EACL_DUPLICATE_ERROR);
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate (*idp)[cnt] = aclentp->a_id;
1580Sstevel@tonic-gate break;
1590Sstevel@tonic-gate
1600Sstevel@tonic-gate case DEF_USER_OBJ:
1610Sstevel@tonic-gate /* check uniqueness */
1620Sstevel@tonic-gate if (tally.def_user_obj.count > 0) {
163789Sahrens *which = (int)(aclentp - aclbufp);
1640Sstevel@tonic-gate (void) free_mem(&tally);
1650Sstevel@tonic-gate errno = EINVAL;
166789Sahrens return (EACL_USER_ERROR);
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate tally.def_user_obj.count = 1;
1690Sstevel@tonic-gate break;
1700Sstevel@tonic-gate
1710Sstevel@tonic-gate case DEF_GROUP_OBJ:
1720Sstevel@tonic-gate /* check uniqueness */
1730Sstevel@tonic-gate if (tally.def_group_obj.count > 0) {
174789Sahrens *which = (int)(aclentp - aclbufp);
1750Sstevel@tonic-gate (void) free_mem(&tally);
1760Sstevel@tonic-gate errno = EINVAL;
177789Sahrens return (EACL_GRP_ERROR);
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate tally.def_group_obj.count = 1;
1800Sstevel@tonic-gate break;
1810Sstevel@tonic-gate
1820Sstevel@tonic-gate case DEF_OTHER_OBJ:
1830Sstevel@tonic-gate /* check uniqueness */
1840Sstevel@tonic-gate if (tally.def_other_obj.count > 0) {
185789Sahrens *which = (int)(aclentp - aclbufp);
1860Sstevel@tonic-gate (void) free_mem(&tally);
1870Sstevel@tonic-gate errno = EINVAL;
188789Sahrens return (EACL_OTHER_ERROR);
1890Sstevel@tonic-gate }
1900Sstevel@tonic-gate tally.def_other_obj.count = 1;
1910Sstevel@tonic-gate break;
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate case DEF_CLASS_OBJ:
1940Sstevel@tonic-gate /* check uniqueness */
1950Sstevel@tonic-gate if (tally.def_class_obj.count > 0) {
196789Sahrens *which = (int)(aclentp - aclbufp);
1970Sstevel@tonic-gate (void) free_mem(&tally);
1980Sstevel@tonic-gate errno = EINVAL;
199789Sahrens return (EACL_CLASS_ERROR);
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate tally.def_class_obj.count = 1;
2020Sstevel@tonic-gate break;
2030Sstevel@tonic-gate
2040Sstevel@tonic-gate default:
2050Sstevel@tonic-gate (void) free_mem(&tally);
2060Sstevel@tonic-gate errno = EINVAL;
207789Sahrens *which = (int)(aclentp - aclbufp);
208789Sahrens return (EACL_ENTRY_ERROR);
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate }
2110Sstevel@tonic-gate /* If there are group or user entries, there must be one class entry */
2120Sstevel@tonic-gate if (tally.user.count > 0 || tally.group.count > 0)
2130Sstevel@tonic-gate if (tally.class_obj.count != 1) {
2140Sstevel@tonic-gate (void) free_mem(&tally);
2150Sstevel@tonic-gate errno = EINVAL;
216789Sahrens return (EACL_MISS_ERROR);
2170Sstevel@tonic-gate }
2180Sstevel@tonic-gate /* same is true for default entries */
2190Sstevel@tonic-gate if (tally.def_user.count > 0 || tally.def_group.count > 0)
2200Sstevel@tonic-gate if (tally.def_class_obj.count != 1) {
2210Sstevel@tonic-gate (void) free_mem(&tally);
2220Sstevel@tonic-gate errno = EINVAL;
223789Sahrens return (EACL_MISS_ERROR);
2240Sstevel@tonic-gate }
2250Sstevel@tonic-gate
2260Sstevel@tonic-gate /* there must be exactly one user_obj, group_obj, and other_obj entry */
2270Sstevel@tonic-gate if (tally.user_obj.count != 1 ||
2280Sstevel@tonic-gate tally.group_obj.count != 1 ||
229*7057Smarks tally.other_obj.count != 1) {
2300Sstevel@tonic-gate (void) free_mem(&tally);
2310Sstevel@tonic-gate errno = EINVAL;
232789Sahrens return (EACL_MISS_ERROR);
2330Sstevel@tonic-gate }
2340Sstevel@tonic-gate
2350Sstevel@tonic-gate /* has default? same rules apply to default entries */
236789Sahrens if (tally.def_user.count > 0 || tally.def_user_obj.count > 0 ||
237789Sahrens tally.def_group.count > 0 || tally.def_group_obj.count > 0 ||
238789Sahrens tally.def_class_obj.count > 0 || tally.def_other_obj.count > 0) {
239789Sahrens
240789Sahrens /*
241789Sahrens * Can't have default ACL's on non-directories
242789Sahrens */
243789Sahrens if (isdir == 0) {
244789Sahrens (void) free_mem(&tally);
245789Sahrens errno = EINVAL;
246789Sahrens return (EACL_INHERIT_NOTDIR);
247789Sahrens }
248789Sahrens
2490Sstevel@tonic-gate if (tally.def_user_obj.count != 1 ||
2500Sstevel@tonic-gate tally.def_group_obj.count != 1 ||
2510Sstevel@tonic-gate tally.def_other_obj.count != 1) {
2520Sstevel@tonic-gate (void) free_mem(&tally);
2530Sstevel@tonic-gate errno = EINVAL;
254789Sahrens return (EACL_MISS_ERROR);
2550Sstevel@tonic-gate }
256789Sahrens }
257789Sahrens
2580Sstevel@tonic-gate (void) free_mem(&tally);
2590Sstevel@tonic-gate return (0);
2600Sstevel@tonic-gate }
2610Sstevel@tonic-gate
262789Sahrens int
aclcheck(aclent_t * aclbufp,int nentries,int * which)263789Sahrens aclcheck(aclent_t *aclbufp, int nentries, int *which)
264789Sahrens {
265789Sahrens return (aclent_aclcheck(aclbufp, nentries, which, 1));
266789Sahrens }
267789Sahrens
268789Sahrens
2690Sstevel@tonic-gate static void
free_mem(struct entry_stat * tallyp)2700Sstevel@tonic-gate free_mem(struct entry_stat *tallyp)
2710Sstevel@tonic-gate {
2720Sstevel@tonic-gate if ((tallyp->user).count > 0)
2730Sstevel@tonic-gate free((tallyp->user).id);
2740Sstevel@tonic-gate if ((tallyp->group).count > 0)
2750Sstevel@tonic-gate free((tallyp->group).id);
2760Sstevel@tonic-gate if ((tallyp->def_user).count > 0)
2770Sstevel@tonic-gate free((tallyp->def_user).id);
2780Sstevel@tonic-gate if ((tallyp->def_group).count > 0)
2790Sstevel@tonic-gate free((tallyp->def_group).id);
2800Sstevel@tonic-gate }
2810Sstevel@tonic-gate
2820Sstevel@tonic-gate static int
check_dup(int count,uid_t * ids,uid_t newid,struct entry_stat * tallyp)2830Sstevel@tonic-gate check_dup(int count, uid_t *ids, uid_t newid, struct entry_stat *tallyp)
2840Sstevel@tonic-gate {
2850Sstevel@tonic-gate int i;
2860Sstevel@tonic-gate
2870Sstevel@tonic-gate for (i = 0; i < count; i++) {
2880Sstevel@tonic-gate if (ids[i] == newid) {
2890Sstevel@tonic-gate errno = EINVAL;
2900Sstevel@tonic-gate (void) free_mem(tallyp);
2910Sstevel@tonic-gate return (-1);
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate }
2940Sstevel@tonic-gate return (0);
2950Sstevel@tonic-gate }
296789Sahrens
297789Sahrens #define IFLAGS (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE| \
298789Sahrens ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE)
299789Sahrens
300789Sahrens static int
ace_aclcheck(acl_t * aclp,int isdir)301789Sahrens ace_aclcheck(acl_t *aclp, int isdir)
302789Sahrens {
303789Sahrens ace_t *acep;
304789Sahrens int i;
305789Sahrens int error = 0;
306789Sahrens
307789Sahrens /*
308789Sahrens * step through all valid flags.
309789Sahrens */
310789Sahrens
311789Sahrens if (aclp->acl_cnt <= 0 || aclp->acl_cnt > MAX_ACL_ENTRIES)
312789Sahrens return (EACL_COUNT_ERROR);
313789Sahrens
314789Sahrens for (i = 0, acep = aclp->acl_aclp;
315789Sahrens i != aclp->acl_cnt && error == 0; i++, acep++) {
316789Sahrens switch (acep->a_flags & 0xf040) {
317789Sahrens case 0:
318789Sahrens case ACE_OWNER:
319789Sahrens case ACE_EVERYONE:
320789Sahrens case ACE_IDENTIFIER_GROUP:
321789Sahrens case ACE_GROUP|ACE_IDENTIFIER_GROUP:
322789Sahrens break;
323789Sahrens default:
324789Sahrens errno = EINVAL;
325789Sahrens return (EACL_FLAGS_ERROR);
326789Sahrens }
327789Sahrens
328789Sahrens /*
329789Sahrens * INHERIT_ONLY/NO_PROPAGATE need a to INHERIT_FILE
330789Sahrens * or INHERIT_DIR also
331789Sahrens */
332789Sahrens if (acep->a_flags &
333789Sahrens (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) {
334789Sahrens if ((acep->a_flags & (ACE_FILE_INHERIT_ACE|
335789Sahrens ACE_DIRECTORY_INHERIT_ACE)) == 0) {
336789Sahrens errno = EINVAL;
337789Sahrens return (EACL_INHERIT_ERROR);
338789Sahrens }
339789Sahrens break;
340789Sahrens }
341789Sahrens
342789Sahrens switch (acep->a_type) {
343789Sahrens case ACE_ACCESS_ALLOWED_ACE_TYPE:
344789Sahrens case ACE_ACCESS_DENIED_ACE_TYPE:
345789Sahrens case ACE_SYSTEM_AUDIT_ACE_TYPE:
346789Sahrens case ACE_SYSTEM_ALARM_ACE_TYPE:
347789Sahrens break;
348789Sahrens default:
349789Sahrens errno = EINVAL;
350789Sahrens return (EACL_ENTRY_ERROR);
351789Sahrens }
352789Sahrens if (acep->a_access_mask > ACE_ALL_PERMS) {
353789Sahrens errno = EINVAL;
354789Sahrens return (EACL_PERM_MASK_ERROR);
355789Sahrens }
356789Sahrens }
357789Sahrens
358789Sahrens return (0);
359789Sahrens }
360789Sahrens
361789Sahrens int
acl_check(acl_t * aclp,int flag)362789Sahrens acl_check(acl_t *aclp, int flag)
363789Sahrens {
364789Sahrens int error;
365789Sahrens int where;
366789Sahrens
367789Sahrens switch (aclp->acl_type) {
368789Sahrens case ACLENT_T:
369789Sahrens error = aclent_aclcheck(aclp->acl_aclp, aclp->acl_cnt,
370789Sahrens &where, flag);
371789Sahrens break;
372789Sahrens case ACE_T:
373789Sahrens error = ace_aclcheck(aclp, flag);
374789Sahrens break;
375789Sahrens default:
376789Sahrens errno = EINVAL;
377789Sahrens error = EACL_ENTRY_ERROR;
378789Sahrens }
379789Sahrens return (error);
380789Sahrens }
381