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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /*LINTLIBRARY*/ 27 28 /* 29 * aclcheck(): check validity of an ACL 30 * A valid ACL is defined as follows: 31 * There must be exactly one USER_OBJ, GROUP_OBJ, and OTHER_OBJ entry. 32 * If there are any USER entries, then the user id must be unique. 33 * If there are any GROUP entries, then the group id must be unique. 34 * If there are any GROUP or USER entries, there must be exactly one 35 * CLASS_OBJ entry. 36 * The same rules apply to default ACL entries. 37 */ 38 39 #include <errno.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <sys/types.h> 43 #include <sys/acl.h> 44 #include <aclutils.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 static int 70 aclent_aclcheck(aclent_t *aclbufp, int nentries, int *which, int isdir) 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 (EACL_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 (EACL_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 (EACL_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 (EACL_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 (EACL_MEM_ERROR); 149 } else { 150 if (check_dup(cnt, *idp, aclentp->a_id, 151 &tally) == -1) { 152 *which = (int)(aclentp - aclbufp); 153 return (EACL_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 (EACL_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 (EACL_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 (EACL_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 (EACL_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 (EACL_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 (EACL_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 (EACL_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 (EACL_MISS_ERROR); 232 } 233 234 /* has default? same rules apply to default entries */ 235 if (tally.def_user.count > 0 || tally.def_user_obj.count > 0 || 236 tally.def_group.count > 0 || tally.def_group_obj.count > 0 || 237 tally.def_class_obj.count > 0 || tally.def_other_obj.count > 0) { 238 239 /* 240 * Can't have default ACL's on non-directories 241 */ 242 if (isdir == 0) { 243 (void) free_mem(&tally); 244 errno = EINVAL; 245 return (EACL_INHERIT_NOTDIR); 246 } 247 248 if (tally.def_user_obj.count != 1 || 249 tally.def_group_obj.count != 1 || 250 tally.def_other_obj.count != 1) { 251 (void) free_mem(&tally); 252 errno = EINVAL; 253 return (EACL_MISS_ERROR); 254 } 255 } 256 257 (void) free_mem(&tally); 258 return (0); 259 } 260 261 int 262 aclcheck(aclent_t *aclbufp, int nentries, int *which) 263 { 264 return (aclent_aclcheck(aclbufp, nentries, which, 1)); 265 } 266 267 268 static void 269 free_mem(struct entry_stat *tallyp) 270 { 271 if ((tallyp->user).count > 0) 272 free((tallyp->user).id); 273 if ((tallyp->group).count > 0) 274 free((tallyp->group).id); 275 if ((tallyp->def_user).count > 0) 276 free((tallyp->def_user).id); 277 if ((tallyp->def_group).count > 0) 278 free((tallyp->def_group).id); 279 } 280 281 static int 282 check_dup(int count, uid_t *ids, uid_t newid, struct entry_stat *tallyp) 283 { 284 int i; 285 286 for (i = 0; i < count; i++) { 287 if (ids[i] == newid) { 288 errno = EINVAL; 289 (void) free_mem(tallyp); 290 return (-1); 291 } 292 } 293 return (0); 294 } 295 296 #define IFLAGS (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE| \ 297 ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE) 298 299 static int 300 ace_aclcheck(acl_t *aclp, int isdir) 301 { 302 ace_t *acep; 303 int i; 304 int error = 0; 305 306 /* 307 * step through all valid flags. 308 */ 309 310 if (aclp->acl_cnt <= 0 || aclp->acl_cnt > MAX_ACL_ENTRIES) 311 return (EACL_COUNT_ERROR); 312 313 for (i = 0, acep = aclp->acl_aclp; 314 i != aclp->acl_cnt && error == 0; i++, acep++) { 315 switch (acep->a_flags & 0xf040) { 316 case 0: 317 case ACE_OWNER: 318 case ACE_EVERYONE: 319 case ACE_IDENTIFIER_GROUP: 320 case ACE_GROUP|ACE_IDENTIFIER_GROUP: 321 break; 322 default: 323 errno = EINVAL; 324 return (EACL_FLAGS_ERROR); 325 } 326 327 /* 328 * INHERIT_ONLY/NO_PROPAGATE need a to INHERIT_FILE 329 * or INHERIT_DIR also 330 */ 331 if (acep->a_flags & 332 (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) { 333 if ((acep->a_flags & (ACE_FILE_INHERIT_ACE| 334 ACE_DIRECTORY_INHERIT_ACE)) == 0) { 335 errno = EINVAL; 336 return (EACL_INHERIT_ERROR); 337 } 338 break; 339 } 340 341 switch (acep->a_type) { 342 case ACE_ACCESS_ALLOWED_ACE_TYPE: 343 case ACE_ACCESS_DENIED_ACE_TYPE: 344 case ACE_SYSTEM_AUDIT_ACE_TYPE: 345 case ACE_SYSTEM_ALARM_ACE_TYPE: 346 break; 347 default: 348 errno = EINVAL; 349 return (EACL_ENTRY_ERROR); 350 } 351 if (acep->a_access_mask > ACE_ALL_PERMS) { 352 errno = EINVAL; 353 return (EACL_PERM_MASK_ERROR); 354 } 355 } 356 357 return (0); 358 } 359 360 int 361 acl_check(acl_t *aclp, int flag) 362 { 363 int error; 364 int where; 365 366 switch (aclp->acl_type) { 367 case ACLENT_T: 368 error = aclent_aclcheck(aclp->acl_aclp, aclp->acl_cnt, 369 &where, flag); 370 break; 371 case ACE_T: 372 error = ace_aclcheck(aclp, flag); 373 break; 374 default: 375 errno = EINVAL; 376 error = EACL_ENTRY_ERROR; 377 } 378 return (error); 379 } 380