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 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 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 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 191 idcmp(const aclent_t *i, const aclent_t *j) 192 { 193 return ((int)(i->a_id) - (int)(j->a_id)); 194 } 195