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 /*
24 * Copyright (c) 1993-1997 by Sun Microsystems, Inc.
25 * All rights reserved
26 */
27
28 #pragma ident "%Z%%M% %I% %E% SMI"
29 /*LINTLIBRARY*/
30
31 /*
32 * aclsort():
33 * Sort an ACL by entry type according to the following order:
34 * USER_OBJ, USER, GROUP_OBJ, GROUP, CLASS_OBJ, OTHER_OBJ
35 * DEF_USER_OBJ, DEF_USER, DEF_GROUP_OBJ, DEF_GROUP, DEF_CLASS_OBJ,
36 * DEF_OTHER_OBJ.
37 * For USER, GROUP, DEF_USER, and DEF_GROUP entries, the entries
38 * are further sorted by ids.
39 */
40
41 #include <stdlib.h>
42 #include <sys/acl.h>
43
44 #define TOTAL_ENTRY_TYPES 12
45
46 /*
47 * This maps the entry defined value to a value for sorting.
48 * These values may not be the same. It is easier to add an
49 * entry type with this map.
50 *
51 * Because the defines and sorting order are not the same,
52 * the following map_to_sort table is needed.
53 */
54 struct map {
55 int sort_order;
56 int entry_type;
57 };
58
59 static struct map map_to_sort[] = {
60 {0, 0}, /* UNUSED */
61 {1, USER_OBJ},
62 {2, USER},
63 {3, GROUP_OBJ},
64 {4, GROUP},
65 {5, CLASS_OBJ},
66 {6, OTHER_OBJ},
67 {7, DEF_USER_OBJ},
68 {8, DEF_USER},
69 {9, DEF_GROUP_OBJ},
70 {10, DEF_GROUP},
71 {11, DEF_CLASS_OBJ},
72 {12, DEF_OTHER_OBJ},
73 };
74
75 static int entrycmp(const aclent_t *, const aclent_t *);
76 static int idcmp(const aclent_t *, const aclent_t *);
77 static void sortid(aclent_t *, int, int);
78
79 int
aclsort(int nentries,int calcmask,aclent_t * aclbufp)80 aclsort(int nentries, int calcmask, aclent_t *aclbufp)
81 {
82 aclent_t *tp;
83 unsigned int newmask = 0;
84 int which;
85 int i;
86 int k;
87
88 /* check validity first before sorting */
89 if (aclcheck(aclbufp, nentries, &which) != 0)
90 return (-1);
91
92 /*
93 * Performance enhancement:
94 * We change entry type to sort order in the ACL, do the sorting.
95 * We then change sort order back to entry type.
96 * This makes entrycmp() very "light" and thus improves performance.
97 * Contrast to original implementation that had to find out
98 * the sorting order each time it is called.
99 */
100 for (tp = aclbufp, i = 0; i < nentries; tp++, i++) {
101 for (k = 1; k <= TOTAL_ENTRY_TYPES; k++) {
102 if (tp->a_type == map_to_sort[k].entry_type) {
103 tp->a_type = map_to_sort[k].sort_order;
104 break;
105 }
106 }
107 }
108
109 /* typecast to remove incompatible type warning */
110 qsort(aclbufp, nentries, sizeof (aclent_t),
111 (int (*)(const void *, const void *))entrycmp);
112
113 for (tp = aclbufp, i = 0; i < nentries; tp++, i++) {
114 for (k = 1; k <= TOTAL_ENTRY_TYPES; k++) {
115 if (tp->a_type == map_to_sort[k].sort_order) {
116 tp->a_type = map_to_sort[k].entry_type;
117 break;
118 }
119 }
120 }
121
122 /*
123 * Start sorting id within USER and GROUP
124 * sortid() could return a pointer and entries left
125 * so that we dont have to search from the beginning
126 * every time it calls
127 */
128 sortid(aclbufp, nentries, USER);
129 sortid(aclbufp, nentries, GROUP);
130 sortid(aclbufp, nentries, DEF_USER);
131 sortid(aclbufp, nentries, DEF_GROUP);
132
133 /*
134 * Recalculate mask entry
135 */
136 if (calcmask != 0) {
137 /*
138 * At this point, ACL is valid and sorted. We may find a
139 * CLASS_OBJ entry and stop. Because of the case of minimum ACL,
140 * we still have to check till OTHER_OBJ entry is shown.
141 */
142 for (tp = aclbufp; tp->a_type != OTHER_OBJ; tp++) {
143 if (tp->a_type == USER || tp->a_type == GROUP ||
144 tp->a_type == GROUP_OBJ)
145 newmask |= tp->a_perm;
146 if (tp->a_type == CLASS_OBJ)
147 break;
148 }
149 if (tp->a_type == CLASS_OBJ)
150 tp->a_perm = (unsigned char)newmask;
151 }
152 return (0);
153 }
154
155 /*
156 * sortid() sorts the ids with the same entry type in increasing order
157 */
158 static void
sortid(aclent_t * ap,int cnt,int type)159 sortid(aclent_t *ap, int cnt, int type)
160 {
161 aclent_t *tp;
162 aclent_t *startp; /* start of the desired entry type */
163 int howmany;
164
165 for (tp = ap; cnt-- > 0; tp++) {
166 if (tp->a_type != type)
167 continue;
168 startp = tp;
169 howmany = 1;
170 for (tp++, cnt--; cnt > 0 && tp->a_type == type; tp++, cnt--)
171 howmany++;
172 /* typecast to remove incompatible type warning */
173 qsort(startp, howmany, sizeof (aclent_t),
174 (int (*)(const void*, const void*))idcmp);
175 }
176 }
177
178 /*
179 * compare the field a_type
180 */
181 static int
entrycmp(const aclent_t * i,const aclent_t * j)182 entrycmp(const aclent_t *i, const aclent_t *j)
183 {
184 return ((int)(i->a_type) - (int)(j->a_type));
185 }
186
187 /*
188 * compare the field a_id
189 */
190 static int
idcmp(const aclent_t * i,const aclent_t * j)191 idcmp(const aclent_t *i, const aclent_t *j)
192 {
193 return ((int)(i->a_id) - (int)(j->a_id));
194 }
195