Blame view

fs/9p/acl.c 8.72 KB
85ff872d3   Aneesh Kumar K.V   fs/9p: Implement ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  /*
   * Copyright IBM Corporation, 2010
   * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of version 2.1 of the GNU Lesser General Public License
   * as published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it would be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   *
   */
  
  #include <linux/module.h>
  #include <linux/fs.h>
  #include <net/9p/9p.h>
  #include <net/9p/client.h>
  #include <linux/slab.h>
22d8dcdf8   Aneesh Kumar K.V   fs/9p: Implement ...
20
  #include <linux/sched.h>
85ff872d3   Aneesh Kumar K.V   fs/9p: Implement ...
21
22
23
  #include <linux/posix_acl_xattr.h>
  #include "xattr.h"
  #include "acl.h"
76381a42e   Aneesh Kumar K.V   fs/9p: Add access...
24
  #include "v9fs.h"
5ffc0cb30   Aneesh Kumar K.V   fs/9p: Add inode ...
25
  #include "v9fs_vfs.h"
85ff872d3   Aneesh Kumar K.V   fs/9p: Implement ...
26
27
28
29
30
  
  static struct posix_acl *__v9fs_get_acl(struct p9_fid *fid, char *name)
  {
  	ssize_t size;
  	void *value = NULL;
009ca3897   Joe Perches   fs/9p: Remove unn...
31
  	struct posix_acl *acl = NULL;
85ff872d3   Aneesh Kumar K.V   fs/9p: Implement ...
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
  
  	size = v9fs_fid_xattr_get(fid, name, NULL, 0);
  	if (size > 0) {
  		value = kzalloc(size, GFP_NOFS);
  		if (!value)
  			return ERR_PTR(-ENOMEM);
  		size = v9fs_fid_xattr_get(fid, name, value, size);
  		if (size > 0) {
  			acl = posix_acl_from_xattr(value, size);
  			if (IS_ERR(acl))
  				goto err_out;
  		}
  	} else if (size == -ENODATA || size == 0 ||
  		   size == -ENOSYS || size == -EOPNOTSUPP) {
  		acl = NULL;
  	} else
  		acl = ERR_PTR(-EIO);
  
  err_out:
  	kfree(value);
  	return acl;
  }
  
  int v9fs_get_acl(struct inode *inode, struct p9_fid *fid)
  {
  	int retval = 0;
  	struct posix_acl *pacl, *dacl;
76381a42e   Aneesh Kumar K.V   fs/9p: Add access...
59
  	struct v9fs_session_info *v9ses;
85ff872d3   Aneesh Kumar K.V   fs/9p: Implement ...
60

76381a42e   Aneesh Kumar K.V   fs/9p: Add access...
61
  	v9ses = v9fs_inode2v9ses(inode);
e782ef710   Venkateswararao Jujjuri (JV)   [fs/9P] Add posix...
62
63
  	if (((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) ||
  			((v9ses->flags & V9FS_ACL_MASK) != V9FS_POSIX_ACL)) {
76381a42e   Aneesh Kumar K.V   fs/9p: Add access...
64
65
66
67
  		set_cached_acl(inode, ACL_TYPE_DEFAULT, NULL);
  		set_cached_acl(inode, ACL_TYPE_ACCESS, NULL);
  		return 0;
  	}
85ff872d3   Aneesh Kumar K.V   fs/9p: Implement ...
68
69
70
71
72
73
74
  	/* get the default/access acl values and cache them */
  	dacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_DEFAULT);
  	pacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_ACCESS);
  
  	if (!IS_ERR(dacl) && !IS_ERR(pacl)) {
  		set_cached_acl(inode, ACL_TYPE_DEFAULT, dacl);
  		set_cached_acl(inode, ACL_TYPE_ACCESS, pacl);
85ff872d3   Aneesh Kumar K.V   fs/9p: Implement ...
75
76
  	} else
  		retval = -EIO;
c61fa0d6d   Venkateswararao Jujjuri (JV)   [fs/9p] Plug pote...
77
78
79
80
81
  	if (!IS_ERR(dacl))
  		posix_acl_release(dacl);
  
  	if (!IS_ERR(pacl))
  		posix_acl_release(pacl);
85ff872d3   Aneesh Kumar K.V   fs/9p: Implement ...
82
83
84
85
86
87
88
89
90
91
92
93
94
95
  	return retval;
  }
  
  static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type)
  {
  	struct posix_acl *acl;
  	/*
  	 * 9p Always cache the acl value when
  	 * instantiating the inode (v9fs_inode_from_fid)
  	 */
  	acl = get_cached_acl(inode, type);
  	BUG_ON(acl == ACL_NOT_CACHED);
  	return acl;
  }
