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