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