vfs_xattr.c revision 1.25 1 /* $NetBSD: vfs_xattr.c,v 1.25 2011/06/28 07:50:03 manu Exp $ */
2
3 /*-
4 * Copyright (c) 2005, 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * Copyright (c) 1989, 1993
34 * The Regents of the University of California. All rights reserved.
35 * (c) UNIX System Laboratories, Inc.
36 * All or some portions of this file are derived from material licensed
37 * to the University of California by American Telephone and Telegraph
38 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
39 * the permission of UNIX System Laboratories, Inc.
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 * 3. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 */
65
66 /*
67 * VFS extended attribute support.
68 */
69
70 #include <sys/cdefs.h>
71 __KERNEL_RCSID(0, "$NetBSD: vfs_xattr.c,v 1.25 2011/06/28 07:50:03 manu Exp $");
72
73 #include <sys/param.h>
74 #include <sys/systm.h>
75 #include <sys/namei.h>
76 #include <sys/filedesc.h>
77 #include <sys/kernel.h>
78 #include <sys/file.h>
79 #include <sys/vnode.h>
80 #include <sys/mount.h>
81 #include <sys/proc.h>
82 #include <sys/uio.h>
83 #include <sys/extattr.h>
84 #include <sys/xattr.h>
85 #include <sys/sysctl.h>
86 #include <sys/syscallargs.h>
87 #include <sys/kauth.h>
88
89 /*
90 * Credential check based on process requesting service, and per-attribute
91 * permissions.
92 *
93 * NOTE: Vnode must be locked.
94 */
95 int
96 extattr_check_cred(struct vnode *vp, int attrnamespace,
97 kauth_cred_t cred, struct lwp *l, int access)
98 {
99
100 if (cred == NOCRED)
101 return (0);
102
103 switch (attrnamespace) {
104 case EXTATTR_NAMESPACE_SYSTEM:
105 /*
106 * Do we really want to allow this, or just require that
107 * these requests come from kernel code (NOCRED case above)?
108 */
109 return (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
110 NULL));
111
112 case EXTATTR_NAMESPACE_USER:
113 return (VOP_ACCESS(vp, access, cred));
114
115 default:
116 return (EPERM);
117 }
118 }
119
120 /*
121 * Default vfs_extattrctl routine for file systems that do not support
122 * it.
123 */
124 /*ARGSUSED*/
125 int
126 vfs_stdextattrctl(struct mount *mp, int cmt, struct vnode *vp,
127 int attrnamespace, const char *attrname)
128 {
129
130 if (vp != NULL)
131 VOP_UNLOCK(vp);
132 return (EOPNOTSUPP);
133 }
134
135 /*
136 * Push extended attribute configuration information into the file
137 * system.
138 *
139 * NOTE: Not all file systems that support extended attributes will
140 * require the use of this system call.
141 */
142 int
143 sys_extattrctl(struct lwp *l, const struct sys_extattrctl_args *uap, register_t *retval)
144 {
145 /* {
146 syscallarg(const char *) path;
147 syscallarg(int) cmd;
148 syscallarg(const char *) filename;
149 syscallarg(int) attrnamespace;
150 syscallarg(const char *) attrname;
151 } */
152 struct vnode *path_vp, *file_vp;
153 struct pathbuf *file_pb;
154 struct nameidata file_nd;
155 char attrname[EXTATTR_MAXNAMELEN];
156 int error;
157
158 if (SCARG(uap, attrname) != NULL) {
159 error = copyinstr(SCARG(uap, attrname), attrname,
160 sizeof(attrname), NULL);
161 if (error)
162 return (error);
163 }
164
165 error = namei_simple_user(SCARG(uap, path),
166 NSM_FOLLOW_NOEMULROOT, &path_vp);
167 if (error) {
168 return (error);
169 }
170
171 file_vp = NULL;
172 if (SCARG(uap, filename) != NULL) {
173 error = pathbuf_copyin(SCARG(uap, filename), &file_pb);
174 if (error) {
175 vrele(path_vp);
176 return (error);
177 }
178 NDINIT(&file_nd, LOOKUP, FOLLOW | LOCKLEAF, file_pb);
179 error = namei(&file_nd);
180 if (error) {
181 pathbuf_destroy(file_pb);
182 vrele(path_vp);
183 return (error);
184 }
185 file_vp = file_nd.ni_vp;
186 pathbuf_destroy(file_pb);
187 }
188
189 error = VFS_EXTATTRCTL(path_vp->v_mount, SCARG(uap, cmd), file_vp,
190 SCARG(uap, attrnamespace),
191 SCARG(uap, attrname) != NULL ? attrname : NULL);
192
193 if (file_vp != NULL)
194 vrele(file_vp);
195 vrele(path_vp);
196
197 return (error);
198 }
199
200 /*****************************************************************************
201 * Internal routines to manipulate file system extended attributes:
202 * - set
203 * - get
204 * - delete
205 * - list
206 *****************************************************************************/
207
208 /*
209 * extattr_set_vp:
210 *
211 * Set a named extended attribute on a file or directory.
212 */
213 static int
214 extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
215 const void *data, size_t nbytes, struct lwp *l, register_t *retval,
216 int flag)
217 {
218 struct uio auio;
219 struct iovec aiov;
220 ssize_t cnt;
221 int error;
222
223 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
224
225 if (flag) {
226 size_t attrlen;
227
228 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, NULL,
229 &attrlen, l->l_cred);
230
231 switch (error) {
232 case ENOATTR:
233 if (flag & XATTR_REPLACE)
234 goto done;
235 break;
236 case 0:
237 if (flag & XATTR_CREATE) {
238 error = EEXIST;
239 goto done;
240 }
241 break;
242 default:
243 goto done;
244 break;
245 }
246 }
247
248 aiov.iov_base = __UNCONST(data); /* XXXUNCONST kills const */
249 aiov.iov_len = nbytes;
250 auio.uio_iov = &aiov;
251 auio.uio_iovcnt = 1;
252 auio.uio_offset = 0;
253 if (nbytes > INT_MAX) {
254 error = EINVAL;
255 goto done;
256 }
257 auio.uio_resid = nbytes;
258 auio.uio_rw = UIO_WRITE;
259 KASSERT(l == curlwp);
260 auio.uio_vmspace = l->l_proc->p_vmspace;
261 cnt = nbytes;
262
263 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio, l->l_cred);
264 cnt -= auio.uio_resid;
265 retval[0] = cnt;
266
267 done:
268 VOP_UNLOCK(vp);
269 return (error);
270 }
271
272 /*
273 * extattr_get_vp:
274 *
275 * Get a named extended attribute on a file or directory.
276 */
277 static int
278 extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
279 void *data, size_t nbytes, struct lwp *l, register_t *retval)
280 {
281 struct uio auio, *auiop;
282 struct iovec aiov;
283 ssize_t cnt;
284 size_t size, *sizep;
285 int error;
286
287 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
288
289 /*
290 * Slightly unusual semantics: if the user provides a NULL data
291 * pointer, they don't want to receive the data, just the maximum
292 * read length.
293 */
294 auiop = NULL;
295 sizep = NULL;
296 cnt = 0;
297 if (data != NULL) {
298 aiov.iov_base = data;
299 aiov.iov_len = nbytes;
300 auio.uio_iov = &aiov;
301 auio.uio_offset = 0;
302 if (nbytes > INT_MAX) {
303 error = EINVAL;
304 goto done;
305 }
306 auio.uio_resid = nbytes;
307 auio.uio_rw = UIO_READ;
308 KASSERT(l == curlwp);
309 auio.uio_vmspace = l->l_proc->p_vmspace;
310 auiop = &auio;
311 cnt = nbytes;
312 } else
313 sizep = &size;
314
315 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep,
316 l->l_cred);
317
318 if (auiop != NULL) {
319 cnt -= auio.uio_resid;
320 retval[0] = cnt;
321 } else
322 retval[0] = size;
323
324 done:
325 VOP_UNLOCK(vp);
326 return (error);
327 }
328
329 /*
330 * extattr_delete_vp:
331 *
332 * Delete a named extended attribute on a file or directory.
333 */
334 static int
335 extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
336 struct lwp *l)
337 {
338 int error;
339
340 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
341
342 error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, l->l_cred);
343 if (error == EOPNOTSUPP)
344 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
345 l->l_cred);
346
347 VOP_UNLOCK(vp);
348 return (error);
349 }
350
351 /*
352 * extattr_list_vp:
353 *
354 * Retrieve a list of extended attributes on a file or directory.
355 */
356 static int
357 extattr_list_vp(struct vnode *vp, int attrnamespace, void *data, size_t nbytes,
358 struct lwp *l, register_t *retval)
359 {
360 struct uio auio, *auiop;
361 size_t size, *sizep;
362 struct iovec aiov;
363 ssize_t cnt;
364 int error;
365
366 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
367
368 auiop = NULL;
369 sizep = NULL;
370 cnt = 0;
371 if (data != NULL) {
372 aiov.iov_base = data;
373 aiov.iov_len = nbytes;
374 auio.uio_iov = &aiov;
375 auio.uio_offset = 0;
376 if (nbytes > INT_MAX) {
377 error = EINVAL;
378 goto done;
379 }
380 auio.uio_resid = nbytes;
381 auio.uio_rw = UIO_READ;
382 KASSERT(l == curlwp);
383 auio.uio_vmspace = l->l_proc->p_vmspace;
384 auiop = &auio;
385 cnt = nbytes;
386 } else
387 sizep = &size;
388
389 error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep, l->l_cred);
390
391 if (auiop != NULL) {
392 cnt -= auio.uio_resid;
393 retval[0] = cnt;
394 } else
395 retval[0] = size;
396
397 done:
398 VOP_UNLOCK(vp);
399 return (error);
400 }
401
402 /*****************************************************************************
403 * BSD <sys/extattr.h> API for file system extended attributes
404 *****************************************************************************/
405
406 int
407 sys_extattr_set_fd(struct lwp *l, const struct sys_extattr_set_fd_args *uap, register_t *retval)
408 {
409 /* {
410 syscallarg(int) fd;
411 syscallarg(int) attrnamespace;
412 syscallarg(const char *) attrname;
413 syscallarg(const void *) data;
414 syscallarg(size_t) nbytes;
415 } */
416 struct file *fp;
417 struct vnode *vp;
418 char attrname[EXTATTR_MAXNAMELEN];
419 int error;
420
421 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
422 NULL);
423 if (error)
424 return (error);
425
426 error = fd_getvnode(SCARG(uap, fd), &fp);
427 if (error)
428 return (error);
429 vp = (struct vnode *) fp->f_data;
430
431 error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname,
432 SCARG(uap, data), SCARG(uap, nbytes), l, retval, 0);
433
434 fd_putfile(SCARG(uap, fd));
435 return (error);
436 }
437
438 int
439 sys_extattr_set_file(struct lwp *l, const struct sys_extattr_set_file_args *uap, register_t *retval)
440 {
441 /* {
442 syscallarg(const char *) path;
443 syscallarg(int) attrnamespace;
444 syscallarg(const char *) attrname;
445 syscallarg(const void *) data;
446 syscallarg(size_t) nbytes;
447 } */
448 struct vnode *vp;
449 char attrname[EXTATTR_MAXNAMELEN];
450 int error;
451
452 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
453 NULL);
454 if (error)
455 return (error);
456
457 error = namei_simple_user(SCARG(uap, path),
458 NSM_FOLLOW_NOEMULROOT, &vp);
459 if (error)
460 return (error);
461
462 error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname,
463 SCARG(uap, data), SCARG(uap, nbytes), l, retval, 0);
464
465 vrele(vp);
466 return (error);
467 }
468
469 int
470 sys_extattr_set_link(struct lwp *l, const struct sys_extattr_set_link_args *uap, register_t *retval)
471 {
472 /* {
473 syscallarg(const char *) path;
474 syscallarg(int) attrnamespace;
475 syscallarg(const char *) attrname;
476 syscallarg(const void *) data;
477 syscallarg(size_t) nbytes;
478 } */
479 struct vnode *vp;
480 char attrname[EXTATTR_MAXNAMELEN];
481 int error;
482
483 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
484 NULL);
485 if (error)
486 return (error);
487
488 error = namei_simple_user(SCARG(uap, path),
489 NSM_NOFOLLOW_NOEMULROOT, &vp);
490 if (error)
491 return (error);
492
493 error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname,
494 SCARG(uap, data), SCARG(uap, nbytes), l, retval, 0);
495
496 vrele(vp);
497 return (error);
498 }
499
500 int
501 sys_extattr_get_fd(struct lwp *l, const struct sys_extattr_get_fd_args *uap, register_t *retval)
502 {
503 /* {
504 syscallarg(int) fd;
505 syscallarg(int) attrnamespace;
506 syscallarg(const char *) attrname;
507 syscallarg(void *) data;
508 syscallarg(size_t) nbytes;
509 } */
510 struct file *fp;
511 struct vnode *vp;
512 char attrname[EXTATTR_MAXNAMELEN];
513 int error;
514
515 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
516 NULL);
517 if (error)
518 return (error);
519
520 error = fd_getvnode(SCARG(uap, fd), &fp);
521 if (error)
522 return (error);
523 vp = (struct vnode *) fp->f_data;
524
525 error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname,
526 SCARG(uap, data), SCARG(uap, nbytes), l, retval);
527
528 fd_putfile(SCARG(uap, fd));
529 return (error);
530 }
531
532 int
533 sys_extattr_get_file(struct lwp *l, const struct sys_extattr_get_file_args *uap, register_t *retval)
534 {
535 /* {
536 syscallarg(const char *) path;
537 syscallarg(int) attrnamespace;
538 syscallarg(const char *) attrname;
539 syscallarg(void *) data;
540 syscallarg(size_t) nbytes;
541 } */
542 struct vnode *vp;
543 char attrname[EXTATTR_MAXNAMELEN];
544 int error;
545
546 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
547 NULL);
548 if (error)
549 return (error);
550
551 error = namei_simple_user(SCARG(uap, path),
552 NSM_FOLLOW_NOEMULROOT, &vp);
553 if (error)
554 return (error);
555
556 error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname,
557 SCARG(uap, data), SCARG(uap, nbytes), l, retval);
558
559 vrele(vp);
560 return (error);
561 }
562
563 int
564 sys_extattr_get_link(struct lwp *l, const struct sys_extattr_get_link_args *uap, register_t *retval)
565 {
566 /* {
567 syscallarg(const char *) path;
568 syscallarg(int) attrnamespace;
569 syscallarg(const char *) attrname;
570 syscallarg(void *) data;
571 syscallarg(size_t) nbytes;
572 } */
573 struct vnode *vp;
574 char attrname[EXTATTR_MAXNAMELEN];
575 int error;
576
577 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
578 NULL);
579 if (error)
580 return (error);
581
582 error = namei_simple_user(SCARG(uap, path),
583 NSM_NOFOLLOW_NOEMULROOT, &vp);
584 if (error)
585 return (error);
586
587 error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname,
588 SCARG(uap, data), SCARG(uap, nbytes), l, retval);
589
590 vrele(vp);
591 return (error);
592 }
593
594 int
595 sys_extattr_delete_fd(struct lwp *l, const struct sys_extattr_delete_fd_args *uap, register_t *retval)
596 {
597 /* {
598 syscallarg(int) fd;
599 syscallarg(int) attrnamespace;
600 syscallarg(const char *) attrname;
601 } */
602 struct file *fp;
603 struct vnode *vp;
604 char attrname[EXTATTR_MAXNAMELEN];
605 int error;
606
607 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
608 NULL);
609 if (error)
610 return (error);
611
612 error = fd_getvnode(SCARG(uap, fd), &fp);
613 if (error)
614 return (error);
615 vp = (struct vnode *) fp->f_data;
616
617 error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l);
618
619 fd_putfile(SCARG(uap, fd));
620 return (error);
621 }
622
623 int
624 sys_extattr_delete_file(struct lwp *l, const struct sys_extattr_delete_file_args *uap, register_t *retval)
625 {
626 /* {
627 syscallarg(const char *) path;
628 syscallarg(int) attrnamespace;
629 syscallarg(const char *) attrname;
630 } */
631 struct vnode *vp;
632 char attrname[EXTATTR_MAXNAMELEN];
633 int error;
634
635 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
636 NULL);
637 if (error)
638 return (error);
639
640 error = namei_simple_user(SCARG(uap, path),
641 NSM_FOLLOW_NOEMULROOT, &vp);
642 if (error)
643 return (error);
644
645 error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l);
646
647 vrele(vp);
648 return (error);
649 }
650
651 int
652 sys_extattr_delete_link(struct lwp *l, const struct sys_extattr_delete_link_args *uap, register_t *retval)
653 {
654 /* {
655 syscallarg(const char *) path;
656 syscallarg(int) attrnamespace;
657 syscallarg(const char *) attrname;
658 } */
659 struct vnode *vp;
660 char attrname[EXTATTR_MAXNAMELEN];
661 int error;
662
663 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
664 NULL);
665 if (error)
666 return (error);
667
668 error = namei_simple_user(SCARG(uap, path),
669 NSM_NOFOLLOW_NOEMULROOT, &vp);
670 if (error)
671 return (error);
672
673 error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l);
674
675 vrele(vp);
676 return (error);
677 }
678
679 int
680 sys_extattr_list_fd(struct lwp *l, const struct sys_extattr_list_fd_args *uap, register_t *retval)
681 {
682 /* {
683 syscallarg(int) fd;
684 syscallarg(int) attrnamespace;
685 syscallarg(void *) data;
686 syscallarg(size_t) nbytes;
687 } */
688 struct file *fp;
689 struct vnode *vp;
690 int error;
691
692 error = fd_getvnode(SCARG(uap, fd), &fp);
693 if (error)
694 return (error);
695 vp = (struct vnode *) fp->f_data;
696
697 error = extattr_list_vp(vp, SCARG(uap, attrnamespace),
698 SCARG(uap, data), SCARG(uap, nbytes), l, retval);
699
700 fd_putfile(SCARG(uap, fd));
701 return (error);
702 }
703
704 int
705 sys_extattr_list_file(struct lwp *l, const struct sys_extattr_list_file_args *uap, register_t *retval)
706 {
707 /* {
708 syscallarg(const char *) path;
709 syscallarg(int) attrnamespace;
710 syscallarg(void *) data;
711 syscallarg(size_t) nbytes;
712 } */
713 struct vnode *vp;
714 int error;
715
716 error = namei_simple_user(SCARG(uap, path),
717 NSM_FOLLOW_NOEMULROOT, &vp);
718 if (error)
719 return (error);
720
721 error = extattr_list_vp(vp, SCARG(uap, attrnamespace),
722 SCARG(uap, data), SCARG(uap, nbytes), l, retval);
723
724 vrele(vp);
725 return (error);
726 }
727
728 int
729 sys_extattr_list_link(struct lwp *l, const struct sys_extattr_list_link_args *uap, register_t *retval)
730 {
731 /* {
732 syscallarg(const char *) path;
733 syscallarg(int) attrnamespace;
734 syscallarg(void *) data;
735 syscallarg(size_t) nbytes;
736 } */
737 struct vnode *vp;
738 int error;
739
740 error = namei_simple_user(SCARG(uap, path),
741 NSM_NOFOLLOW_NOEMULROOT, &vp);
742 if (error)
743 return (error);
744
745 error = extattr_list_vp(vp, SCARG(uap, attrnamespace),
746 SCARG(uap, data), SCARG(uap, nbytes), l, retval);
747
748 vrele(vp);
749 return (error);
750 }
751
752 /*****************************************************************************
753 * Linux-compatible <sys/xattr.h> API for file system extended attributes
754 *****************************************************************************/
755
756 #define MATCH_NS(ns, key) (strncmp(ns, key, sizeof(ns) - 1) == 0)
757 static int
758 xattr_native(const char *key) {
759 if (MATCH_NS("system.", key))
760 return EXTATTR_NAMESPACE_SYSTEM;
761 else if (MATCH_NS("user.", key))
762 return EXTATTR_NAMESPACE_USER;
763 else if (MATCH_NS("security.", key))
764 return EXTATTR_NAMESPACE_SYSTEM;
765 else if (MATCH_NS("trusted.", key))
766 return EXTATTR_NAMESPACE_SYSTEM;
767 else
768 return EXTATTR_NAMESPACE_USER;
769
770 }
771 #undef MATCH_NS
772
773 int
774 sys_setxattr(struct lwp *l, const struct sys_setxattr_args *uap, register_t *retval)
775 {
776 /* {
777 syscallarg(const char *) path;
778 syscallarg(const char *) name;
779 syscallarg(void *) value;
780 syscallarg(size_t) size;
781 syscallarg(int) flags;
782 } */
783 struct vnode *vp;
784 char attrname[XATTR_NAME_MAX];
785 int namespace;
786 register_t attrlen;
787 int error;
788
789 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
790 NULL);
791 if (error)
792 goto out;
793
794 error = namei_simple_user(SCARG(uap, path),
795 NSM_FOLLOW_NOEMULROOT, &vp);
796 if (error)
797 goto out_rele;
798
799 namespace = xattr_native(attrname);
800
801 error = extattr_set_vp(vp, namespace,
802 attrname, SCARG(uap, value), SCARG(uap, size), l,
803 &attrlen, SCARG(uap, flags));
804
805 out_rele:
806 vrele(vp);
807 out:
808 *retval = (error == 0) ? 0 : -1;
809 return (error);
810 }
811
812 int
813 sys_lsetxattr(struct lwp *l, const struct sys_lsetxattr_args *uap, register_t *retval)
814 {
815 /* {
816 syscallarg(const char *) path;
817 syscallarg(const char *) name;
818 syscallarg(void *) value;
819 syscallarg(size_t) size;
820 syscallarg(int) flags;
821 } */
822 struct vnode *vp;
823 char attrname[XATTR_NAME_MAX];
824 int namespace;
825 register_t attrlen;
826 int error;
827
828 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
829 NULL);
830 if (error)
831 goto out;
832
833 error = namei_simple_user(SCARG(uap, path),
834 NSM_NOFOLLOW_NOEMULROOT, &vp);
835 if (error)
836 goto out_rele;
837
838 namespace = xattr_native(attrname);
839
840 error = extattr_set_vp(vp, namespace,
841 attrname, SCARG(uap, value), SCARG(uap, size), l,
842 &attrlen, SCARG(uap, flags));
843
844 out_rele:
845 vrele(vp);
846 out:
847 *retval = (error == 0) ? 0 : -1;
848 return (error);
849 }
850
851 int
852 sys_fsetxattr(struct lwp *l, const struct sys_fsetxattr_args *uap, register_t *retval)
853 {
854 /* {
855 syscallarg(int) fd;
856 syscallarg(const char *) name;
857 syscallarg(void *) value;
858 syscallarg(size_t) size;
859 syscallarg(int) flags;
860 } */
861 struct file *fp;
862 struct vnode *vp;
863 char attrname[XATTR_NAME_MAX];
864 int namespace;
865 register_t attrlen;
866 int error;
867
868 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
869 NULL);
870 if (error)
871 goto out;
872
873 error = fd_getvnode(SCARG(uap, fd), &fp);
874 if (error)
875 goto out;
876 vp = (struct vnode *) fp->f_data;
877
878 namespace = xattr_native(attrname);
879
880 error = extattr_set_vp(vp, namespace,
881 attrname, SCARG(uap, value), SCARG(uap, size), l,
882 &attrlen, SCARG(uap, flags));
883
884 fd_putfile(SCARG(uap, fd));
885 out:
886 *retval = (error == 0) ? 0 : -1;
887 return (error);
888 }
889
890 int
891 sys_getxattr(struct lwp *l, const struct sys_getxattr_args *uap, register_t *retval)
892 {
893 /* {
894 syscallarg(const char *) path;
895 syscallarg(const char *) name;
896 syscallarg(void *) value;
897 syscallarg(size_t) size;
898 } */
899 struct vnode *vp;
900 char attrname[XATTR_NAME_MAX];
901 int namespace;
902 int error;
903
904 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
905 NULL);
906 if (error)
907 return (error);
908
909 error = namei_simple_user(SCARG(uap, path),
910 NSM_FOLLOW_NOEMULROOT, &vp);
911 if (error)
912 return (error);
913
914 namespace = xattr_native(attrname);
915
916 error = extattr_get_vp(vp, namespace,
917 attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
918
919 vrele(vp);
920 return (error);
921 }
922
923 int
924 sys_lgetxattr(struct lwp *l, const struct sys_lgetxattr_args *uap, register_t *retval)
925 {
926 /* {
927 syscallarg(const char *) path;
928 syscallarg(const char *) name;
929 syscallarg(void *) value;
930 syscallarg(size_t) size;
931 } */
932 struct vnode *vp;
933 char attrname[XATTR_NAME_MAX];
934 int namespace;
935 int error;
936
937 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
938 NULL);
939 if (error)
940 return (error);
941
942 error = namei_simple_user(SCARG(uap, path),
943 NSM_NOFOLLOW_NOEMULROOT, &vp);
944 if (error)
945 return (error);
946
947 namespace = xattr_native(attrname);
948
949 error = extattr_get_vp(vp, namespace,
950 attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
951
952 vrele(vp);
953 return (error);
954 }
955
956 int
957 sys_fgetxattr(struct lwp *l, const struct sys_fgetxattr_args *uap, register_t *retval)
958 {
959 /* {
960 syscallarg(int) fd;
961 syscallarg(const char *) name;
962 syscallarg(void *) value;
963 syscallarg(size_t) size;
964 } */
965 struct file *fp;
966 struct vnode *vp;
967 char attrname[XATTR_NAME_MAX];
968 int namespace;
969 int error;
970
971 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
972 NULL);
973 if (error)
974 return (error);
975
976 error = fd_getvnode(SCARG(uap, fd), &fp);
977 if (error)
978 return (error);
979 vp = (struct vnode *) fp->f_data;
980
981 namespace = xattr_native(attrname);
982
983 error = extattr_get_vp(vp, namespace,
984 attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
985
986 fd_putfile(SCARG(uap, fd));
987 return (error);
988 }
989
990 int
991 sys_listxattr(struct lwp *l, const struct sys_listxattr_args *uap, register_t *retval)
992 {
993 /* {
994 syscallarg(const char *) path;
995 syscallarg(char *) list;
996 syscallarg(size_t) size;
997 } */
998 struct vnode *vp;
999 char *list;
1000 size_t size;
1001 register_t listsize_usr, listsize_sys;
1002 int error;
1003
1004 error = namei_simple_user(SCARG(uap, path),
1005 NSM_FOLLOW_NOEMULROOT, &vp);
1006 if (error)
1007 return (error);
1008
1009 list = SCARG(uap, list);
1010 size = SCARG(uap, size);
1011
1012 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER,
1013 list, size, l, &listsize_usr);
1014 if (error)
1015 goto out;
1016
1017 if (list)
1018 list += listsize_usr;
1019 if (size)
1020 size -= listsize_usr;
1021
1022 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM,
1023 list, size, l, &listsize_sys);
1024 switch (error) {
1025 case EPERM:
1026 error = 0; /* Ignore and just skip system EA */
1027 listsize_sys = 0;
1028 break;
1029 case 0:
1030 break;
1031 default:
1032 goto out;
1033 break;
1034 }
1035
1036 *retval = listsize_usr + listsize_sys;
1037
1038 out:
1039 vrele(vp);
1040 return (error);
1041 }
1042
1043 int
1044 sys_llistxattr(struct lwp *l, const struct sys_llistxattr_args *uap, register_t *retval)
1045 {
1046 /* {
1047 syscallarg(const char *) path;
1048 syscallarg(char *) list;
1049 syscallarg(size_t) size;
1050 } */
1051 struct vnode *vp;
1052 char *list;
1053 size_t size;
1054 register_t listsize_usr, listsize_sys;
1055 int error;
1056
1057 error = namei_simple_user(SCARG(uap, path),
1058 NSM_NOFOLLOW_NOEMULROOT, &vp);
1059 if (error)
1060 return (error);
1061
1062 list = SCARG(uap, list);
1063 size = SCARG(uap, size);
1064
1065 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER,
1066 list, size, l, &listsize_usr);
1067 if (error)
1068 goto out;
1069
1070 if (list)
1071 list += listsize_usr;
1072 if (size)
1073 size -= listsize_usr;
1074
1075 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM,
1076 list, size, l, &listsize_sys);
1077 switch (error) {
1078 case EPERM:
1079 error = 0; /* Ignore and just skip system EA */
1080 listsize_sys = 0;
1081 break;
1082 case 0:
1083 break;
1084 default:
1085 goto out;
1086 break;
1087 }
1088
1089 *retval = listsize_usr + listsize_sys;
1090 out:
1091 vrele(vp);
1092 return (error);
1093 }
1094
1095 int
1096 sys_flistxattr(struct lwp *l, const struct sys_flistxattr_args *uap, register_t *retval)
1097 {
1098 /* {
1099 syscallarg(int) fd;
1100 syscallarg(char *) list;
1101 syscallarg(size_t) size;
1102 } */
1103 struct file *fp;
1104 struct vnode *vp;
1105 char *list;
1106 size_t size;
1107 register_t listsize_usr, listsize_sys;
1108 int error;
1109
1110 error = fd_getvnode(SCARG(uap, fd), &fp);
1111 if (error)
1112 return (error);
1113 vp = (struct vnode *) fp->f_data;
1114
1115 list = SCARG(uap, list);
1116 size = SCARG(uap, size);
1117
1118 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER,
1119 list, size, l, &listsize_usr);
1120 if (error)
1121 goto out;
1122
1123 if (list)
1124 list += listsize_usr;
1125 if (size)
1126 size -= listsize_usr;
1127
1128 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM,
1129 list, size, l, &listsize_sys);
1130 switch (error) {
1131 case EPERM:
1132 error = 0; /* Ignore and just skip system EA */
1133 listsize_sys = 0;
1134 break;
1135 case 0:
1136 break;
1137 default:
1138 goto out;
1139 break;
1140 }
1141
1142 *retval = listsize_usr + listsize_sys;
1143 out:
1144
1145 fd_putfile(SCARG(uap, fd));
1146 return (error);
1147 }
1148
1149 int
1150 sys_removexattr(struct lwp *l, const struct sys_removexattr_args *uap, register_t *retval)
1151 {
1152 /* {
1153 syscallarg(const char *) path;
1154 syscallarg(const char *) name;
1155 } */
1156 struct vnode *vp;
1157 char attrname[XATTR_NAME_MAX];
1158 int namespace;
1159 int error;
1160
1161 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
1162 NULL);
1163 if (error)
1164 return (error);
1165
1166 error = namei_simple_user(SCARG(uap, path),
1167 NSM_FOLLOW_NOEMULROOT, &vp);
1168 if (error)
1169 return (error);
1170
1171 namespace = xattr_native(attrname);
1172
1173 error = extattr_delete_vp(vp, namespace, attrname, l);
1174
1175 vrele(vp);
1176 return (error);
1177 }
1178
1179 int
1180 sys_lremovexattr(struct lwp *l, const struct sys_lremovexattr_args *uap, register_t *retval)
1181 {
1182 /* {
1183 syscallarg(const char *) path;
1184 syscallarg(const char *) name;
1185 } */
1186 struct vnode *vp;
1187 char attrname[XATTR_NAME_MAX];
1188 int namespace;
1189 int error;
1190
1191 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
1192 NULL);
1193 if (error)
1194 return (error);
1195
1196 error = namei_simple_user(SCARG(uap, path),
1197 NSM_NOFOLLOW_NOEMULROOT, &vp);
1198 if (error)
1199 return (error);
1200
1201 namespace = xattr_native(attrname);
1202
1203 error = extattr_delete_vp(vp, namespace, attrname, l);
1204
1205 vrele(vp);
1206 return (error);
1207 }
1208
1209 int
1210 sys_fremovexattr(struct lwp *l, const struct sys_fremovexattr_args *uap, register_t *retval)
1211 {
1212 /* {
1213 syscallarg(int) fd;
1214 syscallarg(const char *) name;
1215 } */
1216 struct file *fp;
1217 struct vnode *vp;
1218 char attrname[XATTR_NAME_MAX];
1219 int namespace;
1220 int error;
1221
1222 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
1223 NULL);
1224 if (error)
1225 return (error);
1226
1227 error = fd_getvnode(SCARG(uap, fd), &fp);
1228 if (error)
1229 return (error);
1230 vp = (struct vnode *) fp->f_data;
1231
1232 namespace = xattr_native(attrname);
1233
1234 error = extattr_delete_vp(vp, namespace, attrname, l);
1235
1236 fd_putfile(SCARG(uap, fd));
1237 return (error);
1238 }
1239