home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume2 / access < prev    next >
Internet Message Format  |  1986-11-30  |  39KB

  1. Date: Wed, 26 Jun 85 11:39:25 edt
  2. From: linus!security!jjg (Jeff Glass)
  3. Subject: source for access control lists
  4.  
  5.  
  6. This should be everything you need to install access control lists under 4.2bsd.
  7.  
  8. create a directory somewhere to hold this stuff.  run the rest of this
  9. through sh .  then follow the instructions in README.
  10.  
  11. ------------ cut here -------------
  12. #! /bin/sh
  13. echo x - Makefile
  14. cat >Makefile <<'!E!O!F!'
  15. CFLAGS = -O
  16. ALL = edacl lsacl chacl cpacl
  17. BINDIR = /usr/local
  18.  
  19. # .l (man page) files confuse make, which thinks they are lex programs
  20. .SUFFIXES :
  21. .SUFFIXES : .out .o .c .e .r .f .y .s .p
  22.  
  23. all : ${ALL}
  24.  
  25. edacl :
  26.     cp edacl.sh edacl
  27.  
  28. lsacl : lsacl.o
  29.     cc lsacl.o -o lsacl
  30.  
  31. chacl : chacl.o
  32.     cc chacl.o -o chacl
  33.  
  34. cpacl : cpacl.o
  35.     cc cpacl.o -o cpacl
  36.  
  37. clean :
  38.     rm -f *.o core a.out ${ALL}
  39.  
  40. man :
  41.     cp chacl.l cpacl.l edacl.l lsacl.l /usr/man/manl
  42.     cp getacl.2 setacl.2 /usr/man/man2
  43.  
  44. install : ${ALL}
  45.     for i in ${ALL} ; do install -m 755 $$i ${BINDIR} ; done
  46. !E!O!F!
  47. echo x - README
  48. cat >README <<'!E!O!F!'
  49. This should explain how to install the mods for access control lists.
  50. I am writing this after the fact, though, so if I have forgotten anything,
  51. let me know.
  52.  
  53. 0) after unpacking, you should have the files
  54.  
  55.     README        README.kernel
  56.     h.pat        sys.pat
  57.     acl.h        acl.c
  58.     getacl.2    setacl.2
  59.     login.pat
  60.  
  61.     Makefile    jjg.h
  62.     chacl.c        chacl.l
  63.     cpacl.c        cpacl.l
  64.     edacl.sh    edacl.l
  65.     lsacl.c        lsacl.l
  66.  
  67. 1) h.pat and sys.pat are patches to files in the /sys/h and /sys/sys
  68.    directories.  if you have the patch program, then
  69.  
  70.     ( cd /sys/h ; patch ) < h.pat
  71.     ( cd /sys/sys ; patch ) < sys.pat
  72.  
  73.    otherwise you will have to apply the patches to the files by hand.
  74.  
  75. 2) install the files acl.h and acl.c in /sys/h and /sys/sys , respectively.
  76.  
  77. 3) make and install the new kernel.  brief instructions are in README.kernel .
  78.  
  79. 4) edit the Makefile and change BINDIR to whatever.  then "make install"
  80.    to get the programs chacl cpacl edacl lsacl .
  81.  
  82. 5) login.pat is a patch to /usr/src/bin/login.c , to make login clear
  83.    the acl on the user's terminal.  patch, make, and install login .
  84.  
  85. 6) install the man pages;  "make man" will do it.
  86.  
  87. 7) reboot.
  88.  
  89. 8) read the man pages for the programs, and try them out.
  90.  
  91. 9) please send comments, fixes, improvements, and (mild) flames back
  92.    to me - linus!security!jjg .
  93. !E!O!F!
  94. echo x - README.kernel
  95. cat >README.kernel <<'!E!O!F!'
  96. This is a brief set of instructions for installing the system calls getacl()
  97. and setacl().  It is intended for people like me, who have never hacked the
  98. kernel much before. 
  99.  
  100. 1) add the routines "getacl" and "setacl" to the standard library.
  101.    for the VAX, this requires that you:
  102.  
  103.     a) create the files getacl.c and setacl.c in
  104.        /usr/src/lib/libc/vax/sys .  copy one of the existing
  105.        files there (like read.c) to get the format.
  106.  
  107.     b) update the Makefile in that directory.  add "getacl.o"
  108.        and "setacl.o" to the definition of the OBJS variable.
  109.  
  110.     c) add the two lines
  111.         
  112.         #define SYS_getacl    151
  113.         #define SYS_setacl    152
  114.  
  115.        to the end of the file /usr/include/syscall.h .  change "151"
  116.        and "152" to whatever are the next two numbers.
  117.  
  118.     d) cd to /usr/src/lib/libc , and "make" .  then "make install".
  119.  
  120. 2) add the names of the new system calls ( "getacl" and "setacl" ) to
  121.    the end of the array syscallnames in /sys/sys/syscalls.c .
  122.  
  123. 3) in /sys/sys/init_sysent.c , declare getacl() and setacl() as int functions,
  124.    and add the two lines 
  125.    
  126.     3, getacl,    /* 151 = getacl */
  127.     3, setacl,    /* 152 = setacl */
  128.  
  129.    to the end of the sysent array declaration.
  130.  
  131. 4) cd to /sys/conf , add the one line
  132.  
  133.     sys/acl.c    standard
  134.  
  135.    to the file /sys/conf/files , and run "/etc/config MACH",
  136.    where MACH is your machine's name.
  137.  
  138. 5) cd to ../MACH and "make depend", and "make".
  139.  
  140. 6) install vmunix in / .
  141.  
  142. !E!O!F!
  143. echo x - TODO
  144. cat >TODO <<'!E!O!F!'
  145. 1) put lsacl(1) into ls(1) .  ls needs a "-A" option :-)
  146.  
  147. 2) make cp(1) copy the file's acl to the destination file.
  148.  
  149. 3) when execve(2) is checking for any IEXEC permission
  150.    ( i.e., "(ip->i_mode & (IEXEC|IEXEC>>3|IEXEC>>6) == 0)" ),
  151.    check for an acl entry which has IEXEC permission.
  152.  
  153. 4) come up with a default acl when creating files and directories.
  154.    Multics allows defaults at the user/directory level.  a compromise
  155.    might be to allow a default at the user level, and store it in the
  156.    u area, ala umask(2).
  157.  
  158. 5) increase the size of an acl.  this requires putting the acl somewhere
  159.    other than the inode, or increasing the size of the inode beyond 128 bytes.
  160.  
  161.  
  162. !E!O!F!
  163. echo x - acl.c
  164. cat >acl.c <<'!E!O!F!'
  165. #include "../h/param.h"
  166. #include "../h/systm.h"
  167. #include "../h/dir.h"
  168. #include "../h/inode.h"
  169. #include "../h/user.h"
  170. #include "../h/nami.h"
  171. #include "../h/acl.h"
  172.  
  173. #define FOLLOW_LINK 1
  174.  
  175. /*
  176.  * pack_acle() copies an acle struct into the inode.  the acle is packed
  177.  * since the inode is rather short of space.
  178.  */
  179. pack_acle( ip, a, n )
  180. struct inode *ip;
  181. struct acle a;
  182. int n;
  183. {
  184.     /* clear the type and mode fields */
  185.     ip->i_acle[n/2] &= 017 << ((n%2) ? 4 : 0);
  186.  
  187.     /* set the type, mode, and id fields */
  188.     ip->i_acle[n/2] |= ( a.a_type != A_GROUP ? A_USER : A_GROUP ) <<
  189.         ((n%2) ? 3 : 7);
  190.     ip->i_acle[n/2] |= ( a.a_mode & 07 ) << ((n%2) ? 0 : 4);
  191.     ip->i_aclid[n] = a.a_id;
  192. }
  193.  
  194. /*
  195.  * null_acle() puts an end-of-acl marker in the acl at entry n.
  196.  * the end-of-acl marker looks like an acl entry for root
  197.  * (a_type == A_USER  && a_id == 0).
  198.  */
  199. null_acle( ip, n )
  200. struct inode *ip;
  201. int n;
  202. {
  203.     /* clear the type and mode fields */
  204.     ip->i_acle[n/2] &= 017 << ((n%2) ? 4 : 0);
  205.  
  206.     /* clear the id field */
  207.     ip->i_aclid[n] = 0;
  208. }
  209.  
  210. /*
  211.  * getacl() returns the set of acl entries associated with the file.
  212.  * the user must be able to access the file in order to read the acl.
  213.  */
  214. getacl()
  215. {
  216.     struct inode *ip;
  217.     struct acle ka[MAXACL];
  218.     struct a {
  219.         char *fname;
  220.         int n_acle;
  221.         struct acle *acle_p;
  222.     } *uap = (struct a *) u.u_ap;
  223.     int i;
  224.  
  225.     if ( (ip = namei(uchar,LOOKUP,FOLLOW_LINK)) != NULL ) {
  226.         /* unpack the acl entries */
  227.         for (i = 0; i < MAXACL && ok_acle(ip,i); i++ ) {
  228.             ka[i].a_type = acle_type( ip, i );
  229.             ka[i].a_mode = acle_mode( ip, i );
  230.             ka[i].a_id = acle_id( ip, i );
  231.         }
  232.  
  233.         /* getacl doesn't need the inode any more. */
  234.         iput( ip );
  235.  
  236.         if ( uap->n_acle < i ) {
  237.             u.u_error = EINVAL;
  238.         } else {
  239.             /*
  240.              * copy the acl entries to the user's buffer,
  241.              * and return the number of entries found.
  242.              */
  243.             u.u_error = copyout((caddr_t) ka, (caddr_t) uap->acle_p,
  244.                 i*sizeof(struct acle));
  245.             if ( u.u_error == 0 ) u.u_r.r_val1 = i;
  246.         }
  247.     }
  248. }
  249.  
  250. /*
  251.  * setacl() defines the acl for an inode.  to do this, the user must
  252.  * be the owner of the inode, or else must be the superuser.
  253.  *
  254.  * bugs: acl entries should be sorted by a_type , so that access() does
  255.  * not have to read the entire acl three times.  since the number of acl
  256.  * entries is so small, though, this would make setacl() more complex
  257.  * (sorting the entries) without really buying that much.
  258.  */
  259. setacl()
  260. {
  261.     struct inode *ip;
  262.     struct acle ka[MAXACL];
  263.     int kn;
  264.     struct a {
  265.         char *fname;
  266.         int n_acle;
  267.         struct acle *acle_p;
  268.     } *uap = (struct a *) u.u_ap;
  269.     int i;
  270.  
  271.     /*
  272.      * copy the user's arguments into kernel space; kn will contain
  273.      * the number of acl entries, and ka will contain the entries.
  274.      */
  275.     if ( (kn = uap->n_acle) > MAXACL ) {
  276.         u.u_error = EINVAL;
  277.     } else {
  278.         u.u_error = copyin( (caddr_t) uap->acle_p, (caddr_t) ka,
  279.             kn*sizeof(struct acle) );
  280.         if ( u.u_error == 0 ) {
  281.             if ( (ip = owner(FOLLOW_LINK)) != NULL ) {
  282.                 for ( i = 0; i < kn; i++ ) {
  283.                     pack_acle( ip, ka[i], i );
  284.                     if (! ok_acle(ip,i) ) break;
  285.                 }
  286.  
  287.                 if ( kn < MAXACL ) null_acle( ip, kn );
  288.  
  289.                 /* update ctime for the inode */
  290.                 ip->i_flag |= ICHG;
  291.                 iput( ip );
  292.             }
  293.         }
  294.     }
  295. }
  296. !E!O!F!
  297. echo x - acl.h
  298. cat >acl.h <<'!E!O!F!'
  299. #define A_GROUP    1
  300. #define A_USER    0
  301.  
  302. /*
  303.  * macros to disassemble the packed acl in the inode
  304.  */
  305. #ifdef KERNEL
  306. #define acle_type(ip,n)    ( ( (ip)->i_acle[(n)/2] >> (((n)%2) ? 3 : 7) ) & 01 )
  307. #define acle_id(ip,n)    (ip)->i_aclid[(n)]
  308. #define acle_mode(ip,n)    ( ( (ip)->i_acle[(n)/2] >> (((n)%2) ? 0 : 4) ) & 07 )
  309. #define ok_acle(ip,n)    ( ( acle_type((ip),(n)) != A_USER ) || ( acle_id((ip),(n)) != 0 ) )
  310. #else
  311. #define ok_uacle(a)    ( ( (a).a_type != A_USER ) || ( (a).a_id != 0 ) )
  312. #endif
  313.  
  314. struct acle {
  315.     char a_type;    /* A_GROUP or A_USER */
  316.     char a_mode;    /* 0 (no permission) through 7 (rwx) */
  317.     int a_id;    /* gid or uid, depending */
  318. };
  319. !E!O!F!
  320. echo x - chacl.c
  321. cat >chacl.c <<'!E!O!F!'
  322. #include <stdio.h>
  323. #include <sys/param.h>
  324. #include <sys/acl.h>
  325. #include <grp.h>
  326. #include <pwd.h>
  327. #include "jjg.h"
  328.  
  329. #define ERR_FATAL 1    /* for the err() routine */
  330. #define ERR_NONFATAL 0    /* for the err() routine */
  331.  
  332. /*
  333.  * calling sequence: chacl [-u [user mode]] [-g [group mode]] -f [file]
  334.  *
  335.  * items enclosed in brackets may repeat.
  336.  */
  337. main(argc, argv, environ)
  338. int argc;
  339. char *argv[], *environ[];
  340. {
  341.     int i, j, na;
  342.     struct acle acl[MAXACL];
  343.     int is_u_type;
  344.     int filec;
  345.     int status;
  346.  
  347.     na = 0;
  348.  
  349.     for ( i = 1; i < argc; i++ ) {
  350.         if ( equal(argv[i],"-u") || equal(argv[i],"-g") ) {
  351.             is_u_type = equal( argv[i], "-u" );
  352.  
  353.         } else if ( equal(argv[i],"-f") ) {
  354.             break;
  355.  
  356.         } else if ( *argv[i] == '-' ) {
  357.             err( ERR_FATAL, "unrecognized option - %s", argv[i] );
  358.  
  359.         } else {
  360.             struct passwd *up;
  361.             struct group *gp;
  362.             int valid_name;
  363.  
  364.             if ( is_u_type ) {
  365.                 up = getpwnam( argv[i] );
  366.                 valid_name = up != NULL;
  367.             } else {
  368.                 gp = getgrnam( argv[i] );
  369.                 valid_name = gp != NULL;
  370.             }
  371.  
  372.             if ( valid_name ) {
  373.                 i++;
  374.  
  375.                 if ( i < argc ) {
  376.                     if ( is_u_type && up->pw_uid == 0 ) {
  377.                         err( ERR_NONFATAL, "warning: cannot deny access to user %s", "root" );
  378.                     } else {
  379.                         if ( sscanf( argv[i], "%d", &acl[na].a_mode ) == 1 &&
  380.                             acl[na].a_mode >= 0 && acl[na].a_mode <= 7 ) {
  381.                             if ( na < MAXACL ) {
  382.                                 acl[na].a_type = is_u_type ? A_USER : A_GROUP;
  383.                                 acl[na].a_id = is_u_type ? up->pw_uid : gp->gr_gid;
  384.                                 na++;
  385.                             } else {
  386.                                 err( ERR_NONFATAL, "warning: too many acl entries (must be no more than %d)", MAXACL );
  387.                             }
  388.  
  389.                         } else {
  390.                             err( ERR_FATAL, "unrecognizable mode - %d (must be 0-7)", acl[na].a_mode );
  391.                         }
  392.                     }
  393.  
  394.                 } else {
  395.                     err( ERR_FATAL, "expected mode after %sname", is_u_type ? "user" : "group" );
  396.                 }
  397.             } else {
  398.                 err( ERR_FATAL, is_u_type ? "no such user - %s" : "no such group - %s", argv[i] );
  399.             }
  400.         }
  401.     }
  402.  
  403. /*    
  404.     printf( "number of acle = %d\n", na );
  405.     printf( "file list begins at %d; argc = %d\n", i+1, argc );
  406.  
  407.     for ( i = 0; i < na; i++ ) {
  408.         printf( "type = %s id = %d mode = %d\n", acl[i].a_type == A_GROUP ? "-g"
  409.             : "-u", acl[i].a_id, acl[i].a_mode );
  410.     }
  411. */
  412.  
  413.     status = 0;
  414.     for ( filec = i+1; filec < argc; filec++ ) {
  415.         if ( setacl( argv[filec], na, acl ) != 0 ) {
  416.             perror( argv[filec] );
  417.             status++;
  418.         }
  419.     }
  420.     exit( status );
  421. }
  422.  
  423. err( level, fmt, arg )
  424. int level;
  425. char *fmt, *arg;
  426. {
  427.     char buf[240];
  428.  
  429.     sprintf( buf, fmt, arg );
  430.     fprintf( stderr, "chacl: %s\n", buf );
  431.  
  432.     if ( level == ERR_FATAL )
  433.         exit( 1 );
  434. }
  435. !E!O!F!
  436. echo x - chacl.l
  437. cat >chacl.l <<'!E!O!F!'
  438. ''' $Header:$
  439. ''' 
  440. ''' $Log:$
  441. .de Sh
  442. .br
  443. .ne 5
  444. .PP
  445. \fB\\$1\fR
  446. .PP
  447. ..
  448. .de Sp
  449. .if t .sp .5v
  450. .if n .sp
  451. ..
  452. '''
  453. '''     Set up \*(-- to give an unbreakable dash;
  454. '''     string Tr holds user defined translation string.
  455. '''     Bell System Logo is used as a dummy character.
  456. '''
  457. .ie n \{\
  458. .tr \(bs-\*(Tr
  459. .ds -- \(bs-
  460. .if (\n(.H=4u)&(1m=24u) .ds -- \(bs\h'-12u'\(bs\h'-12u'-\" diablo 10 pitch
  461. .if (\n(.H=4u)&(1m=20u) .ds -- \(bs\h'-12u'\(bs\h'-8u'-\" diablo 12 pitch
  462. .ds L" ""
  463. .ds R" ""
  464. .ds L' '
  465. .ds R' '
  466. 'br\}
  467. .el\{\
  468. .ds -- \(em\|
  469. .tr \*(Tr
  470. .ds L" ``
  471. .ds R" ''
  472. .ds L' `
  473. .ds R' '
  474. 'br\}
  475. .TH chacl 1 LOCAL
  476. .SH NAME
  477. chacl - change the access control list for files
  478. .SH SYNOPSIS
  479. .B chacl
  480. [-u username mode ...] [-g groupname mode ...] -f file ...
  481. .SH DESCRIPTION
  482. .I chacl
  483. changes the access control lists for one or more files.  The
  484. access control list (or acl) and the file's ownership are used to determine
  485. which users can access the file.
  486. .PP
  487. The
  488. .B \-u
  489. option marks the beginning of a list of "username mode" pairs.
  490. Similarly, the
  491. .B \-g
  492. option marks the beginning of a list of "groupname mode" pairs.
  493. A "name mode" pair is referred to as an "acl entry".
  494. The
  495. .B \-f
  496. option separates the acl from the list of files involved.
  497. .PP
  498. The username or groupname is hunted for in the first field of /etc/passwd
  499. or /etc/group , respectively.
  500. The mode is a single digit in the range [0-7] indicating read-write-execute
  501. permission ala
  502. .IR chmod .
  503. .PP
  504. The current implementation allows up to 8 acl entries.  This is defined
  505. by the constant MAXACL in <sys/acl.h>.  An entry cannot deny access
  506. to the superuser.
  507. Setting a file's acl removes any existing acl entries (i.e., calls to
  508. .I chacl
  509. do not accumulate).  Only the owner of a file (or the superuser) can
  510. change its acl.
  511. .PP
  512. Access decisions are made in the following way.
  513. .Sp
  514.     If the effective userid (euid) is the superuser, grant access.
  515. .Sp
  516.     Else if the euid is the file's owning uid, check the owner permission.
  517. .Sp
  518.     Else if the euid matches an acl entry,
  519. check the entry's mode.
  520. .Sp
  521.     Else if the effective groupid (egid) matches an acl entry,
  522. check the entry's mode.
  523. .Sp
  524.     Else if some member of the group list matches an acl entry,
  525. check the entry's mode.
  526. .Sp
  527.     Else if the egid is the file's owning gid, check the group permission.
  528. .Sp
  529.     Else if some member of the group list matches the file's owning gid,
  530. check the group permission.
  531. .Sp
  532.     Else check the other permission.
  533. .PP
  534. Order within the acl is important.  When matching against the acl, entries
  535. are checked in order, stopping at the first match.  (Multiple matches could
  536. only occur in group acl entries.)
  537. .SH EXAMPLES
  538.     chacl -u jjg 7 -g d75 0 -f gossip
  539. .Sp
  540. grants full access to the file "gossip" to the user "jjg", and denies all
  541. access to this file to the group "d75".
  542. .Sp
  543.     chacl -f rumors
  544. .Sp
  545. resets the acl for the file "rumors".
  546. .Sp
  547.     chacl -u jjg 6 uucp 4 -f facts
  548. .Sp
  549. grants read-write access to the user "jjg" and read access to the user
  550. "uucp" for the file "facts".
  551. .SH DIAGNOSTICS
  552. Various messages indicate syntactic errors in the command line arguments.
  553. Minor errors are flagged with a "warning:", and indicate that
  554. .I chacl
  555. carried on and set the access control lists for the files.
  556. .PP
  557. .I chacl
  558. returns with exit status 0 if all is well;  with exit status 1 if there
  559. are errors in the command line arguments;  or with exit status greater
  560. than 0 if the acls for some files could not be set.
  561. .SH SEE ALSO
  562. cpacl(1),
  563. edacl(1),
  564. lsacl(1),
  565. getacl(2),
  566. setacl(2)
  567. .SH CAVEAT
  568. The implementation of access control lists is an experiment.  This
  569. implementation stores the access control list in a (formerly) unused field
  570. in the inode.
  571. There is no guarantee that future versions of Unix will not use this field
  572. for something else.
  573. .PP
  574. Therefore, you should only use access control lists with the full
  575. understanding that you are participating in an experiment.
  576. .SH BUGS
  577. Allowing wildcards in the acl entry's name would be useful.
  578. !E!O!F!
  579. echo x - cpacl.c
  580. cat >cpacl.c <<'!E!O!F!'
  581. #include <stdio.h>
  582. #include <sys/param.h>
  583. #include <sys/acl.h>
  584.  
  585. /*
  586.  * cpacl : copy the access control list of one file to other files.
  587.  *
  588.  * usage : cpacl fromfile tofile [tofile ...]
  589.  */
  590. main(argc, argv, environ)
  591. int argc;
  592. char *argv[], *environ[];
  593. {
  594.     int i;
  595.     struct acle acl[MAXACL];
  596.     int status;
  597.     int na;
  598.  
  599.     status = 0;
  600.  
  601.     if ( argc > 1 ) {
  602.         if ( (na = getacl(argv[1],MAXACL,acl)) != -1 ) {
  603.             for ( i = 2; i < argc; i++ ) {
  604.                 if ( setacl( argv[i], na, acl ) != 0 ) {
  605.                     perror( argv[i] );
  606.                     status++;
  607.                 }
  608.             }
  609.         } else {
  610.             perror( argv[1] );
  611.             status++;
  612.         }
  613.     } else {
  614.         fprintf( stderr, "cpacl: usage: cpacl fromfile tofile [tofile ...]\n" );
  615.     }
  616.  
  617.     exit( status );
  618. }
  619. !E!O!F!
  620. echo x - cpacl.l
  621. cat >cpacl.l <<'!E!O!F!'
  622. ''' $Header:$
  623. ''' 
  624. ''' $Log:$
  625. .de Sh
  626. .br
  627. .ne 5
  628. .PP
  629. \fB\\$1\fR
  630. .PP
  631. ..
  632. .de Sp
  633. .if t .sp .5v
  634. .if n .sp
  635. ..
  636. '''
  637. '''     Set up \*(-- to give an unbreakable dash;
  638. '''     string Tr holds user defined translation string.
  639. '''     Bell System Logo is used as a dummy character.
  640. '''
  641. .ie n \{\
  642. .tr \(bs-\*(Tr
  643. .ds -- \(bs-
  644. .if (\n(.H=4u)&(1m=24u) .ds -- \(bs\h'-12u'\(bs\h'-12u'-\" diablo 10 pitch
  645. .if (\n(.H=4u)&(1m=20u) .ds -- \(bs\h'-12u'\(bs\h'-8u'-\" diablo 12 pitch
  646. .ds L" ""
  647. .ds R" ""
  648. .ds L' '
  649. .ds R' '
  650. 'br\}
  651. .el\{\
  652. .ds -- \(em\|
  653. .tr \*(Tr
  654. .ds L" ``
  655. .ds R" ''
  656. .ds L' `
  657. .ds R' '
  658. 'br\}
  659. .TH CPACL 1 LOCAL
  660. .SH NAME
  661. cpacl - copy the access control list of one file to other files
  662. .SH SYNOPSIS
  663. .B cpacl
  664. fromfile tofile [tofile ...]
  665. .SH DESCRIPTION
  666. .I cpacl
  667. copies the access control list of a file to the access control lists of
  668. one or more other files.  The access control list
  669. and the file's ownership are used to determine which users can access
  670. the file.
  671. .PP
  672. .I cpacl
  673. gets the access control list for fromfile, and copies this acl to the acl
  674. for each tofile.
  675. .SH DIAGNOSTICS
  676. .I cpacl
  677. returns with exit status 0 if all is well;  with exit status 1 if it
  678. could not get the access control list for fromfile; or with exit status
  679. greater than 0 if the access control lists for some tofiles could not
  680. be set.
  681. .SH SEE ALSO
  682. chacl(1),
  683. edacl(1),
  684. lsacl(1),
  685. getacl(2),
  686. setacl(2)
  687. .SH CAVEAT
  688. The implementation of access control lists is an experiment.  This
  689. implementation stores the access control list in a (formerly) unused field
  690. in the inode.
  691. There is no guarantee that future versions of Unix will not use this field
  692. for something else.
  693. .PP
  694. Therefore, you should only use access control lists with the full
  695. understanding that you are participating in an experiment.
  696. .SH BUGS
  697. The entire mechanism hasn't been fully tested.
  698. !E!O!F!
  699. echo x - edacl.l
  700. cat >edacl.l <<'!E!O!F!'
  701. ''' $Header:$
  702. ''' 
  703. ''' $Log:$
  704. .de Sh
  705. .br
  706. .ne 5
  707. .PP
  708. \fB\\$1\fR
  709. .PP
  710. ..
  711. .de Sp
  712. .if t .sp .5v
  713. .if n .sp
  714. ..
  715. '''
  716. '''     Set up \*(-- to give an unbreakable dash;
  717. '''     string Tr holds user defined translation string.
  718. '''     Bell System Logo is used as a dummy character.
  719. '''
  720. .ie n \{\
  721. .tr \(bs-\*(Tr
  722. .ds -- \(bs-
  723. .if (\n(.H=4u)&(1m=24u) .ds -- \(bs\h'-12u'\(bs\h'-12u'-\" diablo 10 pitch
  724. .if (\n(.H=4u)&(1m=20u) .ds -- \(bs\h'-12u'\(bs\h'-8u'-\" diablo 12 pitch
  725. .ds L" ""
  726. .ds R" ""
  727. .ds L' '
  728. .ds R' '
  729. 'br\}
  730. .el\{\
  731. .ds -- \(em\|
  732. .tr \*(Tr
  733. .ds L" ``
  734. .ds R" ''
  735. .ds L' `
  736. .ds R' '
  737. 'br\}
  738. .TH EDACL 1 LOCAL
  739. .SH NAME
  740. edacl - edit the access control lists for files
  741. .SH SYNOPSIS
  742. .B edacl
  743. file ...
  744. .SH DESCRIPTION
  745. .I edacl
  746. edits the access control lists for one or more files.  The access control list
  747. and the file's ownership are used to determine which users can access
  748. the file.
  749. .PP
  750. For each file,
  751. .I edacl
  752. invokes the editor of your choice on the access control list of that file.
  753. The first line has the name of the file whose acl is being edited.
  754. The following lines contain the acl entries.  
  755. .PP
  756. Each acl entry has three fields.  The first field is either the string "user"
  757. or "group".
  758. The second field is a user or group name;  which it is depends on the
  759. value of the first field.  The last field is the mode granted to that
  760. user or group.  It is a single digit in the range [0-7],
  761. indicating read-write-execute permission ala
  762. .IR chmod .
  763. .PP
  764. You may add, change, or delete entries.  Upon exiting the editor,
  765. .I edacl
  766. will ask you if you wish to update the acl for that file.
  767. .SH DIAGNOSTICS
  768. .I edacl
  769. calls
  770. .I lsacl(1)
  771. and
  772. .I chacl(1)
  773. to do the dirty work;  see the DIAGNOSTICS sections in their documentation.
  774. .SH ENVIRONMENT VARIABLES
  775. If the EDITOR variable is set,
  776. .I edacl
  777. assumes it contains the name of your desired editor.  Otherwise,
  778. .I edacl
  779. will ask you which one to use.
  780. .SH SEE ALSO
  781. chacl(1),
  782. cpacl(1),
  783. lsacl(1),
  784. getacl(2),
  785. setacl(2)
  786. .SH CAVEAT
  787. The implementation of access control lists is an experiment.  This
  788. implementation stores the access control list in a (formerly) unused field
  789. in the inode.
  790. There is no guarantee that future versions of Unix will not use this field
  791. for something else.
  792. .PP
  793. Therefore, you should only use access control lists with the full
  794. understanding that you are participating in an experiment.
  795. .SH BUGS
  796. The entire mechanism hasn't been fully tested.
  797. .PP
  798. It might be nice if the mode were given symbolically ("rwx" instead
  799. of "7").
  800. !E!O!F!
  801. echo x - edacl.sh
  802. cat >edacl.sh <<'!E!O!F!'
  803. #! /bin/csh -f
  804.  
  805. set path = ( /usr/new /usr/local /usr/ucb /usr/bin /bin . )
  806. setenv PATH  /usr/new:/usr/local:/usr/ucb:/usr/bin:/bin:.
  807. unset noclobber
  808. set noglob
  809.  
  810. set DEF_ED = /usr/ucb/vi
  811. # WS == WhiteSpace ; WF == WordForming ; NF == NumberForming .
  812. set WS = "[     ][     ]*"
  813. set WSO = "[     ]*"
  814. set WF = "[a-zA-Z][a-zA-Z0-9]*"
  815. set NF = "[0-9][0-9]*"
  816.  
  817. foreach i ( $argv[*]:q )
  818.     set acl_file = "/tmp/edacl_${i:t}_$$"
  819.     lsacl "$i" > "$acl_file"
  820.  
  821.     if ( $status == 0 ) then
  822.         set state = edit
  823.         while 1
  824.             switch ( $state )
  825.             case edit :
  826.                 if ( ! $?EDITOR ) then
  827.                     echo -n "edacl: editor [$DEF_ED] : "
  828.                     set EDITOR = $<
  829.                     if ( "_$EDITOR" == "_" ) set EDITOR = $DEF_ED
  830.                 endif
  831.  
  832.                 /bin/sh -c "$EDITOR '$acl_file'"
  833.  
  834.                 if ( $status == 0 ) then
  835.                     set state = prompt
  836.                 else
  837.                     unset EDITOR
  838.                     unsetenv EDITOR
  839.                 endif
  840.  
  841.                 breaksw
  842.  
  843.             case prompt :
  844.                 echo -n edacl: update acl for "$i" "? [yne] "
  845.                 set response = $<
  846.  
  847.                 if ( "_$response" == "_" || "_$response" =~ _y* ) then
  848.                     set state = update
  849.                 else if ( "_$response" =~ _e* ) then
  850.                     set state = edit
  851.                 else if ( "_$response" =~ _n* ) then
  852.                     set state = noupdate
  853.                 else
  854.                     echo "Yes - update acl;  No - opposite of Yes;  Edit - try again."
  855.                 endif
  856.  
  857.                 breaksw
  858.  
  859.             case update :
  860.                 chacl `sed -e 1d -e '2,$'"s/^${WSO}user\(${WS}${WF}${WS}${NF}\)/-u \1/" -e '2,$'"s/^${WSO}group\(${WS}${WF}${WS}${NF}\)/-g \1/" "$acl_file"` -f "$i"
  861.  
  862.                 break
  863.  
  864.             case noupdate :
  865.  
  866.                 break
  867.  
  868.             default :
  869.                 echo "edacl: internal error (in switch statement).  HELP"
  870.  
  871.                 breaksw
  872.  
  873.             endsw
  874.         end
  875.  
  876.         rm -f "$acl_file"
  877.     endif
  878. end
  879. !E!O!F!
  880. echo x - getacl.2
  881. cat >getacl.2 <<'!E!O!F!'
  882. .TH GETACL 2 "15 May 1985"
  883. .UC 4
  884. .SH NAME
  885. getacl \- get the access control list for a file
  886. .SH SYNOPSIS
  887. .nf
  888. .ft B
  889. #include <sys/param.h>
  890. #include <sys/acl.h>
  891. .PP
  892. .ft B
  893. getacl(path, nacle, acl)
  894. char *path;
  895. int nacle;
  896. struct acle *acl;
  897. .fi
  898. .SH DESCRIPTION
  899. .I getacl
  900. fetches the access control list of the file whose name is given by
  901. .IR path .
  902. The list is placed in the array
  903. .IR acl .
  904. The parameter
  905. .I nacle
  906. indicates the number of access control list entries which may be placed in 
  907. .IR acl .
  908. No more than MAXACL entries, as defined in
  909. .RI < sys/param.h >,
  910. will be returned.
  911. .PP
  912. An access control list entry is described in
  913. .RI < sys/acl.h >.
  914. .PP
  915. .nf
  916. #define A_GROUP    1
  917. #define A_USER    0
  918.  
  919. struct acle {
  920.     char a_type;    /* A_GROUP or A_USER */
  921.     char a_mode;    /* rwx [0-7] permissions */
  922.     int a_id;    /* gid or uid according to a_type */
  923. };
  924. .fi
  925. .PP
  926. .I a_type
  927. is a flag indicating whether the entry is for a user or a group.
  928. .I a_id
  929. contains either a uid or a gid, depending on the value of
  930. .IR a_flag .
  931. This user or group will have the permissions described by
  932. .IR a_mode ,
  933. which is an integer in the range 0-7. It indicates read-write-execute
  934. permissions in the manner of
  935. .IR chmod(2) .
  936. .SH "RETURN VALUE
  937. .I getacl
  938. returns the number of entries in the file's access control list,
  939. which is always greater than or equal to zero.
  940. A value of \-1 indicates that an error occurred, and the error
  941. code is stored in the global variable \fIerrno\fP\|.
  942. .SH "ERRORS
  943. .I getacl
  944. will fail if:
  945. .TP 15
  946. [EFAULT]
  947. The argument
  948. .I acl
  949. specifies an invalid address.
  950. .TP 15
  951. [EINVAL]
  952. The argument
  953. .I nacle
  954. is smaller than the number of access control list entries for the file.
  955. .TP 15
  956. [EPERM]
  957. The argument
  958. .I path
  959. contains a byte with the high-order bit set.
  960. .TP 15
  961. [ENOTDIR]
  962. A component of the pathname is not a directory.
  963. .TP 15
  964. [ENOENT]
  965. The pathname was too long, or the named file does not exist.
  966. .TP 15
  967. [EACCES]
  968. Search permission is denied on a component of the pathname.
  969. .TP 15
  970. [ELOOP]
  971. Too many symbolic links were encountered in translating the pathname.
  972. .SH SEE ALSO
  973. chacl(1),
  974. cpacl(1),
  975. edacl(1),
  976. lsacl(1),
  977. setacl(2)
  978. .SH CAVEAT
  979. The implementation of access control lists is an experiment.  This
  980. implementation stores the access control list in a (formerly) unused field
  981. in the inode.
  982. There is no guarantee that future versions of Unix will not use this field
  983. for something else.
  984. .PP
  985. Therefore, you should only use access control lists with the full
  986. understanding that you are participating in an experiment.
  987. !E!O!F!
  988. echo x - h.pat
  989. cat >h.pat <<'!E!O!F!'
  990. RCS file: inode.h,v
  991. retrieving revision 1.1
  992. diff -c1 -r1.1 inode.h
  993. *** inode.h.r1_1    Tue Jun 25 18:55:17 1985
  994. --- inode.h    Tue Apr 30 16:36:54 1985
  995. ***************
  996. *** 48,50
  997.           long    ic_blocks;    /* 104: blocks actually held */
  998. !         long    ic_spare[5];    /* 108: reserved, currently unused */
  999.       } i_ic;
  1000.  
  1001. --- 48,51 -----
  1002.           long    ic_blocks;    /* 104: blocks actually held */
  1003. !         char    ic_acle[(MAXACL+1)/2];
  1004. !         short    ic_aclid[MAXACL];
  1005.       } i_ic;
  1006. ***************
  1007. *** 58,59
  1008.   };
  1009.   
  1010.  
  1011. --- 59,63 -----
  1012.   };
  1013. + #define i_acle        i_ic.ic_acle
  1014. + #define i_aclid        i_ic.ic_aclid
  1015.   
  1016.  
  1017. # putting MAXACL in param.h is not a good idea, since changing param.h
  1018. # causes the whole kernel to be recompiled.  you might try putting MAXACL
  1019. # in acl.h , and including acl.h in inode.h .
  1020.  
  1021. RCS file: param.h,v
  1022. retrieving revision 1.1
  1023. diff -c2 -r1.1 param.h
  1024. *** param.h.r1_1    Tue Jun 25 18:15:16 1985
  1025. --- param.h    Tue Apr 30 16:31:54 1985
  1026. ***************
  1027. *** 27,30
  1028.   
  1029.   /*
  1030.    * Priorities
  1031.    */
  1032.  
  1033. --- 27,35 -----
  1034.   
  1035.   /*
  1036. +  * Access Control Lists
  1037. +  */
  1038. + #define MAXACL 8
  1039. + /*
  1040.    * Priorities
  1041.    */
  1042. !E!O!F!
  1043. echo x - jjg.h
  1044. cat >jjg.h <<'!E!O!F!'
  1045. typedef enum { FALSE = 0, TRUE = 1 } bool;
  1046.  
  1047. #include <strings.h>
  1048. #define equal(x,y)    ( strcmp((x),(y)) == 0 )
  1049. #define equaln(x,y,n)    ( strncmp((x),(y),(n)) == 0 )
  1050. #define any(p,c)    ( index((p),(c)) != (char *)0 )
  1051.  
  1052. #ifdef DEBUG
  1053. #ifndef stderr
  1054. #include <stdio.h>
  1055. #endif
  1056. #define dprintf(x)    if (debug_control) fprintf( stderr, (x) )
  1057. #define d2printf(x,y)    if (debug_control) fprintf( stderr, (x), (y) )
  1058. #define d3printf(x,y,z)    if (debug_control) fprintf( stderr, (x), (y), (z) )
  1059. #define DEBUG_FILE    "./.debug"
  1060. #define debug_test    debug_control = (bool) (access(DEBUG_FILE,0) == 0)
  1061. #define debug_var    bool debug_control = TRUE;
  1062. extern bool debug_control;
  1063. #else
  1064. #define dprintf(x)    /* null */
  1065. #define d2printf(x,y)    /* null */
  1066. #define d3printf(x,y,z)    /* null */
  1067. #define debug_test    /* null */
  1068. #define debug_var    /* null */
  1069. #endif
  1070.  
  1071. #ifdef BSD41
  1072. int BSD41_i;
  1073. #define bcopy(x,y,n) for ( BSD41_i = 0; BSD41_i < (n); BSD41_i++ ) \
  1074.             (y)[BSD41_i] = (x)[BSD41_i]
  1075. #define bzero(x,n) for ( BSD41_i = 0; BSD41_i < (n); BSD41_i++ ) \
  1076.             (x)[BSD41_i] = 0
  1077. #endif
  1078. !E!O!F!
  1079. echo x - login.pat
  1080. cat >login.pat <<'!E!O!F!'
  1081. RCS file: login.c,v
  1082. retrieving revision 1.1
  1083. diff -c2 -r1.1 login.c
  1084. *** login.c.r1_1    Wed Jun 26 10:19:05 1985
  1085. --- login.c    Wed Jun 26 10:16:48 1985
  1086. ***************
  1087. *** 14,17
  1088.   #include <sys/time.h>
  1089.   #include <sys/resource.h>
  1090.   
  1091.   #include <sgtty.h>
  1092.  
  1093. --- 14,18 -----
  1094.   #include <sys/time.h>
  1095.   #include <sys/resource.h>
  1096. + #include <sys/acl.h>
  1097.   
  1098.   #include <sgtty.h>
  1099. ***************
  1100. *** 93,96
  1101.   char    *rhost;
  1102.   
  1103.   main(argc, argv)
  1104.       char *argv[];
  1105.  
  1106. --- 94,99 -----
  1107.   char    *rhost;
  1108.   
  1109. + struct acle null_acl[1];
  1110.   main(argc, argv)
  1111.       char *argv[];
  1112. ***************
  1113. *** 286,289
  1114.       chown(ttyn, pwd->pw_uid, pwd->pw_gid);
  1115.       chmod(ttyn, 0622);
  1116.       setgid(pwd->pw_gid);
  1117.       strncpy(name, utmp.ut_name, NMAX);
  1118.  
  1119. --- 289,296 -----
  1120.       chown(ttyn, pwd->pw_uid, pwd->pw_gid);
  1121.       chmod(ttyn, 0622);
  1122. +     /*
  1123. +      * clear the acl.  
  1124. +      */
  1125. +     setacl(ttyn, 0, null_acl );
  1126.       setgid(pwd->pw_gid);
  1127.       strncpy(name, utmp.ut_name, NMAX);
  1128. !E!O!F!
  1129. echo x - lsacl.c
  1130. cat >lsacl.c <<'!E!O!F!'
  1131. #include <stdio.h>
  1132. #include <sys/param.h>
  1133. #include <sys/acl.h>
  1134. #include <grp.h>
  1135. #include <pwd.h>
  1136.  
  1137. main(argc, argv, environ)
  1138. int argc;
  1139. char *argv[], *environ[];
  1140. {
  1141.     int i, j, na;
  1142.     struct acle acl[MAXACL];
  1143.     int status;
  1144.  
  1145.     status = 0;
  1146.  
  1147.     for ( i = 1; i < argc; i++ ) {
  1148.         na = getacl( argv[i], MAXACL, acl );
  1149.  
  1150.         if ( na < 0 ) {
  1151.             perror( argv[i] );
  1152.             status++;
  1153.  
  1154.         } else {
  1155.             printf( "%s\n", argv[i] );
  1156.  
  1157.             for ( j = 0; j < na; j++ ) {
  1158.                 int type = acl[j].a_type;
  1159.                 int id = acl[j].a_id;
  1160.                 int mode = acl[j].a_mode;
  1161.  
  1162.                 if ( type == A_USER ) {
  1163.                     struct passwd *up = getpwuid(id);
  1164.  
  1165.                     if ( up == NULL ) {
  1166.                         printf( "\tuser\t[uid %d]\t%d\n", id, mode );
  1167.                     } else {
  1168.                         printf( "\tuser\t%s\t%d\n", up->pw_name, mode );
  1169.                     }
  1170.  
  1171.                 } else {
  1172.                     struct group *gp = getgrgid(id);
  1173.  
  1174.                     if ( gp == NULL ) {
  1175.                         printf( "\tgroup\t[gid %d]\t%d\n", id, mode );
  1176.                     } else {
  1177.                         printf( "\tgroup\t%s\t%d\n", gp->gr_name, mode );
  1178.                     }
  1179.                 }
  1180.             }
  1181.         }
  1182.     }
  1183.  
  1184.     exit( status );
  1185. }
  1186. !E!O!F!
  1187. echo x - lsacl.l
  1188. cat >lsacl.l <<'!E!O!F!'
  1189. ''' $Header:$
  1190. ''' 
  1191. ''' $Log:$
  1192. .de Sh
  1193. .br
  1194. .ne 5
  1195. .PP
  1196. \fB\\$1\fR
  1197. .PP
  1198. ..
  1199. .de Sp
  1200. .if t .sp .5v
  1201. .if n .sp
  1202. ..
  1203. '''
  1204. '''     Set up \*(-- to give an unbreakable dash;
  1205. '''     string Tr holds user defined translation string.
  1206. '''     Bell System Logo is used as a dummy character.
  1207. '''
  1208. .ie n \{\
  1209. .tr \(bs-\*(Tr
  1210. .ds -- \(bs-
  1211. .if (\n(.H=4u)&(1m=24u) .ds -- \(bs\h'-12u'\(bs\h'-12u'-\" diablo 10 pitch
  1212. .if (\n(.H=4u)&(1m=20u) .ds -- \(bs\h'-12u'\(bs\h'-8u'-\" diablo 12 pitch
  1213. .ds L" ""
  1214. .ds R" ""
  1215. .ds L' '
  1216. .ds R' '
  1217. 'br\}
  1218. .el\{\
  1219. .ds -- \(em\|
  1220. .tr \*(Tr
  1221. .ds L" ``
  1222. .ds R" ''
  1223. .ds L' `
  1224. .ds R' '
  1225. 'br\}
  1226. .TH LSACL 1 LOCAL
  1227. .SH NAME
  1228. lsacl - list the access control lists for files
  1229. .SH SYNOPSIS
  1230. .B lsacl
  1231. file ...
  1232. .SH DESCRIPTION
  1233. .I lsacl
  1234. lists the access control lists for one or more files.  The access control list
  1235. and the file's ownership are used to determine which users can access
  1236. the file.
  1237. .PP
  1238. For each file,
  1239. .I lsacl
  1240. prints the file name alone on a line.  Following that,
  1241. .I lsacl
  1242. prints the access control list entries, one per line.  The entries are
  1243. indented by a tab to make them easily distinguishable from the file name.
  1244. Each entry has a user or group name, and the mode granted to
  1245. that user or group.  The mode is a single digit in the range [0-7],
  1246. indicating read-write-execute permission ala
  1247. .IR chmod .
  1248. .SH DIAGNOSTICS
  1249. .I lsacl
  1250. returns with exit status 0 if all is well;  or with exit status greater
  1251. than 0 if it cannot get the access control lists for some files.
  1252. .SH SEE ALSO
  1253. chacl(1),
  1254. cpacl(1),
  1255. edacl(1),
  1256. getacl(2),
  1257. setacl(2)
  1258. .SH CAVEAT
  1259. The implementation of access control lists is an experiment.  This
  1260. implementation stores the access control list in a (formerly) unused field
  1261. in the inode.
  1262. There is no guarantee that future versions of Unix will not use this field
  1263. for something else.
  1264. .PP
  1265. Therefore, you should only use access control lists with the full
  1266. understanding that you are participating in an experiment.
  1267. .SH BUGS
  1268. The entire mechanism hasn't been fully tested.
  1269. .PP
  1270. It might be nice if the mode were given symbolically ("rwx" instead
  1271. of "7").
  1272. .PP
  1273. .I lsacl
  1274. should become yet another option to
  1275. .IR ls .
  1276. !E!O!F!
  1277. echo x - setacl.2
  1278. cat >setacl.2 <<'!E!O!F!'
  1279. .TH SETACL 2 "15 May 1985"
  1280. .UC 4
  1281. .SH NAME
  1282. setacl \- set the access control list for a file
  1283. .SH SYNOPSIS
  1284. .nf
  1285. .ft B
  1286. #include <sys/param.h>
  1287. #include <sys/acl.h>
  1288. .PP
  1289. .ft B
  1290. setacl(path, nacle, acl)
  1291. char *path;
  1292. int nacle;
  1293. struct acle *acl;
  1294. .fi
  1295. .SH DESCRIPTION
  1296. .I setacl
  1297. sets the access control list of the file whose name is given by
  1298. .IR path .
  1299. The list is taken from the array
  1300. .IR acl .
  1301. The parameter
  1302. .I nacle
  1303. indicates the number of entries in
  1304. .IR acl ,
  1305. which may not be larger than MAXACL , as defined in
  1306. .RI < sys/param.h >.
  1307. .PP
  1308. An access control list entry is described in
  1309. .RI < sys/acl.h >.
  1310. .PP
  1311. .nf
  1312. #define A_GROUP    1
  1313. #define A_USER    0
  1314.  
  1315. #define ok_uacle(a)    ( ( (a).a_type != A_USER ) || ( (a).a_id != 0 ) )
  1316.  
  1317. struct acle {
  1318.     char a_type;    /* A_GROUP or A_USER */
  1319.     char a_mode;    /* rwx [0-7] permissions */
  1320.     int a_id;    /* gid or uid according to a_type */
  1321. };
  1322. .fi
  1323. .PP
  1324. .I a_type
  1325. is a flag indicating whether the entry is for a user or a group.
  1326. .I a_id
  1327. contains either a uid or a gid, depending on the value of
  1328. .IR a_flag .
  1329. This user or group will have the permissions described by
  1330. .IR a_mode ,
  1331. which is an integer in the range 0-7. It indicates read-write-execute
  1332. permissions in the manner of
  1333. .IR chmod(2) .
  1334. .PP
  1335. Since the superuser always has access to all files, an entry may not
  1336. be specified for the superuser.  An entry with a zero
  1337. .I a_type
  1338. and a zero
  1339. .I a_id
  1340. is interpreted by
  1341. .I setacl
  1342. as an end-of-list marker.
  1343. .SH "RETURN VALUE
  1344. .I setacl
  1345. returns the value 0 if all is well.
  1346. A value of \-1 indicates that an error occurred, and the error
  1347. code is stored in the global variable \fIerrno\fP\|.
  1348. .SH "ERRORS
  1349. .I setacl
  1350. will fail if:
  1351. .TP 15
  1352. [EFAULT]
  1353. The argument
  1354. .I acl
  1355. specifies an invalid address.
  1356. .TP 15
  1357. [EINVAL]
  1358. The argument
  1359. .I nacle
  1360. is greater than MAXACL.
  1361. .TP 15
  1362. [EPERM]
  1363. The argument
  1364. .I path
  1365. contains a byte with the high-order bit set.
  1366. .TP 15
  1367. [ENOTDIR]
  1368. A component of the pathname is not a directory.
  1369. .TP 15
  1370. [ENOENT]
  1371. The pathname was too long, or the named file does not exist.
  1372. .TP 15
  1373. [EACCES]
  1374. Search permission is denied on a component of the pathname.
  1375. .TP 15
  1376. [EPERM]
  1377. The effective userid does not match the owner of the file and the
  1378. effective userid is not the superuser.
  1379. .TP 15
  1380. [EROFS]
  1381. The named file resides on a read-only file system.
  1382. [ELOOP]
  1383. Too many symbolic links were encountered in translating the pathname.
  1384. .SH SEE ALSO
  1385. chacl(1),
  1386. cpacl(1),
  1387. edacl(1),
  1388. lsacl(1),
  1389. setacl(2)
  1390. .SH CAVEAT
  1391. The implementation of access control lists is an experiment.  This
  1392. implementation stores the access control list in a (formerly) unused field
  1393. in the inode.
  1394. There is no guarantee that future versions of Unix will not use this field
  1395. for something else.
  1396. .PP
  1397. Therefore, you should only use access control lists with the full
  1398. understanding that you are participating in an experiment.
  1399. .SH BUGS
  1400. Setting an access control list entry for the file's owner has no
  1401. effect, because of the order in which the file access mode and the access
  1402. control list are checked.  To wit, the owner permission
  1403. in the file access mode is checked before the access control
  1404. list entry for the file's owner. 
  1405. This is arguably wrong, since the system reverses this order
  1406. when checking for the permission for the file's group (i.e., the
  1407. access control list entry for the file's group is checked before the 
  1408. group permission in the file access mode).
  1409. !E!O!F!
  1410. echo x - sys.pat
  1411. cat >sys.pat <<'!E!O!F!'
  1412. RCS file: RCS/ufs_syscalls.c,v
  1413. retrieving revision 1.1
  1414. diff -c2 -r1.1 ufs_syscalls.c
  1415. *** ufs_syscalls.r1_1    Tue Jun 25 18:34:36 1985
  1416. --- ufs_syscalls.c    Tue Jun 25 18:33:05 1985
  1417. ***************
  1418. *** 1049,1052
  1419.           mode |= IFREG;
  1420.       ip->i_mode = mode & ~u.u_cmask;
  1421.       ip->i_nlink = 1;
  1422.       ip->i_uid = u.u_uid;
  1423.  
  1424. --- 1049,1059 -----
  1425.           mode |= IFREG;
  1426.       ip->i_mode = mode & ~u.u_cmask;
  1427. +     /*
  1428. +      * clear the acl.  there should be a default acl (besides a null one).
  1429. +      * there is no room to put a default acl in the parent directory's
  1430. +      * inode;  so the alternative is to put a default acl in the u area
  1431. +      * (which is where the umask is).
  1432. +      */
  1433. +     null_acle( ip, 0 );
  1434.       ip->i_nlink = 1;
  1435.       ip->i_uid = u.u_uid;
  1436. ***************
  1437. *** 1126,1129
  1438.       ip->i_flag |= IACC|IUPD|ICHG;
  1439.       ip->i_mode = uap->dmode & ~u.u_cmask;
  1440.       ip->i_nlink = 2;
  1441.       ip->i_uid = u.u_uid;
  1442.  
  1443. --- 1133,1143 -----
  1444.       ip->i_flag |= IACC|IUPD|ICHG;
  1445.       ip->i_mode = uap->dmode & ~u.u_cmask;
  1446. +     /*
  1447. +      * clear the acl.  there should be a default acl (besides a null one).
  1448. +      * a good default for a directory might be to copy the parent
  1449. +      * directory's acl.  or put a default directory acl alongside the
  1450. +      * default file acl (wherever that ends up).
  1451. +      */
  1452. +     null_acle( ip, 0 );
  1453.       ip->i_nlink = 2;
  1454.       ip->i_uid = u.u_uid;
  1455.  
  1456. # there are some changes to the access() routine, just because it made
  1457. # it more readable for me, that have nothing to do with acls.  like
  1458. # changing the "m" variable to "mode_desire".
  1459.  
  1460. RCS file: RCS/ufs_fio.c,v
  1461. retrieving revision 1.1
  1462. diff -c2 -r1.1 ufs_fio.c
  1463. *** ufs_fio.c.r1_1    Tue Jun 25 18:47:49 1985
  1464. --- ufs_fio.c    Tue Jun 25 18:45:33 1985
  1465. ***************
  1466. *** 17,20
  1467.   #include "../h/proc.h"
  1468.   #include "../h/nami.h"
  1469.   
  1470.   /*
  1471.  
  1472. --- 17,21 -----
  1473.   #include "../h/proc.h"
  1474.   #include "../h/nami.h"
  1475. + #include "../h/acl.h"
  1476.   
  1477.   /*
  1478. ***************
  1479. *** 31,35
  1480.    * permissions.
  1481.    */
  1482. ! access(ip, mode)
  1483.       register struct inode *ip;
  1484.       int mode;
  1485.  
  1486. --- 32,36 -----
  1487.    * permissions.
  1488.    */
  1489. ! access(ip, mode_desire)
  1490.       register struct inode *ip;
  1491.       int mode_desire;
  1492. ***************
  1493. *** 33,37
  1494.   access(ip, mode)
  1495.       register struct inode *ip;
  1496. !     int mode;
  1497.   {
  1498.       register m;
  1499.  
  1500. --- 34,38 -----
  1501.   access(ip, mode_desire)
  1502.       register struct inode *ip;
  1503. !     int mode_desire;
  1504.   {
  1505.       register int i;
  1506. ***************
  1507. *** 35,40
  1508.       int mode;
  1509.   {
  1510. !     register m;
  1511. !     register int *gp;
  1512.   
  1513.       m = mode;
  1514.  
  1515. --- 36,43 -----
  1516.       int mode_desire;
  1517.   {
  1518. !     register int i;
  1519. !     int id_match;
  1520. !     int mode_allow;
  1521. !     int *gp;
  1522.   
  1523.       if (mode_desire == IWRITE) {
  1524. ***************
  1525. *** 38,43
  1526.       register int *gp;
  1527.   
  1528. !     m = mode;
  1529. !     if (m == IWRITE) {
  1530.           /*
  1531.            * Disallow write attempts on read-only
  1532.  
  1533. --- 41,45 -----
  1534.       int *gp;
  1535.   
  1536. !     if (mode_desire == IWRITE) {
  1537.           /*
  1538.            * Disallow write attempts on read-only
  1539. ***************
  1540. *** 78,92
  1541.        * check public access.
  1542.        */
  1543. !     if (u.u_uid != ip->i_uid) {
  1544. !         m >>= 3;
  1545. !         if (u.u_gid == ip->i_gid)
  1546. !             goto found;
  1547. !         gp = u.u_groups;
  1548. !         for (; gp < &u.u_groups[NGROUPS] && *gp != NOGROUP; gp++)
  1549. !             if (ip->i_gid == *gp)
  1550. !                 goto found;
  1551. !         m >>= 3;
  1552. ! found:
  1553. !         ;
  1554.       }
  1555.       if ((ip->i_mode&m) != 0)
  1556.  
  1557. --- 80,100 -----
  1558.        * check public access.
  1559.        */
  1560. !     id_match = 0;
  1561. !     /*
  1562. !      * user access (1) - match effective uid against fileowner uid.
  1563. !      * user access (2) - match group list against fileowner uid.
  1564. !      */
  1565. !     if (u.u_uid == ip->i_uid) {
  1566. !         id_match++;
  1567. !         mode_allow = ip->i_mode;
  1568. !     } else {
  1569. !         for( i = 0; i < MAXACL && ok_acle(ip,i); i++ ) {
  1570. !             if ( ( acle_type(ip,i) == A_USER ) &&
  1571. !                 ( u.u_uid == acle_id(ip,i) ) ) {
  1572. !                 id_match++;
  1573. !                 mode_allow = acle_mode(ip,i) << 6;
  1574. !                 break;
  1575. !             }
  1576. !         }
  1577.       }
  1578.           
  1579. ***************
  1580. *** 90,94
  1581.           ;
  1582.       }
  1583. !     if ((ip->i_mode&m) != 0)
  1584.           return (0);
  1585.       u.u_error = EACCES;
  1586.  
  1587. --- 98,158 -----
  1588.           }
  1589.       }
  1590. !         
  1591. !     /*
  1592. !      * group access (1) - match effective gid against acl.
  1593. !      */
  1594. !     if ( ! id_match ) {
  1595. !         mode_desire >>= 3;
  1596. !         for( i = 0; i < MAXACL && ok_acle(ip,i); i++ ) {
  1597. !             if ( ( acle_type(ip,i) == A_GROUP ) &&
  1598. !                 ( u.u_gid == acle_id(ip,i) ) ) {
  1599. !                 id_match++;
  1600. !                 mode_allow = acle_mode(ip,i) << 3;
  1601. !                 break;
  1602. !             }
  1603. !         }
  1604. !     }
  1605. !         
  1606. !     /*
  1607. !      * group access (2) - match group list against acl.
  1608. !      */
  1609. !     if ( ! id_match ) {
  1610. !         for (gp = u.u_groups; gp < &u.u_groups[NGROUPS] && *gp != NOGROUP; gp++)
  1611. !             for( i = 0; i < MAXACL && ok_acle(ip,i); i++ ) {
  1612. !                 if ( ( acle_type(ip,i) == A_GROUP ) &&
  1613. !                     ( *gp == acle_id(ip,i) ) ) {
  1614. !                     id_match++;
  1615. !                     mode_allow = acle_mode(ip,i) << 3;
  1616. !                     break;
  1617. !                 }
  1618. !             }
  1619. !     }
  1620. !         
  1621. !     /*
  1622. !      * group access (3) - match effective gid against fileowner gid.
  1623. !      * group access (4) - match group list against fileowner gid.
  1624. !      */
  1625. !     if ( ! id_match ) {
  1626. !         if ( u.u_gid == ip->i_gid ) {
  1627. !             id_match++;
  1628. !             mode_allow = ip->i_mode;
  1629. !         } else {
  1630. !             for (gp = u.u_groups; gp < &u.u_groups[NGROUPS] && *gp != NOGROUP; gp++)
  1631. !                 if (ip->i_gid == *gp) {
  1632. !                     id_match++;
  1633. !                     mode_allow = ip->i_mode;
  1634. !                     break;
  1635. !                 }
  1636. !         }
  1637. !     }
  1638. !     /*
  1639. !      * other access.
  1640. !      */
  1641. !     if ( ! id_match ) {
  1642. !         mode_desire >>= 3;
  1643. !         mode_allow = ip->i_mode;
  1644. !     }
  1645. !     if ((mode_allow&mode_desire) != 0)
  1646.           return (0);
  1647.       u.u_error = EACCES;
  1648. !E!O!F!
  1649.  
  1650.