1 /* $NetBSD: vfs_xattr.c,v 1.28 2011/07/22 12:46:18 manu 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.28 2011/07/22 12:46:18 manu 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 int 790 sys_setxattr(struct lwp *l, const struct sys_setxattr_args *uap, register_t *retval) 791 { 792 /* { 793 syscallarg(const char *) path; 794 syscallarg(const char *) name; 795 syscallarg(void *) value; 796 syscallarg(size_t) size; 797 syscallarg(int) flags; 798 } */ 799 struct vnode *vp; 800 char attrname[XATTR_NAME_MAX]; 801 int namespace; 802 register_t attrlen; 803 int error; 804 805 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 806 NULL); 807 if (error) 808 goto out; 809 810 error = namei_simple_user(SCARG(uap, path), 811 NSM_FOLLOW_NOEMULROOT, &vp); 812 if (error) 813 goto out; 814 815 namespace = xattr_native(attrname); 816 817 error = extattr_set_vp(vp, namespace, 818 attrname, SCARG(uap, value), SCARG(uap, size), l, 819 &attrlen, SCARG(uap, flags)); 820 821 vrele(vp); 822 out: 823 *retval = (error == 0) ? 0 : -1; 824 return (error); 825 } 826 827 int 828 sys_lsetxattr(struct lwp *l, const struct sys_lsetxattr_args *uap, register_t *retval) 829 { 830 /* { 831 syscallarg(const char *) path; 832 syscallarg(const char *) name; 833 syscallarg(void *) value; 834 syscallarg(size_t) size; 835 syscallarg(int) flags; 836 } */ 837 struct vnode *vp; 838 char attrname[XATTR_NAME_MAX]; 839 int namespace; 840 register_t attrlen; 841 int error; 842 843 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 844 NULL); 845 if (error) 846 goto out; 847 848 error = namei_simple_user(SCARG(uap, path), 849 NSM_NOFOLLOW_NOEMULROOT, &vp); 850 if (error) 851 goto out; 852 853 namespace = xattr_native(attrname); 854 855 error = extattr_set_vp(vp, namespace, 856 attrname, SCARG(uap, value), SCARG(uap, size), l, 857 &attrlen, SCARG(uap, flags)); 858 859 vrele(vp); 860 out: 861 *retval = (error == 0) ? 0 : -1; 862 return (error); 863 } 864 865 int 866 sys_fsetxattr(struct lwp *l, const struct sys_fsetxattr_args *uap, register_t *retval) 867 { 868 /* { 869 syscallarg(int) fd; 870 syscallarg(const char *) name; 871 syscallarg(void *) value; 872 syscallarg(size_t) size; 873 syscallarg(int) flags; 874 } */ 875 struct file *fp; 876 struct vnode *vp; 877 char attrname[XATTR_NAME_MAX]; 878 int namespace; 879 register_t attrlen; 880 int error; 881 882 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 883 NULL); 884 if (error) 885 goto out; 886 887 error = fd_getvnode(SCARG(uap, fd), &fp); 888 if (error) 889 goto out; 890 vp = (struct vnode *) fp->f_data; 891 892 namespace = xattr_native(attrname); 893 894 error = extattr_set_vp(vp, namespace, 895 attrname, SCARG(uap, value), SCARG(uap, size), l, 896 &attrlen, SCARG(uap, flags)); 897 898 fd_putfile(SCARG(uap, fd)); 899 out: 900 *retval = (error == 0) ? 0 : -1; 901 return (error); 902 } 903 904 int 905 sys_getxattr(struct lwp *l, const struct sys_getxattr_args *uap, register_t *retval) 906 { 907 /* { 908 syscallarg(const char *) path; 909 syscallarg(const char *) name; 910 syscallarg(void *) value; 911 syscallarg(size_t) size; 912 } */ 913 struct vnode *vp; 914 char attrname[XATTR_NAME_MAX]; 915 int namespace; 916 int error; 917 918 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 919 NULL); 920 if (error) 921 return (error); 922 923 error = namei_simple_user(SCARG(uap, path), 924 NSM_FOLLOW_NOEMULROOT, &vp); 925 if (error) 926 return (error); 927 928 namespace = xattr_native(attrname); 929 930 error = extattr_get_vp(vp, namespace, 931 attrname, SCARG(uap, value), SCARG(uap, size), l, retval); 932 933 vrele(vp); 934 return (error); 935 } 936 937 int 938 sys_lgetxattr(struct lwp *l, const struct sys_lgetxattr_args *uap, register_t *retval) 939 { 940 /* { 941 syscallarg(const char *) path; 942 syscallarg(const char *) name; 943 syscallarg(void *) value; 944 syscallarg(size_t) size; 945 } */ 946 struct vnode *vp; 947 char attrname[XATTR_NAME_MAX]; 948 int namespace; 949 int error; 950 951 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 952 NULL); 953 if (error) 954 return (error); 955 956 error = namei_simple_user(SCARG(uap, path), 957 NSM_NOFOLLOW_NOEMULROOT, &vp); 958 if (error) 959 return (error); 960 961 namespace = xattr_native(attrname); 962 963 error = extattr_get_vp(vp, namespace, 964 attrname, SCARG(uap, value), SCARG(uap, size), l, retval); 965 966 vrele(vp); 967 return (error); 968 } 969 970 int 971 sys_fgetxattr(struct lwp *l, const struct sys_fgetxattr_args *uap, register_t *retval) 972 { 973 /* { 974 syscallarg(int) fd; 975 syscallarg(const char *) name; 976 syscallarg(void *) value; 977 syscallarg(size_t) size; 978 } */ 979 struct file *fp; 980 struct vnode *vp; 981 char attrname[XATTR_NAME_MAX]; 982 int namespace; 983 int error; 984 985 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 986 NULL); 987 if (error) 988 return (error); 989 990 error = fd_getvnode(SCARG(uap, fd), &fp); 991 if (error) 992 return (error); 993 vp = (struct vnode *) fp->f_data; 994 995 namespace = xattr_native(attrname); 996 997 error = extattr_get_vp(vp, namespace, 998 attrname, SCARG(uap, value), SCARG(uap, size), l, retval); 999 1000 fd_putfile(SCARG(uap, fd)); 1001 return (error); 1002 } 1003 1004 int 1005 sys_listxattr(struct lwp *l, const struct sys_listxattr_args *uap, register_t *retval) 1006 { 1007 /* { 1008 syscallarg(const char *) path; 1009 syscallarg(char *) list; 1010 syscallarg(size_t) size; 1011 } */ 1012 struct vnode *vp; 1013 char *list; 1014 size_t size; 1015 register_t listsize_usr, listsize_sys; 1016 int error; 1017 1018 error = namei_simple_user(SCARG(uap, path), 1019 NSM_FOLLOW_NOEMULROOT, &vp); 1020 if (error) 1021 return (error); 1022 1023 list = SCARG(uap, list); 1024 size = SCARG(uap, size); 1025 1026 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER, 1027 list, size, 0, l, &listsize_usr); 1028 if (error) 1029 goto out; 1030 1031 if (list) 1032 list += listsize_usr; 1033 if (size) 1034 size -= listsize_usr; 1035 1036 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM, 1037 list, size, 0, l, &listsize_sys); 1038 switch (error) { 1039 case EPERM: 1040 error = 0; /* Ignore and just skip system EA */ 1041 listsize_sys = 0; 1042 break; 1043 case 0: 1044 break; 1045 default: 1046 goto out; 1047 break; 1048 } 1049 1050 *retval = listsize_usr + listsize_sys; 1051 1052 out: 1053 vrele(vp); 1054 return (error); 1055 } 1056 1057 int 1058 sys_llistxattr(struct lwp *l, const struct sys_llistxattr_args *uap, register_t *retval) 1059 { 1060 /* { 1061 syscallarg(const char *) path; 1062 syscallarg(char *) list; 1063 syscallarg(size_t) size; 1064 } */ 1065 struct vnode *vp; 1066 char *list; 1067 size_t size; 1068 register_t listsize_usr, listsize_sys; 1069 int error; 1070 1071 error = namei_simple_user(SCARG(uap, path), 1072 NSM_NOFOLLOW_NOEMULROOT, &vp); 1073 if (error) 1074 return (error); 1075 1076 list = SCARG(uap, list); 1077 size = SCARG(uap, size); 1078 1079 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER, 1080 list, size, 0, l, &listsize_usr); 1081 if (error) 1082 goto out; 1083 if (list) 1084 list += listsize_usr; 1085 if (size) 1086 size -= listsize_usr; 1087 1088 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM, 1089 list, size, 0, l, &listsize_sys); 1090 switch (error) { 1091 case EPERM: 1092 error = 0; /* Ignore and just skip system EA */ 1093 listsize_sys = 0; 1094 break; 1095 case 0: 1096 break; 1097 default: 1098 goto out; 1099 break; 1100 } 1101 1102 *retval = listsize_usr + listsize_sys; 1103 out: 1104 vrele(vp); 1105 return (error); 1106 } 1107 1108 int 1109 sys_flistxattr(struct lwp *l, const struct sys_flistxattr_args *uap, register_t *retval) 1110 { 1111 /* { 1112 syscallarg(int) fd; 1113 syscallarg(char *) list; 1114 syscallarg(size_t) size; 1115 } */ 1116 struct file *fp; 1117 struct vnode *vp; 1118 char *list; 1119 size_t size; 1120 register_t listsize_usr, listsize_sys; 1121 int error; 1122 1123 error = fd_getvnode(SCARG(uap, fd), &fp); 1124 if (error) 1125 return (error); 1126 vp = (struct vnode *) fp->f_data; 1127 1128 list = SCARG(uap, list); 1129 size = SCARG(uap, size); 1130 1131 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER, 1132 list, size, 0, l, &listsize_usr); 1133 if (error) 1134 goto out; 1135 1136 if (list) 1137 list += listsize_usr; 1138 if (size) 1139 size -= listsize_usr; 1140 1141 error = extattr_list_vp(vp, EXTATTR_NAMESPACE_SYSTEM, 1142 list, size, 0, l, &listsize_sys); 1143 switch (error) { 1144 case EPERM: 1145 error = 0; /* Ignore and just skip system EA */ 1146 listsize_sys = 0; 1147 break; 1148 case 0: 1149 break; 1150 default: 1151 goto out; 1152 break; 1153 } 1154 1155 *retval = listsize_usr + listsize_sys; 1156 out: 1157 1158 fd_putfile(SCARG(uap, fd)); 1159 return (error); 1160 } 1161 1162 int 1163 sys_removexattr(struct lwp *l, const struct sys_removexattr_args *uap, register_t *retval) 1164 { 1165 /* { 1166 syscallarg(const char *) path; 1167 syscallarg(const char *) name; 1168 } */ 1169 struct vnode *vp; 1170 char attrname[XATTR_NAME_MAX]; 1171 int namespace; 1172 int error; 1173 1174 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 1175 NULL); 1176 if (error) 1177 return (error); 1178 1179 error = namei_simple_user(SCARG(uap, path), 1180 NSM_FOLLOW_NOEMULROOT, &vp); 1181 if (error) 1182 return (error); 1183 1184 namespace = xattr_native(attrname); 1185 1186 error = extattr_delete_vp(vp, namespace, attrname, l); 1187 1188 vrele(vp); 1189 return (error); 1190 } 1191 1192 int 1193 sys_lremovexattr(struct lwp *l, const struct sys_lremovexattr_args *uap, register_t *retval) 1194 { 1195 /* { 1196 syscallarg(const char *) path; 1197 syscallarg(const char *) name; 1198 } */ 1199 struct vnode *vp; 1200 char attrname[XATTR_NAME_MAX]; 1201 int namespace; 1202 int error; 1203 1204 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 1205 NULL); 1206 if (error) 1207 return (error); 1208 1209 error = namei_simple_user(SCARG(uap, path), 1210 NSM_NOFOLLOW_NOEMULROOT, &vp); 1211 if (error) 1212 return (error); 1213 1214 namespace = xattr_native(attrname); 1215 1216 error = extattr_delete_vp(vp, namespace, attrname, l); 1217 1218 vrele(vp); 1219 return (error); 1220 } 1221 1222 int 1223 sys_fremovexattr(struct lwp *l, const struct sys_fremovexattr_args *uap, register_t *retval) 1224 { 1225 /* { 1226 syscallarg(int) fd; 1227 syscallarg(const char *) name; 1228 } */ 1229 struct file *fp; 1230 struct vnode *vp; 1231 char attrname[XATTR_NAME_MAX]; 1232 int namespace; 1233 int error; 1234 1235 error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname), 1236 NULL); 1237 if (error) 1238 return (error); 1239 1240 error = fd_getvnode(SCARG(uap, fd), &fp); 1241 if (error) 1242 return (error); 1243 vp = (struct vnode *) fp->f_data; 1244 1245 namespace = xattr_native(attrname); 1246 1247 error = extattr_delete_vp(vp, namespace, attrname, l); 1248 1249 fd_putfile(SCARG(uap, fd)); 1250 return (error); 1251 } 1252