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/fcntl.h> 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 */ 58 int 59 extattrctl(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); 135 out: 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 */ 151 static int 152 extattr_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 195 done: 196 VOP_UNLOCK(vp, 0); 197 vn_finished_write(mp); 198 return (error); 199 } 200 201 int 202 extattr_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 236 int 237 extattr_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 273 int 274 extattr_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 */ 320 static int 321 extattr_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 377 done: 378 VOP_UNLOCK(vp, 0); 379 return (error); 380 } 381 382 int 383 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 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 417 int 418 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 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 454 int 455 extattr_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 */ 501 static int 502 extattr_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 528 done: 529 #endif 530 VOP_UNLOCK(vp, 0); 531 vn_finished_write(mp); 532 return (error); 533 } 534 535 int 536 extattr_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 567 int 568 extattr_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 600 int 601 extattr_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 */ 643 static int 644 extattr_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 694 done: 695 VOP_UNLOCK(vp, 0); 696 return (error); 697 } 698 699 700 int 701 extattr_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 728 int 729 extattr_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 758 int 759 extattr_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 } 787