summaryrefslogtreecommitdiff
path: root/usr/src/lib/libsec/common/aclsort.c
blob: 784ff36c725baa74cb287dc4747a3cc201a3039c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright (c) 1993-1997 by Sun Microsystems, Inc.
 * All rights reserved
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"
/*LINTLIBRARY*/

/*
 * aclsort():
 *	Sort an ACL by entry type according to the following order:
 *	USER_OBJ, USER, GROUP_OBJ, GROUP, CLASS_OBJ, OTHER_OBJ
 *	DEF_USER_OBJ, DEF_USER, DEF_GROUP_OBJ, DEF_GROUP, DEF_CLASS_OBJ,
 *	DEF_OTHER_OBJ.
 *	For USER, GROUP, DEF_USER, and DEF_GROUP entries, the entries
 *	are further sorted by ids.
 */

#include <stdlib.h>
#include <sys/acl.h>

#define	TOTAL_ENTRY_TYPES	12

/*
 * This maps the entry defined value to a value for sorting.
 * These values may not be the same. It is easier to add an
 * entry type with this map.
 *
 * Because the defines and sorting order are not the same,
 * the following map_to_sort table is needed.
 */
struct map {
	int	sort_order;
	int	entry_type;
};

static struct map map_to_sort[] = {
		{0, 0}, /* UNUSED */
		{1,	USER_OBJ},
		{2,	USER},
		{3, 	GROUP_OBJ},
		{4,	GROUP},
		{5,	CLASS_OBJ},
		{6, 	OTHER_OBJ},
		{7, 	DEF_USER_OBJ},
		{8, 	DEF_USER},
		{9, 	DEF_GROUP_OBJ},
		{10,	DEF_GROUP},
		{11,	DEF_CLASS_OBJ},
		{12,	DEF_OTHER_OBJ},
};

static int entrycmp(const aclent_t *, const aclent_t *);
static int idcmp(const aclent_t *, const aclent_t *);
static void sortid(aclent_t *, int, int);

int
aclsort(int nentries, int calcmask, aclent_t *aclbufp)
{
	aclent_t		*tp;
	unsigned int		newmask = 0;
	int			which;
	int			i;
	int			k;

	/* check validity first before sorting */
	if (aclcheck(aclbufp, nentries, &which) != 0)
		return (-1);

	/*
	 * Performance enhancement:
	 * We change entry type to sort order in the ACL, do the sorting.
	 * We then change sort order back to entry type.
	 * This makes entrycmp() very "light" and thus improves performance.
	 * Contrast to original implementation that had to find out
	 * the sorting order each time it is called.
	 */
	for (tp = aclbufp, i = 0; i < nentries; tp++, i++) {
		for (k = 1; k <= TOTAL_ENTRY_TYPES; k++) {
			if (tp->a_type == map_to_sort[k].entry_type) {
				tp->a_type = map_to_sort[k].sort_order;
				break;
			}
		}
	}

	/* typecast to remove incompatible type warning */
	qsort(aclbufp, nentries, sizeof (aclent_t),
	    (int (*)(const void *, const void *))entrycmp);

	for (tp = aclbufp, i = 0; i < nentries; tp++, i++) {
		for (k = 1; k <= TOTAL_ENTRY_TYPES; k++) {
			if (tp->a_type == map_to_sort[k].sort_order) {
				tp->a_type = map_to_sort[k].entry_type;
				break;
			}
		}
	}

	/*
	 * Start sorting id within USER and GROUP
	 * sortid() could return a pointer and entries left
	 * so that we dont have to search from the beginning
	 *  every time it calls
	 */
	sortid(aclbufp, nentries, USER);
	sortid(aclbufp, nentries, GROUP);
	sortid(aclbufp, nentries, DEF_USER);
	sortid(aclbufp, nentries, DEF_GROUP);

	/*
	 * Recalculate mask entry
	 */
	if (calcmask != 0) {
		/*
		 * At this point, ACL is valid and sorted. We may find a
		 * CLASS_OBJ entry and stop. Because of the case of minimum ACL,
		 * we still have to check till OTHER_OBJ entry is shown.
		 */
		for (tp = aclbufp; tp->a_type != OTHER_OBJ; tp++) {
			if (tp->a_type == USER || tp->a_type == GROUP ||
			    tp->a_type == GROUP_OBJ)
				newmask |= tp->a_perm;
			if (tp->a_type == CLASS_OBJ)
				break;
		}
		if (tp->a_type == CLASS_OBJ)
			tp->a_perm = (unsigned char)newmask;
	}
	return (0);
}

/*
 * sortid() sorts the ids with the same entry type in increasing order
 */
static void
sortid(aclent_t *ap, int cnt, int type)
{
	aclent_t	*tp;
	aclent_t	*startp; /* start of the desired entry type */
	int		howmany;

	for (tp = ap; cnt-- > 0; tp++) {
		if (tp->a_type != type)
			continue;
		startp = tp;
		howmany = 1;
		for (tp++, cnt--; cnt > 0 && tp->a_type == type; tp++, cnt--)
			howmany++;
		/* typecast to remove incompatible type warning */
		qsort(startp, howmany, sizeof (aclent_t),
		    (int (*)(const void*, const void*))idcmp);
	}
}

/*
 * compare the field a_type
 */
static int
entrycmp(const aclent_t *i, const aclent_t *j)
{
	return ((int)(i->a_type) - (int)(j->a_type));
}

/*
 * compare the field a_id
 */
static int
idcmp(const aclent_t *i, const aclent_t *j)
{
	return ((int)(i->a_id) - (int)(j->a_id));
}