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