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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 1993-1997 by Sun Microsystems, Inc.
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 
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 int
70 aclcheck(aclent_t *aclbufp, int nentries, int *which)
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 (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 (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 (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 (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 (MEM_ERROR);
149 			} else {
150 				if (check_dup(cnt, *idp, aclentp->a_id,
151 				    &tally) == -1) {
152 					*which = (int) (aclentp - aclbufp);
153 					return (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 (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 (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 (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 (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 (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 (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 (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 (MISS_ERROR);
232 	}
233 
234 	/* has default? same rules apply to default entries */
235 	if (tally.def_user.count > 0 ||
236 	    tally.def_user_obj.count > 0 ||
237 	    tally.def_group.count > 0 ||
238 	    tally.def_group_obj.count > 0 ||
239 	    tally.def_class_obj.count > 0 ||
240 	    tally.def_other_obj.count > 0)
241 		if (tally.def_user_obj.count != 1 ||
242 		    tally.def_group_obj.count != 1 ||
243 		    tally.def_other_obj.count != 1) {
244 			(void) free_mem(&tally);
245 			errno = EINVAL;
246 			return (MISS_ERROR);
247 		}
248 	(void) free_mem(&tally);
249 	return (0);
250 }
251 
252 static void
253 free_mem(struct entry_stat *tallyp)
254 {
255 	if ((tallyp->user).count > 0)
256 		free((tallyp->user).id);
257 	if ((tallyp->group).count > 0)
258 		free((tallyp->group).id);
259 	if ((tallyp->def_user).count > 0)
260 		free((tallyp->def_user).id);
261 	if ((tallyp->def_group).count > 0)
262 		free((tallyp->def_group).id);
263 }
264 
265 static int
266 check_dup(int count, uid_t *ids, uid_t newid, struct entry_stat *tallyp)
267 {
268 	int	i;
269 
270 	for (i = 0; i < count; i++) {
271 		if (ids[i] == newid) {
272 			errno = EINVAL;
273 			(void) free_mem(tallyp);
274 			return (-1);
275 		}
276 	}
277 	return (0);
278 }
279