xref: /openbmc/linux/fs/orangefs/acl.c (revision 5db11c21a929cd9d8c0484006efb1014fc723c93)
1*5db11c21SMike Marshall /*
2*5db11c21SMike Marshall  * (C) 2001 Clemson University and The University of Chicago
3*5db11c21SMike Marshall  *
4*5db11c21SMike Marshall  * See COPYING in top-level directory.
5*5db11c21SMike Marshall  */
6*5db11c21SMike Marshall 
7*5db11c21SMike Marshall #include "protocol.h"
8*5db11c21SMike Marshall #include "pvfs2-kernel.h"
9*5db11c21SMike Marshall #include "pvfs2-bufmap.h"
10*5db11c21SMike Marshall #include <linux/posix_acl_xattr.h>
11*5db11c21SMike Marshall #include <linux/fs_struct.h>
12*5db11c21SMike Marshall 
13*5db11c21SMike Marshall struct posix_acl *pvfs2_get_acl(struct inode *inode, int type)
14*5db11c21SMike Marshall {
15*5db11c21SMike Marshall 	struct posix_acl *acl;
16*5db11c21SMike Marshall 	int ret;
17*5db11c21SMike Marshall 	char *key = NULL, *value = NULL;
18*5db11c21SMike Marshall 
19*5db11c21SMike Marshall 	switch (type) {
20*5db11c21SMike Marshall 	case ACL_TYPE_ACCESS:
21*5db11c21SMike Marshall 		key = PVFS2_XATTR_NAME_ACL_ACCESS;
22*5db11c21SMike Marshall 		break;
23*5db11c21SMike Marshall 	case ACL_TYPE_DEFAULT:
24*5db11c21SMike Marshall 		key = PVFS2_XATTR_NAME_ACL_DEFAULT;
25*5db11c21SMike Marshall 		break;
26*5db11c21SMike Marshall 	default:
27*5db11c21SMike Marshall 		gossip_err("pvfs2_get_acl: bogus value of type %d\n", type);
28*5db11c21SMike Marshall 		return ERR_PTR(-EINVAL);
29*5db11c21SMike Marshall 	}
30*5db11c21SMike Marshall 	/*
31*5db11c21SMike Marshall 	 * Rather than incurring a network call just to determine the exact
32*5db11c21SMike Marshall 	 * length of the attribute, I just allocate a max length to save on
33*5db11c21SMike Marshall 	 * the network call. Conceivably, we could pass NULL to
34*5db11c21SMike Marshall 	 * pvfs2_inode_getxattr() to probe the length of the value, but
35*5db11c21SMike Marshall 	 * I don't do that for now.
36*5db11c21SMike Marshall 	 */
37*5db11c21SMike Marshall 	value = kmalloc(PVFS_MAX_XATTR_VALUELEN, GFP_KERNEL);
38*5db11c21SMike Marshall 	if (value == NULL)
39*5db11c21SMike Marshall 		return ERR_PTR(-ENOMEM);
40*5db11c21SMike Marshall 
41*5db11c21SMike Marshall 	gossip_debug(GOSSIP_ACL_DEBUG,
42*5db11c21SMike Marshall 		     "inode %pU, key %s, type %d\n",
43*5db11c21SMike Marshall 		     get_khandle_from_ino(inode),
44*5db11c21SMike Marshall 		     key,
45*5db11c21SMike Marshall 		     type);
46*5db11c21SMike Marshall 	ret = pvfs2_inode_getxattr(inode,
47*5db11c21SMike Marshall 				   "",
48*5db11c21SMike Marshall 				   key,
49*5db11c21SMike Marshall 				   value,
50*5db11c21SMike Marshall 				   PVFS_MAX_XATTR_VALUELEN);
51*5db11c21SMike Marshall 	/* if the key exists, convert it to an in-memory rep */
52*5db11c21SMike Marshall 	if (ret > 0) {
53*5db11c21SMike Marshall 		acl = posix_acl_from_xattr(&init_user_ns, value, ret);
54*5db11c21SMike Marshall 	} else if (ret == -ENODATA || ret == -ENOSYS) {
55*5db11c21SMike Marshall 		acl = NULL;
56*5db11c21SMike Marshall 	} else {
57*5db11c21SMike Marshall 		gossip_err("inode %pU retrieving acl's failed with error %d\n",
58*5db11c21SMike Marshall 			   get_khandle_from_ino(inode),
59*5db11c21SMike Marshall 			   ret);
60*5db11c21SMike Marshall 		acl = ERR_PTR(ret);
61*5db11c21SMike Marshall 	}
62*5db11c21SMike Marshall 	/* kfree(NULL) is safe, so don't worry if value ever got used */
63*5db11c21SMike Marshall 	kfree(value);
64*5db11c21SMike Marshall 	return acl;
65*5db11c21SMike Marshall }
66*5db11c21SMike Marshall 
67*5db11c21SMike Marshall int pvfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
68*5db11c21SMike Marshall {
69*5db11c21SMike Marshall 	struct pvfs2_inode_s *pvfs2_inode = PVFS2_I(inode);
70*5db11c21SMike Marshall 	int error = 0;
71*5db11c21SMike Marshall 	void *value = NULL;
72*5db11c21SMike Marshall 	size_t size = 0;
73*5db11c21SMike Marshall 	const char *name = NULL;
74*5db11c21SMike Marshall 
75*5db11c21SMike Marshall 	switch (type) {
76*5db11c21SMike Marshall 	case ACL_TYPE_ACCESS:
77*5db11c21SMike Marshall 		name = PVFS2_XATTR_NAME_ACL_ACCESS;
78*5db11c21SMike Marshall 		if (acl) {
79*5db11c21SMike Marshall 			umode_t mode = inode->i_mode;
80*5db11c21SMike Marshall 			/*
81*5db11c21SMike Marshall 			 * can we represent this with the traditional file
82*5db11c21SMike Marshall 			 * mode permission bits?
83*5db11c21SMike Marshall 			 */
84*5db11c21SMike Marshall 			error = posix_acl_equiv_mode(acl, &mode);
85*5db11c21SMike Marshall 			if (error < 0) {
86*5db11c21SMike Marshall 				gossip_err("%s: posix_acl_equiv_mode err: %d\n",
87*5db11c21SMike Marshall 					   __func__,
88*5db11c21SMike Marshall 					   error);
89*5db11c21SMike Marshall 				return error;
90*5db11c21SMike Marshall 			}
91*5db11c21SMike Marshall 
92*5db11c21SMike Marshall 			if (inode->i_mode != mode)
93*5db11c21SMike Marshall 				SetModeFlag(pvfs2_inode);
94*5db11c21SMike Marshall 			inode->i_mode = mode;
95*5db11c21SMike Marshall 			mark_inode_dirty_sync(inode);
96*5db11c21SMike Marshall 			if (error == 0)
97*5db11c21SMike Marshall 				acl = NULL;
98*5db11c21SMike Marshall 		}
99*5db11c21SMike Marshall 		break;
100*5db11c21SMike Marshall 	case ACL_TYPE_DEFAULT:
101*5db11c21SMike Marshall 		name = PVFS2_XATTR_NAME_ACL_DEFAULT;
102*5db11c21SMike Marshall 		break;
103*5db11c21SMike Marshall 	default:
104*5db11c21SMike Marshall 		gossip_err("%s: invalid type %d!\n", __func__, type);
105*5db11c21SMike Marshall 		return -EINVAL;
106*5db11c21SMike Marshall 	}
107*5db11c21SMike Marshall 
108*5db11c21SMike Marshall 	gossip_debug(GOSSIP_ACL_DEBUG,
109*5db11c21SMike Marshall 		     "%s: inode %pU, key %s type %d\n",
110*5db11c21SMike Marshall 		     __func__, get_khandle_from_ino(inode),
111*5db11c21SMike Marshall 		     name,
112*5db11c21SMike Marshall 		     type);
113*5db11c21SMike Marshall 
114*5db11c21SMike Marshall 	if (acl) {
115*5db11c21SMike Marshall 		size = posix_acl_xattr_size(acl->a_count);
116*5db11c21SMike Marshall 		value = kmalloc(size, GFP_KERNEL);
117*5db11c21SMike Marshall 		if (!value)
118*5db11c21SMike Marshall 			return -ENOMEM;
119*5db11c21SMike Marshall 
120*5db11c21SMike Marshall 		error = posix_acl_to_xattr(&init_user_ns, acl, value, size);
121*5db11c21SMike Marshall 		if (error < 0)
122*5db11c21SMike Marshall 			goto out;
123*5db11c21SMike Marshall 	}
124*5db11c21SMike Marshall 
125*5db11c21SMike Marshall 	gossip_debug(GOSSIP_ACL_DEBUG,
126*5db11c21SMike Marshall 		     "%s: name %s, value %p, size %zd, acl %p\n",
127*5db11c21SMike Marshall 		     __func__, name, value, size, acl);
128*5db11c21SMike Marshall 	/*
129*5db11c21SMike Marshall 	 * Go ahead and set the extended attribute now. NOTE: Suppose acl
130*5db11c21SMike Marshall 	 * was NULL, then value will be NULL and size will be 0 and that
131*5db11c21SMike Marshall 	 * will xlate to a removexattr. However, we don't want removexattr
132*5db11c21SMike Marshall 	 * complain if attributes does not exist.
133*5db11c21SMike Marshall 	 */
134*5db11c21SMike Marshall 	error = pvfs2_inode_setxattr(inode, "", name, value, size, 0);
135*5db11c21SMike Marshall 
136*5db11c21SMike Marshall out:
137*5db11c21SMike Marshall 	kfree(value);
138*5db11c21SMike Marshall 	if (!error)
139*5db11c21SMike Marshall 		set_cached_acl(inode, type, acl);
140*5db11c21SMike Marshall 	return error;
141*5db11c21SMike Marshall }
142*5db11c21SMike Marshall 
143*5db11c21SMike Marshall int pvfs2_init_acl(struct inode *inode, struct inode *dir)
144*5db11c21SMike Marshall {
145*5db11c21SMike Marshall 	struct pvfs2_inode_s *pvfs2_inode = PVFS2_I(inode);
146*5db11c21SMike Marshall 	struct posix_acl *default_acl, *acl;
147*5db11c21SMike Marshall 	umode_t mode = inode->i_mode;
148*5db11c21SMike Marshall 	int error = 0;
149*5db11c21SMike Marshall 
150*5db11c21SMike Marshall 	ClearModeFlag(pvfs2_inode);
151*5db11c21SMike Marshall 
152*5db11c21SMike Marshall 	error = posix_acl_create(dir, &mode, &default_acl, &acl);
153*5db11c21SMike Marshall 	if (error)
154*5db11c21SMike Marshall 		return error;
155*5db11c21SMike Marshall 
156*5db11c21SMike Marshall 	if (default_acl) {
157*5db11c21SMike Marshall 		error = pvfs2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
158*5db11c21SMike Marshall 		posix_acl_release(default_acl);
159*5db11c21SMike Marshall 	}
160*5db11c21SMike Marshall 
161*5db11c21SMike Marshall 	if (acl) {
162*5db11c21SMike Marshall 		if (!error)
163*5db11c21SMike Marshall 			error = pvfs2_set_acl(inode, acl, ACL_TYPE_ACCESS);
164*5db11c21SMike Marshall 		posix_acl_release(acl);
165*5db11c21SMike Marshall 	}
166*5db11c21SMike Marshall 
167*5db11c21SMike Marshall 	/* If mode of the inode was changed, then do a forcible ->setattr */
168*5db11c21SMike Marshall 	if (mode != inode->i_mode) {
169*5db11c21SMike Marshall 		SetModeFlag(pvfs2_inode);
170*5db11c21SMike Marshall 		inode->i_mode = mode;
171*5db11c21SMike Marshall 		pvfs2_flush_inode(inode);
172*5db11c21SMike Marshall 	}
173*5db11c21SMike Marshall 
174*5db11c21SMike Marshall 	return error;
175*5db11c21SMike Marshall }
176