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