]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/vfs_extattr.c
Fix missing pfctl(8) tunable.
[FreeBSD/FreeBSD.git] / sys / kern / vfs_extattr.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }