1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright (c) 1993-1997 by Sun Microsystems, Inc.
24*0Sstevel@tonic-gate  */
25*0Sstevel@tonic-gate 
26*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*0Sstevel@tonic-gate /*LINTLIBRARY*/
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * aclcheck(): check validity of an ACL
31*0Sstevel@tonic-gate  *	A valid ACL is defined as follows:
32*0Sstevel@tonic-gate  *	There must be exactly one USER_OBJ, GROUP_OBJ, and OTHER_OBJ entry.
33*0Sstevel@tonic-gate  *	If there are any USER entries, then the user id must be unique.
34*0Sstevel@tonic-gate  *	If there are any GROUP entries, then the group id must be unique.
35*0Sstevel@tonic-gate  *	If there are any GROUP or USER entries, there must be exactly one
36*0Sstevel@tonic-gate  *	CLASS_OBJ entry.
37*0Sstevel@tonic-gate  *	The same rules apply to default ACL entries.
38*0Sstevel@tonic-gate  */
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate #include <errno.h>
41*0Sstevel@tonic-gate #include <stdlib.h>
42*0Sstevel@tonic-gate #include <string.h>
43*0Sstevel@tonic-gate #include <sys/types.h>
44*0Sstevel@tonic-gate #include <sys/acl.h>
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate struct entry {
47*0Sstevel@tonic-gate 	int	count;
48*0Sstevel@tonic-gate 	uid_t	*id;
49*0Sstevel@tonic-gate };
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate struct entry_stat {
52*0Sstevel@tonic-gate 	struct entry	user_obj;
53*0Sstevel@tonic-gate 	struct entry	user;
54*0Sstevel@tonic-gate 	struct entry	group_obj;
55*0Sstevel@tonic-gate 	struct entry	group;
56*0Sstevel@tonic-gate 	struct entry	other_obj;
57*0Sstevel@tonic-gate 	struct entry	class_obj;
58*0Sstevel@tonic-gate 	struct entry	def_user_obj;
59*0Sstevel@tonic-gate 	struct entry	def_user;
60*0Sstevel@tonic-gate 	struct entry	def_group_obj;
61*0Sstevel@tonic-gate 	struct entry	def_group;
62*0Sstevel@tonic-gate 	struct entry	def_other_obj;
63*0Sstevel@tonic-gate 	struct entry	def_class_obj;
64*0Sstevel@tonic-gate };
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate static void free_mem(struct entry_stat *);
67*0Sstevel@tonic-gate static int check_dup(int, uid_t *, uid_t, struct entry_stat *);
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate int
70*0Sstevel@tonic-gate aclcheck(aclent_t *aclbufp, int nentries, int *which)
71*0Sstevel@tonic-gate {
72*0Sstevel@tonic-gate 	struct entry_stat	tally;
73*0Sstevel@tonic-gate 	aclent_t		*aclentp;
74*0Sstevel@tonic-gate 	uid_t			**idp;
75*0Sstevel@tonic-gate 	int			cnt;
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate 	*which = -1;
78*0Sstevel@tonic-gate 	memset(&tally, '\0', sizeof (tally));
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate 	for (aclentp = aclbufp; nentries > 0; nentries--, aclentp++) {
81*0Sstevel@tonic-gate 		switch (aclentp->a_type) {
82*0Sstevel@tonic-gate 		case USER_OBJ:
83*0Sstevel@tonic-gate 			/* check uniqueness */
84*0Sstevel@tonic-gate 			if (tally.user_obj.count > 0) {
85*0Sstevel@tonic-gate 				*which = (int) (aclentp - aclbufp);
86*0Sstevel@tonic-gate 				(void) free_mem(&tally);
87*0Sstevel@tonic-gate 				errno = EINVAL;
88*0Sstevel@tonic-gate 				return (USER_ERROR);
89*0Sstevel@tonic-gate 			}
90*0Sstevel@tonic-gate 			tally.user_obj.count = 1;
91*0Sstevel@tonic-gate 			break;
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate 		case GROUP_OBJ:
94*0Sstevel@tonic-gate 			/* check uniqueness */
95*0Sstevel@tonic-gate 			if (tally.group_obj.count > 0) {
96*0Sstevel@tonic-gate 				*which = (int) (aclentp - aclbufp);
97*0Sstevel@tonic-gate 				(void) free_mem(&tally);
98*0Sstevel@tonic-gate 				errno = EINVAL;
99*0Sstevel@tonic-gate 				return (GRP_ERROR);
100*0Sstevel@tonic-gate 			}
101*0Sstevel@tonic-gate 			tally.group_obj.count = 1;
102*0Sstevel@tonic-gate 			break;
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate 		case OTHER_OBJ:
105*0Sstevel@tonic-gate 			/* check uniqueness */
106*0Sstevel@tonic-gate 			if (tally.other_obj.count > 0) {
107*0Sstevel@tonic-gate 				*which = (int) (aclentp - aclbufp);
108*0Sstevel@tonic-gate 				(void) free_mem(&tally);
109*0Sstevel@tonic-gate 				errno = EINVAL;
110*0Sstevel@tonic-gate 				return (OTHER_ERROR);
111*0Sstevel@tonic-gate 			}
112*0Sstevel@tonic-gate 			tally.other_obj.count = 1;
113*0Sstevel@tonic-gate 			break;
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate 		case CLASS_OBJ:
116*0Sstevel@tonic-gate 			/* check uniqueness */
117*0Sstevel@tonic-gate 			if (tally.class_obj.count > 0) {
118*0Sstevel@tonic-gate 				*which = (int) (aclentp - aclbufp);
119*0Sstevel@tonic-gate 				(void) free_mem(&tally);
120*0Sstevel@tonic-gate 				errno = EINVAL;
121*0Sstevel@tonic-gate 				return (CLASS_ERROR);
122*0Sstevel@tonic-gate 			}
123*0Sstevel@tonic-gate 			tally.class_obj.count = 1;
124*0Sstevel@tonic-gate 			break;
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate 		case USER:
127*0Sstevel@tonic-gate 		case GROUP:
128*0Sstevel@tonic-gate 		case DEF_USER:
129*0Sstevel@tonic-gate 		case DEF_GROUP:
130*0Sstevel@tonic-gate 			/* check duplicate */
131*0Sstevel@tonic-gate 			if (aclentp->a_type == DEF_USER) {
132*0Sstevel@tonic-gate 				cnt = (tally.def_user.count)++;
133*0Sstevel@tonic-gate 				idp = &(tally.def_user.id);
134*0Sstevel@tonic-gate 			} else if (aclentp->a_type == DEF_GROUP) {
135*0Sstevel@tonic-gate 				cnt = (tally.def_group.count)++;
136*0Sstevel@tonic-gate 				idp = &(tally.def_group.id);
137*0Sstevel@tonic-gate 			} else if (aclentp->a_type == USER) {
138*0Sstevel@tonic-gate 				cnt = (tally.user.count)++;
139*0Sstevel@tonic-gate 				idp = &(tally.user.id);
140*0Sstevel@tonic-gate 			} else {
141*0Sstevel@tonic-gate 				cnt = (tally.group.count)++;
142*0Sstevel@tonic-gate 				idp = &(tally.group.id);
143*0Sstevel@tonic-gate 			}
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate 			if (cnt == 0) {
146*0Sstevel@tonic-gate 				*idp = calloc(nentries, sizeof (uid_t));
147*0Sstevel@tonic-gate 				if (*idp == NULL)
148*0Sstevel@tonic-gate 					return (MEM_ERROR);
149*0Sstevel@tonic-gate 			} else {
150*0Sstevel@tonic-gate 				if (check_dup(cnt, *idp, aclentp->a_id,
151*0Sstevel@tonic-gate 				    &tally) == -1) {
152*0Sstevel@tonic-gate 					*which = (int) (aclentp - aclbufp);
153*0Sstevel@tonic-gate 					return (DUPLICATE_ERROR);
154*0Sstevel@tonic-gate 				}
155*0Sstevel@tonic-gate 			}
156*0Sstevel@tonic-gate 			(*idp)[cnt] = aclentp->a_id;
157*0Sstevel@tonic-gate 			break;
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate 		case DEF_USER_OBJ:
160*0Sstevel@tonic-gate 			/* check uniqueness */
161*0Sstevel@tonic-gate 			if (tally.def_user_obj.count > 0) {
162*0Sstevel@tonic-gate 				*which = (int) (aclentp - aclbufp);
163*0Sstevel@tonic-gate 				(void) free_mem(&tally);
164*0Sstevel@tonic-gate 				errno = EINVAL;
165*0Sstevel@tonic-gate 				return (USER_ERROR);
166*0Sstevel@tonic-gate 			}
167*0Sstevel@tonic-gate 			tally.def_user_obj.count = 1;
168*0Sstevel@tonic-gate 			break;
169*0Sstevel@tonic-gate 
170*0Sstevel@tonic-gate 		case DEF_GROUP_OBJ:
171*0Sstevel@tonic-gate 			/* check uniqueness */
172*0Sstevel@tonic-gate 			if (tally.def_group_obj.count > 0) {
173*0Sstevel@tonic-gate 				*which = (int) (aclentp - aclbufp);
174*0Sstevel@tonic-gate 				(void) free_mem(&tally);
175*0Sstevel@tonic-gate 				errno = EINVAL;
176*0Sstevel@tonic-gate 				return (GRP_ERROR);
177*0Sstevel@tonic-gate 			}
178*0Sstevel@tonic-gate 			tally.def_group_obj.count = 1;
179*0Sstevel@tonic-gate 			break;
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 		case DEF_OTHER_OBJ:
182*0Sstevel@tonic-gate 			/* check uniqueness */
183*0Sstevel@tonic-gate 			if (tally.def_other_obj.count > 0) {
184*0Sstevel@tonic-gate 				*which = (int) (aclentp - aclbufp);
185*0Sstevel@tonic-gate 				(void) free_mem(&tally);
186*0Sstevel@tonic-gate 				errno = EINVAL;
187*0Sstevel@tonic-gate 				return (OTHER_ERROR);
188*0Sstevel@tonic-gate 			}
189*0Sstevel@tonic-gate 			tally.def_other_obj.count = 1;
190*0Sstevel@tonic-gate 			break;
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate 		case DEF_CLASS_OBJ:
193*0Sstevel@tonic-gate 			/* check uniqueness */
194*0Sstevel@tonic-gate 			if (tally.def_class_obj.count > 0) {
195*0Sstevel@tonic-gate 				*which = (int) (aclentp - aclbufp);
196*0Sstevel@tonic-gate 				(void) free_mem(&tally);
197*0Sstevel@tonic-gate 				errno = EINVAL;
198*0Sstevel@tonic-gate 				return (CLASS_ERROR);
199*0Sstevel@tonic-gate 			}
200*0Sstevel@tonic-gate 			tally.def_class_obj.count = 1;
201*0Sstevel@tonic-gate 			break;
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate 		default:
204*0Sstevel@tonic-gate 			(void) free_mem(&tally);
205*0Sstevel@tonic-gate 			errno = EINVAL;
206*0Sstevel@tonic-gate 			*which = (int) (aclentp - aclbufp);
207*0Sstevel@tonic-gate 			return (ENTRY_ERROR);
208*0Sstevel@tonic-gate 		}
209*0Sstevel@tonic-gate 	}
210*0Sstevel@tonic-gate 	/* If there are group or user entries, there must be one class entry */
211*0Sstevel@tonic-gate 	if (tally.user.count > 0 || tally.group.count > 0)
212*0Sstevel@tonic-gate 		if (tally.class_obj.count != 1) {
213*0Sstevel@tonic-gate 			(void) free_mem(&tally);
214*0Sstevel@tonic-gate 			errno = EINVAL;
215*0Sstevel@tonic-gate 			return (MISS_ERROR);
216*0Sstevel@tonic-gate 		}
217*0Sstevel@tonic-gate 	/* same is true for default entries */
218*0Sstevel@tonic-gate 	if (tally.def_user.count > 0 || tally.def_group.count > 0)
219*0Sstevel@tonic-gate 		if (tally.def_class_obj.count != 1) {
220*0Sstevel@tonic-gate 			(void) free_mem(&tally);
221*0Sstevel@tonic-gate 			errno = EINVAL;
222*0Sstevel@tonic-gate 			return (MISS_ERROR);
223*0Sstevel@tonic-gate 		}
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 	/* there must be exactly one user_obj, group_obj, and other_obj entry */
226*0Sstevel@tonic-gate 	if (tally.user_obj.count != 1 ||
227*0Sstevel@tonic-gate 	    tally.group_obj.count != 1 ||
228*0Sstevel@tonic-gate 		tally.other_obj.count != 1) {
229*0Sstevel@tonic-gate 		(void) free_mem(&tally);
230*0Sstevel@tonic-gate 		errno = EINVAL;
231*0Sstevel@tonic-gate 		return (MISS_ERROR);
232*0Sstevel@tonic-gate 	}
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 	/* has default? same rules apply to default entries */
235*0Sstevel@tonic-gate 	if (tally.def_user.count > 0 ||
236*0Sstevel@tonic-gate 	    tally.def_user_obj.count > 0 ||
237*0Sstevel@tonic-gate 	    tally.def_group.count > 0 ||
238*0Sstevel@tonic-gate 	    tally.def_group_obj.count > 0 ||
239*0Sstevel@tonic-gate 	    tally.def_class_obj.count > 0 ||
240*0Sstevel@tonic-gate 	    tally.def_other_obj.count > 0)
241*0Sstevel@tonic-gate 		if (tally.def_user_obj.count != 1 ||
242*0Sstevel@tonic-gate 		    tally.def_group_obj.count != 1 ||
243*0Sstevel@tonic-gate 		    tally.def_other_obj.count != 1) {
244*0Sstevel@tonic-gate 			(void) free_mem(&tally);
245*0Sstevel@tonic-gate 			errno = EINVAL;
246*0Sstevel@tonic-gate 			return (MISS_ERROR);
247*0Sstevel@tonic-gate 		}
248*0Sstevel@tonic-gate 	(void) free_mem(&tally);
249*0Sstevel@tonic-gate 	return (0);
250*0Sstevel@tonic-gate }
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate static void
253*0Sstevel@tonic-gate free_mem(struct entry_stat *tallyp)
254*0Sstevel@tonic-gate {
255*0Sstevel@tonic-gate 	if ((tallyp->user).count > 0)
256*0Sstevel@tonic-gate 		free((tallyp->user).id);
257*0Sstevel@tonic-gate 	if ((tallyp->group).count > 0)
258*0Sstevel@tonic-gate 		free((tallyp->group).id);
259*0Sstevel@tonic-gate 	if ((tallyp->def_user).count > 0)
260*0Sstevel@tonic-gate 		free((tallyp->def_user).id);
261*0Sstevel@tonic-gate 	if ((tallyp->def_group).count > 0)
262*0Sstevel@tonic-gate 		free((tallyp->def_group).id);
263*0Sstevel@tonic-gate }
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate static int
266*0Sstevel@tonic-gate check_dup(int count, uid_t *ids, uid_t newid, struct entry_stat *tallyp)
267*0Sstevel@tonic-gate {
268*0Sstevel@tonic-gate 	int	i;
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
271*0Sstevel@tonic-gate 		if (ids[i] == newid) {
272*0Sstevel@tonic-gate 			errno = EINVAL;
273*0Sstevel@tonic-gate 			(void) free_mem(tallyp);
274*0Sstevel@tonic-gate 			return (-1);
275*0Sstevel@tonic-gate 		}
276*0Sstevel@tonic-gate 	}
277*0Sstevel@tonic-gate 	return (0);
278*0Sstevel@tonic-gate }
279