ACL implementation on FreeSBD: semantics/standards/etc

Robert Watson robert at cyrus.watson.org
Mon Jan 17 17:38:15 GMT 2000


So I have pretty much finished implementing ACLs in FreeBSD--in 4.0, we'll be
shipping with the ACL interface in there, although not support in UFS/FFS for
the time being.  To make the POSIX.1e ACL spec fit our needs, I made a number
of design choices that either resolve ambiguities in the spec, or diverge from
the spec :-).  I thought I'd post a description of some of the things I did to
see if there was any other past experience in these areas, or concensus on the
approach, as well as to see if anyone had objections to the approaches :-).

1) Scrap the POSIX.1e ACL editing library, limiting interfaces to
allocating, freeing, validating, converting, getting, and setting of ACLs.
I found the editing library counter-intuitive and problematic to implement
given the ACL storage format I chose.  This reduces portability as this means
exposing the internals of acl_t, which in the case of FreeBSD is backed by
a struct acl:

#define MAX_ACL_ENTRIES 32    /* maximum entries in an ACL */
#define _POSIX_ACL_PATH_MAX     MAX_ACL_ENTRIES

struct acl_entry {
        acl_tag_t       ae_tag;
        uid_t           ae_id;
        acl_perm_t      ae_perm;
};

struct acl {
        int                     acl_cnt;
        struct acl_entry        acl_entry[MAX_ACL_ENTRIES];
};

I implemented the following POSIX.1e interfaces:
int	acl_calc_mask(acl_t *acl_p);
int	acl_delete_def_file(const char *path_p);
int	acl_delete_file(const char *path_p, acl_type_t type);
int	acl_delete_fd(int filedes, acl_type_t type);
int	acl_free(void *obj_p);
acl_t	acl_from_text(const char *buf_p);
acl_t	acl_get_fd(int fd, acl_type_t type);
acl_t	acl_get_file(const char *path_p, acl_type_t type);
acl_t	acl_init(int count);
int	acl_set_fd(int fd, acl_t acl, acl_type_t type);
int	acl_set_file(const char *path_p, acl_type_t type, acl_t acl);
char	*acl_to_text(acl_t acl, ssize_t *len_p);
int	acl_valid(acl_t acl);

I introduced the following non-POSIX.1e interfaces:
int	acl_delete_def_fd(int filedes);
int	acl_valid_file(const char *pathp, acl_type_t type, acl_t acl);
int	acl_valid_fd(int fd, acl_type_t type, acl_t acl);

In FreeBSD, a file descriptor for a directory may be returned--it seemed
inconsistent to allow fchown() and fchmod(), but not setting an ACL by file
descriptor, so I introduced acl_delete_def_fd() to complete the set of
set/get calls.

In FreeBSD, the VFS allows access to a wide variety of file systems with a
wide variety of semantics.  For example, AFS and Coda support an ACL mechanism
that is syntactically similar to the ACLs described in POSIX.1e, but
semantically different.  POSIX.1e does not preclude having additional
permissions, for example, but was not intended to support multiple semantics
in the same namespace, as would be the case with an FFS root partition, but
AFS /afs namespace.  Most of the routines couldn't care less about the
semantics, and it's clearly up to the file system to accept/reject ACLs as
they fit its needs.  But the acl_valid() routine asserts that it is possible
to test the validity of an ACL without knowledge of its context (acl type,
target object).  I implemented an acl_valid() according to the POSIX.1e
requirements, but also introduced acl_valid_file() and acl_valid_fd() that
test whether an ACL may be applied to a specific object or not.  The VFS
delivers this call to the final consumer of the vop_setacl() call via our
vop_aclcheck() vnode operation, and the file system can then return whatever
it sees fit.  I was tempted to make acl_valid() wrap acl_valid_file("/", ...)
but this didn't seem useful in as much as cute.  It also didn't seem
appropriate. :-)

2) Userland interface

Getfacl was easy to implement given these calls.  However, setfacl makes
reference to short ACLs being combined with relative permissions.  This
behavior wasn't well-defined, in my view, and I'm interested to see how others
interpretted and implemented this behavior.  Relative ACLs seem useful,
although they do introduce a race condition given the POSIX.1e get/set
interface, as there is no atomic get/modify/set behavior.  Locking could
be used to implement this, however.  For the time being, we have no plans to
ship a getfacl/setfacl with FreeBSD 4.0, but if I can resolve this then we
would go ahead and ship with it.

3) VFS interface

This is a BSD-specific thing, but I figured I'd post on this one also in case
anyone was interested.  We expose ACL syntax and calls at the VFS layer in the
following way:

#
#% getacl       vp      = = =
#
vop_getacl {
        IN struct vnode *vp;
        IN acl_type_t type;
        OUT struct acl *aclp;
        IN struct ucred *cred;
        IN struct proc *p;
};

#
#% setacl       vp      L L L
#
vop_setacl {
        IN struct vnode *vp;
        IN acl_type_t type;
        IN struct acl *aclp;
        IN struct ucred *cred;
        IN struct proc *p;
};

#
#% aclcheck     vp      = = =
#
vop_aclcheck {
        IN struct vnode *vp;
        IN acl_type_t type;
        IN struct acl *aclp;
        IN struct ucred *cred;
        IN struct proc *p;
};




  Robert N M Watson 

robert at fledge.watson.org              http://www.watson.org/~robert/
PGP key fingerprint: AF B5 5F FF A6 4A 79 37  ED 5F 55 E9 58 04 6A B1
TIS Labs at Network Associates, Safeport Network Services

To Unsubscribe: send mail to majordomo at cyrus.watson.org
with "unsubscribe posix1e" in the body of the message



More information about the posix1e mailing list