xref: /freebsd/sys/kern/vfs_extattr.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
19454b2d8SWarner Losh /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
38a36da99SPedro F. Giffuni  *
4168d0553SRobert Watson  * Copyright (c) 1999-2001 Robert N. M. Watson
5168d0553SRobert Watson  * All rights reserved.
6168d0553SRobert Watson  *
7168d0553SRobert Watson  * This software was developed by Robert Watson for the TrustedBSD Project.
8df8bae1dSRodney W. Grimes  *
9df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
10df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
11df8bae1dSRodney W. Grimes  * are met:
12df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
13df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
14df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
15df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
16df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
17df8bae1dSRodney W. Grimes  *
18168d0553SRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21168d0553SRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
29df8bae1dSRodney W. Grimes  */
30df8bae1dSRodney W. Grimes 
31df8bae1dSRodney W. Grimes #include <sys/param.h>
32df8bae1dSRodney W. Grimes #include <sys/systm.h>
334a144410SRobert Watson #include <sys/capsicum.h>
34168d0553SRobert Watson #include <sys/lock.h>
35c24fda81SAlfred Perlstein #include <sys/mount.h>
3635e0e5b3SJohn Baldwin #include <sys/mutex.h>
37d2d3e875SBruce Evans #include <sys/sysproto.h>
3857b4252eSKonstantin Belousov #include <sys/fcntl.h>
39df8bae1dSRodney W. Grimes #include <sys/namei.h>
40df8bae1dSRodney W. Grimes #include <sys/filedesc.h>
41104a9b7eSAlexander Kabaev #include <sys/limits.h>
42df8bae1dSRodney W. Grimes #include <sys/vnode.h>
43df8bae1dSRodney W. Grimes #include <sys/proc.h>
4491f37dcbSRobert Watson #include <sys/extattr.h>
45*3555be01SJohn Baldwin #include <sys/syscallsubr.h>
46b82f5b62SAndrey A. Chernov 
47bc5504b9SWayne Salamon #include <security/audit/audit.h>
48aed55708SRobert Watson #include <security/mac/mac_framework.h>
49bc5504b9SWayne Salamon 
506453d424SDmitry Chagin static int	user_extattr_set_path(struct thread *td, const char *path,
510a2c60c3SBrooks Davis 		    int attrnamespace, const char *attrname, void *data,
520a2c60c3SBrooks Davis 		    size_t nbytes, int follow);
536453d424SDmitry Chagin static int	user_extattr_get_path(struct thread *td, const char *path,
540a2c60c3SBrooks Davis 		    int attrnamespace, const char *attrname, void *data,
550a2c60c3SBrooks Davis 		    size_t nbytes, int follow);
566453d424SDmitry Chagin static int	user_extattr_delete_path(struct thread *td, const char *path,
570a2c60c3SBrooks Davis 		    int attrnamespace, const char *attrname, int follow);
586453d424SDmitry Chagin static int	user_extattr_list_path(struct thread *td, const char *path,
590a2c60c3SBrooks Davis 		    int attrnamespace, void *data, size_t nbytes, int follow);
600a2c60c3SBrooks Davis 
6191f37dcbSRobert Watson /*
62afae6388SRobert Watson  * Syscall to push extended attribute configuration information into the VFS.
63afae6388SRobert Watson  * Accepts a path, which it converts to a mountpoint, as well as a command
64afae6388SRobert Watson  * (int cmd), and attribute name and misc data.
6591f37dcbSRobert Watson  *
66afae6388SRobert Watson  * Currently this is used only by UFS1 extended attributes.
6791f37dcbSRobert Watson  */
6802bc058fSBrooks Davis #ifndef _SYS_SYSPROTO_H_
6902bc058fSBrooks Davis struct extattrctl_args {
70b80521feSAlfred Perlstein 	const char *path;
71b80521feSAlfred Perlstein 	int cmd;
72b80521feSAlfred Perlstein 	const char *filename;
73b80521feSAlfred Perlstein 	int attrnamespace;
74b80521feSAlfred Perlstein 	const char *attrname;
7502bc058fSBrooks Davis };
7602bc058fSBrooks Davis #endif
7702bc058fSBrooks Davis int
sys_extattrctl(struct thread * td,struct extattrctl_args * uap)7802bc058fSBrooks Davis sys_extattrctl(struct thread *td, struct extattrctl_args *uap)
7991f37dcbSRobert Watson {
8070f36851SRobert Watson 	struct vnode *filename_vp;
8191f37dcbSRobert Watson 	struct nameidata nd;
82143bb598SRobert Watson 	struct mount *mp, *mp_writable;
83b21ae0ffSConrad Meyer 	char attrname[EXTATTR_MAXNAMELEN + 1];
845050aa86SKonstantin Belousov 	int error;
8591f37dcbSRobert Watson 
8614961ba7SRobert Watson 	AUDIT_ARG_CMD(uap->cmd);
8714961ba7SRobert Watson 	AUDIT_ARG_VALUE(uap->attrnamespace);
8870f36851SRobert Watson 	/*
8905103170SRobert Watson 	 * uap->attrname is not always defined.  We check again later when we
9005103170SRobert Watson 	 * invoke the VFS call so as to pass in NULL there if needed.
9170f36851SRobert Watson 	 */
9205103170SRobert Watson 	if (uap->attrname != NULL) {
93b21ae0ffSConrad Meyer 		error = copyinstr(uap->attrname, attrname, sizeof(attrname),
9405103170SRobert Watson 		    NULL);
9570f36851SRobert Watson 		if (error)
9670f36851SRobert Watson 			return (error);
9770f36851SRobert Watson 	}
9814961ba7SRobert Watson 	AUDIT_ARG_TEXT(attrname);
9970f36851SRobert Watson 
100d19b9927SKonstantin Belousov 	mp = NULL;
10170f36851SRobert Watson 	filename_vp = NULL;
10205103170SRobert Watson 	if (uap->filename != NULL) {
1037e1d3eefSMateusz Guzik 		NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE2, UIO_USERSPACE,
1047e1d3eefSMateusz Guzik 		    uap->filename);
1052dba710dSRobert Watson 		error = namei(&nd);
1062dba710dSRobert Watson 		if (error)
10770f36851SRobert Watson 			return (error);
10870f36851SRobert Watson 		filename_vp = nd.ni_vp;
10985dac03eSMateusz Guzik 		NDFREE_PNBUF(&nd);
11070f36851SRobert Watson 	}
11170f36851SRobert Watson 
11205103170SRobert Watson 	/* uap->path is always defined. */
1137e1d3eefSMateusz Guzik 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, UIO_USERSPACE,
1147e1d3eefSMateusz Guzik 	    uap->path);
1152dba710dSRobert Watson 	error = namei(&nd);
116d19b9927SKonstantin Belousov 	if (error)
117c47a4d1cSChristian S.J. Peron 		goto out;
118143bb598SRobert Watson 	mp = nd.ni_vp->v_mount;
119d19b9927SKonstantin Belousov 	error = vfs_busy(mp, 0);
12070f36851SRobert Watson 	if (error) {
12185dac03eSMateusz Guzik 		vput(nd.ni_vp);
12285dac03eSMateusz Guzik 		NDFREE_PNBUF(&nd);
123d19b9927SKonstantin Belousov 		mp = NULL;
124c47a4d1cSChristian S.J. Peron 		goto out;
12570f36851SRobert Watson 	}
126b249ce48SMateusz Guzik 	VOP_UNLOCK(nd.ni_vp);
127a75d1dddSMateusz Guzik 	error = vn_start_write(nd.ni_vp, &mp_writable, V_WAIT | V_PCATCH);
12885dac03eSMateusz Guzik 	vrele(nd.ni_vp);
12985dac03eSMateusz Guzik 	NDFREE_PNBUF(&nd);
130d19b9927SKonstantin Belousov 	if (error)
131d19b9927SKonstantin Belousov 		goto out;
132d19b9927SKonstantin Belousov 	if (filename_vp != NULL) {
133d19b9927SKonstantin Belousov 		/*
134d19b9927SKonstantin Belousov 		 * uap->filename is not always defined.  If it is,
135d19b9927SKonstantin Belousov 		 * grab a vnode lock, which VFS_EXTATTRCTL() will
136d19b9927SKonstantin Belousov 		 * later release.
137d19b9927SKonstantin Belousov 		 */
138d19b9927SKonstantin Belousov 		error = vn_lock(filename_vp, LK_EXCLUSIVE);
139d19b9927SKonstantin Belousov 		if (error) {
140d19b9927SKonstantin Belousov 			vn_finished_write(mp_writable);
141d19b9927SKonstantin Belousov 			goto out;
142d19b9927SKonstantin Belousov 		}
143d19b9927SKonstantin Belousov 	}
14470f36851SRobert Watson 
145956fc3f8SRobert Watson 	error = VFS_EXTATTRCTL(mp, uap->cmd, filename_vp, uap->attrnamespace,
146dfd233edSAttilio Rao 	    uap->attrname != NULL ? attrname : NULL);
14770f36851SRobert Watson 
148143bb598SRobert Watson 	vn_finished_write(mp_writable);
149d19b9927SKonstantin Belousov out:
150d19b9927SKonstantin Belousov 	if (mp != NULL)
151d19b9927SKonstantin Belousov 		vfs_unbusy(mp);
152d19b9927SKonstantin Belousov 
15370f36851SRobert Watson 	/*
154afae6388SRobert Watson 	 * VFS_EXTATTRCTL will have unlocked, but not de-ref'd, filename_vp,
155afae6388SRobert Watson 	 * so vrele it if it is defined.
15670f36851SRobert Watson 	 */
15770f36851SRobert Watson 	if (filename_vp != NULL)
15870f36851SRobert Watson 		vrele(filename_vp);
159f2a2857bSKirk McKusick 	return (error);
16091f37dcbSRobert Watson }
16191f37dcbSRobert Watson 
1621a996ed1SEdward Tomasz Napierala /*-
16374237f55SRobert Watson  * Set a named extended attribute on a file or directory
164fec605c8SRobert Watson  *
165fec605c8SRobert Watson  * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
16674237f55SRobert Watson  *            kernelspace string pointer "attrname", userspace buffer
16774237f55SRobert Watson  *            pointer "data", buffer length "nbytes", thread "td".
168fec605c8SRobert Watson  * Returns: 0 on success, an error number otherwise
169fec605c8SRobert Watson  * Locks: none
170fec605c8SRobert Watson  * References: vp must be a valid reference for the duration of the call
17191f37dcbSRobert Watson  */
172fec605c8SRobert Watson static int
extattr_set_vp(struct vnode * vp,int attrnamespace,const char * attrname,void * data,size_t nbytes,struct thread * td)173fec605c8SRobert Watson extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
17456e04d01SRobert Watson     void *data, size_t nbytes, struct thread *td)
17591f37dcbSRobert Watson {
176f2a2857bSKirk McKusick 	struct mount *mp;
17791f37dcbSRobert Watson 	struct uio auio;
17874237f55SRobert Watson 	struct iovec aiov;
17974237f55SRobert Watson 	ssize_t cnt;
18074237f55SRobert Watson 	int error;
18191f37dcbSRobert Watson 
18261b214f3SFedor Uporov 	if (nbytes > IOSIZE_MAX)
18361b214f3SFedor Uporov 		return (EINVAL);
18461b214f3SFedor Uporov 
185a75d1dddSMateusz Guzik 	error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH);
1862dba710dSRobert Watson 	if (error)
18791f37dcbSRobert Watson 		return (error);
188cb05b60aSAttilio Rao 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
189fec605c8SRobert Watson 
19074237f55SRobert Watson 	aiov.iov_base = data;
19174237f55SRobert Watson 	aiov.iov_len = nbytes;
19274237f55SRobert Watson 	auio.uio_iov = &aiov;
19374237f55SRobert Watson 	auio.uio_iovcnt = 1;
19474237f55SRobert Watson 	auio.uio_offset = 0;
19574237f55SRobert Watson 	auio.uio_resid = nbytes;
19691f37dcbSRobert Watson 	auio.uio_rw = UIO_WRITE;
19791f37dcbSRobert Watson 	auio.uio_segflg = UIO_USERSPACE;
198b40ce416SJulian Elischer 	auio.uio_td = td;
19974237f55SRobert Watson 	cnt = nbytes;
20074237f55SRobert Watson 
201f4d2cfddSRobert Watson #ifdef MAC
20230d239bcSRobert Watson 	error = mac_vnode_check_setextattr(td->td_ucred, vp, attrnamespace,
203fefd0ac8SRobert Watson 	    attrname);
204f4d2cfddSRobert Watson 	if (error)
205f4d2cfddSRobert Watson 		goto done;
206f4d2cfddSRobert Watson #endif
207f4d2cfddSRobert Watson 
208fec605c8SRobert Watson 	error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
209a854ed98SJohn Baldwin 	    td->td_ucred, td);
21091f37dcbSRobert Watson 	cnt -= auio.uio_resid;
211b40ce416SJulian Elischer 	td->td_retval[0] = cnt;
21274237f55SRobert Watson 
2134ba058c0SFedor Uporov #ifdef MAC
21491f37dcbSRobert Watson done:
2154ba058c0SFedor Uporov #endif
216b249ce48SMateusz Guzik 	VOP_UNLOCK(vp);
217f2a2857bSKirk McKusick 	vn_finished_write(mp);
21891f37dcbSRobert Watson 	return (error);
21991f37dcbSRobert Watson }
22091f37dcbSRobert Watson 
22102bc058fSBrooks Davis #ifndef _SYS_SYSPROTO_H_
22202bc058fSBrooks Davis struct extattr_set_fd_args {
223b80521feSAlfred Perlstein 	int fd;
224b80521feSAlfred Perlstein 	int attrnamespace;
225b80521feSAlfred Perlstein 	const char *attrname;
226b80521feSAlfred Perlstein 	void *data;
227b80521feSAlfred Perlstein 	size_t nbytes;
22802bc058fSBrooks Davis };
22902bc058fSBrooks Davis #endif
23002bc058fSBrooks Davis int
sys_extattr_set_fd(struct thread * td,struct extattr_set_fd_args * uap)23102bc058fSBrooks Davis sys_extattr_set_fd(struct thread *td, struct extattr_set_fd_args *uap)
232b101411bSRobert Watson {
233b21ae0ffSConrad Meyer 	char attrname[EXTATTR_MAXNAMELEN + 1];
2345050aa86SKonstantin Belousov 	int error;
235b101411bSRobert Watson 
236b21ae0ffSConrad Meyer 	error = copyinstr(uap->attrname, attrname, sizeof(attrname), NULL);
237b101411bSRobert Watson 	if (error)
238b101411bSRobert Watson 		return (error);
2396453d424SDmitry Chagin 	return (kern_extattr_set_fd(td, uap->fd, uap->attrnamespace,
2406453d424SDmitry Chagin 	    attrname, uap->data, uap->nbytes));
2416453d424SDmitry Chagin }
2426453d424SDmitry Chagin 
2436453d424SDmitry Chagin int
kern_extattr_set_fd(struct thread * td,int fd,int attrnamespace,const char * attrname,void * data,size_t nbytes)2446453d424SDmitry Chagin kern_extattr_set_fd(struct thread *td, int fd, int attrnamespace,
2456453d424SDmitry Chagin     const char *attrname, void *data, size_t nbytes)
2466453d424SDmitry Chagin {
2476453d424SDmitry Chagin 	struct file *fp;
2486453d424SDmitry Chagin 	cap_rights_t rights;
2496453d424SDmitry Chagin 	int error;
2506453d424SDmitry Chagin 
2516453d424SDmitry Chagin 	AUDIT_ARG_FD(fd);
2526453d424SDmitry Chagin 	AUDIT_ARG_VALUE(attrnamespace);
25314961ba7SRobert Watson 	AUDIT_ARG_TEXT(attrname);
254b101411bSRobert Watson 
2556453d424SDmitry Chagin 	error = getvnode_path(td, fd,
256e126c5a3SMateusz Guzik 	    cap_rights_init_one(&rights, CAP_EXTATTR_SET), &fp);
2572dba710dSRobert Watson 	if (error)
258b101411bSRobert Watson 		return (error);
259b101411bSRobert Watson 
2606453d424SDmitry Chagin 	error = extattr_set_vp(fp->f_vnode, attrnamespace,
2616453d424SDmitry Chagin 	    attrname, data, nbytes, td);
262b101411bSRobert Watson 	fdrop(fp, td);
263b101411bSRobert Watson 
264b101411bSRobert Watson 	return (error);
265b101411bSRobert Watson }
266b101411bSRobert Watson 
26702bc058fSBrooks Davis #ifndef _SYS_SYSPROTO_H_
26802bc058fSBrooks Davis struct extattr_set_file_args {
269b80521feSAlfred Perlstein 	const char *path;
270b80521feSAlfred Perlstein 	int attrnamespace;
271b80521feSAlfred Perlstein 	const char *attrname;
272b80521feSAlfred Perlstein 	void *data;
273b80521feSAlfred Perlstein 	size_t nbytes;
27402bc058fSBrooks Davis };
27502bc058fSBrooks Davis #endif
27602bc058fSBrooks Davis int
sys_extattr_set_file(struct thread * td,struct extattr_set_file_args * uap)27702bc058fSBrooks Davis sys_extattr_set_file(struct thread *td, struct extattr_set_file_args *uap)
278fec605c8SRobert Watson {
279fec605c8SRobert Watson 
2806453d424SDmitry Chagin 	return (user_extattr_set_path(td, uap->path, uap->attrnamespace,
2810a2c60c3SBrooks Davis 	    uap->attrname, uap->data, uap->nbytes, FOLLOW));
282fec605c8SRobert Watson }
283fec605c8SRobert Watson 
28402bc058fSBrooks Davis #ifndef _SYS_SYSPROTO_H_
28502bc058fSBrooks Davis struct extattr_set_link_args {
286b80521feSAlfred Perlstein 	const char *path;
287b80521feSAlfred Perlstein 	int attrnamespace;
288b80521feSAlfred Perlstein 	const char *attrname;
289b80521feSAlfred Perlstein 	void *data;
290b80521feSAlfred Perlstein 	size_t nbytes;
29102bc058fSBrooks Davis };
29202bc058fSBrooks Davis #endif
29302bc058fSBrooks Davis int
sys_extattr_set_link(struct thread * td,struct extattr_set_link_args * uap)29402bc058fSBrooks Davis sys_extattr_set_link(struct thread *td, struct extattr_set_link_args *uap)
2956f90723cSRobert Watson {
2960a2c60c3SBrooks Davis 
2976453d424SDmitry Chagin 	return (user_extattr_set_path(td, uap->path, uap->attrnamespace,
2980a2c60c3SBrooks Davis 	    uap->attrname, uap->data, uap->nbytes, NOFOLLOW));
2990a2c60c3SBrooks Davis }
3000a2c60c3SBrooks Davis 
3010a2c60c3SBrooks Davis static int
user_extattr_set_path(struct thread * td,const char * path,int attrnamespace,const char * uattrname,void * data,size_t nbytes,int follow)3026453d424SDmitry Chagin user_extattr_set_path(struct thread *td, const char *path, int attrnamespace,
3030a2c60c3SBrooks Davis     const char *uattrname, void *data, size_t nbytes, int follow)
3040a2c60c3SBrooks Davis {
305b21ae0ffSConrad Meyer 	char attrname[EXTATTR_MAXNAMELEN + 1];
3065050aa86SKonstantin Belousov 	int error;
3076f90723cSRobert Watson 
308b21ae0ffSConrad Meyer 	error = copyinstr(uattrname, attrname, sizeof(attrname), NULL);
3096f90723cSRobert Watson 	if (error)
3106f90723cSRobert Watson 		return (error);
3116453d424SDmitry Chagin 	return (kern_extattr_set_path(td, path, attrnamespace,
3126453d424SDmitry Chagin 	    attrname, data, nbytes, follow, UIO_USERSPACE));
3136453d424SDmitry Chagin }
3146453d424SDmitry Chagin 
3156453d424SDmitry Chagin int
kern_extattr_set_path(struct thread * td,const char * path,int attrnamespace,const char * attrname,void * data,size_t nbytes,int follow,enum uio_seg pathseg)3166453d424SDmitry Chagin kern_extattr_set_path(struct thread *td, const char *path, int attrnamespace,
3176453d424SDmitry Chagin     const char *attrname, void *data, size_t nbytes, int follow,
3186453d424SDmitry Chagin     enum uio_seg pathseg)
3196453d424SDmitry Chagin {
3206453d424SDmitry Chagin 	struct nameidata nd;
3216453d424SDmitry Chagin 	int error;
3226453d424SDmitry Chagin 
3236453d424SDmitry Chagin 	AUDIT_ARG_VALUE(attrnamespace);
32414961ba7SRobert Watson 	AUDIT_ARG_TEXT(attrname);
3256f90723cSRobert Watson 
3266453d424SDmitry Chagin 	NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path);
3272dba710dSRobert Watson 	error = namei(&nd);
3282dba710dSRobert Watson 	if (error)
3296f90723cSRobert Watson 		return (error);
330bb92cd7bSMateusz Guzik 	NDFREE_PNBUF(&nd);
3316f90723cSRobert Watson 
3320a2c60c3SBrooks Davis 	error = extattr_set_vp(nd.ni_vp, attrnamespace, attrname, data,
3330a2c60c3SBrooks Davis 	    nbytes, td);
3346f90723cSRobert Watson 
3356f90723cSRobert Watson 	vrele(nd.ni_vp);
3366f90723cSRobert Watson 	return (error);
3376f90723cSRobert Watson }
3386f90723cSRobert Watson 
3391a996ed1SEdward Tomasz Napierala /*-
34074237f55SRobert Watson  * Get a named extended attribute on a file or directory
341fec605c8SRobert Watson  *
342fec605c8SRobert Watson  * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
34374237f55SRobert Watson  *            kernelspace string pointer "attrname", userspace buffer
34474237f55SRobert Watson  *            pointer "data", buffer length "nbytes", thread "td".
345fec605c8SRobert Watson  * Returns: 0 on success, an error number otherwise
346fec605c8SRobert Watson  * Locks: none
347fec605c8SRobert Watson  * References: vp must be a valid reference for the duration of the call
34891f37dcbSRobert Watson  */
349fec605c8SRobert Watson static int
extattr_get_vp(struct vnode * vp,int attrnamespace,const char * attrname,void * data,size_t nbytes,struct thread * td)350fec605c8SRobert Watson extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
35174237f55SRobert Watson     void *data, size_t nbytes, struct thread *td)
352fec605c8SRobert Watson {
3537a0776e4SRobert Watson 	struct uio auio, *auiop;
35474237f55SRobert Watson 	struct iovec aiov;
35574237f55SRobert Watson 	ssize_t cnt;
3567a0776e4SRobert Watson 	size_t size, *sizep;
35774237f55SRobert Watson 	int error;
358fec605c8SRobert Watson 
35961b214f3SFedor Uporov 	if (nbytes > IOSIZE_MAX)
36061b214f3SFedor Uporov 		return (EINVAL);
36161b214f3SFedor Uporov 
362926cd204SMatthew D Fleming 	vn_lock(vp, LK_SHARED | LK_RETRY);
363fec605c8SRobert Watson 
36474237f55SRobert Watson 	/*
36574237f55SRobert Watson 	 * Slightly unusual semantics: if the user provides a NULL data
366afae6388SRobert Watson 	 * pointer, they don't want to receive the data, just the maximum
367afae6388SRobert Watson 	 * read length.
36874237f55SRobert Watson 	 */
3697a0776e4SRobert Watson 	auiop = NULL;
3707a0776e4SRobert Watson 	sizep = NULL;
3717a0776e4SRobert Watson 	cnt = 0;
37274237f55SRobert Watson 	if (data != NULL) {
37374237f55SRobert Watson 		aiov.iov_base = data;
37474237f55SRobert Watson 		aiov.iov_len = nbytes;
37574237f55SRobert Watson 		auio.uio_iov = &aiov;
3761209e08fSCraig Rodrigues 		auio.uio_iovcnt = 1;
37774237f55SRobert Watson 		auio.uio_offset = 0;
37874237f55SRobert Watson 		auio.uio_resid = nbytes;
379fec605c8SRobert Watson 		auio.uio_rw = UIO_READ;
380fec605c8SRobert Watson 		auio.uio_segflg = UIO_USERSPACE;
381b40ce416SJulian Elischer 		auio.uio_td = td;
3827a0776e4SRobert Watson 		auiop = &auio;
38374237f55SRobert Watson 		cnt = nbytes;
3844f3bf9b9SRobert Watson 	} else
3857a0776e4SRobert Watson 		sizep = &size;
3867a0776e4SRobert Watson 
387f4d2cfddSRobert Watson #ifdef MAC
38830d239bcSRobert Watson 	error = mac_vnode_check_getextattr(td->td_ucred, vp, attrnamespace,
389fefd0ac8SRobert Watson 	    attrname);
390f4d2cfddSRobert Watson 	if (error)
391f4d2cfddSRobert Watson 		goto done;
392f4d2cfddSRobert Watson #endif
393f4d2cfddSRobert Watson 
3947a0776e4SRobert Watson 	error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep,
3957a0776e4SRobert Watson 	    td->td_ucred, td);
3967a0776e4SRobert Watson 
3977a0776e4SRobert Watson 	if (auiop != NULL) {
398fec605c8SRobert Watson 		cnt -= auio.uio_resid;
399b40ce416SJulian Elischer 		td->td_retval[0] = cnt;
4004f3bf9b9SRobert Watson 	} else
40174237f55SRobert Watson 		td->td_retval[0] = size;
4024ba058c0SFedor Uporov #ifdef MAC
403fec605c8SRobert Watson done:
4044ba058c0SFedor Uporov #endif
405b249ce48SMateusz Guzik 	VOP_UNLOCK(vp);
406fec605c8SRobert Watson 	return (error);
407fec605c8SRobert Watson }
408fec605c8SRobert Watson 
40902bc058fSBrooks Davis #ifndef _SYS_SYSPROTO_H_
41002bc058fSBrooks Davis struct extattr_get_fd_args {
411b80521feSAlfred Perlstein 	int fd;
412b80521feSAlfred Perlstein 	int attrnamespace;
413b80521feSAlfred Perlstein 	const char *attrname;
414b80521feSAlfred Perlstein 	void *data;
415b80521feSAlfred Perlstein 	size_t nbytes;
41602bc058fSBrooks Davis };
41702bc058fSBrooks Davis #endif
41802bc058fSBrooks Davis int
sys_extattr_get_fd(struct thread * td,struct extattr_get_fd_args * uap)41902bc058fSBrooks Davis sys_extattr_get_fd(struct thread *td, struct extattr_get_fd_args *uap)
420b101411bSRobert Watson {
421b21ae0ffSConrad Meyer 	char attrname[EXTATTR_MAXNAMELEN + 1];
4225050aa86SKonstantin Belousov 	int error;
423b101411bSRobert Watson 
424b21ae0ffSConrad Meyer 	error = copyinstr(uap->attrname, attrname, sizeof(attrname), NULL);
425b101411bSRobert Watson 	if (error)
426b101411bSRobert Watson 		return (error);
4276453d424SDmitry Chagin 	return (kern_extattr_get_fd(td, uap->fd, uap->attrnamespace,
4286453d424SDmitry Chagin 	    attrname, uap->data, uap->nbytes));
4296453d424SDmitry Chagin }
4306453d424SDmitry Chagin 
4316453d424SDmitry Chagin int
kern_extattr_get_fd(struct thread * td,int fd,int attrnamespace,const char * attrname,void * data,size_t nbytes)4326453d424SDmitry Chagin kern_extattr_get_fd(struct thread *td, int fd, int attrnamespace,
4336453d424SDmitry Chagin     const char *attrname, void *data, size_t nbytes)
4346453d424SDmitry Chagin {
4356453d424SDmitry Chagin 	struct file *fp;
4366453d424SDmitry Chagin 	cap_rights_t rights;
4376453d424SDmitry Chagin 	int error;
4386453d424SDmitry Chagin 
4396453d424SDmitry Chagin 	AUDIT_ARG_FD(fd);
4406453d424SDmitry Chagin 	AUDIT_ARG_VALUE(attrnamespace);
44114961ba7SRobert Watson 	AUDIT_ARG_TEXT(attrname);
442b101411bSRobert Watson 
4436453d424SDmitry Chagin 	error = getvnode_path(td, fd,
444e126c5a3SMateusz Guzik 	    cap_rights_init_one(&rights, CAP_EXTATTR_GET), &fp);
4452dba710dSRobert Watson 	if (error)
446b101411bSRobert Watson 		return (error);
447b101411bSRobert Watson 
4486453d424SDmitry Chagin 	error = extattr_get_vp(fp->f_vnode, attrnamespace,
4496453d424SDmitry Chagin 	    attrname, data, nbytes, td);
450b101411bSRobert Watson 
451b101411bSRobert Watson 	fdrop(fp, td);
452b101411bSRobert Watson 	return (error);
453b101411bSRobert Watson }
454b101411bSRobert Watson 
45502bc058fSBrooks Davis #ifndef _SYS_SYSPROTO_H_
45602bc058fSBrooks Davis struct extattr_get_file_args {
457b80521feSAlfred Perlstein 	const char *path;
458b80521feSAlfred Perlstein 	int attrnamespace;
459b80521feSAlfred Perlstein 	const char *attrname;
460b80521feSAlfred Perlstein 	void *data;
461b80521feSAlfred Perlstein 	size_t nbytes;
46202bc058fSBrooks Davis };
46302bc058fSBrooks Davis #endif
46402bc058fSBrooks Davis int
sys_extattr_get_file(struct thread * td,struct extattr_get_file_args * uap)46502bc058fSBrooks Davis sys_extattr_get_file(struct thread *td, struct extattr_get_file_args *uap)
46691f37dcbSRobert Watson {
4676453d424SDmitry Chagin 	return (user_extattr_get_path(td, uap->path, uap->attrnamespace,
4680a2c60c3SBrooks Davis 	    uap->attrname, uap->data, uap->nbytes, FOLLOW));
46991f37dcbSRobert Watson }
470fec605c8SRobert Watson 
47102bc058fSBrooks Davis #ifndef _SYS_SYSPROTO_H_
47202bc058fSBrooks Davis struct extattr_get_link_args {
473b80521feSAlfred Perlstein 	const char *path;
474b80521feSAlfred Perlstein 	int attrnamespace;
475b80521feSAlfred Perlstein 	const char *attrname;
476b80521feSAlfred Perlstein 	void *data;
477b80521feSAlfred Perlstein 	size_t nbytes;
47802bc058fSBrooks Davis };
47902bc058fSBrooks Davis #endif
48002bc058fSBrooks Davis int
sys_extattr_get_link(struct thread * td,struct extattr_get_link_args * uap)48102bc058fSBrooks Davis sys_extattr_get_link(struct thread *td, struct extattr_get_link_args *uap)
4826f90723cSRobert Watson {
4836453d424SDmitry Chagin 	return (user_extattr_get_path(td, uap->path, uap->attrnamespace,
4840a2c60c3SBrooks Davis 	    uap->attrname, uap->data, uap->nbytes, NOFOLLOW));
4850a2c60c3SBrooks Davis }
4860a2c60c3SBrooks Davis 
4870a2c60c3SBrooks Davis static int
user_extattr_get_path(struct thread * td,const char * path,int attrnamespace,const char * uattrname,void * data,size_t nbytes,int follow)4886453d424SDmitry Chagin user_extattr_get_path(struct thread *td, const char *path, int attrnamespace,
4890a2c60c3SBrooks Davis     const char *uattrname, void *data, size_t nbytes, int follow)
4900a2c60c3SBrooks Davis {
491b21ae0ffSConrad Meyer 	char attrname[EXTATTR_MAXNAMELEN + 1];
4925050aa86SKonstantin Belousov 	int error;
4936f90723cSRobert Watson 
494b21ae0ffSConrad Meyer 	error = copyinstr(uattrname, attrname, sizeof(attrname), NULL);
4956f90723cSRobert Watson 	if (error)
4966f90723cSRobert Watson 		return (error);
4976453d424SDmitry Chagin 	return (kern_extattr_get_path(td, path, attrnamespace,
4986453d424SDmitry Chagin 	    attrname, data, nbytes, follow, UIO_USERSPACE));
4996453d424SDmitry Chagin }
5006453d424SDmitry Chagin 
5016453d424SDmitry Chagin int
kern_extattr_get_path(struct thread * td,const char * path,int attrnamespace,const char * attrname,void * data,size_t nbytes,int follow,enum uio_seg pathseg)5026453d424SDmitry Chagin kern_extattr_get_path(struct thread *td, const char *path, int attrnamespace,
5036453d424SDmitry Chagin     const char *attrname, void *data, size_t nbytes, int follow,
5046453d424SDmitry Chagin     enum uio_seg pathseg)
5056453d424SDmitry Chagin {
5066453d424SDmitry Chagin 	struct nameidata nd;
5076453d424SDmitry Chagin 	int error;
5086453d424SDmitry Chagin 
5096453d424SDmitry Chagin 	AUDIT_ARG_VALUE(attrnamespace);
51014961ba7SRobert Watson 	AUDIT_ARG_TEXT(attrname);
5116f90723cSRobert Watson 
5126453d424SDmitry Chagin 	NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path);
5132dba710dSRobert Watson 	error = namei(&nd);
5142dba710dSRobert Watson 	if (error)
5156f90723cSRobert Watson 		return (error);
516bb92cd7bSMateusz Guzik 	NDFREE_PNBUF(&nd);
5176f90723cSRobert Watson 
5180a2c60c3SBrooks Davis 	error = extattr_get_vp(nd.ni_vp, attrnamespace, attrname, data,
5190a2c60c3SBrooks Davis 	    nbytes, td);
5206f90723cSRobert Watson 
5216f90723cSRobert Watson 	vrele(nd.ni_vp);
5226f90723cSRobert Watson 	return (error);
5236f90723cSRobert Watson }
5246f90723cSRobert Watson 
52591f37dcbSRobert Watson /*
526fec605c8SRobert Watson  * extattr_delete_vp(): Delete a named extended attribute on a file or
527fec605c8SRobert Watson  *                      directory
528fec605c8SRobert Watson  *
529fec605c8SRobert Watson  * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
530fec605c8SRobert Watson  *            kernelspace string pointer "attrname", proc "p"
531fec605c8SRobert Watson  * Returns: 0 on success, an error number otherwise
532fec605c8SRobert Watson  * Locks: none
533fec605c8SRobert Watson  * References: vp must be a valid reference for the duration of the call
53491f37dcbSRobert Watson  */
535fec605c8SRobert Watson static int
extattr_delete_vp(struct vnode * vp,int attrnamespace,const char * attrname,struct thread * td)536fec605c8SRobert Watson extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
537b40ce416SJulian Elischer     struct thread *td)
538fec605c8SRobert Watson {
539fec605c8SRobert Watson 	struct mount *mp;
540fec605c8SRobert Watson 	int error;
541fec605c8SRobert Watson 
542a75d1dddSMateusz Guzik 	error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH);
5432dba710dSRobert Watson 	if (error)
544fec605c8SRobert Watson 		return (error);
545cb05b60aSAttilio Rao 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
546fec605c8SRobert Watson 
547f4d2cfddSRobert Watson #ifdef MAC
54830d239bcSRobert Watson 	error = mac_vnode_check_deleteextattr(td->td_ucred, vp, attrnamespace,
549c096756cSRobert Watson 	    attrname);
5502dba710dSRobert Watson 	if (error)
5512dba710dSRobert Watson 		goto done;
552f4d2cfddSRobert Watson #endif
553f4d2cfddSRobert Watson 
5549080ff25SRobert Watson 	error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, td->td_ucred,
5559080ff25SRobert Watson 	    td);
5566b42f0a2SRobert Watson 	if (error == EOPNOTSUPP)
5576b42f0a2SRobert Watson 		error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
5586b42f0a2SRobert Watson 		    td->td_ucred, td);
5592dba710dSRobert Watson #ifdef MAC
5602dba710dSRobert Watson done:
5612dba710dSRobert Watson #endif
562b249ce48SMateusz Guzik 	VOP_UNLOCK(vp);
563fec605c8SRobert Watson 	vn_finished_write(mp);
564fec605c8SRobert Watson 	return (error);
565fec605c8SRobert Watson }
566fec605c8SRobert Watson 
56702bc058fSBrooks Davis #ifndef _SYS_SYSPROTO_H_
56802bc058fSBrooks Davis struct extattr_delete_fd_args {
569b80521feSAlfred Perlstein 	int fd;
570b80521feSAlfred Perlstein 	int attrnamespace;
571b80521feSAlfred Perlstein 	const char *attrname;
57202bc058fSBrooks Davis };
57302bc058fSBrooks Davis #endif
57402bc058fSBrooks Davis int
sys_extattr_delete_fd(struct thread * td,struct extattr_delete_fd_args * uap)57502bc058fSBrooks Davis sys_extattr_delete_fd(struct thread *td, struct extattr_delete_fd_args *uap)
576fec605c8SRobert Watson {
577b21ae0ffSConrad Meyer 	char attrname[EXTATTR_MAXNAMELEN + 1];
5785050aa86SKonstantin Belousov 	int error;
579fec605c8SRobert Watson 
580b21ae0ffSConrad Meyer 	error = copyinstr(uap->attrname, attrname, sizeof(attrname), NULL);
581fec605c8SRobert Watson 	if (error)
582fec605c8SRobert Watson 		return (error);
5836453d424SDmitry Chagin 	return (kern_extattr_delete_fd(td, uap->fd, uap->attrnamespace,
5846453d424SDmitry Chagin 	    attrname));
5856453d424SDmitry Chagin }
5866453d424SDmitry Chagin 
5876453d424SDmitry Chagin int
kern_extattr_delete_fd(struct thread * td,int fd,int attrnamespace,const char * attrname)5886453d424SDmitry Chagin kern_extattr_delete_fd(struct thread *td, int fd, int attrnamespace,
5896453d424SDmitry Chagin     const char *attrname)
5906453d424SDmitry Chagin {
5916453d424SDmitry Chagin 	struct file *fp;
5926453d424SDmitry Chagin 	cap_rights_t rights;
5936453d424SDmitry Chagin 	int error;
5946453d424SDmitry Chagin 
5956453d424SDmitry Chagin 	AUDIT_ARG_FD(fd);
5966453d424SDmitry Chagin 	AUDIT_ARG_VALUE(attrnamespace);
59714961ba7SRobert Watson 	AUDIT_ARG_TEXT(attrname);
598fec605c8SRobert Watson 
5996453d424SDmitry Chagin 	error = getvnode_path(td, fd,
600e126c5a3SMateusz Guzik 	    cap_rights_init_one(&rights, CAP_EXTATTR_DELETE), &fp);
6012dba710dSRobert Watson 	if (error)
602fec605c8SRobert Watson 		return (error);
603fec605c8SRobert Watson 
6046453d424SDmitry Chagin 	error = extattr_delete_vp(fp->f_vnode, attrnamespace,
605c47a4d1cSChristian S.J. Peron 	    attrname, td);
606426da3bcSAlfred Perlstein 	fdrop(fp, td);
60791f37dcbSRobert Watson 	return (error);
60891f37dcbSRobert Watson }
6096f90723cSRobert Watson 
61002bc058fSBrooks Davis #ifndef _SYS_SYSPROTO_H_
61102bc058fSBrooks Davis struct extattr_delete_file_args {
612b80521feSAlfred Perlstein 	const char *path;
613b80521feSAlfred Perlstein 	int attrnamespace;
614b80521feSAlfred Perlstein 	const char *attrname;
61502bc058fSBrooks Davis };
61602bc058fSBrooks Davis #endif
61702bc058fSBrooks Davis int
sys_extattr_delete_file(struct thread * td,struct extattr_delete_file_args * uap)61802bc058fSBrooks Davis sys_extattr_delete_file(struct thread *td, struct extattr_delete_file_args *uap)
619b101411bSRobert Watson {
620b101411bSRobert Watson 
6216453d424SDmitry Chagin 	return (user_extattr_delete_path(td, uap->path, uap->attrnamespace,
6220a2c60c3SBrooks Davis 	    uap->attrname, FOLLOW));
623b101411bSRobert Watson }
624b101411bSRobert Watson 
62502bc058fSBrooks Davis #ifndef _SYS_SYSPROTO_H_
62602bc058fSBrooks Davis struct extattr_delete_link_args {
627b80521feSAlfred Perlstein 	const char *path;
628b80521feSAlfred Perlstein 	int attrnamespace;
629b80521feSAlfred Perlstein 	const char *attrname;
63002bc058fSBrooks Davis };
63102bc058fSBrooks Davis #endif
63202bc058fSBrooks Davis int
sys_extattr_delete_link(struct thread * td,struct extattr_delete_link_args * uap)63302bc058fSBrooks Davis sys_extattr_delete_link(struct thread *td, struct extattr_delete_link_args *uap)
6346f90723cSRobert Watson {
6350a2c60c3SBrooks Davis 
6366453d424SDmitry Chagin 	return (user_extattr_delete_path(td, uap->path, uap->attrnamespace,
6370a2c60c3SBrooks Davis 	    uap->attrname, NOFOLLOW));
6380a2c60c3SBrooks Davis }
6390a2c60c3SBrooks Davis 
6406453d424SDmitry Chagin int
user_extattr_delete_path(struct thread * td,const char * path,int attrnamespace,const char * uattrname,int follow)6416453d424SDmitry Chagin user_extattr_delete_path(struct thread *td, const char *path, int attrnamespace,
6420a2c60c3SBrooks Davis     const char *uattrname, int follow)
6430a2c60c3SBrooks Davis {
644b21ae0ffSConrad Meyer 	char attrname[EXTATTR_MAXNAMELEN + 1];
6455050aa86SKonstantin Belousov 	int error;
6466f90723cSRobert Watson 
647b21ae0ffSConrad Meyer 	error = copyinstr(uattrname, attrname, sizeof(attrname), NULL);
6486f90723cSRobert Watson 	if (error)
6496f90723cSRobert Watson 		return(error);
6506453d424SDmitry Chagin 	return (kern_extattr_delete_path(td, path, attrnamespace,
6516453d424SDmitry Chagin 	    attrname, follow, UIO_USERSPACE));
6526453d424SDmitry Chagin }
6536453d424SDmitry Chagin 
6546453d424SDmitry Chagin int
kern_extattr_delete_path(struct thread * td,const char * path,int attrnamespace,const char * attrname,int follow,enum uio_seg pathseg)6556453d424SDmitry Chagin kern_extattr_delete_path(struct thread *td, const char *path, int attrnamespace,
6566453d424SDmitry Chagin     const char *attrname, int follow, enum uio_seg pathseg)
6576453d424SDmitry Chagin {
6586453d424SDmitry Chagin 	struct nameidata nd;
6596453d424SDmitry Chagin 	int error;
6606453d424SDmitry Chagin 
6616453d424SDmitry Chagin 	AUDIT_ARG_VALUE(attrnamespace);
66214961ba7SRobert Watson 	AUDIT_ARG_TEXT(attrname);
6636f90723cSRobert Watson 
6646453d424SDmitry Chagin 	NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path);
6652dba710dSRobert Watson 	error = namei(&nd);
6662dba710dSRobert Watson 	if (error)
6676f90723cSRobert Watson 		return(error);
668bb92cd7bSMateusz Guzik 	NDFREE_PNBUF(&nd);
6696f90723cSRobert Watson 
6700a2c60c3SBrooks Davis 	error = extattr_delete_vp(nd.ni_vp, attrnamespace, attrname, td);
6716f90723cSRobert Watson 	vrele(nd.ni_vp);
6726f90723cSRobert Watson 	return(error);
6736f90723cSRobert Watson }
6748bebbb1aSRobert Watson 
6751a996ed1SEdward Tomasz Napierala /*-
6768bebbb1aSRobert Watson  * Retrieve a list of extended attributes on a file or directory.
6778bebbb1aSRobert Watson  *
6788bebbb1aSRobert Watson  * Arguments: unlocked vnode "vp", attribute namespace 'attrnamespace",
6798bebbb1aSRobert Watson  *            userspace buffer pointer "data", buffer length "nbytes",
6808bebbb1aSRobert Watson  *            thread "td".
6818bebbb1aSRobert Watson  * Returns: 0 on success, an error number otherwise
6828bebbb1aSRobert Watson  * Locks: none
6838bebbb1aSRobert Watson  * References: vp must be a valid reference for the duration of the call
6848bebbb1aSRobert Watson  */
6858bebbb1aSRobert Watson static int
extattr_list_vp(struct vnode * vp,int attrnamespace,struct uio * auiop,struct thread * td)6866453d424SDmitry Chagin extattr_list_vp(struct vnode *vp, int attrnamespace, struct uio *auiop,
6876453d424SDmitry Chagin     struct thread *td)
6888bebbb1aSRobert Watson {
6898bebbb1aSRobert Watson 	size_t size, *sizep;
6908bebbb1aSRobert Watson 	ssize_t cnt;
6918bebbb1aSRobert Watson 	int error;
6928bebbb1aSRobert Watson 
6938bebbb1aSRobert Watson 	sizep = NULL;
6948bebbb1aSRobert Watson 	cnt = 0;
6956453d424SDmitry Chagin 	if (auiop != NULL) {
6966453d424SDmitry Chagin 		if (auiop->uio_resid > IOSIZE_MAX)
6976453d424SDmitry Chagin 			return (EINVAL);
6986453d424SDmitry Chagin 		cnt = auiop->uio_resid;
6994f3bf9b9SRobert Watson 	} else
7008bebbb1aSRobert Watson 		sizep = &size;
7018bebbb1aSRobert Watson 
702e682df53SConrad Meyer 	vn_lock(vp, LK_SHARED | LK_RETRY);
703e682df53SConrad Meyer 
7048bebbb1aSRobert Watson #ifdef MAC
70530d239bcSRobert Watson 	error = mac_vnode_check_listextattr(td->td_ucred, vp, attrnamespace);
706e682df53SConrad Meyer 	if (error) {
707b249ce48SMateusz Guzik 		VOP_UNLOCK(vp);
708e682df53SConrad Meyer 		return (error);
709e682df53SConrad Meyer 	}
7108bebbb1aSRobert Watson #endif
7118bebbb1aSRobert Watson 
71277762179SRobert Watson 	error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep,
7138bebbb1aSRobert Watson 	    td->td_ucred, td);
714b249ce48SMateusz Guzik 	VOP_UNLOCK(vp);
7158bebbb1aSRobert Watson 
7168bebbb1aSRobert Watson 	if (auiop != NULL) {
7176453d424SDmitry Chagin 		cnt -= auiop->uio_resid;
7188bebbb1aSRobert Watson 		td->td_retval[0] = cnt;
7194f3bf9b9SRobert Watson 	} else
7208bebbb1aSRobert Watson 		td->td_retval[0] = size;
7218bebbb1aSRobert Watson 	return (error);
7228bebbb1aSRobert Watson }
7238bebbb1aSRobert Watson 
72402bc058fSBrooks Davis #ifndef _SYS_SYSPROTO_H_
72502bc058fSBrooks Davis struct extattr_list_fd_args {
7268bebbb1aSRobert Watson 	int fd;
7278bebbb1aSRobert Watson 	int attrnamespace;
7288bebbb1aSRobert Watson 	void *data;
7298bebbb1aSRobert Watson 	size_t nbytes;
73002bc058fSBrooks Davis };
73102bc058fSBrooks Davis #endif
73202bc058fSBrooks Davis int
sys_extattr_list_fd(struct thread * td,struct extattr_list_fd_args * uap)73302bc058fSBrooks Davis sys_extattr_list_fd(struct thread *td, struct extattr_list_fd_args *uap)
7348bebbb1aSRobert Watson {
7356453d424SDmitry Chagin 	struct uio auio, *auiop;
7366453d424SDmitry Chagin 	struct iovec aiov;
7376453d424SDmitry Chagin 
7386453d424SDmitry Chagin 	if (uap->data != NULL) {
7396453d424SDmitry Chagin 		aiov.iov_base = uap->data;
7406453d424SDmitry Chagin 		aiov.iov_len = uap->nbytes;
7416453d424SDmitry Chagin 		auio.uio_iov = &aiov;
7426453d424SDmitry Chagin 		auio.uio_iovcnt = 1;
7436453d424SDmitry Chagin 		auio.uio_offset = 0;
7446453d424SDmitry Chagin 		auio.uio_resid = uap->nbytes;
7456453d424SDmitry Chagin 		auio.uio_rw = UIO_READ;
7466453d424SDmitry Chagin 		auio.uio_segflg = UIO_USERSPACE;
7476453d424SDmitry Chagin 		auio.uio_td = td;
7486453d424SDmitry Chagin 		auiop = &auio;
7496453d424SDmitry Chagin 	} else
7506453d424SDmitry Chagin 		auiop = NULL;
7516453d424SDmitry Chagin 
7526453d424SDmitry Chagin 	return (kern_extattr_list_fd(td, uap->fd, uap->attrnamespace,
7536453d424SDmitry Chagin 	    auiop));
7546453d424SDmitry Chagin }
7556453d424SDmitry Chagin 
7566453d424SDmitry Chagin int
kern_extattr_list_fd(struct thread * td,int fd,int attrnamespace,struct uio * auiop)7576453d424SDmitry Chagin kern_extattr_list_fd(struct thread *td, int fd, int attrnamespace,
7586453d424SDmitry Chagin     struct uio *auiop)
7596453d424SDmitry Chagin {
7608bebbb1aSRobert Watson 	struct file *fp;
7617008be5bSPawel Jakub Dawidek 	cap_rights_t rights;
7625050aa86SKonstantin Belousov 	int error;
7638bebbb1aSRobert Watson 
7646453d424SDmitry Chagin 	AUDIT_ARG_FD(fd);
7656453d424SDmitry Chagin 	AUDIT_ARG_VALUE(attrnamespace);
7666453d424SDmitry Chagin 	error = getvnode_path(td, fd,
767e126c5a3SMateusz Guzik 	    cap_rights_init_one(&rights, CAP_EXTATTR_LIST), &fp);
7688bebbb1aSRobert Watson 	if (error)
7698bebbb1aSRobert Watson 		return (error);
7708bebbb1aSRobert Watson 
7716453d424SDmitry Chagin 	error = extattr_list_vp(fp->f_vnode, attrnamespace, auiop, td);
7728bebbb1aSRobert Watson 
7738bebbb1aSRobert Watson 	fdrop(fp, td);
7748bebbb1aSRobert Watson 	return (error);
7758bebbb1aSRobert Watson }
7768bebbb1aSRobert Watson 
77702bc058fSBrooks Davis #ifndef _SYS_SYSPROTO_H_
77802bc058fSBrooks Davis struct extattr_list_file_args {
7798bebbb1aSRobert Watson 	const char *path;
7808bebbb1aSRobert Watson 	int attrnamespace;
7818bebbb1aSRobert Watson 	void *data;
7828bebbb1aSRobert Watson 	size_t nbytes;
78302bc058fSBrooks Davis }
78402bc058fSBrooks Davis #endif
78502bc058fSBrooks Davis int
sys_extattr_list_file(struct thread * td,struct extattr_list_file_args * uap)78602bc058fSBrooks Davis sys_extattr_list_file(struct thread *td, struct extattr_list_file_args *uap)
7878bebbb1aSRobert Watson {
7888bebbb1aSRobert Watson 
7896453d424SDmitry Chagin 	return (user_extattr_list_path(td, uap->path, uap->attrnamespace,
7900a2c60c3SBrooks Davis 	    uap->data, uap->nbytes, FOLLOW));
7918bebbb1aSRobert Watson }
7928bebbb1aSRobert Watson 
79302bc058fSBrooks Davis #ifndef _SYS_SYSPROTO_H_
79402bc058fSBrooks Davis struct extattr_list_link_args {
7958bebbb1aSRobert Watson 	const char *path;
7968bebbb1aSRobert Watson 	int attrnamespace;
7978bebbb1aSRobert Watson 	void *data;
7988bebbb1aSRobert Watson 	size_t nbytes;
79902bc058fSBrooks Davis };
80002bc058fSBrooks Davis #endif
80102bc058fSBrooks Davis int
sys_extattr_list_link(struct thread * td,struct extattr_list_link_args * uap)80202bc058fSBrooks Davis sys_extattr_list_link(struct thread *td, struct extattr_list_link_args *uap)
8038bebbb1aSRobert Watson {
8040a2c60c3SBrooks Davis 
8056453d424SDmitry Chagin 	return (user_extattr_list_path(td, uap->path, uap->attrnamespace,
8060a2c60c3SBrooks Davis 	    uap->data, uap->nbytes, NOFOLLOW));
8070a2c60c3SBrooks Davis }
8080a2c60c3SBrooks Davis 
8090a2c60c3SBrooks Davis static int
user_extattr_list_path(struct thread * td,const char * path,int attrnamespace,void * data,size_t nbytes,int follow)8106453d424SDmitry Chagin user_extattr_list_path(struct thread *td, const char *path, int attrnamespace,
8110a2c60c3SBrooks Davis     void *data, size_t nbytes, int follow)
8120a2c60c3SBrooks Davis {
8136453d424SDmitry Chagin 	struct uio auio, *auiop;
8146453d424SDmitry Chagin 	struct iovec aiov;
8156453d424SDmitry Chagin 
8166453d424SDmitry Chagin 	if (data != NULL) {
8176453d424SDmitry Chagin 		aiov.iov_base = data;
8186453d424SDmitry Chagin 		aiov.iov_len = nbytes;
8196453d424SDmitry Chagin 		auio.uio_iov = &aiov;
8206453d424SDmitry Chagin 		auio.uio_iovcnt = 1;
8216453d424SDmitry Chagin 		auio.uio_offset = 0;
8226453d424SDmitry Chagin 		auio.uio_resid = nbytes;
8236453d424SDmitry Chagin 		auio.uio_rw = UIO_READ;
8246453d424SDmitry Chagin 		auio.uio_segflg = UIO_USERSPACE;
8256453d424SDmitry Chagin 		auio.uio_td = td;
8266453d424SDmitry Chagin 		auiop = &auio;
8276453d424SDmitry Chagin 	} else
8286453d424SDmitry Chagin 		auiop = NULL;
8296453d424SDmitry Chagin 
8306453d424SDmitry Chagin 	return (kern_extattr_list_path(td, path, attrnamespace,
8316453d424SDmitry Chagin 	    auiop, follow, UIO_USERSPACE));
8326453d424SDmitry Chagin }
8336453d424SDmitry Chagin 
8346453d424SDmitry Chagin int
kern_extattr_list_path(struct thread * td,const char * path,int attrnamespace,struct uio * auiop,int follow,enum uio_seg pathseg)8356453d424SDmitry Chagin kern_extattr_list_path(struct thread *td, const char *path, int attrnamespace,
8366453d424SDmitry Chagin     struct uio *auiop, int follow, enum uio_seg pathseg)
8376453d424SDmitry Chagin {
8388bebbb1aSRobert Watson 	struct nameidata nd;
8395050aa86SKonstantin Belousov 	int error;
8408bebbb1aSRobert Watson 
8410a2c60c3SBrooks Davis 	AUDIT_ARG_VALUE(attrnamespace);
8426453d424SDmitry Chagin 	NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path);
8438bebbb1aSRobert Watson 	error = namei(&nd);
8448bebbb1aSRobert Watson 	if (error)
8458bebbb1aSRobert Watson 		return (error);
846bb92cd7bSMateusz Guzik 	NDFREE_PNBUF(&nd);
8478bebbb1aSRobert Watson 
8486453d424SDmitry Chagin 	error = extattr_list_vp(nd.ni_vp, attrnamespace, auiop, td);
8498bebbb1aSRobert Watson 
8508bebbb1aSRobert Watson 	vrele(nd.ni_vp);
8518bebbb1aSRobert Watson 	return (error);
8528bebbb1aSRobert Watson }
853