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