xref: /netbsd-src/sys/kern/vfs_xattr.c (revision 9aa0541bdf64142d9a27c2cf274394d60182818f)
1 /*	$NetBSD: vfs_xattr.c,v 1.28 2011/07/22 12:46:18 manu Exp $	*/
2 
3 /*-
4  * Copyright (c) 2005, 2008 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 1989, 1993
34  *	The Regents of the University of California.  All rights reserved.
35  * (c) UNIX System Laboratories, Inc.
36  * All or some portions of this file are derived from material licensed
37  * to the University of California by American Telephone and Telegraph
38  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
39  * the permission of UNIX System Laboratories, Inc.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. Neither the name of the University nor the names of its contributors
50  *    may be used to endorse or promote products derived from this software
51  *    without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63  * SUCH DAMAGE.
64  */
65 
66 /*
67  * VFS extended attribute support.
68  */
69 
70 #include <sys/cdefs.h>
71 __KERNEL_RCSID(0, "$NetBSD: vfs_xattr.c,v 1.28 2011/07/22 12:46:18 manu Exp $");
72 
73 #include <sys/param.h>
74 #include <sys/systm.h>
75 #include <sys/namei.h>
76 #include <sys/filedesc.h>
77 #include <sys/kernel.h>
78 #include <sys/file.h>
79 #include <sys/vnode.h>
80 #include <sys/mount.h>
81 #include <sys/proc.h>
82 #include <sys/uio.h>
83 #include <sys/extattr.h>
84 #include <sys/xattr.h>
85 #include <sys/sysctl.h>
86 #include <sys/syscallargs.h>
87 #include <sys/kauth.h>
88 #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 int
790 sys_setxattr(struct lwp *l, const struct sys_setxattr_args *uap, register_t *retval)
791 {
792 	/* {
793 		syscallarg(const char *) path;
794 		syscallarg(const char *) name;
795 		syscallarg(void *) value;
796 		syscallarg(size_t) size;
797 		syscallarg(int) flags;
798 	} */
799 	struct vnode *vp;
800 	char attrname[XATTR_NAME_MAX];
801 	int namespace;
802 	register_t attrlen;
803 	int error;
804 
805 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
806 	    NULL);
807 	if (error)
808 		goto out;
809 
810 	error = namei_simple_user(SCARG(uap, path),
811 				NSM_FOLLOW_NOEMULROOT, &vp);
812 	if (error)
813 		goto out;
814 
815 	namespace = xattr_native(attrname);
816 
817 	error = extattr_set_vp(vp, namespace,
818 	    attrname, SCARG(uap, value), SCARG(uap, size), l,
819 	    &attrlen, SCARG(uap, flags));
820 
821 	vrele(vp);
822 out:
823 	*retval = (error == 0) ? 0 : -1;
824 	return (error);
825 }
826 
827 int
828 sys_lsetxattr(struct lwp *l, const struct sys_lsetxattr_args *uap, register_t *retval)
829 {
830 	/* {
831 		syscallarg(const char *) path;
832 		syscallarg(const char *) name;
833 		syscallarg(void *) value;
834 		syscallarg(size_t) size;
835 		syscallarg(int) flags;
836 	} */
837 	struct vnode *vp;
838 	char attrname[XATTR_NAME_MAX];
839 	int namespace;
840 	register_t attrlen;
841 	int error;
842 
843 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
844 	    NULL);
845 	if (error)
846 		goto out;
847 
848 	error = namei_simple_user(SCARG(uap, path),
849 				NSM_NOFOLLOW_NOEMULROOT, &vp);
850 	if (error)
851 		goto out;
852 
853 	namespace = xattr_native(attrname);
854 
855 	error = extattr_set_vp(vp, namespace,
856 	    attrname, SCARG(uap, value), SCARG(uap, size), l,
857 	    &attrlen, SCARG(uap, flags));
858 
859 	vrele(vp);
860 out:
861 	*retval = (error == 0) ? 0 : -1;
862 	return (error);
863 }
864 
865 int
866 sys_fsetxattr(struct lwp *l, const struct sys_fsetxattr_args *uap, register_t *retval)
867 {
868 	/* {
869 		syscallarg(int) fd;
870 		syscallarg(const char *) name;
871 		syscallarg(void *) value;
872 		syscallarg(size_t) size;
873 		syscallarg(int) flags;
874 	} */
875 	struct file *fp;
876 	struct vnode *vp;
877 	char attrname[XATTR_NAME_MAX];
878 	int namespace;
879 	register_t attrlen;
880 	int error;
881 
882 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
883 	    NULL);
884 	if (error)
885 		goto out;
886 
887 	error = fd_getvnode(SCARG(uap, fd), &fp);
888 	if (error)
889 		goto out;
890 	vp = (struct vnode *) fp->f_data;
891 
892 	namespace = xattr_native(attrname);
893 
894 	error = extattr_set_vp(vp, namespace,
895 	    attrname, SCARG(uap, value), SCARG(uap, size), l,
896 	    &attrlen, SCARG(uap, flags));
897 
898 	fd_putfile(SCARG(uap, fd));
899 out:
900 	*retval = (error == 0) ? 0 : -1;
901 	return (error);
902 }
903 
904 int
905 sys_getxattr(struct lwp *l, const struct sys_getxattr_args *uap, register_t *retval)
906 {
907 	/* {
908 		syscallarg(const char *) path;
909 		syscallarg(const char *) name;
910 		syscallarg(void *) value;
911 		syscallarg(size_t) size;
912 	} */
913 	struct vnode *vp;
914 	char attrname[XATTR_NAME_MAX];
915 	int namespace;
916 	int error;
917 
918 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
919 	    NULL);
920 	if (error)
921 		return (error);
922 
923 	error = namei_simple_user(SCARG(uap, path),
924 				NSM_FOLLOW_NOEMULROOT, &vp);
925 	if (error)
926 		return (error);
927 
928 	namespace = xattr_native(attrname);
929 
930 	error = extattr_get_vp(vp, namespace,
931 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
932 
933 	vrele(vp);
934 	return (error);
935 }
936 
937 int
938 sys_lgetxattr(struct lwp *l, const struct sys_lgetxattr_args *uap, register_t *retval)
939 {
940 	/* {
941 		syscallarg(const char *) path;
942 		syscallarg(const char *) name;
943 		syscallarg(void *) value;
944 		syscallarg(size_t) size;
945 	} */
946 	struct vnode *vp;
947 	char attrname[XATTR_NAME_MAX];
948 	int namespace;
949 	int error;
950 
951 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
952 	    NULL);
953 	if (error)
954 		return (error);
955 
956 	error = namei_simple_user(SCARG(uap, path),
957 				NSM_NOFOLLOW_NOEMULROOT, &vp);
958 	if (error)
959 		return (error);
960 
961 	namespace = xattr_native(attrname);
962 
963 	error = extattr_get_vp(vp, namespace,
964 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
965 
966 	vrele(vp);
967 	return (error);
968 }
969 
970 int
971 sys_fgetxattr(struct lwp *l, const struct sys_fgetxattr_args *uap, register_t *retval)
972 {
973 	/* {
974 		syscallarg(int) fd;
975 		syscallarg(const char *) name;
976 		syscallarg(void *) value;
977 		syscallarg(size_t) size;
978 	} */
979 	struct file *fp;
980 	struct vnode *vp;
981 	char attrname[XATTR_NAME_MAX];
982 	int namespace;
983 	int error;
984 
985 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
986 	    NULL);
987 	if (error)
988 		return (error);
989 
990 	error = fd_getvnode(SCARG(uap, fd), &fp);
991 	if (error)
992 		return (error);
993 	vp = (struct vnode *) fp->f_data;
994 
995 	namespace = xattr_native(attrname);
996 
997 	error = extattr_get_vp(vp, namespace,
998 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
999 
1000 	fd_putfile(SCARG(uap, fd));
1001 	return (error);
1002 }
1003 
1004 int
1005 sys_listxattr(struct lwp *l, const struct sys_listxattr_args *uap, register_t *retval)
1006 {
1007 	/* {
1008 		syscallarg(const char *) path;
1009 		syscallarg(char *) list;
1010 		syscallarg(size_t) size;
1011 	} */
1012 	struct vnode *vp;
1013 	char *list;
1014 	size_t size;
1015 	register_t listsize_usr, listsize_sys;
1016 	int error;
1017 
1018 	error = namei_simple_user(SCARG(uap, path),
1019 				NSM_FOLLOW_NOEMULROOT, &vp);
1020 	if (error)
1021 		return (error);
1022 
1023 	list = SCARG(uap, list);
1024 	size = SCARG(uap, size);
1025 
1026 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER,
1027 	    list, size, 0, l, &listsize_usr);
1028 	if (error)
1029 		goto out;
1030 
1031 	if (list)
1032 		list += listsize_usr;
1033 	if (size)
1034 		size -= listsize_usr;
1035 
1036 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM,
1037 	    list, size, 0, l, &listsize_sys);
1038 	switch (error) {
1039 	case EPERM:
1040 		error = 0; /* Ignore and just skip system EA */
1041 		listsize_sys = 0;
1042 		break;
1043 	case 0:
1044 		break;
1045 	default:
1046 		goto out;
1047 		break;
1048 	}
1049 
1050 	*retval = listsize_usr + listsize_sys;
1051 
1052 out:
1053 	vrele(vp);
1054 	return (error);
1055 }
1056 
1057 int
1058 sys_llistxattr(struct lwp *l, const struct sys_llistxattr_args *uap, register_t *retval)
1059 {
1060 	/* {
1061 		syscallarg(const char *) path;
1062 		syscallarg(char *) list;
1063 		syscallarg(size_t) size;
1064 	} */
1065 	struct vnode *vp;
1066 	char *list;
1067 	size_t size;
1068 	register_t listsize_usr, listsize_sys;
1069 	int error;
1070 
1071 	error = namei_simple_user(SCARG(uap, path),
1072 				NSM_NOFOLLOW_NOEMULROOT, &vp);
1073 	if (error)
1074 		return (error);
1075 
1076 	list = SCARG(uap, list);
1077 	size = SCARG(uap, size);
1078 
1079 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER,
1080 	    list, size, 0, l, &listsize_usr);
1081 	if (error)
1082 		goto out;
1083 	if (list)
1084 		list += listsize_usr;
1085 	if (size)
1086 		size -= listsize_usr;
1087 
1088 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM,
1089 	    list, size, 0, l, &listsize_sys);
1090 	switch (error) {
1091 	case EPERM:
1092 		error = 0; /* Ignore and just skip system EA */
1093 		listsize_sys = 0;
1094 		break;
1095 	case 0:
1096 		break;
1097 	default:
1098 		goto out;
1099 		break;
1100 	}
1101 
1102 	*retval = listsize_usr + listsize_sys;
1103 out:
1104 	vrele(vp);
1105 	return (error);
1106 }
1107 
1108 int
1109 sys_flistxattr(struct lwp *l, const struct sys_flistxattr_args *uap, register_t *retval)
1110 {
1111 	/* {
1112 		syscallarg(int) fd;
1113 		syscallarg(char *) list;
1114 		syscallarg(size_t) size;
1115 	} */
1116 	struct file *fp;
1117 	struct vnode *vp;
1118 	char *list;
1119 	size_t size;
1120 	register_t listsize_usr, listsize_sys;
1121 	int error;
1122 
1123 	error = fd_getvnode(SCARG(uap, fd), &fp);
1124 	if (error)
1125 		return (error);
1126 	vp = (struct vnode *) fp->f_data;
1127 
1128 	list = SCARG(uap, list);
1129 	size = SCARG(uap, size);
1130 
1131 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER,
1132 	    list, size, 0, l, &listsize_usr);
1133 	if (error)
1134 		goto out;
1135 
1136 	if (list)
1137 		list += listsize_usr;
1138 	if (size)
1139 		size -= listsize_usr;
1140 
1141 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM,
1142 	    list, size, 0, l, &listsize_sys);
1143 	switch (error) {
1144 	case EPERM:
1145 		error = 0; /* Ignore and just skip system EA */
1146 		listsize_sys = 0;
1147 		break;
1148 	case 0:
1149 		break;
1150 	default:
1151 		goto out;
1152 		break;
1153 	}
1154 
1155 	*retval = listsize_usr + listsize_sys;
1156 out:
1157 
1158 	fd_putfile(SCARG(uap, fd));
1159 	return (error);
1160 }
1161 
1162 int
1163 sys_removexattr(struct lwp *l, const struct sys_removexattr_args *uap, register_t *retval)
1164 {
1165 	/* {
1166 		syscallarg(const char *) path;
1167 		syscallarg(const char *) name;
1168 	} */
1169 	struct vnode *vp;
1170 	char attrname[XATTR_NAME_MAX];
1171 	int namespace;
1172 	int error;
1173 
1174 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
1175 	    NULL);
1176 	if (error)
1177 		return (error);
1178 
1179 	error = namei_simple_user(SCARG(uap, path),
1180 				NSM_FOLLOW_NOEMULROOT, &vp);
1181 	if (error)
1182 		return (error);
1183 
1184 	namespace = xattr_native(attrname);
1185 
1186 	error = extattr_delete_vp(vp, namespace, attrname, l);
1187 
1188 	vrele(vp);
1189 	return (error);
1190 }
1191 
1192 int
1193 sys_lremovexattr(struct lwp *l, const struct sys_lremovexattr_args *uap, register_t *retval)
1194 {
1195 	/* {
1196 		syscallarg(const char *) path;
1197 		syscallarg(const char *) name;
1198 	} */
1199 	struct vnode *vp;
1200 	char attrname[XATTR_NAME_MAX];
1201 	int namespace;
1202 	int error;
1203 
1204 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
1205 	    NULL);
1206 	if (error)
1207 		return (error);
1208 
1209 	error = namei_simple_user(SCARG(uap, path),
1210 				NSM_NOFOLLOW_NOEMULROOT, &vp);
1211 	if (error)
1212 		return (error);
1213 
1214 	namespace = xattr_native(attrname);
1215 
1216 	error = extattr_delete_vp(vp, namespace, attrname, l);
1217 
1218 	vrele(vp);
1219 	return (error);
1220 }
1221 
1222 int
1223 sys_fremovexattr(struct lwp *l, const struct sys_fremovexattr_args *uap, register_t *retval)
1224 {
1225 	/* {
1226 		syscallarg(int) fd;
1227 		syscallarg(const char *) name;
1228 	} */
1229 	struct file *fp;
1230 	struct vnode *vp;
1231 	char attrname[XATTR_NAME_MAX];
1232 	int namespace;
1233 	int error;
1234 
1235 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
1236 	    NULL);
1237 	if (error)
1238 		return (error);
1239 
1240 	error = fd_getvnode(SCARG(uap, fd), &fp);
1241 	if (error)
1242 		return (error);
1243 	vp = (struct vnode *) fp->f_data;
1244 
1245 	namespace = xattr_native(attrname);
1246 
1247 	error = extattr_delete_vp(vp, namespace, attrname, l);
1248 
1249 	fd_putfile(SCARG(uap, fd));
1250 	return (error);
1251 }
1252