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>