Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 2 Jul 2008 10:47:18 GMT
From:      Edward Tomasz Napierala <trasz@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 144477 for review
Message-ID:  <200807021047.m62AlICi010865@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=144477

Change 144477 by trasz@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) <<<



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200807021047.m62AlICi010865>