1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 1999-2001 Robert N. M. Watson 5 * All rights reserved. 6 * 7 * This software was developed by Robert Watson for the TrustedBSD Project. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/capsicum.h> 37 #include <sys/lock.h> 38 #include <sys/mount.h> 39 #include <sys/mutex.h> 40 #include <sys/sysproto.h> 41 #include <sys/fcntl.h> 42 #include <sys/namei.h> 43 #include <sys/filedesc.h> 44 #include <sys/limits.h> 45 #include <sys/vnode.h> 46 #include <sys/proc.h> 47 #include <sys/extattr.h> 48 49 #include <security/audit/audit.h> 50 #include <security/mac/mac_framework.h> 51 52 static int user_extattr_set_path(struct thread *td, const char *path, 53 int attrnamespace, const char *attrname, void *data, 54 size_t nbytes, int follow); 55 static int user_extattr_get_path(struct thread *td, const char *path, 56 int attrnamespace, const char *attrname, void *data, 57 size_t nbytes, int follow); 58 static int user_extattr_delete_path(struct thread *td, const char *path, 59 int attrnamespace, const char *attrname, int follow); 60 static int user_extattr_list_path(struct thread *td, const char *path, 61 int attrnamespace, void *data, size_t nbytes, int follow); 62 63 /* 64 * Syscall to push extended attribute configuration information into the VFS. 65 * Accepts a path, which it converts to a mountpoint, as well as a command 66 * (int cmd), and attribute name and misc data. 67 * 68 * Currently this is used only by UFS1 extended attributes. 69 */ 70 #ifndef _SYS_SYSPROTO_H_ 71 struct extattrctl_args { 72 const char *path; 73 int cmd; 74 const char *filename; 75 int attrnamespace; 76 const char *attrname; 77 }; 78 #endif 79 int 80 sys_extattrctl(struct thread *td, struct extattrctl_args *uap) 81 { 82 struct vnode *filename_vp; 83 struct nameidata nd; 84 struct mount *mp, *mp_writable; 85 char attrname[EXTATTR_MAXNAMELEN + 1]; 86 int error; 87 88 AUDIT_ARG_CMD(uap->cmd); 89 AUDIT_ARG_VALUE(uap->attrnamespace); 90 /* 91 * uap->attrname is not always defined. We check again later when we 92 * invoke the VFS call so as to pass in NULL there if needed. 93 */ 94 if (uap->attrname != NULL) { 95 error = copyinstr(uap->attrname, attrname, sizeof(attrname), 96 NULL); 97 if (error) 98 return (error); 99 } 100 AUDIT_ARG_TEXT(attrname); 101 102 mp = NULL; 103 filename_vp = NULL; 104 if (uap->filename != NULL) { 105 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE2, UIO_USERSPACE, 106 uap->filename); 107 error = namei(&nd); 108 if (error) 109 return (error); 110 filename_vp = nd.ni_vp; 111 NDFREE_PNBUF(&nd); 112 } 113 114 /* uap->path is always defined. */ 115 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, UIO_USERSPACE, 116 uap->path); 117 error = namei(&nd); 118 if (error) 119 goto out; 120 mp = nd.ni_vp->v_mount; 121 error = vfs_busy(mp, 0); 122 if (error) { 123 vput(nd.ni_vp); 124 NDFREE_PNBUF(&nd); 125 mp = NULL; 126 goto out; 127 } 128 VOP_UNLOCK(nd.ni_vp); 129 error = vn_start_write(nd.ni_vp, &mp_writable, V_WAIT | V_PCATCH); 130 vrele(nd.ni_vp); 131 NDFREE_PNBUF(&nd); 132 if (error) 133 goto out; 134 if (filename_vp != NULL) { 135 /* 136 * uap->filename is not always defined. If it is, 137 * grab a vnode lock, which VFS_EXTATTRCTL() will 138 * later release. 139 */ 140 error = vn_lock(filename_vp, LK_EXCLUSIVE); 141 if (error) { 142 vn_finished_write(mp_writable); 143 goto out; 144 } 145 } 146 147 error = VFS_EXTATTRCTL(mp, uap->cmd, filename_vp, uap->attrnamespace, 148 uap->attrname != NULL ? attrname : NULL); 149 150 vn_finished_write(mp_writable); 151 out: 152 if (mp != NULL) 153 vfs_unbusy(mp); 154 155 /* 156 * VFS_EXTATTRCTL will have unlocked, but not de-ref'd, filename_vp, 157 * so vrele it if it is defined. 158 */ 159 if (filename_vp != NULL) 160 vrele(filename_vp); 161 return (error); 162 } 163 164 /*- 165 * Set a named extended attribute on a file or directory 166 * 167 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 168 * kernelspace string pointer "attrname", userspace buffer 169 * pointer "data", buffer length "nbytes", thread "td". 170 * Returns: 0 on success, an error number otherwise 171 * Locks: none 172 * References: vp must be a valid reference for the duration of the call 173 */ 174 static int 175 extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname, 176 void *data, size_t nbytes, struct thread *td) 177 { 178 struct mount *mp; 179 struct uio auio; 180 struct iovec aiov; 181 ssize_t cnt; 182 int error; 183 184 if (nbytes > IOSIZE_MAX) 185 return (EINVAL); 186 187 error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH); 188 if (error) 189 return (error); 190 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 191 192 aiov.iov_base = data; 193 aiov.iov_len = nbytes; 194 auio.uio_iov = &aiov; 195 auio.uio_iovcnt = 1; 196 auio.uio_offset = 0; 197 auio.uio_resid = nbytes; 198 auio.uio_rw = UIO_WRITE; 199 auio.uio_segflg = UIO_USERSPACE; 200 auio.uio_td = td; 201 cnt = nbytes; 202 203 #ifdef MAC 204 error = mac_vnode_check_setextattr(td->td_ucred, vp, attrnamespace, 205 attrname); 206 if (error) 207 goto done; 208 #endif 209 210 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio, 211 td->td_ucred, td); 212 cnt -= auio.uio_resid; 213 td->td_retval[0] = cnt; 214 215 #ifdef MAC 216 done: 217 #endif 218 VOP_UNLOCK(vp); 219 vn_finished_write(mp); 220 return (error); 221 } 222 223 #ifndef _SYS_SYSPROTO_H_ 224 struct extattr_set_fd_args { 225 int fd; 226 int attrnamespace; 227 const char *attrname; 228 void *data; 229 size_t nbytes; 230 }; 231 #endif 232 int 233 sys_extattr_set_fd(struct thread *td, struct extattr_set_fd_args *uap) 234 { 235 char attrname[EXTATTR_MAXNAMELEN + 1]; 236 int error; 237 238 error = copyinstr(uap->attrname, attrname, sizeof(attrname), NULL); 239 if (error) 240 return (error); 241 return (kern_extattr_set_fd(td, uap->fd, uap->attrnamespace, 242 attrname, uap->data, uap->nbytes)); 243 } 244 245 int 246 kern_extattr_set_fd(struct thread *td, int fd, int attrnamespace, 247 const char *attrname, void *data, size_t nbytes) 248 { 249 struct file *fp; 250 cap_rights_t rights; 251 int error; 252 253 AUDIT_ARG_FD(fd); 254 AUDIT_ARG_VALUE(attrnamespace); 255 AUDIT_ARG_TEXT(attrname); 256 257 error = getvnode_path(td, fd, 258 cap_rights_init_one(&rights, CAP_EXTATTR_SET), &fp); 259 if (error) 260 return (error); 261 262 error = extattr_set_vp(fp->f_vnode, attrnamespace, 263 attrname, data, nbytes, td); 264 fdrop(fp, td); 265 266 return (error); 267 } 268 269 #ifndef _SYS_SYSPROTO_H_ 270 struct extattr_set_file_args { 271 const char *path; 272 int attrnamespace; 273 const char *attrname; 274 void *data; 275 size_t nbytes; 276 }; 277 #endif 278 int 279 sys_extattr_set_file(struct thread *td, struct extattr_set_file_args *uap) 280 { 281 282 return (user_extattr_set_path(td, uap->path, uap->attrnamespace, 283 uap->attrname, uap->data, uap->nbytes, FOLLOW)); 284 } 285 286 #ifndef _SYS_SYSPROTO_H_ 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 }; 294 #endif 295 int 296 sys_extattr_set_link(struct thread *td, struct extattr_set_link_args *uap) 297 { 298 299 return (user_extattr_set_path(td, uap->path, uap->attrnamespace, 300 uap->attrname, uap->data, uap->nbytes, NOFOLLOW)); 301 } 302 303 static int 304 user_extattr_set_path(struct thread *td, const char *path, int attrnamespace, 305 const char *uattrname, void *data, size_t nbytes, int follow) 306 { 307 char attrname[EXTATTR_MAXNAMELEN + 1]; 308 int error; 309 310 error = copyinstr(uattrname, attrname, sizeof(attrname), NULL); 311 if (error) 312 return (error); 313 return (kern_extattr_set_path(td, path, attrnamespace, 314 attrname, data, nbytes, follow, UIO_USERSPACE)); 315 } 316 317 int 318 kern_extattr_set_path(struct thread *td, const char *path, int attrnamespace, 319 const char *attrname, void *data, size_t nbytes, int follow, 320 enum uio_seg pathseg) 321 { 322 struct nameidata nd; 323 int error; 324 325 AUDIT_ARG_VALUE(attrnamespace); 326 AUDIT_ARG_TEXT(attrname); 327 328 NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path); 329 error = namei(&nd); 330 if (error) 331 return (error); 332 NDFREE_PNBUF(&nd); 333 334 error = extattr_set_vp(nd.ni_vp, attrnamespace, attrname, data, 335 nbytes, td); 336 337 vrele(nd.ni_vp); 338 return (error); 339 } 340 341 /*- 342 * Get a named extended attribute on a file or directory 343 * 344 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 345 * kernelspace string pointer "attrname", userspace buffer 346 * pointer "data", buffer length "nbytes", thread "td". 347 * Returns: 0 on success, an error number otherwise 348 * Locks: none 349 * References: vp must be a valid reference for the duration of the call 350 */ 351 static int 352 extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname, 353 void *data, size_t nbytes, struct thread *td) 354 { 355 struct uio auio, *auiop; 356 struct iovec aiov; 357 ssize_t cnt; 358 size_t size, *sizep; 359 int error; 360 361 if (nbytes > IOSIZE_MAX) 362 return (EINVAL); 363 364 vn_lock(vp, LK_SHARED | LK_RETRY); 365 366 /* 367 * Slightly unusual semantics: if the user provides a NULL data 368 * pointer, they don't want to receive the data, just the maximum 369 * read length. 370 */ 371 auiop = NULL; 372 sizep = NULL; 373 cnt = 0; 374 if (data != NULL) { 375 aiov.iov_base = data; 376 aiov.iov_len = nbytes; 377 auio.uio_iov = &aiov; 378 auio.uio_iovcnt = 1; 379 auio.uio_offset = 0; 380 auio.uio_resid = nbytes; 381 auio.uio_rw = UIO_READ; 382 auio.uio_segflg = UIO_USERSPACE; 383 auio.uio_td = td; 384 auiop = &auio; 385 cnt = nbytes; 386 } else 387 sizep = &size; 388 389 #ifdef MAC 390 error = mac_vnode_check_getextattr(td->td_ucred, vp, attrnamespace, 391 attrname); 392 if (error) 393 goto done; 394 #endif 395 396 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep, 397 td->td_ucred, td); 398 399 if (auiop != NULL) { 400 cnt -= auio.uio_resid; 401 td->td_retval[0] = cnt; 402 } else 403 td->td_retval[0] = size; 404 #ifdef MAC 405 done: 406 #endif 407 VOP_UNLOCK(vp); 408 return (error); 409 } 410 411 #ifndef _SYS_SYSPROTO_H_ 412 struct extattr_get_fd_args { 413 int fd; 414 int attrnamespace; 415 const char *attrname; 416 void *data; 417 size_t nbytes; 418 }; 419 #endif 420 int 421 sys_extattr_get_fd(struct thread *td, struct extattr_get_fd_args *uap) 422 { 423 char attrname[EXTATTR_MAXNAMELEN + 1]; 424 int error; 425 426 error = copyinstr(uap->attrname, attrname, sizeof(attrname), NULL); 427 if (error) 428 return (error); 429 return (kern_extattr_get_fd(td, uap->fd, uap->attrnamespace, 430 attrname, uap->data, uap->nbytes)); 431 } 432 433 int 434 kern_extattr_get_fd(struct thread *td, int fd, int attrnamespace, 435 const char *attrname, void *data, size_t nbytes) 436 { 437 struct file *fp; 438 cap_rights_t rights; 439 int error; 440 441 AUDIT_ARG_FD(fd); 442 AUDIT_ARG_VALUE(attrnamespace); 443 AUDIT_ARG_TEXT(attrname); 444 445 error = getvnode_path(td, fd, 446 cap_rights_init_one(&rights, CAP_EXTATTR_GET), &fp); 447 if (error) 448 return (error); 449 450 error = extattr_get_vp(fp->f_vnode, attrnamespace, 451 attrname, data, nbytes, td); 452 453 fdrop(fp, td); 454 return (error); 455 } 456 457 #ifndef _SYS_SYSPROTO_H_ 458 struct extattr_get_file_args { 459 const char *path; 460 int attrnamespace; 461 const char *attrname; 462 void *data; 463 size_t nbytes; 464 }; 465 #endif 466 int 467 sys_extattr_get_file(struct thread *td, struct extattr_get_file_args *uap) 468 { 469 return (user_extattr_get_path(td, uap->path, uap->attrnamespace, 470 uap->attrname, uap->data, uap->nbytes, FOLLOW)); 471 } 472 473 #ifndef _SYS_SYSPROTO_H_ 474 struct extattr_get_link_args { 475 const char *path; 476 int attrnamespace; 477 const char *attrname; 478 void *data; 479 size_t nbytes; 480 }; 481 #endif 482 int 483 sys_extattr_get_link(struct thread *td, struct extattr_get_link_args *uap) 484 { 485 return (user_extattr_get_path(td, uap->path, uap->attrnamespace, 486 uap->attrname, uap->data, uap->nbytes, NOFOLLOW)); 487 } 488 489 static int 490 user_extattr_get_path(struct thread *td, const char *path, int attrnamespace, 491 const char *uattrname, void *data, size_t nbytes, int follow) 492 { 493 char attrname[EXTATTR_MAXNAMELEN + 1]; 494 int error; 495 496 error = copyinstr(uattrname, attrname, sizeof(attrname), NULL); 497 if (error) 498 return (error); 499 return (kern_extattr_get_path(td, path, attrnamespace, 500 attrname, data, nbytes, follow, UIO_USERSPACE)); 501 } 502 503 int 504 kern_extattr_get_path(struct thread *td, const char *path, int attrnamespace, 505 const char *attrname, void *data, size_t nbytes, int follow, 506 enum uio_seg pathseg) 507 { 508 struct nameidata nd; 509 int error; 510 511 AUDIT_ARG_VALUE(attrnamespace); 512 AUDIT_ARG_TEXT(attrname); 513 514 NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path); 515 error = namei(&nd); 516 if (error) 517 return (error); 518 NDFREE_PNBUF(&nd); 519 520 error = extattr_get_vp(nd.ni_vp, attrnamespace, attrname, data, 521 nbytes, td); 522 523 vrele(nd.ni_vp); 524 return (error); 525 } 526 527 /* 528 * extattr_delete_vp(): Delete a named extended attribute on a file or 529 * directory 530 * 531 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 532 * kernelspace string pointer "attrname", proc "p" 533 * Returns: 0 on success, an error number otherwise 534 * Locks: none 535 * References: vp must be a valid reference for the duration of the call 536 */ 537 static int 538 extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname, 539 struct thread *td) 540 { 541 struct mount *mp; 542 int error; 543 544 error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH); 545 if (error) 546 return (error); 547 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 548 549 #ifdef MAC 550 error = mac_vnode_check_deleteextattr(td->td_ucred, vp, attrnamespace, 551 attrname); 552 if (error) 553 goto done; 554 #endif 555 556 error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, td->td_ucred, 557 td); 558 if (error == EOPNOTSUPP) 559 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL, 560 td->td_ucred, td); 561 #ifdef MAC 562 done: 563 #endif 564 VOP_UNLOCK(vp); 565 vn_finished_write(mp); 566 return (error); 567 } 568 569 #ifndef _SYS_SYSPROTO_H_ 570 struct extattr_delete_fd_args { 571 int fd; 572 int attrnamespace; 573 const char *attrname; 574 }; 575 #endif 576 int 577 sys_extattr_delete_fd(struct thread *td, struct extattr_delete_fd_args *uap) 578 { 579 char attrname[EXTATTR_MAXNAMELEN + 1]; 580 int error; 581 582 error = copyinstr(uap->attrname, attrname, sizeof(attrname), NULL); 583 if (error) 584 return (error); 585 return (kern_extattr_delete_fd(td, uap->fd, uap->attrnamespace, 586 attrname)); 587 } 588 589 int 590 kern_extattr_delete_fd(struct thread *td, int fd, int attrnamespace, 591 const char *attrname) 592 { 593 struct file *fp; 594 cap_rights_t rights; 595 int error; 596 597 AUDIT_ARG_FD(fd); 598 AUDIT_ARG_VALUE(attrnamespace); 599 AUDIT_ARG_TEXT(attrname); 600 601 error = getvnode_path(td, fd, 602 cap_rights_init_one(&rights, CAP_EXTATTR_DELETE), &fp); 603 if (error) 604 return (error); 605 606 error = extattr_delete_vp(fp->f_vnode, attrnamespace, 607 attrname, td); 608 fdrop(fp, td); 609 return (error); 610 } 611 612 #ifndef _SYS_SYSPROTO_H_ 613 struct extattr_delete_file_args { 614 const char *path; 615 int attrnamespace; 616 const char *attrname; 617 }; 618 #endif 619 int 620 sys_extattr_delete_file(struct thread *td, struct extattr_delete_file_args *uap) 621 { 622 623 return (user_extattr_delete_path(td, uap->path, uap->attrnamespace, 624 uap->attrname, FOLLOW)); 625 } 626 627 #ifndef _SYS_SYSPROTO_H_ 628 struct extattr_delete_link_args { 629 const char *path; 630 int attrnamespace; 631 const char *attrname; 632 }; 633 #endif 634 int 635 sys_extattr_delete_link(struct thread *td, struct extattr_delete_link_args *uap) 636 { 637 638 return (user_extattr_delete_path(td, uap->path, uap->attrnamespace, 639 uap->attrname, NOFOLLOW)); 640 } 641 642 int 643 user_extattr_delete_path(struct thread *td, const char *path, int attrnamespace, 644 const char *uattrname, int follow) 645 { 646 char attrname[EXTATTR_MAXNAMELEN + 1]; 647 int error; 648 649 error = copyinstr(uattrname, attrname, sizeof(attrname), NULL); 650 if (error) 651 return(error); 652 return (kern_extattr_delete_path(td, path, attrnamespace, 653 attrname, follow, UIO_USERSPACE)); 654 } 655 656 int 657 kern_extattr_delete_path(struct thread *td, const char *path, int attrnamespace, 658 const char *attrname, int follow, enum uio_seg pathseg) 659 { 660 struct nameidata nd; 661 int error; 662 663 AUDIT_ARG_VALUE(attrnamespace); 664 AUDIT_ARG_TEXT(attrname); 665 666 NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path); 667 error = namei(&nd); 668 if (error) 669 return(error); 670 NDFREE_PNBUF(&nd); 671 672 error = extattr_delete_vp(nd.ni_vp, attrnamespace, attrname, td); 673 vrele(nd.ni_vp); 674 return(error); 675 } 676 677 /*- 678 * Retrieve a list of extended attributes on a file or directory. 679 * 680 * Arguments: unlocked vnode "vp", attribute namespace 'attrnamespace", 681 * userspace buffer pointer "data", buffer length "nbytes", 682 * thread "td". 683 * Returns: 0 on success, an error number otherwise 684 * Locks: none 685 * References: vp must be a valid reference for the duration of the call 686 */ 687 static int 688 extattr_list_vp(struct vnode *vp, int attrnamespace, struct uio *auiop, 689 struct thread *td) 690 { 691 size_t size, *sizep; 692 ssize_t cnt; 693 int error; 694 695 sizep = NULL; 696 cnt = 0; 697 if (auiop != NULL) { 698 if (auiop->uio_resid > IOSIZE_MAX) 699 return (EINVAL); 700 cnt = auiop->uio_resid; 701 } else 702 sizep = &size; 703 704 vn_lock(vp, LK_SHARED | LK_RETRY); 705 706 #ifdef MAC 707 error = mac_vnode_check_listextattr(td->td_ucred, vp, attrnamespace); 708 if (error) { 709 VOP_UNLOCK(vp); 710 return (error); 711 } 712 #endif 713 714 error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep, 715 td->td_ucred, td); 716 VOP_UNLOCK(vp); 717 718 if (auiop != NULL) { 719 cnt -= auiop->uio_resid; 720 td->td_retval[0] = cnt; 721 } else 722 td->td_retval[0] = size; 723 return (error); 724 } 725 726 #ifndef _SYS_SYSPROTO_H_ 727 struct extattr_list_fd_args { 728 int fd; 729 int attrnamespace; 730 void *data; 731 size_t nbytes; 732 }; 733 #endif 734 int 735 sys_extattr_list_fd(struct thread *td, struct extattr_list_fd_args *uap) 736 { 737 struct uio auio, *auiop; 738 struct iovec aiov; 739 740 if (uap->data != NULL) { 741 aiov.iov_base = uap->data; 742 aiov.iov_len = uap->nbytes; 743 auio.uio_iov = &aiov; 744 auio.uio_iovcnt = 1; 745 auio.uio_offset = 0; 746 auio.uio_resid = uap->nbytes; 747 auio.uio_rw = UIO_READ; 748 auio.uio_segflg = UIO_USERSPACE; 749 auio.uio_td = td; 750 auiop = &auio; 751 } else 752 auiop = NULL; 753 754 return (kern_extattr_list_fd(td, uap->fd, uap->attrnamespace, 755 auiop)); 756 } 757 758 int 759 kern_extattr_list_fd(struct thread *td, int fd, int attrnamespace, 760 struct uio *auiop) 761 { 762 struct file *fp; 763 cap_rights_t rights; 764 int error; 765 766 AUDIT_ARG_FD(fd); 767 AUDIT_ARG_VALUE(attrnamespace); 768 error = getvnode_path(td, fd, 769 cap_rights_init_one(&rights, CAP_EXTATTR_LIST), &fp); 770 if (error) 771 return (error); 772 773 error = extattr_list_vp(fp->f_vnode, attrnamespace, auiop, td); 774 775 fdrop(fp, td); 776 return (error); 777 } 778 779 #ifndef _SYS_SYSPROTO_H_ 780 struct extattr_list_file_args { 781 const char *path; 782 int attrnamespace; 783 void *data; 784 size_t nbytes; 785 } 786 #endif 787 int 788 sys_extattr_list_file(struct thread *td, struct extattr_list_file_args *uap) 789 { 790 791 return (user_extattr_list_path(td, uap->path, uap->attrnamespace, 792 uap->data, uap->nbytes, FOLLOW)); 793 } 794 795 #ifndef _SYS_SYSPROTO_H_ 796 struct extattr_list_link_args { 797 const char *path; 798 int attrnamespace; 799 void *data; 800 size_t nbytes; 801 }; 802 #endif 803 int 804 sys_extattr_list_link(struct thread *td, struct extattr_list_link_args *uap) 805 { 806 807 return (user_extattr_list_path(td, uap->path, uap->attrnamespace, 808 uap->data, uap->nbytes, NOFOLLOW)); 809 } 810 811 static int 812 user_extattr_list_path(struct thread *td, const char *path, int attrnamespace, 813 void *data, size_t nbytes, int follow) 814 { 815 struct uio auio, *auiop; 816 struct iovec aiov; 817 818 if (data != NULL) { 819 aiov.iov_base = data; 820 aiov.iov_len = nbytes; 821 auio.uio_iov = &aiov; 822 auio.uio_iovcnt = 1; 823 auio.uio_offset = 0; 824 auio.uio_resid = nbytes; 825 auio.uio_rw = UIO_READ; 826 auio.uio_segflg = UIO_USERSPACE; 827 auio.uio_td = td; 828 auiop = &auio; 829 } else 830 auiop = NULL; 831 832 return (kern_extattr_list_path(td, path, attrnamespace, 833 auiop, follow, UIO_USERSPACE)); 834 } 835 836 int 837 kern_extattr_list_path(struct thread *td, const char *path, int attrnamespace, 838 struct uio *auiop, int follow, enum uio_seg pathseg) 839 { 840 struct nameidata nd; 841 int error; 842 843 AUDIT_ARG_VALUE(attrnamespace); 844 NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path); 845 error = namei(&nd); 846 if (error) 847 return (error); 848 NDFREE_PNBUF(&nd); 849 850 error = extattr_list_vp(nd.ni_vp, attrnamespace, auiop, td); 851 852 vrele(nd.ni_vp); 853 return (error); 854 } 855