Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

ACL support

  • Loading branch information...
commit dfca4c7affca1c095293a64c12aa429736df55fa 1 parent 29961d7
Prasad Joshi authored
23 include/lzfs_xattr.h
View
@@ -12,16 +12,35 @@ ssize_t
lzfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
extern struct xattr_handler lzfs_xattr_user_handler;
-
extern struct xattr_handler lzfs_xattr_security_handler;
+extern struct xattr_handler lzfs_xattr_acl_access_handler;
+extern struct xattr_handler lzfs_xattr_acl_default_handler;
int
lzfs_xattr_get(struct inode *inode, const char *name,
- void *buffer, size_t size, int);
+ void *buffer, size_t size, const char *xattr_name);
+
+int
+lzfs_xattr_set(struct inode *inode, const char *name,
+ void *buffer, size_t size, const char *xattr_name);
+
int
lzfs_removexattr(struct dentry *dentry, const char *name);
int
lzfs_init_security(struct dentry *dentry, struct inode *dir);
+
+extern int
+lzfs_acl_init(struct inode *inode, struct inode *dir);
+
+extern int
+lzfs_acl_chmod(struct inode *inode);
+
+extern int
+lzfs_check_acl(struct inode *inode, int mask);
+
+extern int
+lzfs_vnop_setattr(struct dentry *dentry, struct iattr *iattr);
+
#endif /* _LZFS_XATTR_H */
1  module/Makefile.in
View
@@ -14,6 +14,7 @@ lzfs-objs += lzfs_exportfs.o
lzfs-objs += lzfs_xattr.o
lzfs-objs += lzfs_xattr_user.o
lzfs-objs += lzfs_xattr_security.o
+lzfs-objs += lzfs_xattr_acl.o
INSTALL=/usr/bin/install
1  module/lzfs_super.c
View
@@ -258,6 +258,7 @@ lzfs_fill_super(struct super_block *sb, void *data, int silent)
sb->s_op = &lzfs_ops;
sb->s_time_gran = 1;
sb->s_flags = MS_ACTIVE;
+ sb->s_flags |= MS_POSIXACL;
sb->s_export_op = &zfs_export_ops;
sb->s_xattr = lzfs_xattr_handlers;
error = zfs_domount(vfsp, data);
93 module/lzfs_vnops.c
View
@@ -98,7 +98,7 @@ lzfs_vnop_create(struct inode *dir, struct dentry *dentry, int mode,
vattr_t *vap;
const struct cred *cred = get_current_cred();
- int err, se_err;
+ int err;
SENTRY;
err = checkname((char *)dentry->d_name.name);
@@ -122,20 +122,19 @@ lzfs_vnop_create(struct inode *dir, struct dentry *dentry, int mode,
put_cred(cred);
kfree(vap);
if (err) {
- tsd_exit();
- SEXIT;
- return PTR_ERR(ERR_PTR(-err));
+ err = -err;
+ goto failed;
}
d_instantiate(dentry, LZFS_VTOI(vp));
- se_err = lzfs_init_security(dentry, dir);
- if(se_err) {
- tsd_exit();
- SEXIT;
- return se_err;
+ if ((err = lzfs_acl_init(dentry->d_inode, dir))) {
+ /* XXX need more error handling */
+ goto failed;
}
+ err = lzfs_init_security(dentry, dir);
+failed:
tsd_exit();
SEXIT;
- return 0;
+ return err;
}
/* Read the directory. It uses the filldir function provided by Linux kernel.
@@ -281,7 +280,7 @@ lzfs_vnop_symlink (struct inode *dir, struct dentry *dentry,
vnode_t *vp;
vattr_t *vap;
const struct cred *cred = get_current_cred();
- int err, se_err;
+ int err;
SENTRY;
err = checkname((char *)dentry->d_name.name);
if(err)
@@ -303,20 +302,20 @@ lzfs_vnop_symlink (struct inode *dir, struct dentry *dentry,
kfree(vap);
put_cred(cred);
if (err) {
- tsd_exit();
- SEXIT;
- return PTR_ERR(ERR_PTR(-err));
+ err = -err;
+ goto failed;
}
d_instantiate(dentry, LZFS_VTOI(vp));
- se_err = lzfs_init_security(dentry, dir);
- if(se_err) {
- tsd_exit();
- SEXIT;
- return se_err;
+ err = lzfs_acl_init(dentry->d_inode, dir);
+ if(err) {
+ /* XXX error handling */
+ goto failed;
}
+ err = lzfs_init_security(dentry, dir);
+failed:
tsd_exit();
SEXIT;
- return 0;
+ return err;
}
static int
@@ -326,7 +325,7 @@ lzfs_vnop_mkdir(struct inode *dir, struct dentry *dentry, int mode)
vnode_t *dvp;
vattr_t *vap;
const struct cred *cred = get_current_cred();
- int err, se_err;
+ int err;
SENTRY;
err = checkname((char *)dentry->d_name.name);
if(err)
@@ -346,21 +345,20 @@ lzfs_vnop_mkdir(struct inode *dir, struct dentry *dentry, int mode)
kfree(vap);
put_cred(cred);
if (err) {
- tsd_exit();
- SEXIT;
- return PTR_ERR(ERR_PTR(-err));
+ err = -err;
+ goto failed;
}
d_instantiate(dentry, LZFS_VTOI(vp));
- se_err = lzfs_init_security(dentry, dir);
- if(se_err) {
- tsd_exit();
- SEXIT;
- return se_err;
+ err = lzfs_acl_init(dentry->d_inode,dir);
+ if(err) {
+ /* XXX error handling */
+ goto failed;
}
-
+ err = lzfs_init_security(dentry, dir);
+failed:
tsd_exit();
SEXIT;
- return 0;
+ return err;
}
static int
@@ -397,7 +395,7 @@ lzfs_vnop_mknod(struct inode * dir, struct dentry *dentry, int mode,
vattr_t *vap;
const struct cred *cred = get_current_cred();
- int err, se_err;
+ int err;
SENTRY;
vap = kmalloc(sizeof(vattr_t), GFP_KERNEL);
ASSERT(vap != NULL);
@@ -423,21 +421,22 @@ lzfs_vnop_mknod(struct inode * dir, struct dentry *dentry, int mode,
put_cred(cred);
kfree(vap);
if (err) {
- tsd_exit();
- SEXIT;
- return PTR_ERR(ERR_PTR(-err));
+ err = -err;
+ goto failed;
}
d_instantiate(dentry, LZFS_VTOI(vp));
- se_err = lzfs_init_security(dentry, dir);
- if(se_err) {
- tsd_exit();
- SEXIT;
- return se_err;
+ init_special_inode(dentry->d_inode,mode,rdev);
+ err = lzfs_acl_init(dentry->d_inode,dir);
+ if(err) {
+ /* XXX error handling */
+ goto failed;
}
+ err = lzfs_init_security(dentry, dir);
+failed:
tsd_exit();
SEXIT;
- return 0;
+ return err;
}
static int
@@ -526,6 +525,9 @@ lzfs_vnop_setattr(struct dentry *dentry, struct iattr *iattr)
err = zfs_setattr(vp, vap, 0, (struct cred *)cred, NULL);
kfree(vap);
+ if(mask & ATTR_MODE){
+ lzfs_acl_chmod(inode);
+ }
put_cred(cred);
tsd_exit();
SEXIT;
@@ -534,12 +536,15 @@ lzfs_vnop_setattr(struct dentry *dentry, struct iattr *iattr)
return 0;
}
+#if 0
int
lzfs_vnop_permission(struct inode *inode, int mask)
{
return generic_permission(inode, mask, NULL);
}
+#endif
+
static void lzfs_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr)
{
char *buf = nd_get_link(nd);
@@ -1194,7 +1199,8 @@ const struct inode_operations zfs_inode_operations = {
.mknod = lzfs_vnop_mknod,
.rename = lzfs_vnop_rename,
.setattr = lzfs_vnop_setattr,
- .permission = lzfs_vnop_permission,
+// .permission = lzfs_vnop_permission,
+ .check_acl = lzfs_check_acl,
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
.listxattr = lzfs_listxattr,
@@ -1225,7 +1231,8 @@ const struct inode_operations zfs_dir_inode_operations ={
.mknod = lzfs_vnop_mknod,
.rename = lzfs_vnop_rename,
.setattr = lzfs_vnop_setattr,
- .permission = lzfs_vnop_permission,
+// .permission = lzfs_vnop_permission,
+ .check_acl = lzfs_check_acl,
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
.listxattr = lzfs_listxattr,
441 module/lzfs_xattr_acl.c
View
@@ -0,0 +1,441 @@
+#include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/xattr.h>
+#include <linux/posix_acl_xattr.h>
+#include <linux/slab.h>
+
+#include <sys/vnode.h>
+#include <sys/vfs.h>
+
+#include <lzfs_xattr.h>
+
+static int lzfs_set_mode(struct inode *inode, mode_t mode)
+{
+ struct iattr *att;
+ struct dentry *fake_de = NULL;
+ int err = -ENOMEM;
+
+ att = kzalloc(sizeof(struct iattr), GFP_KERNEL);
+ if(att == NULL)
+ goto out;
+
+ fake_de = kzalloc(sizeof(struct dentry), GFP_KERNEL);
+ if(fake_de == NULL)
+ goto out;
+
+ fake_de->d_inode = inode;
+ att->ia_valid = ATTR_MODE;
+ att->ia_mode = mode;
+ err = lzfs_vnop_setattr(fake_de, att);
+out:
+ if (att)
+ kfree(att);
+ if (fake_de)
+ kfree(fake_de);
+ return err;
+
+}
+
+static int
+lzfs_set_acl(struct inode *inode,struct posix_acl *acl, int type)
+{
+ int err = 0;
+ size_t size=0;
+
+ char *xattr_name = NULL;
+ char * value = NULL;
+
+ if (S_ISLNK(inode->i_mode))
+ return -EOPNOTSUPP;
+
+ switch(type) {
+ case ACL_TYPE_ACCESS:
+ xattr_name = POSIX_ACL_XATTR_ACCESS;
+ if (acl) {
+ mode_t mode = inode->i_mode;
+ err = posix_acl_equiv_mode(acl, &mode);
+ if (err < 0)
+ return err;
+ else {
+ if (inode->i_mode != mode) {
+ int rc;
+ rc = lzfs_set_mode(inode,mode);
+ if (rc) {
+ /* XXX error handling */
+ }
+ }
+ if (err == 0) {
+ /* not extended attribute */
+ acl = NULL;
+ }
+ }
+ }
+ break;
+
+ case ACL_TYPE_DEFAULT:
+ xattr_name = POSIX_ACL_XATTR_DEFAULT;
+ if (!S_ISDIR(inode->i_mode))
+ return acl ? -EACCES : 0;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (acl) {
+ size = posix_acl_xattr_size(acl->a_count);
+ value = kmalloc(size, GFP_KERNEL);
+ if (IS_ERR(value))
+ return (int)PTR_ERR(value);
+
+ err = posix_acl_to_xattr(acl, value, size);
+ if (err < 0)
+ goto out;
+ }
+
+ err = lzfs_xattr_set(inode, xattr_name, value, size, xattr_name);
+
+ if (!err)
+ set_cached_acl(inode, type, acl);
+// posix_acl_release(acl);
+
+out:
+ if (value)
+ kfree(value);
+ return err;
+
+}
+
+
+static struct posix_acl *
+lzfs_get_acl(struct inode *inode, int type)
+{
+ char *name;
+ char *xattr_name;
+ char *value = NULL;
+ struct posix_acl *acl;
+ int retval;
+
+ acl = get_cached_acl(inode, type);
+ if (acl != ACL_NOT_CACHED)
+ return acl;
+
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ name = POSIX_ACL_XATTR_ACCESS;
+ break;
+ case ACL_TYPE_DEFAULT:
+ name = POSIX_ACL_XATTR_DEFAULT;
+ break;
+ default:
+ BUG();
+ }
+
+ xattr_name = kmalloc(strlen(name), GFP_NOFS);
+ if (!xattr_name)
+ return ERR_PTR(-ENOMEM);
+ xattr_name = strncpy(xattr_name, name,strlen(name));
+
+ retval = lzfs_xattr_get(inode, name, NULL, 0, xattr_name);
+ if (retval > 0) {
+ value = kmalloc(retval, GFP_NOFS);
+ if (!value) {
+ kfree(xattr_name);
+ return ERR_PTR(-ENOMEM);
+ }
+ retval = lzfs_xattr_get(inode, name, value, retval, xattr_name);
+ }
+ kfree(xattr_name);
+
+ if (retval > 0)
+ acl = posix_acl_from_xattr(value, retval);
+
+ else if (retval == -ENODATA || retval == -ENOSYS)
+ acl = NULL;
+ else
+ acl = ERR_PTR(retval);
+
+ if (value)
+ kfree(value);
+
+ if (!IS_ERR(acl))
+ set_cached_acl(inode, type, acl);
+
+ return acl;
+}
+
+int
+lzfs_acl_init(struct inode *inode, struct inode *dir)
+{
+ struct posix_acl *acl = NULL;
+ int error = 0;
+
+ if (!S_ISLNK(inode->i_mode)) {
+ acl = lzfs_get_acl(dir, ACL_TYPE_DEFAULT);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ if (!acl) {
+ inode->i_mode &= ~current_umask();
+ error = lzfs_set_mode(inode,inode->i_mode);
+ if (error)
+ goto cleanup;
+ }
+ }
+
+ if (acl) {
+ struct posix_acl *clone;
+ mode_t mode;
+
+ if (S_ISDIR(inode->i_mode)) {
+ error = lzfs_set_acl(inode, acl, ACL_TYPE_DEFAULT);
+ if (error < 0)
+ goto cleanup;
+ }
+ clone = posix_acl_clone(acl, GFP_NOFS);
+ error = -ENOMEM;
+ if (!clone)
+ goto cleanup;
+
+ mode = inode->i_mode;
+ error = posix_acl_create_masq(clone, &mode);
+ if (error >= 0) {
+ int err;
+ inode->i_mode = mode;
+ err = lzfs_set_mode(inode, mode);
+ if (error > 0) {
+ /* This is an extended ACL */
+ error = lzfs_set_acl(inode, clone, ACL_TYPE_ACCESS);
+ }
+ error |= err;
+ }
+ posix_acl_release(clone);
+ }
+cleanup:
+ posix_acl_release(acl);
+ return error;
+}
+
+int
+lzfs_check_acl(struct inode *inode, int mask)
+{
+ struct posix_acl *acl = lzfs_get_acl(inode, ACL_TYPE_ACCESS);
+
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ if (acl) {
+ int error = posix_acl_permission(inode, acl, mask);
+ posix_acl_release(acl);
+ return error;
+ }
+ return -EAGAIN;
+}
+
+int
+lzfs_acl_chmod(struct inode *inode)
+{
+ struct posix_acl *acl, *clone;
+ int error;
+
+ if (S_ISLNK(inode->i_mode))
+ return -EOPNOTSUPP;
+
+ acl = lzfs_get_acl(inode, ACL_TYPE_ACCESS);
+ if (IS_ERR(acl) || !acl)
+ return PTR_ERR(acl);
+ clone = posix_acl_clone(acl, GFP_KERNEL);
+ posix_acl_release(acl);
+ if (!clone)
+ return -ENOMEM;
+ error = posix_acl_chmod_masq(clone, inode->i_mode);
+ if (!error)
+ error = lzfs_set_acl(inode, clone, ACL_TYPE_ACCESS);
+ posix_acl_release(clone);
+ return error;
+
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
+static inline size_t
+lzfs_xattr_acl_list_access(struct inode *inode, char *list,
+ size_t list_size,const char *name, size_t name_len)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)
+static inline size_t
+lzfs_xattr_acl_list_access(struct dentry *dentry, char *list,
+ size_t list_size,const char *name, size_t name_len,int type)
+#endif
+{
+ const size_t total_len = sizeof(POSIX_ACL_XATTR_ACCESS);
+
+ if (list && total_len <= list_size)
+ memcpy(list, POSIX_ACL_XATTR_ACCESS, total_len);
+ return total_len;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
+static inline size_t
+lzfs_xattr_acl_list_default(struct inode *inode, char *list, size_t list_size,
+ const char *name, size_t name_len)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)
+static inline size_t
+lzfs_xattr_acl_list_default(struct dentry *dentry, char *list, size_t list_size,
+ const char *name, size_t name_len,int type)
+#endif
+{
+ const size_t total_len = sizeof(POSIX_ACL_XATTR_DEFAULT);
+
+ if (list && total_len <= list_size)
+ memcpy(list, POSIX_ACL_XATTR_DEFAULT,total_len);
+ return total_len;
+}
+
+
+static int
+lzfs_xattr_acl_get(struct dentry *dentry, const char *name, void *buffer,
+ size_t size, int type)
+{
+ struct posix_acl *acl;
+ int error;
+
+ if (strcmp(name, "") != 0)
+ return -EINVAL;
+
+ acl = lzfs_get_acl(dentry->d_inode, type);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ if (acl == NULL)
+ return -ENODATA;
+
+ error = posix_acl_to_xattr(acl, buffer, size);
+ posix_acl_release(acl);
+ return error;
+}
+
+static int
+lzfs_xattr_acl_set(struct dentry *dentry, const char *name, const void *value,
+ size_t size, int flags, int type)
+{
+ struct posix_acl * acl = NULL;
+ int err = 0;
+
+ if ((strcmp(name, "") != 0) &&
+ ((type != ACL_TYPE_ACCESS) && (type != ACL_TYPE_DEFAULT)))
+ return -EINVAL;
+
+ if (!is_owner_or_cap(dentry->d_inode))
+ return -EPERM;
+
+ if (value) {
+ acl = posix_acl_from_xattr(value, size);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ else if (acl) {
+ err = posix_acl_valid(acl);
+ if (err)
+ goto release_and_out;
+ }
+ }
+
+ err = lzfs_set_acl(dentry->d_inode, acl, type);
+release_and_out:
+ posix_acl_release(acl);
+ return err;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
+static inline int
+__lzfs_xattr_acl_get(struct inode *inode, const char *name,
+ void *buffer, size_t size, int type)
+{
+ struct dentry *fake_de = NULL;
+ int error;
+
+ fake_de = kzalloc(sizeof(struct dentry), GFP_KERNEL);
+ if (!fake_de)
+ return -ENOMEM;
+
+ fake_de->d_inode = inode;
+ error = lzfs_xattr_acl_get(fake_de, "", buffer, size, type);
+ kfree(fake_de);
+
+ return error;
+
+}
+
+static inline int
+lzfs_xattr_acl_get_access(struct inode *inode, const char *name,
+ void *buffer, size_t size)
+{
+ return __lzfs_xattr_acl_get(inode, name, buffer, size, ACL_TYPE_ACCESS);
+}
+
+static inline int
+__lzfs_xattr_acl_set(struct inode *inode, const char *name,
+ const void *buffer, size_t size, int type, int flags)
+{
+ struct dentry *fake_de = NULL;
+ int error;
+
+ fake_de = kzalloc(sizeof(struct dentry), GFP_KERNEL);
+ if (!fake_de)
+ return -ENOMEM;
+
+ fake_de->d_inode = inode;
+ error = lzfs_xattr_acl_set(fake_de, "", buffer, size, flags, type);
+ kfree(fake_de);
+
+ return error;
+
+}
+
+static inline int
+lzfs_xattr_acl_set_access(struct inode *inode, const char *name,
+ const void *buffer, size_t size, int flags)
+{
+ return __lzfs_xattr_acl_set(inode, name, buffer, size, flags, ACL_TYPE_ACCESS);
+}
+#endif
+
+struct xattr_handler lzfs_xattr_acl_access_handler =
+{
+ .prefix = POSIX_ACL_XATTR_ACCESS,
+ .list = lzfs_xattr_acl_list_access,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
+ .get = lzfs_xattr_acl_get_access,
+ .set = lzfs_xattr_acl_set_access,
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)
+ .get = lzfs_xattr_acl_get,
+ .set = lzfs_xattr_acl_set,
+ .flags = ACL_TYPE_ACCESS,
+#endif
+};
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
+static inline int
+lzfs_xattr_acl_get_default(struct inode *inode, const char *name,
+ void *buffer, size_t size)
+{
+ return __lzfs_xattr_acl_get(inode, name, buffer, size, ACL_TYPE_DEFAULT);
+}
+
+static inline int
+lzfs_xattr_acl_set_default(struct inode *inode, const char *name,
+ const void *buffer, size_t size, int flags)
+{
+ return __lzfs_xattr_acl_set(inode, name, buffer, size, flags, ACL_TYPE_DEFAULT);
+}
+#endif
+
+struct xattr_handler lzfs_xattr_acl_default_handler =
+{
+ .prefix = POSIX_ACL_XATTR_DEFAULT,
+ .list = lzfs_xattr_acl_list_default,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
+ .get = lzfs_xattr_acl_get_default,
+ .set = lzfs_xattr_acl_set_default,
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)
+ .get = lzfs_xattr_acl_get,
+ .set = lzfs_xattr_acl_set,
+ .flags = ACL_TYPE_DEFAULT,
+#endif
+};
Please sign in to comment.
Something went wrong with that request. Please try again.