4e34e719e   Christoph Hellwig   fs: take the ACL ...
96
  struct posix_acl *v9fs_iop_get_acl(struct inode *inode, int type)
85ff872d3   Aneesh Kumar K.V   fs/9p: Implement ...
97
  {
76381a42e   Aneesh Kumar K.V   fs/9p: Add access...
98
99
100
  	struct v9fs_session_info *v9ses;
  
  	v9ses = v9fs_inode2v9ses(inode);
e782ef710   Venkateswararao Jujjuri (JV)   [fs/9P] Add posix...
101
102
  	if (((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) ||
  			((v9ses->flags & V9FS_ACL_MASK) != V9FS_POSIX_ACL)) {
76381a42e   Aneesh Kumar K.V   fs/9p: Add access...
103
  		/*
e782ef710   Venkateswararao Jujjuri (JV)   [fs/9P] Add posix...
104
  		 * On access = client  and acl = on mode get the acl
76381a42e   Aneesh Kumar K.V   fs/9p: Add access...
105
106
  		 * values from the server
  		 */
4e34e719e   Christoph Hellwig   fs: take the ACL ...
107
  		return NULL;
76381a42e   Aneesh Kumar K.V   fs/9p: Add access...
108
  	}
4e34e719e   Christoph Hellwig   fs: take the ACL ...
109
  	return v9fs_get_cached_acl(inode, type);
85ff872d3   Aneesh Kumar K.V   fs/9p: Implement ...
110
  }
7a4566b0b   Aneesh Kumar K.V   fs/9p: Add xattr ...
111

6e8dc5555   Aneesh Kumar K.V   fs/9p: Update ACL...
112
113
114
115
116
117
118
119
120
  static int v9fs_set_acl(struct dentry *dentry, int type, struct posix_acl *acl)
  {
  	int retval;
  	char *name;
  	size_t size;
  	void *buffer;
  	struct inode *inode = dentry->d_inode;
  
  	set_cached_acl(inode, type, acl);
d344b0fb7   Venkateswararao Jujjuri (JV)   [fs/9p] Initialze...
121
122
123
  
  	if (!acl)
  		return 0;
6e8dc5555   Aneesh Kumar K.V   fs/9p: Update ACL...
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
  	/* Set a setxattr request to server */
  	size = posix_acl_xattr_size(acl->a_count);
  	buffer = kmalloc(size, GFP_KERNEL);
  	if (!buffer)
  		return -ENOMEM;
  	retval = posix_acl_to_xattr(acl, buffer, size);
  	if (retval < 0)
  		goto err_free_out;
  	switch (type) {
  	case ACL_TYPE_ACCESS:
  		name = POSIX_ACL_XATTR_ACCESS;
  		break;
  	case ACL_TYPE_DEFAULT:
  		name = POSIX_ACL_XATTR_DEFAULT;
  		break;
  	default:
  		BUG();
  	}
  	retval = v9fs_xattr_set(dentry, name, buffer, size, 0);
  err_free_out:
  	kfree(buffer);
  	return retval;
  }
  
  int v9fs_acl_chmod(struct dentry *dentry)
  {
  	int retval = 0;
bc26ab5f6   Al Viro   kill boilerplate ...
151
  	struct posix_acl *acl;
6e8dc5555   Aneesh Kumar K.V   fs/9p: Update ACL...
152
153
154
155
156
157
  	struct inode *inode = dentry->d_inode;
  
  	if (S_ISLNK(inode->i_mode))
  		return -EOPNOTSUPP;
  	acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS);
  	if (acl) {
bc26ab5f6   Al Viro   kill boilerplate ...
158
159
160
161
  		retval = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
  		if (retval)
  			return retval;
  		retval = v9fs_set_acl(dentry, ACL_TYPE_ACCESS, acl);
6e8dc5555   Aneesh Kumar K.V   fs/9p: Update ACL...
162
  		posix_acl_release(acl);
6e8dc5555   Aneesh Kumar K.V   fs/9p: Update ACL...
163
164
165
  	}
  	return retval;
  }
ad77dbce5   Aneesh Kumar K.V   fs/9p: Implement ...
166
  int v9fs_set_create_acl(struct dentry *dentry,
1ec95bf34   Al Viro   9p: close ACL leaks
167
  			struct posix_acl **dpacl, struct posix_acl **pacl)
ad77dbce5   Aneesh Kumar K.V   fs/9p: Implement ...
168
  {
1ec95bf34   Al Viro   9p: close ACL leaks
169
170
171
172
173
174
175
  	if (dentry) {
  		v9fs_set_acl(dentry, ACL_TYPE_DEFAULT, *dpacl);
  		v9fs_set_acl(dentry, ACL_TYPE_ACCESS, *pacl);
  	}
  	posix_acl_release(*dpacl);
  	posix_acl_release(*pacl);
  	*dpacl = *pacl = NULL;
ad77dbce5   Aneesh Kumar K.V   fs/9p: Implement ...
176
177
  	return 0;
  }
