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