PERFORCE change 144477 for review
Edward Tomasz Napierala
trasz at FreeBSD.org
Wed Jul 2 10:47:19 UTC 2008
http://perforce.freebsd.org/chv.cgi?CH=144477
Change 144477 by trasz at trasz_traszkan on 2008/07/02 10:46:29
Initial cut of the NFSv4 ACLs implementation, kernel part.
Affected files ...
.. //depot/projects/soc2008/trasz_nfs4acl/sys/conf/files#4 edit
.. //depot/projects/soc2008/trasz_nfs4acl/sys/kern/subr_acl_nfs4.c#1 add
.. //depot/projects/soc2008/trasz_nfs4acl/sys/kern/subr_acl_posix1e.c#2 edit
.. //depot/projects/soc2008/trasz_nfs4acl/sys/kern/vfs_acl.c#4 edit
.. //depot/projects/soc2008/trasz_nfs4acl/sys/sys/acl.h#6 edit
.. //depot/projects/soc2008/trasz_nfs4acl/sys/sys/vnode.h#2 edit
.. //depot/projects/soc2008/trasz_nfs4acl/sys/ufs/ffs/ffs_vfsops.c#4 edit
.. //depot/projects/soc2008/trasz_nfs4acl/sys/ufs/ufs/ufs_acl.c#5 edit
.. //depot/projects/soc2008/trasz_nfs4acl/sys/ufs/ufs/ufs_vnops.c#5 edit
Differences ...
==== //depot/projects/soc2008/trasz_nfs4acl/sys/conf/files#4 (text+ko) ====
@@ -1611,6 +1611,7 @@
kern/stack_protector.c standard \
compile-with "${NORMAL_C:N-fstack-protector*}"
kern/subr_acl_posix1e.c standard
+kern/subr_acl_nfs4.c standard
kern/subr_autoconf.c standard
kern/subr_blist.c standard
kern/subr_bus.c standard
==== //depot/projects/soc2008/trasz_nfs4acl/sys/kern/subr_acl_posix1e.c#2 (text+ko) ====
@@ -427,6 +427,10 @@
printf("acl_posix1e_mode_to_entry: invalid tag (%d)\n", tag);
}
+ acl_entry.ae_acl = NULL;
+ acl_entry.ae_extended = ACL_EXTENDED_ALLOW;
+ acl_entry.ae_flags = 0;
+
return (acl_entry);
}
==== //depot/projects/soc2008/trasz_nfs4acl/sys/kern/vfs_acl.c#4 (text+ko) ====
@@ -66,7 +66,114 @@
static int vacl_aclcheck(struct thread *td, struct vnode *vp,
acl_type_t type, struct acl *aclp);
+int
+acl_copy_oldacl_into_acl(const struct oldacl *source, struct acl *dest)
+{
+ int i;
+
+ if (source->acl_cnt < 0 || source->acl_cnt >= ACL_MAX_ENTRIES)
+ return (-1);
+
+ bzero(dest, sizeof(*dest));
+
+ dest->acl_magic = ACL_MAGIC;
+ dest->acl_cnt = source->acl_cnt;
+
+ for (i = 0; i < dest->acl_cnt; i++) {
+ dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag;
+ dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id;
+ dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm;
+ dest->acl_entry[i].ae_extended = ACL_EXTENDED_ALLOW;
+ dest->acl_entry[i].ae_flags = 0;
+ }
+
+ return (0);
+}
+
+int
+acl_copy_acl_into_oldacl(const struct acl *source, struct oldacl *dest)
+{
+ int i;
+
+ if (source->acl_cnt < 0 || source->acl_cnt >= ACL_MAX_ENTRIES)
+ return (-1);
+
+ bzero(dest, sizeof(*dest));
+
+ dest->acl_cnt = source->acl_cnt;
+
+ for (i = 0; i < dest->acl_cnt; i++) {
+ dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag;
+ dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id;
+ dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm;
+ }
+
+ return (0);
+}
+
/*
+ * At one time, "struct ACL" was extended in order to add support for NFSv4
+ * ACLs. Instead of creating compatibility versions of all the ACL-related
+ * syscalls, they were left intact. It's possible to find out what the code
+ * calling these syscalls (libc) expects basing on "type" argument - if it's
+ * either ACL_TYPE_ACCESS_OLD or ACL_TYPE_DEFAULT_OLD (which previously were
+ * known as ACL_TYPE_ACCESS and ACL_TYPE_DEFAULT), then it's the "struct
+ * oldacl". If it's something else, then it's the new "struct acl". In the
+ * latter case, the routines below just copyin/copyout the contents. In the
+ * former case, they copyin the "struct oldacl" and convert it to the new
+ * format.
+ */
+static int
+copyin_acl(void *user_acl, struct acl *kernel_acl, acl_type_t type)
+{
+ int error;
+ struct oldacl old;
+
+ /* Is it the new "struct acl"? */
+ if (type != ACL_TYPE_ACCESS_OLD && type != ACL_TYPE_DEFAULT_OLD)
+ return (copyin(user_acl, kernel_acl, sizeof(struct acl)));
+
+ /* Nope, it's a "struct oldacl". */
+ error = copyin(user_acl, &old, sizeof(struct oldacl));
+ if (error)
+ return (error);
+
+ error = acl_copy_oldacl_into_acl(&old, kernel_acl);
+
+ return (error);
+}
+
+static int
+copyout_acl(struct acl *kernel_acl, void *user_acl, acl_type_t type)
+{
+ int error;
+ struct oldacl old;
+
+ if (type != ACL_TYPE_ACCESS_OLD && type != ACL_TYPE_DEFAULT_OLD)
+ return (copyout(kernel_acl, user_acl, sizeof(struct acl)));
+
+ error = acl_copy_acl_into_oldacl(kernel_acl, &old);
+ if (error)
+ return (error);
+
+ error = copyout(&old, user_acl, sizeof(struct oldacl));
+
+ return (error);
+}
+
+static int
+type_unold(int type)
+{
+ if (type == ACL_TYPE_ACCESS_OLD)
+ return (ACL_TYPE_ACCESS);
+
+ if (type == ACL_TYPE_DEFAULT_OLD)
+ return (ACL_TYPE_DEFAULT);
+
+ return (type);
+}
+
+/*
* These calls wrap the real vnode operations, and are called by the syscall
* code once the syscall has converted the path or file descriptor to a vnode
* (unlocked). The aclp pointer is assumed still to point to userland, so
@@ -85,7 +192,7 @@
struct mount *mp;
int error;
- error = copyin(aclp, &inkernacl, sizeof(struct acl));
+ error = copyin_acl(aclp, &inkernacl, type);
if (error)
return(error);
error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
@@ -98,7 +205,7 @@
if (error != 0)
goto out;
#endif
- error = VOP_SETACL(vp, type, &inkernacl, td->td_ucred, td);
+ error = VOP_SETACL(vp, type_unold(type), &inkernacl, td->td_ucred, td);
#ifdef MAC
out:
#endif
@@ -124,13 +231,14 @@
if (error != 0)
goto out;
#endif
- error = VOP_GETACL(vp, type, &inkernelacl, td->td_ucred, td);
+ error = VOP_GETACL(vp, type_unold(type), &inkernelacl,
+ td->td_ucred, td);
#ifdef MAC
out:
#endif
VOP_UNLOCK(vp, 0);
if (error == 0)
- error = copyout(&inkernelacl, aclp, sizeof(struct acl));
+ error = copyout_acl(&inkernelacl, aclp, type);
return (error);
}
@@ -153,7 +261,7 @@
if (error)
goto out;
#endif
- error = VOP_SETACL(vp, type, 0, td->td_ucred, td);
+ error = VOP_SETACL(vp, type_unold(type), 0, td->td_ucred, td);
#ifdef MAC
out:
#endif
@@ -172,10 +280,11 @@
struct acl inkernelacl;
int error;
- error = copyin(aclp, &inkernelacl, sizeof(struct acl));
+ error = copyin_acl(aclp, &inkernelacl, type);
if (error)
return(error);
- error = VOP_ACLCHECK(vp, type, &inkernelacl, td->td_ucred, td);
+ error = VOP_ACLCHECK(vp, type_unold(type), &inkernelacl,
+ td->td_ucred, td);
return (error);
}
==== //depot/projects/soc2008/trasz_nfs4acl/sys/sys/acl.h#6 (text+ko) ====
@@ -47,23 +47,58 @@
#define POSIX1E_ACL_ACCESS_EXTATTR_NAME "posix1e.acl_access"
#define POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE EXTATTR_NAMESPACE_SYSTEM
#define POSIX1E_ACL_DEFAULT_EXTATTR_NAME "posix1e.acl_default"
+#define NFS4_ACL_EXTATTR_NAMESPACE EXTATTR_NAMESPACE_SYSTEM
+#define NFS4_ACL_EXTATTR_NAME "nfs4.acl"
#define ACL_MAX_ENTRIES 32 /* maximum entries in an ACL */
+/*
+ * "struct oldacl" is used in compatibility ACL syscalls and for on-disk
+ * storage of POSIX.1e ACLs.
+ */
+typedef int oldacl_tag_t;
+typedef mode_t oldacl_perm_t;
+
+struct oldacl_entry {
+ oldacl_tag_t ae_tag;
+ uid_t ae_id;
+ oldacl_perm_t ae_perm;
+};
+typedef struct oldacl_entry *oldacl_entry_t;
+
+/* internal ACL structure */
+struct oldacl {
+ int acl_cnt;
+ struct oldacl_entry acl_entry[ACL_MAX_ENTRIES];
+};
+
+/*
+ * Current "struct acl".
+ */
+typedef int acl_tag_t;
+typedef int acl_flag_t;
+typedef int acl_perm_t;
+typedef int acl_extended_t;
typedef int acl_type_t;
-typedef int acl_tag_t;
-typedef mode_t acl_perm_t;
-typedef mode_t *acl_permset_t;
+typedef int *acl_permset_t;
struct acl_entry {
acl_tag_t ae_tag;
uid_t ae_id;
acl_perm_t ae_perm;
+ /* "allow" or "deny". Unused in POSIX ACLs. */
+ acl_extended_t ae_extended;
+ /* Flags control inheritance. Unused in POSIX ACLs. */
+ acl_flag_t ae_flags;
+ struct acl *ae_acl; /* XXX: This is ugly. */
};
typedef struct acl_entry *acl_entry_t;
/* internal ACL structure */
struct acl {
+ int acl_magic;
int acl_cnt;
+ int acl_length;
+ int acl_brand;
struct acl_entry acl_entry[ACL_MAX_ENTRIES];
};
@@ -74,6 +109,15 @@
};
typedef struct acl_t_struct *acl_t;
+#define ACL_MAGIC 0x5452535a
+
+/*
+ * Possible valid values for acl_brand field.
+ */
+#define ACL_BRAND_UNKNOWN 0
+#define ACL_BRAND_POSIX 1
+#define ACL_BRAND_NFS4 2
+
/*
* Possible valid values for ae_tag field.
*/
@@ -85,15 +129,27 @@
#define ACL_MASK 0x00000010
#define ACL_OTHER 0x00000020
#define ACL_OTHER_OBJ ACL_OTHER
+#define ACL_EVERYONE 0x00000040
/*
+ * Possible valid values for ae_extended field.
+ */
+#define ACL_EXTENDED_ALLOW 0x00000100
+#define ACL_EXTENDED_DENY 0x00000200
+#define ACL_EXTENDED_AUDIT 0x00000400
+#define ACL_EXTENDED_ALARM 0x00000800
+
+/*
* Possible valid values for acl_type_t arguments.
*/
-#define ACL_TYPE_ACCESS 0x00000000
-#define ACL_TYPE_DEFAULT 0x00000001
+#define ACL_TYPE_ACCESS_OLD 0x00000000
+#define ACL_TYPE_DEFAULT_OLD 0x00000001
+#define ACL_TYPE_ACCESS 0x00000002
+#define ACL_TYPE_DEFAULT 0x00000003
+#define ACL_TYPE_NFS4 0x00000004
/*
- * Possible flags in ae_perm field.
+ * Possible flags in ae_perm field for POSIX ACLs.
*/
#define ACL_EXECUTE 0x0001
#define ACL_WRITE 0x0002
@@ -103,12 +159,65 @@
#define ACL_POSIX1E_BITS (ACL_EXECUTE | ACL_WRITE | ACL_READ)
/*
+ * Possible flags in ae_perm field for NFSv4 ACLs.
+ * XXX: Change values of these to match rfc3530.
+ */
+#define ACL_READ_DATA 0x00010000
+#define ACL_LIST_DIRECTORY 0x00010000
+#define ACL_WRITE_DATA 0x00020000
+#define ACL_ADD_FILE 0x00020000
+#define ACL_APPEND_DATA 0x00040000
+#define ACL_ADD_SUBDIRECTORY 0x00040000
+#define ACL_READ_NAMED_ATTRS 0x00080000
+#define ACL_READ_EXTATTRIBUTES ACL_READ_NAMED_ATTRS /* Darwin compatibility. */
+#define ACL_WRITE_NAMED_ATTRS 0x00100000
+#define ACL_WRITE_EXTATTRIBUTES ACL_WRITE_NAMED_ATTRS /* Darwin compatibility. */
+#ifdef XXX_conflicting_defines
+#define ACL_EXECUTE 0x00200000
+#define ACL_SEARCH ACL_EXECUTE /* Darwin compatibility. */
+#else
+#define ACL_SEARCH 0x00200000
+#endif
+#define ACL_DELETE_CHILD 0x00400000
+#define ACL_READ_ATTRIBUTES 0x00800000
+#define ACL_WRITE_ATTRIBUTES 0x01000000
+#define ACL_DELETE 0x02000000
+#define ACL_READ_ACL 0x04000000
+#define ACL_READ_SECURITY ACL_READ_ACL /* Darwin compatibility. */
+#define ACL_WRITE_ACL 0x08000000
+#define ACL_WRITE_SECURITY ACL_WRITE_ACL /* Darwin compatibility. */
+#define ACL_WRITE_OWNER 0x10000000
+#define ACL_CHANGE_OWNER ACL_WRITE_OWNER /* Darwin compatibility. */
+#define ACL_SYNCHRONIZE 0x20000000
+
+#define ACL_NFS4_PERM_BITS (ACL_READ_DATA | ACL_WRITE_DATA | ACL_APPEND_DATA | \
+ ACL_READ_NAMED_ATTRS | ACL_WRITE_NAMED_ATTRS | ACL_EXECUTE | ACL_DELETE_CHILD | \
+ ACL_READ_ATTRIBUTES | ACL_WRITE_ATTRIBUTES | ACL_DELETE | ACL_READ_ACL | \
+ ACL_WRITE_ACL | ACL_WRITE_OWNER | ACL_SYNCHRONIZE)
+
+/*
* Possible entry_id values for acl_get_entry()
*/
#define ACL_FIRST_ENTRY 0
#define ACL_NEXT_ENTRY 1
/*
+ * Possible values in ae_flags field; valid only for NFSv4 ACLs.
+ */
+/* #define ACL_FLAG_DEFER_INHERIT - this doesn't seem to be used in Darwin. */
+/* #define ACL_ENTRY_INHERITED - this seems to be used in Darwin, but how does it translate into rfc3530? */
+#define ACL_ENTRY_FILE_INHERIT 0x00000001 /* ACE4_FILE_INHERIT_ACE */
+#define ACL_ENTRY_DIRECTORY_INHERIT 0x00000002 /* ACE4_DIRECTORY_INHERIT_ACE */
+#define ACL_ENTRY_LIMIT_INHERIT 0x00000004 /* ACE4_NO_PROPAGATE_INHERIT_ACE */
+#define ACL_ENTRY_ONLY_INHERIT 0x00000008 /* ACE4_INHERIT_ONLY_ACE */
+#define ACL_FLAG_SUCCESSFUL_ACCESS 0x00000010 /* Valid only for ACL_EXTENDED_ALARM and ACL_EXTENDED_AUDIT. */
+#define ACL_FLAG_FAILED_ACCESS 0x00000020 /* s/a */
+
+#define ACL_FLAGS_BITS (ACL_ENTRY_FILE_INHERIT | ACL_ENTRY_DIRECTORY_INHERIT | \
+ ACL_ENTRY_LIMIT_INHERIT | ACL_ENTRY_ONLY_INHERIT | ACL_FLAG_SUCCESSFUL_ACCESS | \
+ ACL_FLAG_FAILED_ACCESS)
+
+/*
* Undefined value in ae_id field
*/
#define ACL_UNDEFINED_ID ((uid_t)-1)
@@ -118,6 +227,7 @@
extern uma_zone_t acl_zone;
+#endif
/*
* POSIX.1e ACLs are capable of expressing the read, write, and execute bits
* of the POSIX mode field. We provide two masks: one that defines the bits
@@ -127,6 +237,7 @@
#define ACL_OVERRIDE_MASK (S_IRWXU | S_IRWXG | S_IRWXO)
#define ACL_PRESERVE_MASK (~ACL_OVERRIDE_MASK)
+#ifdef _KERNEL
/*
* File system independent code to move back and forth between POSIX mode and
* POSIX.1e ACL representations.
@@ -142,10 +253,19 @@
mode_t acl_posix1e_newfilemode(mode_t cmode,
struct acl *dacl);
+int acl_nfs4_sync_acl_from_mode(struct acl *aclp, mode_t mode, int file_owner_id);
+void acl_nfs4_sync_mode_from_acl(mode_t *mode, const struct acl *aclp);
+int acl_nfs4_is_trivial(const struct acl *aclp);
+int acl_nfs4_compute_inherited_acl(struct acl *child_aclp, const struct acl *parent_aclp,
+ mode_t mode, int file_owner_id, int is_directory);
+int acl_copy_oldacl_into_acl(const struct oldacl *source, struct acl *dest);
+int acl_copy_acl_into_oldacl(const struct acl *source, struct oldacl *dest);
+
/*
* File system independent syntax check for a POSIX.1e ACL.
*/
int acl_posix1e_check(struct acl *acl);
+int acl_nfs4_check(const struct acl *aclp, int is_directory);
#else /* !_KERNEL */
@@ -184,7 +304,9 @@
ssize_t acl_copy_ext(void *_buf_p, acl_t _acl, ssize_t _size);
acl_t acl_copy_int(const void *_buf_p);
int acl_create_entry(acl_t *_acl_p, acl_entry_t *_entry_p);
+int acl_create_entry_at_position_np(acl_t *_acl_p, acl_entry_t *_entry_p, int _index);
int acl_delete_entry(acl_t _acl, acl_entry_t _entry_d);
+int acl_delete_entry_at_position_np(acl_t _acl, int _index);
int acl_delete_fd_np(int _filedes, acl_type_t _type);
int acl_delete_file_np(const char *_path_p, acl_type_t _type);
int acl_delete_link_np(const char *_path_p, acl_type_t _type);
@@ -198,6 +320,8 @@
acl_t acl_get_fd(int _fd);
acl_t acl_get_fd_np(int fd, acl_type_t _type);
acl_t acl_get_file(const char *_path_p, acl_type_t _type);
+int acl_get_flags_np(acl_entry_t _entry_d, acl_flag_t *_flags_p);
+int acl_get_extended_np(acl_entry_t _entry_d, acl_extended_t *_extended_p);
acl_t acl_get_link_np(const char *_path_p, acl_type_t _type);
void *acl_get_qualifier(acl_entry_t _entry_d);
int acl_get_perm_np(acl_permset_t _permset_d, acl_perm_t _perm);
@@ -207,6 +331,8 @@
int acl_set_fd(int _fd, acl_t _acl);
int acl_set_fd_np(int _fd, acl_t _acl, acl_type_t _type);
int acl_set_file(const char *_path_p, acl_type_t _type, acl_t _acl);
+int acl_set_flags_np(acl_entry_t _entry_d, acl_flag_t _flags);
+int acl_set_extended_np(acl_entry_t _entry_d, acl_extended_t _extended);
int acl_set_link_np(const char *_path_p, acl_type_t _type, acl_t _acl);
int acl_set_permset(acl_entry_t _entry_d, acl_permset_t _permset_d);
int acl_set_qualifier(acl_entry_t _entry_d, const void *_tag_qualifier_p);
@@ -217,6 +343,9 @@
int acl_valid_fd_np(int _fd, acl_type_t _type, acl_t _acl);
int acl_valid_file_np(const char *_path_p, acl_type_t _type, acl_t _acl);
int acl_valid_link_np(const char *_path_p, acl_type_t _type, acl_t _acl);
+int acl_is_trivial_np(const acl_t _acl);
+acl_t acl_compute_trivial_np(const acl_t _acl);
+acl_t acl_strip_np(const acl_t _acl, int recalculate_mask);
__END_DECLS
#endif /* !_KERNEL */
==== //depot/projects/soc2008/trasz_nfs4acl/sys/sys/vnode.h#2 (text+ko) ====
@@ -589,6 +589,9 @@
int vaccess_acl_posix1e(enum vtype type, uid_t file_uid,
gid_t file_gid, struct acl *acl, mode_t acc_mode,
struct ucred *cred, int *privused);
+int vaccess_acl_nfs4(enum vtype type, uid_t file_uid,
+ gid_t file_gid, struct acl *acl, mode_t acc_mode,
+ struct ucred *cred, int *privused);
void vattr_null(struct vattr *vap);
int vcount(struct vnode *vp);
void vdrop(struct vnode *);
==== //depot/projects/soc2008/trasz_nfs4acl/sys/ufs/ffs/ffs_vfsops.c#4 (text+ko) ====
@@ -172,10 +172,12 @@
vfs_deleteopt(mp->mnt_opt, "snapshot");
if (vfs_getopt(mp->mnt_optnew, "nfs4acls", NULL, NULL) == 0) {
- printf("WARNING: both acls and nfs4acls specified\n");
+ if (mntorflags & MNT_ACLS) {
+ printf("WARNING: both acls and nfs4acls specified\n");
#if 0
- return (EINVAL);
+ return (EINVAL);
#endif
+ }
mntorflags |= MNT_NFS4ACLS;
}
==== //depot/projects/soc2008/trasz_nfs4acl/sys/ufs/ufs/ufs_acl.c#5 (text+ko) ====
@@ -139,6 +139,52 @@
DIP_SET(ip, i_mode, ip->i_mode);
}
+static int
+ufs_getacl_nfs4(struct vop_getacl_args *ap)
+{
+ int error, len;
+ struct inode *ip = VTOI(ap->a_vp);
+
+ if ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 0)
+ return (EOPNOTSUPP);
+
+ bzero(ap->a_aclp, sizeof(*ap->a_aclp));
+ len = sizeof(*ap->a_aclp);
+
+ error = vn_extattr_get(ap->a_vp, IO_NODELOCKED,
+ NFS4_ACL_EXTATTR_NAMESPACE,
+ NFS4_ACL_EXTATTR_NAME, &len, (char *) ap->a_aclp,
+ ap->a_td);
+
+ if (error == ENOATTR) {
+ /*
+ * Legitimately no ACL set on object, purely
+ * emulate it through the inode.
+ */
+ error = acl_nfs4_sync_acl_from_mode(ap->a_aclp, ip->i_mode, ip->i_uid);
+
+ return (error);
+ }
+
+ if (error)
+ return (error);
+
+ if (len != sizeof(*ap->a_aclp)) {
+ /*
+ * A short (or long) read, meaning that for
+ * some reason the ACL is corrupted. Return
+ * EPERM since the object DAC protections
+ * are unsafe.
+ */
+ printf("ufs_getacl_nfs4(): Loaded invalid ACL ("
+ "%d bytes)\n", len);
+
+ return (EPERM);
+ }
+
+ return (0);
+}
+
/*
* Retrieve the ACL on a file.
*
@@ -146,18 +192,12 @@
* assemble both into a final ACL product. Right now this is not done
* very efficiently.
*/
-int
-ufs_getacl(ap)
- struct vop_getacl_args /* {
- struct vnode *vp;
- struct acl_type_t type;
- struct acl *aclp;
- struct ucred *cred;
- struct thread *td;
- } */ *ap;
+static int
+ufs_getacl_posix1e(struct vop_getacl_args *ap)
{
struct inode *ip = VTOI(ap->a_vp);
int error, len;
+ struct oldacl old;
/*
* XXX: If ufs_getacl() should work on file systems not supporting
@@ -169,8 +209,8 @@
/*
* Attempt to retrieve the ACL based on the ACL type.
*/
- bzero(ap->a_aclp, sizeof(*ap->a_aclp));
- len = sizeof(*ap->a_aclp);
+ bzero(&old, sizeof(old));
+ len = sizeof(old);
switch(ap->a_type) {
case ACL_TYPE_ACCESS:
/*
@@ -182,7 +222,7 @@
*/
error = vn_extattr_get(ap->a_vp, IO_NODELOCKED,
POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE,
- POSIX1E_ACL_ACCESS_EXTATTR_NAME, &len, (char *) ap->a_aclp,
+ POSIX1E_ACL_ACCESS_EXTATTR_NAME, &len, (char *) &old,
ap->a_td);
switch (error) {
/* XXX: If ufs_getacl() should work on filesystems without
@@ -194,34 +234,45 @@
* be updated when the ACL is synchronized with
* the inode later.
*/
- ap->a_aclp->acl_cnt = 3;
- ap->a_aclp->acl_entry[0].ae_tag = ACL_USER_OBJ;
- ap->a_aclp->acl_entry[0].ae_id = ACL_UNDEFINED_ID;
- ap->a_aclp->acl_entry[0].ae_perm = ACL_PERM_NONE;
- ap->a_aclp->acl_entry[1].ae_tag = ACL_GROUP_OBJ;
- ap->a_aclp->acl_entry[1].ae_id = ACL_UNDEFINED_ID;
- ap->a_aclp->acl_entry[1].ae_perm = ACL_PERM_NONE;
- ap->a_aclp->acl_entry[2].ae_tag = ACL_OTHER;
- ap->a_aclp->acl_entry[2].ae_id = ACL_UNDEFINED_ID;
- ap->a_aclp->acl_entry[2].ae_perm = ACL_PERM_NONE;
+ old.acl_cnt = 3;
+ old.acl_entry[0].ae_tag = ACL_USER_OBJ;
+ old.acl_entry[0].ae_id = ACL_UNDEFINED_ID;
+ old.acl_entry[0].ae_perm = ACL_PERM_NONE;
+ old.acl_entry[1].ae_tag = ACL_GROUP_OBJ;
+ old.acl_entry[1].ae_id = ACL_UNDEFINED_ID;
+ old.acl_entry[1].ae_perm = ACL_PERM_NONE;
+ old.acl_entry[2].ae_tag = ACL_OTHER;
+ old.acl_entry[2].ae_id = ACL_UNDEFINED_ID;
+ old.acl_entry[2].ae_perm = ACL_PERM_NONE;
+
+ error = acl_copy_oldacl_into_acl(&old, ap->a_aclp);
+ if (error)
+ return (error);
+
ufs_sync_acl_from_inode(ip, ap->a_aclp);
- error = 0;
- break;
+
+ return (0);
case 0:
- if (len != sizeof(*ap->a_aclp)) {
+ if (len != sizeof(old)) {
/*
* A short (or long) read, meaning that for
* some reason the ACL is corrupted. Return
* EPERM since the object DAC protections
* are unsafe.
*/
- printf("ufs_getacl(): Loaded invalid ACL ("
+ printf("ufs_getacl_posix1e(): Loaded invalid ACL ("
"%d bytes)\n", len);
return (EPERM);
}
+
+ error = acl_copy_oldacl_into_acl(&old, ap->a_aclp);
+ if (error)
+ return (error);
+
ufs_sync_acl_from_inode(ip, ap->a_aclp);
- break;
+
+ return (0);
default:
break;
@@ -236,7 +287,7 @@
error = vn_extattr_get(ap->a_vp, IO_NODELOCKED,
POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE,
POSIX1E_ACL_DEFAULT_EXTATTR_NAME, &len,
- (char *) ap->a_aclp, ap->a_td);
+ (char *) &old, ap->a_td);
/*
* Unlike ACL_TYPE_ACCESS, there is no relationship between
* the inode contents and the ACL, and it is therefore
@@ -248,13 +299,13 @@
/* XXX: If ufs_getacl() should work on filesystems without
* the EA configured, add case EOPNOTSUPP here. */
case ENOATTR:
- bzero(ap->a_aclp, sizeof(*ap->a_aclp));
- ap->a_aclp->acl_cnt = 0;
+ bzero(&old, sizeof(old));
+ old.acl_cnt = 0;
error = 0;
break;
case 0:
- if (len != sizeof(*ap->a_aclp)) {
+ if (len != sizeof(old)) {
/*
* A short (or long) read, meaning that for
* some reason the ACL is corrupted. Return
@@ -276,9 +327,98 @@
error = EINVAL;
}
+ if (error)
+ return (error);
+
+ error = acl_copy_oldacl_into_acl(&old, ap->a_aclp);
+
return (error);
}
+int
+ufs_getacl(ap)
+ struct vop_getacl_args /* {
+ struct vnode *vp;
+ acl_type_t type;
+ struct acl *aclp;
+ struct ucred *cred;
+ struct thread *td;
+ } */ *ap;
+{
+ if (ap->a_type == ACL_TYPE_NFS4)
+ return (ufs_getacl_nfs4(ap));
+
+ return (ufs_getacl_posix1e(ap));
+}
+
+static int
+ufs_setacl_nfs4(struct vop_setacl_args *ap)
+{
+ int error;
+ mode_t mode;
+ struct inode *ip = VTOI(ap->a_vp);
+
+ if ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 0)
+ return (EOPNOTSUPP);
+
+ if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
+ return (EROFS);
+
+ if (ap->a_aclp == NULL)
+ return (EINVAL);
+
+ error = VOP_ACLCHECK(ap->a_vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td);
+ if (error)
+ return (error);
+
+ /*
+ * Authorize the ACL operation.
+ */
+ if (ip->i_flags & (IMMUTABLE | APPEND))
+ return (EPERM);
+
+ /*
+ * Must hold VADMIN (be file owner) or have appropriate privilege.
+ */
+ if ((error = VOP_ACCESS(ap->a_vp, VADMIN, ap->a_cred, ap->a_td)))
+ return (error);
+
+ if (acl_nfs4_is_trivial(ap->a_aclp)) {
+ error = vn_extattr_rm(ap->a_vp, IO_NODELOCKED,
+ NFS4_ACL_EXTATTR_NAMESPACE,
+ NFS4_ACL_EXTATTR_NAME, ap->a_td);
+
+ } else {
+ error = vn_extattr_set(ap->a_vp, IO_NODELOCKED,
+ NFS4_ACL_EXTATTR_NAMESPACE,
+ NFS4_ACL_EXTATTR_NAME, sizeof(*ap->a_aclp),
+ (char *) ap->a_aclp, ap->a_td);
+ }
+
+ /*
+ * Map lack of attribute definition in UFS_EXTATTR into lack of
+ * support for ACLs on the filesystem.
+ */
+ if (error == ENOATTR)
+ return (EOPNOTSUPP);
+
+ if (error)
+ return (error);
+
+ mode = ip->i_mode;
+
+ acl_nfs4_sync_mode_from_acl(&mode, ap->a_aclp);
+
+ ip->i_mode &= ACL_PRESERVE_MASK;
+ ip->i_mode |= mode;
+ DIP_SET(ip, i_mode, ip->i_mode);
+ ip->i_flag |= IN_CHANGE;
+
+ VN_KNOTE_UNLOCKED(ap->a_vp, NOTE_ATTRIB);
+
+ return (0);
+}
+
/*
* Set the ACL on a file.
*
@@ -288,18 +428,12 @@
* a fair number of different access checks may be required to go ahead
* with the operation at all.
*/
-int
-ufs_setacl(ap)
- struct vop_setacl_args /* {
- struct vnode *vp;
- acl_type_t type;
- struct acl *aclp;
- struct ucred *cred;
- struct proc *p;
- } */ *ap;
+static int
+ufs_setacl_posix1e(struct vop_setacl_args *ap)
{
struct inode *ip = VTOI(ap->a_vp);
int error;
+ struct oldacl old;
if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0)
return (EOPNOTSUPP);
@@ -344,12 +478,16 @@
if ((error = VOP_ACCESS(ap->a_vp, VADMIN, ap->a_cred, ap->a_td)))
return (error);
+ error = acl_copy_acl_into_oldacl(ap->a_aclp, &old);
+ if (error)
+ return (error);
+
switch(ap->a_type) {
case ACL_TYPE_ACCESS:
error = vn_extattr_set(ap->a_vp, IO_NODELOCKED,
POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE,
- POSIX1E_ACL_ACCESS_EXTATTR_NAME, sizeof(*ap->a_aclp),
- (char *) ap->a_aclp, ap->a_td);
+ POSIX1E_ACL_ACCESS_EXTATTR_NAME, sizeof(old),
+ (char *) &old, ap->a_td);
break;
case ACL_TYPE_DEFAULT:
@@ -373,7 +511,7 @@
error = vn_extattr_set(ap->a_vp, IO_NODELOCKED,
POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE,
POSIX1E_ACL_DEFAULT_EXTATTR_NAME,
- sizeof(*ap->a_aclp), (char *) ap->a_aclp, ap->a_td);
+ sizeof(old), (char *) &old, ap->a_td);
break;
default:
@@ -401,12 +539,9 @@
return (0);
}
-/*
- * Check the validity of an ACL for a file.
- */
int
-ufs_aclcheck(ap)
- struct vop_aclcheck_args /* {
+ufs_setacl(ap)
+ struct vop_setacl_args /* {
struct vnode *vp;
acl_type_t type;
struct acl *aclp;
@@ -414,7 +549,29 @@
struct thread *td;
} */ *ap;
{
+ if (ap->a_type == ACL_TYPE_NFS4)
+ return (ufs_setacl_nfs4(ap));
+
+ return (ufs_setacl_posix1e(ap));
+}
+
+static int
+ufs_aclcheck_nfs4(struct vop_aclcheck_args *ap)
+{
+ int is_directory = 0;
+
+ if ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 0)
+ return (EOPNOTSUPP);
+
+ if (ap->a_vp->v_type == VDIR)
+ is_directory = 1;
+ return (acl_nfs4_check(ap->a_aclp, is_directory));
+}
+
+static int
+ufs_aclcheck_posix1e(struct vop_aclcheck_args *ap)
+{
if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0)
return (EOPNOTSUPP);
@@ -438,4 +595,23 @@
return (acl_posix1e_check(ap->a_aclp));
}
+/*
+ * Check the validity of an ACL for a file.
+ */
+int
+ufs_aclcheck(ap)
+ struct vop_aclcheck_args /* {
+ struct vnode *vp;
+ acl_type_t type;
+ struct acl *aclp;
+ struct ucred *cred;
+ struct thread *td;
+ } */ *ap;
+{
+ if (ap->a_type == ACL_TYPE_NFS4)
+ return (ufs_aclcheck_nfs4(ap));
+
+ return (ufs_aclcheck_posix1e(ap));
+}
+
#endif /* !UFS_ACL */
==== //depot/projects/soc2008/trasz_nfs4acl/sys/ufs/ufs/ufs_vnops.c#5 (text+ko) ====
@@ -312,6 +312,7 @@
int error;
#ifdef UFS_ACL
struct acl *acl;
+ acl_type_t type;
#endif
/*
@@ -337,9 +338,14 @@
return (EPERM);
#ifdef UFS_ACL
- if ((vp->v_mount->mnt_flag & MNT_ACLS) != 0) {
+ if ((vp->v_mount->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) != 0) {
+ if (vp->v_mount->mnt_flag & MNT_NFS4ACLS)
+ type = ACL_TYPE_NFS4;
+ else
+ type = ACL_TYPE_ACCESS;
+
acl = uma_zalloc(acl_zone, M_WAITOK);
- error = VOP_GETACL(vp, ACL_TYPE_ACCESS, acl, ap->a_cred,
+ error = VOP_GETACL(vp, type, acl, ap->a_cred,
ap->a_td);
switch (error) {
case EOPNOTSUPP:
@@ -347,8 +353,13 @@
ip->i_gid, ap->a_mode, ap->a_cred, NULL);
break;
case 0:
- error = vaccess_acl_posix1e(vp->v_type, ip->i_uid,
- ip->i_gid, acl, ap->a_mode, ap->a_cred, NULL);
+ if (type == ACL_TYPE_NFS4) {
+ error = vaccess_acl_nfs4(vp->v_type, ip->i_uid,
+ ip->i_gid, acl, ap->a_mode, ap->a_cred, NULL);
+ } else {
+ error = vaccess_acl_posix1e(vp->v_type, ip->i_uid,
+ ip->i_gid, acl, ap->a_mode, ap->a_cred, NULL);
+ }
break;
default:
printf(
@@ -631,6 +642,37 @@
return (error);
}
+#ifdef UFS_ACL
+static int
+ufs_update_nfs4_acl_after_mode_change(struct vnode *vp, int mode,
+ int file_owner_id, struct ucred *cred, struct thread *td)
+{
+ int error;
+ struct acl *aclp;
+
+ aclp = uma_zalloc(acl_zone, M_WAITOK);
+
+ error = VOP_GETACL(vp, ACL_TYPE_NFS4, aclp, cred, td);
+ /*
+ * We cannot get EOPNOTSUPP here, as the filesystem claims
+ * to support ACLs.
+ */
+ if (error)
+ goto out;
+
+ error = acl_nfs4_sync_acl_from_mode(aclp, mode, file_owner_id);
+ if (error)
+ goto out;
+
+ error = VOP_SETACL(vp, ACL_TYPE_NFS4, aclp, cred, td);
+
+out:
+ uma_zfree(acl_zone, aclp);
+
+ return (error);
+}
+#endif /* UFS_ACL */
+
/*
* Change the mode on a file.
* Inode must be locked before calling.
@@ -670,7 +712,11 @@
ip->i_mode |= (mode & ALLPERMS);
DIP_SET(ip, i_mode, ip->i_mode);
ip->i_flag |= IN_CHANGE;
- return (0);
+#ifdef UFS_ACL
+ if ((vp->v_mount->mnt_flag & MNT_NFS4ACLS) != 0)
+ error = ufs_update_nfs4_acl_after_mode_change(vp, mode, ip->i_uid, cred, td);
+#endif
+ return (error);
}
/*
@@ -1355,6 +1401,38 @@
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list