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