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 #pragma ident "%Z%%M% %I% %E% SMI" 27 /*LINTLIBRARY*/ 28 29 /* 30 * aclcheck(): check validity of an ACL 31 * A valid ACL is defined as follows: 32 * There must be exactly one USER_OBJ, GROUP_OBJ, and OTHER_OBJ entry. 33 * If there are any USER entries, then the user id must be unique. 34 * If there are any GROUP entries, then the group id must be unique. 35 * If there are any GROUP or USER entries, there must be exactly one 36 * CLASS_OBJ entry. 37 * The same rules apply to default ACL entries. 38 */ 39 40 #include <errno.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <sys/types.h> 44 #include <sys/acl.h> 45 #include <aclutils.h> 46 47 struct entry { 48 int count; 49 uid_t *id; 50 }; 51 52 struct entry_stat { 53 struct entry user_obj; 54 struct entry user; 55 struct entry group_obj; 56 struct entry group; 57 struct entry other_obj; 58 struct entry class_obj; 59 struct entry def_user_obj; 60 struct entry def_user; 61 struct entry def_group_obj; 62 struct entry def_group; 63 struct entry def_other_obj; 64 struct entry def_class_obj; 65 }; 66 67 static void free_mem(struct entry_stat *); 68 static int check_dup(int, uid_t *, uid_t, struct entry_stat *); 69 70 static int 71 aclent_aclcheck(aclent_t *aclbufp, int nentries, int *which, int isdir) 72 { 73 struct entry_stat tally; 74 aclent_t *aclentp; 75 uid_t **idp; 76 int cnt; 77 78 *which = -1; 79 memset(&tally, '\0', sizeof (tally)); 80 81 for (aclentp = aclbufp; nentries > 0; nentries--, aclentp++) { 82 switch (aclentp->a_type) { 83 case USER_OBJ: 84 /* check uniqueness */ 85 if (tally.user_obj.count > 0) { 86 *which = (int)(aclentp - aclbufp); 87 (void) free_mem(&tally); 88 errno = EINVAL; 89 return (EACL_USER_ERROR); 90 } 91 tally.user_obj.count = 1; 92 break; 93 94 case GROUP_OBJ: 95 /* check uniqueness */ 96 if (tally.group_obj.count > 0) { 97 *which = (int)(aclentp - aclbufp); 98 (void) free_mem(&tally); 99 errno = EINVAL; 100 return (EACL_GRP_ERROR); 101 } 102 tally.group_obj.count = 1; 103 break; 104 105 case OTHER_OBJ: 106 /* check uniqueness */ 107 if (tally.other_obj.count > 0) { 108 *which = (int)(aclentp - aclbufp); 109 (void) free_mem(&tally); 110 errno = EINVAL; 111 return (EACL_OTHER_ERROR); 112 } 113 tally.other_obj.count = 1; 114 break; 115 116 case CLASS_OBJ: 117 /* check uniqueness */ 118 if (tally.class_obj.count > 0) { 119 *which = (int)(aclentp - aclbufp); 120 (void) free_mem(&tally); 121 errno = EINVAL; 122 return (EACL_CLASS_ERROR); 123 } 124 tally.class_obj.count = 1; 125 break; 126 127 case USER: 128 case GROUP: 129 case DEF_USER: 130 case DEF_GROUP: 131 /* check duplicate */ 132 if (aclentp->a_type == DEF_USER) { 133 cnt = (tally.def_user.count)++; 134 idp = &(tally.def_user.id); 135 } else if (aclentp->a_type == DEF_GROUP) { 136 cnt = (tally.def_group.count)++; 137 idp = &(tally.def_group.id); 138 } else if (aclentp->a_type == USER) { 139 cnt = (tally.user.count)++; 140 idp = &(tally.user.id); 141 } else { 142 cnt = (tally.group.count)++; 143 idp = &(tally.group.id); 144 } 145 146 if (cnt == 0) { 147 *idp = calloc(nentries, sizeof (uid_t)); 148 if (*idp == NULL) 149 return (EACL_MEM_ERROR); 150 } else { 151 if (check_dup(cnt, *idp, aclentp->a_id, 152 &tally) == -1) { 153 *which = (int)(aclentp - aclbufp); 154 return (EACL_DUPLICATE_ERROR); 155 } 156 } 157 (*idp)[cnt] = aclentp->a_id; 158 break; 159 160 case DEF_USER_OBJ: 161 /* check uniqueness */ 162 if (tally.def_user_obj.count > 0) { 163 *which = (int)(aclentp - aclbufp); 164 (void) free_mem(&tally); 165 errno = EINVAL; 166 return (EACL_USER_ERROR); 167 } 168 tally.def_user_obj.count = 1; 169 break; 170 171 case DEF_GROUP_OBJ: 172 /* check uniqueness */ 173 if (tally.def_group_obj.count > 0) { 174 *which = (int)(aclentp - aclbufp); 175 (void) free_mem(&tally); 176 errno = EINVAL; 177 return (EACL_GRP_ERROR); 178 } 179 tally.def_group_obj.count = 1; 180 break; 181 182 case DEF_OTHER_OBJ: 183 /* check uniqueness */ 184 if (tally.def_other_obj.count > 0) { 185 *which = (int)(aclentp - aclbufp); 186 (void) free_mem(&tally); 187 errno = EINVAL; 188 return (EACL_OTHER_ERROR); 189 } 190 tally.def_other_obj.count = 1; 191 break; 192 193 case DEF_CLASS_OBJ: 194 /* check uniqueness */ 195 if (tally.def_class_obj.count > 0) { 196 *which = (int)(aclentp - aclbufp); 197 (void) free_mem(&tally); 198 errno = EINVAL; 199 return (EACL_CLASS_ERROR); 200 } 201 tally.def_class_obj.count = 1; 202 break; 203 204 default: 205 (void) free_mem(&tally); 206 errno = EINVAL; 207 *which = (int)(aclentp - aclbufp); 208 return (EACL_ENTRY_ERROR); 209 } 210 } 211 /* If there are group or user entries, there must be one class entry */ 212 if (tally.user.count > 0 || tally.group.count > 0) 213 if (tally.class_obj.count != 1) { 214 (void) free_mem(&tally); 215 errno = EINVAL; 216 return (EACL_MISS_ERROR); 217 } 218 /* same is true for default entries */ 219 if (tally.def_user.count > 0 || tally.def_group.count > 0) 220 if (tally.def_class_obj.count != 1) { 221 (void) free_mem(&tally); 222 errno = EINVAL; 223 return (EACL_MISS_ERROR); 224 } 225 226 /* there must be exactly one user_obj, group_obj, and other_obj entry */ 227 if (tally.user_obj.count != 1 || 228 tally.group_obj.count != 1 || 229 tally.other_obj.count != 1) { 230 (void) free_mem(&tally); 231 errno = EINVAL; 232 return (EACL_MISS_ERROR); 233 } 234 235 /* has default? same rules apply to default entries */ 236 if (tally.def_user.count > 0 || tally.def_user_obj.count > 0 || 237 tally.def_group.count > 0 || tally.def_group_obj.count > 0 || 238 tally.def_class_obj.count > 0 || tally.def_other_obj.count > 0) { 239 240 /* 241 * Can't have default ACL's on non-directories 242 */ 243 if (isdir == 0) { 244 (void) free_mem(&tally); 245 errno = EINVAL; 246 return (EACL_INHERIT_NOTDIR); 247 } 248 249 if (tally.def_user_obj.count != 1 || 250 tally.def_group_obj.count != 1 || 251 tally.def_other_obj.count != 1) { 252 (void) free_mem(&tally); 253 errno = EINVAL; 254 return (EACL_MISS_ERROR); 255 } 256 } 257 258 (void) free_mem(&tally); 259 return (0); 260 } 261 262 int 263 aclcheck(aclent_t *aclbufp, int nentries, int *which) 264 { 265 return (aclent_aclcheck(aclbufp, nentries, which, 1)); 266 } 267 268 269 static void 270 free_mem(struct entry_stat *tallyp) 271 { 272 if ((tallyp->user).count > 0) 273 free((tallyp->user).id); 274 if ((tallyp->group).count > 0) 275 free((tallyp->group).id); 276 if ((tallyp->def_user).count > 0) 277 free((tallyp->def_user).id); 278 if ((tallyp->def_group).count > 0) 279 free((tallyp->def_group).id); 280 } 281 282 static int 283 check_dup(int count, uid_t *ids, uid_t newid, struct entry_stat *tallyp) 284 { 285 int i; 286 287 for (i = 0; i < count; i++) { 288 if (ids[i] == newid) { 289 errno = EINVAL; 290 (void) free_mem(tallyp); 291 return (-1); 292 } 293 } 294 return (0); 295 } 296 297 #define IFLAGS (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE| \ 298 ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE) 299 300 static int 301 ace_aclcheck(acl_t *aclp, int isdir) 302 { 303 ace_t *acep; 304 int i; 305 int error = 0; 306 307 /* 308 * step through all valid flags. 309 */ 310 311 if (aclp->acl_cnt <= 0 || aclp->acl_cnt > MAX_ACL_ENTRIES) 312 return (EACL_COUNT_ERROR); 313 314 for (i = 0, acep = aclp->acl_aclp; 315 i != aclp->acl_cnt && error == 0; i++, acep++) { 316 switch (acep->a_flags & 0xf040) { 317 case 0: 318 case ACE_OWNER: 319 case ACE_EVERYONE: 320 case ACE_IDENTIFIER_GROUP: 321 case ACE_GROUP|ACE_IDENTIFIER_GROUP: 322 break; 323 default: 324 errno = EINVAL; 325 return (EACL_FLAGS_ERROR); 326 } 327 328 /* 329 * INHERIT_ONLY/NO_PROPAGATE need a to INHERIT_FILE 330 * or INHERIT_DIR also 331 */ 332 if (acep->a_flags & 333 (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) { 334 if ((acep->a_flags & (ACE_FILE_INHERIT_ACE| 335 ACE_DIRECTORY_INHERIT_ACE)) == 0) { 336 errno = EINVAL; 337 return (EACL_INHERIT_ERROR); 338 } 339 break; 340 } 341 342 switch (acep->a_type) { 343 case ACE_ACCESS_ALLOWED_ACE_TYPE: 344 case ACE_ACCESS_DENIED_ACE_TYPE: 345 case ACE_SYSTEM_AUDIT_ACE_TYPE: 346 case ACE_SYSTEM_ALARM_ACE_TYPE: 347 break; 348 default: 349 errno = EINVAL; 350 return (EACL_ENTRY_ERROR); 351 } 352 if (acep->a_access_mask > ACE_ALL_PERMS) { 353 errno = EINVAL; 354 return (EACL_PERM_MASK_ERROR); 355 } 356 } 357 358 return (0); 359 } 360 361 int 362 acl_check(acl_t *aclp, int flag) 363 { 364 int error; 365 int where; 366 367 switch (aclp->acl_type) { 368 case ACLENT_T: 369 error = aclent_aclcheck(aclp->acl_aclp, aclp->acl_cnt, 370 &where, flag); 371 break; 372 case ACE_T: 373 error = ace_aclcheck(aclp, flag); 374 break; 375 default: 376 errno = EINVAL; 377 error = EACL_ENTRY_ERROR; 378 } 379 return (error); 380 } 381