From 159de5f89c010dd2fe082d8b8109e5e3c8633462 Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox@samba.org>
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(-)
@@ -47,6 +47,8 @@
#include <linux/key-type.h>
#include "dns_resolve.h"
#include "cifs_spnego.h"
+#include <linux/posix_acl.h>
+#include <linux/posix_acl_xattr.h>
#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