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