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