diff mbox

[linux-cifs-client,RFC] CIFS posix acl permission checking

Message ID E1NnU8A-00HEea-5z@intern.SerNet.DE (mailing list archive)
State New, archived
Headers show

Commit Message

Michael Adam March 5, 2010, 9:47 a.m. UTC
None
diff mbox

Patch

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(-)

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 <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