d3fb61207   Al Viro   switch posix_acl_...
178
  int v9fs_acl_mode(struct inode *dir, umode_t *modep,
ad77dbce5   Aneesh Kumar K.V   fs/9p: Implement ...
179
180
181
  		  struct posix_acl **dpacl, struct posix_acl **pacl)
  {
  	int retval = 0;
d3fb61207   Al Viro   switch posix_acl_...
182
  	umode_t mode = *modep;
ad77dbce5   Aneesh Kumar K.V   fs/9p: Implement ...
183
184
185
186
187
188
189
190
191
192
  	struct posix_acl *acl = NULL;
  
  	if (!S_ISLNK(mode)) {
  		acl = v9fs_get_cached_acl(dir, ACL_TYPE_DEFAULT);
  		if (IS_ERR(acl))
  			return PTR_ERR(acl);
  		if (!acl)
  			mode &= ~current_umask();
  	}
  	if (acl) {
ad77dbce5   Aneesh Kumar K.V   fs/9p: Implement ...
193
  		if (S_ISDIR(mode))
1ec95bf34   Al Viro   9p: close ACL leaks
194
  			*dpacl = posix_acl_dup(acl);
826cae2f2   Al Viro   kill boilerplates...
195
196
197
  		retval = posix_acl_create(&acl, GFP_NOFS, &mode);
  		if (retval < 0)
  			return retval;
ad77dbce5   Aneesh Kumar K.V   fs/9p: Implement ...
198
  		if (retval > 0)
826cae2f2   Al Viro   kill boilerplates...
199
  			*pacl = acl;
1ec95bf34   Al Viro   9p: close ACL leaks
200
  		else
826cae2f2   Al Viro   kill boilerplates...
201
  			posix_acl_release(acl);
ad77dbce5   Aneesh Kumar K.V   fs/9p: Implement ...
202
203
204
  	}
  	*modep  = mode;
  	return 0;
ad77dbce5   Aneesh Kumar K.V   fs/9p: Implement ...
205
  }
76381a42e   Aneesh Kumar K.V   fs/9p: Add access...
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
  static int v9fs_remote_get_acl(struct dentry *dentry, const char *name,
  			       void *buffer, size_t size, int type)
  {
  	char *full_name;
  
  	switch (type) {
  	case ACL_TYPE_ACCESS:
  		full_name =  POSIX_ACL_XATTR_ACCESS;
  		break;
  	case ACL_TYPE_DEFAULT:
  		full_name = POSIX_ACL_XATTR_DEFAULT;
  		break;
  	default:
  		BUG();
  	}
  	return v9fs_xattr_get(dentry, full_name, buffer, size);
  }
7a4566b0b   Aneesh Kumar K.V   fs/9p: Add xattr ...
223
224
225
  static int v9fs_xattr_get_acl(struct dentry *dentry, const char *name,
  			      void *buffer, size_t size, int type)
  {
76381a42e   Aneesh Kumar K.V   fs/9p: Add access...
226
  	struct v9fs_session_info *v9ses;
7a4566b0b   Aneesh Kumar K.V   fs/9p: Add xattr ...
227
228
229
230
231
  	struct posix_acl *acl;
  	int error;
  
  	if (strcmp(name, "") != 0)
  		return -EINVAL;
42869c8ad   Aneesh Kumar K.V   fs/9p: Add v9fs_d...
232
  	v9ses = v9fs_dentry2v9ses(dentry);
76381a42e   Aneesh Kumar K.V   fs/9p: Add access...
233
234
235
236
237
  	/*
  	 * We allow set/get/list of acl when access=client is not specified
  	 */
  	if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
  		return v9fs_remote_get_acl(dentry, name, buffer, size, type);
7a4566b0b   Aneesh Kumar K.V   fs/9p: Add xattr ...
238
239
240
241
242
243
244
245
246
247
  	acl = v9fs_get_cached_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;
  }
76381a42e   Aneesh Kumar K.V   fs/9p: Add access...
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
  static int v9fs_remote_set_acl(struct dentry *dentry, const char *name,
  			      const void *value, size_t size,
  			      int flags, int type)
  {
  	char *full_name;
  
  	switch (type) {
  	case ACL_TYPE_ACCESS:
  		full_name =  POSIX_ACL_XATTR_ACCESS;
  		break;
  	case ACL_TYPE_DEFAULT:
  		full_name = POSIX_ACL_XATTR_DEFAULT;
  		break;
  	default:
  		BUG();
  	}
  	return v9fs_xattr_set(dentry, full_name, value, size, flags);
  }
