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 "opt_mac.h"
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/lock.h>
37 #include <sys/mount.h>
38 #include <sys/mutex.h>
39 #include <sys/sysproto.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 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 vfslocked, fnvfslocked, 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 vfslocked = fnvfslocked = 0;
89 /*
90 * uap->filename is not always defined. If it is, grab a vnode lock,
91 * which VFS_EXTATTRCTL() will later release.
92 */
93 filename_vp = NULL;
94 if (uap->filename != NULL) {
95 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | LOCKLEAF |
96 AUDITVNODE2, UIO_USERSPACE, uap->filename, td);
97 error = namei(&nd);
98 if (error)
99 return (error);
100 fnvfslocked = NDHASGIANT(&nd);
101 filename_vp = nd.ni_vp;
102 NDFREE(&nd, NDF_NO_VP_RELE | NDF_NO_VP_UNLOCK);
103 }
104
105 /* uap->path is always defined. */
106 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE,
107 uap->path, td);
108 error = namei(&nd);
109 if (error) {
110 if (filename_vp != NULL)
111 vput(filename_vp);
112 goto out;
113 }
114 vfslocked = NDHASGIANT(&nd);
115 mp = nd.ni_vp->v_mount;
116 error = vn_start_write(nd.ni_vp, &mp_writable, V_WAIT | PCATCH);
117 NDFREE(&nd, 0);
118 if (error) {
119 if (filename_vp != NULL)
120 vput(filename_vp);
121 goto out;
122 }
123
124 error = VFS_EXTATTRCTL(mp, uap->cmd, filename_vp, uap->attrnamespace,
125 uap->attrname != NULL ? attrname : NULL, td);
126
127 vn_finished_write(mp_writable);
128 /*
129 * VFS_EXTATTRCTL will have unlocked, but not de-ref'd, filename_vp,
130 * so vrele it if it is defined.
131 */
132 if (filename_vp != NULL)
133 vrele(filename_vp);
134 out:
135 VFS_UNLOCK_GIANT(fnvfslocked);
136 VFS_UNLOCK_GIANT(vfslocked);
137 return (error);
138 }
139
140 /*-
141 * Set a named extended attribute on a file or directory
142 *
143 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
144 * kernelspace string pointer "attrname", userspace buffer
145 * pointer "data", buffer length "nbytes", thread "td".
146 * Returns: 0 on success, an error number otherwise
147 * Locks: none
148 * References: vp must be a valid reference for the duration of the call
149 */
150 static int
151 extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
152 void *data, size_t nbytes, struct thread *td)
153 {
154 struct mount *mp;
155 struct uio auio;
156 struct iovec aiov;
157 ssize_t cnt;
158 int error;
159
160 VFS_ASSERT_GIANT(vp->v_mount);
161 error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
162 if (error)
163 return (error);
164 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
165 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
166
167 aiov.iov_base = data;
168 aiov.iov_len = nbytes;
169 auio.uio_iov = &aiov;
170 auio.uio_iovcnt = 1;
171 auio.uio_offset = 0;
172 if (nbytes > INT_MAX) {
173 error = EINVAL;
174 goto done;
175 }
176 auio.uio_resid = nbytes;
177 auio.uio_rw = UIO_WRITE;
178 auio.uio_segflg = UIO_USERSPACE;
179 auio.uio_td = td;
180 cnt = nbytes;
181
182 #ifdef MAC
183 error = mac_check_vnode_setextattr(td->td_ucred, vp, attrnamespace,
184 attrname, &auio);
185 if (error)
186 goto done;
187 #endif
188
189 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
190 td->td_ucred, td);
191 cnt -= auio.uio_resid;
192 td->td_retval[0] = cnt;
193
194 done:
195 VOP_UNLOCK(vp, 0, td);
196 vn_finished_write(mp);
197 return (error);
198 }
199
200 int
201 extattr_set_fd(td, uap)
202 struct thread *td;
203 struct extattr_set_fd_args /* {
204 int fd;
205 int attrnamespace;
206 const char *attrname;
207 void *data;
208 size_t nbytes;
209 } */ *uap;
210 {
211 struct file *fp;
212 char attrname[EXTATTR_MAXNAMELEN];
213 int vfslocked, error;
214
215 AUDIT_ARG(fd, uap->fd);
216 AUDIT_ARG(value, uap->attrnamespace);
217 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
218 if (error)
219 return (error);
220 AUDIT_ARG(text, attrname);
221
222 error = getvnode(td->td_proc->p_fd, uap->fd, &fp);
223 if (error)
224 return (error);
225
226 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
227 error = extattr_set_vp(fp->f_vnode, uap->attrnamespace,
228 attrname, uap->data, uap->nbytes, td);
229 fdrop(fp, td);
230 VFS_UNLOCK_GIANT(vfslocked);
231
232 return (error);
233 }
234
235 int
236 extattr_set_file(td, uap)
237 struct thread *td;
238 struct extattr_set_file_args /* {
239 const char *path;
240 int attrnamespace;
241 const char *attrname;
242 void *data;
243 size_t nbytes;
244 } */ *uap;
245 {
246 struct nameidata nd;
247 char attrname[EXTATTR_MAXNAMELEN];
248 int vfslocked, error;
249
250 AUDIT_ARG(value, uap->attrnamespace);
251 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
252 if (error)
253 return (error);
254 AUDIT_ARG(text, attrname);
255
256 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE,
257 uap->path, td);
258 error = namei(&nd);
259 if (error)
260 return (error);
261 NDFREE(&nd, NDF_ONLY_PNBUF);
262
263 vfslocked = NDHASGIANT(&nd);
264 error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname,
265 uap->data, uap->nbytes, td);
266
267 vrele(nd.ni_vp);
268 VFS_UNLOCK_GIANT(vfslocked);
269 return (error);
270 }
271
272 int
273 extattr_set_link(td, uap)
274 struct thread *td;
275 struct extattr_set_link_args /* {
276 const char *path;
277 int attrnamespace;
278 const char *attrname;
279 void *data;
280 size_t nbytes;
281 } */ *uap;
282 {
283 struct nameidata nd;
284 char attrname[EXTATTR_MAXNAMELEN];
285 int vfslocked, error;
286
287 AUDIT_ARG(value, uap->attrnamespace);
288 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
289 if (error)
290 return (error);
291 AUDIT_ARG(text, attrname);
292
293 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE,
294 uap->path, td);
295 error = namei(&nd);
296 if (error)
297 return (error);
298 NDFREE(&nd, NDF_ONLY_PNBUF);
299
300 vfslocked = NDHASGIANT(&nd);
301 error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname,
302 uap->data, uap->nbytes, td);
303
304 vrele(nd.ni_vp);
305 VFS_UNLOCK_GIANT(vfslocked);
306 return (error);
307 }
308
309 /*-
310 * Get a named extended attribute on a file or directory
311 *
312 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
313 * kernelspace string pointer "attrname", userspace buffer
314 * pointer "data", buffer length "nbytes", thread "td".
315 * Returns: 0 on success, an error number otherwise
316 * Locks: none
317 * References: vp must be a valid reference for the duration of the call
318 */
319 static int
320 extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
321 void *data, size_t nbytes, struct thread *td)
322 {
323 struct uio auio, *auiop;
324 struct iovec aiov;
325 ssize_t cnt;
326 size_t size, *sizep;
327 int error;
328
329 VFS_ASSERT_GIANT(vp->v_mount);
330 VOP_LEASE(vp, td, td->td_ucred, LEASE_READ);
331 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
332
333 /*
334 * Slightly unusual semantics: if the user provides a NULL data
335 * pointer, they don't want to receive the data, just the maximum
336 * read length.
337 */
338 auiop = NULL;
339 sizep = NULL;
340 cnt = 0;
341 if (data != NULL) {
342 aiov.iov_base = data;
343 aiov.iov_len = nbytes;
344 auio.uio_iov = &aiov;
345 auio.uio_iovcnt = 1;
346 auio.uio_offset = 0;
347 if (nbytes > INT_MAX) {
348 error = EINVAL;
349 goto done;
350 }
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_check_vnode_getextattr(td->td_ucred, vp, attrnamespace,
362 attrname, &auio);
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
376 done:
377 VOP_UNLOCK(vp, 0, td);
378 return (error);
379 }
380
381 int
382 extattr_get_fd(td, uap)
383 struct thread *td;
384 struct extattr_get_fd_args /* {
385 int fd;
386 int attrnamespace;
387 const char *attrname;
388 void *data;
389 size_t nbytes;
390 } */ *uap;
391 {
392 struct file *fp;
393 char attrname[EXTATTR_MAXNAMELEN];
394 int vfslocked, error;
395
396 AUDIT_ARG(fd, uap->fd);
397 AUDIT_ARG(value, uap->attrnamespace);
398 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
399 if (error)
400 return (error);
401 AUDIT_ARG(text, attrname);
402
403 error = getvnode(td->td_proc->p_fd, uap->fd, &fp);
404 if (error)
405 return (error);
406
407 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
408 error = extattr_get_vp(fp->f_vnode, uap->attrnamespace,
409 attrname, uap->data, uap->nbytes, td);
410
411 fdrop(fp, td);
412 VFS_UNLOCK_GIANT(vfslocked);
413 return (error);
414 }
415
416 int
417 extattr_get_file(td, uap)
418 struct thread *td;
419 struct extattr_get_file_args /* {
420 const char *path;
421 int attrnamespace;
422 const char *attrname;
423 void *data;
424 size_t nbytes;
425 } */ *uap;
426 {
427 struct nameidata nd;
428 char attrname[EXTATTR_MAXNAMELEN];
429 int vfslocked, error;
430
431 AUDIT_ARG(value, uap->attrnamespace);
432 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
433 if (error)
434 return (error);
435 AUDIT_ARG(text, attrname);
436
437 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE,
438 uap->path, td);
439 error = namei(&nd);
440 if (error)
441 return (error);
442 NDFREE(&nd, NDF_ONLY_PNBUF);
443
444 vfslocked = NDHASGIANT(&nd);
445 error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname,
446 uap->data, uap->nbytes, td);
447
448 vrele(nd.ni_vp);
449 VFS_UNLOCK_GIANT(vfslocked);
450 return (error);
451 }
452
453 int
454 extattr_get_link(td, uap)
455 struct thread *td;
456 struct extattr_get_link_args /* {
457 const char *path;
458 int attrnamespace;
459 const char *attrname;
460 void *data;
461 size_t nbytes;
462 } */ *uap;
463 {
464 struct nameidata nd;
465 char attrname[EXTATTR_MAXNAMELEN];
466 int vfslocked, error;
467
468 AUDIT_ARG(value, uap->attrnamespace);
469 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
470 if (error)
471 return (error);
472 AUDIT_ARG(text, attrname);
473
474 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE,
475 uap->path, td);
476 error = namei(&nd);
477 if (error)
478 return (error);
479 NDFREE(&nd, NDF_ONLY_PNBUF);
480
481 vfslocked = NDHASGIANT(&nd);
482 error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname,
483 uap->data, uap->nbytes, td);
484
485 vrele(nd.ni_vp);
486 VFS_UNLOCK_GIANT(vfslocked);
487 return (error);
488 }
489
490 /*
491 * extattr_delete_vp(): Delete a named extended attribute on a file or
492 * directory
493 *
494 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
495 * kernelspace string pointer "attrname", proc "p"
496 * Returns: 0 on success, an error number otherwise
497 * Locks: none
498 * References: vp must be a valid reference for the duration of the call
499 */
500 static int
501 extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
502 struct thread *td)
503 {
504 struct mount *mp;
505 int error;
506
507 VFS_ASSERT_GIANT(vp->v_mount);
508 error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
509 if (error)
510 return (error);
511 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
512 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
513
514 #ifdef MAC
515 error = mac_check_vnode_deleteextattr(td->td_ucred, vp, attrnamespace,
516 attrname);
517 if (error)
518 goto done;
519 #endif
520
521 error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, td->td_ucred,
522 td);
523 if (error == EOPNOTSUPP)
524 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
525 td->td_ucred, td);
526 #ifdef MAC
527 done:
528 #endif
529 VOP_UNLOCK(vp, 0, td);
530 vn_finished_write(mp);
531 return (error);
532 }
533
534 int
535 extattr_delete_fd(td, uap)
536 struct thread *td;
537 struct extattr_delete_fd_args /* {
538 int fd;
539 int attrnamespace;
540 const char *attrname;
541 } */ *uap;
542 {
543 struct file *fp;
544 char attrname[EXTATTR_MAXNAMELEN];
545 int vfslocked, error;
546
547 AUDIT_ARG(fd, uap->fd);
548 AUDIT_ARG(value, uap->attrnamespace);
549 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
550 if (error)
551 return (error);
552 AUDIT_ARG(text, attrname);
553
554 error = getvnode(td->td_proc->p_fd, uap->fd, &fp);
555 if (error)
556 return (error);
557
558 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
559 error = extattr_delete_vp(fp->f_vnode, uap->attrnamespace,
560 attrname, td);
561 fdrop(fp, td);
562 VFS_UNLOCK_GIANT(vfslocked);
563 return (error);
564 }
565
566 int
567 extattr_delete_file(td, uap)
568 struct thread *td;
569 struct extattr_delete_file_args /* {
570 const char *path;
571 int attrnamespace;
572 const char *attrname;
573 } */ *uap;
574 {
575 struct nameidata nd;
576 char attrname[EXTATTR_MAXNAMELEN];
577 int vfslocked, error;
578
579 AUDIT_ARG(value, uap->attrnamespace);
580 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
581 if (error)
582 return(error);
583 AUDIT_ARG(text, attrname);
584
585 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE,
586 uap->path, td);
587 error = namei(&nd);
588 if (error)
589 return(error);
590 NDFREE(&nd, NDF_ONLY_PNBUF);
591
592 vfslocked = NDHASGIANT(&nd);
593 error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td);
594 vrele(nd.ni_vp);
595 VFS_UNLOCK_GIANT(vfslocked);
596 return(error);
597 }
598
599 int
600 extattr_delete_link(td, uap)
601 struct thread *td;
602 struct extattr_delete_link_args /* {
603 const char *path;
604 int attrnamespace;
605 const char *attrname;
606 } */ *uap;
607 {
608 struct nameidata nd;
609 char attrname[EXTATTR_MAXNAMELEN];
610 int vfslocked, error;
611
612 AUDIT_ARG(value, uap->attrnamespace);
613 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
614 if (error)
615 return(error);
616 AUDIT_ARG(text, attrname);
617
618 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE,
619 uap->path, td);
620 error = namei(&nd);
621 if (error)
622 return(error);
623 NDFREE(&nd, NDF_ONLY_PNBUF);
624
625 vfslocked = NDHASGIANT(&nd);
626 error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td);
627 vrele(nd.ni_vp);
628 VFS_UNLOCK_GIANT(vfslocked);
629 return(error);
630 }
631
632 /*-
633 * Retrieve a list of extended attributes on a file or directory.
634 *
635 * Arguments: unlocked vnode "vp", attribute namespace 'attrnamespace",
636 * userspace buffer pointer "data", buffer length "nbytes",
637 * thread "td".
638 * Returns: 0 on success, an error number otherwise
639 * Locks: none
640 * References: vp must be a valid reference for the duration of the call
641 */
642 static int
643 extattr_list_vp(struct vnode *vp, int attrnamespace, void *data,
644 size_t nbytes, struct thread *td)
645 {
646 struct uio auio, *auiop;
647 size_t size, *sizep;
648 struct iovec aiov;
649 ssize_t cnt;
650 int error;
651
652 VFS_ASSERT_GIANT(vp->v_mount);
653 VOP_LEASE(vp, td, td->td_ucred, LEASE_READ);
654 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
655
656 auiop = NULL;
657 sizep = NULL;
658 cnt = 0;
659 if (data != NULL) {
660 aiov.iov_base = data;
661 aiov.iov_len = nbytes;
662 auio.uio_iov = &aiov;
663 auio.uio_iovcnt = 1;
664 auio.uio_offset = 0;
665 if (nbytes > INT_MAX) {
666 error = EINVAL;
667 goto done;
668 }
669 auio.uio_resid = nbytes;
670 auio.uio_rw = UIO_READ;
671 auio.uio_segflg = UIO_USERSPACE;
672 auio.uio_td = td;
673 auiop = &auio;
674 cnt = nbytes;
675 } else
676 sizep = &size;
677
678 #ifdef MAC
679 error = mac_check_vnode_listextattr(td->td_ucred, vp, attrnamespace);
680 if (error)
681 goto done;
682 #endif
683
684 error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep,
685 td->td_ucred, td);
686
687 if (auiop != NULL) {
688 cnt -= auio.uio_resid;
689 td->td_retval[0] = cnt;
690 } else
691 td->td_retval[0] = size;
692
693 done:
694 VOP_UNLOCK(vp, 0, td);
695 return (error);
696 }
697
698
699 int
700 extattr_list_fd(td, uap)
701 struct thread *td;
702 struct extattr_list_fd_args /* {
703 int fd;
704 int attrnamespace;
705 void *data;
706 size_t nbytes;
707 } */ *uap;
708 {
709 struct file *fp;
710 int vfslocked, error;
711
712 AUDIT_ARG(fd, uap->fd);
713 AUDIT_ARG(value, uap->attrnamespace);
714 error = getvnode(td->td_proc->p_fd, uap->fd, &fp);
715 if (error)
716 return (error);
717
718 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
719 error = extattr_list_vp(fp->f_vnode, uap->attrnamespace, uap->data,
720 uap->nbytes, td);
721
722 fdrop(fp, td);
723 VFS_UNLOCK_GIANT(vfslocked);
724 return (error);
725 }
726
727 int
728 extattr_list_file(td, uap)
729 struct thread*td;
730 struct extattr_list_file_args /* {
731 const char *path;
732 int attrnamespace;
733 void *data;
734 size_t nbytes;
735 } */ *uap;
736 {
737 struct nameidata nd;
738 int vfslocked, error;
739
740 AUDIT_ARG(value, uap->attrnamespace);
741 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE,
742 uap->path, td);
743 error = namei(&nd);
744 if (error)
745 return (error);
746 NDFREE(&nd, NDF_ONLY_PNBUF);
747
748 vfslocked = NDHASGIANT(&nd);
749 error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data,
750 uap->nbytes, td);
751
752 vrele(nd.ni_vp);
753 VFS_UNLOCK_GIANT(vfslocked);
754 return (error);
755 }
756
757 int
758 extattr_list_link(td, uap)
759 struct thread*td;
760 struct extattr_list_link_args /* {
761 const char *path;
762 int attrnamespace;
763 void *data;
764 size_t nbytes;
765 } */ *uap;
766 {
767 struct nameidata nd;
768 int vfslocked, error;
769
770 AUDIT_ARG(value, uap->attrnamespace);
771 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE,
772 uap->path, td);
773 error = namei(&nd);
774 if (error)
775 return (error);
776 NDFREE(&nd, NDF_ONLY_PNBUF);
777
778 vfslocked = NDHASGIANT(&nd);
779 error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data,
780 uap->nbytes, td);
781
782 vrele(nd.ni_vp);
783 VFS_UNLOCK_GIANT(vfslocked);
784 return (error);
785 }
Cache object: 287da548ae004b4ca59e1009f78014cb
|