1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/param.h> 27 #include <sys/isa_defs.h> 28 #include <sys/types.h> 29 #include <sys/sysmacros.h> 30 #include <sys/cred.h> 31 #include <sys/systm.h> 32 #include <sys/errno.h> 33 #include <sys/fcntl.h> 34 #include <sys/pathname.h> 35 #include <sys/stat.h> 36 #include <sys/vfs.h> 37 #include <sys/acl.h> 38 #include <sys/file.h> 39 #include <sys/sunddi.h> 40 #include <sys/debug.h> 41 #include <sys/cmn_err.h> 42 #include <sys/vnode.h> 43 #include <sys/mode.h> 44 #include <sys/nvpair.h> 45 #include <sys/attr.h> 46 #include <sys/gfs.h> 47 #include <sys/mutex.h> 48 #include <fs/fs_subr.h> 49 #include <sys/kidmap.h> 50 51 typedef struct { 52 gfs_file_t gfs_private; 53 xattr_view_t xattr_view; 54 } xattr_file_t; 55 56 /* ARGSUSED */ 57 static int 58 xattr_file_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct) 59 { 60 xattr_file_t *np = (*vpp)->v_data; 61 62 if ((np->xattr_view == XATTR_VIEW_READONLY) && (flags & FWRITE)) 63 return (EACCES); 64 65 return (0); 66 } 67 68 /* ARGSUSED */ 69 static int 70 xattr_file_access(vnode_t *vp, int mode, int flags, cred_t *cr, 71 caller_context_t *ct) 72 { 73 xattr_file_t *np = vp->v_data; 74 75 if ((np->xattr_view == XATTR_VIEW_READONLY) && (mode & VWRITE)) 76 return (EACCES); 77 78 return (0); 79 } 80 81 /* ARGSUSED */ 82 static int 83 xattr_file_close(vnode_t *vp, int flags, int count, offset_t off, 84 cred_t *cr, caller_context_t *ct) 85 { 86 cleanlocks(vp, ddi_get_pid(), 0); 87 cleanshares(vp, ddi_get_pid()); 88 return (0); 89 } 90 91 static int 92 xattr_common_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct) 93 { 94 xattr_fid_t *xfidp; 95 vnode_t *pvp, *savevp; 96 int error; 97 uint16_t orig_len; 98 99 if (fidp->fid_len < XATTR_FIDSZ) { 100 fidp->fid_len = XATTR_FIDSZ; 101 return (ENOSPC); 102 } 103 104 savevp = pvp = gfs_file_parent(vp); 105 mutex_enter(&savevp->v_lock); 106 if (pvp->v_flag & V_XATTRDIR) { 107 pvp = gfs_file_parent(pvp); 108 } 109 mutex_exit(&savevp->v_lock); 110 111 xfidp = (xattr_fid_t *)fidp; 112 orig_len = fidp->fid_len; 113 fidp->fid_len = sizeof (xfidp->parent_fid); 114 115 error = VOP_FID(pvp, fidp, ct); 116 if (error) { 117 fidp->fid_len = orig_len; 118 return (error); 119 } 120 121 xfidp->parent_len = fidp->fid_len; 122 fidp->fid_len = XATTR_FIDSZ; 123 xfidp->dir_offset = gfs_file_inode(vp); 124 125 return (0); 126 } 127 128 /* ARGSUSED */ 129 static int 130 xattr_fill_nvlist(vnode_t *vp, xattr_view_t xattr_view, nvlist_t *nvlp, 131 cred_t *cr, caller_context_t *ct) 132 { 133 int error; 134 f_attr_t attr; 135 uint64_t fsid; 136 xvattr_t xvattr; 137 xoptattr_t *xoap; /* Pointer to optional attributes */ 138 vnode_t *ppvp; 139 const char *domain; 140 uint32_t rid; 141 142 xva_init(&xvattr); 143 144 if ((xoap = xva_getxoptattr(&xvattr)) == NULL) 145 return (EINVAL); 146 147 /* 148 * For detecting ephemeral uid/gid 149 */ 150 xvattr.xva_vattr.va_mask |= (AT_UID|AT_GID); 151 152 /* 153 * We need to access the real fs object. 154 * vp points to a GFS file; ppvp points to the real object. 155 */ 156 ppvp = gfs_file_parent(gfs_file_parent(vp)); 157 158 /* 159 * Iterate through the attrs associated with this view 160 */ 161 162 for (attr = 0; attr < F_ATTR_ALL; attr++) { 163 if (xattr_view != attr_to_xattr_view(attr)) { 164 continue; 165 } 166 167 switch (attr) { 168 case F_SYSTEM: 169 XVA_SET_REQ(&xvattr, XAT_SYSTEM); 170 break; 171 case F_READONLY: 172 XVA_SET_REQ(&xvattr, XAT_READONLY); 173 break; 174 case F_HIDDEN: 175 XVA_SET_REQ(&xvattr, XAT_HIDDEN); 176 break; 177 case F_ARCHIVE: 178 XVA_SET_REQ(&xvattr, XAT_ARCHIVE); 179 break; 180 case F_IMMUTABLE: 181 XVA_SET_REQ(&xvattr, XAT_IMMUTABLE); 182 break; 183 case F_APPENDONLY: 184 XVA_SET_REQ(&xvattr, XAT_APPENDONLY); 185 break; 186 case F_NOUNLINK: 187 XVA_SET_REQ(&xvattr, XAT_NOUNLINK); 188 break; 189 case F_OPAQUE: 190 XVA_SET_REQ(&xvattr, XAT_OPAQUE); 191 break; 192 case F_NODUMP: 193 XVA_SET_REQ(&xvattr, XAT_NODUMP); 194 break; 195 case F_AV_QUARANTINED: 196 XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED); 197 break; 198 case F_AV_MODIFIED: 199 XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED); 200 break; 201 case F_AV_SCANSTAMP: 202 if (ppvp->v_type == VREG) 203 XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP); 204 break; 205 case F_CRTIME: 206 XVA_SET_REQ(&xvattr, XAT_CREATETIME); 207 break; 208 case F_FSID: 209 fsid = (((uint64_t)vp->v_vfsp->vfs_fsid.val[0] << 32) | 210 (uint64_t)(vp->v_vfsp->vfs_fsid.val[1] & 211 0xffffffff)); 212 VERIFY(nvlist_add_uint64(nvlp, attr_to_name(attr), 213 fsid) == 0); 214 break; 215 default: 216 break; 217 } 218 } 219 220 error = VOP_GETATTR(ppvp, &xvattr.xva_vattr, 0, cr, ct); 221 if (error) 222 return (error); 223 224 /* 225 * Process all the optional attributes together here. Notice that 226 * xoap was set when the optional attribute bits were set above. 227 */ 228 if ((xvattr.xva_vattr.va_mask & AT_XVATTR) && xoap) { 229 if (XVA_ISSET_RTN(&xvattr, XAT_READONLY)) { 230 VERIFY(nvlist_add_boolean_value(nvlp, 231 attr_to_name(F_READONLY), 232 xoap->xoa_readonly) == 0); 233 } 234 if (XVA_ISSET_RTN(&xvattr, XAT_HIDDEN)) { 235 VERIFY(nvlist_add_boolean_value(nvlp, 236 attr_to_name(F_HIDDEN), 237 xoap->xoa_hidden) == 0); 238 } 239 if (XVA_ISSET_RTN(&xvattr, XAT_SYSTEM)) { 240 VERIFY(nvlist_add_boolean_value(nvlp, 241 attr_to_name(F_SYSTEM), 242 xoap->xoa_system) == 0); 243 } 244 if (XVA_ISSET_RTN(&xvattr, XAT_ARCHIVE)) { 245 VERIFY(nvlist_add_boolean_value(nvlp, 246 attr_to_name(F_ARCHIVE), 247 xoap->xoa_archive) == 0); 248 } 249 if (XVA_ISSET_RTN(&xvattr, XAT_IMMUTABLE)) { 250 VERIFY(nvlist_add_boolean_value(nvlp, 251 attr_to_name(F_IMMUTABLE), 252 xoap->xoa_immutable) == 0); 253 } 254 if (XVA_ISSET_RTN(&xvattr, XAT_NOUNLINK)) { 255 VERIFY(nvlist_add_boolean_value(nvlp, 256 attr_to_name(F_NOUNLINK), 257 xoap->xoa_nounlink) == 0); 258 } 259 if (XVA_ISSET_RTN(&xvattr, XAT_APPENDONLY)) { 260 VERIFY(nvlist_add_boolean_value(nvlp, 261 attr_to_name(F_APPENDONLY), 262 xoap->xoa_appendonly) == 0); 263 } 264 if (XVA_ISSET_RTN(&xvattr, XAT_NODUMP)) { 265 VERIFY(nvlist_add_boolean_value(nvlp, 266 attr_to_name(F_NODUMP), 267 xoap->xoa_nodump) == 0); 268 } 269 if (XVA_ISSET_RTN(&xvattr, XAT_OPAQUE)) { 270 VERIFY(nvlist_add_boolean_value(nvlp, 271 attr_to_name(F_OPAQUE), 272 xoap->xoa_opaque) == 0); 273 } 274 if (XVA_ISSET_RTN(&xvattr, XAT_AV_QUARANTINED)) { 275 VERIFY(nvlist_add_boolean_value(nvlp, 276 attr_to_name(F_AV_QUARANTINED), 277 xoap->xoa_av_quarantined) == 0); 278 } 279 if (XVA_ISSET_RTN(&xvattr, XAT_AV_MODIFIED)) { 280 VERIFY(nvlist_add_boolean_value(nvlp, 281 attr_to_name(F_AV_MODIFIED), 282 xoap->xoa_av_modified) == 0); 283 } 284 if (XVA_ISSET_RTN(&xvattr, XAT_AV_SCANSTAMP)) { 285 VERIFY(nvlist_add_uint8_array(nvlp, 286 attr_to_name(F_AV_SCANSTAMP), 287 xoap->xoa_av_scanstamp, 288 sizeof (xoap->xoa_av_scanstamp)) == 0); 289 } 290 if (XVA_ISSET_RTN(&xvattr, XAT_CREATETIME)) { 291 VERIFY(nvlist_add_uint64_array(nvlp, 292 attr_to_name(F_CRTIME), 293 (uint64_t *)&(xoap->xoa_createtime), 294 sizeof (xoap->xoa_createtime) / 295 sizeof (uint64_t)) == 0); 296 } 297 } 298 /* 299 * Check for optional ownersid/groupsid 300 */ 301 302 if (xvattr.xva_vattr.va_uid > MAXUID) { 303 nvlist_t *nvl_sid; 304 305 if (nvlist_alloc(&nvl_sid, NV_UNIQUE_NAME, KM_SLEEP)) 306 return (ENOMEM); 307 308 if (kidmap_getsidbyuid(crgetzone(cr), xvattr.xva_vattr.va_uid, 309 &domain, &rid) == 0) { 310 VERIFY(nvlist_add_string(nvl_sid, 311 SID_DOMAIN, domain) == 0); 312 VERIFY(nvlist_add_uint32(nvl_sid, SID_RID, rid) == 0); 313 VERIFY(nvlist_add_nvlist(nvlp, attr_to_name(F_OWNERSID), 314 nvl_sid) == 0); 315 } 316 nvlist_free(nvl_sid); 317 } 318 if (xvattr.xva_vattr.va_gid > MAXUID) { 319 nvlist_t *nvl_sid; 320 321 if (nvlist_alloc(&nvl_sid, NV_UNIQUE_NAME, KM_SLEEP)) 322 return (ENOMEM); 323 324 if (kidmap_getsidbygid(crgetzone(cr), xvattr.xva_vattr.va_gid, 325 &domain, &rid) == 0) { 326 VERIFY(nvlist_add_string(nvl_sid, 327 SID_DOMAIN, domain) == 0); 328 VERIFY(nvlist_add_uint32(nvl_sid, SID_RID, rid) == 0); 329 VERIFY(nvlist_add_nvlist(nvlp, attr_to_name(F_GROUPSID), 330 nvl_sid) == 0); 331 } 332 nvlist_free(nvl_sid); 333 } 334 335 return (0); 336 } 337 338 /* 339 * The size of a sysattr file is the size of the nvlist that will be 340 * returned by xattr_file_read(). A call to xattr_file_write() could 341 * change the size of that nvlist. That size is not stored persistently 342 * so xattr_fill_nvlist() calls VOP_GETATTR so that it can be calculated. 343 */ 344 static int 345 xattr_file_size(vnode_t *vp, xattr_view_t xattr_view, size_t *size, 346 cred_t *cr, caller_context_t *ct) 347 { 348 nvlist_t *nvl; 349 350 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP)) { 351 return (ENOMEM); 352 } 353 354 if (xattr_fill_nvlist(vp, xattr_view, nvl, cr, ct)) { 355 nvlist_free(nvl); 356 return (EFAULT); 357 } 358 359 VERIFY(nvlist_size(nvl, size, NV_ENCODE_XDR) == 0); 360 nvlist_free(nvl); 361 return (0); 362 } 363 364 /* ARGSUSED */ 365 static int 366 xattr_file_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, 367 caller_context_t *ct) 368 { 369 xattr_file_t *np = vp->v_data; 370 timestruc_t now; 371 size_t size; 372 int error; 373 vnode_t *pvp; 374 vattr_t pvattr; 375 376 vap->va_type = VREG; 377 vap->va_mode = MAKEIMODE(vap->va_type, 378 (np->xattr_view == XATTR_VIEW_READONLY ? 0444 : 0644)); 379 vap->va_nodeid = gfs_file_inode(vp); 380 vap->va_nlink = 1; 381 pvp = gfs_file_parent(vp); 382 (void) memset(&pvattr, 0, sizeof (pvattr)); 383 pvattr.va_mask = AT_CTIME|AT_MTIME; 384 error = VOP_GETATTR(pvp, &pvattr, flags, cr, ct); 385 if (error) { 386 return (error); 387 } 388 vap->va_ctime = pvattr.va_ctime; 389 vap->va_mtime = pvattr.va_mtime; 390 gethrestime(&now); 391 vap->va_atime = now; 392 vap->va_uid = 0; 393 vap->va_gid = 0; 394 vap->va_rdev = 0; 395 vap->va_blksize = DEV_BSIZE; 396 vap->va_seq = 0; 397 vap->va_fsid = vp->v_vfsp->vfs_dev; 398 error = xattr_file_size(vp, np->xattr_view, &size, cr, ct); 399 vap->va_size = size; 400 vap->va_nblocks = howmany(vap->va_size, vap->va_blksize); 401 return (error); 402 } 403 404 /* ARGSUSED */ 405 static int 406 xattr_file_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, 407 caller_context_t *ct) 408 { 409 xattr_file_t *np = vp->v_data; 410 xattr_view_t xattr_view = np->xattr_view; 411 char *buf; 412 size_t filesize; 413 nvlist_t *nvl; 414 int error; 415 416 /* 417 * Validate file offset and fasttrack empty reads 418 */ 419 if (uiop->uio_loffset < (offset_t)0) 420 return (EINVAL); 421 422 if (uiop->uio_resid == 0) 423 return (0); 424 425 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP)) 426 return (ENOMEM); 427 428 if (xattr_fill_nvlist(vp, xattr_view, nvl, cr, ct)) { 429 nvlist_free(nvl); 430 return (EFAULT); 431 } 432 433 VERIFY(nvlist_size(nvl, &filesize, NV_ENCODE_XDR) == 0); 434 435 if (uiop->uio_loffset >= filesize) { 436 nvlist_free(nvl); 437 return (0); 438 } 439 440 buf = kmem_alloc(filesize, KM_SLEEP); 441 VERIFY(nvlist_pack(nvl, &buf, &filesize, NV_ENCODE_XDR, 442 KM_SLEEP) == 0); 443 444 error = uiomove((caddr_t)buf, filesize, UIO_READ, uiop); 445 kmem_free(buf, filesize); 446 nvlist_free(nvl); 447 return (error); 448 } 449 450 /* ARGSUSED */ 451 static int 452 xattr_file_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, 453 caller_context_t *ct) 454 { 455 int error = 0; 456 char *buf; 457 char *domain; 458 uint32_t rid; 459 ssize_t size = uiop->uio_resid; 460 nvlist_t *nvp; 461 nvpair_t *pair = NULL; 462 vnode_t *ppvp; 463 xvattr_t xvattr; 464 xoptattr_t *xoap = NULL; /* Pointer to optional attributes */ 465 466 if (vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) == 0) 467 return (EINVAL); 468 469 /* 470 * Validate file offset and size. 471 */ 472 if (uiop->uio_loffset < (offset_t)0) 473 return (EINVAL); 474 475 if (size == 0) 476 return (EINVAL); 477 478 xva_init(&xvattr); 479 480 if ((xoap = xva_getxoptattr(&xvattr)) == NULL) { 481 return (EINVAL); 482 } 483 484 /* 485 * Copy and unpack the nvlist 486 */ 487 buf = kmem_alloc(size, KM_SLEEP); 488 if (uiomove((caddr_t)buf, size, UIO_WRITE, uiop)) { 489 return (EFAULT); 490 } 491 492 if (nvlist_unpack(buf, size, &nvp, KM_SLEEP) != 0) { 493 kmem_free(buf, size); 494 uiop->uio_resid = size; 495 return (EINVAL); 496 } 497 kmem_free(buf, size); 498 499 /* 500 * Fasttrack empty writes (nvlist with no nvpairs) 501 */ 502 if (nvlist_next_nvpair(nvp, NULL) == 0) 503 return (0); 504 505 ppvp = gfs_file_parent(gfs_file_parent(vp)); 506 507 while (pair = nvlist_next_nvpair(nvp, pair)) { 508 data_type_t type; 509 f_attr_t attr; 510 boolean_t value; 511 uint64_t *time, *times; 512 uint_t elem, nelems; 513 nvlist_t *nvp_sid; 514 uint8_t *scanstamp; 515 516 /* 517 * Validate the name and type of each attribute. 518 * Log any unknown names and continue. This will 519 * help if additional attributes are added later. 520 */ 521 type = nvpair_type(pair); 522 if ((attr = name_to_attr(nvpair_name(pair))) == F_ATTR_INVAL) { 523 cmn_err(CE_WARN, "Unknown attribute %s", 524 nvpair_name(pair)); 525 continue; 526 } 527 528 /* 529 * Verify nvlist type matches required type and view is OK 530 */ 531 532 if (type != attr_to_data_type(attr) || 533 (attr_to_xattr_view(attr) == XATTR_VIEW_READONLY)) { 534 nvlist_free(nvp); 535 return (EINVAL); 536 } 537 538 /* 539 * For OWNERSID/GROUPSID make sure the target 540 * file system support ephemeral ID's 541 */ 542 if ((attr == F_OWNERSID || attr == F_GROUPSID) && 543 (!(vp->v_vfsp->vfs_flag & VFS_XID))) { 544 nvlist_free(nvp); 545 return (EINVAL); 546 } 547 548 /* 549 * Retrieve data from nvpair 550 */ 551 switch (type) { 552 case DATA_TYPE_BOOLEAN_VALUE: 553 if (nvpair_value_boolean_value(pair, &value)) { 554 nvlist_free(nvp); 555 return (EINVAL); 556 } 557 break; 558 case DATA_TYPE_UINT64_ARRAY: 559 if (nvpair_value_uint64_array(pair, ×, &nelems)) { 560 nvlist_free(nvp); 561 return (EINVAL); 562 } 563 break; 564 case DATA_TYPE_NVLIST: 565 if (nvpair_value_nvlist(pair, &nvp_sid)) { 566 nvlist_free(nvp); 567 return (EINVAL); 568 } 569 break; 570 case DATA_TYPE_UINT8_ARRAY: 571 if (nvpair_value_uint8_array(pair, 572 &scanstamp, &nelems)) { 573 nvlist_free(nvp); 574 return (EINVAL); 575 } 576 break; 577 default: 578 nvlist_free(nvp); 579 return (EINVAL); 580 } 581 582 switch (attr) { 583 /* 584 * If we have several similar optional attributes to 585 * process then we should do it all together here so that 586 * xoap and the requested bitmap can be set in one place. 587 */ 588 case F_READONLY: 589 XVA_SET_REQ(&xvattr, XAT_READONLY); 590 xoap->xoa_readonly = value; 591 break; 592 case F_HIDDEN: 593 XVA_SET_REQ(&xvattr, XAT_HIDDEN); 594 xoap->xoa_hidden = value; 595 break; 596 case F_SYSTEM: 597 XVA_SET_REQ(&xvattr, XAT_SYSTEM); 598 xoap->xoa_system = value; 599 break; 600 case F_ARCHIVE: 601 XVA_SET_REQ(&xvattr, XAT_ARCHIVE); 602 xoap->xoa_archive = value; 603 break; 604 case F_IMMUTABLE: 605 XVA_SET_REQ(&xvattr, XAT_IMMUTABLE); 606 xoap->xoa_immutable = value; 607 break; 608 case F_NOUNLINK: 609 XVA_SET_REQ(&xvattr, XAT_NOUNLINK); 610 xoap->xoa_nounlink = value; 611 break; 612 case F_APPENDONLY: 613 XVA_SET_REQ(&xvattr, XAT_APPENDONLY); 614 xoap->xoa_appendonly = value; 615 break; 616 case F_NODUMP: 617 XVA_SET_REQ(&xvattr, XAT_NODUMP); 618 xoap->xoa_nodump = value; 619 break; 620 case F_AV_QUARANTINED: 621 XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED); 622 xoap->xoa_av_quarantined = value; 623 break; 624 case F_AV_MODIFIED: 625 XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED); 626 xoap->xoa_av_modified = value; 627 break; 628 case F_CRTIME: 629 XVA_SET_REQ(&xvattr, XAT_CREATETIME); 630 time = (uint64_t *)&(xoap->xoa_createtime); 631 for (elem = 0; elem < nelems; elem++) 632 *time++ = times[elem]; 633 break; 634 case F_OWNERSID: 635 case F_GROUPSID: 636 if (nvlist_lookup_string(nvp_sid, SID_DOMAIN, 637 &domain) || nvlist_lookup_uint32(nvp_sid, SID_RID, 638 &rid)) { 639 nvlist_free(nvp); 640 return (EINVAL); 641 } 642 643 /* 644 * Now map domain+rid to ephemeral id's 645 * 646 * If mapping fails, then the uid/gid will 647 * be set to UID_NOBODY by Winchester. 648 */ 649 650 if (attr == F_OWNERSID) { 651 (void) kidmap_getuidbysid(crgetzone(cr), domain, 652 rid, &xvattr.xva_vattr.va_uid); 653 xvattr.xva_vattr.va_mask |= AT_UID; 654 } else { 655 (void) kidmap_getgidbysid(crgetzone(cr), domain, 656 rid, &xvattr.xva_vattr.va_gid); 657 xvattr.xva_vattr.va_mask |= AT_GID; 658 } 659 break; 660 case F_AV_SCANSTAMP: 661 if (ppvp->v_type == VREG) { 662 XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP); 663 (void) memcpy(xoap->xoa_av_scanstamp, 664 scanstamp, nelems); 665 } else { 666 nvlist_free(nvp); 667 return (EINVAL); 668 } 669 break; 670 default: 671 break; 672 } 673 } 674 675 ppvp = gfs_file_parent(gfs_file_parent(vp)); 676 error = VOP_SETATTR(ppvp, &xvattr.xva_vattr, 0, cr, ct); 677 if (error) 678 uiop->uio_resid = size; 679 680 nvlist_free(nvp); 681 return (error); 682 } 683 684 static int 685 xattr_file_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr, 686 caller_context_t *ct) 687 { 688 switch (cmd) { 689 case _PC_XATTR_EXISTS: 690 case _PC_SATTR_ENABLED: 691 case _PC_SATTR_EXISTS: 692 *valp = 0; 693 return (0); 694 default: 695 return (fs_pathconf(vp, cmd, valp, cr, ct)); 696 } 697 } 698 699 vnodeops_t *xattr_file_ops; 700 701 static const fs_operation_def_t xattr_file_tops[] = { 702 { VOPNAME_OPEN, { .vop_open = xattr_file_open } }, 703 { VOPNAME_CLOSE, { .vop_close = xattr_file_close } }, 704 { VOPNAME_READ, { .vop_read = xattr_file_read } }, 705 { VOPNAME_WRITE, { .vop_write = xattr_file_write } }, 706 { VOPNAME_IOCTL, { .error = fs_ioctl } }, 707 { VOPNAME_GETATTR, { .vop_getattr = xattr_file_getattr } }, 708 { VOPNAME_ACCESS, { .vop_access = xattr_file_access } }, 709 { VOPNAME_READDIR, { .error = fs_notdir } }, 710 { VOPNAME_SEEK, { .vop_seek = fs_seek } }, 711 { VOPNAME_INACTIVE, { .vop_inactive = gfs_vop_inactive } }, 712 { VOPNAME_FID, { .vop_fid = xattr_common_fid } }, 713 { VOPNAME_PATHCONF, { .vop_pathconf = xattr_file_pathconf } }, 714 { VOPNAME_PUTPAGE, { .error = fs_putpage } }, 715 { VOPNAME_FSYNC, { .error = fs_fsync } }, 716 { NULL } 717 }; 718 719 vnode_t * 720 xattr_mkfile(vnode_t *pvp, xattr_view_t xattr_view) 721 { 722 vnode_t *vp; 723 xattr_file_t *np; 724 725 vp = gfs_file_create(sizeof (xattr_file_t), pvp, xattr_file_ops); 726 np = vp->v_data; 727 np->xattr_view = xattr_view; 728 vp->v_flag |= V_SYSATTR; 729 return (vp); 730 } 731 732 vnode_t * 733 xattr_mkfile_ro(vnode_t *pvp) 734 { 735 return (xattr_mkfile(pvp, XATTR_VIEW_READONLY)); 736 } 737 738 vnode_t * 739 xattr_mkfile_rw(vnode_t *pvp) 740 { 741 return (xattr_mkfile(pvp, XATTR_VIEW_READWRITE)); 742 } 743 744 vnodeops_t *xattr_dir_ops; 745 746 static gfs_dirent_t xattr_dirents[] = { 747 { VIEW_READONLY, xattr_mkfile_ro, GFS_CACHE_VNODE, }, 748 { VIEW_READWRITE, xattr_mkfile_rw, GFS_CACHE_VNODE, }, 749 { NULL }, 750 }; 751 752 #define XATTRDIR_NENTS ((sizeof (xattr_dirents) / sizeof (gfs_dirent_t)) - 1) 753 754 static int 755 is_sattr_name(char *s) 756 { 757 int i; 758 759 for (i = 0; i < XATTRDIR_NENTS; ++i) { 760 if (strcmp(s, xattr_dirents[i].gfse_name) == 0) { 761 return (1); 762 } 763 } 764 return (0); 765 } 766 767 /* 768 * Given the name of an extended attribute file, determine if there is a 769 * normalization conflict with a sysattr view name. 770 */ 771 int 772 xattr_sysattr_casechk(char *s) 773 { 774 int i; 775 776 for (i = 0; i < XATTRDIR_NENTS; ++i) { 777 if (strcasecmp(s, xattr_dirents[i].gfse_name) == 0) 778 return (1); 779 } 780 return (0); 781 } 782 783 static int 784 xattr_copy(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, 785 cred_t *cr, caller_context_t *ct) 786 { 787 xvattr_t xvattr; 788 vnode_t *pdvp; 789 int error; 790 791 /* 792 * Only copy system attrs if the views are the same 793 */ 794 if (strcmp(snm, tnm) != 0) 795 return (EINVAL); 796 797 xva_init(&xvattr); 798 799 XVA_SET_REQ(&xvattr, XAT_SYSTEM); 800 XVA_SET_REQ(&xvattr, XAT_READONLY); 801 XVA_SET_REQ(&xvattr, XAT_HIDDEN); 802 XVA_SET_REQ(&xvattr, XAT_ARCHIVE); 803 XVA_SET_REQ(&xvattr, XAT_APPENDONLY); 804 XVA_SET_REQ(&xvattr, XAT_NOUNLINK); 805 XVA_SET_REQ(&xvattr, XAT_IMMUTABLE); 806 XVA_SET_REQ(&xvattr, XAT_NODUMP); 807 XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED); 808 XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED); 809 XVA_SET_REQ(&xvattr, XAT_CREATETIME); 810 811 pdvp = gfs_file_parent(sdvp); 812 error = VOP_GETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct); 813 if (error) 814 return (error); 815 816 pdvp = gfs_file_parent(tdvp); 817 error = VOP_SETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct); 818 return (error); 819 } 820 821 static int 822 xattr_dir_realdir(vnode_t *dvp, vnode_t **realdvp, int lookup_flags, 823 cred_t *cr, caller_context_t *ct) 824 { 825 vnode_t *pvp; 826 int error; 827 struct pathname pn; 828 char *startnm = ""; 829 830 *realdvp = NULL; 831 832 pvp = gfs_file_parent(dvp); 833 834 error = pn_get(startnm, UIO_SYSSPACE, &pn); 835 if (error) { 836 VN_RELE(pvp); 837 return (error); 838 } 839 840 /* 841 * Set the LOOKUP_HAVE_SYSATTR_DIR flag so that we don't get into an 842 * infinite loop with fop_lookup calling back to xattr_dir_lookup. 843 */ 844 lookup_flags |= LOOKUP_HAVE_SYSATTR_DIR; 845 error = VOP_LOOKUP(pvp, startnm, realdvp, &pn, lookup_flags, 846 rootvp, cr, ct, NULL, NULL); 847 pn_free(&pn); 848 849 return (error); 850 } 851 852 /* ARGSUSED */ 853 static int 854 xattr_dir_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct) 855 { 856 if (flags & FWRITE) { 857 return (EACCES); 858 } 859 860 return (0); 861 } 862 863 /* ARGSUSED */ 864 static int 865 xattr_dir_close(vnode_t *vpp, int flags, int count, offset_t off, cred_t *cr, 866 caller_context_t *ct) 867 { 868 return (0); 869 } 870 871 /* ARGSUSED */ 872 static int 873 xattr_dir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, 874 caller_context_t *ct) 875 { 876 timestruc_t now; 877 vnode_t *pvp; 878 int error; 879 vattr_t pvattr; 880 881 error = xattr_dir_realdir(vp, &pvp, LOOKUP_XATTR, cr, ct); 882 if (error == 0) { 883 error = VOP_GETATTR(pvp, vap, 0, cr, ct); 884 VN_RELE(pvp); 885 if (error) { 886 return (error); 887 } 888 vap->va_nlink += XATTRDIR_NENTS; 889 vap->va_size += XATTRDIR_NENTS; 890 return (0); 891 } 892 893 /* 894 * There is no real xattr directory. Cobble together 895 * an entry using info from the parent object. 896 */ 897 pvp = gfs_file_parent(vp); 898 (void) memset(&pvattr, 0, sizeof (pvattr)); 899 pvattr.va_mask = AT_UID|AT_GID|AT_RDEV|AT_CTIME|AT_MTIME; 900 error = VOP_GETATTR(pvp, &pvattr, 0, cr, ct); 901 if (error) { 902 return (error); 903 } 904 *vap = pvattr; 905 vap->va_type = VDIR; 906 vap->va_mode = MAKEIMODE(vap->va_type, S_ISVTX | 0777); 907 vap->va_fsid = vp->v_vfsp->vfs_dev; 908 vap->va_nodeid = gfs_file_inode(vp); 909 vap->va_nlink = XATTRDIR_NENTS+2; 910 vap->va_size = vap->va_nlink; 911 gethrestime(&now); 912 vap->va_atime = now; 913 vap->va_blksize = 0; 914 vap->va_nblocks = 0; 915 vap->va_seq = 0; 916 return (0); 917 } 918 919 static int 920 xattr_dir_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, 921 caller_context_t *ct) 922 { 923 vnode_t *realvp; 924 int error; 925 926 /* 927 * If there is a real xattr directory, do the setattr there. 928 * Otherwise, just return success. The GFS directory is transient, 929 * and any setattr changes can disappear anyway. 930 */ 931 error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct); 932 if (error == 0) { 933 error = VOP_SETATTR(realvp, vap, flags, cr, ct); 934 VN_RELE(realvp); 935 } 936 if (error == ENOENT) { 937 error = 0; 938 } 939 return (error); 940 } 941 942 /* ARGSUSED */ 943 static int 944 xattr_dir_access(vnode_t *vp, int mode, int flags, cred_t *cr, 945 caller_context_t *ct) 946 { 947 int error; 948 vnode_t *realvp = NULL; 949 950 if (mode & VWRITE) { 951 return (EACCES); 952 } 953 954 error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct); 955 956 if (realvp) 957 VN_RELE(realvp); 958 959 /* 960 * No real xattr dir isn't an error 961 * an error of EINVAL indicates attributes on attributes 962 * are not supported. In that case just allow access to the 963 * transient directory. 964 */ 965 return ((error == ENOENT || error == EINVAL) ? 0 : error); 966 } 967 968 static int 969 xattr_dir_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl, 970 int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct, 971 vsecattr_t *vsecp) 972 { 973 vnode_t *pvp; 974 int error; 975 976 *vpp = NULL; 977 978 /* 979 * Don't allow creation of extended attributes with sysattr names. 980 */ 981 if (is_sattr_name(name)) { 982 return (gfs_dir_lookup(dvp, name, vpp, cr, 0, NULL, NULL)); 983 } 984 985 error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR|CREATE_XATTR_DIR, 986 cr, ct); 987 if (error == 0) { 988 error = VOP_CREATE(pvp, name, vap, excl, mode, vpp, cr, flag, 989 ct, vsecp); 990 VN_RELE(pvp); 991 } 992 return (error); 993 } 994 995 static int 996 xattr_dir_remove(vnode_t *dvp, char *name, cred_t *cr, caller_context_t *ct, 997 int flags) 998 { 999 vnode_t *pvp; 1000 int error; 1001 1002 if (is_sattr_name(name)) { 1003 return (EACCES); 1004 } 1005 1006 error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR, cr, ct); 1007 if (error == 0) { 1008 error = VOP_REMOVE(pvp, name, cr, ct, flags); 1009 VN_RELE(pvp); 1010 } 1011 return (error); 1012 } 1013 1014 static int 1015 xattr_dir_link(vnode_t *tdvp, vnode_t *svp, char *name,