1 /* $NetBSD: vfs_xattr.c,v 1.29 2011/11/09 18:29:28 drochner Exp $ */ 2 3 /*- 4 * Copyright (c) 2005, 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1989, 1993 34 * The Regents of the University of California. All rights reserved. 35 * (c) UNIX System Laboratories, Inc. 36 * All or some portions of this file are derived from material licensed 37 * to the University of California by American Telephone and Telegraph 38 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 39 * the permission of UNIX System Laboratories, Inc. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 3. Neither the name of the University nor the names of its contributors 50 * may be used to endorse or promote products derived from this software 51 * without specific prior written permission. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 * SUCH DAMAGE. 64 */ 65 66 /* 67 * VFS extended attribute support. 68 */ 69 70 #include <sys/cdefs.h> 71 __KERNEL_RCSID(0, "$NetBSD: vfs_xattr.c,v 1.29 2011/11/09 18:29:28 drochner Exp $"); 72 73 #include <sys/param.h> 74 #include <sys/systm.h> 75 #include <sys/namei.h> 76 #include <sys/filedesc.h> 77 #include <sys/kernel.h> 78 #include <sys/file.h> 79 #include <sys/vnode.h> 80 #include <sys/mount.h> 81 #include <sys/proc.h> 82 #include <sys/uio.h> 83 #include <sys/extattr.h> 84 #include <sys/xattr.h> 85 #include <sys/sysctl.h> 86 #include <sys/syscallargs.h> 87 #include <sys/kauth.h> 88 #include <sys/ktrace.h> 89 90 /* 91 * Credential check based on process requesting service, and per-attribute 92 * permissions. 93 * 94 * NOTE: Vnode must be locked. 95 */ 96 int 97 extattr_check_cred(struct vnode *vp, int attrnamespace, 98 kauth_cred_t cred, struct lwp *l, int access) 99 { 100 101 if (cred == NOCRED) 102 return (0); 103 104 switch (attrnamespace) { 105 case EXTATTR_NAMESPACE_SYSTEM: 106 /* 107 * Do we really want to allow this, or just require that 108 * these requests come from kernel code (NOCRED case above)? 109 */ 110 return (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, 111 NULL)); 112 113 case EXTATTR_NAMESPACE_USER: 114 return (VOP_ACCESS(vp, access, cred)); 115 116 default: 117 return (EPERM); 118 } 119 } 120 121 /* 122 * Default vfs_extattrctl routine for file systems that do not support 123 * it. 124 */ 125 /*ARGSUSED*/ 126 int 127 vfs_stdextattrctl(struct mount *mp, int cmt, struct vnode *vp, 128 int attrnamespace, const char *attrname) 129 { 130 131 if (vp != NULL) 132 VOP_UNLOCK(vp); 133 return (EOPNOTSUPP); 134 } 135 136 /* 137 * Push extended attribute configuration information into the file 138 * system. 139 * 140 * NOTE: Not all file systems that support extended attributes will 141 * require the use of this system call. 142 */ 143 int 144 sys_extattrctl(struct lwp *l, const struct sys_extattrctl_args *uap, register_t *retval) 145 { 146 /* { 147 syscallarg(const char *) path; 148 syscallarg(int) cmd; 149 syscallarg(const char *) filename; 150 syscallarg(int) attrnamespace; 151 syscallarg(const char *) attrname; 152 } */ 153 struct vnode *path_vp, *file_vp; 154 struct pathbuf *file_pb; 155 struct nameidata file_nd; 156 char attrname[EXTATTR_MAXNAMELEN]; 157 int error; 158 159 if (SCARG(uap, attrname) != NULL) { 160 error = copyinstr(SCARG(uap, attrname), attrname, 161 sizeof(attrname), NULL); 162 if (error) 163 return (error); 164 } 165 166 error = namei_simple_user(SCARG(uap, path), 167 NSM_FOLLOW_NOEMULROOT, &path_vp); 168 if (error) { 169 return (error); 170 } 171 172 file_vp = NULL; 173 if (SCARG(uap, filename) != NULL) { 174 error = pathbuf_copyin(SCARG(uap, filename), &file_pb); 175 if (error) { 176 vrele(path_vp); 177 return (error); 178 } 179 NDINIT(&file_nd, LOOKUP, FOLLOW | LOCKLEAF, file_pb); 180 error = namei(&file_nd); 181 if (error) { 182 pathbuf_destroy(file_pb); 183 vrele(path_vp); 184 return (error); 185 } 186 file_vp = file_nd.ni_vp; 187 pathbuf_destroy(file_pb); 188 } 189 190 error = VFS_EXTATTRCTL(path_vp->v_mount, SCARG(uap, cmd), file_vp, 191 SCARG(uap, attrnamespace), 192 SCARG(uap, attrname) != NULL ? attrname : NULL); 193 194 if (file_vp != NULL) 195 vrele(file_vp); 196 vrele(path_vp); 197 198 return (error); 199 } 200 201 /***************************************************************************** 202 * Internal routines to manipulate file system extended attributes: 203 * - set 204 * - get 205 * - delete 206 * - list 207 *****************************************************************************/ 208 209 /* 210 * extattr_set_vp: 211 * 212 * Set a named extended attribute on a file or directory. 213 */ 214 static int 215 extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname, 216 const void *data, size_t nbytes, struct lwp *l, register_t *retval, 217 int flag) 218 { 219 struct uio auio; 220 struct iovec aiov; 221 ssize_t cnt; 222 int error; 223 224 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 225 226 if (flag) { 227 size_t attrlen; 228 229 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, NULL, 230 &attrlen, l->l_cred); 231 232 switch (error) { 233 case ENOATTR: 234 if (flag & XATTR_REPLACE) 235 goto done; 236 break; 237 case 0: 238 if (flag & XATTR_CREATE) { 239 error = EEXIST; 240 goto done; 241 } 242 break; 243 default: 244 goto done; 245 break; 246 } 247 } 248 249 aiov.iov_base = __UNCONST(data); /* XXXUNCONST kills const */ 250 aiov.iov_len = nbytes; 251 auio.uio_iov = &aiov; 252 auio.uio_iovcnt = 1; 253 auio.uio_offset = 0; 254 if (nbytes > INT_MAX) { 255 error = EINVAL; 256 goto done; 257 } 258 auio.uio_resid = nbytes; 259 auio.uio_rw = UIO_WRITE; 260 KASSERT(l == curlwp); 261 auio.uio_vmspace = l->l_proc->p_vmspace; 262 cnt = nbytes; 263 264 ktrkuser("xattr-name", (void *)__UNCONST(attrname), strlen(attrname)); 265 ktrkuser("xattr-val", __UNCONST(data), nbytes); 266 267 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio, l->l_cred); 268 cnt -= auio.uio_resid; 269 retval[0] = cnt; 270 271 done: 272 VOP_UNLOCK(vp); 273 return (error); 274 } 275 276 /* 277 * extattr_get_vp: 278 * 279 * Get a named extended attribute on a file or directory. 280 */ 281 static int 282 extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname, 283 void *data, size_t nbytes, struct lwp *l, register_t *retval) 284 { 285 struct uio auio, *auiop; 286 struct iovec aiov; 287 ssize_t cnt; 288 size_t size, *sizep; 289 int error; 290 291 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 292 293 /* 294 * Slightly unusual semantics: if the user provides a NULL data 295 * pointer, they don't want to receive the data, just the maximum 296 * read length. 297 */ 298 auiop = NULL; 299 sizep = NULL; 300 cnt = 0; 301 if (data != NULL) { 302 aiov.iov_base = data; 303 aiov.iov_len = nbytes; 304 auio.uio_iov = &aiov; 305 auio.uio_offset = 0; 306 if (nbytes > INT_MAX) { 307 error = EINVAL; 308 goto done; 309 } 310 auio.uio_resid = nbytes; 311 auio.uio_rw = UIO_READ; 312 KASSERT(l == curlwp); 313 auio.uio_vmspace = l->l_proc->p_vmspace; 314 auiop = &auio; 315 cnt = nbytes; 316 } else 317 sizep = &size; 318 319 ktrkuser("xattr-name", (void *)__UNCONST(attrname), strlen(attrname)); 320 321 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep, 322 l->l_cred); 323 324 if (auiop != NULL) { 325 cnt -= auio.uio_resid; 326 retval[0] = cnt; 327 328 ktrkuser("xattr-val", data, cnt); 329 } else 330 retval[0] = size; 331 332 done: 333 VOP_UNLOCK(vp); 334 return (error); 335 } 336 337 /* 338 * extattr_delete_vp: 339 * 340 * Delete a named extended attribute on a file or directory. 341 */ 342 static int 343 extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname, 344 struct lwp *l) 345 { 346 int error; 347 348 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 349 350 ktrkuser("xattr-name", (void *)__UNCONST(attrname), strlen(attrname)); 351 352 error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, l->l_cred); 353 if (error == EOPNOTSUPP) 354 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL, 355 l->l_cred); 356 357 VOP_UNLOCK(vp); 358 return (error); 359 } 360 361 /* 362 * extattr_list_vp: 363 * 364 * Retrieve a list of extended attributes on a file or directory. 365 */ 366 static int 367 extattr_list_vp(struct vnode *vp, int attrnamespace, void *data, size_t nbytes, 368 int flag, struct lwp *l, register_t *retval) 369 { 370 struct uio auio, *auiop; 371 size_t size, *sizep; 372 struct iovec aiov; 373 ssize_t cnt; 374 int error; 375 376 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 377 378 auiop = NULL; 379 sizep = NULL; 380 cnt = 0; 381 if (data != NULL) { 382 aiov.iov_base = data; 383 aiov.iov_len = nbytes; 384 auio.uio_iov = &aiov; 385 auio.uio_offset = 0; 386 if (nbytes > INT_MAX) { 387 error = EINVAL; 388 goto done; 389 } 390 auio.uio_resid = nbytes; 391 auio.uio_rw = UIO_READ; 392 KASSERT(l == curlwp); 393 auio.uio_vmspace = l->l_proc->p_vmspace; 394 auiop = &auio; 395 cnt = nbytes; 396 } else 397 sizep = &size; 398 399 error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep, 400 flag, l->l_cred); 401 402 if (auiop != NULL) { 403 cnt -= auio.uio_resid; 404 retval[0] = cnt; 405 406 ktrkuser("xattr-list", data, cnt); 407 } else 408 retval[0] = size; 409 410 done: 411 VOP_UNLOCK(vp); 412 return (error); 413 } 414 415 /***************************************************************************** 416 * BSD <sys/extattr.h> API for file system extended attributes 417 *****************************************************************************/ 418 419 int 420 sys_extattr_set_fd(struct lwp *l, const struct sys_extattr_set_fd_args *uap, register_t *retval) 421 { 422 /* { 423 syscallarg(int) fd; 424 syscallarg(int) attrnamespace; 425 syscallarg(const char *) attrname; 426 syscallarg(const void *) data; 427 syscallarg(size_t) nbytes; 428 } */ 429 struct file *fp; 430 struct vnode *vp; 431 char attrname[EXTATTR_MAXNAMELEN]; 432 int error; 433 434 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 435 NULL); 436 if (error) 437 return (error); 438 439 error = fd_getvnode(SCARG(uap, fd), &fp); 440 if (error) 441 return (error); 442 vp = (struct vnode *) fp->f_data; 443 444 error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname, 445 SCARG(uap, data), SCARG(uap, nbytes), l, retval, 0); 446 447 fd_putfile(SCARG(uap, fd)); 448 return (error); 449 } 450 451 int 452 sys_extattr_set_file(struct lwp *l, const struct sys_extattr_set_file_args *uap, register_t *retval) 453 { 454 /* { 455 syscallarg(const char *) path; 456 syscallarg(int) attrnamespace; 457 syscallarg(const char *) attrname; 458 syscallarg(const void *) data; 459 syscallarg(size_t) nbytes; 460 } */ 461 struct vnode *vp; 462 char attrname[EXTATTR_MAXNAMELEN]; 463 int error; 464 465 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 466 NULL); 467 if (error) 468 return (error); 469 470 error = namei_simple_user(SCARG(uap, path), 471 NSM_FOLLOW_NOEMULROOT, &vp); 472 if (error) 473 return (error); 474 475 error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname, 476 SCARG(uap, data), SCARG(uap, nbytes), l, retval, 0); 477 478 vrele(vp); 479 return (error); 480 } 481 482 int 483 sys_extattr_set_link(struct lwp *l, const struct sys_extattr_set_link_args *uap, register_t *retval) 484 { 485 /* { 486 syscallarg(const char *) path; 487 syscallarg(int) attrnamespace; 488 syscallarg(const char *) attrname; 489 syscallarg(const void *) data; 490 syscallarg(size_t) nbytes; 491 } */ 492 struct vnode *vp; 493 char attrname[EXTATTR_MAXNAMELEN]; 494 int error; 495 496 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 497 NULL); 498 if (error) 499 return (error); 500 501 error = namei_simple_user(SCARG(uap, path), 502 NSM_NOFOLLOW_NOEMULROOT, &vp); 503 if (error) 504 return (error); 505 506 error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname, 507 SCARG(uap, data), SCARG(uap, nbytes), l, retval, 0); 508 509 vrele(vp); 510 return (error); 511 } 512 513 int 514 sys_extattr_get_fd(struct lwp *l, const struct sys_extattr_get_fd_args *uap, register_t *retval) 515 { 516 /* { 517 syscallarg(int) fd; 518 syscallarg(int) attrnamespace; 519 syscallarg(const char *) attrname; 520 syscallarg(void *) data; 521 syscallarg(size_t) nbytes; 522 } */ 523 struct file *fp; 524 struct vnode *vp; 525 char attrname[EXTATTR_MAXNAMELEN]; 526 int error; 527 528 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 529 NULL); 530 if (error) 531 return (error); 532 533 error = fd_getvnode(SCARG(uap, fd), &fp); 534 if (error) 535 return (error); 536 vp = (struct vnode *) fp->f_data; 537 538 error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname, 539 SCARG(uap, data), SCARG(uap, nbytes), l, retval); 540 541 fd_putfile(SCARG(uap, fd)); 542 return (error); 543 } 544 545 int 546 sys_extattr_get_file(struct lwp *l, const struct sys_extattr_get_file_args *uap, register_t *retval) 547 { 548 /* { 549 syscallarg(const char *) path; 550 syscallarg(int) attrnamespace; 551 syscallarg(const char *) attrname; 552 syscallarg(void *) data; 553 syscallarg(size_t) nbytes; 554 } */ 555 struct vnode *vp; 556 char attrname[EXTATTR_MAXNAMELEN]; 557 int error; 558 559 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 560 NULL); 561 if (error) 562 return (error); 563 564 error = namei_simple_user(SCARG(uap, path), 565 NSM_FOLLOW_NOEMULROOT, &vp); 566 if (error) 567 return (error); 568 569 error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname, 570 SCARG(uap, data), SCARG(uap, nbytes), l, retval); 571 572 vrele(vp); 573 return (error); 574 } 575 576 int 577 sys_extattr_get_link(struct lwp *l, const struct sys_extattr_get_link_args *uap, register_t *retval) 578 { 579 /* { 580 syscallarg(const char *) path; 581 syscallarg(int) attrnamespace; 582 syscallarg(const char *) attrname; 583 syscallarg(void *) data; 584 syscallarg(size_t) nbytes; 585 } */ 586 struct vnode *vp; 587 char attrname[EXTATTR_MAXNAMELEN]; 588 int error; 589 590 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 591 NULL); 592 if (error) 593 return (error); 594 595 error = namei_simple_user(SCARG(uap, path), 596 NSM_NOFOLLOW_NOEMULROOT, &vp); 597 if (error) 598 return (error); 599 600 error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname, 601 SCARG(uap, data), SCARG(uap, nbytes), l, retval); 602 603 vrele(vp); 604 return (error); 605 } 606 607 int 608 sys_extattr_delete_fd(struct lwp *l, const struct sys_extattr_delete_fd_args *uap, register_t *retval) 609 { 610 /* { 611 syscallarg(int) fd; 612 syscallarg(int) attrnamespace; 613 syscallarg(const char *) attrname; 614 } */ 615 struct file *fp; 616 struct vnode *vp; 617 char attrname[EXTATTR_MAXNAMELEN]; 618 int error; 619 620 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 621 NULL); 622 if (error) 623 return (error); 624 625 error = fd_getvnode(SCARG(uap, fd), &fp); 626 if (error) 627 return (error); 628 vp = (struct vnode *) fp->f_data; 629 630 error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l); 631 632 fd_putfile(SCARG(uap, fd)); 633 return (error); 634 } 635 636 int 637 sys_extattr_delete_file(struct lwp *l, const struct sys_extattr_delete_file_args *uap, register_t *retval) 638 { 639 /* { 640 syscallarg(const char *) path; 641 syscallarg(int) attrnamespace; 642 syscallarg(const char *) attrname; 643 } */ 644 struct vnode *vp; 645 char attrname[EXTATTR_MAXNAMELEN]; 646 int error; 647 648 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 649 NULL); 650 if (error) 651 return (error); 652 653 error = namei_simple_user(SCARG(uap, path), 654 NSM_FOLLOW_NOEMULROOT, &vp); 655 if (error) 656 return (error); 657 658 error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l); 659 660 vrele(vp); 661 return (error); 662 } 663 664 int 665 sys_extattr_delete_link(struct lwp *l, const struct sys_extattr_delete_link_args *uap, register_t *retval) 666 { 667 /* { 668 syscallarg(const char *) path; 669 syscallarg(int) attrnamespace; 670 syscallarg(const char *) attrname; 671 } */ 672 struct vnode *vp; 673 char attrname[EXTATTR_MAXNAMELEN]; 674 int error; 675 676 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname), 677 NULL); 678 if (error) 679 return (error); 680 681 error = namei_simple_user(SCARG(uap, path), 682 NSM_NOFOLLOW_NOEMULROOT, &vp); 683 if (error) 684 return (error); 685 686 error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l); 687 688 vrele(vp); 689 return (error); 690 } 691 692 int 693 sys_extattr_list_fd(struct lwp *l, const struct sys_extattr_list_fd_args *uap, register_t *retval) 694 { 695 /* { 696 syscallarg(int) fd; 697 syscallarg(int) attrnamespace; 698 syscallarg(void *) data; 699 syscallarg(size_t) nbytes; 700 } */ 701 struct file *fp; 702 struct vnode *vp; 703 int error; 704 705 error = fd_getvnode(SCARG(uap, fd), &fp); 706 if (error) 707 return (error); 708 vp = (struct vnode *) fp->f_data; 709 710 error = extattr_list_vp(vp, SCARG(uap, attrnamespace), 711 SCARG(uap, data), SCARG(uap, nbytes), 712 EXTATTR_LIST_LENPREFIX, l, retval); 713 714 fd_putfile(SCARG(uap, fd)); 715 return (error); 716 } 717 718 int 719 sys_extattr_list_file(struct lwp *l, const struct sys_extattr_list_file_args *uap, register_t *retval) 720 { 721 /* { 722 syscallarg(const char *) path; 723 syscallarg(int) attrnamespace; 724 syscallarg(void *) data; 725 syscallarg(size_t) nbytes; 726 } */ 727 struct vnode *vp; 728 int error; 729 730 error = namei_simple_user(SCARG(uap, path), 731 NSM_FOLLOW_NOEMULROOT, &vp); 732 if (error) 733 return (error); 734 735 error = extattr_list_vp(vp, SCARG(uap, attrnamespace), 736 SCARG(uap, data), SCARG(uap, nbytes), 737 EXTATTR_LIST_LENPREFIX, l, retval); 738 739 vrele(vp); 740 return (error); 741 } 742 743 int 744 sys_extattr_list_link(struct lwp *l, const struct sys_extattr_list_link_args *uap, register_t *retval) 745 { 746 /* { 747 syscallarg(const char *) path; 748 syscallarg(int) attrnamespace; 749 syscallarg(void *) data; 750 syscallarg(size_t) nbytes; 751 } */ 752 struct vnode *vp; 753 int error; 754 755 error = namei_simple_user(SCARG(uap, path), 756 NSM_NOFOLLOW_NOEMULROOT, &vp); 757 if (error) 758 return (error); 759 760 error = extattr_list_vp(vp, SCARG(uap, attrnamespace), 761 SCARG(uap, data), SCARG(uap, nbytes), 762 EXTATTR_LIST_LENPREFIX, l, retval); 763 764 vrele(vp); 765 return (error); 766 } 767 768 /***************************************************************************** 769 * Linux-compatible <sys/xattr.h> API for file system extended attributes 770 *****************************************************************************/ 771 772 #define MATCH_NS(ns, key) (strncmp(ns, key, sizeof(ns) - 1) == 0) 773 static int 774 xattr_native(const char *key) { 775 if (MATCH_NS("system.", key)) 776 return EXTATTR_NAMESPACE_SYSTEM; 777 else if (MATCH_NS("user.", key)) 778 return EXTATTR_NAMESPACE_USER; 779 else if (MATCH_NS("security.", key)) 780 return EXTATTR_NAMESPACE_SYSTEM; 781 else if (MATCH_NS("trusted.", key)) 782 return EXTATTR_NAMESPACE_SYSTEM; 783 else 784 return EXTATTR_NAMESPACE_USER; 785 786 } 787 #undef MATCH_NS 788 789 #define XATTR_ERRNO(e) ((e) == EOPNOTSUPP ? ENOTSUP : (e)) 790 791 int 792 sys_setxattr(struct lwp *l, const struct sys_setxattr_args *uap, register_t *retval) 793 { 794 /* { 795 syscallarg(const char *) path; 796 syscallarg(const char *) name; 797 syscallarg(void *) value; 798 syscallarg(size_t) size; 799 syscallarg(int) flags; 800 } */ 801 struct vnode *vp; 802 char attrname[XATTR_NAME_MAX]; 803 int namespace; 804 register_t attrlen; 805 int error; 806 807 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 808 NULL); 809 if (error) 810 goto out; 811 812 error = namei_simple_user(SCARG(uap, path), 813 NSM_FOLLOW_NOEMULROOT, &vp); 814 if (error) 815 goto out; 816 817 namespace = xattr_native(attrname); 818 819 error = extattr_set_vp(vp, namespace, 820 attrname, SCARG(uap, value), SCARG(uap, size), l, 821 &attrlen, SCARG(uap, flags)); 822 823 vrele(vp); 824 out: 825 *retval = (error == 0) ? 0 : -1; 826 return (XATTR_ERRNO(error)); 827 } 828 829 int 830 sys_lsetxattr(struct lwp *l, const struct sys_lsetxattr_args *uap, register_t *retval) 831 { 832 /* { 833 syscallarg(const char *) path; 834 syscallarg(const char *) name; 835 syscallarg(void *) value; 836 syscallarg(size_t) size; 837 syscallarg(int) flags; 838 } */ 839 struct vnode *vp; 840 char attrname[XATTR_NAME_MAX]; 841 int namespace; 842 register_t attrlen; 843 int error; 844 845 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 846 NULL); 847 if (error) 848 goto out; 849 850 error = namei_simple_user(SCARG(uap, path), 851 NSM_NOFOLLOW_NOEMULROOT, &vp); 852 if (error) 853 goto out; 854 855 namespace = xattr_native(attrname); 856 857 error = extattr_set_vp(vp, namespace, 858 attrname, SCARG(uap, value), SCARG(uap, size), l, 859 &attrlen, SCARG(uap, flags)); 860 861 vrele(vp); 862 out: 863 *retval = (error == 0) ? 0 : -1; 864 return (XATTR_ERRNO(error)); 865 } 866 867 int 868 sys_fsetxattr(struct lwp *l, const struct sys_fsetxattr_args *uap, register_t *retval) 869 { 870 /* { 871 syscallarg(int) fd; 872 syscallarg(const char *) name; 873 syscallarg(void *) value; 874 syscallarg(size_t) size; 875 syscallarg(int) flags; 876 } */ 877 struct file *fp; 878 struct vnode *vp; 879 char attrname[XATTR_NAME_MAX]; 880 int namespace; 881 register_t attrlen; 882 int error; 883 884 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 885 NULL); 886 if (error) 887 goto out; 888 889 error = fd_getvnode(SCARG(uap, fd), &fp); 890 if (error) 891 goto out; 892 vp = (struct vnode *) fp->f_data; 893 894 namespace = xattr_native(attrname); 895 896 error = extattr_set_vp(vp, namespace, 897 attrname, SCARG(uap, value), SCARG(uap, size), l, 898 &attrlen, SCARG(uap, flags)); 899 900 fd_putfile(SCARG(uap, fd)); 901 out: 902 *retval = (error == 0) ? 0 : -1; 903 return (XATTR_ERRNO(error)); 904 } 905 906 int 907 sys_getxattr(struct lwp *l, const struct sys_getxattr_args *uap, register_t *retval) 908 { 909 /* { 910 syscallarg(const char *) path; 911 syscallarg(const char *) name; 912 syscallarg(void *) value; 913 syscallarg(size_t) size; 914 } */ 915 struct vnode *vp; 916 char attrname[XATTR_NAME_MAX]; 917 int namespace; 918 int error; 919 920 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 921 NULL); 922 if (error) 923 return (error); 924 925 error = namei_simple_user(SCARG(uap, path), 926 NSM_FOLLOW_NOEMULROOT, &vp); 927 if (error) 928 return (error); 929 930 namespace = xattr_native(attrname); 931 932 error = extattr_get_vp(vp, namespace, 933 attrname, SCARG(uap, value), SCARG(uap, size), l, retval); 934 935 vrele(vp); 936 return (XATTR_ERRNO(error)); 937 } 938 939 int 940 sys_lgetxattr(struct lwp *l, const struct sys_lgetxattr_args *uap, register_t *retval) 941 { 942 /* { 943 syscallarg(const char *) path; 944 syscallarg(const char *) name; 945 syscallarg(void *) value; 946 syscallarg(size_t) size; 947 } */ 948 struct vnode *vp; 949 char attrname[XATTR_NAME_MAX]; 950 int namespace; 951 int error; 952 953 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 954 NULL); 955 if (error) 956 return (error); 957 958 error = namei_simple_user(SCARG(uap, path), 959 NSM_NOFOLLOW_NOEMULROOT, &vp); 960 if (error) 961 return (error); 962 963 namespace = xattr_native(attrname); 964 965 error = extattr_get_vp(vp, namespace, 966 attrname, SCARG(uap, value), SCARG(uap, size), l, retval); 967 968 vrele(vp); 969 return (XATTR_ERRNO(error)); 970 } 971 972 int 973 sys_fgetxattr(struct lwp *l, const struct sys_fgetxattr_args *uap, register_t *retval) 974 { 975 /* { 976 syscallarg(int) fd; 977 syscallarg(const char *) name; 978 syscallarg(void *) value; 979 syscallarg(size_t) size; 980 } */ 981 struct file *fp; 982 struct vnode *vp; 983 char attrname[XATTR_NAME_MAX]; 984 int namespace; 985 int error; 986 987 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 988 NULL); 989 if (error) 990 return (error); 991 992 error = fd_getvnode(SCARG(uap, fd), &fp); 993 if (error) 994 return (error); 995 vp = (struct vnode *) fp->f_data; 996 997 namespace = xattr_native(attrname); 998 999 error = extattr_get_vp(vp, namespace, 1000 attrname, SCARG(uap, value), SCARG(uap, size), l, retval); 1001 1002 fd_putfile(SCARG(uap, fd)); 1003 return (XATTR_ERRNO(error)); 1004 } 1005 1006 int 1007 sys_listxattr(struct lwp *l, const struct sys_listxattr_args *uap, register_t *retval) 1008 { 1009 /* { 1010 syscallarg(const char *) path; 1011 syscallarg(char *) list; 1012 syscallarg(size_t) size; 1013 } */ 1014 struct vnode *vp; 1015 char *list; 1016 size_t size; 1017 register_t listsize_usr, listsize_sys; 1018 int error; 1019 1020 error = namei_simple_user(SCARG(uap, path), 1021 NSM_FOLLOW_NOEMULROOT, &vp); 1022 if (error) 1023 return (error); 1024 1025 list = SCARG(uap, list); 1026 size = SCARG(uap, size); 1027 1028 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER, 1029 list, size, 0, l, &listsize_usr); 1030 if (error) 1031 goto out; 1032 1033 if (list) 1034 list += listsize_usr; 1035 if (size) 1036 size -= listsize_usr; 1037 1038 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM, 1039 list, size, 0, l, &listsize_sys); 1040 switch (error) { 1041 case EPERM: 1042 error = 0; /* Ignore and just skip system EA */ 1043 listsize_sys = 0; 1044 break; 1045 case 0: 1046 break; 1047 default: 1048 goto out; 1049 break; 1050 } 1051 1052 *retval = listsize_usr + listsize_sys; 1053 1054 out: 1055 vrele(vp); 1056 return (XATTR_ERRNO(error)); 1057 } 1058 1059 int 1060 sys_llistxattr(struct lwp *l, const struct sys_llistxattr_args *uap, register_t *retval) 1061 { 1062 /* { 1063 syscallarg(const char *) path; 1064 syscallarg(char *) list; 1065 syscallarg(size_t) size; 1066 } */ 1067 struct vnode *vp; 1068 char *list; 1069 size_t size; 1070 register_t listsize_usr, listsize_sys; 1071 int error; 1072 1073 error = namei_simple_user(SCARG(uap, path), 1074 NSM_NOFOLLOW_NOEMULROOT, &vp); 1075 if (error) 1076 return (error); 1077 1078 list = SCARG(uap, list); 1079 size = SCARG(uap, size); 1080 1081 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER, 1082 list, size, 0, l, &listsize_usr); 1083 if (error) 1084 goto out; 1085 if (list) 1086 list += listsize_usr; 1087 if (size) 1088 size -= listsize_usr; 1089 1090 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM, 1091 list, size, 0, l, &listsize_sys); 1092 switch (error) { 1093 case EPERM: 1094 error = 0; /* Ignore and just skip system EA */ 1095 listsize_sys = 0; 1096 break; 1097 case 0: 1098 break; 1099 default: 1100 goto out; 1101 break; 1102 } 1103 1104 *retval = listsize_usr + listsize_sys; 1105 out: 1106 vrele(vp); 1107 return (XATTR_ERRNO(error)); 1108 } 1109 1110 int 1111 sys_flistxattr(struct lwp *l, const struct sys_flistxattr_args *uap, register_t *retval) 1112 { 1113 /* { 1114 syscallarg(int) fd; 1115 syscallarg(char *) list; 1116 syscallarg(size_t) size; 1117 } */ 1118 struct file *fp; 1119 struct vnode *vp; 1120 char *list; 1121 size_t size; 1122 register_t listsize_usr, listsize_sys; 1123 int error; 1124 1125 error = fd_getvnode(SCARG(uap, fd), &fp); 1126 if (error) 1127 return (error); 1128 vp = (struct vnode *) fp->f_data; 1129 1130 list = SCARG(uap, list); 1131 size = SCARG(uap, size); 1132 1133 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER, 1134 list, size, 0, l, &listsize_usr); 1135 if (error) 1136 goto out; 1137 1138 if (list) 1139 list += listsize_usr; 1140 if (size) 1141 size -= listsize_usr; 1142 1143 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM, 1144 list, size, 0, l, &listsize_sys); 1145 switch (error) { 1146 case EPERM: 1147 error = 0; /* Ignore and just skip system EA */ 1148 listsize_sys = 0; 1149 break; 1150 case 0: 1151 break; 1152 default: 1153 goto out; 1154 break; 1155 } 1156 1157 *retval = listsize_usr + listsize_sys; 1158 out: 1159 1160 fd_putfile(SCARG(uap, fd)); 1161 return (XATTR_ERRNO(error)); 1162 } 1163 1164 int 1165 sys_removexattr(struct lwp *l, const struct sys_removexattr_args *uap, register_t *retval) 1166 { 1167 /* { 1168 syscallarg(const char *) path; 1169 syscallarg(const char *) name; 1170 } */ 1171 struct vnode *vp; 1172 char attrname[XATTR_NAME_MAX]; 1173 int namespace; 1174 int error; 1175 1176 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 1177 NULL); 1178 if (error) 1179 return (error); 1180 1181 error = namei_simple_user(SCARG(uap, path), 1182 NSM_FOLLOW_NOEMULROOT, &vp); 1183 if (error) 1184 return (error); 1185 1186 namespace = xattr_native(attrname); 1187 1188 error = extattr_delete_vp(vp, namespace, attrname, l); 1189 1190 vrele(vp); 1191 return (XATTR_ERRNO(error)); 1192 } 1193 1194 int 1195 sys_lremovexattr(struct lwp *l, const struct sys_lremovexattr_args *uap, register_t *retval) 1196 { 1197 /* { 1198 syscallarg(const char *) path; 1199 syscallarg(const char *) name; 1200 } */ 1201 struct vnode *vp; 1202 char attrname[XATTR_NAME_MAX]; 1203 int namespace; 1204 int error; 1205 1206 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 1207 NULL); 1208 if (error) 1209 return (error); 1210 1211 error = namei_simple_user(SCARG(uap, path), 1212 NSM_NOFOLLOW_NOEMULROOT, &vp); 1213 if (error) 1214 return (error); 1215 1216 namespace = xattr_native(attrname); 1217 1218 error = extattr_delete_vp(vp, namespace, attrname, l); 1219 1220 vrele(vp); 1221 return (XATTR_ERRNO(error)); 1222 } 1223 1224 int 1225 sys_fremovexattr(struct lwp *l, const struct sys_fremovexattr_args *uap, register_t *retval) 1226 { 1227 /* { 1228 syscallarg(int) fd; 1229 syscallarg(const char *) name; 1230 } */ 1231 struct file *fp; 1232 struct vnode *vp; 1233 char attrname[XATTR_NAME_MAX]; 1234 int namespace; 1235 int error; 1236 1237 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 1238 NULL); 1239 if (error) 1240 return (error); 1241 1242 error = fd_getvnode(SCARG(uap, fd), &fp); 1243 if (error) 1244 return (error); 1245 vp = (struct vnode *) fp->f_data; 1246 1247 namespace = xattr_native(attrname); 1248 1249 error = extattr_delete_vp(vp, namespace, attrname, l); 1250 1251 fd_putfile(SCARG(uap, fd)); 1252 return (XATTR_ERRNO(error)); 1253 } 1254