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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/stat.h> 28 #include <sys/uio.h> 29 #include <sys/statvfs.h> 30 #include <sys/vnode.h> 31 #include <sys/thread.h> 32 #include <sys/pathname.h> 33 #include <sys/cred.h> 34 #include <sys/extdirent.h> 35 #include <sys/nbmlock.h> 36 #include <sys/share.h> 37 #include <sys/fcntl.h> 38 #include <nfs/lm.h> 39 40 #include <smbsrv/smb_vops.h> 41 #include <smbsrv/string.h> 42 43 #include <smbsrv/smb_fsops.h> 44 #include <smbsrv/smb_kproto.h> 45 #include <smbsrv/smb_incl.h> 46 47 static void smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr); 48 static void smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp); 49 static callb_cpr_t *smb_lock_frlock_callback(flk_cb_when_t, void *); 50 51 extern sysid_t lm_alloc_sysidt(); 52 53 #define SMB_AT_MAX 16 54 static uint_t smb_attrmap[SMB_AT_MAX] = { 55 0, 56 AT_TYPE, 57 AT_MODE, 58 AT_UID, 59 AT_GID, 60 AT_FSID, 61 AT_NODEID, 62 AT_NLINK, 63 AT_SIZE, 64 AT_ATIME, 65 AT_MTIME, 66 AT_CTIME, 67 AT_RDEV, 68 AT_BLKSIZE, 69 AT_NBLOCKS, 70 AT_SEQ 71 }; 72 73 static boolean_t smb_vop_initialized = B_FALSE; 74 caller_context_t smb_ct; 75 76 /* 77 * smb_vop_init 78 * 79 * This function is not multi-thread safe. The caller must make sure only one 80 * thread makes the call. 81 */ 82 int 83 smb_vop_init(void) 84 { 85 if (smb_vop_initialized) 86 return (0); 87 /* 88 * The caller_context will be used primarily for range locking. 89 * Since the CIFS server is mapping its locks to POSIX locks, 90 * only one pid is used for operations originating from the 91 * CIFS server (to represent CIFS in the VOP_FRLOCK routines). 92 */ 93 smb_ct.cc_sysid = lm_alloc_sysidt(); 94 if (smb_ct.cc_sysid == LM_NOSYSID) 95 return (ENOMEM); 96 97 smb_ct.cc_caller_id = fs_new_caller_id(); 98 smb_ct.cc_pid = IGN_PID; 99 smb_ct.cc_flags = 0; 100 101 smb_vop_initialized = B_TRUE; 102 return (0); 103 } 104 105 /* 106 * smb_vop_fini 107 * 108 * This function is not multi-thread safe. The caller must make sure only one 109 * thread makes the call. 110 */ 111 void 112 smb_vop_fini(void) 113 { 114 if (!smb_vop_initialized) 115 return; 116 117 lm_free_sysidt(smb_ct.cc_sysid); 118 smb_ct.cc_pid = IGN_PID; 119 smb_ct.cc_sysid = LM_NOSYSID; 120 smb_vop_initialized = B_FALSE; 121 } 122 123 /* 124 * The smb_ct will be used primarily for range locking. 125 * Since the CIFS server is mapping its locks to POSIX locks, 126 * only one pid is used for operations originating from the 127 * CIFS server (to represent CIFS in the VOP_FRLOCK routines). 128 */ 129 130 int 131 smb_vop_open(vnode_t **vpp, int mode, cred_t *cred) 132 { 133 return (VOP_OPEN(vpp, mode, cred, &smb_ct)); 134 } 135 136 void 137 smb_vop_close(vnode_t *vp, int mode, cred_t *cred) 138 { 139 (void) VOP_CLOSE(vp, mode, 1, (offset_t)0, cred, &smb_ct); 140 } 141 142 int 143 smb_vop_other_opens(vnode_t *vp, int mode) 144 { 145 return (((mode & FWRITE) && vn_has_other_opens(vp, V_WRITE)) || 146 (((mode & FWRITE) == 0) && vn_is_opened(vp, V_WRITE)) || 147 ((mode & FREAD) && vn_has_other_opens(vp, V_READ)) || 148 (((mode & FREAD) == 0) && vn_is_opened(vp, V_READ)) || 149 vn_is_mapped(vp, V_RDORWR)); 150 } 151 152 /* 153 * The smb_vop_* functions have minimal knowledge of CIFS semantics and 154 * serve as an interface to the VFS layer. 155 * 156 * Only smb_fsop_* layer functions should call smb_vop_* layer functions. 157 * (Higher-level CIFS service code should never skip the smb_fsop_* layer 158 * to call smb_vop_* layer functions directly.) 159 */ 160 161 /* 162 * XXX - Extended attributes support in the file system assumed. 163 * This is needed for full NT Streams functionality. 164 */ 165 166 int 167 smb_vop_read(vnode_t *vp, uio_t *uiop, cred_t *cr) 168 { 169 int error; 170 171 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &smb_ct); 172 error = VOP_READ(vp, uiop, 0, cr, &smb_ct); 173 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &smb_ct); 174 return (error); 175 } 176 177 int 178 smb_vop_write(vnode_t *vp, uio_t *uiop, int ioflag, uint32_t *lcount, 179 cred_t *cr) 180 { 181 int error; 182 183 *lcount = uiop->uio_resid; 184 185 uiop->uio_llimit = MAXOFFSET_T; 186 187 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &smb_ct); 188 error = VOP_WRITE(vp, uiop, ioflag, cr, &smb_ct); 189 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &smb_ct); 190 191 *lcount -= uiop->uio_resid; 192 193 return (error); 194 } 195 196 /* 197 * smb_vop_getattr() 198 * 199 * smb_fsop_getattr()/smb_vop_getattr() should always be called from the CIFS 200 * service (instead of calling VOP_GETATTR directly) to retrieve attributes 201 * due to special processing needed for streams files. 202 * 203 * All attributes are retrieved. 204 * 205 * When vp denotes a named stream, then unnamed_vp should be passed in (denoting 206 * the corresponding unnamed stream). 207 * A named stream's attributes (as far as CIFS is concerned) are those of the 208 * unnamed stream (minus the size attribute, and the type), plus the size of 209 * the named stream, and a type value of VREG. 210 * Although the file system may store other attributes with the named stream, 211 * these should not be used by CIFS for any purpose. 212 * 213 * File systems without VFSFT_XVATTR do not support DOS attributes or create 214 * time (crtime). In this case the mtime is used as the crtime. 215 * Likewise if VOP_GETATTR doesn't return any system attributes the dosattr 216 * is 0 and the mtime is used as the crtime. 217 */ 218 int 219 smb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *ret_attr, 220 int flags, cred_t *cr) 221 { 222 int error; 223 vnode_t *use_vp; 224 smb_attr_t tmp_attr; 225 xvattr_t tmp_xvattr; 226 xoptattr_t *xoap = NULL; 227 228 if (unnamed_vp) 229 use_vp = unnamed_vp; 230 else 231 use_vp = vp; 232 233 if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) { 234 xva_init(&tmp_xvattr); 235 xoap = xva_getxoptattr(&tmp_xvattr); 236 ASSERT(xoap); 237 238 smb_sa_to_va_mask(ret_attr->sa_mask, 239 &tmp_xvattr.xva_vattr.va_mask); 240 241 XVA_SET_REQ(&tmp_xvattr, XAT_READONLY); 242 XVA_SET_REQ(&tmp_xvattr, XAT_HIDDEN); 243 XVA_SET_REQ(&tmp_xvattr, XAT_SYSTEM); 244 XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE); 245 XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME); 246 247 error = VOP_GETATTR(use_vp, &tmp_xvattr.xva_vattr, flags, 248 cr, &smb_ct); 249 if (error != 0) 250 return (error); 251 252 ret_attr->sa_vattr = tmp_xvattr.xva_vattr; 253 ret_attr->sa_dosattr = 0; 254 255 if (tmp_xvattr.xva_vattr.va_mask & AT_XVATTR) { 256 xoap = xva_getxoptattr(&tmp_xvattr); 257 ASSERT(xoap); 258 259 if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_READONLY)) && 260 (xoap->xoa_readonly)) { 261 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY; 262 } 263 264 if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_HIDDEN)) && 265 (xoap->xoa_hidden)) { 266 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_HIDDEN; 267 } 268 269 if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_SYSTEM)) && 270 (xoap->xoa_system)) { 271 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_SYSTEM; 272 } 273 274 if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_ARCHIVE)) && 275 (xoap->xoa_archive)) { 276 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_ARCHIVE; 277 } 278 279 ret_attr->sa_crtime = xoap->xoa_createtime; 280 } else { 281 ret_attr->sa_crtime = ret_attr->sa_vattr.va_mtime; 282 } 283 } else { 284 /* 285 * Support for file systems without VFSFT_XVATTR 286 */ 287 smb_sa_to_va_mask(ret_attr->sa_mask, 288 &ret_attr->sa_vattr.va_mask); 289 290 error = VOP_GETATTR(use_vp, &ret_attr->sa_vattr, 291 flags, cr, &smb_ct); 292 if (error != 0) 293 return (error); 294 295 ret_attr->sa_dosattr = 0; 296 ret_attr->sa_crtime = ret_attr->sa_vattr.va_mtime; 297 } 298 299 if (unnamed_vp) { 300 ret_attr->sa_vattr.va_type = VREG; 301 302 if (ret_attr->sa_mask & SMB_AT_SIZE) { 303 tmp_attr.sa_vattr.va_mask = AT_SIZE; 304 305 error = VOP_GETATTR(vp, &tmp_attr.sa_vattr, 306 flags, cr, &smb_ct); 307 if (error != 0) 308 return (error); 309 310 ret_attr->sa_vattr.va_size = tmp_attr.sa_vattr.va_size; 311 } 312 } 313 314 if (ret_attr->sa_vattr.va_type == VDIR) 315 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY; 316 317 return (error); 318 } 319 320 /* 321 * smb_vop_setattr() 322 * 323 * smb_fsop_setattr()/smb_vop_setattr() should always be used instead of 324 * VOP_SETATTR() when calling from the CIFS service, due to special processing 325 * for streams files. 326 * 327 * Streams have a size but otherwise do not have separate attributes from 328 * the (unnamed stream) file, i.e., the security and ownership of the file 329 * applies to the stream. In contrast, extended attribute files, which are 330 * used to implement streams, are independent objects with their own 331 * attributes. 332 * 333 * For compatibility with streams, we set the size on the extended attribute 334 * file and apply other attributes to the (unnamed stream) file. The one 335 * exception is that the UID and GID can be set on the stream by passing a 336 * NULL unnamed_vp, which allows callers to synchronize stream ownership 337 * with the (unnamed stream) file. 338 */ 339 340 int 341 smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *set_attr, 342 int flags, cred_t *cr) 343 { 344 int error = 0; 345 int at_size = 0; 346 vnode_t *use_vp; 347 xvattr_t xvattr; 348 vattr_t *vap; 349 350 if (unnamed_vp) { 351 use_vp = unnamed_vp; 352 if (set_attr->sa_mask & SMB_AT_SIZE) { 353 at_size = 1; 354 set_attr->sa_mask &= ~SMB_AT_SIZE; 355 } 356 } else { 357 use_vp = vp; 358 } 359 360 /* 361 * The caller should not be setting sa_vattr.va_mask, 362 * but rather sa_mask. 363 */ 364 365 set_attr->sa_vattr.va_mask = 0; 366 367 if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) { 368 smb_vop_setup_xvattr(set_attr, &xvattr); 369 vap = &xvattr.xva_vattr; 370 } else { 371 smb_sa_to_va_mask(set_attr->sa_mask, 372 &set_attr->sa_vattr.va_mask); 373 vap = &set_attr->sa_vattr; 374 } 375 376 if ((error = VOP_SETATTR(use_vp, vap, flags, cr, &smb_ct)) != 0) 377 return (error); 378 379 if (at_size) { 380 set_attr->sa_vattr.va_mask = AT_SIZE; 381 error = VOP_SETATTR(vp, &set_attr->sa_vattr, flags, cr, 382 &smb_ct); 383 } 384 385 return (error); 386 } 387 388 /* 389 * smb_vop_access 390 * 391 * This is a wrapper round VOP_ACCESS. VOP_ACCESS checks the given mode 392 * against file's ACL or Unix permissions. CIFS on the other hand needs to 393 * know if the requested operation can succeed for the given object, this 394 * requires more checks in case of DELETE bit since permissions on the parent 395 * directory are important as well. Based on Windows rules if parent's ACL 396 * grant FILE_DELETE_CHILD a file can be delete regardless of the file's 397 * permissions. 398 */ 399 int 400 smb_vop_access(vnode_t *vp, int mode, int flags, vnode_t *dir_vp, cred_t *cr) 401 { 402 int error = 0; 403 404 if (mode == 0) 405 return (0); 406 407 if ((flags == V_ACE_MASK) && (mode & ACE_DELETE)) { 408 if (dir_vp) { 409 error = VOP_ACCESS(dir_vp, ACE_DELETE_CHILD, flags, 410 cr, NULL); 411 412 if (error == 0) 413 mode &= ~ACE_DELETE; 414 } 415 } 416 417 if (mode) { 418 error = VOP_ACCESS(vp, mode, flags, cr, NULL); 419 } 420 421 return (error); 422 } 423 424 /* 425 * smb_vop_lookup 426 * 427 * dvp: directory vnode (in) 428 * name: name of file to be looked up (in) 429 * vpp: looked-up vnode (out) 430 * od_name: on-disk name of file (out). 431 * This parameter is optional. If a pointer is passed in, it 432 * must be allocated with MAXNAMELEN bytes 433 * rootvp: vnode of the tree root (in) 434 * This parameter is always passed in non-NULL except at the time 435 * of share set up. 436 */ 437 438 int 439 smb_vop_lookup( 440 vnode_t *dvp, 441 char *name, 442 vnode_t **vpp, 443 char *od_name, 444 int flags, 445 vnode_t *rootvp, 446 cred_t *cr) 447 { 448 int error = 0; 449 int option_flags = 0; 450 pathname_t rpn; 451 452 if (*name == '\0') 453 return (EINVAL); 454 455 ASSERT(vpp); 456 *vpp = NULL; 457 458 if ((name[0] == '.') && (name[1] == '.') && (name[2] == 0)) { 459 if (rootvp && (dvp == rootvp)) { 460 VN_HOLD(dvp); 461 *vpp = dvp; 462 return (0); 463 } 464 465 if (dvp->v_flag & VROOT) { 466 vfs_t *vfsp; 467 vnode_t *cvp = dvp; 468 469 /* 470 * Set dvp and check for races with forced unmount 471 * (see lookuppnvp()) 472 */ 473 474 vfsp = cvp->v_vfsp; 475 vfs_rlock_wait(vfsp); 476 if (((dvp = cvp->v_vfsp->vfs_vnodecovered) == NULL) || 477 (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) { 478 vfs_unlock(vfsp); 479 return (EIO); 480 } 481 vfs_unlock(vfsp); 482 } 483 } 484 485 486 487 if (flags & SMB_IGNORE_CASE) 488 option_flags = FIGNORECASE; 489 490 pn_alloc(&rpn); 491 492 error = VOP_LOOKUP(dvp, name, vpp, NULL, option_flags, NULL, cr, 493 &smb_ct, NULL, &rpn); 494 495 if ((error == 0) && od_name) { 496 bzero(od_name, MAXNAMELEN); 497 if (option_flags == FIGNORECASE) 498 (void) strlcpy(od_name, rpn.pn_buf, MAXNAMELEN); 499 else 500 (void) strlcpy(od_name, name, MAXNAMELEN); 501 } 502 503 pn_free(&rpn); 504 return (error); 505 } 506 507 int 508 smb_vop_create(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp, 509 int flags, cred_t *cr, vsecattr_t *vsap) 510 { 511 int error; 512 int option_flags = 0; 513 xvattr_t xvattr; 514 vattr_t *vap; 515 516 if (flags & SMB_IGNORE_CASE) 517 option_flags = FIGNORECASE; 518 519 attr->sa_vattr.va_mask = 0; 520 521 if (vfs_has_feature(dvp->v_vfsp, VFSFT_XVATTR)) { 522 smb_vop_setup_xvattr(attr, &xvattr); 523 vap = &xvattr.xva_vattr; 524 } else { 525 smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask); 526 vap = &attr->sa_vattr; 527 } 528 529 error = VOP_CREATE(dvp, name, vap, EXCL, attr->sa_vattr.va_mode, 530 vpp, cr, option_flags, &smb_ct, vsap); 531 532 return (error); 533 } 534 535 int 536 smb_vop_remove(vnode_t *dvp, char *name, int flags, cred_t *cr) 537 { 538 int error; 539 int option_flags = 0; 540 541 if (flags & SMB_IGNORE_CASE) 542 option_flags = FIGNORECASE; 543 544 error = VOP_REMOVE(dvp, name, cr, &smb_ct, option_flags); 545 546 return (error); 547 } 548 549 /* 550 * smb_vop_rename() 551 * 552 * The rename is for files in the same tree (identical TID) only. 553 */ 554 555 int 556 smb_vop_rename(vnode_t *from_dvp, char *from_name, vnode_t *to_dvp, 557 char *to_name, int flags, cred_t *cr) 558 { 559 int error; 560 int option_flags = 0; 561 562 563 if (flags & SMB_IGNORE_CASE) 564 option_flags = FIGNORECASE; 565 566 error = VOP_RENAME(from_dvp, from_name, to_dvp, to_name, cr, 567 &smb_ct, option_flags); 568 569 return (error); 570 } 571 572 int 573 smb_vop_mkdir(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp, 574 int flags, cred_t *cr, vsecattr_t *vsap) 575 { 576 int error; 577 int option_flags = 0; 578 xvattr_t xvattr; 579 vattr_t *vap; 580 581 if (flags & SMB_IGNORE_CASE) 582 option_flags = FIGNORECASE; 583 584 attr->sa_vattr.va_mask = 0; 585 586 if (vfs_has_feature(dvp->v_vfsp, VFSFT_XVATTR)) { 587 smb_vop_setup_xvattr(attr, &xvattr); 588 vap = &xvattr.xva_vattr; 589 } else { 590 smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask); 591 vap = &attr->sa_vattr; 592 } 593 594 error = VOP_MKDIR(dvp, name, vap, vpp, cr, &smb_ct, 595 option_flags, vsap); 596 597 return (error); 598 } 599 600 /* 601 * smb_vop_rmdir() 602 * 603 * Only simple rmdir supported, consistent with NT semantics 604 * (can only remove an empty directory). 605 * 606 */ 607 608 int 609 smb_vop_rmdir(vnode_t *dvp, char *name, int flags, cred_t *cr) 610 { 611 int error; 612 int option_flags = 0; 613 614 if (flags & SMB_IGNORE_CASE) 615 option_flags = FIGNORECASE; 616 617 /* 618 * Comments adapted from rfs_rmdir(). 619 * 620 * VOP_RMDIR now takes a new third argument (the current 621 * directory of the process). That's because rmdir 622 * wants to return EINVAL if one tries to remove ".". 623 * Of course, SMB servers do not know what their 624 * clients' current directories are. We fake it by 625 * supplying a vnode known to exist and illegal to 626 * remove. 627 */ 628 629 error = VOP_RMDIR(dvp, name, rootdir, cr, &smb_ct, option_flags); 630 return (error); 631 } 632 633 int 634 smb_vop_commit(vnode_t *vp, cred_t *cr) 635 { 636 return (VOP_FSYNC(vp, 1, cr, &smb_ct)); 637 } 638 639 static void 640 smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr) 641 { 642 xoptattr_t *xoap = NULL; 643 uint_t xva_mask; 644 645 /* 646 * Initialize xvattr, including bzero 647 */ 648 xva_init(xvattr); 649 xoap = xva_getxoptattr(xvattr); 650 651 ASSERT(xoap); 652 653 /* 654 * Copy caller-specified classic attributes to xvattr. 655 * First save xvattr's mask (set in xva_init()), which 656 * contains AT_XVATTR. This is |'d in later if needed. 657 */ 658 659 xva_mask = xvattr->xva_vattr.va_mask; 660 xvattr->xva_vattr = smb_attr->sa_vattr; 661 662 smb_sa_to_va_mask(smb_attr->sa_mask, &xvattr->xva_vattr.va_mask); 663 664 /* 665 * Do not set ctime (only the file system can do it) 666 */ 667 668 xvattr->xva_vattr.va_mask &= ~AT_CTIME; 669 670 if (smb_attr->sa_mask & SMB_AT_DOSATTR) { 671 672 /* 673 * "|" in the original xva_mask, which contains 674 * AT_XVATTR 675 */ 676 677 xvattr->xva_vattr.va_mask |= xva_mask; 678 679 XVA_SET_REQ(xvattr, XAT_ARCHIVE); 680 XVA_SET_REQ(xvattr, XAT_SYSTEM); 681 XVA_SET_REQ(xvattr, XAT_READONLY); 682 XVA_SET_REQ(xvattr, XAT_HIDDEN); 683 684 /* 685 * smb_attr->sa_dosattr: If a given bit is not set, 686 * that indicates that the corresponding field needs 687 * to be updated with a "0" value. This is done 688 * implicitly as the xoap->xoa_* fields were bzero'd. 689 */ 690 691 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_ARCHIVE) 692 xoap->xoa_archive = 1; 693 694 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_SYSTEM) 695 xoap->xoa_system = 1; 696 697 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_READONLY) 698 xoap->xoa_readonly = 1; 699 700 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_HIDDEN) 701 xoap->xoa_hidden = 1; 702 } 703 704 if (smb_attr->sa_mask & SMB_AT_CRTIME) { 705 /* 706 * "|" in the original xva_mask, which contains 707 * AT_XVATTR 708 */ 709 710 xvattr->xva_vattr.va_mask |= xva_mask; 711 XVA_SET_REQ(xvattr, XAT_CREATETIME); 712 xoap->xoa_createtime = smb_attr->sa_crtime; 713 } 714 } 715 716 /* 717 * smb_vop_readdir() 718 * 719 * Collects an SMB_MINLEN_RDDIR_BUF "page" of directory entries. 720 * The directory entries are returned in an fs-independent format by the 721 * underlying file system. That is, the "page" of information returned is 722 * not literally stored on-disk in the format returned. 723 * If the file system supports extended directory entries (has features 724 * VFSFT_DIRENTFLAGS), set V_RDDIR_ENTFLAGS to cause the buffer to be 725 * filled with edirent_t structures, instead of dirent64_t structures. 726 * 727 * Some file systems can have directories larger than SMB_MAXDIRSIZE. 728 * After VOP_READDIR, if offset is larger than SMB_MAXDIRSIZE treat as EOF. 729 */ 730 int 731 smb_vop_readdir(vnode_t *vp, uint32_t offset, 732 void *buf, int *count, int *eof, cred_t *cr) 733 { 734 int error = 0; 735 int rdirent_flags = 0; 736 int rdirent_size; 737 struct uio auio; 738 struct iovec aiov; 739 740 if (vp->v_type != VDIR) 741 return (ENOTDIR); 742 743 if (vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS)) { 744 rdirent_flags = V_RDDIR_ENTFLAGS; 745 rdirent_size = sizeof (edirent_t); 746 } else { 747 rdirent_size = sizeof (dirent64_t); 748 } 749 750 if (*count < rdirent_size) 751 return (EINVAL); 752 753 aiov.iov_base = buf; 754 aiov.iov_len = *count; 755 auio.uio_iov = &aiov; 756 auio.uio_iovcnt = 1; 757 auio.uio_loffset = (uint64_t)offset; 758 auio.uio_segflg = UIO_SYSSPACE; 759 auio.uio_resid = *count; 760 auio.uio_fmode = 0; 761 762 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &smb_ct); 763 error = VOP_READDIR(vp, &auio, cr, eof, &smb_ct, rdirent_flags); 764 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &smb_ct); 765 766 if (auio.uio_loffset > SMB_MAXDIRSIZE) 767 *eof = 1; 768 769 if (error == 0) 770 *count = *count - auio.uio_resid; 771 772 return (error); 773 } 774 775 /* 776 * smb_sa_to_va_mask 777 * 778 * Set va_mask by running through the SMB_AT_* #define's and 779 * setting those bits that correspond to the SMB_AT_* bits 780 * set in sa_mask. 781 */ 782 783 void 784 smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp) 785 { 786 int i; 787 uint_t smask; 788 789 smask = (sa_mask); 790 for (i = SMB_AT_TYPE; (i < SMB_AT_MAX) && (smask != 0); ++i) { 791 if (smask & 1) 792 *(va_maskp) |= smb_attrmap[i]; 793 794 smask >>= 1; 795 } 796 } 797 798 /* 799 * smb_vop_stream_lookup() 800 * 801 * The name returned in od_name is the on-disk name of the stream with the 802 * SMB_STREAM_PREFIX stripped off. od_name should be allocated to MAXNAMELEN 803 * by the caller. 804 */ 805 806 int 807 smb_vop_stream_lookup( 808 vnode_t *fvp, 809 char *stream_name, 810 vnode_t **vpp, 811 char *od_name, 812 vnode_t **xattrdirvpp, 813 int flags, 814 vnode_t *rootvp, 815 cred_t *cr) 816 { 817 char *solaris_stream_name; 818 char *name; 819 int error; 820 821 if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp, 822 LOOKUP_XATTR | CREATE_XATTR_DIR, cr)) != 0) 823 return (error); 824 825 /* 826 * Prepend SMB_STREAM_PREFIX to stream name 827 */ 828 829 solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 830 (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 831 stream_name); 832 833 /* 834 * "name" will hold the on-disk name returned from smb_vop_lookup 835 * for the stream, including the SMB_STREAM_PREFIX. 836 */ 837 838 name = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 839 840 if ((error = smb_vop_lookup(*xattrdirvpp, solaris_stream_name, vpp, 841 name, flags, rootvp, cr)) != 0) { 842 VN_RELE(*xattrdirvpp); 843 } else { 844 (void) strlcpy(od_name, &(name[SMB_STREAM_PREFIX_LEN]), 845 MAXNAMELEN); 846 } 847 848 kmem_free(solaris_stream_name, MAXNAMELEN); 849 kmem_free(name, MAXNAMELEN); 850 851 return (error); 852 } 853 854 int 855 smb_vop_stream_create(vnode_t *fvp, char *stream_name, smb_attr_t *attr, 856 vnode_t **vpp, vnode_t **xattrdirvpp, int flags, cred_t *cr) 857 { 858 char *solaris_stream_name; 859 int error; 860 861 if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp, 862 LOOKUP_XATTR | CREATE_XATTR_DIR, cr)) != 0) 863 return (error); 864 865 /* 866 * Prepend SMB_STREAM_PREFIX to stream name 867 */ 868 869 solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 870 (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 871 stream_name); 872 873 if ((error = smb_vop_create(*xattrdirvpp, solaris_stream_name, attr, 874 vpp, flags, cr, NULL)) != 0) 875 VN_RELE(*xattrdirvpp); 876 877 kmem_free(solaris_stream_name, MAXNAMELEN); 878 879 return (error); 880 } 881 882 int 883 smb_vop_stream_remove(vnode_t *vp, char *stream_name, int flags, cred_t *cr) 884 { 885 char *solaris_stream_name; 886 vnode_t *xattrdirvp; 887 int error; 888 889 error = smb_vop_lookup_xattrdir(vp, &xattrdirvp, LOOKUP_XATTR, cr); 890 if (error != 0) 891 return (error); 892 893 /* 894 * Prepend SMB_STREAM_PREFIX to stream name 895 */ 896 897 solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 898 (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 899 stream_name); 900 901 /* XXX might have to use kcred */ 902 error = smb_vop_remove(xattrdirvp, solaris_stream_name, flags, cr); 903 904 kmem_free(solaris_stream_name, MAXNAMELEN); 905 906 return (error); 907 } 908 909 int 910 smb_vop_lookup_xattrdir(vnode_t *fvp, vnode_t **xattrdirvpp, int flags, 911 cred_t *cr) 912 { 913 int error; 914 915 error = VOP_LOOKUP(fvp, "", xattrdirvpp, NULL, flags, NULL, cr, 916 &smb_ct, NULL, NULL); 917 return (error); 918 } 919 920 /* 921 * smb_vop_traverse_check() 922 * 923 * This function checks to see if the passed-in vnode has a file system 924 * mounted on it. If it does, the mount point is "traversed" and the 925 * vnode for the root of the file system is returned. 926 */ 927 928 int 929 smb_vop_traverse_check(vnode_t **vpp) 930 { 931 int error; 932 933 if (vn_mountedvfs(*vpp) == 0) 934 return (0); 935 936 /* 937 * traverse() may return a different held vnode, even in the error case. 938 * If it returns a different vnode, it will have released the original. 939 */ 940 941 error = traverse(vpp); 942 943 return (error); 944 } 945 946 int /*ARGSUSED*/ 947 smb_vop_statfs(vnode_t *vp, struct statvfs64 *statp, cred_t *cr) 948 { 949 int error; 950 951 error = VFS_STATVFS(vp->v_vfsp, statp); 952 953 return (error); 954 } 955 956 /* 957 * smb_vop_acl_read 958 * 959 * Reads the ACL of the specified file into 'aclp'. 960 * acl_type is the type of ACL which the filesystem supports. 961 * 962 * Caller has to free the allocated memory for aclp by calling 963 * acl_free(). 964 */ 965 int 966 smb_vop_acl_read(vnode_t *vp, acl_t **aclp, int flags, acl_type_t acl_type, 967 cred_t *cr) 968 { 969 int error; 970 vsecattr_t vsecattr; 971 972 ASSERT(vp); 973 ASSERT(aclp); 974 975 *aclp = NULL; 976 bzero(&vsecattr, sizeof (vsecattr_t)); 977 978 switch (acl_type) { 979 case ACLENT_T: 980 vsecattr.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL | 981 VSA_DFACLCNT; 982 break; 983 984 case ACE_T: 985 vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS; 986 break; 987 988 default: 989 return (EINVAL); 990 } 991 992 if (error = VOP_GETSECATTR(vp, &vsecattr, flags, cr, &smb_ct)) 993 return (error); 994 995 *aclp = smb_fsacl_from_vsa(&vsecattr, acl_type); 996 if (vp->v_type == VDIR) 997 (*aclp)->acl_flags |= ACL_IS_DIR; 998 999 return (0); 1000 } 1001 1002 /* 1003 * smb_vop_acl_write 1004 * 1005 * Writes the given ACL in aclp for the specified file. 1006 */ 1007 int 1008 smb_vop_acl_write(vnode_t *vp, acl_t *aclp, int flags, cred_t *cr) 1009 { 1010 int error; 1011 vsecattr_t vsecattr; 1012 int aclbsize; 1013 1014 ASSERT(vp); 1015 ASSERT(aclp); 1016 1017 error = smb_fsacl_to_vsa(aclp, &vsecattr, &aclbsize); 1018 1019 if (error == 0) { 1020 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &smb_ct); 1021 error = VOP_SETSECATTR(vp, &vsecattr, flags, cr, &smb_ct); 1022 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &smb_ct); 1023 } 1024 1025 if (aclbsize && vsecattr.vsa_aclentp) 1026 kmem_free(vsecattr.vsa_aclentp, aclbsize); 1027 1028 return (error); 1029 } 1030 1031 /* 1032 * smb_vop_acl_type 1033 * 1034 * Determines the ACL type for the given vnode. 1035 * ACLENT_T is a Posix ACL and ACE_T is a ZFS ACL. 1036 */ 1037 acl_type_t 1038 smb_vop_acl_type(vnode_t *vp) 1039 { 1040 int error; 1041 ulong_t whichacl; 1042 1043 error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl, kcred, NULL); 1044 if (error != 0) { 1045 /* 1046 * If we got an error, then the filesystem 1047 * likely does not understand the _PC_ACL_ENABLED 1048 * pathconf. In this case, we fall back to trying 1049 * POSIX-draft (aka UFS-style) ACLs. 1050 */ 1051 whichacl = _ACL_ACLENT_ENABLED; 1052 } 1053 1054 if (!(whichacl & (_ACL_ACE_ENABLED | _ACL_ACLENT_ENABLED))) { 1055 /* 1056 * If the file system supports neither ACE nor 1057 * ACLENT ACLs we will fall back to UFS-style ACLs 1058 * like we did above if there was an error upon 1059 * calling VOP_PATHCONF. 1060 * 1061 * ACE and ACLENT type ACLs are the only interfaces 1062 * supported thus far. If any other bits are set on 1063 * 'whichacl' upon return from VOP_PATHCONF, we will 1064 * ignore them. 1065 */ 1066 whichacl = _ACL_ACLENT_ENABLED; 1067 } 1068 1069 if (whichacl == _ACL_ACLENT_ENABLED) 1070 return (ACLENT_T); 1071 1072 return (ACE_T); 1073 } 1074 1075 static int zfs_perms[] = { 1076 ACE_READ_DATA, ACE_WRITE_DATA, ACE_APPEND_DATA, ACE_READ_NAMED_ATTRS, 1077 ACE_WRITE_NAMED_ATTRS, ACE_EXECUTE, ACE_DELETE_CHILD, 1078 ACE_READ_ATTRIBUTES, ACE_WRITE_ATTRIBUTES, ACE_DELETE, ACE_READ_ACL, 1079 ACE_WRITE_ACL, ACE_WRITE_OWNER, ACE_SYNCHRONIZE 1080 }; 1081 1082 static int unix_perms[] = { VREAD, VWRITE, VEXEC }; 1083 /* 1084 * smb_vop_eaccess 1085 * 1086 * Returns the effective permission of the given credential for the 1087 * specified object. 1088 * 1089 * This is just a workaround. We need VFS/FS support for this. 1090 */ 1091 void 1092 smb_vop_eaccess(vnode_t *vp, int *mode, int flags, vnode_t *dir_vp, cred_t *cr) 1093 { 1094 int error, i; 1095 int pnum; 1096 1097 *mode = 0; 1098 1099 if (flags == V_ACE_MASK) { 1100 pnum = sizeof (zfs_perms) / sizeof (int); 1101 1102 for (i = 0; i < pnum; i++) { 1103 error = smb_vop_access(vp, zfs_perms[i], flags, 1104 dir_vp, cr); 1105 if (error == 0) 1106 *mode |= zfs_perms[i]; 1107 } 1108 } else { 1109 pnum = sizeof (unix_perms) / sizeof (int); 1110 1111 for (i = 0; i < pnum; i++) { 1112 error = smb_vop_access(vp, unix_perms[i], flags, 1113 dir_vp, cr); 1114 if (error == 0) 1115 *mode |= unix_perms[i]; 1116 } 1117 } 1118 } 1119 1120 /* 1121 * smb_vop_shrlock() 1122 * 1123 * See comments for smb_fsop_shrlock() 1124 */ 1125 1126 int 1127 smb_vop_shrlock(vnode_t *vp, uint32_t uniq_fid, uint32_t desired_access, 1128 uint32_t share_access, cred_t *cr) 1129 { 1130 struct shrlock shr; 1131 struct shr_locowner shr_own; 1132 short new_access = 0; 1133 short deny = 0; 1134 int flag = 0; 1135 int cmd; 1136 1137 cmd = (nbl_need_check(vp)) ? F_SHARE_NBMAND : F_SHARE; 1138 1139 /* 1140 * Check if this is a metadata access 1141 */ 1142 1143 if ((desired_access & FILE_DATA_ALL) == 0) { 1144 new_access |= F_MDACC; 1145 } else { 1146 if (desired_access & (ACE_READ_DATA | ACE_EXECUTE)) { 1147 new_access |= F_RDACC; 1148 flag |= FREAD; 1149 } 1150 1151 if (desired_access & (ACE_WRITE_DATA | ACE_APPEND_DATA | 1152 ACE_ADD_FILE)) { 1153 new_access |= F_WRACC; 1154 flag |= FWRITE; 1155 } 1156 1157 if (SMB_DENY_READ(share_access)) { 1158 deny |= F_RDDNY; 1159 } 1160 1161 if (SMB_DENY_WRITE(share_access)) { 1162 deny |= F_WRDNY; 1163 } 1164 1165 if (cmd == F_SHARE_NBMAND) { 1166 if (desired_access & ACE_DELETE) 1167 new_access |= F_RMACC; 1168 1169 if (SMB_DENY_DELETE(share_access)) { 1170 deny |= F_RMDNY; 1171 } 1172 } 1173 } 1174 1175 shr.s_access = new_access; 1176 shr.s_deny = deny; 1177 shr.s_sysid = smb_ct.cc_sysid; 1178 shr.s_pid = uniq_fid; 1179 shr.s_own_len = sizeof (shr_own); 1180 shr.s_owner = (caddr_t)&shr_own; 1181 shr_own.sl_id = shr.s_sysid; 1182 shr_own.sl_pid = shr.s_pid; 1183 1184 return (VOP_SHRLOCK(vp, cmd, &shr, flag, cr, NULL)); 1185 } 1186 1187 int 1188 smb_vop_unshrlock(vnode_t *vp, uint32_t uniq_fid, cred_t *cr) 1189 { 1190 struct shrlock shr; 1191 struct shr_locowner shr_own; 1192 1193 /* 1194 * For s_access and s_deny, we do not need to pass in the original 1195 * values. 1196 */ 1197 1198 shr.s_access = 0; 1199 shr.s_deny = 0; 1200 shr.s_sysid = smb_ct.cc_sysid; 1201 shr.s_pid = uniq_fid; 1202 shr.s_own_len = sizeof (shr_own); 1203 shr.s_owner = (caddr_t)&shr_own; 1204 shr_own.sl_id = shr.s_sysid; 1205 shr_own.sl_pid = shr.s_pid; 1206 1207 return (VOP_SHRLOCK(vp, F_UNSHARE, &shr, 0, cr, NULL)); 1208 } 1209 1210 int 1211 smb_vop_frlock(vnode_t *vp, cred_t *cr, int flag, flock64_t *bf) 1212 { 1213 int cmd = nbl_need_check(vp) ? F_SETLK_NBMAND : F_SETLK; 1214 flk_callback_t flk_cb; 1215 1216 flk_init_callback(&flk_cb, smb_lock_frlock_callback, NULL); 1217 1218 return (VOP_FRLOCK(vp, cmd, bf, flag, 0, &flk_cb, cr, &smb_ct)); 1219 } 1220 1221 static callb_cpr_t * 1222 /* ARGSUSED */ 1223 smb_lock_frlock_callback(flk_cb_when_t when, void *error) 1224 { 1225 return (0); 1226 } 1227