1 /*- 2 * Copyright (c) 1999-2006 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * This software was developed by Robert Watson for the TrustedBSD Project. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 /* 29 * Developed by the TrustedBSD Project. 30 * 31 * ACL support routines specific to POSIX.1e access control lists. These are 32 * utility routines for code common across file systems implementing POSIX.1e 33 * ACLs. 34 */ 35 36 #include <sys/cdefs.h> 37 __FBSDID("$FreeBSD$"); 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/mount.h> 42 #include <sys/priv.h> 43 #include <sys/vnode.h> 44 #include <sys/errno.h> 45 #include <sys/stat.h> 46 #include <sys/acl.h> 47 48 /* 49 * Implement a version of vaccess() that understands POSIX.1e ACL semantics; 50 * the access ACL has already been prepared for evaluation by the file system 51 * and is passed via 'uid', 'gid', and 'acl'. Return 0 on success, else an 52 * errno value. 53 */ 54 int 55 vaccess_acl_posix1e(enum vtype type, uid_t file_uid, gid_t file_gid, 56 struct acl *acl, accmode_t accmode, struct ucred *cred, int *privused) 57 { 58 struct acl_entry *acl_other, *acl_mask; 59 accmode_t dac_granted; 60 accmode_t priv_granted; 61 accmode_t acl_mask_granted; 62 int group_matched, i; 63 64 KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND)) == 0, 65 ("invalid bit in accmode")); 66 67 /* 68 * Look for a normal, non-privileged way to access the file/directory 69 * as requested. If it exists, go with that. Otherwise, attempt to 70 * use privileges granted via priv_granted. In some cases, which 71 * privileges to use may be ambiguous due to "best match", in which 72 * case fall back on first match for the time being. 73 */ 74 if (privused != NULL) 75 *privused = 0; 76 77 /* 78 * Determine privileges now, but don't apply until we've found a DAC 79 * entry that matches but has failed to allow access. 80 * 81 * XXXRW: Ideally, we'd determine the privileges required before 82 * asking for them. 83 */ 84 priv_granted = 0; 85 86 if (type == VDIR) { 87 if ((accmode & VEXEC) && !priv_check_cred(cred, 88 PRIV_VFS_LOOKUP, 0)) 89 priv_granted |= VEXEC; 90 } else { 91 if ((accmode & VEXEC) && !priv_check_cred(cred, 92 PRIV_VFS_EXEC, 0)) 93 priv_granted |= VEXEC; 94 } 95 96 if ((accmode & VREAD) && !priv_check_cred(cred, PRIV_VFS_READ, 0)) 97 priv_granted |= VREAD; 98 99 if (((accmode & VWRITE) || (accmode & VAPPEND)) && 100 !priv_check_cred(cred, PRIV_VFS_WRITE, 0)) 101 priv_granted |= (VWRITE | VAPPEND); 102 103 if ((accmode & VADMIN) && !priv_check_cred(cred, PRIV_VFS_ADMIN, 0)) 104 priv_granted |= VADMIN; 105 106 /* 107 * The owner matches if the effective uid associated with the 108 * credential matches that of the ACL_USER_OBJ entry. While we're 109 * doing the first scan, also cache the location of the ACL_MASK and 110 * ACL_OTHER entries, preventing some future iterations. 111 */ 112 acl_mask = acl_other = NULL; 113 for (i = 0; i < acl->acl_cnt; i++) { 114 switch (acl->acl_entry[i].ae_tag) { 115 case ACL_USER_OBJ: 116 if (file_uid != cred->cr_uid) 117 break; 118 dac_granted = 0; 119 dac_granted |= VADMIN; 120 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE) 121 dac_granted |= VEXEC; 122 if (acl->acl_entry[i].ae_perm & ACL_READ) 123 dac_granted |= VREAD; 124 if (acl->acl_entry[i].ae_perm & ACL_WRITE) 125 dac_granted |= (VWRITE | VAPPEND); 126 if ((accmode & dac_granted) == accmode) 127 return (0); 128 129 /* 130 * XXXRW: Do privilege lookup here. 131 */ 132 if ((accmode & (dac_granted | priv_granted)) == 133 accmode) { 134 if (privused != NULL) 135 *privused = 1; 136 return (0); 137 } 138 goto error; 139 140 case ACL_MASK: 141 acl_mask = &acl->acl_entry[i]; 142 break; 143 144 case ACL_OTHER: 145 acl_other = &acl->acl_entry[i]; 146 break; 147 148 default: 149 break; 150 } 151 } 152 153 /* 154 * An ACL_OTHER entry should always exist in a valid access ACL. If 155 * it doesn't, then generate a serious failure. For now, this means 156 * a debugging message and EPERM, but in the future should probably 157 * be a panic. 158 */ 159 if (acl_other == NULL) { 160 /* 161 * XXX This should never happen 162 */ 163 printf("vaccess_acl_posix1e: ACL_OTHER missing\n"); 164 return (EPERM); 165 } 166 167 /* 168 * Checks against ACL_USER, ACL_GROUP_OBJ, and ACL_GROUP fields are 169 * masked by an ACL_MASK entry, if any. As such, first identify the 170 * ACL_MASK field, then iterate through identifying potential user 171 * matches, then group matches. If there is no ACL_MASK, assume that 172 * the mask allows all requests to succeed. 173 */ 174 if (acl_mask != NULL) { 175 acl_mask_granted = 0; 176 if (acl_mask->ae_perm & ACL_EXECUTE) 177 acl_mask_granted |= VEXEC; 178 if (acl_mask->ae_perm & ACL_READ) 179 acl_mask_granted |= VREAD; 180 if (acl_mask->ae_perm & ACL_WRITE) 181 acl_mask_granted |= (VWRITE | VAPPEND); 182 } else 183 acl_mask_granted = VEXEC | VREAD | VWRITE | VAPPEND; 184 185 /* 186 * Check ACL_USER ACL entries. There will either be one or no 187 * matches; if there is one, we accept or rejected based on the 188 * match; otherwise, we continue on to groups. 189 */ 190 for (i = 0; i < acl->acl_cnt; i++) { 191 switch (acl->acl_entry[i].ae_tag) { 192 case ACL_USER: 193 if (acl->acl_entry[i].ae_id != cred->cr_uid) 194 break; 195 dac_granted = 0; 196 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE) 197 dac_granted |= VEXEC; 198 if (acl->acl_entry[i].ae_perm & ACL_READ) 199 dac_granted |= VREAD; 200 if (acl->acl_entry[i].ae_perm & ACL_WRITE) 201 dac_granted |= (VWRITE | VAPPEND); 202 dac_granted &= acl_mask_granted; 203 if ((accmode & dac_granted) == accmode) 204 return (0); 205 /* 206 * XXXRW: Do privilege lookup here. 207 */ 208 if ((accmode & (dac_granted | priv_granted)) != 209 accmode) 210 goto error; 211 212 if (privused != NULL) 213 *privused = 1; 214 return (0); 215 } 216 } 217 218 /* 219 * Group match is best-match, not first-match, so find a "best" 220 * match. Iterate across, testing each potential group match. Make 221 * sure we keep track of whether we found a match or not, so that we 222 * know if we should try again with any available privilege, or if we 223 * should move on to ACL_OTHER. 224 */ 225 group_matched = 0; 226 for (i = 0; i < acl->acl_cnt; i++) { 227 switch (acl->acl_entry[i].ae_tag) { 228 case ACL_GROUP_OBJ: 229 if (!groupmember(file_gid, cred)) 230 break; 231 dac_granted = 0; 232 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE) 233 dac_granted |= VEXEC; 234 if (acl->acl_entry[i].ae_perm & ACL_READ) 235 dac_granted |= VREAD; 236 if (acl->acl_entry[i].ae_perm & ACL_WRITE) 237 dac_granted |= (VWRITE | VAPPEND); 238 dac_granted &= acl_mask_granted; 239 240 if ((accmode & dac_granted) == accmode) 241 return (0); 242 243 group_matched = 1; 244 break; 245 246 case ACL_GROUP: 247 if (!groupmember(acl->acl_entry[i].ae_id, cred)) 248 break; 249 dac_granted = 0; 250 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE) 251 dac_granted |= VEXEC; 252 if (acl->acl_entry[i].ae_perm & ACL_READ) 253 dac_granted |= VREAD; 254 if (acl->acl_entry[i].ae_perm & ACL_WRITE) 255 dac_granted |= (VWRITE | VAPPEND); 256 dac_granted &= acl_mask_granted; 257 258 if ((accmode & dac_granted) == accmode) 259 return (0); 260 261 group_matched = 1; 262 break; 263 264 default: 265 break; 266 } 267 } 268 269 if (group_matched == 1) { 270 /* 271 * There was a match, but it did not grant rights via pure 272 * DAC. Try again, this time with privilege. 273 */ 274 for (i = 0; i < acl->acl_cnt; i++) { 275 switch (acl->acl_entry[i].ae_tag) { 276 case ACL_GROUP_OBJ: 277 if (!groupmember(file_gid, cred)) 278 break; 279 dac_granted = 0; 280 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE) 281 dac_granted |= VEXEC; 282 if (acl->acl_entry[i].ae_perm & ACL_READ) 283 dac_granted |= VREAD; 284 if (acl->acl_entry[i].ae_perm & ACL_WRITE) 285 dac_granted |= (VWRITE | VAPPEND); 286 dac_granted &= acl_mask_granted; 287 288 /* 289 * XXXRW: Do privilege lookup here. 290 */ 291 if ((accmode & (dac_granted | priv_granted)) 292 != accmode) 293 break; 294 295 if (privused != NULL) 296 *privused = 1; 297 return (0); 298 299 case ACL_GROUP: 300 if (!groupmember(acl->acl_entry[i].ae_id, 301 cred)) 302 break; 303 dac_granted = 0; 304 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE) 305 dac_granted |= VEXEC; 306 if (acl->acl_entry[i].ae_perm & ACL_READ) 307 dac_granted |= VREAD; 308 if (acl->acl_entry[i].ae_perm & ACL_WRITE) 309 dac_granted |= (VWRITE | VAPPEND); 310 dac_granted &= acl_mask_granted; 311 312 /* 313 * XXXRW: Do privilege lookup here. 314 */ 315 if ((accmode & (dac_granted | priv_granted)) 316 != accmode) 317 break; 318 319 if (privused != NULL) 320 *privused = 1; 321 return (0); 322 323 default: 324 break; 325 } 326 } 327 /* 328 * Even with privilege, group membership was not sufficient. 329 * Return failure. 330 */ 331 goto error; 332 } 333 334 /* 335 * Fall back on ACL_OTHER. ACL_MASK is not applied to ACL_OTHER. 336 */ 337 dac_granted = 0; 338 if (acl_other->ae_perm & ACL_EXECUTE) 339 dac_granted |= VEXEC; 340 if (acl_other->ae_perm & ACL_READ) 341 dac_granted |= VREAD; 342 if (acl_other->ae_perm & ACL_WRITE) 343 dac_granted |= (VWRITE | VAPPEND); 344 345 if ((accmode & dac_granted) == accmode) 346 return (0); 347 /* 348 * XXXRW: Do privilege lookup here. 349 */ 350 if ((accmode & (dac_granted | priv_granted)) == accmode) { 351 if (privused != NULL) 352 *privused = 1; 353 return (0); 354 } 355 356 error: 357 return ((accmode & VADMIN) ? EPERM : EACCES); 358 } 359 360 /* 361 * For the purposes of filesystems maintaining the _OBJ entries in an inode 362 * with a mode_t field, this routine converts a mode_t entry to an 363 * acl_perm_t. 364 */ 365 acl_perm_t 366 acl_posix1e_mode_to_perm(acl_tag_t tag, mode_t mode) 367 { 368 acl_perm_t perm = 0; 369 370 switch(tag) { 371 case ACL_USER_OBJ: 372 if (mode & S_IXUSR) 373 perm |= ACL_EXECUTE; 374 if (mode & S_IRUSR) 375 perm |= ACL_READ; 376 if (mode & S_IWUSR) 377 perm |= ACL_WRITE; 378 return (perm); 379 380 case ACL_GROUP_OBJ: 381 if (mode & S_IXGRP) 382 perm |= ACL_EXECUTE; 383 if (mode & S_IRGRP) 384 perm |= ACL_READ; 385 if (mode & S_IWGRP) 386 perm |= ACL_WRITE; 387 return (perm); 388 389 case ACL_OTHER: 390 if (mode & S_IXOTH) 391 perm |= ACL_EXECUTE; 392 if (mode & S_IROTH) 393 perm |= ACL_READ; 394 if (mode & S_IWOTH) 395 perm |= ACL_WRITE; 396 return (perm); 397 398 default: 399 printf("acl_posix1e_mode_to_perm: invalid tag (%d)\n", tag); 400 return (0); 401 } 402 } 403 404 /* 405 * Given inode information (uid, gid, mode), return an acl entry of the 406 * appropriate type. 407 */ 408 struct acl_entry 409 acl_posix1e_mode_to_entry(acl_tag_t tag, uid_t uid, gid_t gid, mode_t mode) 410 { 411 struct acl_entry acl_entry; 412 413 acl_entry.ae_tag = tag; 414 acl_entry.ae_perm = acl_posix1e_mode_to_perm(tag, mode); 415 acl_entry.ae_entry_type = 0; 416 acl_entry.ae_flags = 0; 417 switch(tag) { 418 case ACL_USER_OBJ: 419 acl_entry.ae_id = uid; 420 break; 421 422 case ACL_GROUP_OBJ: 423 acl_entry.ae_id = gid; 424 break; 425 426 case ACL_OTHER: 427 acl_entry.ae_id = ACL_UNDEFINED_ID; 428 break; 429 430 default: 431 acl_entry.ae_id = ACL_UNDEFINED_ID; 432 printf("acl_posix1e_mode_to_entry: invalid tag (%d)\n", tag); 433 } 434 435 return (acl_entry); 436 } 437 438 /* 439 * Utility function to generate a file mode given appropriate ACL entries. 440 */ 441 mode_t 442 acl_posix1e_perms_to_mode(struct acl_entry *acl_user_obj_entry, 443 struct acl_entry *acl_group_obj_entry, struct acl_entry *acl_other_entry) 444 { 445 mode_t mode; 446 447 mode = 0; 448 if (acl_user_obj_entry->ae_perm & ACL_EXECUTE) 449 mode |= S_IXUSR; 450 if (acl_user_obj_entry->ae_perm & ACL_READ) 451 mode |= S_IRUSR; 452 if (acl_user_obj_entry->ae_perm & ACL_WRITE) 453 mode |= S_IWUSR; 454 if (acl_group_obj_entry->ae_perm & ACL_EXECUTE) 455 mode |= S_IXGRP; 456 if (acl_group_obj_entry->ae_perm & ACL_READ) 457 mode |= S_IRGRP; 458 if (acl_group_obj_entry->ae_perm & ACL_WRITE) 459 mode |= S_IWGRP; 460 if (acl_other_entry->ae_perm & ACL_EXECUTE) 461 mode |= S_IXOTH; 462 if (acl_other_entry->ae_perm & ACL_READ) 463 mode |= S_IROTH; 464 if (acl_other_entry->ae_perm & ACL_WRITE) 465 mode |= S_IWOTH; 466 467 return (mode); 468 } 469 470 /* 471 * Utility function to generate a file mode given a complete POSIX.1e access 472 * ACL. Note that if the ACL is improperly formed, this may result in a 473 * panic. 474 */ 475 mode_t 476 acl_posix1e_acl_to_mode(struct acl *acl) 477 { 478 struct acl_entry *acl_mask, *acl_user_obj, *acl_group_obj, *acl_other; 479 int i; 480 481 /* 482 * Find the ACL entries relevant to a POSIX permission mode. 483 */ 484 acl_user_obj = acl_group_obj = acl_other = acl_mask = NULL; 485 for (i = 0; i < acl->acl_cnt; i++) { 486 switch (acl->acl_entry[i].ae_tag) { 487 case ACL_USER_OBJ: 488 acl_user_obj = &acl->acl_entry[i]; 489 break; 490 491 case ACL_GROUP_OBJ: 492 acl_group_obj = &acl->acl_entry[i]; 493 break; 494 495 case ACL_OTHER: 496 acl_other = &acl->acl_entry[i]; 497 break; 498 499 case ACL_MASK: 500 acl_mask = &acl->acl_entry[i]; 501 break; 502 503 case ACL_USER: 504 case ACL_GROUP: 505 break; 506 507 default: 508 panic("acl_posix1e_acl_to_mode: bad ae_tag"); 509 } 510 } 511 512 if (acl_user_obj == NULL || acl_group_obj == NULL || acl_other == NULL) 513 panic("acl_posix1e_acl_to_mode: missing base ae_tags"); 514 515 /* 516 * POSIX.1e specifies that if there is an ACL_MASK entry, we replace 517 * the mode "group" bits with its permissions. If there isn't, we 518 * use the ACL_GROUP_OBJ permissions. 519 */ 520 if (acl_mask != NULL) 521 return (acl_posix1e_perms_to_mode(acl_user_obj, acl_mask, 522 acl_other)); 523 else 524 return (acl_posix1e_perms_to_mode(acl_user_obj, acl_group_obj, 525 acl_other)); 526 } 527 528 /* 529 * Perform a syntactic check of the ACL, sufficient to allow an implementing 530 * filesystem to determine if it should accept this and rely on the POSIX.1e 531 * ACL properties. 532 */ 533 int 534 acl_posix1e_check(struct acl *acl) 535 { 536 int num_acl_user_obj, num_acl_user, num_acl_group_obj, num_acl_group; 537 int num_acl_mask, num_acl_other, i; 538 539 /* 540 * Verify that the number of entries does not exceed the maximum 541 * defined for acl_t. 542 * 543 * Verify that the correct number of various sorts of ae_tags are 544 * present: 545 * Exactly one ACL_USER_OBJ 546 * Exactly one ACL_GROUP_OBJ 547 * Exactly one ACL_OTHER 548 * If any ACL_USER or ACL_GROUP entries appear, then exactly one 549 * ACL_MASK entry must also appear. 550 * 551 * Verify that all ae_perm entries are in ACL_PERM_BITS. 552 * 553 * Verify all ae_tag entries are understood by this implementation. 554 * 555 * Note: Does not check for uniqueness of qualifier (ae_id) field. 556 */ 557 num_acl_user_obj = num_acl_user = num_acl_group_obj = num_acl_group = 558 num_acl_mask = num_acl_other = 0; 559 if (acl->acl_cnt > ACL_MAX_ENTRIES || acl->acl_cnt < 0) 560 return (EINVAL); 561 for (i = 0; i < acl->acl_cnt; i++) { 562 /* 563 * Check for a valid tag. 564 */ 565 switch(acl->acl_entry[i].ae_tag) { 566 case ACL_USER_OBJ: 567 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */ 568 if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID) 569 return (EINVAL); 570 num_acl_user_obj++; 571 break; 572 case ACL_GROUP_OBJ: 573 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */ 574 if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID) 575 return (EINVAL); 576 num_acl_group_obj++; 577 break; 578 case ACL_USER: 579 if (acl->acl_entry[i].ae_id == ACL_UNDEFINED_ID) 580 return (EINVAL); 581 num_acl_user++; 582 break; 583 case ACL_GROUP: 584 if (acl->acl_entry[i].ae_id == ACL_UNDEFINED_ID) 585 return (EINVAL); 586 num_acl_group++; 587 break; 588 case ACL_OTHER: 589 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */ 590 if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID) 591 return (EINVAL); 592 num_acl_other++; 593 break; 594 case ACL_MASK: 595 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */ 596 if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID) 597 return (EINVAL); 598 num_acl_mask++; 599 break; 600 default: 601 return (EINVAL); 602 } 603 /* 604 * Check for valid perm entries. 605 */ 606 if ((acl->acl_entry[i].ae_perm | ACL_PERM_BITS) != 607 ACL_PERM_BITS) 608 return (EINVAL); 609 } 610 if ((num_acl_user_obj != 1) || (num_acl_group_obj != 1) || 611 (num_acl_other != 1) || (num_acl_mask != 0 && num_acl_mask != 1)) 612 return (EINVAL); 613 if (((num_acl_group != 0) || (num_acl_user != 0)) && 614 (num_acl_mask != 1)) 615 return (EINVAL); 616 return (0); 617 } 618 619 /* 620 * Given a requested mode for a new object, and a default ACL, combine the 621 * two to produce a new mode. Be careful not to clear any bits that aren't 622 * intended to be affected by the POSIX.1e ACL. Eventually, this might also 623 * take the cmask as an argument, if we push that down into 624 * per-filesystem-code. 625 */ 626 mode_t 627 acl_posix1e_newfilemode(mode_t cmode, struct acl *dacl) 628 { 629 mode_t mode; 630 631 mode = cmode; 632 /* 633 * The current composition policy is that a permission bit must be 634 * set in *both* the ACL and the requested creation mode for it to 635 * appear in the resulting mode/ACL. First clear any possibly 636 * effected bits, then reconstruct. 637 */ 638 mode &= ACL_PRESERVE_MASK; 639 mode |= (ACL_OVERRIDE_MASK & cmode & acl_posix1e_acl_to_mode(dacl)); 640 641 return (mode); 642 } 643