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); 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 194 done: 195 VOP_UNLOCK(vp, 0); 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); 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 376 done: 377 VOP_UNLOCK(vp, 0); 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); 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 527 done: 528 #endif 529 VOP_UNLOCK(vp, 0); 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); 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 693 done: 694 VOP_UNLOCK(vp, 0); 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 } 786