Linux 2.6.33 compat, get/set xattr callbacks
[zfs.git] / module / zfs / zpl_xattr.c
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2011, Lawrence Livermore National Security, LLC.
23  *
24  * Extended attributes (xattr) on Solaris are implemented as files
25  * which exist in a hidden xattr directory.  These extended attributes
26  * can be accessed using the attropen() system call which opens
27  * the extended attribute.  It can then be manipulated just like
28  * a standard file descriptor.  This has a couple advantages such
29  * as practically no size limit on the file, and the extended
30  * attributes permissions may differ from those of the parent file.
31  * This interface is really quite clever, but it's also completely
32  * different than what is supported on Linux.
33  *
34  * Under Linux extended attributes are manipulated by the system
35  * calls getxattr(2), setxattr(2), and listxattr(2).  They consider
36  * extended attributes to be name/value pairs where the name is a
37  * NULL terminated string.  The name must also include one of the
38  * following name space prefixes:
39  *
40  *   user     - No restrictions and is available to user applications.
41  *   trusted  - Restricted to kernel and root (CAP_SYS_ADMIN) use.
42  *   system   - Used for access control lists (system.nfs4_acl, etc).
43  *   security - Used by SELinux to store a files security context.
44  *
45  * This Linux interface is implemented internally using the more
46  * flexible Solaris style extended attributes.  Every extended
47  * attribute is store as a file in a hidden directory associated
48  * with the parent file.  This ensures on disk compatibility with
49  * zfs implementations on other platforms (Solaris, FreeBSD, MacOS).
50  *
51  * One consequence of this implementation is that when an extended
52  * attribute is manipulated an inode is created.  This inode will
53  * exist in the Linux inode cache but there will be no associated
54  * entry in the dentry cache which references it.  This is safe
55  * but it may result in some confusion.
56  *
57  * Longer term I would like to see the 'security.selinux' extended
58  * attribute moved to a SA.  This should significantly improve
59  * performance on a SELinux enabled system by minimizing the
60  * number of seeks required to access a file.  However, for now
61  * this xattr is still stored in a file because I'm pretty sure
62  * adding a new SA will break on-disk compatibility.
63  */
64
65
66 #include <sys/zfs_vfsops.h>
67 #include <sys/zfs_vnops.h>
68 #include <sys/zfs_znode.h>
69 #include <sys/vfs.h>
70 #include <sys/zpl.h>
71
72 typedef struct xattr_filldir {
73         size_t size;
74         size_t offset;
75         char *buf;
76         struct inode *inode;
77 } xattr_filldir_t;
78
79 static int
80 zpl_xattr_filldir(void *arg, const char *name, int name_len,
81     loff_t offset, uint64_t objnum, unsigned int d_type)
82 {
83         xattr_filldir_t *xf = arg;
84
85         if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
86                 if (!(ITOZSB(xf->inode)->z_flags & ZSB_XATTR_USER))
87                         return (0);
88
89         if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN))
90                 if (!capable(CAP_SYS_ADMIN))
91                         return (0);
92
93         /* When xf->buf is NULL only calculate the required size. */
94         if (xf->buf) {
95                 if (xf->offset + name_len + 1 > xf->size)
96                         return (-ERANGE);
97
98                 memcpy(xf->buf + xf->offset, name, name_len);
99                 xf->buf[xf->offset + name_len] = '\0';
100         }
101
102         xf->offset += (name_len + 1);
103
104         return (0);
105 }
106
107 ssize_t
108 zpl_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size)
109 {
110         struct inode *ip = dentry->d_inode;
111         struct inode *dxip = NULL;
112         loff_t pos = 3;  /* skip '.', '..', and '.zfs' entries. */
113         cred_t *cr;
114         int error;
115         xattr_filldir_t xf = { buffer_size, 0, buffer, ip };
116
117         cr = (cred_t *)get_current_cred();
118
119         /* Lookup the xattr directory */
120         error = -zfs_lookup(ip, NULL, &dxip, LOOKUP_XATTR, cr, NULL, NULL);
121         if (error) {
122                 if (error == -ENOENT)
123                         error = 0;
124
125                 goto out;
126         }
127
128         /* Fill provided buffer via zpl_zattr_filldir helper */
129         error = -zfs_readdir(dxip, (void *)&xf, zpl_xattr_filldir, &pos, cr);
130         if (error)
131                 goto out;
132
133         error = xf.offset;
134 out:
135         if (dxip)
136                 iput(dxip);
137
138         put_cred(cr);
139
140         return (error);
141 }
142
143 static int
144 zpl_xattr_get(struct inode *ip, const char *name, void *buf, size_t size)
145 {
146         struct inode *dxip = NULL;
147         struct inode *xip = NULL;
148         cred_t *cr;
149         int error;
150
151         cr = (cred_t *)get_current_cred();
152
153         /* Lookup the xattr directory */
154         error = -zfs_lookup(ip, NULL, &dxip, LOOKUP_XATTR, cr, NULL, NULL);
155         if (error)
156                 goto out;
157
158         /* Lookup a specific xattr name in the directory */
159         error = -zfs_lookup(dxip, (char *)name, &xip, 0, cr, NULL, NULL);
160         if (error)
161                 goto out;
162
163         if (!size) {
164                 error = i_size_read(xip);
165                 goto out;
166         }
167
168         error = zpl_read_common(xip, buf, size, 0, UIO_SYSSPACE, 0, cr);
169 out:
170         if (xip)
171                 iput(xip);
172
173         if (dxip)
174                 iput(dxip);
175
176         put_cred(cr);
177
178         if (error == -ENOENT)
179                 error = -ENODATA;
180
181         return (error);
182 }
183
184 static int
185 zpl_xattr_set(struct inode *ip, const char *name, const void *value,
186     size_t size, int flags)
187 {
188         struct inode *dxip = NULL;
189         struct inode *xip = NULL;
190         vattr_t *vap = NULL;
191         cred_t *cr;
192         ssize_t wrote;
193         int error;
194
195         cr = (cred_t *)get_current_cred();
196
197         /* Lookup the xattr directory and create it if required. */
198         error = -zfs_lookup(ip, NULL, &dxip, LOOKUP_XATTR | CREATE_XATTR_DIR,
199             cr, NULL, NULL);
200         if (error)
201                 goto out;
202
203         /*
204          * Lookup a specific xattr name in the directory, two failure modes:
205          *   XATTR_CREATE: fail if xattr already exists
206          *   XATTR_REMOVE: fail if xattr does not exist
207          */
208         error = -zfs_lookup(dxip, (char *)name, &xip, 0, cr, NULL, NULL);
209         if (error) {
210                 if (error != -ENOENT)
211                         goto out;
212
213                 if ((error == -ENOENT) && (flags & XATTR_REPLACE))
214                         goto out;
215         } else {
216                 error = -EEXIST;
217                 if (flags & XATTR_CREATE)
218                         goto out;
219         }
220         error = 0;
221
222         /* Remove a specific name xattr when value is set to NULL. */
223         if (value == NULL) {
224                 if (xip)
225                         error = -zfs_remove(dxip, (char *)name, cr);
226
227                 goto out;
228         }
229
230         /* Lookup failed create a new xattr. */
231         if (xip == NULL) {
232                 vap = kmem_zalloc(sizeof(vattr_t), KM_SLEEP);
233                 vap->va_mode = S_IFREG | 0644;
234                 vap->va_mask = ATTR_MODE;
235                 vap->va_uid = current_fsuid();
236                 vap->va_gid = current_fsgid();
237
238                 error = -zfs_create(dxip, (char *)name, vap, 0, 0644, &xip,
239                     cr, 0, NULL);
240                 if (error)
241                         goto out;
242         }
243
244         ASSERT(xip != NULL);
245         wrote = zpl_write_common(xip, value, size, 0, UIO_SYSSPACE, 0, cr);
246         if (wrote < 0)
247                 error = wrote;
248
249 out:
250         if (vap)
251                 kmem_free(vap, sizeof(vattr_t));
252
253         if (xip)
254                 iput(xip);
255
256         if (dxip)
257                 iput(dxip);
258
259         put_cred(cr);
260         if (error == -ENOENT)
261                 error = -ENODATA;
262
263         ASSERT3S(error, <=, 0);
264
265         return (error);
266 }
267
268 static int
269 __zpl_xattr_user_get(struct inode *ip, const char *name,
270     void *buffer, size_t size)
271 {
272         char *xattr_name;
273         int error;
274
275         if (strcmp(name, "") == 0)
276                 return -EINVAL;
277
278         if (!(ITOZSB(ip)->z_flags & ZSB_XATTR_USER))
279                 return -EOPNOTSUPP;
280
281         xattr_name = kmem_asprintf("%s%s", XATTR_USER_PREFIX, name);
282         error = zpl_xattr_get(ip, xattr_name, buffer, size);
283         strfree(xattr_name);
284
285         return (error);
286 }
287 ZPL_XATTR_GET_WRAPPER(zpl_xattr_user_get);
288
289 static int
290 __zpl_xattr_user_set(struct inode *ip, const char *name,
291     const void *value, size_t size, int flags)
292 {
293         char *xattr_name;
294         int error;
295
296         if (strcmp(name, "") == 0)
297                 return -EINVAL;
298
299         if (!(ITOZSB(ip)->z_flags & ZSB_XATTR_USER))
300                 return -EOPNOTSUPP;
301
302         xattr_name = kmem_asprintf("%s%s", XATTR_USER_PREFIX, name);
303         error = zpl_xattr_set(ip, xattr_name, value, size, flags);
304         strfree(xattr_name);
305
306         return (error);
307 }
308 ZPL_XATTR_SET_WRAPPER(zpl_xattr_user_set);
309
310 xattr_handler_t zpl_xattr_user_handler = {
311         .prefix = XATTR_USER_PREFIX,
312         .get    = zpl_xattr_user_get,
313         .set    = zpl_xattr_user_set,
314 };
315
316 static int
317 __zpl_xattr_trusted_get(struct inode *ip, const char *name,
318     void *buffer, size_t size)
319 {
320         char *xattr_name;
321         int error;
322
323         if (!capable(CAP_SYS_ADMIN))
324                 return -EACCES;
325
326         if (strcmp(name, "") == 0)
327                 return -EINVAL;
328
329         xattr_name = kmem_asprintf("%s%s", XATTR_TRUSTED_PREFIX, name);
330         error = zpl_xattr_get(ip, xattr_name, buffer, size);
331         strfree(xattr_name);
332
333         return (error);
334 }
335 ZPL_XATTR_GET_WRAPPER(zpl_xattr_trusted_get);
336
337 static int
338 __zpl_xattr_trusted_set(struct inode *ip, const char *name,
339     const void *value, size_t size, int flags)
340 {
341         char *xattr_name;
342         int error;
343
344         if (!capable(CAP_SYS_ADMIN))
345                 return -EACCES;
346
347         if (strcmp(name, "") == 0)
348                 return -EINVAL;
349
350         xattr_name = kmem_asprintf("%s%s", XATTR_TRUSTED_PREFIX, name);
351         error = zpl_xattr_set(ip, xattr_name, value, size, flags);
352         strfree(xattr_name);
353
354         return (error);
355 }
356 ZPL_XATTR_SET_WRAPPER(zpl_xattr_trusted_set);
357
358 xattr_handler_t zpl_xattr_trusted_handler = {
359         .prefix = XATTR_TRUSTED_PREFIX,
360         .get    = zpl_xattr_trusted_get,
361         .set    = zpl_xattr_trusted_set,
362 };
363
364 static int
365 __zpl_xattr_security_get(struct inode *ip, const char *name,
366     void *buffer, size_t size)
367 {
368         char *xattr_name;
369         int error;
370
371         if (strcmp(name, "") == 0)
372                 return -EINVAL;
373
374         xattr_name = kmem_asprintf("%s%s", XATTR_SECURITY_PREFIX, name);
375         error = zpl_xattr_get(ip, xattr_name, buffer, size);
376         strfree(xattr_name);
377
378         return (error);
379 }
380 ZPL_XATTR_GET_WRAPPER(zpl_xattr_security_get);
381
382 static int
383 __zpl_xattr_security_set(struct inode *ip, const char *name,
384     const void *value, size_t size, int flags)
385 {
386         char *xattr_name;
387         int error;
388
389         if (strcmp(name, "") == 0)
390                 return -EINVAL;
391
392         xattr_name = kmem_asprintf("%s%s", XATTR_SECURITY_PREFIX, name);
393         error = zpl_xattr_set(ip, xattr_name, value, size, flags);
394         strfree(xattr_name);
395
396         return (error);
397 }
398 ZPL_XATTR_SET_WRAPPER(zpl_xattr_security_set);
399
400 int
401 zpl_xattr_security_init(struct inode *ip, struct inode *dip)
402 {
403         int error;
404         size_t len;
405         void *value;
406         char *name;
407
408         error = security_inode_init_security(ip, dip, &name, &value, &len);
409         if (error) {
410                 if (error == -EOPNOTSUPP)
411                         return 0;
412
413                 return (error);
414         }
415
416         error = __zpl_xattr_security_set(ip, name, value, len, 0);
417
418         kfree(name);
419         kfree(value);
420
421         return (error);
422 }
423
424 xattr_handler_t zpl_xattr_security_handler = {
425         .prefix = XATTR_SECURITY_PREFIX,
426         .get    = zpl_xattr_security_get,
427         .set    = zpl_xattr_security_set,
428 };
429
430 xattr_handler_t *zpl_xattr_handlers[] = {
431         &zpl_xattr_security_handler,
432         &zpl_xattr_trusted_handler,
433         &zpl_xattr_user_handler,
434 #ifdef HAVE_POSIX_ACLS
435         &zpl_xattr_acl_access_handler,
436         &zpl_xattr_acl_default_handler,
437 #endif /* HAVE_POSIX_ACLS */
438 };