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/sid.h> 29*5331Samw #include <smbsrv/smb_incl.h> 30*5331Samw #include <smbsrv/smb_fsops.h> 31*5331Samw #include <acl/acl_common.h> 32*5331Samw 33*5331Samw u_longlong_t smb_caller_id; 34*5331Samw 35*5331Samw static int smb_fsop_amask_to_omode(uint32_t granted_access); 36*5331Samw 37*5331Samw extern uint32_t smb_sd_tofs(smb_sdbuf_t *sr_sd, smb_fssd_t *fs_sd); 38*5331Samw 39*5331Samw extern uint32_t smb_sd_write(smb_request_t *sr, smb_sdbuf_t *sr_sd, 40*5331Samw uint32_t secinfo); 41*5331Samw 42*5331Samw extern int smb_vop_acl_to_vsa(acl_t *acl_info, vsecattr_t *vsecattr, 43*5331Samw int *aclbsize); 44*5331Samw 45*5331Samw static int smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, 46*5331Samw smb_fssd_t *fs_sd); 47*5331Samw 48*5331Samw static void smb_fsop_aclsplit(acl_t *zacl, acl_t **dacl, acl_t **sacl, 49*5331Samw int which_acl); 50*5331Samw static acl_t *smb_fsop_aclmerge(acl_t *dacl, acl_t *sacl); 51*5331Samw 52*5331Samw /* 53*5331Samw * The smb_fsop_* functions have knowledge of CIFS semantics. 54*5331Samw * 55*5331Samw * The smb_vop_* functions have minimal knowledge of CIFS semantics and 56*5331Samw * serve as an interface to the VFS layer. 57*5331Samw * 58*5331Samw * Hence, smb_request_t and smb_node_t structures should not be passed 59*5331Samw * from the smb_fsop_* layer to the smb_vop_* layer. 60*5331Samw * 61*5331Samw * In general, CIFS service code should only ever call smb_fsop_* 62*5331Samw * functions directly, and never smb_vop_* functions directly. 63*5331Samw * 64*5331Samw * smb_fsop_* functions should call smb_vop_* functions where possible, instead 65*5331Samw * of their smb_fsop_* counterparts. However, there are times when 66*5331Samw * this cannot be avoided. 67*5331Samw */ 68*5331Samw 69*5331Samw /* 70*5331Samw * Note: Stream names cannot be mangled. 71*5331Samw */ 72*5331Samw 73*5331Samw int 74*5331Samw smb_fsop_start() 75*5331Samw { 76*5331Samw int error; 77*5331Samw 78*5331Samw smb_caller_id = fs_new_caller_id(); 79*5331Samw error = smb_node_root_init(); 80*5331Samw 81*5331Samw if (error == 0) 82*5331Samw error = smb_fem_init(); 83*5331Samw 84*5331Samw return (error); 85*5331Samw } 86*5331Samw 87*5331Samw void 88*5331Samw smb_fsop_stop() 89*5331Samw { 90*5331Samw smb_fem_shutdown(); 91*5331Samw smb_vfs_rele_all(); 92*5331Samw smb_node_root_fini(); 93*5331Samw } 94*5331Samw 95*5331Samw int 96*5331Samw smb_fsop_open(smb_ofile_t *of) 97*5331Samw { 98*5331Samw caller_context_t ct; 99*5331Samw int mode; 100*5331Samw 101*5331Samw mode = smb_fsop_amask_to_omode(of->f_granted_access); 102*5331Samw 103*5331Samw smb_get_caller_context(NULL, &ct); 104*5331Samw 105*5331Samw /* 106*5331Samw * Assuming that same vnode is returned as we had before 107*5331Samw * (i.e. no special vnodes) 108*5331Samw */ 109*5331Samw 110*5331Samw return (smb_vop_open(&of->f_node->vp, mode, of->f_cr, &ct)); 111*5331Samw } 112*5331Samw 113*5331Samw int 114*5331Samw smb_fsop_close(smb_ofile_t *of) 115*5331Samw { 116*5331Samw caller_context_t ct; 117*5331Samw int mode; 118*5331Samw 119*5331Samw mode = smb_fsop_amask_to_omode(of->f_granted_access); 120*5331Samw 121*5331Samw smb_get_caller_context(NULL, &ct); 122*5331Samw 123*5331Samw return (smb_vop_close(of->f_node->vp, mode, of->f_cr, &ct)); 124*5331Samw } 125*5331Samw 126*5331Samw static int 127*5331Samw smb_fsop_amask_to_omode(uint32_t granted_access) 128*5331Samw { 129*5331Samw int mode = 0; 130*5331Samw 131*5331Samw if (granted_access & (ACE_READ_DATA | ACE_EXECUTE)) 132*5331Samw mode |= FREAD; 133*5331Samw 134*5331Samw if (granted_access & (ACE_WRITE_DATA | ACE_APPEND_DATA)) 135*5331Samw mode |= FWRITE; 136*5331Samw 137*5331Samw if (granted_access & ACE_APPEND_DATA) 138*5331Samw mode |= FAPPEND; 139*5331Samw 140*5331Samw return (mode); 141*5331Samw } 142*5331Samw 143*5331Samw static int 144*5331Samw smb_fsop_create_with_sd( 145*5331Samw struct smb_request *sr, 146*5331Samw cred_t *cr, 147*5331Samw smb_node_t *snode, 148*5331Samw char *name, 149*5331Samw smb_attr_t *attr, 150*5331Samw smb_node_t **ret_snode, 151*5331Samw smb_attr_t *ret_attr, 152*5331Samw smb_fssd_t *fs_sd) 153*5331Samw { 154*5331Samw caller_context_t ct; 155*5331Samw vsecattr_t *vsap; 156*5331Samw vsecattr_t vsecattr; 157*5331Samw acl_t *acl, *dacl, *sacl; 158*5331Samw smb_attr_t set_attr; 159*5331Samw vnode_t *vp; 160*5331Samw int aclbsize = 0; /* size of acl list in bytes */ 161*5331Samw int flags = 0; 162*5331Samw int is_dir; 163*5331Samw int rc; 164*5331Samw 165*5331Samw ASSERT(fs_sd); 166*5331Samw 167*5331Samw if (SMB_TREE_CASE_INSENSITIVE(sr)) 168*5331Samw flags = SMB_IGNORE_CASE; 169*5331Samw 170*5331Samw ASSERT(cr); 171*5331Samw smb_get_caller_context(sr, &ct); 172*5331Samw 173*5331Samw is_dir = ((fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR) != 0); 174*5331Samw 175*5331Samw if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACLONCREATE) { 176*5331Samw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 177*5331Samw dacl = fs_sd->sd_zdacl; 178*5331Samw sacl = fs_sd->sd_zsacl; 179*5331Samw ASSERT(dacl || sacl); 180*5331Samw if (dacl && sacl) { 181*5331Samw acl = smb_fsop_aclmerge(dacl, sacl); 182*5331Samw } else if (dacl) { 183*5331Samw acl = dacl; 184*5331Samw } else { 185*5331Samw acl = sacl; 186*5331Samw } 187*5331Samw 188*5331Samw rc = smb_vop_acl_to_vsa(acl, &vsecattr, &aclbsize); 189*5331Samw 190*5331Samw if (dacl && sacl) 191*5331Samw acl_free(acl); 192*5331Samw 193*5331Samw if (rc) 194*5331Samw return (rc); 195*5331Samw 196*5331Samw vsap = &vsecattr; 197*5331Samw } 198*5331Samw else 199*5331Samw vsap = NULL; 200*5331Samw 201*5331Samw if (is_dir) { 202*5331Samw rc = smb_vop_mkdir(snode->vp, name, attr, &vp, flags, 203*5331Samw cr, &ct, vsap); 204*5331Samw } else { 205*5331Samw rc = smb_vop_create(snode->vp, name, attr, &vp, flags, 206*5331Samw cr, &ct, vsap); 207*5331Samw } 208*5331Samw 209*5331Samw if (vsap != NULL) 210*5331Samw kmem_free(vsap->vsa_aclentp, aclbsize); 211*5331Samw 212*5331Samw if (rc != 0) 213*5331Samw return (rc); 214*5331Samw 215*5331Samw set_attr.sa_mask = 0; 216*5331Samw 217*5331Samw /* 218*5331Samw * Ideally we should be able to specify the owner and owning 219*5331Samw * group at create time along with the ACL. Since we cannot 220*5331Samw * do that right now, kcred is passed to smb_vop_setattr so it 221*5331Samw * doesn't fail due to lack of permission. 222*5331Samw */ 223*5331Samw if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 224*5331Samw set_attr.sa_vattr.va_uid = fs_sd->sd_uid; 225*5331Samw set_attr.sa_mask |= SMB_AT_UID; 226*5331Samw } 227*5331Samw 228*5331Samw if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 229*5331Samw set_attr.sa_vattr.va_gid = fs_sd->sd_gid; 230*5331Samw set_attr.sa_mask |= SMB_AT_GID; 231*5331Samw } 232*5331Samw 233*5331Samw if (set_attr.sa_mask) { 234*5331Samw rc = smb_vop_setattr(snode->vp, NULL, &set_attr, 235*5331Samw 0, kcred, &ct); 236*5331Samw } 237*5331Samw 238*5331Samw } else { 239*5331Samw /* 240*5331Samw * For filesystems that don't support ACL-on-create, try 241*5331Samw * to set the specified SD after create, which could actually 242*5331Samw * fail because of conflicts between inherited security 243*5331Samw * attributes upon creation and the specified SD. 244*5331Samw * 245*5331Samw * Passing kcred to smb_fsop_sdwrite() to overcome this issue. 246*5331Samw */ 247*5331Samw 248*5331Samw if (is_dir) { 249*5331Samw rc = smb_vop_mkdir(snode->vp, name, attr, &vp, flags, 250*5331Samw cr, &ct, NULL); 251*5331Samw } else { 252*5331Samw rc = smb_vop_create(snode->vp, name, attr, &vp, flags, 253*5331Samw cr, &ct, NULL); 254*5331Samw } 255*5331Samw 256*5331Samw if (rc == 0) 257*5331Samw rc = smb_fsop_sdwrite(sr, kcred, snode, fs_sd, 1); 258*5331Samw } 259*5331Samw 260*5331Samw if (rc == 0) { 261*5331Samw *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp, name, 262*5331Samw snode, NULL, ret_attr); 263*5331Samw 264*5331Samw if (*ret_snode == NULL) { 265*5331Samw VN_RELE(vp); 266*5331Samw rc = ENOMEM; 267*5331Samw } 268*5331Samw } 269*5331Samw 270*5331Samw return (rc); 271*5331Samw } 272*5331Samw 273*5331Samw 274*5331Samw /* 275*5331Samw * smb_fsop_create 276*5331Samw * 277*5331Samw * All SMB functions should use this wrapper to ensure that 278*5331Samw * all the smb_vop_creates are performed with the appropriate credentials. 279*5331Samw * Please document any direct calls to explain the reason 280*5331Samw * for avoiding this wrapper. 281*5331Samw * 282*5331Samw * It is assumed that a reference exists on snode coming into this routine. 283*5331Samw * 284*5331Samw * *ret_snode is returned with a reference upon success. No reference is 285*5331Samw * taken if an error is returned. 286*5331Samw */ 287*5331Samw 288*5331Samw int 289*5331Samw smb_fsop_create( 290*5331Samw struct smb_request *sr, 291*5331Samw cred_t *cr, 292*5331Samw smb_node_t *dir_snode, 293*5331Samw char *name, 294*5331Samw smb_attr_t *attr, 295*5331Samw smb_node_t **ret_snode, 296*5331Samw smb_attr_t *ret_attr) 297*5331Samw { 298*5331Samw struct open_param *op = &sr->arg.open; 299*5331Samw smb_node_t *fnode; 300*5331Samw smb_attr_t file_attr; 301*5331Samw caller_context_t ct; 302*5331Samw vnode_t *xattrdirvp; 303*5331Samw vnode_t *vp; 304*5331Samw char *longname = NULL; 305*5331Samw char *namep; 306*5331Samw char *fname; 307*5331Samw char *sname; 308*5331Samw int is_stream; 309*5331Samw int flags = 0; 310*5331Samw int rc = 0; 311*5331Samw smb_fssd_t fs_sd; 312*5331Samw uint32_t secinfo; 313*5331Samw uint32_t status; 314*5331Samw 315*5331Samw ASSERT(cr); 316*5331Samw ASSERT(dir_snode); 317*5331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 318*5331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 319*5331Samw 320*5331Samw ASSERT(ret_snode); 321*5331Samw *ret_snode = 0; 322*5331Samw 323*5331Samw ASSERT(name); 324*5331Samw if (*name == 0) 325*5331Samw return (EINVAL); 326*5331Samw 327*5331Samw if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0) 328*5331Samw return (EACCES); 329*5331Samw 330*5331Samw ASSERT(sr); 331*5331Samw ASSERT(sr->tid_tree); 332*5331Samw if (SMB_TREE_IS_READ_ONLY(sr)) 333*5331Samw return (EROFS); 334*5331Samw 335*5331Samw if (SMB_TREE_CASE_INSENSITIVE(sr)) 336*5331Samw flags = SMB_IGNORE_CASE; 337*5331Samw 338*5331Samw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 339*5331Samw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 340*5331Samw 341*5331Samw is_stream = smb_stream_parse_name(name, fname, sname); 342*5331Samw 343*5331Samw if (is_stream) 344*5331Samw namep = fname; 345*5331Samw else 346*5331Samw namep = name; 347*5331Samw 348*5331Samw if (smb_maybe_mangled_name(namep)) { 349*5331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 350*5331Samw 351*5331Samw rc = smb_unmangle_name(sr, cr, dir_snode, namep, longname, 352*5331Samw MAXNAMELEN, NULL, NULL, 1); 353*5331Samw 354*5331Samw if ((is_stream == 0) && (rc == 0)) 355*5331Samw rc = EEXIST; 356*5331Samw 357*5331Samw if ((is_stream && rc) || 358*5331Samw ((is_stream == 0) && (rc != ENOENT))) { 359*5331Samw kmem_free(longname, MAXNAMELEN); 360*5331Samw kmem_free(fname, MAXNAMELEN); 361*5331Samw kmem_free(sname, MAXNAMELEN); 362*5331Samw return (rc); 363*5331Samw } 364*5331Samw 365*5331Samw if (is_stream) 366*5331Samw namep = longname; 367*5331Samw else 368*5331Samw kmem_free(longname, MAXNAMELEN); 369*5331Samw } 370*5331Samw 371*5331Samw if (is_stream) { 372*5331Samw /* 373*5331Samw * Look up the unnamed stream. 374*5331Samw * 375*5331Samw * Mangle processing in smb_fsop_lookup() for the unnamed 376*5331Samw * stream won't be needed (as it was done above), but 377*5331Samw * it may be needed on any link target (which 378*5331Samw * smb_fsop_lookup() will provide). 379*5331Samw */ 380*5331Samw rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, 381*5331Samw sr->tid_tree->t_snode, dir_snode, namep, &fnode, &file_attr, 382*5331Samw 0, 0); 383*5331Samw 384*5331Samw if (longname) { 385*5331Samw kmem_free(longname, MAXNAMELEN); 386*5331Samw namep = NULL; 387*5331Samw } 388*5331Samw 389*5331Samw if (rc != 0) { 390*5331Samw kmem_free(fname, MAXNAMELEN); 391*5331Samw kmem_free(sname, MAXNAMELEN); 392*5331Samw return (rc); 393*5331Samw } 394*5331Samw 395*5331Samw smb_get_caller_context(sr, &ct); 396*5331Samw 397*5331Samw rc = smb_vop_stream_create(fnode->vp, sname, attr, &vp, 398*5331Samw &xattrdirvp, flags, cr, &ct); 399*5331Samw 400*5331Samw if (rc != 0) { 401*5331Samw smb_node_release(fnode); 402*5331Samw kmem_free(fname, MAXNAMELEN); 403*5331Samw kmem_free(sname, MAXNAMELEN); 404*5331Samw return (rc); 405*5331Samw } 406*5331Samw 407*5331Samw *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, 408*5331Samw vp, sname, ret_attr); 409*5331Samw 410*5331Samw smb_node_release(fnode); 411*5331Samw 412*5331Samw if (*ret_snode == NULL) { 413*5331Samw VN_RELE(xattrdirvp); 414*5331Samw VN_RELE(vp); 415*5331Samw kmem_free(fname, MAXNAMELEN); 416*5331Samw kmem_free(sname, MAXNAMELEN); 417*5331Samw return (ENOMEM); 418*5331Samw } 419*5331Samw } else { 420*5331Samw if (op->sd_buf) { 421*5331Samw /* 422*5331Samw * SD sent by client in Windows format. Needs to be 423*5331Samw * converted to FS format. No inheritance. 424*5331Samw */ 425*5331Samw secinfo = smb_sd_get_secinfo((smb_sdbuf_t *)op->sd_buf); 426*5331Samw smb_fsop_sdinit(&fs_sd, secinfo, 0); 427*5331Samw 428*5331Samw status = smb_sd_tofs(op->sd_buf, &fs_sd); 429*5331Samw if (status == NT_STATUS_SUCCESS) { 430*5331Samw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 431*5331Samw name, attr, ret_snode, ret_attr, &fs_sd); 432*5331Samw } 433*5331Samw else 434*5331Samw rc = EINVAL; 435*5331Samw smb_fsop_sdterm(&fs_sd); 436*5331Samw } else if (sr->tid_tree->t_acltype == ACE_T) { 437*5331Samw /* 438*5331Samw * No incoming SD and filesystem is ZFS 439*5331Samw * Server applies Windows inheritance rules, 440*5331Samw * see smb_fsop_sdinherit() comments as to why. 441*5331Samw */ 442*5331Samw smb_fsop_sdinit(&fs_sd, SMB_ACL_SECINFO, 0); 443*5331Samw rc = smb_fsop_sdinherit(sr, dir_snode, &fs_sd); 444*5331Samw if (rc == 0) { 445*5331Samw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 446*5331Samw name, attr, ret_snode, ret_attr, &fs_sd); 447*5331Samw } 448*5331Samw 449*5331Samw smb_fsop_sdterm(&fs_sd); 450*5331Samw } else { 451*5331Samw /* 452*5331Samw * No incoming SD and filesystem is not ZFS 453*5331Samw * let the filesystem handles the inheritance. 454*5331Samw */ 455*5331Samw smb_get_caller_context(sr, &ct); 456*5331Samw rc = smb_vop_create(dir_snode->vp, name, attr, &vp, 457*5331Samw flags, cr, &ct, NULL); 458*5331Samw 459*5331Samw if (rc == 0) { 460*5331Samw *ret_snode = smb_node_lookup(sr, op, cr, vp, 461*5331Samw name, dir_snode, NULL, ret_attr); 462*5331Samw 463*5331Samw if (*ret_snode == NULL) { 464*5331Samw VN_RELE(vp); 465*5331Samw rc = ENOMEM; 466*5331Samw } 467*5331Samw } 468*5331Samw 469*5331Samw } 470*5331Samw } 471*5331Samw 472*5331Samw kmem_free(fname, MAXNAMELEN); 473*5331Samw kmem_free(sname, MAXNAMELEN); 474*5331Samw return (rc); 475*5331Samw } 476*5331Samw 477*5331Samw /* 478*5331Samw * smb_fsop_mkdir 479*5331Samw * 480*5331Samw * All SMB functions should use this wrapper to ensure that 481*5331Samw * the the calls are performed with the appropriate credentials. 482*5331Samw * Please document any direct call to explain the reason 483*5331Samw * for avoiding this wrapper. 484*5331Samw * 485*5331Samw * It is assumed that a reference exists on snode coming into this routine. 486*5331Samw * 487*5331Samw * *ret_snode is returned with a reference upon success. No reference is 488*5331Samw * taken if an error is returned. 489*5331Samw */ 490*5331Samw int 491*5331Samw smb_fsop_mkdir( 492*5331Samw struct smb_request *sr, 493*5331Samw cred_t *cr, 494*5331Samw smb_node_t *dir_snode, 495*5331Samw char *name, 496*5331Samw smb_attr_t *attr, 497*5331Samw smb_node_t **ret_snode, 498*5331Samw smb_attr_t *ret_attr) 499*5331Samw { 500*5331Samw struct open_param *op = &sr->arg.open; 501*5331Samw caller_context_t ct; 502*5331Samw char *longname; 503*5331Samw vnode_t *vp; 504*5331Samw int flags = 0; 505*5331Samw smb_fssd_t fs_sd; 506*5331Samw uint32_t secinfo; 507*5331Samw uint32_t status; 508*5331Samw int rc; 509*5331Samw 510*5331Samw ASSERT(cr); 511*5331Samw ASSERT(dir_snode); 512*5331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 513*5331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 514*5331Samw 515*5331Samw ASSERT(ret_snode); 516*5331Samw *ret_snode = 0; 517*5331Samw 518*5331Samw ASSERT(name); 519*5331Samw if (*name == 0) 520*5331Samw return (EINVAL); 521*5331Samw 522*5331Samw if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0) 523*5331Samw return (EACCES); 524*5331Samw 525*5331Samw ASSERT(sr); 526*5331Samw ASSERT(sr->tid_tree); 527*5331Samw if (SMB_TREE_IS_READ_ONLY(sr)) 528*5331Samw return (EROFS); 529*5331Samw 530*5331Samw if (smb_maybe_mangled_name(name)) { 531*5331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 532*5331Samw rc = smb_unmangle_name(sr, cr, dir_snode, name, longname, 533*5331Samw MAXNAMELEN, NULL, NULL, 1); 534*5331Samw 535*5331Samw kmem_free(longname, MAXNAMELEN); 536*5331Samw 537*5331Samw /* 538*5331Samw * If the name passed in by the client has an unmangled 539*5331Samw * equivalent that is found in the specified directory, 540*5331Samw * then the mkdir cannot succeed. Return EEXIST. 541*5331Samw * 542*5331Samw * Only if ENOENT is returned will a mkdir be attempted. 543*5331Samw */ 544*5331Samw 545*5331Samw if (rc == 0) 546*5331Samw rc = EEXIST; 547*5331Samw 548*5331Samw if (rc != ENOENT) 549*5331Samw return (rc); 550*5331Samw } 551*5331Samw 552*5331Samw if (SMB_TREE_CASE_INSENSITIVE(sr)) 553*5331Samw flags = SMB_IGNORE_CASE; 554*5331Samw 555*5331Samw smb_get_caller_context(sr, &ct); 556*5331Samw 557*5331Samw if (op->sd_buf) { 558*5331Samw /* 559*5331Samw * SD sent by client in Windows format. Needs to be 560*5331Samw * converted to FS format. No inheritance. 561*5331Samw */ 562*5331Samw secinfo = smb_sd_get_secinfo((smb_sdbuf_t *)op->sd_buf); 563*5331Samw smb_fsop_sdinit(&fs_sd, secinfo, SMB_FSSD_FLAGS_DIR); 564*5331Samw 565*5331Samw status = smb_sd_tofs(op->sd_buf, &fs_sd); 566*5331Samw if (status == NT_STATUS_SUCCESS) { 567*5331Samw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 568*5331Samw name, attr, ret_snode, ret_attr, &fs_sd); 569*5331Samw } 570*5331Samw else 571*5331Samw rc = EINVAL; 572*5331Samw smb_fsop_sdterm(&fs_sd); 573*5331Samw } else if (sr->tid_tree->t_acltype == ACE_T) { 574*5331Samw /* 575*5331Samw * No incoming SD and filesystem is ZFS 576*5331Samw * Server applies Windows inheritance rules, 577*5331Samw * see smb_fsop_sdinherit() comments as to why. 578*5331Samw */ 579*5331Samw smb_fsop_sdinit(&fs_sd, SMB_ACL_SECINFO, SMB_FSSD_FLAGS_DIR); 580*5331Samw rc = smb_fsop_sdinherit(sr, dir_snode, &fs_sd); 581*5331Samw if (rc == 0) { 582*5331Samw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 583*5331Samw name, attr, ret_snode, ret_attr, &fs_sd); 584*5331Samw } 585*5331Samw 586*5331Samw smb_fsop_sdterm(&fs_sd); 587*5331Samw 588*5331Samw } else { 589*5331Samw rc = smb_vop_mkdir(dir_snode->vp, name, attr, &vp, flags, cr, 590*5331Samw &ct, NULL); 591*5331Samw 592*5331Samw if (rc == 0) { 593*5331Samw *ret_snode = smb_node_lookup(sr, op, cr, vp, name, 594*5331Samw dir_snode, NULL, ret_attr); 595*5331Samw 596*5331Samw if (*ret_snode == NULL) { 597*5331Samw VN_RELE(vp); 598*5331Samw rc = ENOMEM; 599*5331Samw } 600*5331Samw } 601*5331Samw } 602*5331Samw 603*5331Samw return (rc); 604*5331Samw } 605*5331Samw 606*5331Samw /* 607*5331Samw * smb_fsop_remove 608*5331Samw * 609*5331Samw * All SMB functions should use this wrapper to ensure that 610*5331Samw * the the calls are performed with the appropriate credentials. 611*5331Samw * Please document any direct call to explain the reason 612*5331Samw * for avoiding this wrapper. 613*5331Samw * 614*5331Samw * It is assumed that a reference exists on snode coming into this routine. 615*5331Samw * 616*5331Samw * od: This means that the name passed in is an on-disk name. 617*5331Samw * A null smb_request might be passed to this function. 618*5331Samw */ 619*5331Samw 620*5331Samw int 621*5331Samw smb_fsop_remove( 622*5331Samw struct smb_request *sr, 623*5331Samw cred_t *cr, 624*5331Samw smb_node_t *dir_snode, 625*5331Samw char *name, 626*5331Samw int od) 627*5331Samw { 628*5331Samw smb_node_t *fnode; 629*5331Samw smb_attr_t file_attr; 630*5331Samw caller_context_t ct; 631*5331Samw char *longname; 632*5331Samw char *fname; 633*5331Samw char *sname; 634*5331Samw int flags = 0; 635*5331Samw int rc; 636*5331Samw 637*5331Samw ASSERT(cr); 638*5331Samw /* 639*5331Samw * The state of the node could be SMB_NODE_STATE_DESTROYING if this 640*5331Samw * function is called during the deletion of the node (because of 641*5331Samw * DELETE_ON_CLOSE). 642*5331Samw */ 643*5331Samw ASSERT(dir_snode); 644*5331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 645*5331Samw 646*5331Samw if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0) 647*5331Samw return (EACCES); 648*5331Samw 649*5331Samw if (SMB_TREE_IS_READ_ONLY(sr)) 650*5331Samw return (EROFS); 651*5331Samw 652*5331Samw smb_get_caller_context(sr, &ct); 653*5331Samw 654*5331Samw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 655*5331Samw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 656*5331Samw 657*5331Samw if (smb_stream_parse_name(name, fname, sname)) { 658*5331Samw 659*5331Samw ASSERT(od == 0); 660*5331Samw 661*5331Samw if (SMB_TREE_CASE_INSENSITIVE(sr)) 662*5331Samw flags = SMB_IGNORE_CASE; 663*5331Samw 664*5331Samw /* 665*5331Samw * Look up the unnamed stream (i.e. fname). 666*5331Samw * Unmangle processing will be done on fname 667*5331Samw * as well as any link target. 668*5331Samw */ 669*5331Samw 670*5331Samw rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, 671*5331Samw sr->tid_tree->t_snode, dir_snode, fname, &fnode, &file_attr, 672*5331Samw 0, 0); 673*5331Samw 674*5331Samw if (rc != 0) { 675*5331Samw kmem_free(fname, MAXNAMELEN); 676*5331Samw kmem_free(sname, MAXNAMELEN); 677*5331Samw return (rc); 678*5331Samw } 679*5331Samw 680*5331Samw /* 681*5331Samw * XXX 682*5331Samw * Need to find out what permission is required by NTFS 683*5331Samw * to remove a stream. 684*5331Samw */ 685*5331Samw rc = smb_vop_stream_remove(fnode->vp, sname, flags, cr, &ct); 686*5331Samw 687*5331Samw smb_node_release(fnode); 688*5331Samw } else { 689*5331Samw /* 690*5331Samw * If the passed-in name is an on-disk name, 691*5331Samw * then we need to do a case-sensitive remove. 692*5331Samw * This is important if the on-disk name 693*5331Samw * corresponds to a mangled name passed in by 694*5331Samw * the client. We want to make sure to remove 695*5331Samw * the exact file specified by the client, 696*5331Samw * instead of letting the underlying file system 697*5331Samw * do a remove on the "first match." 698*5331Samw */ 699*5331Samw 700*5331Samw if ((od == 0) && SMB_TREE_CASE_INSENSITIVE(sr)) 701*5331Samw flags = SMB_IGNORE_CASE; 702*5331Samw 703*5331Samw rc = smb_vop_remove(dir_snode->vp, name, flags, cr, &ct); 704*5331Samw 705*5331Samw if (rc == ENOENT) { 706*5331Samw if (smb_maybe_mangled_name(name) == 0) { 707*5331Samw kmem_free(fname, MAXNAMELEN); 708*5331Samw kmem_free(sname, MAXNAMELEN); 709*5331Samw return (rc); 710*5331Samw } 711*5331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 712*5331Samw 713*5331Samw rc = smb_unmangle_name(sr, cr, dir_snode, name, 714*5331Samw longname, MAXNAMELEN, NULL, NULL, 1); 715*5331Samw 716*5331Samw if (rc == 0) { 717*5331Samw /* 718*5331Samw * We passed "1" as the "od" parameter 719*5331Samw * to smb_unmangle_name(), such that longname 720*5331Samw * is the real (case-sensitive) on-disk name. 721*5331Samw * We make sure we do a remove on this exact 722*5331Samw * name, as the name was mangled and denotes 723*5331Samw * a unique file. 724*5331Samw */ 725*5331Samw flags &= ~SMB_IGNORE_CASE; 726*5331Samw rc = smb_vop_remove(dir_snode->vp, longname, 727*5331Samw flags, cr, &ct); 728*5331Samw } 729*5331Samw 730*5331Samw kmem_free(longname, MAXNAMELEN); 731*5331Samw } 732*5331Samw } 733*5331Samw 734*5331Samw kmem_free(fname, MAXNAMELEN); 735*5331Samw kmem_free(sname, MAXNAMELEN); 736*5331Samw return (rc); 737*5331Samw } 738*5331Samw 739*5331Samw /* 740*5331Samw * smb_fsop_remove_streams 741*5331Samw * 742*5331Samw * This function removes a file's streams without removing the 743*5331Samw * file itself. 744*5331Samw * 745*5331Samw * It is assumed that snode is not a link. 746*5331Samw */ 747*5331Samw int 748*5331Samw smb_fsop_remove_streams(struct smb_request *sr, cred_t *cr, 749*5331Samw smb_node_t *fnode) 750*5331Samw { 751*5331Samw struct fs_stream_info stream_info; 752*5331Samw caller_context_t ct; 753*5331Samw uint32_t cookie = 0; 754*5331Samw int flags = 0; 755*5331Samw int rc; 756*5331Samw 757*5331Samw ASSERT(cr); 758*5331Samw ASSERT(fnode); 759*5331Samw ASSERT(fnode->n_magic == SMB_NODE_MAGIC); 760*5331Samw ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING); 761*5331Samw 762*5331Samw if (SMB_TREE_ROOT_FS(sr, fnode) == 0) 763*5331Samw return (EACCES); 764*5331Samw 765*5331Samw if (SMB_TREE_IS_READ_ONLY(sr)) 766*5331Samw return (EROFS); 767*5331Samw 768*5331Samw if (SMB_TREE_CASE_INSENSITIVE(sr)) 769*5331Samw flags = SMB_IGNORE_CASE; 770*5331Samw 771*5331Samw smb_get_caller_context(sr, &ct); 772*5331Samw 773*5331Samw for (;;) { 774*5331Samw rc = smb_vop_stream_readdir(fnode->vp, &cookie, &stream_info, 775*5331Samw NULL, NULL, flags, cr, &ct); 776*5331Samw 777*5331Samw if ((rc != 0) || (cookie == SMB_EOF)) 778*5331Samw break; 779*5331Samw 780*5331Samw (void) smb_vop_stream_remove(fnode->vp, stream_info.name, flags, 781*5331Samw cr, &ct); 782*5331Samw } 783*5331Samw return (rc); 784*5331Samw } 785*5331Samw 786*5331Samw /* 787*5331Samw * smb_fsop_rmdir 788*5331Samw * 789*5331Samw * All SMB functions should use this wrapper to ensure that 790*5331Samw * the the calls are performed with the appropriate credentials. 791*5331Samw * Please document any direct call to explain the reason 792*5331Samw * for avoiding this wrapper. 793*5331Samw * 794*5331Samw * It is assumed that a reference exists on snode coming into this routine. 795*5331Samw * 796*5331Samw * od: This means that the name passed in is an on-disk name. 797*5331Samw */ 798*5331Samw 799*5331Samw int 800*5331Samw smb_fsop_rmdir( 801*5331Samw struct smb_request *sr, 802*5331Samw cred_t *cr, 803*5331Samw smb_node_t *dir_snode, 804*5331Samw char *name, 805*5331Samw int od) 806*5331Samw { 807*5331Samw caller_context_t ct; 808*5331Samw int rc; 809*5331Samw int flags = 0; 810*5331Samw char *longname; 811*5331Samw 812*5331Samw ASSERT(cr); 813*5331Samw /* 814*5331Samw * The state of the node could be SMB_NODE_STATE_DESTROYING if this 815*5331Samw * function is called during the deletion of the node (because of 816*5331Samw * DELETE_ON_CLOSE). 817*5331Samw */ 818*5331Samw ASSERT(dir_snode); 819*5331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 820*5331Samw 821*5331Samw if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0) 822*5331Samw return (EACCES); 823*5331Samw 824*5331Samw if (SMB_TREE_IS_READ_ONLY(sr)) 825*5331Samw return (EROFS); 826*5331Samw 827*5331Samw /* 828*5331Samw * If the passed-in name is an on-disk name, 829*5331Samw * then we need to do a case-sensitive rmdir. 830*5331Samw * This is important if the on-disk name 831*5331Samw * corresponds to a mangled name passed in by 832*5331Samw * the client. We want to make sure to remove 833*5331Samw * the exact directory specified by the client, 834*5331Samw * instead of letting the underlying file system 835*5331Samw * do a rmdir on the "first match." 836*5331Samw */ 837*5331Samw 838*5331Samw if ((od == 0) && SMB_TREE_CASE_INSENSITIVE(sr)) 839*5331Samw flags = SMB_IGNORE_CASE; 840*5331Samw 841*5331Samw smb_get_caller_context(sr, &ct); 842*5331Samw 843*5331Samw rc = smb_vop_rmdir(dir_snode->vp, name, flags, cr, &ct); 844*5331Samw 845*5331Samw if (rc == ENOENT) { 846*5331Samw if (smb_maybe_mangled_name(name) == 0) 847*5331Samw return (rc); 848*5331Samw 849*5331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 850*5331Samw 851*5331Samw rc = smb_unmangle_name(sr, cr, dir_snode, 852*5331Samw name, longname, MAXNAMELEN, NULL, 853*5331Samw NULL, 1); 854*5331Samw 855*5331Samw if (rc == 0) { 856*5331Samw /* 857*5331Samw * We passed "1" as the "od" parameter 858*5331Samw * to smb_unmangle_name(), such that longname 859*5331Samw * is the real (case-sensitive) on-disk name. 860*5331Samw * We make sure we do a rmdir on this exact 861*5331Samw * name, as the name was mangled and denotes 862*5331Samw * a unique directory. 863*5331Samw */ 864*5331Samw flags &= ~SMB_IGNORE_CASE; 865*5331Samw rc = smb_vop_rmdir(dir_snode->vp, longname, flags, cr, 866*5331Samw &ct); 867*5331Samw } 868*5331Samw 869*5331Samw kmem_free(longname, MAXNAMELEN); 870*5331Samw } 871*5331Samw 872*5331Samw return (rc); 873*5331Samw } 874*5331Samw 875*5331Samw /* 876*5331Samw * smb_fsop_getattr 877*5331Samw * 878*5331Samw * All SMB functions should use this wrapper to ensure that 879*5331Samw * the the calls are performed with the appropriate credentials. 880*5331Samw * Please document any direct call to explain the reason 881*5331Samw * for avoiding this wrapper. 882*5331Samw * 883*5331Samw * It is assumed that a reference exists on snode coming into this routine. 884*5331Samw */ 885*5331Samw int 886*5331Samw smb_fsop_getattr(struct smb_request *sr, cred_t *cr, smb_node_t *snode, 887*5331Samw smb_attr_t *attr) 888*5331Samw { 889*5331Samw smb_node_t *unnamed_node; 890*5331Samw vnode_t *unnamed_vp = NULL; 891*5331Samw caller_context_t ct; 892*5331Samw uint32_t status; 893*5331Samw uint32_t access = 0; 894*5331Samw int flags = 0; 895*5331Samw 896*5331Samw ASSERT(cr); 897*5331Samw ASSERT(snode); 898*5331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 899*5331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 900*5331Samw 901*5331Samw if (SMB_TREE_ROOT_FS(sr, snode) == 0) 902*5331Samw return (EACCES); 903*5331Samw 904*5331Samw if (sr->fid_ofile) { 905*5331Samw /* if uid and/or gid is requested */ 906*5331Samw if (attr->sa_mask & (SMB_AT_UID|SMB_AT_GID)) 907*5331Samw access |= READ_CONTROL; 908*5331Samw 909*5331Samw /* if anything else is also requested */ 910*5331Samw if (attr->sa_mask & ~(SMB_AT_UID|SMB_AT_GID)) 911*5331Samw access |= FILE_READ_ATTRIBUTES; 912*5331Samw 913*5331Samw status = smb_ofile_access(sr->fid_ofile, cr, access); 914*5331Samw if (status != NT_STATUS_SUCCESS) 915*5331Samw return (EACCES); 916*5331Samw 917*5331Samw if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS) 918*5331Samw flags = ATTR_NOACLCHECK; 919*5331Samw } 920*5331Samw 921*5331Samw smb_get_caller_context(sr, &ct); 922*5331Samw 923*5331Samw unnamed_node = SMB_IS_STREAM(snode); 924*5331Samw 925*5331Samw if (unnamed_node) { 926*5331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 927*5331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 928*5331Samw unnamed_vp = unnamed_node->vp; 929*5331Samw } 930*5331Samw 931*5331Samw return (smb_vop_getattr(snode->vp, unnamed_vp, attr, flags, cr, &ct)); 932*5331Samw } 933*5331Samw 934*5331Samw /* 935*5331Samw * smb_fsop_readdir 936*5331Samw * 937*5331Samw * All SMB functions should use this smb_fsop_readdir wrapper to ensure that 938*5331Samw * the smb_vop_readdir is performed with the appropriate credentials. 939*5331Samw * Please document any direct call to smb_vop_readdir to explain the reason 940*5331Samw * for avoiding this wrapper. 941*5331Samw * 942*5331Samw * It is assumed that a reference exists on snode coming into this routine. 943*5331Samw */ 944*5331Samw int 945*5331Samw smb_fsop_readdir( 946*5331Samw struct smb_request *sr, 947*5331Samw cred_t *cr, 948*5331Samw smb_node_t *dir_snode, 949*5331Samw uint32_t *cookie, 950*5331Samw char *name, 951*5331Samw int *namelen, 952*5331Samw ino64_t *fileid, 953*5331Samw struct fs_stream_info *stream_info, 954*5331Samw smb_node_t **ret_snode, 955*5331Samw smb_attr_t *ret_attr) 956*5331Samw { 957*5331Samw caller_context_t ct; 958*5331Samw smb_node_t *ret_snodep; 959*5331Samw smb_node_t *fnode; 960*5331Samw smb_attr_t tmp_attr; 961*5331Samw vnode_t *xattrdirvp; 962*5331Samw vnode_t *fvp; 963*5331Samw vnode_t *vp = NULL; 964*5331Samw char *od_name; 965*5331Samw int rc; 966*5331Samw int flags = 0; 967*5331Samw 968*5331Samw ASSERT(cr); 969*5331Samw ASSERT(dir_snode); 970*5331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 971*5331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 972*5331Samw 973*5331Samw if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0) 974*5331Samw return (EACCES); 975*5331Samw 976*5331Samw if (*cookie == SMB_EOF) { 977*5331Samw *namelen = 0; 978*5331Samw return (0); 979*5331Samw } 980*5331Samw 981*5331Samw if (SMB_TREE_CASE_INSENSITIVE(sr)) 982*5331Samw flags = SMB_IGNORE_CASE; 983*5331Samw 984*5331Samw smb_get_caller_context(sr, &ct); 985*5331Samw 986*5331Samw od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 987*5331Samw 988*5331Samw if (stream_info) { 989*5331Samw rc = smb_vop_lookup(dir_snode->vp, name, &fvp, od_name, 990*5331Samw SMB_FOLLOW_LINKS, sr->tid_tree->t_snode->vp, cr, &ct); 991*5331Samw 992*5331Samw if (rc != 0) { 993*5331Samw kmem_free(od_name, MAXNAMELEN); 994*5331Samw return (rc); 995*5331Samw } 996*5331Samw 997*5331Samw fnode = smb_node_lookup(sr, NULL, cr, fvp, od_name, dir_snode, 998*5331Samw NULL, ret_attr); 999*5331Samw 1000*5331Samw kmem_free(od_name, MAXNAMELEN); 1001*5331Samw 1002*5331Samw if (fnode == NULL) { 1003*5331Samw VN_RELE(fvp); 1004*5331Samw return (ENOMEM); 1005*5331Samw } 1006*5331Samw 1007*5331Samw /* 1008*5331Samw * XXX 1009*5331Samw * Need to find out what permission(s) NTFS requires for getting 1010*5331Samw * a file's streams list. 1011*5331Samw * 1012*5331Samw * Might have to use kcred. 1013*5331Samw */ 1014*5331Samw rc = smb_vop_stream_readdir(fvp, cookie, stream_info, &vp, 1015*5331Samw &xattrdirvp, flags, cr, &ct); 1016*5331Samw 1017*5331Samw if ((rc != 0) || (*cookie == SMB_EOF)) { 1018*5331Samw smb_node_release(fnode); 1019*5331Samw return (rc); 1020*5331Samw } 1021*5331Samw 1022*5331Samw ret_snodep = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, 1023*5331Samw vp, stream_info->name, &tmp_attr); 1024*5331Samw 1025*5331Samw smb_node_release(fnode); 1026*5331Samw 1027*5331Samw if (ret_snodep == NULL) { 1028*5331Samw VN_RELE(xattrdirvp); 1029*5331Samw VN_RELE(vp); 1030*5331Samw return (ENOMEM); 1031*5331Samw } 1032*5331Samw 1033*5331Samw stream_info->size = tmp_attr.sa_vattr.va_size; 1034*5331Samw 1035*5331Samw if (ret_attr) 1036*5331Samw *ret_attr = tmp_attr; 1037*5331Samw 1038*5331Samw if (ret_snode) 1039*5331Samw *ret_snode = ret_snodep; 1040*5331Samw else 1041*5331Samw smb_node_release(ret_snodep); 1042*5331Samw 1043*5331Samw } else { 1044*5331Samw rc = smb_vop_readdir(dir_snode->vp, cookie, name, namelen, 1045*5331Samw fileid, &vp, od_name, flags, cr, &ct); 1046*5331Samw 1047*5331Samw if (rc != 0) { 1048*5331Samw kmem_free(od_name, MAXNAMELEN); 1049*5331Samw return (rc); 1050*5331Samw } 1051*5331Samw 1052*5331Samw if (*namelen) { 1053*5331Samw ASSERT(vp); 1054*5331Samw if (ret_attr || ret_snode) { 1055*5331Samw ret_snodep = smb_node_lookup(sr, NULL, cr, vp, 1056*5331Samw od_name, dir_snode, NULL, &tmp_attr); 1057*5331Samw 1058*5331Samw if (ret_snodep == NULL) { 1059*5331Samw kmem_free(od_name, MAXNAMELEN); 1060*5331Samw VN_RELE(vp); 1061*5331Samw return (ENOMEM); 1062*5331Samw } 1063*5331Samw 1064*5331Samw if (ret_attr) 1065*5331Samw *ret_attr = tmp_attr; 1066*5331Samw 1067*5331Samw if (ret_snode) 1068*5331Samw *ret_snode = ret_snodep; 1069*5331Samw else 1070*5331Samw smb_node_release(ret_snodep); 1071*5331Samw } 1072*5331Samw } 1073*5331Samw 1074*5331Samw kmem_free(od_name, MAXNAMELEN); 1075*5331Samw } 1076*5331Samw 1077*5331Samw return (rc); 1078*5331Samw } 1079*5331Samw 1080*5331Samw /* 1081*5331Samw * smb_fsop_getdents 1082*5331Samw * 1083*5331Samw * All SMB functions should use this smb_vop_getdents wrapper to ensure that 1084*5331Samw * the smb_vop_getdents is performed with the appropriate credentials. 1085*5331Samw * Please document any direct call to smb_vop_getdents to explain the reason 1086*5331Samw * for avoiding this wrapper. 1087*5331Samw * 1088*5331Samw * It is assumed that a reference exists on snode coming into this routine. 1089*5331Samw */ 1090*5331Samw /*ARGSUSED*/ 1091*5331Samw int 1092*5331Samw smb_fsop_getdents( 1093*5331Samw struct smb_request *sr, 1094*5331Samw cred_t *cr, 1095*5331Samw smb_node_t *dir_snode, 1096*5331Samw uint32_t *cookie, 1097*5331Samw uint64_t *verifierp, 1098*5331Samw int32_t *maxcnt, 1099*5331Samw char *args, 1100*5331Samw char *pattern) 1101*5331Samw { 1102*5331Samw caller_context_t ct; 1103*5331Samw int flags = 0; 1104*5331Samw 1105*5331Samw ASSERT(cr); 1106*5331Samw ASSERT(dir_snode); 1107*5331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 1108*5331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 1109*5331Samw 1110*5331Samw if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0) 1111*5331Samw return (EACCES); 1112*5331Samw 1113*5331Samw if (SMB_TREE_CASE_INSENSITIVE(sr)) 1114*5331Samw flags = SMB_IGNORE_CASE; 1115*5331Samw 1116*5331Samw smb_get_caller_context(sr, &ct); 1117*5331Samw 1118*5331Samw return (smb_vop_getdents(dir_snode, cookie, 0, maxcnt, args, pattern, 1119*5331Samw flags, sr, cr, &ct)); 1120*5331Samw } 1121*5331Samw 1122*5331Samw /* 1123*5331Samw * smb_fsop_rename 1124*5331Samw * 1125*5331Samw * All SMB functions should use this smb_vop_rename wrapper to ensure that 1126*5331Samw * the smb_vop_rename is performed with the appropriate credentials. 1127*5331Samw * Please document any direct call to smb_vop_rename to explain the reason 1128*5331Samw * for avoiding this wrapper. 1129*5331Samw * 1130*5331Samw * It is assumed that references exist on from_dir_snode and to_dir_snode coming 1131*5331Samw * into this routine. 1132*5331Samw */ 1133*5331Samw int 1134*5331Samw smb_fsop_rename( 1135*5331Samw struct smb_request *sr, 1136*5331Samw cred_t *cr, 1137*5331Samw smb_node_t *from_dir_snode, 1138*5331Samw char *from_name, 1139*5331Samw smb_node_t *to_dir_snode, 1140*5331Samw char *to_name) 1141*5331Samw { 1142*5331Samw smb_node_t *from_snode; 1143*5331Samw caller_context_t ct; 1144*5331Samw smb_attr_t tmp_attr; 1145*5331Samw vnode_t *from_vp; 1146*5331Samw int flags = 0; 1147*5331Samw int rc; 1148*5331Samw 1149*5331Samw ASSERT(cr); 1150*5331Samw ASSERT(from_dir_snode); 1151*5331Samw ASSERT(from_dir_snode->n_magic == SMB_NODE_MAGIC); 1152*5331Samw ASSERT(from_dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 1153*5331Samw 1154*5331Samw ASSERT(to_dir_snode); 1155*5331Samw ASSERT(to_dir_snode->n_magic == SMB_NODE_MAGIC); 1156*5331Samw ASSERT(to_dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 1157*5331Samw 1158*5331Samw if (SMB_TREE_ROOT_FS(sr, from_dir_snode) == 0) 1159*5331Samw return (EACCES); 1160*5331Samw 1161*5331Samw if (SMB_TREE_ROOT_FS(sr, to_dir_snode) == 0) 1162*5331Samw return (EACCES); 1163*5331Samw 1164*5331Samw ASSERT(sr); 1165*5331Samw ASSERT(sr->tid_tree); 1166*5331Samw if (SMB_TREE_IS_READ_ONLY(sr)) 1167*5331Samw return (EROFS); 1168*5331Samw 1169*5331Samw /* 1170*5331Samw * Note: There is no need to check SMB_TREE_CASE_INSENSITIVE(sr) 1171*5331Samw * here. 1172*5331Samw * 1173*5331Samw * A case-sensitive rename is always done in this routine 1174*5331Samw * because we are using the on-disk name from an earlier lookup. 1175*5331Samw * If a mangled name was passed in by the caller (denoting a 1176*5331Samw * deterministic lookup), then the exact file must be renamed 1177*5331Samw * (i.e. SMB_IGNORE_CASE must not be passed to VOP_RENAME, or 1178*5331Samw * else the underlying file system might return a "first-match" 1179*5331Samw * on this on-disk name, possibly resulting in the wrong file). 1180*5331Samw */ 1181*5331Samw 1182*5331Samw /* 1183*5331Samw * XXX: Lock required through smb_node_release() below? 1184*5331Samw */ 1185*5331Samw 1186*5331Samw smb_get_caller_context(sr, &ct); 1187*5331Samw 1188*5331Samw rc = smb_vop_lookup(from_dir_snode->vp, from_name, &from_vp, NULL, 0, 1189*5331Samw NULL, cr, &ct); 1190*5331Samw 1191*5331Samw if (rc != 0) 1192*5331Samw return (rc); 1193*5331Samw 1194*5331Samw rc = smb_vop_rename(from_dir_snode->vp, from_name, to_dir_snode->vp, 1195*5331Samw to_name, flags, cr, &ct); 1196*5331Samw 1197*5331Samw if (rc == 0) { 1198*5331Samw from_snode = smb_node_lookup(sr, NULL, cr, from_vp, from_name, 1199*5331Samw from_dir_snode, NULL, &tmp_attr); 1200*5331Samw 1201*5331Samw if (from_snode == NULL) { 1202*5331Samw VN_RELE(from_vp); 1203*5331Samw return (ENOMEM); 1204*5331Samw } 1205*5331Samw 1206*5331Samw (void) smb_node_rename(from_dir_snode, from_snode, to_dir_snode, 1207*5331Samw to_name); 1208*5331Samw 1209*5331Samw smb_node_release(from_snode); 1210*5331Samw } else { 1211*5331Samw VN_RELE(from_vp); 1212*5331Samw } 1213*5331Samw 1214*5331Samw /* XXX: unlock */ 1215*5331Samw 1216*5331Samw return (rc); 1217*5331Samw } 1218*5331Samw 1219*5331Samw /* 1220*5331Samw * smb_fsop_setattr 1221*5331Samw * 1222*5331Samw * All SMB functions should use this wrapper to ensure that 1223*5331Samw * the the calls are performed with the appropriate credentials. 1224*5331Samw * Please document any direct call to explain the reason 1225*5331Samw * for avoiding this wrapper. 1226*5331Samw * 1227*5331Samw * It is assumed that a reference exists on snode coming into this routine. 1228*5331Samw * A null smb_request might be passed to this function. 1229*5331Samw */ 1230*5331Samw int 1231*5331Samw smb_fsop_setattr( 1232*5331Samw smb_request_t *sr, 1233*5331Samw cred_t *cr, 1234*5331Samw smb_node_t *snode, 1235*5331Samw smb_attr_t *set_attr, 1236*5331Samw smb_attr_t *ret_attr) 1237*5331Samw { 1238*5331Samw smb_node_t *unnamed_node; 1239*5331Samw vnode_t *unnamed_vp = NULL; 1240*5331Samw caller_context_t ct; 1241*5331Samw uint32_t status; 1242*5331Samw uint32_t access = 0; 1243*5331Samw int rc = 0; 1244*5331Samw int flags = 0; 1245*5331Samw 1246*5331Samw ASSERT(cr); 1247*5331Samw ASSERT(snode); 1248*5331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 1249*5331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 1250*5331Samw 1251*5331Samw if (SMB_TREE_ROOT_FS(sr, snode) == 0) 1252*5331Samw return (EACCES); 1253*5331Samw 1254*5331Samw if (SMB_TREE_IS_READ_ONLY(sr)) 1255*5331Samw return (EROFS); 1256*5331Samw 1257*5331Samw /* sr could be NULL in some cases */ 1258*5331Samw if (sr && sr->fid_ofile) { 1259*5331Samw /* if uid and/or gid is requested */ 1260*5331Samw if (set_attr->sa_mask & (SMB_AT_UID|SMB_AT_GID)) 1261*5331Samw access |= WRITE_OWNER; 1262*5331Samw 1263*5331Samw /* if anything else is also requested */ 1264*5331Samw if (set_attr->sa_mask & ~(SMB_AT_UID|SMB_AT_GID)) 1265*5331Samw access |= FILE_WRITE_ATTRIBUTES; 1266*5331Samw 1267*5331Samw status = smb_ofile_access(sr->fid_ofile, cr, access); 1268*5331Samw if (status != NT_STATUS_SUCCESS) 1269*5331Samw return (EACCES); 1270*5331Samw 1271*5331Samw if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS) 1272*5331Samw flags = ATTR_NOACLCHECK; 1273*5331Samw } 1274*5331Samw 1275*5331Samw smb_get_caller_context(sr, &ct); 1276*5331Samw 1277*5331Samw unnamed_node = SMB_IS_STREAM(snode); 1278*5331Samw 1279*5331Samw if (unnamed_node) { 1280*5331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 1281*5331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 1282*5331Samw unnamed_vp = unnamed_node->vp; 1283*5331Samw } 1284*5331Samw 1285*5331Samw rc = smb_vop_setattr(snode->vp, unnamed_vp, set_attr, flags, cr, &ct); 1286*5331Samw 1287*5331Samw if ((rc == 0) && ret_attr) { 1288*5331Samw /* 1289*5331Samw * This is an operation on behalf of CIFS service (to update 1290*5331Samw * smb node's attr) not on behalf of the user so it's done 1291*5331Samw * using kcred and the return value is intentionally ignored. 1292*5331Samw */ 1293*5331Samw ret_attr->sa_mask = SMB_AT_ALL; 1294*5331Samw (void) smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0, 1295*5331Samw kcred, &ct); 1296*5331Samw } 1297*5331Samw 1298*5331Samw return (rc); 1299*5331Samw } 1300*5331Samw 1301*5331Samw /* 1302*5331Samw * smb_fsop_read 1303*5331Samw * 1304*5331Samw * All SMB functions should use this wrapper to ensure that 1305*5331Samw * the the calls are performed with the appropriate credentials. 1306*5331Samw * Please document any direct call to explain the reason 1307*5331Samw * for avoiding this wrapper. 1308*5331Samw * 1309*5331Samw * It is assumed that a reference exists on snode coming into this routine. 1310*5331Samw */ 1311*5331Samw int 1312*5331Samw smb_fsop_read( 1313*5331Samw struct smb_request *sr, 1314*5331Samw cred_t *cr, 1315*5331Samw smb_node_t *snode, 1316*5331Samw uio_t *uio, 1317*5331Samw smb_attr_t *ret_attr) 1318*5331Samw { 1319*5331Samw smb_node_t *unnamed_node; 1320*5331Samw vnode_t *unnamed_vp = NULL; 1321*5331Samw caller_context_t ct; 1322*5331Samw int rc; 1323*5331Samw 1324*5331Samw ASSERT(cr); 1325*5331Samw ASSERT(snode); 1326*5331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 1327*5331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 1328*5331Samw 1329*5331Samw ASSERT(sr); 1330*5331Samw ASSERT(sr->fid_ofile); 1331*5331Samw 1332*5331Samw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_READ_DATA); 1333*5331Samw if (rc != NT_STATUS_SUCCESS) { 1334*5331Samw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_EXECUTE); 1335*5331Samw if (rc != NT_STATUS_SUCCESS) 1336*5331Samw return (EACCES); 1337*5331Samw } 1338*5331Samw 1339*5331Samw unnamed_node = SMB_IS_STREAM(snode); 1340*5331Samw if (unnamed_node) { 1341*5331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 1342*5331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 1343*5331Samw unnamed_vp = unnamed_node->vp; 1344*5331Samw /* 1345*5331Samw * Streams permission are checked against the unnamed stream, 1346*5331Samw * but in FS level they have their own permissions. To avoid 1347*5331Samw * rejection by FS due to lack of permission on the actual 1348*5331Samw * extended attr kcred is passed for streams. 1349*5331Samw */ 1350*5331Samw cr = kcred; 1351*5331Samw } 1352*5331Samw 1353*5331Samw smb_get_caller_context(sr, &ct); 1354*5331Samw rc = smb_vop_read(snode->vp, uio, cr, &ct); 1355*5331Samw 1356*5331Samw if (rc == 0) { 1357*5331Samw /* 1358*5331Samw * This is an operation on behalf of CIFS service (to update 1359*5331Samw * smb node's attr) not on behalf of the user so it's done 1360*5331Samw * using kcred and the return value is intentionally ignored. 1361*5331Samw */ 1362*5331Samw ret_attr->sa_mask = SMB_AT_ALL; 1363*5331Samw (void) smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0, 1364*5331Samw kcred, &ct); 1365*5331Samw } 1366*5331Samw 1367*5331Samw return (rc); 1368*5331Samw } 1369*5331Samw 1370*5331Samw /* 1371*5331Samw * smb_fsop_write 1372*5331Samw * 1373*5331Samw * This is a wrapper function used for smb_write and smb_write_raw operations. 1374*5331Samw * 1375*5331Samw * It is assumed that a reference exists on snode coming into this routine. 1376*5331Samw */ 1377*5331Samw int 1378*5331Samw smb_fsop_write( 1379*5331Samw struct smb_request *sr, 1380*5331Samw cred_t *cr, 1381*5331Samw smb_node_t *snode, 1382*5331Samw uio_t *uio, 1383*5331Samw uint32_t *lcount, 1384*5331Samw smb_attr_t *ret_attr, 1385*5331Samw uint32_t *flag) 1386*5331Samw { 1387*5331Samw smb_node_t *unnamed_node; 1388*5331Samw vnode_t *unnamed_vp = NULL; 1389*5331Samw caller_context_t ct; 1390*5331Samw int rc; 1391*5331Samw 1392*5331Samw ASSERT(cr); 1393*5331Samw ASSERT(snode); 1394*5331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 1395*5331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 1396*5331Samw 1397*5331Samw ASSERT(sr); 1398*5331Samw ASSERT(sr->tid_tree); 1399*5331Samw ASSERT(sr->fid_ofile); 1400*5331Samw 1401*5331Samw if (SMB_TREE_IS_READ_ONLY(sr)) 1402*5331Samw return (EROFS); 1403*5331Samw /* 1404*5331Samw * XXX what if the file has been opened only with 1405*5331Samw * FILE_APPEND_DATA? 1406*5331Samw */ 1407*5331Samw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_WRITE_DATA); 1408*5331Samw if (rc != NT_STATUS_SUCCESS) 1409*5331Samw return (EACCES); 1410*5331Samw 1411*5331Samw smb_get_caller_context(sr, &ct); 1412*5331Samw 1413*5331Samw unnamed_node = SMB_IS_STREAM(snode); 1414*5331Samw 1415*5331Samw if (unnamed_node) { 1416*5331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 1417*5331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 1418*5331Samw unnamed_vp = unnamed_node->vp; 1419*5331Samw /* 1420*5331Samw * Streams permission are checked against the unnamed stream, 1421*5331Samw * but in FS level they have their own permissions. To avoid 1422*5331Samw * rejection by FS due to lack of permission on the actual 1423*5331Samw * extended attr kcred is passed for streams. 1424*5331Samw */ 1425*5331Samw cr = kcred; 1426*5331Samw } 1427*5331Samw 1428*5331Samw rc = smb_vop_write(snode->vp, uio, flag, lcount, cr, &ct); 1429*5331Samw 1430*5331Samw if (rc == 0) { 1431*5331Samw /* 1432*5331Samw * This is an operation on behalf of CIFS service (to update 1433*5331Samw * smb node's attr) not on behalf of the user so it's done 1434*5331Samw * using kcred and the return value is intentionally ignored. 1435*5331Samw */ 1436*5331Samw ret_attr->sa_mask = SMB_AT_ALL; 1437*5331Samw (void) smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0, 1438*5331Samw kcred, &ct); 1439*5331Samw } 1440*5331Samw 1441*5331Samw return (rc); 1442*5331Samw } 1443*5331Samw 1444*5331Samw /* 1445*5331Samw * smb_fsop_statfs 1446*5331Samw * 1447*5331Samw * This is a wrapper function used for stat operations. 1448*5331Samw */ 1449*5331Samw int 1450*5331Samw smb_fsop_statfs( 1451*5331Samw cred_t *cr, 1452*5331Samw smb_node_t *snode, 1453*5331Samw struct statvfs64 *statp) 1454*5331Samw { 1455*5331Samw ASSERT(cr); 1456*5331Samw ASSERT(snode); 1457*5331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 1458*5331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 1459*5331Samw 1460*5331Samw return (smb_vop_statfs(snode->vp, statp, cr)); 1461*5331Samw } 1462*5331Samw 1463*5331Samw /* 1464*5331Samw * smb_fsop_access 1465*5331Samw */ 1466*5331Samw int 1467*5331Samw smb_fsop_access(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 1468*5331Samw uint32_t faccess) 1469*5331Samw { 1470*5331Samw int access = 0; 1471*5331Samw int error; 1472*5331Samw vnode_t *dir_vp; 1473*5331Samw boolean_t acl_check = B_TRUE; 1474*5331Samw smb_node_t *unnamed_node; 1475*5331Samw 1476*5331Samw ASSERT(cr); 1477*5331Samw ASSERT(snode); 1478*5331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 1479*5331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 1480*5331Samw 1481*5331Samw if (faccess == 0) 1482*5331Samw return (NT_STATUS_SUCCESS); 1483*5331Samw 1484*5331Samw if (SMB_TREE_IS_READ_ONLY(sr)) { 1485*5331Samw if (faccess & (FILE_WRITE_DATA|FILE_APPEND_DATA| 1486*5331Samw FILE_WRITE_EA|FILE_DELETE_CHILD|FILE_WRITE_ATTRIBUTES| 1487*5331Samw DELETE|WRITE_DAC|WRITE_OWNER)) { 1488*5331Samw return (NT_STATUS_ACCESS_DENIED); 1489*5331Samw } 1490*5331Samw } 1491*5331Samw 1492*5331Samw unnamed_node = SMB_IS_STREAM(snode); 1493*5331Samw if (unnamed_node) { 1494*5331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 1495*5331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 1496*5331Samw /* 1497*5331Samw * Streams authorization should be performed against the 1498*5331Samw * unnamed stream. 1499*5331Samw */ 1500*5331Samw snode = unnamed_node; 1501*5331Samw } 1502*5331Samw 1503*5331Samw if (faccess & ACCESS_SYSTEM_SECURITY) { 1504*5331Samw /* 1505*5331Samw * This permission is required for reading/writing SACL and 1506*5331Samw * it's not part of DACL. It's only granted via proper 1507*5331Samw * privileges. 1508*5331Samw */ 1509*5331Samw if ((sr->uid_user->u_privileges & 1510*5331Samw (SMB_USER_PRIV_BACKUP | 1511*5331Samw SMB_USER_PRIV_RESTORE | 1512*5331Samw SMB_USER_PRIV_SECURITY)) == 0) 1513*5331Samw return (NT_STATUS_PRIVILEGE_NOT_HELD); 1514*5331Samw 1515*5331Samw faccess &= ~ACCESS_SYSTEM_SECURITY; 1516*5331Samw } 1517*5331Samw 1518*5331Samw /* Links don't have ACL */ 1519*5331Samw if (((sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS) == 0) || 1520*5331Samw (snode->attr.sa_vattr.va_type == VLNK)) 1521*5331Samw acl_check = B_FALSE; 1522*5331Samw 1523*5331Samw if (acl_check) { 1524*5331Samw dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL; 1525*5331Samw error = smb_vop_access(snode->vp, faccess, V_ACE_MASK, dir_vp, 1526*5331Samw cr); 1527*5331Samw } else { 1528*5331Samw /* 1529*5331Samw * FS doesn't understand 32-bit mask, need to map 1530*5331Samw */ 1531*5331Samw if (faccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) 1532*5331Samw access |= VWRITE; 1533*5331Samw 1534*5331Samw if (faccess & FILE_READ_DATA) 1535*5331Samw access |= VREAD; 1536*5331Samw 1537*5331Samw if (faccess & FILE_EXECUTE) 1538*5331Samw access |= VEXEC; 1539*5331Samw 1540*5331Samw error = smb_vop_access(snode->vp, access, 0, NULL, cr); 1541*5331Samw } 1542*5331Samw 1543*5331Samw return ((error) ? NT_STATUS_ACCESS_DENIED : NT_STATUS_SUCCESS); 1544*5331Samw } 1545*5331Samw 1546*5331Samw /* 1547*5331Samw * smb_fsop_lookup_name() 1548*5331Samw * 1549*5331Samw * Sanity checks on dir_snode done in smb_fsop_lookup(). 1550*5331Samw * 1551*5331Samw * Note: This function is called only from the open path. 1552*5331Samw * It will check if the file is a stream. 1553*5331Samw * It will also return an error if the looked-up file is in 1554*5331Samw * a child mount. 1555*5331Samw */ 1556*5331Samw 1557*5331Samw int 1558*5331Samw smb_fsop_lookup_name( 1559*5331Samw struct smb_request *sr, 1560*5331Samw cred_t *cr, 1561*5331Samw int flags, 1562*5331Samw smb_node_t *root_node, 1563*5331Samw smb_node_t *dir_snode, 1564*5331Samw char *name, 1565*5331Samw smb_node_t **ret_snode, 1566*5331Samw smb_attr_t *ret_attr) 1567*5331Samw { 1568*5331Samw smb_node_t *fnode; 1569*5331Samw smb_attr_t file_attr; 1570*5331Samw caller_context_t ct; 1571*5331Samw vnode_t *xattrdirvp; 1572*5331Samw vnode_t *vp; 1573*5331Samw char *od_name; 1574*5331Samw char *fname; 1575*5331Samw char *sname; 1576*5331Samw int rc; 1577*5331Samw 1578*5331Samw ASSERT(cr); 1579*5331Samw ASSERT(dir_snode); 1580*5331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 1581*5331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 1582*5331Samw 1583*5331Samw /* 1584*5331Samw * The following check is required for streams processing, below 1585*5331Samw */ 1586*5331Samw 1587*5331Samw if (SMB_TREE_CASE_INSENSITIVE(sr)) 1588*5331Samw flags |= SMB_IGNORE_CASE; 1589*5331Samw 1590*5331Samw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1591*5331Samw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1592*5331Samw 1593*5331Samw if (smb_stream_parse_name(name, fname, sname)) { 1594*5331Samw /* 1595*5331Samw * Look up the unnamed stream (i.e. fname). 1596*5331Samw * Unmangle processing will be done on fname 1597*5331Samw * as well as any link target. 1598*5331Samw */ 1599*5331Samw rc = smb_fsop_lookup(sr, cr, flags, root_node, dir_snode, fname, 1600*5331Samw &fnode, &file_attr, NULL, NULL); 1601*5331Samw 1602*5331Samw if (rc != 0) { 1603*5331Samw kmem_free(fname, MAXNAMELEN); 1604*5331Samw kmem_free(sname, MAXNAMELEN); 1605*5331Samw return (rc); 1606*5331Samw } 1607*5331Samw 1608*5331Samw od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1609*5331Samw 1610*5331Samw /* 1611*5331Samw * od_name is the on-disk name of the stream, except 1612*5331Samw * without the prepended stream prefix (SMB_STREAM_PREFIX) 1613*5331Samw */ 1614*5331Samw 1615*5331Samw /* 1616*5331Samw * XXX 1617*5331Samw * What permissions NTFS requires for stream lookup if any? 1618*5331Samw */ 1619*5331Samw rc = smb_vop_stream_lookup(fnode->vp, sname, &vp, od_name, 1620*5331Samw &xattrdirvp, flags, root_node->vp, cr, &ct); 1621*5331Samw 1622*5331Samw if (rc != 0) { 1623*5331Samw smb_node_release(fnode); 1624*5331Samw kmem_free(fname, MAXNAMELEN); 1625*5331Samw kmem_free(sname, MAXNAMELEN); 1626*5331Samw kmem_free(od_name, MAXNAMELEN); 1627*5331Samw return (rc); 1628*5331Samw } 1629*5331Samw 1630*5331Samw *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, 1631*5331Samw vp, od_name, ret_attr); 1632*5331Samw 1633*5331Samw kmem_free(od_name, MAXNAMELEN); 1634*5331Samw smb_node_release(fnode); 1635*5331Samw 1636*5331Samw if (*ret_snode == NULL) { 1637*5331Samw VN_RELE(xattrdirvp); 1638*5331Samw VN_RELE(vp); 1639*5331Samw kmem_free(fname, MAXNAMELEN); 1640*5331Samw kmem_free(sname, MAXNAMELEN); 1641*5331Samw return (ENOMEM); 1642*5331Samw } 1643*5331Samw } else { 1644*5331Samw rc = smb_fsop_lookup(sr, cr, flags, root_node, dir_snode, name, 1645*5331Samw ret_snode, ret_attr, NULL, NULL); 1646*5331Samw } 1647*5331Samw 1648*5331Samw if (rc == 0) { 1649*5331Samw ASSERT(ret_snode); 1650*5331Samw if (SMB_TREE_ROOT_FS(sr, *ret_snode) == 0) { 1651*5331Samw smb_node_release(*ret_snode); 1652*5331Samw *ret_snode = NULL; 1653*5331Samw rc = EACCES; 1654*5331Samw } 1655*5331Samw } 1656*5331Samw 1657*5331Samw kmem_free(fname, MAXNAMELEN); 1658*5331Samw kmem_free(sname, MAXNAMELEN); 1659*5331Samw 1660*5331Samw return (rc); 1661*5331Samw } 1662*5331Samw 1663*5331Samw /* 1664*5331Samw * smb_fsop_lookup 1665*5331Samw * 1666*5331Samw * All SMB functions should use this smb_vop_lookup wrapper to ensure that 1667*5331Samw * the smb_vop_lookup is performed with the appropriate credentials and using 1668*5331Samw * case insensitive compares. Please document any direct call to smb_vop_lookup 1669*5331Samw * to explain the reason for avoiding this wrapper. 1670*5331Samw * 1671*5331Samw * It is assumed that a reference exists on dir_snode coming into this routine 1672*5331Samw * (and that it is safe from deallocation). 1673*5331Samw * 1674*5331Samw * Same with the root_node. 1675*5331Samw * 1676*5331Samw * *ret_snode is returned with a reference upon success. No reference is 1677*5331Samw * taken if an error is returned. 1678*5331Samw * 1679*5331Samw * Note: The returned ret_snode may be in a child mount. This is ok for 1680*5331Samw * readdir and getdents. 1681*5331Samw * 1682*5331Samw * Other smb_fsop_* routines will call SMB_TREE_ROOT_FS() to prevent 1683*5331Samw * operations on files not in the parent mount. 1684*5331Samw */ 1685*5331Samw int 1686*5331Samw smb_fsop_lookup( 1687*5331Samw struct smb_request *sr, 1688*5331Samw cred_t *cr, 1689*5331Samw int flags, 1690*5331Samw smb_node_t *root_node, 1691*5331Samw smb_node_t *dir_snode, 1692*5331Samw char *name, 1693*5331Samw smb_node_t **ret_snode, 1694*5331Samw smb_attr_t *ret_attr, 1695*5331Samw char *ret_shortname, /* Must be at least MANGLE_NAMELEN chars */ 1696*5331Samw char *ret_name83) /* Must be at least MANGLE_NAMELEN chars */ 1697*5331Samw { 1698*5331Samw smb_node_t *lnk_target_node; 1699*5331Samw smb_node_t *lnk_dnode; 1700*5331Samw caller_context_t ct; 1701*5331Samw char *longname; 1702*5331Samw char *od_name; 1703*5331Samw vnode_t *vp; 1704*5331Samw int rc; 1705*5331Samw 1706*5331Samw ASSERT(cr); 1707*5331Samw ASSERT(dir_snode); 1708*5331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 1709*5331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 1710*5331Samw 1711*5331Samw if (name == NULL) 1712*5331Samw return (EINVAL); 1713*5331Samw 1714*5331Samw if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0) 1715*5331Samw return (EACCES); 1716*5331Samw 1717*5331Samw if (SMB_TREE_CASE_INSENSITIVE(sr)) 1718*5331Samw flags |= SMB_IGNORE_CASE; 1719*5331Samw 1720*5331Samw smb_get_caller_context(sr, &ct); 1721*5331Samw 1722*5331Samw od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1723*5331Samw 1724*5331Samw rc = smb_vop_lookup(dir_snode->vp, name, &vp, od_name, flags, 1725*5331Samw root_node ? root_node->vp : NULL, cr, &ct); 1726*5331Samw 1727*5331Samw if (rc != 0) { 1728*5331Samw if (smb_maybe_mangled_name(name) == 0) { 1729*5331Samw kmem_free(od_name, MAXNAMELEN); 1730*5331Samw return (rc); 1731*5331Samw } 1732*5331Samw 1733*5331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1734*5331Samw 1735*5331Samw rc = smb_unmangle_name(sr, cr, dir_snode, name, longname, 1736*5331Samw MAXNAMELEN, ret_shortname, ret_name83, 1); 1737*5331Samw 1738*5331Samw if (rc != 0) { 1739*5331Samw kmem_free(od_name, MAXNAMELEN); 1740*5331Samw kmem_free(longname, MAXNAMELEN); 1741*5331Samw return (rc); 1742*5331Samw } 1743*5331Samw 1744*5331Samw /* 1745*5331Samw * We passed "1" as the "od" parameter 1746*5331Samw * to smb_unmangle_name(), such that longname 1747*5331Samw * is the real (case-sensitive) on-disk name. 1748*5331Samw * We make sure we do a lookup on this exact 1749*5331Samw * name, as the name was mangled and denotes 1750*5331Samw * a unique file. 1751*5331Samw */ 1752*5331Samw 1753*5331Samw if (flags & SMB_IGNORE_CASE) 1754*5331Samw flags &= ~SMB_IGNORE_CASE; 1755*5331Samw 1756*5331Samw rc = smb_vop_lookup(dir_snode->vp, longname, &vp, od_name, 1757*5331Samw flags, root_node ? root_node->vp : NULL, cr, &ct); 1758*5331Samw 1759*5331Samw kmem_free(longname, MAXNAMELEN); 1760*5331Samw 1761*5331Samw if (rc != 0) { 1762*5331Samw kmem_free(od_name, MAXNAMELEN); 1763*5331Samw return (rc); 1764*5331Samw } 1765*5331Samw } 1766*5331Samw 1767*5331Samw if ((flags & SMB_FOLLOW_LINKS) && (vp->v_type == VLNK)) { 1768*5331Samw 1769*5331Samw rc = smb_pathname(sr, od_name, FOLLOW, root_node, dir_snode, 1770*5331Samw &lnk_dnode, &lnk_target_node, cr); 1771*5331Samw 1772*5331Samw if (rc != 0) { 1773*5331Samw /* 1774*5331Samw * The link is assumed to be for the last component 1775*5331Samw * of a path. Hence any ENOTDIR error will be returned 1776*5331Samw * as ENOENT. 1777*5331Samw */ 1778*5331Samw if (rc == ENOTDIR) 1779*5331Samw rc = ENOENT; 1780*5331Samw 1781*5331Samw VN_RELE(vp); 1782*5331Samw kmem_free(od_name, MAXNAMELEN); 1783*5331Samw return (rc); 1784*5331Samw } 1785*5331Samw 1786*5331Samw /* 1787*5331Samw * Release the original VLNK vnode 1788*5331Samw */ 1789*5331Samw 1790*5331Samw VN_RELE(vp); 1791*5331Samw vp = lnk_target_node->vp; 1792*5331Samw 1793*5331Samw rc = smb_vop_traverse_check(&vp); 1794*5331Samw 1795*5331Samw if (rc != 0) { 1796*5331Samw smb_node_release(lnk_dnode); 1797*5331Samw smb_node_release(lnk_target_node); 1798*5331Samw kmem_free(od_name, MAXNAMELEN); 1799*5331Samw return (rc); 1800*5331Samw } 1801*5331Samw 1802*5331Samw /* 1803*5331Samw * smb_vop_traverse_check() may have returned a different vnode 1804*5331Samw */ 1805*5331Samw 1806*5331Samw if (lnk_target_node->vp == vp) { 1807*5331Samw *ret_snode = lnk_target_node; 1808*5331Samw *ret_attr = (*ret_snode)->attr; 1809*5331Samw } else { 1810*5331Samw *ret_snode = smb_node_lookup(sr, NULL, cr, vp, 1811*5331Samw lnk_target_node->od_name, lnk_dnode, NULL, 1812*5331Samw ret_attr); 1813*5331Samw 1814*5331Samw if (*ret_snode == NULL) { 1815*5331Samw VN_RELE(vp); 1816*5331Samw rc = ENOMEM; 1817*5331Samw } 1818*5331Samw smb_node_release(lnk_target_node); 1819*5331Samw } 1820*5331Samw 1821*5331Samw smb_node_release(lnk_dnode); 1822*5331Samw 1823*5331Samw } else { 1824*5331Samw 1825*5331Samw rc = smb_vop_traverse_check(&vp); 1826*5331Samw if (rc) { 1827*5331Samw VN_RELE(vp); 1828*5331Samw kmem_free(od_name, MAXNAMELEN); 1829*5331Samw return (rc); 1830*5331Samw } 1831*5331Samw 1832*5331Samw *ret_snode = smb_node_lookup(sr, NULL, cr, vp, od_name, 1833*5331Samw dir_snode, NULL, ret_attr); 1834*5331Samw 1835*5331Samw if (*ret_snode == NULL) { 1836*5331Samw VN_RELE(vp); 1837*5331Samw rc = ENOMEM; 1838*5331Samw } 1839*5331Samw } 1840*5331Samw 1841*5331Samw kmem_free(od_name, MAXNAMELEN); 1842*5331Samw return (rc); 1843*5331Samw } 1844*5331Samw 1845*5331Samw /* 1846*5331Samw * smb_fsop_stream_readdir() 1847*5331Samw * 1848*5331Samw * ret_snode and ret_attr are optional parameters (i.e. NULL may be passed in) 1849*5331Samw * 1850*5331Samw * This routine will return only NTFS streams. If an NTFS stream is not 1851*5331Samw * found at the offset specified, the directory will be read until an NTFS 1852*5331Samw * stream is found or until EOF. 1853*5331Samw * 1854*5331Samw * Note: Sanity checks done in caller 1855*5331Samw * (smb_fsop_readdir(), smb_fsop_remove_streams()) 1856*5331Samw */ 1857*5331Samw 1858*5331Samw int 1859*5331Samw smb_fsop_stream_readdir(struct smb_request *sr, cred_t *cr, smb_node_t *fnode, 1860*5331Samw uint32_t *cookiep, struct fs_stream_info *stream_info, 1861*5331Samw smb_node_t **ret_snode, smb_attr_t *ret_attr) 1862*5331Samw { 1863*5331Samw smb_node_t *ret_snodep = NULL; 1864*5331Samw caller_context_t ct; 1865*5331Samw smb_attr_t tmp_attr; 1866*5331Samw vnode_t *xattrdirvp; 1867*5331Samw vnode_t *vp; 1868*5331Samw int rc = 0; 1869*5331Samw int flags = 0; 1870*5331Samw 1871*5331Samw /* 1872*5331Samw * XXX NTFS permission requirements if any? 1873*5331Samw */ 1874*5331Samw ASSERT(cr); 1875*5331Samw ASSERT(fnode); 1876*5331Samw ASSERT(fnode->n_magic == SMB_NODE_MAGIC); 1877*5331Samw ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING); 1878*5331Samw 1879*5331Samw if (SMB_TREE_CASE_INSENSITIVE(sr)) 1880*5331Samw flags = SMB_IGNORE_CASE; 1881*5331Samw 1882*5331Samw smb_get_caller_context(sr, &ct); 1883*5331Samw 1884*5331Samw rc = smb_vop_stream_readdir(fnode->vp, cookiep, stream_info, &vp, 1885*5331Samw &xattrdirvp, flags, cr, &ct); 1886*5331Samw 1887*5331Samw if ((rc != 0) || *cookiep == SMB_EOF) 1888*5331Samw return (rc); 1889*5331Samw 1890*5331Samw ret_snodep = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, vp, 1891*5331Samw stream_info->name, &tmp_attr); 1892*5331Samw 1893*5331Samw if (ret_snodep == NULL) { 1894*5331Samw VN_RELE(xattrdirvp); 1895*5331Samw VN_RELE(vp); 1896*5331Samw return (ENOMEM); 1897*5331Samw } 1898*5331Samw 1899*5331Samw stream_info->size = tmp_attr.sa_vattr.va_size; 1900*5331Samw 1901*5331Samw if (ret_attr) 1902*5331Samw *ret_attr = tmp_attr; 1903*5331Samw 1904*5331Samw if (ret_snode) 1905*5331Samw *ret_snode = ret_snodep; 1906*5331Samw else 1907*5331Samw smb_node_release(ret_snodep); 1908*5331Samw 1909*5331Samw return (rc); 1910*5331Samw } 1911*5331Samw 1912*5331Samw int /*ARGSUSED*/ 1913*5331Samw smb_fsop_commit(smb_request_t *sr, cred_t *cr, smb_node_t *snode) 1914*5331Samw { 1915*5331Samw caller_context_t ct; 1916*5331Samw 1917*5331Samw ASSERT(cr); 1918*5331Samw ASSERT(snode); 1919*5331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 1920*5331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 1921*5331Samw 1922*5331Samw ASSERT(sr); 1923*5331Samw ASSERT(sr->tid_tree); 1924*5331Samw if (SMB_TREE_IS_READ_ONLY(sr)) 1925*5331Samw return (EROFS); 1926*5331Samw 1927*5331Samw smb_get_caller_context(sr, &ct); 1928*5331Samw 1929*5331Samw return (smb_vop_commit(snode->vp, cr, &ct)); 1930*5331Samw } 1931*5331Samw 1932*5331Samw /* 1933*5331Samw * smb_fsop_sdinit 1934*5331Samw * 1935*5331Samw * Initializes the given FS SD structure. 1936*5331Samw */ 1937*5331Samw void 1938*5331Samw smb_fsop_sdinit(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t flags) 1939*5331Samw { 1940*5331Samw bzero(fs_sd, sizeof (smb_fssd_t)); 1941*5331Samw fs_sd->sd_secinfo = secinfo; 1942*5331Samw fs_sd->sd_flags = flags; 1943*5331Samw } 1944*5331Samw 1945*5331Samw /* 1946*5331Samw * smb_fsop_sdterm 1947*5331Samw * 1948*5331Samw * Frees allocated memory for acl fields. 1949*5331Samw */ 1950*5331Samw void 1951*5331Samw smb_fsop_sdterm(smb_fssd_t *fs_sd) 1952*5331Samw { 1953*5331Samw ASSERT(fs_sd); 1954*5331Samw 1955*5331Samw smb_fsop_aclfree(fs_sd->sd_zdacl); 1956*5331Samw smb_fsop_aclfree(fs_sd->sd_zsacl); 1957*5331Samw bzero(fs_sd, sizeof (smb_fssd_t)); 1958*5331Samw } 1959*5331Samw 1960*5331Samw /* 1961*5331Samw * smb_fsop_aclread 1962*5331Samw * 1963*5331Samw * Retrieve filesystem ACL. Depends on requested ACLs in 1964*5331Samw * fs_sd->sd_secinfo, it'll set DACL and SACL pointers in 1965*5331Samw * fs_sd. Note that requesting a DACL/SACL doesn't mean that 1966*5331Samw * the corresponding field in fs_sd should be non-NULL upon 1967*5331Samw * return, since the target ACL might not contain that type of 1968*5331Samw * entries. 1969*5331Samw * 1970*5331Samw * Returned ACL is always in ACE_T (aka ZFS) format. 1971*5331Samw * If successful the allocated memory for the ACL should be freed 1972*5331Samw * using smb_fsop_aclfree() or smb_fsop_sdterm() 1973*5331Samw */ 1974*5331Samw int 1975*5331Samw smb_fsop_aclread(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 1976*5331Samw smb_fssd_t *fs_sd) 1977*5331Samw { 1978*5331Samw int error = 0; 1979*5331Samw int flags = 0; 1980*5331Samw int access = 0; 1981*5331Samw acl_t *acl; 1982*5331Samw caller_context_t ct; 1983*5331Samw smb_node_t *unnamed_node; 1984*5331Samw 1985*5331Samw ASSERT(cr); 1986*5331Samw 1987*5331Samw if (sr->fid_ofile) { 1988*5331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 1989*5331Samw access = READ_CONTROL; 1990*5331Samw 1991*5331Samw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 1992*5331Samw access |= ACCESS_SYSTEM_SECURITY; 1993*5331Samw 1994*5331Samw error = smb_ofile_access(sr->fid_ofile, cr, access); 1995*5331Samw if (error != NT_STATUS_SUCCESS) { 1996*5331Samw return (EACCES); 1997*5331Samw } 1998*5331Samw } 1999*5331Samw 2000*5331Samw unnamed_node = SMB_IS_STREAM(snode); 2001*5331Samw if (unnamed_node) { 2002*5331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 2003*5331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 2004*5331Samw /* 2005*5331Samw * Streams don't have ACL, any read ACL attempt on a stream 2006*5331Samw * should be performed on the unnamed stream. 2007*5331Samw */ 2008*5331Samw snode = unnamed_node; 2009*5331Samw } 2010*5331Samw 2011*5331Samw if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS) 2012*5331Samw flags = ATTR_NOACLCHECK; 2013*5331Samw 2014*5331Samw smb_get_caller_context(sr, &ct); 2015*5331Samw error = smb_vop_acl_read(snode->vp, &acl, flags, 2016*5331Samw sr->tid_tree->t_acltype, cr, &ct); 2017*5331Samw if (error != 0) { 2018*5331Samw return (error); 2019*5331Samw } 2020*5331Samw 2021*5331Samw error = acl_translate(acl, _ACL_ACE_ENABLED, 2022*5331Samw (snode->vp->v_type == VDIR), fs_sd->sd_uid, fs_sd->sd_gid); 2023*5331Samw 2024*5331Samw if (error == 0) { 2025*5331Samw smb_fsop_aclsplit(acl, &fs_sd->sd_zdacl, &fs_sd->sd_zsacl, 2026*5331Samw fs_sd->sd_secinfo); 2027*5331Samw } 2028*5331Samw 2029*5331Samw acl_free(acl); 2030*5331Samw return (error); 2031*5331Samw } 2032*5331Samw 2033*5331Samw /* 2034*5331Samw * smb_fsop_aclwrite 2035*5331Samw * 2036*5331Samw * Stores the filesystem ACL provided in fs_sd->sd_acl. 2037*5331Samw */ 2038*5331Samw int 2039*5331Samw smb_fsop_aclwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 2040*5331Samw smb_fssd_t *fs_sd) 2041*5331Samw { 2042*5331Samw int target_flavor; 2043*5331Samw int error = 0; 2044*5331Samw int flags = 0; 2045*5331Samw int access = 0; 2046*5331Samw caller_context_t ct; 2047*5331Samw acl_t *acl, *dacl, *sacl; 2048*5331Samw smb_node_t *unnamed_node; 2049*5331Samw 2050*5331Samw ASSERT(cr); 2051*5331Samw 2052*5331Samw ASSERT(sr); 2053*5331Samw ASSERT(sr->tid_tree); 2054*5331Samw if (SMB_TREE_IS_READ_ONLY(sr)) 2055*5331Samw return (EROFS); 2056*5331Samw 2057*5331Samw if (sr->fid_ofile) { 2058*5331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 2059*5331Samw access = WRITE_DAC; 2060*5331Samw 2061*5331Samw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 2062*5331Samw access |= ACCESS_SYSTEM_SECURITY; 2063*5331Samw 2064*5331Samw error = smb_ofile_access(sr->fid_ofile, cr, access); 2065*5331Samw if (error != NT_STATUS_SUCCESS) 2066*5331Samw return (EACCES); 2067*5331Samw } 2068*5331Samw 2069*5331Samw switch (sr->tid_tree->t_acltype) { 2070*5331Samw case ACLENT_T: 2071*5331Samw target_flavor = _ACL_ACLENT_ENABLED; 2072*5331Samw break; 2073*5331Samw 2074*5331Samw case ACE_T: 2075*5331Samw target_flavor = _ACL_ACE_ENABLED; 2076*5331Samw break; 2077*5331Samw default: 2078*5331Samw return (EINVAL); 2079*5331Samw } 2080*5331Samw 2081*5331Samw unnamed_node = SMB_IS_STREAM(snode); 2082*5331Samw if (unnamed_node) { 2083*5331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 2084*5331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 2085*5331Samw /* 2086*5331Samw * Streams don't have ACL, any write ACL attempt on a stream 2087*5331Samw * should be performed on the unnamed stream. 2088*5331Samw */ 2089*5331Samw snode = unnamed_node; 2090*5331Samw } 2091*5331Samw 2092*5331Samw dacl = fs_sd->sd_zdacl; 2093*5331Samw sacl = fs_sd->sd_zsacl; 2094*5331Samw 2095*5331Samw ASSERT(dacl || sacl); 2096*5331Samw if ((dacl == NULL) && (sacl == NULL)) 2097*5331Samw return (EINVAL); 2098*5331Samw 2099*5331Samw if (dacl && sacl) 2100*5331Samw acl = smb_fsop_aclmerge(dacl, sacl); 2101*5331Samw else if (dacl) 2102*5331Samw acl = dacl; 2103*5331Samw else 2104*5331Samw acl = sacl; 2105*5331Samw 2106*5331Samw error = acl_translate(acl, target_flavor, (snode->vp->v_type == VDIR), 2107*5331Samw fs_sd->sd_uid, fs_sd->sd_gid); 2108*5331Samw if (error == 0) { 2109*5331Samw smb_get_caller_context(sr, &ct); 2110*5331Samw if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS) 2111*5331Samw flags = ATTR_NOACLCHECK; 2112*5331Samw 2113*5331Samw error = smb_vop_acl_write(snode->vp, acl, flags, cr, &ct); 2114*5331Samw } 2115*5331Samw 2116*5331Samw if (dacl && sacl) 2117*5331Samw acl_free(acl); 2118*5331Samw 2119*5331Samw return (error); 2120*5331Samw } 2121*5331Samw 2122*5331Samw acl_t * 2123*5331Samw smb_fsop_aclalloc(int acenum, int flags) 2124*5331Samw { 2125*5331Samw acl_t *acl; 2126*5331Samw 2127*5331Samw acl = acl_alloc(ACE_T); 2128*5331Samw acl->acl_cnt = acenum; 2129*5331Samw acl->acl_aclp = kmem_zalloc(acl->acl_entry_size * acenum, KM_SLEEP); 2130*5331Samw acl->acl_flags = flags; 2131*5331Samw return (acl); 2132*5331Samw } 2133*5331Samw 2134*5331Samw void 2135*5331Samw smb_fsop_aclfree(acl_t *acl) 2136*5331Samw { 2137*5331Samw if (acl) 2138*5331Samw acl_free(acl); 2139*5331Samw } 2140*5331Samw 2141*5331Samw /* 2142*5331Samw * smb_fsop_aclmerge 2143*5331Samw * 2144*5331Samw * smb_fsop_aclread/write routines which interact with filesystem 2145*5331Samw * work with single ACL. This routine merges given DACL and SACL 2146*5331Samw * which might have been created during CIFS to FS conversion into 2147*5331Samw * one single ACL. 2148*5331Samw */ 2149*5331Samw static acl_t * 2150*5331Samw smb_fsop_aclmerge(acl_t *dacl, acl_t *sacl) 2151*5331Samw { 2152*5331Samw acl_t *acl; 2153*5331Samw int dacl_size; 2154*5331Samw 2155*5331Samw ASSERT(dacl); 2156*5331Samw ASSERT(sacl); 2157*5331Samw 2158*5331Samw acl = smb_fsop_aclalloc(dacl->acl_cnt + sacl->acl_cnt, dacl->acl_flags); 2159*5331Samw dacl_size = dacl->acl_cnt * dacl->acl_entry_size; 2160*5331Samw bcopy(dacl->acl_aclp, acl->acl_aclp, dacl_size); 2161*5331Samw bcopy(sacl->acl_aclp, (char *)acl->acl_aclp + dacl_size, 2162*5331Samw sacl->acl_cnt * sacl->acl_entry_size); 2163*5331Samw 2164*5331Samw return (acl); 2165*5331Samw } 2166*5331Samw 2167*5331Samw /* 2168*5331Samw * smb_fsop_aclsplit 2169*5331Samw * 2170*5331Samw * splits the given ACE_T ACL (zacl) to one or two ACLs (DACL/SACL) based on 2171*5331Samw * the 'which_acl' parameter. Note that output dacl/sacl parameters could be 2172*5331Samw * NULL even if they're specified in 'which_acl', which means the target 2173*5331Samw * doesn't have any access and/or audit ACEs. 2174*5331Samw */ 2175*5331Samw static void 2176*5331Samw smb_fsop_aclsplit(acl_t *zacl, acl_t **dacl, acl_t **sacl, int which_acl) 2177*5331Samw { 2178*5331Samw ace_t *zace; 2179*5331Samw ace_t *access_ace; 2180*5331Samw ace_t *audit_ace; 2181*5331Samw int naccess, naudit; 2182*5331Samw int get_dacl, get_sacl; 2183*5331Samw int i; 2184*5331Samw 2185*5331Samw *dacl = *sacl = NULL; 2186*5331Samw naccess = naudit = 0; 2187*5331Samw get_dacl = (which_acl & SMB_DACL_SECINFO); 2188*5331Samw get_sacl = (which_acl & SMB_SACL_SECINFO); 2189*5331Samw 2190*5331Samw for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) { 2191*5331Samw if (get_dacl && smb_ace_is_access(zace->a_type)) 2192*5331Samw naccess++; 2193*5331Samw else if (get_sacl && smb_ace_is_audit(zace->a_type)) 2194*5331Samw naudit++; 2195*5331Samw } 2196*5331Samw 2197*5331Samw if (naccess) { 2198*5331Samw *dacl = smb_fsop_aclalloc(naccess, zacl->acl_flags); 2199*5331Samw access_ace = (*dacl)->acl_aclp; 2200*5331Samw } 2201*5331Samw 2202*5331Samw if (naudit) { 2203*5331Samw *sacl = smb_fsop_aclalloc(naudit, zacl->acl_flags); 2204*5331Samw audit_ace = (*sacl)->acl_aclp; 2205*5331Samw } 2206*5331Samw 2207*5331Samw for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) { 2208*5331Samw if (get_dacl && smb_ace_is_access(zace->a_type)) { 2209*5331Samw *access_ace = *zace; 2210*5331Samw access_ace++; 2211*5331Samw } else if (get_sacl && smb_ace_is_audit(zace->a_type)) { 2212*5331Samw *audit_ace = *zace; 2213*5331Samw audit_ace++; 2214*5331Samw } 2215*5331Samw } 2216*5331Samw } 2217*5331Samw 2218*5331Samw acl_type_t 2219*5331Samw smb_fsop_acltype(smb_node_t *snode) 2220*5331Samw { 2221*5331Samw return (smb_vop_acl_type(snode->vp)); 2222*5331Samw } 2223*5331Samw 2224*5331Samw /* 2225*5331Samw * smb_fsop_sdread 2226*5331Samw * 2227*5331Samw * Read the requested security descriptor items from filesystem. 2228*5331Samw * The items are specified in fs_sd->sd_secinfo. 2229*5331Samw */ 2230*5331Samw int 2231*5331Samw smb_fsop_sdread(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 2232*5331Samw smb_fssd_t *fs_sd) 2233*5331Samw { 2234*5331Samw int error = 0; 2235*5331Samw int getowner = 0; 2236*5331Samw cred_t *ga_cred; 2237*5331Samw smb_attr_t attr; 2238*5331Samw 2239*5331Samw ASSERT(cr); 2240*5331Samw ASSERT(fs_sd); 2241*5331Samw 2242*5331Samw /* 2243*5331Samw * File's uid/gid is fetched in two cases: 2244*5331Samw * 2245*5331Samw * 1. it's explicitly requested 2246*5331Samw * 2247*5331Samw * 2. target ACL is ACE_T (ZFS ACL). They're needed for 2248*5331Samw * owner@/group@ entries. In this case kcred should be used 2249*5331Samw * because uid/gid are fetched on behalf of smb server. 2250*5331Samw */ 2251*5331Samw if (fs_sd->sd_secinfo & (SMB_OWNER_SECINFO | SMB_GROUP_SECINFO)) { 2252*5331Samw getowner = 1; 2253*5331Samw ga_cred = cr; 2254*5331Samw } else if (sr->tid_tree->t_acltype == ACE_T) { 2255*5331Samw getowner = 1; 2256*5331Samw ga_cred = kcred; 2257*5331Samw } 2258*5331Samw 2259*5331Samw if (getowner) { 2260*5331Samw /* 2261*5331Samw * Windows require READ_CONTROL to read owner/group SID since 2262*5331Samw * they're part of Security Descriptor. 2263*5331Samw * ZFS only requires read_attribute. Need to have a explicit 2264*5331Samw * access check here. 2265*5331Samw */ 2266*5331Samw if (sr->fid_ofile == NULL) { 2267*5331Samw error = smb_fsop_access(sr, ga_cred, snode, 2268*5331Samw READ_CONTROL); 2269*5331Samw if (error) 2270*5331Samw return (error); 2271*5331Samw } 2272*5331Samw 2273*5331Samw attr.sa_mask = SMB_AT_UID | SMB_AT_GID; 2274*5331Samw error = smb_fsop_getattr(sr, ga_cred, snode, &attr); 2275*5331Samw if (error == 0) { 2276*5331Samw fs_sd->sd_uid = attr.sa_vattr.va_uid; 2277*5331Samw fs_sd->sd_gid = attr.sa_vattr.va_gid; 2278*5331Samw } else { 2279*5331Samw return (error); 2280*5331Samw } 2281*5331Samw } 2282*5331Samw 2283*5331Samw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 2284*5331Samw error = smb_fsop_aclread(sr, cr, snode, fs_sd); 2285*5331Samw } 2286*5331Samw 2287*5331Samw return (error); 2288*5331Samw } 2289*5331Samw 2290*5331Samw /* 2291*5331Samw * smb_fsop_sdmerge 2292*5331Samw * 2293*5331Samw * From SMB point of view DACL and SACL are two separate list 2294*5331Samw * which can be manipulated independently without one affecting 2295*5331Samw * the other, but entries for both DACL and SACL will end up 2296*5331Samw * in the same ACL if target filesystem supports ACE_T ACLs. 2297*5331Samw * 2298*5331Samw * So, if either DACL or SACL is present in the client set request 2299*5331Samw * the entries corresponding to the non-present ACL shouldn't 2300*5331Samw * be touched in the FS ACL. 2301*5331Samw * 2302*5331Samw * fs_sd parameter contains DACL and SACL specified by SMB 2303*5331Samw * client to be set on a file/directory. The client could 2304*5331Samw * specify both or one of these ACLs (if none is specified 2305*5331Samw * we don't get this far). When both DACL and SACL are given 2306*5331Samw * by client the existing ACL should be overwritten. If only 2307*5331Samw * one of them is specified the entries corresponding to the other 2308*5331Samw * ACL should not be touched. For example, if only DACL 2309*5331Samw * is specified in input fs_sd, the function reads audit entries 2310*5331Samw * of the existing ACL of the file and point fs_sd->sd_zsdacl 2311*5331Samw * pointer to the fetched SACL, this way when smb_fsop_sdwrite() 2312*5331Samw * function is called the passed fs_sd would point to the specified 2313*5331Samw * DACL by client and fetched SACL from filesystem, so the file 2314*5331Samw * will end up with correct ACL. 2315*5331Samw */ 2316*5331Samw static int 2317*5331Samw smb_fsop_sdmerge(smb_request_t *sr, smb_node_t *snode, smb_fssd_t *fs_sd) 2318*5331Samw { 2319*5331Samw smb_fssd_t cur_sd; 2320*5331Samw int error = 0; 2321*5331Samw 2322*5331Samw if (sr->tid_tree->t_acltype != ACE_T) 2323*5331Samw /* Don't bother if target FS doesn't support ACE_T */ 2324*5331Samw return (0); 2325*5331Samw 2326*5331Samw if ((fs_sd->sd_secinfo & SMB_ACL_SECINFO) != SMB_ACL_SECINFO) { 2327*5331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) { 2328*5331Samw /* 2329*5331Samw * Don't overwrite existing audit entries 2330*5331Samw */ 2331*5331Samw smb_fsop_sdinit(&cur_sd, SMB_SACL_SECINFO, 2332*5331Samw fs_sd->sd_flags); 2333*5331Samw 2334*5331Samw error = smb_fsop_sdread(sr, kcred, snode, &cur_sd); 2335*5331Samw if (error == 0) { 2336*5331Samw ASSERT(fs_sd->sd_zsacl == NULL); 2337*5331Samw fs_sd->sd_zsacl = cur_sd.sd_zsacl; 2338*5331Samw if (fs_sd->sd_zsacl && fs_sd->sd_zdacl) 2339*5331Samw fs_sd->sd_zsacl->acl_flags = 2340*5331Samw fs_sd->sd_zdacl->acl_flags; 2341*5331Samw } 2342*5331Samw } else { 2343*5331Samw /* 2344*5331Samw * Don't overwrite existing access entries 2345*5331Samw */ 2346*5331Samw smb_fsop_sdinit(&cur_sd, SMB_DACL_SECINFO, 2347*5331Samw fs_sd->sd_flags); 2348*5331Samw 2349*5331Samw error = smb_fsop_sdread(sr, kcred, snode, &cur_sd); 2350*5331Samw if (error == 0) { 2351*5331Samw ASSERT(fs_sd->sd_zdacl == NULL); 2352*5331Samw fs_sd->sd_zdacl = cur_sd.sd_zdacl; 2353*5331Samw if (fs_sd->sd_zdacl && fs_sd->sd_zsacl) 2354*5331Samw fs_sd->sd_zdacl->acl_flags = 2355*5331Samw fs_sd->sd_zsacl->acl_flags; 2356*5331Samw } 2357*5331Samw } 2358*5331Samw 2359*5331Samw if (error) 2360*5331Samw smb_fsop_sdterm(&cur_sd); 2361*5331Samw } 2362*5331Samw 2363*5331Samw return (error); 2364*5331Samw } 2365*5331Samw 2366*5331Samw /* 2367*5331Samw * smb_fsop_sdwrite 2368*5331Samw * 2369*5331Samw * Stores the given uid, gid and acl in filesystem. 2370*5331Samw * Provided items in fs_sd are specified by fs_sd->sd_secinfo. 2371*5331Samw * 2372*5331Samw * A SMB security descriptor could contain owner, primary group, 2373*5331Samw * DACL and SACL. Setting an SD should be atomic but here it has to 2374*5331Samw * be done via two separate FS operations: VOP_SETATTR and 2375*5331Samw * VOP_SETSECATTR. Therefore, this function has to simulate the 2376*5331Samw * atomicity as well as it can. 2377*5331Samw */ 2378*5331Samw int 2379*5331Samw smb_fsop_sdwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 2380*5331Samw smb_fssd_t *fs_sd, int overwrite) 2381*5331Samw { 2382*5331Samw int error = 0; 2383*5331Samw int access = 0; 2384*5331Samw smb_attr_t set_attr; 2385*5331Samw smb_attr_t orig_attr; 2386*5331Samw 2387*5331Samw ASSERT(cr); 2388*5331Samw ASSERT(fs_sd); 2389*5331Samw 2390*5331Samw ASSERT(sr); 2391*5331Samw ASSERT(sr->tid_tree); 2392*5331Samw if (SMB_TREE_IS_READ_ONLY(sr)) 2393*5331Samw return (EROFS); 2394*5331Samw 2395*5331Samw bzero(&set_attr, sizeof (smb_attr_t)); 2396*5331Samw 2397*5331Samw if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 2398*5331Samw set_attr.sa_vattr.va_uid = fs_sd->sd_uid; 2399*5331Samw set_attr.sa_mask |= SMB_AT_UID; 2400*5331Samw } 2401*5331Samw 2402*5331Samw if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 2403*5331Samw set_attr.sa_vattr.va_gid = fs_sd->sd_gid; 2404*5331Samw set_attr.sa_mask |= SMB_AT_GID; 2405*5331Samw } 2406*5331Samw 2407*5331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 2408*5331Samw access |= WRITE_DAC; 2409*5331Samw 2410*5331Samw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 2411*5331Samw access |= ACCESS_SYSTEM_SECURITY; 2412*5331Samw 2413*5331Samw if (sr->fid_ofile) 2414*5331Samw error = smb_ofile_access(sr->fid_ofile, cr, access); 2415*5331Samw else 2416*5331Samw error = smb_fsop_access(sr, cr, snode, access); 2417*5331Samw 2418*5331Samw if (error) 2419*5331Samw return (EACCES); 2420*5331Samw 2421*5331Samw if (set_attr.sa_mask) { 2422*5331Samw /* 2423*5331Samw * Get the current uid, gid so if smb_fsop_aclwrite fails 2424*5331Samw * we can revert uid, gid changes. 2425*5331Samw * 2426*5331Samw * We use root cred here so the operation doesn't fail 2427*5331Samw * due to lack of permission for the user to read the attrs 2428*5331Samw */ 2429*5331Samw 2430*5331Samw orig_attr.sa_mask = SMB_AT_UID | SMB_AT_GID; 2431*5331Samw error = smb_fsop_getattr(sr, kcred, snode, &orig_attr); 2432*5331Samw if (error == 0) 2433*5331Samw error = smb_fsop_setattr(sr, cr, snode, &set_attr, 2434*5331Samw NULL); 2435*5331Samw 2436*5331Samw if (error) 2437*5331Samw return (error); 2438*5331Samw } 2439*5331Samw 2440*5331Samw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 2441*5331Samw if (overwrite == 0) { 2442*5331Samw error = smb_fsop_sdmerge(sr, snode, fs_sd); 2443*5331Samw if (error) 2444*5331Samw return (error); 2445*5331Samw } 2446*5331Samw 2447*5331Samw error = smb_fsop_aclwrite(sr, cr, snode, fs_sd); 2448*5331Samw if (error) { 2449*5331Samw /* 2450*5331Samw * Revert uid/gid changes if required. 2451*5331Samw */ 2452*5331Samw if (set_attr.sa_mask) { 2453*5331Samw orig_attr.sa_mask = set_attr.sa_mask; 2454*5331Samw (void) smb_fsop_setattr(sr, kcred, snode, 2455*5331Samw &orig_attr, NULL); 2456*5331Samw } 2457*5331Samw } 2458*5331Samw } 2459*5331Samw 2460*5331Samw return (error); 2461*5331Samw } 2462*5331Samw 2463*5331Samw /*ARGSUSED*/ 2464*5331Samw void 2465*5331Samw smb_get_caller_context(smb_request_t *sr, caller_context_t *ct) 2466*5331Samw { 2467*5331Samw ct->cc_caller_id = smb_caller_id; 2468*5331Samw ct->cc_pid = 0; /* TBD */ 2469*5331Samw ct->cc_sysid = 0; /* TBD */ 2470*5331Samw } 2471*5331Samw 2472*5331Samw /* 2473*5331Samw * smb_fsop_sdinherit 2474*5331Samw * 2475*5331Samw * Inherit the security descriptor from the parent container. 2476*5331Samw * This function is called after FS has created the file/folder 2477*5331Samw * so if this doesn't do anything it means FS inheritance is 2478*5331Samw * in place. 2479*5331Samw * 2480*5331Samw * Do inheritance for ZFS internally. 2481*5331Samw * 2482*5331Samw * If we want to let ZFS does the inheritance the 2483*5331Samw * following setting should be true: 2484*5331Samw * 2485*5331Samw * - aclinherit = passthrough 2486*5331Samw * - aclmode = passthrough 2487*5331Samw * - smbd umask = 0777 2488*5331Samw * 2489*5331Samw * This will result in right effective permissions but 2490*5331Samw * ZFS will always add 6 ACEs for owner, owning group 2491*5331Samw * and others to be POSIX compliant. This is not what 2492*5331Samw * Windows clients/users expect, so we decided that CIFS 2493*5331Samw * implements Windows rules and overwrite whatever ZFS 2494*5331Samw * comes up with. This way we also don't have to care 2495*5331Samw * about ZFS aclinherit and aclmode settings. 2496*5331Samw */ 2497*5331Samw static int 2498*5331Samw smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, smb_fssd_t *fs_sd) 2499*5331Samw { 2500*5331Samw int is_dir; 2501*5331Samw acl_t *dacl; 2502*5331Samw acl_t *sacl; 2503*5331Samw ksid_t *owner_sid; 2504*5331Samw int error; 2505*5331Samw 2506*5331Samw ASSERT(fs_sd); 2507*5331Samw 2508*5331Samw if (sr->tid_tree->t_acltype != ACE_T) { 2509*5331Samw /* 2510*5331Samw * No forced inheritance for non-ZFS filesystems. 2511*5331Samw */ 2512*5331Samw fs_sd->sd_secinfo = 0; 2513*5331Samw return (0); 2514*5331Samw } 2515*5331Samw 2516*5331Samw 2517*5331Samw /* Fetch parent directory's ACL */ 2518*5331Samw error = smb_fsop_sdread(sr, kcred, dnode, fs_sd); 2519*5331Samw if (error) { 2520*5331Samw return (error); 2521*5331Samw } 2522*5331Samw 2523*5331Samw is_dir = (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR); 2524*5331Samw owner_sid = crgetsid(sr->user_cr, KSID_OWNER); 2525*5331Samw ASSERT(owner_sid); 2526*5331Samw dacl = smb_acl_inherit(fs_sd->sd_zdacl, is_dir, SMB_DACL_SECINFO, 2527*5331Samw owner_sid->ks_id); 2528*5331Samw sacl = smb_acl_inherit(fs_sd->sd_zsacl, is_dir, SMB_SACL_SECINFO, 2529*5331Samw (uid_t)-1); 2530*5331Samw 2531*5331Samw smb_fsop_aclfree(fs_sd->sd_zdacl); 2532*5331Samw smb_fsop_aclfree(fs_sd->sd_zsacl); 2533*5331Samw 2534*5331Samw fs_sd->sd_zdacl = dacl; 2535*5331Samw fs_sd->sd_zsacl = sacl; 2536*5331Samw 2537*5331Samw return (0); 2538*5331Samw } 2539*5331Samw 2540*5331Samw /* 2541*5331Samw * smb_fsop_eaccess 2542*5331Samw * 2543*5331Samw * Returns the effective permission of the given credential for the 2544*5331Samw * specified object. 2545*5331Samw * 2546*5331Samw * This is just a workaround. We need VFS/FS support for this. 2547*5331Samw */ 2548*5331Samw void 2549*5331Samw smb_fsop_eaccess(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 2550*5331Samw uint32_t *eaccess) 2551*5331Samw { 2552*5331Samw int access = 0; 2553*5331Samw vnode_t *dir_vp; 2554*5331Samw smb_node_t *unnamed_node; 2555*5331Samw 2556*5331Samw ASSERT(cr); 2557*5331Samw ASSERT(snode); 2558*5331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 2559*5331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 2560*5331Samw 2561*5331Samw unnamed_node = SMB_IS_STREAM(snode); 2562*5331Samw if (unnamed_node) { 2563*5331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 2564*5331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 2565*5331Samw /* 2566*5331Samw * Streams authorization should be performed against the 2567*5331Samw * unnamed stream. 2568*5331Samw */ 2569*5331Samw snode = unnamed_node; 2570*5331Samw } 2571*5331Samw 2572*5331Samw if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS) { 2573*5331Samw dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL; 2574*5331Samw smb_vop_eaccess(snode->vp, (int *)eaccess, V_ACE_MASK, dir_vp, 2575*5331Samw cr); 2576*5331Samw return; 2577*5331Samw } 2578*5331Samw 2579*5331Samw /* 2580*5331Samw * FS doesn't understand 32-bit mask 2581*5331Samw */ 2582*5331Samw smb_vop_eaccess(snode->vp, &access, 0, NULL, cr); 2583*5331Samw 2584*5331Samw *eaccess = READ_CONTROL | FILE_READ_EA | FILE_READ_ATTRIBUTES; 2585*5331Samw 2586*5331Samw if (access & VREAD) 2587*5331Samw *eaccess |= FILE_READ_DATA; 2588*5331Samw 2589*5331Samw if (access & VEXEC) 2590*5331Samw *eaccess |= FILE_EXECUTE; 2591*5331Samw 2592*5331Samw if (access & VWRITE) 2593*5331Samw *eaccess |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | 2594*5331Samw FILE_WRITE_EA | FILE_APPEND_DATA | FILE_DELETE_CHILD; 2595*5331Samw } 2596