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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <sys/stat.h> 30 #include <sys/uio.h> 31 #include <sys/statvfs.h> 32 #include <sys/vnode.h> 33 #include <sys/thread.h> 34 #include <sys/pathname.h> 35 #include <sys/cred.h> 36 #include <sys/extdirent.h> 37 #include <acl/acl_common.h> 38 #include <smbsrv/smb_vops.h> 39 #include <smbsrv/string.h> 40 #include <smbsrv/lmshare.h> 41 #include <smbsrv/smbtrans.h> 42 #include <smbsrv/smb_incl.h> 43 #include <smbsrv/smb_fsops.h> 44 45 static int 46 smb_vop_readdir_readpage(vnode_t *vp, void *buf, uint32_t offset, int *count, 47 cred_t *cr, caller_context_t *ct, int flags); 48 49 static int 50 smb_vop_readdir_entry(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen, 51 ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr, 52 caller_context_t *ct, char *dirbuf, int num_bytes); 53 54 static int 55 smb_vop_getdents_entries(smb_node_t *dir_snode, uint32_t *cookiep, 56 int32_t *dircountp, char *arg, uint32_t flags, struct smb_request *sr, 57 cred_t *cr, caller_context_t *ct, char *dirbuf, int *maxentries, 58 int num_bytes, char *); 59 60 extern int 61 smb_gather_dents_info(char *args, ino_t fileid, int namelen, 62 char *name, uint32_t cookie, int32_t *countp, 63 smb_attr_t *attr, struct smb_node *snode, 64 char *shortname, char *name83); 65 66 static void 67 smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp); 68 69 #define SMB_AT_MAX 16 70 static uint_t smb_attrmap[SMB_AT_MAX] = { 71 0, 72 AT_TYPE, 73 AT_MODE, 74 AT_UID, 75 AT_GID, 76 AT_FSID, 77 AT_NODEID, 78 AT_NLINK, 79 AT_SIZE, 80 AT_ATIME, 81 AT_MTIME, 82 AT_CTIME, 83 AT_RDEV, 84 AT_BLKSIZE, 85 AT_NBLOCKS, 86 AT_SEQ 87 }; 88 89 int 90 smb_vop_open(vnode_t **vpp, int mode, cred_t *cred, caller_context_t *ct) 91 { 92 return (VOP_OPEN(vpp, mode, cred, ct)); 93 } 94 95 int 96 smb_vop_close(vnode_t *vp, int mode, cred_t *cred, caller_context_t *ct) 97 { 98 return (VOP_CLOSE(vp, mode, 1, (offset_t)0, cred, ct)); 99 } 100 101 /* 102 * The smb_vop_* functions have minimal knowledge of CIFS semantics and 103 * serve as an interface to the VFS layer. 104 * 105 * Only smb_fsop_* layer functions should call smb_vop_* layer functions. 106 * (Higher-level CIFS service code should never skip the smb_fsop_* layer 107 * to call smb_vop_* layer functions directly.) 108 */ 109 110 /* 111 * XXX - Extended attributes support in the file system assumed. 112 * This is needed for full NT Streams functionality. 113 */ 114 115 int 116 smb_vop_read(vnode_t *vp, uio_t *uiop, cred_t *cr, caller_context_t *ct) 117 { 118 int error; 119 120 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 121 error = VOP_READ(vp, uiop, 0, cr, ct); 122 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 123 return (error); 124 } 125 126 int 127 smb_vop_write(vnode_t *vp, uio_t *uiop, uint32_t *flag, uint32_t *lcount, 128 cred_t *cr, caller_context_t *ct) 129 { 130 int error; 131 int ioflag = 0; 132 133 *lcount = uiop->uio_resid; 134 135 if (*flag == FSSTAB_FILE_SYNC) 136 ioflag = FSYNC; 137 138 uiop->uio_llimit = MAXOFFSET_T; 139 140 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 141 error = VOP_WRITE(vp, uiop, ioflag, cr, ct); 142 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 143 144 *lcount -= uiop->uio_resid; 145 146 return (error); 147 } 148 149 /* 150 * smb_vop_getattr() 151 * 152 * smb_fsop_getattr()/smb_vop_getattr() should always be called from the CIFS 153 * service (instead of calling VOP_GETATTR directly) to retrieve attributes 154 * due to special processing needed for streams files. 155 * 156 * All attributes are retrieved. 157 * 158 * A named stream's attributes (as far as CIFS is concerned) are those of the 159 * unnamed (i.e. data) stream (minus the size attribute), and the size of the 160 * named stream. Though the file system may store attributes other than size 161 * with the named stream, these should not be used by CIFS for any purpose. 162 * 163 * When vp denotes a named stream, then unnamed_vp should be passed in (denoting 164 * the corresponding unnamed stream). 165 */ 166 167 int 168 smb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *ret_attr, 169 int flags, cred_t *cr, caller_context_t *ct) 170 { 171 int error; 172 vnode_t *use_vp; 173 smb_attr_t tmp_attr; 174 xvattr_t tmp_xvattr; 175 xoptattr_t *xoap = NULL; 176 177 if (unnamed_vp) 178 use_vp = unnamed_vp; 179 else 180 use_vp = vp; 181 182 if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) { 183 xva_init(&tmp_xvattr); 184 xoap = xva_getxoptattr(&tmp_xvattr); 185 186 ASSERT(xoap); 187 188 smb_sa_to_va_mask(ret_attr->sa_mask, 189 &tmp_xvattr.xva_vattr.va_mask); 190 191 XVA_SET_REQ(&tmp_xvattr, XAT_READONLY); 192 XVA_SET_REQ(&tmp_xvattr, XAT_HIDDEN); 193 XVA_SET_REQ(&tmp_xvattr, XAT_SYSTEM); 194 XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE); 195 XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME); 196 197 if ((error = VOP_GETATTR(use_vp, (vattr_t *)&tmp_xvattr, flags, 198 cr, ct)) != 0) 199 return (error); 200 201 ret_attr->sa_vattr = tmp_xvattr.xva_vattr; 202 203 /* 204 * Copy special attributes to ret_attr parameter 205 */ 206 207 ret_attr->sa_dosattr = 0; 208 209 ASSERT(tmp_xvattr.xva_vattr.va_mask & AT_XVATTR); 210 211 xoap = xva_getxoptattr(&tmp_xvattr); 212 ASSERT(xoap); 213 214 if (XVA_ISSET_RTN(&tmp_xvattr, XAT_READONLY)) { 215 if (xoap->xoa_readonly) 216 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY; 217 } 218 219 if (XVA_ISSET_RTN(&tmp_xvattr, XAT_HIDDEN)) { 220 if (xoap->xoa_hidden) 221 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_HIDDEN; 222 } 223 224 if (XVA_ISSET_RTN(&tmp_xvattr, XAT_SYSTEM)) { 225 if (xoap->xoa_system) 226 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_SYSTEM; 227 } 228 229 if (XVA_ISSET_RTN(&tmp_xvattr, XAT_ARCHIVE)) { 230 if (xoap->xoa_archive) 231 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_ARCHIVE; 232 } 233 234 ret_attr->sa_crtime = xoap->xoa_createtime; 235 236 if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) { 237 /* 238 * Retrieve stream size attribute into temporary 239 * structure, in case the underlying file system 240 * returns attributes other than the size (we do not 241 * want to have ret_attr's other fields get 242 * overwritten). 243 * 244 * Note that vp is used here, and not use_vp. 245 * Also, only AT_SIZE is needed. 246 */ 247 248 tmp_xvattr.xva_vattr.va_mask = AT_SIZE; 249 250 if ((error = VOP_GETATTR(vp, (vattr_t *)&tmp_xvattr, 251 flags, cr, ct)) != 0) 252 return (error); 253 254 ret_attr->sa_vattr.va_size = 255 tmp_xvattr.xva_vattr.va_size; 256 257 } 258 259 if (ret_attr->sa_vattr.va_type == VDIR) { 260 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY; 261 } 262 263 return (error); 264 } 265 266 /* 267 * Support for file systems without VFSFT_XVATTR 268 */ 269 270 smb_sa_to_va_mask(ret_attr->sa_mask, 271 &ret_attr->sa_vattr.va_mask); 272 273 error = VOP_GETATTR(use_vp, &ret_attr->sa_vattr, flags, cr, ct); 274 275 if (error != 0) 276 return (error); 277 278 /* 279 * "Fake" DOS attributes and create time, filesystem doesn't support 280 * them. 281 */ 282 283 ret_attr->sa_dosattr = 0; 284 ret_attr->sa_crtime = ret_attr->sa_vattr.va_ctime; 285 286 if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) { 287 /* 288 * Retrieve stream size attribute into temporary structure, 289 * in case the underlying file system returns attributes 290 * other than the size (we do not want to have ret_attr's 291 * other fields get overwritten). 292 * 293 * Note that vp is used here, and not use_vp. 294 * Also, only AT_SIZE is needed. 295 */ 296 297 tmp_attr.sa_vattr.va_mask = AT_SIZE; 298 error = VOP_GETATTR(vp, &tmp_attr.sa_vattr, flags, cr, ct); 299 300 if (error != 0) 301 return (error); 302 303 304 ret_attr->sa_vattr.va_size = tmp_attr.sa_vattr.va_size; 305 } 306 307 if (ret_attr->sa_vattr.va_type == VDIR) { 308 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY; 309 } 310 311 return (error); 312 } 313 314 /* 315 * smb_vop_setattr() 316 * 317 * smb_fsop_setattr()/smb_vop_setattr() should always be called from the CIFS 318 * service to set attributes due to special processing for streams files. 319 * 320 * When smb_vop_setattr() is called on a named stream file, all indicated 321 * attributes except the size are set on the unnamed stream file. The size 322 * (if indicated) is set on the named stream file. 323 */ 324 325 int 326 smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *set_attr, 327 int flags, cred_t *cr, caller_context_t *ct) 328 { 329 int error = 0; 330 int at_size = 0; 331 vnode_t *use_vp; 332 xvattr_t tmp_xvattr; 333 xoptattr_t *xoap = NULL; 334 uint_t xva_mask; 335 336 if (unnamed_vp) { 337 use_vp = unnamed_vp; 338 if (set_attr->sa_mask & SMB_AT_SIZE) { 339 at_size = 1; 340 set_attr->sa_mask &= ~SMB_AT_SIZE; 341 } 342 } else { 343 use_vp = vp; 344 } 345 346 /* 347 * The caller should not be setting sa_vattr.va_mask, 348 * but rather sa_mask. 349 */ 350 351 set_attr->sa_vattr.va_mask = 0; 352 353 if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) { 354 /* 355 * Initialize xvattr, including bzero 356 */ 357 xva_init(&tmp_xvattr); 358 xoap = xva_getxoptattr(&tmp_xvattr); 359 360 ASSERT(xoap); 361 362 /* 363 * Copy caller-specified classic attributes to tmp_xvattr. 364 * First save tmp_xvattr's mask (set in xva_init()). 365 * This is |'d in later. 366 */ 367 368 xva_mask = tmp_xvattr.xva_vattr.va_mask; 369 tmp_xvattr.xva_vattr = set_attr->sa_vattr; 370 371 smb_sa_to_va_mask(set_attr->sa_mask, 372 &tmp_xvattr.xva_vattr.va_mask); 373 374 /* 375 * "|" in the original xva_mask. 376 */ 377 378 tmp_xvattr.xva_vattr.va_mask |= xva_mask; 379 380 if (set_attr->sa_mask & SMB_AT_DOSATTR) { 381 XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE); 382 XVA_SET_REQ(&tmp_xvattr, XAT_SYSTEM); 383 XVA_SET_REQ(&tmp_xvattr, XAT_READONLY); 384 XVA_SET_REQ(&tmp_xvattr, XAT_HIDDEN); 385 386 /* 387 * set_attr->sa_dosattr: If a given bit is not set, 388 * that indicates that the corresponding field needs 389 * to be updated with a "0" value. This is done 390 * implicitly as the xoap->xoa_* fields were bzero'd. 391 */ 392 393 if (set_attr->sa_dosattr & FILE_ATTRIBUTE_ARCHIVE) 394 xoap->xoa_archive = 1; 395 396 if (set_attr->sa_dosattr & FILE_ATTRIBUTE_SYSTEM) 397 xoap->xoa_system = 1; 398 399 if (set_attr->sa_dosattr & FILE_ATTRIBUTE_READONLY) 400 xoap->xoa_readonly = 1; 401 402 if (set_attr->sa_dosattr & FILE_ATTRIBUTE_HIDDEN) 403 xoap->xoa_hidden = 1; 404 } 405 406 if (set_attr->sa_mask & SMB_AT_CRTIME) { 407 XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME); 408 xoap->xoa_createtime = set_attr->sa_crtime; 409 } 410 411 if ((error = VOP_SETATTR(use_vp, (vattr_t *)&tmp_xvattr, flags, 412 cr, ct)) != 0) 413 return (error); 414 415 /* 416 * If the size of the stream needs to be set, set it on 417 * the stream file directly. (All other indicated attributes 418 * are set on the stream's unnamed stream, above.) 419 */ 420 421 if (at_size) { 422 /* 423 * set_attr->sa_vattr.va_size already contains the 424 * size as set by the caller 425 * 426 * Note that vp is used here, and not use_vp. 427 * Also, only AT_SIZE is needed. 428 */ 429 430 set_attr->sa_vattr.va_mask = AT_SIZE; 431 error = VOP_SETATTR(vp, &set_attr->sa_vattr, flags, 432 cr, ct); 433 } 434 435 return (error); 436 } 437 438 /* 439 * Support for file systems without VFSFT_XVATTR 440 */ 441 442 smb_sa_to_va_mask(set_attr->sa_mask, &set_attr->sa_vattr.va_mask); 443 444 /* 445 * set_attr->sa_vattr already contains new values 446 * as set by the caller 447 */ 448 449 error = VOP_SETATTR(use_vp, &set_attr->sa_vattr, flags, cr, ct); 450 451 if (error != 0) 452 return (error); 453 454 if (at_size) { 455 /* 456 * set_attr->sa_vattr.va_size already contains the 457 * size as set by the caller 458 * 459 * Note that vp is used here, and not use_vp. 460 * Also, only AT_SIZE is needed. 461 */ 462 463 set_attr->sa_vattr.va_mask = AT_SIZE; 464 error = VOP_SETATTR(vp, &set_attr->sa_vattr, flags, cr, ct); 465 } 466 467 return (error); 468 } 469 470 /* 471 * smb_vop_access 472 * 473 * This is a wrapper round VOP_ACCESS. VOP_ACCESS checks the given mode 474 * against file's ACL or Unix permissions. CIFS on the other hand needs to 475 * know if the requested operation can succeed for the given object, this 476 * requires more checks in case of DELETE bit since permissions on the parent 477 * directory are important as well. Based on Windows rules if parent's ACL 478 * grant FILE_DELETE_CHILD a file can be delete regardless of the file's 479 * permissions. 480 */ 481 int 482 smb_vop_access(vnode_t *vp, int mode, int flags, vnode_t *dir_vp, cred_t *cr) 483 { 484 int error = 0; 485 486 if (mode == 0) 487 return (0); 488 489 if ((flags == V_ACE_MASK) && (mode & ACE_DELETE)) { 490 if (dir_vp) { 491 error = VOP_ACCESS(dir_vp, ACE_DELETE_CHILD, flags, 492 cr, NULL); 493 494 if (error == 0) 495 mode &= ~ACE_DELETE; 496 } 497 } 498 499 if (mode) { 500 error = VOP_ACCESS(vp, mode, flags, cr, NULL); 501 } 502 503 return (error); 504 } 505 506 /* 507 * smb_vop_lookup 508 * 509 * dvp: directory vnode (in) 510 * name: name of file to be looked up (in) 511 * vpp: looked-up vnode (out) 512 * od_name: on-disk name of file (out). 513 * This parameter is optional. If a pointer is passed in, it 514 * must be allocated with MAXNAMELEN bytes 515 * rootvp: vnode of the tree root (in) 516 * This parameter is always passed in non-NULL except at the time 517 * of share set up. 518 */ 519 520 int 521 smb_vop_lookup(vnode_t *dvp, char *name, vnode_t **vpp, char *od_name, 522 int flags, vnode_t *rootvp, cred_t *cr, caller_context_t *ct) 523 { 524 int error = 0; 525 int option_flags = 0; 526 pathname_t rpn; 527 528 if (*name == '\0') 529 return (EINVAL); 530 531 ASSERT(vpp); 532 *vpp = NULL; 533 534 if ((name[0] == '.') && (name[1] == '.') && (name[2] == 0)) { 535 if (rootvp && (dvp == rootvp)) { 536 VN_HOLD(dvp); 537 *vpp = dvp; 538 return (0); 539 } 540 541 if (dvp->v_flag & VROOT) { 542 vfs_t *vfsp; 543 vnode_t *cvp = dvp; 544 545 /* 546 * Set dvp and check for races with forced unmount 547 * (see lookuppnvp()) 548 */ 549 550 vfsp = cvp->v_vfsp; 551 vfs_rlock_wait(vfsp); 552 if (((dvp = cvp->v_vfsp->vfs_vnodecovered) == NULL) || 553 (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) { 554 vfs_unlock(vfsp); 555 return (EIO); 556 } 557 vfs_unlock(vfsp); 558 } 559 } 560 561 562 563 if (flags & SMB_IGNORE_CASE) 564 option_flags = FIGNORECASE; 565 566 pn_alloc(&rpn); 567 568 error = VOP_LOOKUP(dvp, name, vpp, NULL, option_flags, NULL, cr, 569 ct, NULL, &rpn); 570 571 if ((error == 0) && od_name) { 572 bzero(od_name, MAXNAMELEN); 573 if (option_flags == FIGNORECASE) 574 (void) strlcpy(od_name, rpn.pn_buf, MAXNAMELEN); 575 else 576 (void) strlcpy(od_name, name, MAXNAMELEN); 577 } 578 579 pn_free(&rpn); 580 return (error); 581 } 582 583 int 584 smb_vop_create(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp, 585 int flags, cred_t *cr, caller_context_t *ct, vsecattr_t *vsap) 586 { 587 int error; 588 int option_flags = 0; 589 590 if (flags & SMB_IGNORE_CASE) 591 option_flags = FIGNORECASE; 592 593 smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask); 594 595 error = VOP_CREATE(dvp, name, &attr->sa_vattr, EXCL, 596 attr->sa_vattr.va_mode, vpp, cr, option_flags, ct, vsap); 597 598 return (error); 599 } 600 601 int 602 smb_vop_remove(vnode_t *dvp, char *name, int flags, cred_t *cr, 603 caller_context_t *ct) 604 { 605 int error; 606 int option_flags = 0; 607 608 if (flags & SMB_IGNORE_CASE) 609 option_flags = FIGNORECASE; 610 611 error = VOP_REMOVE(dvp, name, cr, ct, option_flags); 612 613 return (error); 614 } 615 616 /* 617 * smb_vop_rename() 618 * 619 * The rename is for files in the same tree (identical TID) only. 620 */ 621 622 int 623 smb_vop_rename(vnode_t *from_dvp, char *from_name, vnode_t *to_dvp, 624 char *to_name, int flags, cred_t *cr, caller_context_t *ct) 625 { 626 int error; 627 int option_flags = 0; 628 629 630 if (flags & SMB_IGNORE_CASE) 631 option_flags = FIGNORECASE; 632 633 error = VOP_RENAME(from_dvp, from_name, to_dvp, to_name, cr, 634 ct, option_flags); 635 636 return (error); 637 } 638 639 int 640 smb_vop_mkdir(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp, 641 int flags, cred_t *cr, caller_context_t *ct, vsecattr_t *vsap) 642 { 643 int error; 644 int option_flags = 0; 645 646 647 648 if (flags & SMB_IGNORE_CASE) 649 option_flags = FIGNORECASE; 650 651 smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask); 652 653 error = VOP_MKDIR(dvp, name, &attr->sa_vattr, vpp, cr, ct, 654 option_flags, vsap); 655 656 return (error); 657 } 658 659 /* 660 * smb_vop_rmdir() 661 * 662 * Only simple rmdir supported, consistent with NT semantics 663 * (can only remove an empty directory). 664 * 665 */ 666 667 int 668 smb_vop_rmdir(vnode_t *dvp, char *name, int flags, cred_t *cr, 669 caller_context_t *ct) 670 { 671 int error; 672 int option_flags = 0; 673 674 if (flags & SMB_IGNORE_CASE) 675 option_flags = FIGNORECASE; 676 677 /* 678 * Comments adapted from rfs_rmdir(). 679 * 680 * VOP_RMDIR now takes a new third argument (the current 681 * directory of the process). That's because rmdir 682 * wants to return EINVAL if one tries to remove ".". 683 * Of course, SMB servers do not know what their 684 * clients' current directories are. We fake it by 685 * supplying a vnode known to exist and illegal to 686 * remove. 687 */ 688 689 error = VOP_RMDIR(dvp, name, rootdir, cr, ct, option_flags); 690 return (error); 691 } 692 693 int 694 smb_vop_commit(vnode_t *vp, cred_t *cr, caller_context_t *ct) 695 { 696 return (VOP_FSYNC(vp, 1, cr, ct)); 697 } 698 699 /* 700 * smb_vop_readdir() 701 * 702 * Upon return, the "name" field will contain either the on-disk name or, if 703 * it needs mangling or has a case-insensitive collision, the mangled 704 * "shortname." 705 * 706 * vpp is an optional parameter. If non-NULL, it will contain a pointer to 707 * the vnode for the name that is looked up (the vnode will be returned held). 708 * 709 * od_name is an optional parameter (NULL can be passed if the on-disk name 710 * is not needed by the caller). 711 */ 712 713 int 714 smb_vop_readdir(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen, 715 ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr, 716 caller_context_t *ct) 717 { 718 int num_bytes; 719 int error = 0; 720 char *dirbuf = NULL; 721 722 ASSERT(dvp); 723 ASSERT(cookiep); 724 ASSERT(name); 725 ASSERT(namelen); 726 ASSERT(inop); 727 ASSERT(cr); 728 ASSERT(ct); 729 730 if (dvp->v_type != VDIR) { 731 *namelen = 0; 732 return (ENOTDIR); 733 } 734 735 if (vpp) 736 *vpp = NULL; 737 738 dirbuf = kmem_zalloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP); 739 num_bytes = SMB_MINLEN_RDDIR_BUF; 740 741 /* 742 * The goal is to retrieve the first valid entry from *cookiep 743 * forward. smb_vop_readdir_readpage() collects an 744 * SMB_MINLEN_RDDIR_BUF-size "page" of directory entry information. 745 * smb_vop_readdir_entry() attempts to find the first valid entry 746 * in that page. 747 */ 748 749 while ((error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep, 750 &num_bytes, cr, ct, flags)) == 0) { 751 752 if (num_bytes <= 0) 753 break; 754 755 name[0] = '\0'; 756 757 error = smb_vop_readdir_entry(dvp, cookiep, name, namelen, 758 inop, vpp, od_name, flags, cr, ct, dirbuf, 759 num_bytes); 760 761 if (error) 762 break; 763 764 if (*name) 765 break; 766 767 bzero(dirbuf, SMB_MINLEN_RDDIR_BUF); 768 num_bytes = SMB_MINLEN_RDDIR_BUF; 769 } 770 771 772 if (error) { 773 kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 774 *namelen = 0; 775 return (error); 776 } 777 778 if (num_bytes == 0) { /* EOF */ 779 kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 780 *cookiep = SMB_EOF; 781 *namelen = 0; 782 return (0); 783 } 784 785 kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 786 return (0); 787 } 788 789 /* 790 * smb_vop_readdir_readpage() 791 * 792 * Collects an SMB_MINLEN_RDDIR_BUF "page" of directory entries. (The 793 * directory entries are returned in an fs-independent format by the 794 * underlying file system. That is, the "page" of information returned is 795 * not literally stored on-disk in the format returned.) 796 * 797 * Much of the following is borrowed from getdents64() 798 * 799 * MAXGETDENTS_SIZE is defined in getdents.c 800 */ 801 802 #define MAXGETDENTS_SIZE (64 * 1024) 803 804 static int 805 smb_vop_readdir_readpage(vnode_t *vp, void *buf, uint32_t offset, int *count, 806 cred_t *cr, caller_context_t *ct, int flags) 807 { 808 int error = 0; 809 int rdirent_flags = 0; 810 int sink; 811 struct uio auio; 812 struct iovec aiov; 813 814 if (vp->v_type != VDIR) 815 return (ENOTDIR); 816 817 /* entflags not working for streams so don't try to use them */ 818 if (!(flags & SMB_STREAM_RDDIR) && 819 (vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS))) { 820 /* 821 * Setting V_RDDIR_ENTFLAGS will cause the buffer to 822 * be filled with edirent_t structures (instead of 823 * dirent64_t structures). 824 */ 825 rdirent_flags = V_RDDIR_ENTFLAGS; 826 827 if (*count < sizeof (edirent_t)) 828 return (EINVAL); 829 } else { 830 if (*count < sizeof (dirent64_t)) 831 return (EINVAL); 832 } 833 834 if (*count > MAXGETDENTS_SIZE) 835 *count = MAXGETDENTS_SIZE; 836 837 aiov.iov_base = buf; 838 aiov.iov_len = *count; 839 auio.uio_iov = &aiov; 840 auio.uio_iovcnt = 1; 841 auio.uio_loffset = (uint64_t)offset; 842 auio.uio_segflg = UIO_SYSSPACE; 843 auio.uio_resid = *count; 844 auio.uio_fmode = 0; 845 846 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 847 error = VOP_READDIR(vp, &auio, cr, &sink, ct, rdirent_flags); 848 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 849 850 if (error) { 851 if (error == ENOENT) { 852 /* Fake EOF if offset is bad due to dropping of lock */ 853 *count = 0; 854 return (0); 855 } else { 856 return (error); 857 } 858 } 859 860 /* 861 * Windows cannot handle an offset > SMB_EOF. 862 * Pretend we are at EOF. 863 */ 864 865 if (auio.uio_loffset > SMB_EOF) { 866 *count = 0; 867 return (0); 868 } 869 870 *count = *count - auio.uio_resid; 871 return (0); 872 } 873 874 /* 875 * smb_vop_readdir_entry() 876 * 877 * This function retrieves the first valid entry from the 878 * SMB_MINLEN_RDDIR_BUF-sized buffer returned by smb_vop_readdir_readpage() 879 * to smb_vop_readdir(). 880 * 881 * Both dirent64_t and edirent_t structures need to be handled. The former is 882 * needed for file systems that do not support VFSFT_DIRENTFLAGS. The latter 883 * is required for proper handling of case collisions on file systems that 884 * support case-insensitivity. edirent_t structures are also used for 885 * case-sensitive file systems if VFSFT_DIRENTFLAGS is supported. 886 */ 887 888 static int 889 smb_vop_readdir_entry(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen, 890 ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr, 891 caller_context_t *ct, char *dirbuf, int num_bytes) 892 { 893 uint32_t next_cookie; 894 int ebufsize; 895 int error = 0; 896 int len; 897 int rc; 898 char shortname[MANGLE_NAMELEN]; 899 char name83[MANGLE_NAMELEN]; 900 char *ebuf = NULL; 901 edirent_t *edp; 902 dirent64_t *dp = NULL; 903 vnode_t *vp = NULL; 904 905 ASSERT(dirbuf); 906 907 /* 908 * Use edirent_t structure for both 909 * entflags not working for streams so don't try to use them 910 */ 911 if (!(flags & SMB_STREAM_RDDIR) && 912 (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS))) { 913 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 914 edp = (edirent_t *)dirbuf; 915 } else { 916 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 917 dp = (dirent64_t *)dirbuf; 918 ebufsize = EDIRENT_RECLEN(MAXNAMELEN); 919 ebuf = kmem_zalloc(ebufsize, KM_SLEEP); 920 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 921 edp = (edirent_t *)ebuf; 922 } 923 924 while (edp) { 925 if (dp) 926 DP_TO_EDP(dp, edp); 927 928 next_cookie = (uint32_t)edp->ed_off; 929 if (edp->ed_ino == 0) { 930 *cookiep = next_cookie; 931 932 if (dp) { 933 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 934 DP_ADVANCE(dp, dirbuf, num_bytes); 935 if (dp == NULL) 936 edp = NULL; 937 } else { 938 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 939 EDP_ADVANCE(edp, dirbuf, num_bytes); 940 } 941 continue; 942 } 943 944 len = strlen(edp->ed_name); 945 946 if (*namelen < len) { 947 *namelen = 0; 948 949 if (ebuf) 950 kmem_free(ebuf, ebufsize); 951 952 return (EOVERFLOW); 953 } 954 955 /* 956 * Do not pass SMB_IGNORE_CASE to smb_vop_lookup 957 */ 958 959 error = smb_vop_lookup(dvp, edp->ed_name, vpp ? vpp : &vp, 960 od_name, 0, NULL, cr, ct); 961 962 if (error) { 963 if (error == ENOENT) { 964 *cookiep = (uint32_t)next_cookie; 965 966 if (dp) { 967 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 968 DP_ADVANCE(dp, dirbuf, num_bytes); 969 if (dp == NULL) 970 edp = NULL; 971 } else { 972 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 973 EDP_ADVANCE(edp, dirbuf, num_bytes); 974 } 975 continue; 976 } 977 978 979 *namelen = 0; 980 981 if (ebuf) 982 kmem_free(ebuf, ebufsize); 983 984 return (error); 985 } 986 987 if ((flags & SMB_IGNORE_CASE) && ED_CASE_CONFLICTS(edp)) { 988 rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 989 shortname, name83, 1); 990 991 if (rc == 1) { /* success */ 992 (void) strlcpy(name, shortname, *namelen + 1); 993 *namelen = strlen(shortname); 994 } else { 995 (void) strlcpy(name, edp->ed_name, 996 *namelen + 1); 997 name[*namelen] = '\0'; 998 } 999 1000 } else { 1001 (void) strlcpy(name, edp->ed_name, *namelen + 1); 1002 *namelen = len; 1003 } 1004 1005 if (vpp == NULL) 1006 VN_RELE(vp); 1007 1008 if (inop) 1009 *inop = edp->ed_ino; 1010 1011 *cookiep = (uint32_t)next_cookie; 1012 break; 1013 } 1014 1015 if (ebuf) 1016 kmem_free(ebuf, ebufsize); 1017 1018 return (error); 1019 } 1020 1021 /* 1022 * smb_sa_to_va_mask 1023 * 1024 * Set va_mask by running through the SMB_AT_* #define's and 1025 * setting those bits that correspond to the SMB_AT_* bits 1026 * set in sa_mask. 1027 */ 1028 1029 void 1030 smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp) 1031 { 1032 int i; 1033 uint_t smask; 1034 1035 smask = (sa_mask); 1036 for (i = SMB_AT_TYPE; (i < SMB_AT_MAX) && (smask != 0); ++i) { 1037 if (smask & 1) 1038 *(va_maskp) |= smb_attrmap[i]; 1039 1040 smask >>= 1; 1041 } 1042 } 1043 1044 /* 1045 * smb_vop_getdents() 1046 * 1047 * Upon success, the smb_node corresponding to each entry returned will 1048 * have a reference taken on it. These will be released in 1049 * smb_trans2_find_get_dents(). 1050 * 1051 * If an error is returned from this routine, a list of already processed 1052 * entries will be returned. The smb_nodes corresponding to these entries 1053 * will be referenced, and will be released in smb_trans2_find_get_dents(). 1054 * 1055 * The returned dp->d_name field will contain either the on-disk name or, if 1056 * it needs mangling or has a case-insensitive collision, the mangled 1057 * "shortname." In this case, the on-disk name can be retrieved from the 1058 * smb_node's od_name (the smb_node is passed to smb_gather_dents_info()). 1059 */ 1060 1061 int /*ARGSUSED*/ 1062 smb_vop_getdents( 1063 smb_node_t *dir_snode, 1064 uint32_t *cookiep, 1065 uint64_t *verifierp, 1066 int32_t *dircountp, 1067 char *arg, 1068 char *pattern, 1069 uint32_t flags, 1070 smb_request_t *sr, 1071 cred_t *cr, 1072 caller_context_t *ct) 1073 { 1074 int error = 0; 1075 int maxentries; 1076 int num_bytes; 1077 int resid; 1078 char *dirbuf = NULL; 1079 vnode_t *dvp; 1080 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1081 smb_dent_info_hdr_t *ihdr = (smb_dent_info_hdr_t *)arg; 1082 1083 dvp = dir_snode->vp; 1084 1085 resid = ihdr->uio.uio_resid; 1086 maxentries = resid / SMB_MAX_DENT_INFO_SIZE; 1087 1088 bzero(ihdr->iov->iov_base, resid); 1089 1090 dirbuf = kmem_alloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP); 1091 1092 while (maxentries) { 1093 1094 bzero(dirbuf, SMB_MINLEN_RDDIR_BUF); 1095 1096 num_bytes = SMB_MINLEN_RDDIR_BUF; 1097 error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep, 1098 &num_bytes, cr, ct, flags); 1099 1100 if (error || (num_bytes <= 0)) 1101 break; 1102 1103 error = smb_vop_getdents_entries(dir_snode, cookiep, dircountp, 1104 arg, flags, sr, cr, ct, dirbuf, &maxentries, num_bytes, 1105 pattern); 1106 1107 if (error) 1108 goto out; 1109 } 1110 1111 if (num_bytes < 0) { 1112 error = -1; 1113 } else if (num_bytes == 0) { 1114 *cookiep = SMB_EOF; 1115 error = 0; 1116 } else { 1117 error = 0; 1118 } 1119 1120 out: 1121 if (dirbuf) 1122 kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 1123 1124 return (error); 1125 } 1126 1127 /* 1128 * smb_vop_getdents_entries() 1129 * 1130 * This function retrieves names from the SMB_MINLEN_RDDIR_BUF-sized buffer 1131 * returned by smb_vop_readdir_readpage() to smb_vop_getdents(). 1132 * 1133 * Both dirent64_t and edirent_t structures need to be handled. The former is 1134 * needed for file systems that do not support VFSFT_DIRENTFLAGS. The latter 1135 * is required for properly handling case collisions on file systems that 1136 * support case-insensitivity. edirent_t is also used on case-sensitive 1137 * file systems where VFSFT_DIRENTFLAGS is available. 1138 */ 1139 1140 static int 1141 smb_vop_getdents_entries( 1142 smb_node_t *dir_snode, 1143 uint32_t *cookiep, 1144 int32_t *dircountp, 1145 char *arg, 1146 uint32_t flags, 1147 struct smb_request *sr, 1148 cred_t *cr, 1149 caller_context_t *ct, 1150 char *dirbuf, 1151 int *maxentries, 1152 int num_bytes, 1153 char *pattern) 1154 { 1155 uint32_t next_cookie; 1156 int ebufsize; 1157 char *tmp_name; 1158 int error; 1159 int rc; 1160 char shortname[MANGLE_NAMELEN]; 1161 char name83[MANGLE_NAMELEN]; 1162 char *ebuf = NULL; 1163 dirent64_t *dp = NULL; 1164 edirent_t *edp; 1165 smb_node_t *ret_snode; 1166 smb_attr_t ret_attr; 1167 vnode_t *dvp; 1168 vnode_t *fvp; 1169 1170 ASSERT(dirbuf); 1171 1172 dvp = dir_snode->vp; 1173 1174 if (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS)) { 1175 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1176 edp = (edirent_t *)dirbuf; 1177 } else { 1178 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1179 dp = (dirent64_t *)dirbuf; 1180 ebufsize = EDIRENT_RECLEN(MAXNAMELEN); 1181 ebuf = kmem_zalloc(ebufsize, KM_SLEEP); 1182 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1183 edp = (edirent_t *)ebuf; 1184 } 1185 1186 while (edp) { 1187 if (dp) 1188 DP_TO_EDP(dp, edp); 1189 1190 if (*maxentries == 0) 1191 break; 1192 1193 next_cookie = (uint32_t)edp->ed_off; 1194 1195 if (edp->ed_ino == 0) { 1196 *cookiep = next_cookie; 1197 if (dp) { 1198 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1199 DP_ADVANCE(dp, dirbuf, num_bytes); 1200 if (dp == NULL) 1201 edp = NULL; 1202 } else { 1203 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1204 EDP_ADVANCE(edp, dirbuf, num_bytes); 1205 } 1206 continue; 1207 } 1208 1209 error = smb_vop_lookup(dvp, edp->ed_name, &fvp, 1210 NULL, 0, NULL, cr, ct); 1211 1212 if (error) { 1213 if (error == ENOENT) { 1214 *cookiep = next_cookie; 1215 if (dp) { 1216 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1217 DP_ADVANCE(dp, dirbuf, 1218 num_bytes); 1219 if (dp == NULL) 1220 edp = NULL; 1221 } else { 1222 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1223 EDP_ADVANCE(edp, dirbuf, 1224 num_bytes); 1225 } 1226 continue; 1227 } 1228 if (ebuf) 1229 kmem_free(ebuf, ebufsize); 1230 1231 return (error); 1232 } 1233 1234 ret_snode = smb_node_lookup(sr, NULL, cr, fvp, 1235 edp->ed_name, dir_snode, NULL, &ret_attr); 1236 1237 if (ret_snode == NULL) { 1238 VN_RELE(fvp); 1239 1240 if (ebuf) 1241 kmem_free(ebuf, ebufsize); 1242 1243 return (ENOMEM); 1244 } 1245 1246 if (smb_match_name(edp->ed_ino, edp->ed_name, shortname, 1247 name83, pattern, (flags & SMB_IGNORE_CASE))) { 1248 1249 tmp_name = edp->ed_name; 1250 1251 if ((flags & SMB_IGNORE_CASE) && 1252 ED_CASE_CONFLICTS(edp)) { 1253 rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 1254 shortname, name83, 1); 1255 if (rc == 1) 1256 tmp_name = shortname; 1257 } else { 1258 rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 1259 shortname, name83, 0); 1260 } 1261 1262 if (rc != 1) { 1263 (void) strlcpy(shortname, edp->ed_name, 1264 MANGLE_NAMELEN); 1265 (void) strlcpy(name83, edp->ed_name, 1266 MANGLE_NAMELEN); 1267 shortname[MANGLE_NAMELEN - 1] = '\0'; 1268 name83[MANGLE_NAMELEN - 1] = '\0'; 1269 } 1270 1271 error = smb_gather_dents_info(arg, edp->ed_ino, 1272 strlen(tmp_name), tmp_name, next_cookie, dircountp, 1273 &ret_attr, ret_snode, shortname, name83); 1274 1275 if (error > 0) { 1276 if (ebuf) 1277 kmem_free(ebuf, ebufsize); 1278 return (error); 1279 } 1280 1281 /* 1282 * Treat errors from smb_gather_dents_info() that are 1283 * < 0 the same as EOF. 1284 */ 1285 if (error < 0) { 1286 if (ebuf) 1287 kmem_free(ebuf, ebufsize); 1288 *maxentries = 0; 1289 return (0); 1290 } 1291 (*maxentries)--; 1292 } else { 1293 smb_node_release(ret_snode); 1294 } 1295 1296 *cookiep = next_cookie; 1297 1298 if (dp) { 1299 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1300 DP_ADVANCE(dp, dirbuf, num_bytes); 1301 if (dp == NULL) 1302 edp = NULL; 1303 } else { 1304 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1305 EDP_ADVANCE(edp, dirbuf, num_bytes); 1306 } 1307 } 1308 1309 if (ebuf) 1310 kmem_free(ebuf, ebufsize); 1311 1312 return (0); 1313 } 1314 1315 /* 1316 * smb_vop_stream_lookup() 1317 * 1318 * The name returned in od_name is the on-disk name of the stream with the 1319 * SMB_STREAM_PREFIX stripped off. od_name should be allocated to MAXNAMELEN 1320 * by the caller. 1321 */ 1322 1323 int 1324 smb_vop_stream_lookup(vnode_t *fvp, char *stream_name, vnode_t **vpp, 1325 char *od_name, vnode_t **xattrdirvpp, int flags, vnode_t *rootvp, 1326 cred_t *cr, caller_context_t *ct) 1327 { 1328 char *solaris_stream_name; 1329 char *name; 1330 int error; 1331 1332 if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp, 1333 LOOKUP_XATTR | CREATE_XATTR_DIR, cr, ct)) != 0) 1334 return (error); 1335 1336 /* 1337 * Prepend SMB_STREAM_PREFIX to stream name 1338 */ 1339 1340 solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1341 (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 1342 stream_name); 1343 1344 /* 1345 * "name" will hold the on-disk name returned from smb_vop_lookup 1346 * for the stream, including the SMB_STREAM_PREFIX. 1347 */ 1348 1349 name = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 1350 1351 if ((error = smb_vop_lookup(*xattrdirvpp, solaris_stream_name, vpp, 1352 name, flags, rootvp, cr, ct)) != 0) { 1353 VN_RELE(*xattrdirvpp); 1354 } else { 1355 (void) strlcpy(od_name, &(name[SMB_STREAM_PREFIX_LEN]), 1356 MAXNAMELEN); 1357 } 1358 1359 kmem_free(solaris_stream_name, MAXNAMELEN); 1360 kmem_free(name, MAXNAMELEN); 1361 1362 return (error); 1363 } 1364 1365 int 1366 smb_vop_stream_create(vnode_t *fvp, char *stream_name, smb_attr_t *attr, 1367 vnode_t **vpp, vnode_t **xattrdirvpp, int flags, cred_t *cr, 1368 caller_context_t *ct) 1369 { 1370 char *solaris_stream_name; 1371 int error; 1372 1373 if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp, 1374 LOOKUP_XATTR | CREATE_XATTR_DIR, cr, ct)) != 0) 1375 return (error); 1376 1377 /* 1378 * Prepend SMB_STREAM_PREFIX to stream name 1379 */ 1380 1381 solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1382 (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 1383 stream_name); 1384 1385 if ((error = smb_vop_create(*xattrdirvpp, solaris_stream_name, attr, 1386 vpp, flags, cr, ct, NULL)) != 0) 1387 VN_RELE(*xattrdirvpp); 1388 1389 kmem_free(solaris_stream_name, MAXNAMELEN); 1390 1391 return (error); 1392 } 1393 1394 int 1395 smb_vop_stream_remove(vnode_t *vp, char *stream_name, int flags, cred_t *cr, 1396 caller_context_t *ct) 1397 { 1398 char *solaris_stream_name; 1399 vnode_t *xattrdirvp; 1400 int error; 1401 1402 if ((error = smb_vop_lookup_xattrdir(vp, &xattrdirvp, LOOKUP_XATTR, cr, 1403 ct)) != 0) 1404 return (error); 1405 1406 /* 1407 * Prepend SMB_STREAM_PREFIX to stream name 1408 */ 1409 1410 solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1411 (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 1412 stream_name); 1413 1414 /* XXX might have to use kcred */ 1415 error = smb_vop_remove(xattrdirvp, solaris_stream_name, flags, cr, ct); 1416 1417 kmem_free(solaris_stream_name, MAXNAMELEN); 1418 1419 return (error); 1420 } 1421 1422 /* 1423 * smb_vop_stream_readdir() 1424 * 1425 * Note: stream_info.size is not filled in in this routine. 1426 * It needs to be filled in by the caller due to the parameters for getattr. 1427 * 1428 * stream_info.name is set to the on-disk stream name with the SMB_STREAM_PREFIX 1429 * removed. 1430 */ 1431 1432 int 1433 smb_vop_stream_readdir(vnode_t *fvp, uint32_t *cookiep, 1434 struct fs_stream_info *stream_info, vnode_t **vpp, vnode_t **xattrdirvpp, 1435 int flags, cred_t *cr, caller_context_t *ct) 1436 { 1437 int nsize = MAXNAMELEN-1; 1438 int error = 0; 1439 ino64_t ino; 1440 char *tmp_name; 1441 vnode_t *xattrdirvp; 1442 vnode_t *vp; 1443 1444 if ((error = smb_vop_lookup_xattrdir(fvp, &xattrdirvp, LOOKUP_XATTR, 1445 cr, ct)) != 0) 1446 return (error); 1447 1448 bzero(stream_info->name, sizeof (stream_info->name)); 1449 stream_info->size = 0; 1450 1451 tmp_name = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 1452 1453 for (;;) { 1454 error = smb_vop_readdir(xattrdirvp, cookiep, tmp_name, &nsize, 1455 &ino, &vp, NULL, flags | SMB_STREAM_RDDIR, cr, ct); 1456 1457 if (error || (*cookiep == SMB_EOF)) 1458 break; 1459 1460 if (strncmp(tmp_name, SMB_STREAM_PREFIX, 1461 SMB_STREAM_PREFIX_LEN)) { 1462 VN_RELE(vp); 1463 continue; 1464 } 1465 1466 tmp_name[nsize] = '\0'; 1467 (void) strlcpy(stream_info->name, 1468 &(tmp_name[SMB_STREAM_PREFIX_LEN]), 1469 sizeof (stream_info->name)); 1470 1471 nsize -= SMB_STREAM_PREFIX_LEN; 1472 break; 1473 } 1474 1475 if ((error == 0) && nsize) { 1476 if (vpp) 1477 *vpp = vp; 1478 else 1479 VN_RELE(vp); 1480 1481 if (xattrdirvpp) 1482 *xattrdirvpp = xattrdirvp; 1483 else 1484 VN_RELE(xattrdirvp); 1485 1486 } 1487 1488 kmem_free(tmp_name, MAXNAMELEN); 1489 1490 return (error); 1491 } 1492 1493 int 1494 smb_vop_lookup_xattrdir(vnode_t *fvp, vnode_t **xattrdirvpp, int flags, 1495 cred_t *cr, caller_context_t *ct) 1496 { 1497 int error; 1498 1499 error = VOP_LOOKUP(fvp, "", xattrdirvpp, NULL, flags, NULL, cr, ct, 1500 NULL, NULL); 1501 return (error); 1502 } 1503 1504 /* 1505 * smb_vop_traverse_check() 1506 * 1507 * This function checks to see if the passed-in vnode has a file system 1508 * mounted on it. If it does, the mount point is "traversed" and the 1509 * vnode for the root of the file system is returned. 1510 */ 1511 1512 int 1513 smb_vop_traverse_check(vnode_t **vpp) 1514 { 1515 int error; 1516 1517 if (vn_mountedvfs(*vpp) == 0) 1518 return (0); 1519 1520 /* 1521 * traverse() may return a different held vnode, even in the error case. 1522 * If it returns a different vnode, it will have released the original. 1523 */ 1524 1525 error = traverse(vpp); 1526 1527 return (error); 1528 } 1529 1530 int /*ARGSUSED*/ 1531 smb_vop_statfs(vnode_t *vp, struct statvfs64 *statp, cred_t *cr) 1532 { 1533 int error; 1534 1535 error = VFS_STATVFS(vp->v_vfsp, statp); 1536 1537 return (error); 1538 } 1539 1540 /* 1541 * smb_vop_acl_from_vsa 1542 * 1543 * Converts given vsecattr_t structure to a acl_t structure. 1544 * 1545 * The allocated memory for retuned acl_t should be freed by 1546 * calling acl_free(). 1547 */ 1548 static acl_t * 1549 smb_vop_acl_from_vsa(vsecattr_t *vsecattr, acl_type_t acl_type) 1550 { 1551 int aclbsize = 0; /* size of acl list in bytes */ 1552 int dfaclbsize = 0; /* size of default acl list in bytes */ 1553 int numacls; 1554 acl_t *acl_info; 1555 1556 ASSERT(vsecattr); 1557 1558 acl_info = acl_alloc(acl_type); 1559 if (acl_info == NULL) 1560 return (NULL); 1561 1562 acl_info->acl_flags = 0; 1563 1564 switch (acl_type) { 1565 1566 case ACLENT_T: 1567 numacls = vsecattr->vsa_aclcnt + vsecattr->vsa_dfaclcnt; 1568 aclbsize = vsecattr->vsa_aclcnt * sizeof (aclent_t); 1569 dfaclbsize = vsecattr->vsa_dfaclcnt * sizeof (aclent_t); 1570 1571 acl_info->acl_cnt = numacls; 1572 acl_info->acl_aclp = kmem_alloc(aclbsize + dfaclbsize, 1573 KM_SLEEP); 1574 (void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp, 1575 aclbsize); 1576 (void) memcpy((char *)acl_info->acl_aclp + aclbsize, 1577 vsecattr->vsa_dfaclentp, dfaclbsize); 1578 1579 if (acl_info->acl_cnt <= MIN_ACL_ENTRIES) 1580 acl_info->acl_flags |= ACL_IS_TRIVIAL; 1581 1582 break; 1583 1584 case ACE_T: 1585 aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t); 1586 acl_info->acl_cnt = vsecattr->vsa_aclcnt; 1587 acl_info->acl_flags = vsecattr->vsa_aclflags; 1588 acl_info->acl_aclp = kmem_alloc(aclbsize, KM_SLEEP); 1589 (void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp, 1590 aclbsize); 1591 if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0) 1592 acl_info->acl_flags |= ACL_IS_TRIVIAL; 1593 1594 break; 1595 1596 default: 1597 acl_free(acl_info); 1598 return (NULL); 1599 } 1600 1601 if (aclbsize && vsecattr->vsa_aclentp) 1602 kmem_free(vsecattr->vsa_aclentp, aclbsize); 1603 if (dfaclbsize && vsecattr->vsa_dfaclentp) 1604 kmem_free(vsecattr->vsa_dfaclentp, dfaclbsize); 1605 1606 return (acl_info); 1607 } 1608 1609 /* 1610 * smb_vop_acl_to_vsa 1611 * 1612 * Converts given acl_t structure to a vsecattr_t structure. 1613 * 1614 * IMPORTANT: 1615 * Upon successful return the memory allocated for vsa_aclentp 1616 * should be freed by calling kmem_free(). The size is returned 1617 * in aclbsize. 1618 */ 1619 int 1620 smb_vop_acl_to_vsa(acl_t *acl_info, vsecattr_t *vsecattr, int *aclbsize) 1621 { 1622 int error = 0; 1623 int numacls; 1624 aclent_t *aclp; 1625 1626 ASSERT(acl_info); 1627 ASSERT(vsecattr); 1628 ASSERT(aclbsize); 1629 1630 bzero(vsecattr, sizeof (vsecattr_t)); 1631 *aclbsize = 0; 1632 1633 switch (acl_info->acl_type) { 1634 case ACLENT_T: 1635 numacls = acl_info->acl_cnt; 1636 /* 1637 * Minimum ACL size is three entries so might as well 1638 * bail out here. Also limit request size to prevent user 1639 * from allocating too much kernel memory. Maximum size 1640 * is MAX_ACL_ENTRIES for the ACL part and MAX_ACL_ENTRIES 1641 * for the default ACL part. 1642 */ 1643 if (numacls < 3 || numacls > (MAX_ACL_ENTRIES * 2)) { 1644 error = EINVAL; 1645 break; 1646 } 1647 1648 vsecattr->vsa_mask = VSA_ACL; 1649 1650 vsecattr->vsa_aclcnt = numacls; 1651 *aclbsize = numacls * sizeof (aclent_t); 1652 vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP); 1653 (void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp, 1654 *aclbsize); 1655 1656 /* Sort the acl list */ 1657 ksort((caddr_t)vsecattr->vsa_aclentp, 1658 vsecattr->vsa_aclcnt, sizeof (aclent_t), cmp2acls); 1659 1660 /* Break into acl and default acl lists */ 1661 for (numacls = 0, aclp = vsecattr->vsa_aclentp; 1662 numacls < vsecattr->vsa_aclcnt; 1663 aclp++, numacls++) { 1664 if (aclp->a_type & ACL_DEFAULT) 1665 break; 1666 } 1667 1668 /* Find where defaults start (if any) */ 1669 if (numacls < vsecattr->vsa_aclcnt) { 1670 vsecattr->vsa_mask |= VSA_DFACL; 1671 vsecattr->vsa_dfaclcnt = vsecattr->vsa_aclcnt - numacls; 1672 vsecattr->vsa_dfaclentp = aclp; 1673 vsecattr->vsa_aclcnt = numacls; 1674 } 1675 1676 /* Adjust if they're all defaults */ 1677 if (vsecattr->vsa_aclcnt == 0) { 1678 vsecattr->vsa_mask &= ~VSA_ACL; 1679 vsecattr->vsa_aclentp = NULL; 1680 } 1681 1682 /* Only directories can have defaults */ 1683 if (vsecattr->vsa_dfaclcnt && 1684 (acl_info->acl_flags & ACL_IS_DIR)) { 1685 error = ENOTDIR; 1686 } 1687 1688 break; 1689 1690 case ACE_T: 1691 if (acl_info->acl_cnt < 1 || 1692 acl_info->acl_cnt > MAX_ACL_ENTRIES) { 1693 error = EINVAL; 1694 break; 1695 } 1696 1697 vsecattr->vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS; 1698 vsecattr->vsa_aclcnt = acl_info->acl_cnt; 1699 vsecattr->vsa_aclflags = acl_info->acl_flags & ACL_FLAGS_ALL; 1700 *aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t); 1701 vsecattr->vsa_aclentsz = *aclbsize; 1702 vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP); 1703 (void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp, 1704 *aclbsize); 1705 1706 break; 1707 1708 default: 1709 error = EINVAL; 1710 } 1711 1712 return (error); 1713 } 1714 1715 /* 1716 * smb_vop_acl_read 1717 * 1718 * Reads the ACL of the specified file into 'aclp'. 1719 * acl_type is the type of ACL which the filesystem supports. 1720 * 1721 * Caller has to free the allocated memory for aclp by calling 1722 * acl_free(). 1723 */ 1724 int 1725 smb_vop_acl_read(vnode_t *vp, acl_t **aclp, int flags, acl_type_t acl_type, 1726 cred_t *cr, caller_context_t *ct) 1727 { 1728 int error; 1729 vsecattr_t vsecattr; 1730 1731 ASSERT(vp); 1732 ASSERT(aclp); 1733 1734 *aclp = NULL; 1735 bzero(&vsecattr, sizeof (vsecattr_t)); 1736 1737 switch (acl_type) { 1738 case ACLENT_T: 1739 vsecattr.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL | 1740 VSA_DFACLCNT; 1741 break; 1742 1743 case ACE_T: 1744 vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS; 1745 break; 1746 1747 default: 1748 return (EINVAL); 1749 } 1750 1751 if (error = VOP_GETSECATTR(vp, &vsecattr, flags, cr, ct)) 1752 return (error); 1753 1754 *aclp = smb_vop_acl_from_vsa(&vsecattr, acl_type); 1755 if (vp->v_type == VDIR) 1756 (*aclp)->acl_flags |= ACL_IS_DIR; 1757 1758 return (0); 1759 } 1760 1761 /* 1762 * smb_vop_acl_write 1763 * 1764 * Writes the given ACL in aclp for the specified file. 1765 */ 1766 int 1767 smb_vop_acl_write(vnode_t *vp, acl_t *aclp, int flags, cred_t *cr, 1768 caller_context_t *ct) 1769 { 1770 int error; 1771 vsecattr_t vsecattr; 1772 int aclbsize; 1773 1774 ASSERT(vp); 1775 ASSERT(aclp); 1776 1777 error = smb_vop_acl_to_vsa(aclp, &vsecattr, &aclbsize); 1778 1779 if (error == 0) { 1780 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 1781 error = VOP_SETSECATTR(vp, &vsecattr, flags, cr, ct); 1782 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 1783 } 1784 1785 if (aclbsize && vsecattr.vsa_aclentp) 1786 kmem_free(vsecattr.vsa_aclentp, aclbsize); 1787 1788 return (error); 1789 } 1790 1791 /* 1792 * smb_vop_acl_type 1793 * 1794 * Determines the ACL type for the given vnode. 1795 * ACLENT_T is a Posix ACL and ACE_T is a ZFS ACL. 1796 */ 1797 acl_type_t 1798 smb_vop_acl_type(vnode_t *vp) 1799 { 1800 int error; 1801 ulong_t whichacl; 1802 1803 error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl, kcred, NULL); 1804 if (error != 0) { 1805 /* 1806 * If we got an error, then the filesystem 1807 * likely does not understand the _PC_ACL_ENABLED 1808 * pathconf. In this case, we fall back to trying 1809 * POSIX-draft (aka UFS-style) ACLs. 1810 */ 1811 whichacl = _ACL_ACLENT_ENABLED; 1812 } 1813 1814 if (!(whichacl & (_ACL_ACE_ENABLED | _ACL_ACLENT_ENABLED))) { 1815 /* 1816 * If the file system supports neither ACE nor 1817 * ACLENT ACLs we will fall back to UFS-style ACLs 1818 * like we did above if there was an error upon 1819 * calling VOP_PATHCONF. 1820 * 1821 * ACE and ACLENT type ACLs are the only interfaces 1822 * supported thus far. If any other bits are set on 1823 * 'whichacl' upon return from VOP_PATHCONF, we will 1824 * ignore them. 1825 */ 1826 whichacl = _ACL_ACLENT_ENABLED; 1827 } 1828 1829 if (whichacl == _ACL_ACLENT_ENABLED) 1830 return (ACLENT_T); 1831 1832 return (ACE_T); 1833 } 1834 1835 static int zfs_perms[] = { 1836 ACE_READ_DATA, ACE_WRITE_DATA, ACE_APPEND_DATA, ACE_READ_NAMED_ATTRS, 1837 ACE_WRITE_NAMED_ATTRS, ACE_EXECUTE, ACE_DELETE_CHILD, 1838 ACE_READ_ATTRIBUTES, ACE_WRITE_ATTRIBUTES, ACE_DELETE, ACE_READ_ACL, 1839 ACE_WRITE_ACL, ACE_WRITE_OWNER, ACE_SYNCHRONIZE 1840 }; 1841 1842 static int unix_perms[] = { VREAD, VWRITE, VEXEC }; 1843 /* 1844 * smb_vop_eaccess 1845 * 1846 * Returns the effective permission of the given credential for the 1847 * specified object. 1848 * 1849 * This is just a workaround. We need VFS/FS support for this. 1850 */ 1851 void 1852 smb_vop_eaccess(vnode_t *vp, int *mode, int flags, vnode_t *dir_vp, cred_t *cr) 1853 { 1854 int error, i; 1855 int pnum; 1856 1857 *mode = 0; 1858 1859 if (flags == V_ACE_MASK) { 1860 pnum = sizeof (zfs_perms) / sizeof (int); 1861 1862 for (i = 0; i < pnum; i++) { 1863 error = smb_vop_access(vp, zfs_perms[i], flags, 1864 dir_vp, cr); 1865 if (error == 0) 1866 *mode |= zfs_perms[i]; 1867 } 1868 } else { 1869 pnum = sizeof (unix_perms) / sizeof (int); 1870 1871 for (i = 0; i < pnum; i++) { 1872 error = smb_vop_access(vp, unix_perms[i], flags, 1873 dir_vp, cr); 1874 if (error == 0) 1875 *mode |= unix_perms[i]; 1876 } 1877 } 1878 } 1879