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