xref: /freebsd-11-stable/sys/kern/vfs_extattr.c (revision 4fc6dddb6d2c0d60f16d06965254bc57bef02895)
1 /*-
2  * Copyright (c) 1999-2001 Robert N. M. Watson
3  * All rights reserved.
4  *
5  * This software was developed by Robert Watson for the TrustedBSD Project.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/capsicum.h>
35 #include <sys/lock.h>
36 #include <sys/mount.h>
37 #include <sys/mutex.h>
38 #include <sys/sysproto.h>
39 #include <sys/fcntl.h>
40 #include <sys/namei.h>
41 #include <sys/filedesc.h>
42 #include <sys/limits.h>
43 #include <sys/vnode.h>
44 #include <sys/proc.h>
45 #include <sys/extattr.h>
46 
47 #include <security/audit/audit.h>
48 #include <security/mac/mac_framework.h>
49 
50 /*
51  * Syscall to push extended attribute configuration information into the VFS.
52  * Accepts a path, which it converts to a mountpoint, as well as a command
53  * (int cmd), and attribute name and misc data.
54  *
55  * Currently this is used only by UFS1 extended attributes.
56  */
57 int
sys_extattrctl(td,uap)58 sys_extattrctl(td, uap)
59 	struct thread *td;
60 	struct extattrctl_args /* {
61 		const char *path;
62 		int cmd;
63 		const char *filename;
64 		int attrnamespace;
65 		const char *attrname;
66 	} */ *uap;
67 {
68 	struct vnode *filename_vp;
69 	struct nameidata nd;
70 	struct mount *mp, *mp_writable;
71 	char attrname[EXTATTR_MAXNAMELEN];
72 	int error;
73 
74 	AUDIT_ARG_CMD(uap->cmd);
75 	AUDIT_ARG_VALUE(uap->attrnamespace);
76 	/*
77 	 * uap->attrname is not always defined.  We check again later when we
78 	 * invoke the VFS call so as to pass in NULL there if needed.
79 	 */
80 	if (uap->attrname != NULL) {
81 		error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN,
82 		    NULL);
83 		if (error)
84 			return (error);
85 	}
86 	AUDIT_ARG_TEXT(attrname);
87 
88 	mp = NULL;
89 	filename_vp = NULL;
90 	if (uap->filename != NULL) {
91 		NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE2,
92 		    UIO_USERSPACE, uap->filename, td);
93 		error = namei(&nd);
94 		if (error)
95 			return (error);
96 		filename_vp = nd.ni_vp;
97 		NDFREE(&nd, NDF_NO_VP_RELE);
98 	}
99 
100 	/* uap->path is always defined. */
101 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1,
102 	    UIO_USERSPACE, uap->path, td);
103 	error = namei(&nd);
104 	if (error)
105 		goto out;
106 	mp = nd.ni_vp->v_mount;
107 	error = vfs_busy(mp, 0);
108 	if (error) {
109 		NDFREE(&nd, 0);
110 		mp = NULL;
111 		goto out;
112 	}
113 	VOP_UNLOCK(nd.ni_vp, 0);
114 	error = vn_start_write(nd.ni_vp, &mp_writable, V_WAIT | PCATCH);
115 	NDFREE(&nd, NDF_NO_VP_UNLOCK);
116 	if (error)
117 		goto out;
118 	if (filename_vp != NULL) {
119 		/*
120 		 * uap->filename is not always defined.  If it is,
121 		 * grab a vnode lock, which VFS_EXTATTRCTL() will
122 		 * later release.
123 		 */
124 		error = vn_lock(filename_vp, LK_EXCLUSIVE);
125 		if (error) {
126 			vn_finished_write(mp_writable);
127 			goto out;
128 		}
129 	}
130 
131 	error = VFS_EXTATTRCTL(mp, uap->cmd, filename_vp, uap->attrnamespace,
132 	    uap->attrname != NULL ? attrname : NULL);
133 
134 	vn_finished_write(mp_writable);
135 out:
136 	if (mp != NULL)
137 		vfs_unbusy(mp);
138 
139 	/*
140 	 * VFS_EXTATTRCTL will have unlocked, but not de-ref'd, filename_vp,
141 	 * so vrele it if it is defined.
142 	 */
143 	if (filename_vp != NULL)
144 		vrele(filename_vp);
145 	return (error);
146 }
147 
148 /*-
149  * Set a named extended attribute on a file or directory
150  *
151  * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
152  *            kernelspace string pointer "attrname", userspace buffer
153  *            pointer "data", buffer length "nbytes", thread "td".
154  * Returns: 0 on success, an error number otherwise
155  * Locks: none
156  * References: vp must be a valid reference for the duration of the call
157  */
158 static int
extattr_set_vp(struct vnode * vp,int attrnamespace,const char * attrname,void * data,size_t nbytes,struct thread * td)159 extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
160     void *data, size_t nbytes, struct thread *td)
161 {
162 	struct mount *mp;
163 	struct uio auio;
164 	struct iovec aiov;
165 	ssize_t cnt;
166 	int error;
167 
168 	if (nbytes > IOSIZE_MAX)
169 		return (EINVAL);
170 
171 	error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
172 	if (error)
173 		return (error);
174 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
175 
176 	aiov.iov_base = data;
177 	aiov.iov_len = nbytes;
178 	auio.uio_iov = &aiov;
179 	auio.uio_iovcnt = 1;
180 	auio.uio_offset = 0;
181 	auio.uio_resid = nbytes;
182 	auio.uio_rw = UIO_WRITE;
183 	auio.uio_segflg = UIO_USERSPACE;
184 	auio.uio_td = td;
185 	cnt = nbytes;
186 
187 #ifdef MAC
188 	error = mac_vnode_check_setextattr(td->td_ucred, vp, attrnamespace,
189 	    attrname);
190 	if (error)
191 		goto done;
192 #endif
193 
194 	error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
195 	    td->td_ucred, td);
196 	cnt -= auio.uio_resid;
197 	td->td_retval[0] = cnt;
198 
199 #ifdef MAC
200 done:
201 #endif
202 	VOP_UNLOCK(vp, 0);
203 	vn_finished_write(mp);
204 	return (error);
205 }
206 
207 int
sys_extattr_set_fd(td,uap)208 sys_extattr_set_fd(td, uap)
209 	struct thread *td;
210 	struct extattr_set_fd_args /* {
211 		int fd;
212 		int attrnamespace;
213 		const char *attrname;
214 		void *data;
215 		size_t nbytes;
216 	} */ *uap;
217 {
218 	struct file *fp;
219 	char attrname[EXTATTR_MAXNAMELEN];
220 	cap_rights_t rights;
221 	int error;
222 
223 	AUDIT_ARG_FD(uap->fd);
224 	AUDIT_ARG_VALUE(uap->attrnamespace);
225 	error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
226 	if (error)
227 		return (error);
228 	AUDIT_ARG_TEXT(attrname);
229 
230 	error = getvnode(td, uap->fd,
231 	    cap_rights_init(&rights, CAP_EXTATTR_SET), &fp);
232 	if (error)
233 		return (error);
234 
235 	error = extattr_set_vp(fp->f_vnode, uap->attrnamespace,
236 	    attrname, uap->data, uap->nbytes, td);
237 	fdrop(fp, td);
238 
239 	return (error);
240 }
241 
242 int
sys_extattr_set_file(td,uap)243 sys_extattr_set_file(td, uap)
244 	struct thread *td;
245 	struct extattr_set_file_args /* {
246 		const char *path;
247 		int attrnamespace;
248 		const char *attrname;
249 		void *data;
250 		size_t nbytes;
251 	} */ *uap;
252 {
253 	struct nameidata nd;
254 	char attrname[EXTATTR_MAXNAMELEN];
255 	int error;
256 
257 	AUDIT_ARG_VALUE(uap->attrnamespace);
258 	error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
259 	if (error)
260 		return (error);
261 	AUDIT_ARG_TEXT(attrname);
262 
263 	NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE,
264 	    uap->path, td);
265 	error = namei(&nd);
266 	if (error)
267 		return (error);
268 	NDFREE(&nd, NDF_ONLY_PNBUF);
269 
270 	error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname,
271 	    uap->data, uap->nbytes, td);
272 
273 	vrele(nd.ni_vp);
274 	return (error);
275 }
276 
277 int
sys_extattr_set_link(td,uap)278 sys_extattr_set_link(td, uap)
279 	struct thread *td;
280 	struct extattr_set_link_args /* {
281 		const char *path;
282 		int attrnamespace;
283 		const char *attrname;
284 		void *data;
285 		size_t nbytes;
286 	} */ *uap;
287 {
288 	struct nameidata nd;
289 	char attrname[EXTATTR_MAXNAMELEN];
290 	int error;
291 
292 	AUDIT_ARG_VALUE(uap->attrnamespace);
293 	error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
294 	if (error)
295 		return (error);
296 	AUDIT_ARG_TEXT(attrname);
297 
298 	NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE,
299 	    uap->path, td);
300 	error = namei(&nd);
301 	if (error)
302 		return (error);
303 	NDFREE(&nd, NDF_ONLY_PNBUF);
304 
305 	error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname,
306 	    uap->data, uap->nbytes, td);
307 
308 	vrele(nd.ni_vp);
309 	return (error);
310 }
311 
312 /*-
313  * Get a named extended attribute on a file or directory
314  *
315  * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
316  *            kernelspace string pointer "attrname", userspace buffer
317  *            pointer "data", buffer length "nbytes", thread "td".
318  * Returns: 0 on success, an error number otherwise
319  * Locks: none
320  * References: vp must be a valid reference for the duration of the call
321  */
322 static int
extattr_get_vp(struct vnode * vp,int attrnamespace,const char * attrname,void * data,size_t nbytes,struct thread * td)323 extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
324     void *data, size_t nbytes, struct thread *td)
325 {
326 	struct uio auio, *auiop;
327 	struct iovec aiov;
328 	ssize_t cnt;
329 	size_t size, *sizep;
330 	int error;
331 
332 	if (nbytes > IOSIZE_MAX)
333 		return (EINVAL);
334 
335 	vn_lock(vp, LK_SHARED | LK_RETRY);
336 
337 	/*
338 	 * Slightly unusual semantics: if the user provides a NULL data
339 	 * pointer, they don't want to receive the data, just the maximum
340 	 * read length.
341 	 */
342 	auiop = NULL;
343 	sizep = NULL;
344 	cnt = 0;
345 	if (data != NULL) {
346 		aiov.iov_base = data;
347 		aiov.iov_len = nbytes;
348 		auio.uio_iov = &aiov;
349 		auio.uio_iovcnt = 1;
350 		auio.uio_offset = 0;
351 		auio.uio_resid = nbytes;
352 		auio.uio_rw = UIO_READ;
353 		auio.uio_segflg = UIO_USERSPACE;
354 		auio.uio_td = td;
355 		auiop = &auio;
356 		cnt = nbytes;
357 	} else
358 		sizep = &size;
359 
360 #ifdef MAC
361 	error = mac_vnode_check_getextattr(td->td_ucred, vp, attrnamespace,
362 	    attrname);
363 	if (error)
364 		goto done;
365 #endif
366 
367 	error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep,
368 	    td->td_ucred, td);
369 
370 	if (auiop != NULL) {
371 		cnt -= auio.uio_resid;
372 		td->td_retval[0] = cnt;
373 	} else
374 		td->td_retval[0] = size;
375 #ifdef MAC
376 done:
377 #endif
378 	VOP_UNLOCK(vp, 0);
379 	return (error);
380 }
381 
382 int
sys_extattr_get_fd(td,uap)383 sys_extattr_get_fd(td, uap)
384 	struct thread *td;
385 	struct extattr_get_fd_args /* {
386 		int fd;
387 		int attrnamespace;
388 		const char *attrname;
389 		void *data;
390 		size_t nbytes;
391 	} */ *uap;
392 {
393 	struct file *fp;
394 	char attrname[EXTATTR_MAXNAMELEN];
395 	cap_rights_t rights;
396 	int error;
397 
398 	AUDIT_ARG_FD(uap->fd);
399 	AUDIT_ARG_VALUE(uap->attrnamespace);
400 	error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
401 	if (error)
402 		return (error);
403 	AUDIT_ARG_TEXT(attrname);
404 
405 	error = getvnode(td, uap->fd,
406 	    cap_rights_init(&rights, CAP_EXTATTR_GET), &fp);
407 	if (error)
408 		return (error);
409 
410 	error = extattr_get_vp(fp->f_vnode, uap->attrnamespace,
411 	    attrname, uap->data, uap->nbytes, td);
412 
413 	fdrop(fp, td);
414 	return (error);
415 }
416 
417 int
sys_extattr_get_file(td,uap)418 sys_extattr_get_file(td, uap)
419 	struct thread *td;
420 	struct extattr_get_file_args /* {
421 		const char *path;
422 		int attrnamespace;
423 		const char *attrname;
424 		void *data;
425 		size_t nbytes;
426 	} */ *uap;
427 {
428 	struct nameidata nd;
429 	char attrname[EXTATTR_MAXNAMELEN];
430 	int error;
431 
432 	AUDIT_ARG_VALUE(uap->attrnamespace);
433 	error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
434 	if (error)
435 		return (error);
436 	AUDIT_ARG_TEXT(attrname);
437 
438 	NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, td);
439 	error = namei(&nd);
440 	if (error)
441 		return (error);
442 	NDFREE(&nd, NDF_ONLY_PNBUF);
443 
444 	error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname,
445 	    uap->data, uap->nbytes, td);
446 
447 	vrele(nd.ni_vp);
448 	return (error);
449 }
450 
451 int
sys_extattr_get_link(td,uap)452 sys_extattr_get_link(td, uap)
453 	struct thread *td;
454 	struct extattr_get_link_args /* {
455 		const char *path;
456 		int attrnamespace;
457 		const char *attrname;
458 		void *data;
459 		size_t nbytes;
460 	} */ *uap;
461 {
462 	struct nameidata nd;
463 	char attrname[EXTATTR_MAXNAMELEN];
464 	int error;
465 
466 	AUDIT_ARG_VALUE(uap->attrnamespace);
467 	error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
468 	if (error)
469 		return (error);
470 	AUDIT_ARG_TEXT(attrname);
471 
472 	NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path,
473 	    td);
474 	error = namei(&nd);
475 	if (error)
476 		return (error);
477 	NDFREE(&nd, NDF_ONLY_PNBUF);
478 
479 	error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname,
480 	    uap->data, uap->nbytes, td);
481 
482 	vrele(nd.ni_vp);
483 	return (error);
484 }
485 
486 /*
487  * extattr_delete_vp(): Delete a named extended attribute on a file or
488  *                      directory
489  *
490  * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
491  *            kernelspace string pointer "attrname", proc "p"
492  * Returns: 0 on success, an error number otherwise
493  * Locks: none
494  * References: vp must be a valid reference for the duration of the call
495  */
496 static int
extattr_delete_vp(struct vnode * vp,int attrnamespace,const char * attrname,struct thread * td)497 extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
498     struct thread *td)
499 {
500 	struct mount *mp;
501 	int error;
502 
503 	error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
504 	if (error)
505 		return (error);
506 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
507 
508 #ifdef MAC
509 	error = mac_vnode_check_deleteextattr(td->td_ucred, vp, attrnamespace,
510 	    attrname);
511 	if (error)
512 		goto done;
513 #endif
514 
515 	error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, td->td_ucred,
516 	    td);
517 	if (error == EOPNOTSUPP)
518 		error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
519 		    td->td_ucred, td);
520 #ifdef MAC
521 done:
522 #endif
523 	VOP_UNLOCK(vp, 0);
524 	vn_finished_write(mp);
525 	return (error);
526 }
527 
528 int
sys_extattr_delete_fd(td,uap)529 sys_extattr_delete_fd(td, uap)
530 	struct thread *td;
531 	struct extattr_delete_fd_args /* {
532 		int fd;
533 		int attrnamespace;
534 		const char *attrname;
535 	} */ *uap;
536 {
537 	struct file *fp;
538 	char attrname[EXTATTR_MAXNAMELEN];
539 	cap_rights_t rights;
540 	int error;
541 
542 	AUDIT_ARG_FD(uap->fd);
543 	AUDIT_ARG_VALUE(uap->attrnamespace);
544 	error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
545 	if (error)
546 		return (error);
547 	AUDIT_ARG_TEXT(attrname);
548 
549 	error = getvnode(td, uap->fd,
550 	    cap_rights_init(&rights, CAP_EXTATTR_DELETE), &fp);
551 	if (error)
552 		return (error);
553 
554 	error = extattr_delete_vp(fp->f_vnode, uap->attrnamespace,
555 	    attrname, td);
556 	fdrop(fp, td);
557 	return (error);
558 }
559 
560 int
sys_extattr_delete_file(td,uap)561 sys_extattr_delete_file(td, uap)
562 	struct thread *td;
563 	struct extattr_delete_file_args /* {
564 		const char *path;
565 		int attrnamespace;
566 		const char *attrname;
567 	} */ *uap;
568 {
569 	struct nameidata nd;
570 	char attrname[EXTATTR_MAXNAMELEN];
571 	int error;
572 
573 	AUDIT_ARG_VALUE(uap->attrnamespace);
574 	error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
575 	if (error)
576 		return(error);
577 	AUDIT_ARG_TEXT(attrname);
578 
579 	NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, td);
580 	error = namei(&nd);
581 	if (error)
582 		return(error);
583 	NDFREE(&nd, NDF_ONLY_PNBUF);
584 
585 	error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td);
586 	vrele(nd.ni_vp);
587 	return(error);
588 }
589 
590 int
sys_extattr_delete_link(td,uap)591 sys_extattr_delete_link(td, uap)
592 	struct thread *td;
593 	struct extattr_delete_link_args /* {
594 		const char *path;
595 		int attrnamespace;
596 		const char *attrname;
597 	} */ *uap;
598 {
599 	struct nameidata nd;
600 	char attrname[EXTATTR_MAXNAMELEN];
601 	int error;
602 
603 	AUDIT_ARG_VALUE(uap->attrnamespace);
604 	error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
605 	if (error)
606 		return(error);
607 	AUDIT_ARG_TEXT(attrname);
608 
609 	NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, td);
610 	error = namei(&nd);
611 	if (error)
612 		return(error);
613 	NDFREE(&nd, NDF_ONLY_PNBUF);
614 
615 	error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td);
616 	vrele(nd.ni_vp);
617 	return(error);
618 }
619 
620 /*-
621  * Retrieve a list of extended attributes on a file or directory.
622  *
623  * Arguments: unlocked vnode "vp", attribute namespace 'attrnamespace",
624  *            userspace buffer pointer "data", buffer length "nbytes",
625  *            thread "td".
626  * Returns: 0 on success, an error number otherwise
627  * Locks: none
628  * References: vp must be a valid reference for the duration of the call
629  */
630 static int
extattr_list_vp(struct vnode * vp,int attrnamespace,void * data,size_t nbytes,struct thread * td)631 extattr_list_vp(struct vnode *vp, int attrnamespace, void *data,
632     size_t nbytes, struct thread *td)
633 {
634 	struct uio auio, *auiop;
635 	size_t size, *sizep;
636 	struct iovec aiov;
637 	ssize_t cnt;
638 	int error;
639 
640 	if (nbytes > IOSIZE_MAX)
641 		return (EINVAL);
642 
643 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
644 
645 	auiop = NULL;
646 	sizep = NULL;
647 	cnt = 0;
648 	if (data != NULL) {
649 		aiov.iov_base = data;
650 		aiov.iov_len = nbytes;
651 		auio.uio_iov = &aiov;
652 		auio.uio_iovcnt = 1;
653 		auio.uio_offset = 0;
654 		auio.uio_resid = nbytes;
655 		auio.uio_rw = UIO_READ;
656 		auio.uio_segflg = UIO_USERSPACE;
657 		auio.uio_td = td;
658 		auiop = &auio;
659 		cnt = nbytes;
660 	} else
661 		sizep = &size;
662 
663 #ifdef MAC
664 	error = mac_vnode_check_listextattr(td->td_ucred, vp, attrnamespace);
665 	if (error)
666 		goto done;
667 #endif
668 
669 	error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep,
670 	    td->td_ucred, td);
671 
672 	if (auiop != NULL) {
673 		cnt -= auio.uio_resid;
674 		td->td_retval[0] = cnt;
675 	} else
676 		td->td_retval[0] = size;
677 #ifdef MAC
678 done:
679 #endif
680 	VOP_UNLOCK(vp, 0);
681 	return (error);
682 }
683 
684 
685 int
sys_extattr_list_fd(td,uap)686 sys_extattr_list_fd(td, uap)
687 	struct thread *td;
688 	struct extattr_list_fd_args /* {
689 		int fd;
690 		int attrnamespace;
691 		void *data;
692 		size_t nbytes;
693 	} */ *uap;
694 {
695 	struct file *fp;
696 	cap_rights_t rights;
697 	int error;
698 
699 	AUDIT_ARG_FD(uap->fd);
700 	AUDIT_ARG_VALUE(uap->attrnamespace);
701 	error = getvnode(td, uap->fd,
702 	    cap_rights_init(&rights, CAP_EXTATTR_LIST), &fp);
703 	if (error)
704 		return (error);
705 
706 	error = extattr_list_vp(fp->f_vnode, uap->attrnamespace, uap->data,
707 	    uap->nbytes, td);
708 
709 	fdrop(fp, td);
710 	return (error);
711 }
712 
713 int
sys_extattr_list_file(td,uap)714 sys_extattr_list_file(td, uap)
715 	struct thread*td;
716 	struct extattr_list_file_args /* {
717 		const char *path;
718 		int attrnamespace;
719 		void *data;
720 		size_t nbytes;
721 	} */ *uap;
722 {
723 	struct nameidata nd;
724 	int error;
725 
726 	AUDIT_ARG_VALUE(uap->attrnamespace);
727 	NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, td);
728 	error = namei(&nd);
729 	if (error)
730 		return (error);
731 	NDFREE(&nd, NDF_ONLY_PNBUF);
732 
733 	error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data,
734 	    uap->nbytes, td);
735 
736 	vrele(nd.ni_vp);
737 	return (error);
738 }
739 
740 int
sys_extattr_list_link(td,uap)741 sys_extattr_list_link(td, uap)
742 	struct thread*td;
743 	struct extattr_list_link_args /* {
744 		const char *path;
745 		int attrnamespace;
746 		void *data;
747 		size_t nbytes;
748 	} */ *uap;
749 {
750 	struct nameidata nd;
751 	int error;
752 
753 	AUDIT_ARG_VALUE(uap->attrnamespace);
754 	NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path,
755 	    td);
756 	error = namei(&nd);
757 	if (error)
758 		return (error);
759 	NDFREE(&nd, NDF_ONLY_PNBUF);
760 
761 	error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data,
762 	    uap->nbytes, td);
763 
764 	vrele(nd.ni_vp);
765 	return (error);
766 }
767