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