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