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