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