From 159de5f89c010dd2fe082d8b8109e5e3c8633462 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Thu, 25 Feb 2010 17:06:03 +0100 Subject: [PATCH] cifs: prototype implementation of client-side posix acl checks. --- fs/cifs/cifsfs.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 113 insertions(+), 1 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 29f1da7..cb31ecd 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -47,6 +47,8 @@ #include #include "dns_resolve.h" #include "cifs_spnego.h" +#include +#include #define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */ #ifdef CONFIG_CIFS_QUOTA @@ -269,6 +271,116 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf) return 0; } +static int cifs_check_acl(struct inode *inode, int mask) +{ + ssize_t rc = -EOPNOTSUPP; + struct cifs_sb_info *cifs_sb; + struct super_block *sb; + struct cifsTconInfo *pTcon; + int xid; + char *full_path; + void *ea_value = NULL; + size_t buf_size = 0; + struct dentry *dentry; + struct posix_acl *acl; + +printk(KERN_NOTICE "cifs_check_acl: entering\n"); + + sb = inode->i_sb; + if (sb == NULL) { + return -EIO; + } + + cifs_sb = CIFS_SB(sb); + pTcon = cifs_sb->tcon; + + xid = GetXid(); + + if (inode->i_dentry.next == NULL) { + /* no dentry found - deny access */ + FreeXid(xid); + return -EACCES; + } + + dentry = list_first_entry(&(inode->i_dentry), struct dentry, d_alias); + if (dentry == NULL) { + FreeXid(xid); + return -EACCES; + } + +printk(KERN_NOTICE "cifs_check_acl: got first dentry\n"); + + full_path = build_path_from_dentry(dentry); + if (full_path == NULL) { + rc = -ENOMEM; + FreeXid(xid); + return rc; + } + +printk(KERN_NOTICE "cifs_check_acl: got path '%s'\n", full_path); + + if (!(sb->s_flags & MS_POSIXACL)) { + rc = -EOPNOTSUPP; + goto out; + } + + ea_value = kmalloc(4096, GFP_KERNEL); + if (ea_value == NULL) { + rc = -ENOMEM; + goto out; + } + buf_size = (size_t)4096; + +printk(KERN_NOTICE "cifs_check_acl: allocated ea buffer (4096)\n"); + + rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, ea_value, + buf_size, ACL_TYPE_ACCESS, + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + if (rc == -1) { +printk(KERN_NOTICE "cifs_check_acl: error calling CIFSSMBGetPosixACL\n"); + goto out; + } + +printk(KERN_NOTICE "cifs_check_ack: CIFSSMBGetPosixACL returned %d\n", rc); + + acl = posix_acl_from_xattr(ea_value, rc); + + if (acl == NULL) { +printk(KERN_NOTICE "cifs_check_acl: error converting acl from ea buffer: NULL ACL\n"); + rc = -EAGAIN; + goto out; + } + + if (IS_ERR(acl)) { +printk(KERN_NOTICE "cifs_check_acl: error converting acl from ea buffer: IS_ERR(acl): %d\n", -PTR_ERR(acl)); + rc = PTR_ERR(acl); + goto out; + } + + rc = posix_acl_valid(acl); + if (rc != 0) { +printk(KERN_NOTICE "cifs_check_acl: acl is invalid\n"); + goto out; + } + + rc = posix_acl_permission(inode, acl, mask); + posix_acl_release(acl); + +printk(KERN_NOTICE "cifs_check_acl: posix_acl_permission check gave: %d\n", rc); + +out: + kfree(full_path); + FreeXid(xid); + if (ea_value != NULL) { + kfree(ea_value); + } + +printk(KERN_NOTICE "cifs_check_acl: done, returning %d\n", rc); + + return rc; +} + static int cifs_permission(struct inode *inode, int mask) { struct cifs_sb_info *cifs_sb; @@ -284,7 +396,7 @@ static int cifs_permission(struct inode *inode, int mask) on the client (above and beyond ACL on servers) for servers which do not support setting and viewing mode bits, so allowing client to check permissions is useful */ - return generic_permission(inode, mask, NULL); + return generic_permission(inode, mask, cifs_check_acl); } static struct kmem_cache *cifs_inode_cachep; -- 1.6.3.3