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