7a4566b0b   Aneesh Kumar K.V   fs/9p: Add xattr ...
266
267
268
269
  static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
  			      const void *value, size_t size,
  			      int flags, int type)
  {
22d8dcdf8   Aneesh Kumar K.V   fs/9p: Implement ...
270
271
  	int retval;
  	struct posix_acl *acl;
76381a42e   Aneesh Kumar K.V   fs/9p: Add access...
272
  	struct v9fs_session_info *v9ses;
22d8dcdf8   Aneesh Kumar K.V   fs/9p: Implement ...
273
274
275
276
  	struct inode *inode = dentry->d_inode;
  
  	if (strcmp(name, "") != 0)
  		return -EINVAL;
76381a42e   Aneesh Kumar K.V   fs/9p: Add access...
277

42869c8ad   Aneesh Kumar K.V   fs/9p: Add v9fs_d...
278
  	v9ses = v9fs_dentry2v9ses(dentry);
76381a42e   Aneesh Kumar K.V   fs/9p: Add access...
279
280
281
282
283
284
285
  	/*
  	 * set the attribute on the remote. Without even looking at the
  	 * xattr value. We leave it to the server to validate
  	 */
  	if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
  		return v9fs_remote_set_acl(dentry, name,
  					   value, size, flags, type);
22d8dcdf8   Aneesh Kumar K.V   fs/9p: Implement ...
286
287
  	if (S_ISLNK(inode->i_mode))
  		return -EOPNOTSUPP;
2e1496707   Serge E. Hallyn   userns: rename is...
288
  	if (!inode_owner_or_capable(inode))
22d8dcdf8   Aneesh Kumar K.V   fs/9p: Implement ...
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
  		return -EPERM;
  	if (value) {
  		/* update the cached acl value */
  		acl = posix_acl_from_xattr(value, size);
  		if (IS_ERR(acl))
  			return PTR_ERR(acl);
  		else if (acl) {
  			retval = posix_acl_valid(acl);
  			if (retval)
  				goto err_out;
  		}
  	} else
  		acl = NULL;
  
  	switch (type) {
  	case ACL_TYPE_ACCESS:
  		name = POSIX_ACL_XATTR_ACCESS;
  		if (acl) {
d6952123b   Al Viro   switch posix_acl_...
307
  			umode_t mode = inode->i_mode;
22d8dcdf8   Aneesh Kumar K.V   fs/9p: Implement ...
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
  			retval = posix_acl_equiv_mode(acl, &mode);
  			if (retval < 0)
  				goto err_out;
  			else {
  				struct iattr iattr;
  				if (retval == 0) {
  					/*
  					 * ACL can be represented
  					 * by the mode bits. So don't
  					 * update ACL.
  					 */
  					acl = NULL;
  					value = NULL;
  					size = 0;
  				}
  				/* Updte the mode bits */
  				iattr.ia_mode = ((mode & S_IALLUGO) |
  						 (inode->i_mode & ~S_IALLUGO));
  				iattr.ia_valid = ATTR_MODE;
  				/* FIXME should we update ctime ?
  				 * What is the following setxattr update the
  				 * mode ?
  				 */
  				v9fs_vfs_setattr_dotl(dentry, &iattr);
  			}
  		}
  		break;
  	case ACL_TYPE_DEFAULT:
  		name = POSIX_ACL_XATTR_DEFAULT;
  		if (!S_ISDIR(inode->i_mode)) {
6f81c1157   Aneesh Kumar K.V   fs/9p: Fix the re...
338
  			retval = acl ? -EINVAL : 0;
22d8dcdf8   Aneesh Kumar K.V   fs/9p: Implement ...
339
340
341
342
343
344
345
346
347
348
349
350
  			goto err_out;
  		}
  		break;
  	default:
  		BUG();
  	}
  	retval = v9fs_xattr_set(dentry, name, value, size, flags);
  	if (!retval)
  		set_cached_acl(inode, type, acl);
  err_out:
  	posix_acl_release(acl);
  	return retval;
7a4566b0b   Aneesh Kumar K.V   fs/9p: Add xattr ...
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
  }
  
  const struct xattr_handler v9fs_xattr_acl_access_handler = {
  	.prefix	= POSIX_ACL_XATTR_ACCESS,
  	.flags	= ACL_TYPE_ACCESS,
  	.get	= v9fs_xattr_get_acl,
  	.set	= v9fs_xattr_set_acl,
  };
  
  const struct xattr_handler v9fs_xattr_acl_default_handler = {
  	.prefix	= POSIX_ACL_XATTR_DEFAULT,
  	.flags	= ACL_TYPE_DEFAULT,
  	.get	= v9fs_xattr_get_acl,
  	.set	= v9fs_xattr_set_acl,
  };