15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw /* 225772Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw #pragma ident "%Z%%M% %I% %E% SMI" 275331Samw 285331Samw #include <sys/sid.h> 295772Sas200622 #include <sys/nbmlock.h> 305331Samw #include <smbsrv/smb_fsops.h> 315521Sas200622 #include <smbsrv/smb_kproto.h> 325521Sas200622 #include <smbsrv/ntstatus.h> 335521Sas200622 #include <smbsrv/ntaccess.h> 345772Sas200622 #include <smbsrv/smb_incl.h> 355331Samw #include <acl/acl_common.h> 365772Sas200622 #include <sys/fcntl.h> 375772Sas200622 #include <sys/flock.h> 385772Sas200622 #include <fs/fs_subr.h> 395331Samw 40*6139Sjb150015 extern caller_context_t smb_ct; 41*6139Sjb150015 425331Samw static int smb_fsop_amask_to_omode(uint32_t granted_access); 435331Samw static int smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, 445331Samw smb_fssd_t *fs_sd); 455331Samw 465772Sas200622 static callb_cpr_t *smb_fsop_frlock_callback(flk_cb_when_t when, void *error); 475772Sas200622 485331Samw /* 495331Samw * The smb_fsop_* functions have knowledge of CIFS semantics. 505331Samw * 515331Samw * The smb_vop_* functions have minimal knowledge of CIFS semantics and 525331Samw * serve as an interface to the VFS layer. 535331Samw * 545331Samw * Hence, smb_request_t and smb_node_t structures should not be passed 555331Samw * from the smb_fsop_* layer to the smb_vop_* layer. 565331Samw * 575331Samw * In general, CIFS service code should only ever call smb_fsop_* 585331Samw * functions directly, and never smb_vop_* functions directly. 595331Samw * 605331Samw * smb_fsop_* functions should call smb_vop_* functions where possible, instead 615331Samw * of their smb_fsop_* counterparts. However, there are times when 625331Samw * this cannot be avoided. 635331Samw */ 645331Samw 655331Samw /* 665331Samw * Note: Stream names cannot be mangled. 675331Samw */ 685331Samw 695331Samw int 705331Samw smb_fsop_open(smb_ofile_t *of) 715331Samw { 725331Samw int mode; 735331Samw 745331Samw mode = smb_fsop_amask_to_omode(of->f_granted_access); 755331Samw 765331Samw /* 775331Samw * Assuming that same vnode is returned as we had before 785331Samw * (i.e. no special vnodes) 795331Samw */ 805772Sas200622 return (smb_vop_open(&of->f_node->vp, mode, of->f_cr)); 815331Samw } 825331Samw 835331Samw int 845331Samw smb_fsop_close(smb_ofile_t *of) 855331Samw { 865331Samw int mode; 875331Samw 885331Samw mode = smb_fsop_amask_to_omode(of->f_granted_access); 895331Samw 905772Sas200622 return (smb_vop_close(of->f_node->vp, mode, of->f_cr)); 915331Samw } 925331Samw 935331Samw static int 945331Samw smb_fsop_amask_to_omode(uint32_t granted_access) 955331Samw { 965331Samw int mode = 0; 975331Samw 985331Samw if (granted_access & (ACE_READ_DATA | ACE_EXECUTE)) 995331Samw mode |= FREAD; 1005331Samw 1015331Samw if (granted_access & (ACE_WRITE_DATA | ACE_APPEND_DATA)) 1025331Samw mode |= FWRITE; 1035331Samw 1045331Samw if (granted_access & ACE_APPEND_DATA) 1055331Samw mode |= FAPPEND; 1065331Samw 1075331Samw return (mode); 1085331Samw } 1095331Samw 1105331Samw static int 1115331Samw smb_fsop_create_with_sd( 112*6139Sjb150015 smb_request_t *sr, 1135331Samw cred_t *cr, 1145331Samw smb_node_t *snode, 1155331Samw char *name, 1165331Samw smb_attr_t *attr, 1175331Samw smb_node_t **ret_snode, 1185331Samw smb_attr_t *ret_attr, 1195331Samw smb_fssd_t *fs_sd) 1205331Samw { 1215331Samw vsecattr_t *vsap; 1225331Samw vsecattr_t vsecattr; 1235331Samw acl_t *acl, *dacl, *sacl; 1245331Samw smb_attr_t set_attr; 1255331Samw vnode_t *vp; 1265331Samw int aclbsize = 0; /* size of acl list in bytes */ 1275331Samw int flags = 0; 1285331Samw int is_dir; 1295331Samw int rc; 1305521Sas200622 boolean_t no_xvattr = B_FALSE; 1315331Samw 1325331Samw ASSERT(fs_sd); 1335331Samw 1345331Samw if (SMB_TREE_CASE_INSENSITIVE(sr)) 1355331Samw flags = SMB_IGNORE_CASE; 1365331Samw 1375331Samw ASSERT(cr); 1385331Samw 1395331Samw is_dir = ((fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR) != 0); 1405331Samw 1415331Samw if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACLONCREATE) { 1425331Samw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 1435331Samw dacl = fs_sd->sd_zdacl; 1445331Samw sacl = fs_sd->sd_zsacl; 1455331Samw ASSERT(dacl || sacl); 1465331Samw if (dacl && sacl) { 1475521Sas200622 acl = smb_fsacl_merge(dacl, sacl); 1485331Samw } else if (dacl) { 1495331Samw acl = dacl; 1505331Samw } else { 1515331Samw acl = sacl; 1525331Samw } 1535331Samw 1545521Sas200622 rc = smb_fsacl_to_vsa(acl, &vsecattr, &aclbsize); 1555331Samw 1565331Samw if (dacl && sacl) 1575331Samw acl_free(acl); 1585331Samw 1595331Samw if (rc) 1605331Samw return (rc); 1615331Samw 1625331Samw vsap = &vsecattr; 1635331Samw } 1645331Samw else 1655331Samw vsap = NULL; 1665331Samw 1675331Samw if (is_dir) { 1685331Samw rc = smb_vop_mkdir(snode->vp, name, attr, &vp, flags, 1695772Sas200622 cr, vsap); 1705331Samw } else { 1715331Samw rc = smb_vop_create(snode->vp, name, attr, &vp, flags, 1725772Sas200622 cr, vsap); 1735331Samw } 1745331Samw 1755331Samw if (vsap != NULL) 1765331Samw kmem_free(vsap->vsa_aclentp, aclbsize); 1775331Samw 1785331Samw if (rc != 0) 1795331Samw return (rc); 1805331Samw 1815331Samw set_attr.sa_mask = 0; 1825331Samw 1835331Samw /* 1845331Samw * Ideally we should be able to specify the owner and owning 1855331Samw * group at create time along with the ACL. Since we cannot 1865331Samw * do that right now, kcred is passed to smb_vop_setattr so it 1875331Samw * doesn't fail due to lack of permission. 1885331Samw */ 1895331Samw if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 1905331Samw set_attr.sa_vattr.va_uid = fs_sd->sd_uid; 1915331Samw set_attr.sa_mask |= SMB_AT_UID; 1925331Samw } 1935331Samw 1945331Samw if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 1955331Samw set_attr.sa_vattr.va_gid = fs_sd->sd_gid; 1965331Samw set_attr.sa_mask |= SMB_AT_GID; 1975331Samw } 1985331Samw 1995331Samw if (set_attr.sa_mask) { 2005521Sas200622 if (sr && sr->tid_tree) 2015521Sas200622 if (sr->tid_tree->t_flags & SMB_TREE_FLAG_UFS) 2025521Sas200622 no_xvattr = B_TRUE; 2035331Samw rc = smb_vop_setattr(snode->vp, NULL, &set_attr, 2045772Sas200622 0, kcred, no_xvattr); 2055331Samw } 2065331Samw 2075331Samw } else { 2085331Samw /* 2095331Samw * For filesystems that don't support ACL-on-create, try 2105331Samw * to set the specified SD after create, which could actually 2115331Samw * fail because of conflicts between inherited security 2125331Samw * attributes upon creation and the specified SD. 2135331Samw * 2145331Samw * Passing kcred to smb_fsop_sdwrite() to overcome this issue. 2155331Samw */ 2165331Samw 2175331Samw if (is_dir) { 2185331Samw rc = smb_vop_mkdir(snode->vp, name, attr, &vp, flags, 2195772Sas200622 cr, NULL); 2205331Samw } else { 2215331Samw rc = smb_vop_create(snode->vp, name, attr, &vp, flags, 2225772Sas200622 cr, NULL); 2235331Samw } 2245331Samw 2255521Sas200622 if (rc != 0) 2265521Sas200622 return (rc); 2275521Sas200622 2285521Sas200622 if ((sr->tid_tree->t_flags & SMB_TREE_FLAG_NFS_MOUNTED) == 0) 2295331Samw rc = smb_fsop_sdwrite(sr, kcred, snode, fs_sd, 1); 2305331Samw } 2315331Samw 2325331Samw if (rc == 0) { 2335331Samw *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp, name, 2345331Samw snode, NULL, ret_attr); 2355331Samw 2365331Samw if (*ret_snode == NULL) { 2375331Samw VN_RELE(vp); 2385331Samw rc = ENOMEM; 2395331Samw } 2405331Samw } 2415331Samw 2425521Sas200622 if (rc != 0) { 2435521Sas200622 if (is_dir) { 2445772Sas200622 (void) smb_vop_rmdir(snode->vp, name, flags, cr); 2455521Sas200622 } else { 2465772Sas200622 (void) smb_vop_remove(snode->vp, name, flags, cr); 2475521Sas200622 } 2485521Sas200622 } 2495521Sas200622 2505331Samw return (rc); 2515331Samw } 2525331Samw 2535331Samw 2545331Samw /* 2555331Samw * smb_fsop_create 2565331Samw * 2575331Samw * All SMB functions should use this wrapper to ensure that 2585331Samw * all the smb_vop_creates are performed with the appropriate credentials. 2595331Samw * Please document any direct calls to explain the reason 2605331Samw * for avoiding this wrapper. 2615331Samw * 2625331Samw * It is assumed that a reference exists on snode coming into this routine. 2635331Samw * 2645331Samw * *ret_snode is returned with a reference upon success. No reference is 2655331Samw * taken if an error is returned. 2665331Samw */ 2675331Samw 2685331Samw int 2695331Samw smb_fsop_create( 270*6139Sjb150015 smb_request_t *sr, 271*6139Sjb150015 cred_t *cr, 272*6139Sjb150015 smb_node_t *dir_snode, 273*6139Sjb150015 char *name, 274*6139Sjb150015 smb_attr_t *attr, 275*6139Sjb150015 smb_node_t **ret_snode, 276*6139Sjb150015 smb_attr_t *ret_attr) 2775331Samw { 2785331Samw struct open_param *op = &sr->arg.open; 279*6139Sjb150015 boolean_t no_xvattr = B_FALSE; 280*6139Sjb150015 smb_node_t *fnode; 281*6139Sjb150015 smb_attr_t file_attr; 282*6139Sjb150015 vnode_t *xattrdirvp; 283*6139Sjb150015 vnode_t *vp; 284*6139Sjb150015 char *longname = NULL; 285*6139Sjb150015 char *namep; 286*6139Sjb150015 char *fname; 287*6139Sjb150015 char *sname; 288*6139Sjb150015 int is_stream; 289*6139Sjb150015 int flags = 0; 290*6139Sjb150015 int rc = 0; 291*6139Sjb150015 smb_fssd_t fs_sd; 292*6139Sjb150015 uint32_t secinfo; 293*6139Sjb150015 uint32_t status; 2945331Samw 2955331Samw ASSERT(cr); 2965331Samw ASSERT(dir_snode); 2975331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 2985331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 2995331Samw 3005331Samw ASSERT(ret_snode); 3015331Samw *ret_snode = 0; 3025331Samw 3035331Samw ASSERT(name); 3045331Samw if (*name == 0) 3055331Samw return (EINVAL); 3065331Samw 3075331Samw if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0) 3085331Samw return (EACCES); 3095331Samw 3105331Samw ASSERT(sr); 3115331Samw ASSERT(sr->tid_tree); 3125331Samw if (SMB_TREE_IS_READ_ONLY(sr)) 3135331Samw return (EROFS); 3145331Samw 3155331Samw if (SMB_TREE_CASE_INSENSITIVE(sr)) 3165331Samw flags = SMB_IGNORE_CASE; 3175331Samw 3185331Samw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 3195331Samw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 3205331Samw 3215331Samw is_stream = smb_stream_parse_name(name, fname, sname); 3225331Samw 3235331Samw if (is_stream) 3245331Samw namep = fname; 3255331Samw else 3265331Samw namep = name; 3275331Samw 3285331Samw if (smb_maybe_mangled_name(namep)) { 3295331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 3305331Samw 3315331Samw rc = smb_unmangle_name(sr, cr, dir_snode, namep, longname, 3325331Samw MAXNAMELEN, NULL, NULL, 1); 3335331Samw 3345331Samw if ((is_stream == 0) && (rc == 0)) 3355331Samw rc = EEXIST; 3365331Samw 3375331Samw if ((is_stream && rc) || 3385331Samw ((is_stream == 0) && (rc != ENOENT))) { 3395331Samw kmem_free(longname, MAXNAMELEN); 3405331Samw kmem_free(fname, MAXNAMELEN); 3415331Samw kmem_free(sname, MAXNAMELEN); 3425331Samw return (rc); 3435331Samw } 3445331Samw 3455331Samw if (is_stream) 3465331Samw namep = longname; 3475331Samw else 3485331Samw kmem_free(longname, MAXNAMELEN); 3495331Samw } 3505331Samw 3515331Samw if (is_stream) { 3525331Samw /* 3535331Samw * Look up the unnamed stream. 3545331Samw * 3555331Samw * Mangle processing in smb_fsop_lookup() for the unnamed 3565331Samw * stream won't be needed (as it was done above), but 3575331Samw * it may be needed on any link target (which 3585331Samw * smb_fsop_lookup() will provide). 3595331Samw */ 3605331Samw rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, 3615331Samw sr->tid_tree->t_snode, dir_snode, namep, &fnode, &file_attr, 3625331Samw 0, 0); 3635331Samw 3645331Samw if (longname) { 3655331Samw kmem_free(longname, MAXNAMELEN); 3665331Samw namep = NULL; 3675331Samw } 3685331Samw 3695331Samw if (rc != 0) { 3705331Samw kmem_free(fname, MAXNAMELEN); 3715331Samw kmem_free(sname, MAXNAMELEN); 3725331Samw return (rc); 3735331Samw } 3745331Samw 3755331Samw rc = smb_vop_stream_create(fnode->vp, sname, attr, &vp, 3765772Sas200622 &xattrdirvp, flags, cr); 3775331Samw 3785331Samw if (rc != 0) { 3795331Samw smb_node_release(fnode); 3805331Samw kmem_free(fname, MAXNAMELEN); 3815331Samw kmem_free(sname, MAXNAMELEN); 3825331Samw return (rc); 3835331Samw } 3845331Samw 3856030Sjb150015 if (sr && sr->tid_tree) 3866030Sjb150015 if (sr->tid_tree->t_flags & SMB_TREE_FLAG_UFS) 3876030Sjb150015 no_xvattr = B_TRUE; 3886030Sjb150015 3896030Sjb150015 attr->sa_vattr.va_uid = file_attr.sa_vattr.va_uid; 3906030Sjb150015 attr->sa_vattr.va_gid = file_attr.sa_vattr.va_gid; 3916030Sjb150015 attr->sa_mask = SMB_AT_UID | SMB_AT_GID; 3926030Sjb150015 3936030Sjb150015 /* 3946030Sjb150015 * The second parameter of smb_vop_setattr() is set to 3956030Sjb150015 * NULL, even though an unnamed stream exists. This is 3966030Sjb150015 * because we want to set the UID and GID on the named 3976030Sjb150015 * stream in this case for consistency with the (unnamed 3986030Sjb150015 * stream) file (see comments for smb_vop_setattr()). 3996030Sjb150015 */ 4006030Sjb150015 4016030Sjb150015 rc = smb_vop_setattr(vp, NULL, attr, 0, kcred, no_xvattr); 4026030Sjb150015 4036030Sjb150015 if (rc != 0) { 4046030Sjb150015 smb_node_release(fnode); 4056030Sjb150015 kmem_free(fname, MAXNAMELEN); 4066030Sjb150015 kmem_free(sname, MAXNAMELEN); 4076030Sjb150015 return (rc); 4086030Sjb150015 } 4096030Sjb150015 4105331Samw *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, 4115331Samw vp, sname, ret_attr); 4125331Samw 4135331Samw smb_node_release(fnode); 4145331Samw 4155331Samw if (*ret_snode == NULL) { 4165331Samw VN_RELE(xattrdirvp); 4175331Samw VN_RELE(vp); 4185331Samw kmem_free(fname, MAXNAMELEN); 4195331Samw kmem_free(sname, MAXNAMELEN); 4205331Samw return (ENOMEM); 4215331Samw } 4225331Samw } else { 4235521Sas200622 if (op->sd) { 4245331Samw /* 4255331Samw * SD sent by client in Windows format. Needs to be 4265331Samw * converted to FS format. No inheritance. 4275331Samw */ 4285521Sas200622 secinfo = smb_sd_get_secinfo(op->sd); 4295521Sas200622 smb_fssd_init(&fs_sd, secinfo, 0); 4305521Sas200622 4315521Sas200622 status = smb_sd_tofs(op->sd, &fs_sd); 4325331Samw if (status == NT_STATUS_SUCCESS) { 4335331Samw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 4345331Samw name, attr, ret_snode, ret_attr, &fs_sd); 4355331Samw } 4365331Samw else 4375331Samw rc = EINVAL; 4385521Sas200622 smb_fssd_term(&fs_sd); 4395331Samw } else if (sr->tid_tree->t_acltype == ACE_T) { 4405331Samw /* 4415331Samw * No incoming SD and filesystem is ZFS 4425331Samw * Server applies Windows inheritance rules, 4435331Samw * see smb_fsop_sdinherit() comments as to why. 4445331Samw */ 4455521Sas200622 smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, 0); 4465331Samw rc = smb_fsop_sdinherit(sr, dir_snode, &fs_sd); 4475331Samw if (rc == 0) { 4485331Samw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 4495331Samw name, attr, ret_snode, ret_attr, &fs_sd); 4505331Samw } 4515331Samw 4525521Sas200622 smb_fssd_term(&fs_sd); 4535331Samw } else { 4545331Samw /* 4555331Samw * No incoming SD and filesystem is not ZFS 4565331Samw * let the filesystem handles the inheritance. 4575331Samw */ 4585331Samw rc = smb_vop_create(dir_snode->vp, name, attr, &vp, 4595772Sas200622 flags, cr, NULL); 4605331Samw 4615331Samw if (rc == 0) { 4625331Samw *ret_snode = smb_node_lookup(sr, op, cr, vp, 4635331Samw name, dir_snode, NULL, ret_attr); 4645331Samw 4655331Samw if (*ret_snode == NULL) { 4665331Samw VN_RELE(vp); 4675331Samw rc = ENOMEM; 4685331Samw } 4695331Samw } 4705331Samw 4715331Samw } 4725331Samw } 4735331Samw 4745331Samw kmem_free(fname, MAXNAMELEN); 4755331Samw kmem_free(sname, MAXNAMELEN); 4765331Samw return (rc); 4775331Samw } 4785331Samw 4795331Samw /* 4805331Samw * smb_fsop_mkdir 4815331Samw * 4825331Samw * All SMB functions should use this wrapper to ensure that 4835331Samw * the the calls are performed with the appropriate credentials. 4845331Samw * Please document any direct call to explain the reason 4855331Samw * for avoiding this wrapper. 4865331Samw * 4875331Samw * It is assumed that a reference exists on snode coming into this routine. 4885331Samw * 4895331Samw * *ret_snode is returned with a reference upon success. No reference is 4905331Samw * taken if an error is returned. 4915331Samw */ 4925331Samw int 4935331Samw smb_fsop_mkdir( 494*6139Sjb150015 smb_request_t *sr, 4955331Samw cred_t *cr, 4965331Samw smb_node_t *dir_snode, 4975331Samw char *name, 4985331Samw smb_attr_t *attr, 4995331Samw smb_node_t **ret_snode, 5005331Samw smb_attr_t *ret_attr) 5015331Samw { 5025331Samw struct open_param *op = &sr->arg.open; 5035331Samw char *longname; 5045331Samw vnode_t *vp; 5055331Samw int flags = 0; 5065331Samw smb_fssd_t fs_sd; 5075331Samw uint32_t secinfo; 5085331Samw uint32_t status; 5095331Samw int rc; 5105331Samw ASSERT(cr); 5115331Samw ASSERT(dir_snode); 5125331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 5135331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 5145331Samw 5155331Samw ASSERT(ret_snode); 5165331Samw *ret_snode = 0; 5175331Samw 5185331Samw ASSERT(name); 5195331Samw if (*name == 0) 5205331Samw return (EINVAL); 5215331Samw 5225331Samw if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0) 5235331Samw return (EACCES); 5245331Samw 5255331Samw ASSERT(sr); 5265331Samw ASSERT(sr->tid_tree); 5275331Samw if (SMB_TREE_IS_READ_ONLY(sr)) 5285331Samw return (EROFS); 5295331Samw 5305331Samw if (smb_maybe_mangled_name(name)) { 5315331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 5325331Samw rc = smb_unmangle_name(sr, cr, dir_snode, name, longname, 5335331Samw MAXNAMELEN, NULL, NULL, 1); 5345331Samw 5355331Samw kmem_free(longname, MAXNAMELEN); 5365331Samw 5375331Samw /* 5385331Samw * If the name passed in by the client has an unmangled 5395331Samw * equivalent that is found in the specified directory, 5405331Samw * then the mkdir cannot succeed. Return EEXIST. 5415331Samw * 5425331Samw * Only if ENOENT is returned will a mkdir be attempted. 5435331Samw */ 5445331Samw 5455331Samw if (rc == 0) 5465331Samw rc = EEXIST; 5475331Samw 5485331Samw if (rc != ENOENT) 5495331Samw return (rc); 5505331Samw } 5515331Samw 5525331Samw if (SMB_TREE_CASE_INSENSITIVE(sr)) 5535331Samw flags = SMB_IGNORE_CASE; 5545331Samw 5555521Sas200622 if (op->sd) { 5565331Samw /* 5575331Samw * SD sent by client in Windows format. Needs to be 5585331Samw * converted to FS format. No inheritance. 5595331Samw */ 5605521Sas200622 secinfo = smb_sd_get_secinfo(op->sd); 5615521Sas200622 smb_fssd_init(&fs_sd, secinfo, SMB_FSSD_FLAGS_DIR); 5625521Sas200622 5635521Sas200622 status = smb_sd_tofs(op->sd, &fs_sd); 5645331Samw if (status == NT_STATUS_SUCCESS) { 5655331Samw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 5665331Samw name, attr, ret_snode, ret_attr, &fs_sd); 5675331Samw } 5685331Samw else 5695331Samw rc = EINVAL; 5705521Sas200622 smb_fssd_term(&fs_sd); 5715331Samw } else if (sr->tid_tree->t_acltype == ACE_T) { 5725331Samw /* 5735331Samw * No incoming SD and filesystem is ZFS 5745331Samw * Server applies Windows inheritance rules, 5755331Samw * see smb_fsop_sdinherit() comments as to why. 5765331Samw */ 5775521Sas200622 smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, SMB_FSSD_FLAGS_DIR); 5785331Samw rc = smb_fsop_sdinherit(sr, dir_snode, &fs_sd); 5795331Samw if (rc == 0) { 5805331Samw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 5815331Samw name, attr, ret_snode, ret_attr, &fs_sd); 5825331Samw } 5835331Samw 5845521Sas200622 smb_fssd_term(&fs_sd); 5855331Samw 5865331Samw } else { 5875331Samw rc = smb_vop_mkdir(dir_snode->vp, name, attr, &vp, flags, cr, 5885772Sas200622 NULL); 5895331Samw 5905331Samw if (rc == 0) { 5915331Samw *ret_snode = smb_node_lookup(sr, op, cr, vp, name, 5925331Samw dir_snode, NULL, ret_attr); 5935331Samw 5945331Samw if (*ret_snode == NULL) { 5955331Samw VN_RELE(vp); 5965331Samw rc = ENOMEM; 5975331Samw } 5985331Samw } 5995331Samw } 6005331Samw 6015331Samw return (rc); 6025331Samw } 6035331Samw 6045331Samw /* 6055331Samw * smb_fsop_remove 6065331Samw * 6075331Samw * All SMB functions should use this wrapper to ensure that 6085331Samw * the the calls are performed with the appropriate credentials. 6095331Samw * Please document any direct call to explain the reason 6105331Samw * for avoiding this wrapper. 6115331Samw * 6125331Samw * It is assumed that a reference exists on snode coming into this routine. 6135331Samw * 6145331Samw * od: This means that the name passed in is an on-disk name. 6155331Samw * A null smb_request might be passed to this function. 6165331Samw */ 6175331Samw 6185331Samw int 6195331Samw smb_fsop_remove( 620*6139Sjb150015 smb_request_t *sr, 621*6139Sjb150015 cred_t *cr, 622*6139Sjb150015 smb_node_t *dir_snode, 623*6139Sjb150015 char *name, 624*6139Sjb150015 int od) 6255331Samw { 626*6139Sjb150015 smb_node_t *fnode; 627*6139Sjb150015 smb_attr_t file_attr; 628*6139Sjb150015 char *longname; 629*6139Sjb150015 char *fname; 630*6139Sjb150015 char *sname; 631*6139Sjb150015 int flags = 0; 632*6139Sjb150015 int rc; 6335331Samw 6345331Samw ASSERT(cr); 6355331Samw /* 6365331Samw * The state of the node could be SMB_NODE_STATE_DESTROYING if this 6375331Samw * function is called during the deletion of the node (because of 6385331Samw * DELETE_ON_CLOSE). 6395331Samw */ 6405331Samw ASSERT(dir_snode); 6415331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 6425331Samw 6435331Samw if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0) 6445331Samw return (EACCES); 6455331Samw 6465331Samw if (SMB_TREE_IS_READ_ONLY(sr)) 6475331Samw return (EROFS); 6485331Samw 6495331Samw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 6505331Samw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 6515331Samw 6525967Scp160787 /* 6535967Scp160787 * If the passed-in name is an on-disk name, 6545967Scp160787 * then we need to do a case-sensitive remove. 6555967Scp160787 * This is important if the on-disk name 6565967Scp160787 * corresponds to a mangled name passed in by 6575967Scp160787 * the client. We want to make sure to remove 6585967Scp160787 * the exact file specified by the client, 6595967Scp160787 * instead of letting the underlying file system 6605967Scp160787 * do a remove on the "first match." 6615967Scp160787 */ 6625967Scp160787 6635967Scp160787 if ((od == 0) && SMB_TREE_CASE_INSENSITIVE(sr)) 6645967Scp160787 flags = SMB_IGNORE_CASE; 6655967Scp160787 6665967Scp160787 if (dir_snode->flags & NODE_XATTR_DIR) { 6675967Scp160787 rc = smb_vop_stream_remove(dir_snode->dir_snode->vp, 6685967Scp160787 name, flags, cr); 6695967Scp160787 } else if (smb_stream_parse_name(name, fname, sname)) { 6705967Scp160787 /* 6715967Scp160787 * It is assumed that "name" corresponds to the path 6725967Scp160787 * passed in by the client, and no need of suppressing 6735967Scp160787 * case-insensitive lookups is needed. 6745967Scp160787 */ 6755331Samw 6765331Samw ASSERT(od == 0); 6775331Samw 6785331Samw /* 6795331Samw * Look up the unnamed stream (i.e. fname). 6805331Samw * Unmangle processing will be done on fname 6815331Samw * as well as any link target. 6825331Samw */ 6835331Samw 6845331Samw rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, 6855331Samw sr->tid_tree->t_snode, dir_snode, fname, &fnode, &file_attr, 6865331Samw 0, 0); 6875331Samw 6885331Samw if (rc != 0) { 6895331Samw kmem_free(fname, MAXNAMELEN); 6905331Samw kmem_free(sname, MAXNAMELEN); 6915331Samw return (rc); 6925331Samw } 6935331Samw 6945331Samw /* 6955331Samw * XXX 6965331Samw * Need to find out what permission is required by NTFS 6975331Samw * to remove a stream. 6985331Samw */ 6995772Sas200622 rc = smb_vop_stream_remove(fnode->vp, sname, flags, cr); 7005331Samw 7015331Samw smb_node_release(fnode); 7025331Samw } else { 7035772Sas200622 rc = smb_vop_remove(dir_snode->vp, name, flags, cr); 7045331Samw 7055331Samw if (rc == ENOENT) { 7065331Samw if (smb_maybe_mangled_name(name) == 0) { 7075331Samw kmem_free(fname, MAXNAMELEN); 7085331Samw kmem_free(sname, MAXNAMELEN); 7095331Samw return (rc); 7105331Samw } 7115331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 7125331Samw 7135331Samw rc = smb_unmangle_name(sr, cr, dir_snode, name, 7145331Samw longname, MAXNAMELEN, NULL, NULL, 1); 7155331Samw 7165331Samw if (rc == 0) { 7175331Samw /* 7185331Samw * We passed "1" as the "od" parameter 7195331Samw * to smb_unmangle_name(), such that longname 7205331Samw * is the real (case-sensitive) on-disk name. 7215331Samw * We make sure we do a remove on this exact 7225331Samw * name, as the name was mangled and denotes 7235331Samw * a unique file. 7245331Samw */ 7255331Samw flags &= ~SMB_IGNORE_CASE; 7265331Samw rc = smb_vop_remove(dir_snode->vp, longname, 7275772Sas200622 flags, cr); 7285331Samw } 7295331Samw 7305331Samw kmem_free(longname, MAXNAMELEN); 7315331Samw } 7325331Samw } 7335331Samw 7345331Samw kmem_free(fname, MAXNAMELEN); 7355331Samw kmem_free(sname, MAXNAMELEN); 7365331Samw return (rc); 7375331Samw } 7385331Samw 7395331Samw /* 7405331Samw * smb_fsop_remove_streams 7415331Samw * 7425331Samw * This function removes a file's streams without removing the 7435331Samw * file itself. 7445331Samw * 7455331Samw * It is assumed that snode is not a link. 7465331Samw */ 7475331Samw int 748*6139Sjb150015 smb_fsop_remove_streams(smb_request_t *sr, cred_t *cr, smb_node_t *fnode) 7495331Samw { 7505331Samw struct fs_stream_info stream_info; 7515331Samw uint32_t cookie = 0; 7525331Samw int flags = 0; 7535331Samw int rc; 7545331Samw 7555331Samw ASSERT(cr); 7565331Samw ASSERT(fnode); 7575331Samw ASSERT(fnode->n_magic == SMB_NODE_MAGIC); 7585331Samw ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING); 7595331Samw 7605331Samw if (SMB_TREE_ROOT_FS(sr, fnode) == 0) 7615331Samw return (EACCES); 7625331Samw 7635331Samw if (SMB_TREE_IS_READ_ONLY(sr)) 7645331Samw return (EROFS); 7655331Samw 7665331Samw if (SMB_TREE_CASE_INSENSITIVE(sr)) 7675331Samw flags = SMB_IGNORE_CASE; 7685331Samw 7695331Samw for (;;) { 7705331Samw rc = smb_vop_stream_readdir(fnode->vp, &cookie, &stream_info, 7715772Sas200622 NULL, NULL, flags, cr); 7725331Samw 7735331Samw if ((rc != 0) || (cookie == SMB_EOF)) 7745331Samw break; 7755331Samw 7765331Samw (void) smb_vop_stream_remove(fnode->vp, stream_info.name, flags, 7775772Sas200622 cr); 7785331Samw } 7795331Samw return (rc); 7805331Samw } 7815331Samw 7825331Samw /* 7835331Samw * smb_fsop_rmdir 7845331Samw * 7855331Samw * All SMB functions should use this wrapper to ensure that 7865331Samw * the the calls are performed with the appropriate credentials. 7875331Samw * Please document any direct call to explain the reason 7885331Samw * for avoiding this wrapper. 7895331Samw * 7905331Samw * It is assumed that a reference exists on snode coming into this routine. 7915331Samw * 7925331Samw * od: This means that the name passed in is an on-disk name. 7935331Samw */ 7945331Samw 7955331Samw int 7965331Samw smb_fsop_rmdir( 797*6139Sjb150015 smb_request_t *sr, 798*6139Sjb150015 cred_t *cr, 799*6139Sjb150015 smb_node_t *dir_snode, 800*6139Sjb150015 char *name, 801*6139Sjb150015 int od) 8025331Samw { 803*6139Sjb150015 int rc; 804*6139Sjb150015 int flags = 0; 805*6139Sjb150015 char *longname; 8065331Samw 8075331Samw ASSERT(cr); 8085331Samw /* 8095331Samw * The state of the node could be SMB_NODE_STATE_DESTROYING if this 8105331Samw * function is called during the deletion of the node (because of 8115331Samw * DELETE_ON_CLOSE). 8125331Samw */ 8135331Samw ASSERT(dir_snode); 8145331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 8155331Samw 8165331Samw if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0) 8175331Samw return (EACCES); 8185331Samw 8195331Samw if (SMB_TREE_IS_READ_ONLY(sr)) 8205331Samw return (EROFS); 8215331Samw 8225331Samw /* 8235331Samw * If the passed-in name is an on-disk name, 8245331Samw * then we need to do a case-sensitive rmdir. 8255331Samw * This is important if the on-disk name 8265331Samw * corresponds to a mangled name passed in by 8275331Samw * the client. We want to make sure to remove 8285331Samw * the exact directory specified by the client, 8295331Samw * instead of letting the underlying file system 8305331Samw * do a rmdir on the "first match." 8315331Samw */ 8325331Samw 8335331Samw if ((od == 0) && SMB_TREE_CASE_INSENSITIVE(sr)) 8345331Samw flags = SMB_IGNORE_CASE; 8355331Samw 8365772Sas200622 rc = smb_vop_rmdir(dir_snode->vp, name, flags, cr); 8375331Samw 8385331Samw if (rc == ENOENT) { 8395331Samw if (smb_maybe_mangled_name(name) == 0) 8405331Samw return (rc); 8415331Samw 8425331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 8435331Samw 8445331Samw rc = smb_unmangle_name(sr, cr, dir_snode, 8455331Samw name, longname, MAXNAMELEN, NULL, 8465331Samw NULL, 1); 8475331Samw 8485331Samw if (rc == 0) { 8495331Samw /* 8505331Samw * We passed "1" as the "od" parameter 8515331Samw * to smb_unmangle_name(), such that longname 8525331Samw * is the real (case-sensitive) on-disk name. 8535331Samw * We make sure we do a rmdir on this exact 8545331Samw * name, as the name was mangled and denotes 8555331Samw * a unique directory. 8565331Samw */ 8575331Samw flags &= ~SMB_IGNORE_CASE; 8585772Sas200622 rc = smb_vop_rmdir(dir_snode->vp, longname, flags, cr); 8595331Samw } 8605331Samw 8615331Samw kmem_free(longname, MAXNAMELEN); 8625331Samw } 8635331Samw 8645331Samw return (rc); 8655331Samw } 8665331Samw 8675331Samw /* 8685331Samw * smb_fsop_getattr 8695331Samw * 8705331Samw * All SMB functions should use this wrapper to ensure that 8715331Samw * the the calls are performed with the appropriate credentials. 8725331Samw * Please document any direct call to explain the reason 8735331Samw * for avoiding this wrapper. 8745331Samw * 8755331Samw * It is assumed that a reference exists on snode coming into this routine. 8765331Samw */ 8775331Samw int 878*6139Sjb150015 smb_fsop_getattr(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 8795331Samw smb_attr_t *attr) 8805331Samw { 8815331Samw smb_node_t *unnamed_node; 8825331Samw vnode_t *unnamed_vp = NULL; 8835331Samw uint32_t status; 8845331Samw uint32_t access = 0; 8855331Samw int flags = 0; 8865772Sas200622 int rc; 8875331Samw 8885331Samw ASSERT(cr); 8895331Samw ASSERT(snode); 8905331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 8915331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 8925331Samw 8935331Samw if (SMB_TREE_ROOT_FS(sr, snode) == 0) 8945331Samw return (EACCES); 8955331Samw 8965331Samw if (sr->fid_ofile) { 8975331Samw /* if uid and/or gid is requested */ 8985331Samw if (attr->sa_mask & (SMB_AT_UID|SMB_AT_GID)) 8995331Samw access |= READ_CONTROL; 9005331Samw 9015331Samw /* if anything else is also requested */ 9025331Samw if (attr->sa_mask & ~(SMB_AT_UID|SMB_AT_GID)) 9035331Samw access |= FILE_READ_ATTRIBUTES; 9045331Samw 9055331Samw status = smb_ofile_access(sr->fid_ofile, cr, access); 9065331Samw if (status != NT_STATUS_SUCCESS) 9075331Samw return (EACCES); 9085331Samw 9095331Samw if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS) 9105331Samw flags = ATTR_NOACLCHECK; 9115331Samw } 9125331Samw 9135331Samw unnamed_node = SMB_IS_STREAM(snode); 9145331Samw 9155331Samw if (unnamed_node) { 9165331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 9175331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 9185331Samw unnamed_vp = unnamed_node->vp; 9195331Samw } 9205331Samw 9215772Sas200622 rc = smb_vop_getattr(snode->vp, unnamed_vp, attr, flags, cr); 9225772Sas200622 if (rc == 0) 9235772Sas200622 snode->attr = *attr; 9245772Sas200622 9255772Sas200622 return (rc); 9265331Samw } 9275331Samw 9285331Samw /* 9295331Samw * smb_fsop_readdir 9305331Samw * 9315331Samw * All SMB functions should use this smb_fsop_readdir wrapper to ensure that 9325331Samw * the smb_vop_readdir is performed with the appropriate credentials. 9335331Samw * Please document any direct call to smb_vop_readdir to explain the reason 9345331Samw * for avoiding this wrapper. 9355331Samw * 9365331Samw * It is assumed that a reference exists on snode coming into this routine. 9375331Samw */ 9385331Samw int 9395331Samw smb_fsop_readdir( 940*6139Sjb150015 smb_request_t *sr, 9415331Samw cred_t *cr, 9425331Samw smb_node_t *dir_snode, 9435331Samw uint32_t *cookie, 9445331Samw char *name, 9455331Samw int *namelen, 9465331Samw ino64_t *fileid, 9475331Samw struct fs_stream_info *stream_info, 9485331Samw smb_node_t **ret_snode, 9495331Samw smb_attr_t *ret_attr) 9505331Samw { 951*6139Sjb150015 smb_node_t *ret_snodep; 952*6139Sjb150015 smb_node_t *fnode; 953*6139Sjb150015 smb_attr_t tmp_attr; 954*6139Sjb150015 vnode_t *xattrdirvp; 955*6139Sjb150015 vnode_t *fvp; 956*6139Sjb150015 vnode_t *vp = NULL; 957*6139Sjb150015 char *od_name; 958*6139Sjb150015 int rc; 959*6139Sjb150015 int flags = 0; 9605331Samw 9615331Samw ASSERT(cr); 9625331Samw ASSERT(dir_snode); 9635331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 9645331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 9655331Samw 9665331Samw if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0) 9675331Samw return (EACCES); 9685331Samw 9695331Samw if (*cookie == SMB_EOF) { 9705331Samw *namelen = 0; 9715331Samw return (0); 9725331Samw } 9735331Samw 9745331Samw if (SMB_TREE_CASE_INSENSITIVE(sr)) 9755331Samw flags = SMB_IGNORE_CASE; 9765331Samw 9775331Samw od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 9785331Samw 9795331Samw if (stream_info) { 9805331Samw rc = smb_vop_lookup(dir_snode->vp, name, &fvp, od_name, 9815772Sas200622 SMB_FOLLOW_LINKS, sr->tid_tree->t_snode->vp, cr); 9825331Samw 9835331Samw if (rc != 0) { 9845331Samw kmem_free(od_name, MAXNAMELEN); 9855331Samw return (rc); 9865331Samw } 9875331Samw 9885331Samw fnode = smb_node_lookup(sr, NULL, cr, fvp, od_name, dir_snode, 9895331Samw NULL, ret_attr); 9905331Samw 9915331Samw kmem_free(od_name, MAXNAMELEN); 9925331Samw 9935331Samw if (fnode == NULL) { 9945331Samw VN_RELE(fvp); 9955331Samw return (ENOMEM); 9965331Samw } 9975331Samw 9985331Samw /* 9995331Samw * XXX 10005331Samw * Need to find out what permission(s) NTFS requires for getting 10015331Samw * a file's streams list. 10025331Samw * 10035331Samw * Might have to use kcred. 10045331Samw */ 10055331Samw rc = smb_vop_stream_readdir(fvp, cookie, stream_info, &vp, 10065772Sas200622 &xattrdirvp, flags, cr); 10075331Samw 10085331Samw if ((rc != 0) || (*cookie == SMB_EOF)) { 10095331Samw smb_node_release(fnode); 10105331Samw return (rc); 10115331Samw } 10125331Samw 10135331Samw ret_snodep = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, 10145331Samw vp, stream_info->name, &tmp_attr); 10155331Samw 10165331Samw smb_node_release(fnode); 10175331Samw 10185331Samw if (ret_snodep == NULL) { 10195331Samw VN_RELE(xattrdirvp); 10205331Samw VN_RELE(vp); 10215331Samw return (ENOMEM); 10225331Samw } 10235331Samw 10245331Samw stream_info->size = tmp_attr.sa_vattr.va_size; 10255331Samw 10265331Samw if (ret_attr) 10275331Samw *ret_attr = tmp_attr; 10285331Samw 10295331Samw if (ret_snode) 10305331Samw *ret_snode = ret_snodep; 10315331Samw else 10325331Samw smb_node_release(ret_snodep); 10335331Samw 10345331Samw } else { 10355331Samw rc = smb_vop_readdir(dir_snode->vp, cookie, name, namelen, 10365772Sas200622 fileid, &vp, od_name, flags, cr); 10375331Samw 10385331Samw if (rc != 0) { 10395331Samw kmem_free(od_name, MAXNAMELEN); 10405331Samw return (rc); 10415331Samw } 10425331Samw 10435331Samw if (*namelen) { 10445331Samw ASSERT(vp); 10455331Samw if (ret_attr || ret_snode) { 10465331Samw ret_snodep = smb_node_lookup(sr, NULL, cr, vp, 10475331Samw od_name, dir_snode, NULL, &tmp_attr); 10485331Samw 10495331Samw if (ret_snodep == NULL) { 10505331Samw kmem_free(od_name, MAXNAMELEN); 10515331Samw VN_RELE(vp); 10525331Samw return (ENOMEM); 10535331Samw } 10545331Samw 10555331Samw if (ret_attr) 10565331Samw *ret_attr = tmp_attr; 10575331Samw 10585331Samw if (ret_snode) 10595331Samw *ret_snode = ret_snodep; 10605331Samw else 10615331Samw smb_node_release(ret_snodep); 10625331Samw } 10635331Samw } 10645331Samw 10655331Samw kmem_free(od_name, MAXNAMELEN); 10665331Samw } 10675331Samw 10685331Samw return (rc); 10695331Samw } 10705331Samw 10715331Samw /* 10725331Samw * smb_fsop_getdents 10735331Samw * 10745331Samw * All SMB functions should use this smb_vop_getdents wrapper to ensure that 10755331Samw * the smb_vop_getdents is performed with the appropriate credentials. 10765331Samw * Please document any direct call to smb_vop_getdents to explain the reason 10775331Samw * for avoiding this wrapper. 10785331Samw * 10795331Samw * It is assumed that a reference exists on snode coming into this routine. 10805331Samw */ 10815331Samw /*ARGSUSED*/ 10825331Samw int 10835331Samw smb_fsop_getdents( 10845331Samw struct smb_request *sr, 10855331Samw cred_t *cr, 10865331Samw smb_node_t *dir_snode, 10875331Samw uint32_t *cookie, 10885331Samw uint64_t *verifierp, 10895331Samw int32_t *maxcnt, 10905331Samw char *args, 10915331Samw char *pattern) 10925331Samw { 10935331Samw int flags = 0; 10945331Samw 10955331Samw ASSERT(cr); 10965331Samw ASSERT(dir_snode); 10975331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 10985331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 10995331Samw 11005331Samw if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0) 11015331Samw return (EACCES); 11025331Samw 11035331Samw if (SMB_TREE_CASE_INSENSITIVE(sr)) 11045331Samw flags = SMB_IGNORE_CASE; 11055331Samw 11065331Samw return (smb_vop_getdents(dir_snode, cookie, 0, maxcnt, args, pattern, 11075772Sas200622 flags, sr, cr)); 11085331Samw } 11095331Samw 11105331Samw /* 11115331Samw * smb_fsop_rename 11125331Samw * 11135331Samw * All SMB functions should use this smb_vop_rename wrapper to ensure that 11145331Samw * the smb_vop_rename is performed with the appropriate credentials. 11155331Samw * Please document any direct call to smb_vop_rename to explain the reason 11165331Samw * for avoiding this wrapper. 11175331Samw * 11185331Samw * It is assumed that references exist on from_dir_snode and to_dir_snode coming 11195331Samw * into this routine. 11205331Samw */ 11215331Samw int 11225331Samw smb_fsop_rename( 1123*6139Sjb150015 smb_request_t *sr, 11245331Samw cred_t *cr, 11255331Samw smb_node_t *from_dir_snode, 11265331Samw char *from_name, 11275331Samw smb_node_t *to_dir_snode, 11285331Samw char *to_name) 11295331Samw { 11305331Samw smb_node_t *from_snode; 11315331Samw smb_attr_t tmp_attr; 11325331Samw vnode_t *from_vp; 11335331Samw int flags = 0; 11345331Samw int rc; 11355331Samw 11365331Samw ASSERT(cr); 11375331Samw ASSERT(from_dir_snode); 11385331Samw ASSERT(from_dir_snode->n_magic == SMB_NODE_MAGIC); 11395331Samw ASSERT(from_dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 11405331Samw 11415331Samw ASSERT(to_dir_snode); 11425331Samw ASSERT(to_dir_snode->n_magic == SMB_NODE_MAGIC); 11435331Samw ASSERT(to_dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 11445331Samw 11455331Samw if (SMB_TREE_ROOT_FS(sr, from_dir_snode) == 0) 11465331Samw return (EACCES); 11475331Samw 11485331Samw if (SMB_TREE_ROOT_FS(sr, to_dir_snode) == 0) 11495331Samw return (EACCES); 11505331Samw 11515331Samw ASSERT(sr); 11525331Samw ASSERT(sr->tid_tree); 11535331Samw if (SMB_TREE_IS_READ_ONLY(sr)) 11545331Samw return (EROFS); 11555331Samw 11565331Samw /* 11575331Samw * Note: There is no need to check SMB_TREE_CASE_INSENSITIVE(sr) 11585331Samw * here. 11595331Samw * 11605331Samw * A case-sensitive rename is always done in this routine 11615331Samw * because we are using the on-disk name from an earlier lookup. 11625331Samw * If a mangled name was passed in by the caller (denoting a 11635331Samw * deterministic lookup), then the exact file must be renamed 11645331Samw * (i.e. SMB_IGNORE_CASE must not be passed to VOP_RENAME, or 11655331Samw * else the underlying file system might return a "first-match" 11665331Samw * on this on-disk name, possibly resulting in the wrong file). 11675331Samw */ 11685331Samw 11695331Samw /* 11705331Samw * XXX: Lock required through smb_node_release() below? 11715331Samw */ 11725331Samw 11735331Samw rc = smb_vop_lookup(from_dir_snode->vp, from_name, &from_vp, NULL, 0, 11745772Sas200622 NULL, cr); 11755331Samw 11765331Samw if (rc != 0) 11775331Samw return (rc); 11785331Samw 11795331Samw rc = smb_vop_rename(from_dir_snode->vp, from_name, to_dir_snode->vp, 11805772Sas200622 to_name, flags, cr); 11815331Samw 11825331Samw if (rc == 0) { 11835331Samw from_snode = smb_node_lookup(sr, NULL, cr, from_vp, from_name, 11845331Samw from_dir_snode, NULL, &tmp_attr); 11855331Samw 11865331Samw if (from_snode == NULL) { 11875331Samw VN_RELE(from_vp); 11885331Samw return (ENOMEM); 11895331Samw } 11905331Samw 11915331Samw (void) smb_node_rename(from_dir_snode, from_snode, to_dir_snode, 11925331Samw to_name); 11935331Samw 11945331Samw smb_node_release(from_snode); 11955331Samw } else { 11965331Samw VN_RELE(from_vp); 11975331Samw } 11985331Samw 11995331Samw /* XXX: unlock */ 12005331Samw 12015331Samw return (rc); 12025331Samw } 12035331Samw 12045331Samw /* 12055331Samw * smb_fsop_setattr 12065331Samw * 12075331Samw * All SMB functions should use this wrapper to ensure that 12085331Samw * the the calls are performed with the appropriate credentials. 12095331Samw * Please document any direct call to explain the reason 12105331Samw * for avoiding this wrapper. 12115331Samw * 12125331Samw * It is assumed that a reference exists on snode coming into this routine. 12135331Samw * A null smb_request might be passed to this function. 12145331Samw */ 12155331Samw int 12165331Samw smb_fsop_setattr( 1217*6139Sjb150015 smb_request_t *sr, 1218*6139Sjb150015 cred_t *cr, 1219*6139Sjb150015 smb_node_t *snode, 1220*6139Sjb150015 smb_attr_t *set_attr, 1221*6139Sjb150015 smb_attr_t *ret_attr) 12225331Samw { 12235331Samw smb_node_t *unnamed_node; 12245331Samw vnode_t *unnamed_vp = NULL; 12255331Samw uint32_t status; 12265331Samw uint32_t access = 0; 12275331Samw int rc = 0; 12285331Samw int flags = 0; 12295521Sas200622 boolean_t no_xvattr = B_FALSE; 12305331Samw 12315331Samw ASSERT(cr); 12325331Samw ASSERT(snode); 12335331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 12345331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 12355331Samw 12365331Samw if (SMB_TREE_ROOT_FS(sr, snode) == 0) 12375331Samw return (EACCES); 12385331Samw 12395331Samw if (SMB_TREE_IS_READ_ONLY(sr)) 12405331Samw return (EROFS); 12415331Samw 12425331Samw /* sr could be NULL in some cases */ 12435331Samw if (sr && sr->fid_ofile) { 12445331Samw /* if uid and/or gid is requested */ 12455331Samw if (set_attr->sa_mask & (SMB_AT_UID|SMB_AT_GID)) 12465331Samw access |= WRITE_OWNER; 12475331Samw 12485331Samw /* if anything else is also requested */ 12495331Samw if (set_attr->sa_mask & ~(SMB_AT_UID|SMB_AT_GID)) 12505331Samw access |= FILE_WRITE_ATTRIBUTES; 12515331Samw 12525331Samw status = smb_ofile_access(sr->fid_ofile, cr, access); 12535331Samw if (status != NT_STATUS_SUCCESS) 12545331Samw return (EACCES); 12555331Samw 12565331Samw if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS) 12575331Samw flags = ATTR_NOACLCHECK; 12585331Samw } 12595331Samw 12605331Samw unnamed_node = SMB_IS_STREAM(snode); 12615331Samw 12625331Samw if (unnamed_node) { 12635331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 12645331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 12655331Samw unnamed_vp = unnamed_node->vp; 12665331Samw } 12675521Sas200622 if (sr && sr->tid_tree) 12685521Sas200622 if (sr->tid_tree->t_flags & SMB_TREE_FLAG_UFS) 12695521Sas200622 no_xvattr = B_TRUE; 12705521Sas200622 12715772Sas200622 rc = smb_vop_setattr(snode->vp, unnamed_vp, set_attr, flags, cr, 12725772Sas200622 no_xvattr); 12735331Samw 12745331Samw if ((rc == 0) && ret_attr) { 12755331Samw /* 12765772Sas200622 * Use kcred to update the node attr because this 12775772Sas200622 * call is not being made on behalf of the user. 12785331Samw */ 12795331Samw ret_attr->sa_mask = SMB_AT_ALL; 12805772Sas200622 rc = smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0, kcred); 12815772Sas200622 if (rc == 0) 12825772Sas200622 snode->attr = *ret_attr; 12835331Samw } 12845331Samw 12855331Samw return (rc); 12865331Samw } 12875331Samw 12885331Samw /* 12895331Samw * smb_fsop_read 12905331Samw * 12915331Samw * All SMB functions should use this wrapper to ensure that 12925331Samw * the the calls are performed with the appropriate credentials. 12935331Samw * Please document any direct call to explain the reason 12945331Samw * for avoiding this wrapper. 12955331Samw * 12965331Samw * It is assumed that a reference exists on snode coming into this routine. 12975331Samw */ 12985331Samw int 12995331Samw smb_fsop_read( 13005331Samw struct smb_request *sr, 13015331Samw cred_t *cr, 13025331Samw smb_node_t *snode, 13035331Samw uio_t *uio, 13045331Samw smb_attr_t *ret_attr) 13055331Samw { 13065331Samw smb_node_t *unnamed_node; 13075331Samw vnode_t *unnamed_vp = NULL; 13085772Sas200622 int svmand; 13095331Samw int rc; 13105331Samw 13115331Samw ASSERT(cr); 13125331Samw ASSERT(snode); 13135331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 13145331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 13155331Samw 13165331Samw ASSERT(sr); 13175331Samw ASSERT(sr->fid_ofile); 13185331Samw 13195331Samw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_READ_DATA); 13205331Samw if (rc != NT_STATUS_SUCCESS) { 13215331Samw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_EXECUTE); 13225331Samw if (rc != NT_STATUS_SUCCESS) 13235331Samw return (EACCES); 13245331Samw } 13255331Samw 13265331Samw unnamed_node = SMB_IS_STREAM(snode); 13275331Samw if (unnamed_node) { 13285331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 13295331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 13305331Samw unnamed_vp = unnamed_node->vp; 13315331Samw /* 13325331Samw * Streams permission are checked against the unnamed stream, 13335331Samw * but in FS level they have their own permissions. To avoid 13345331Samw * rejection by FS due to lack of permission on the actual 13355331Samw * extended attr kcred is passed for streams. 13365331Samw */ 13375331Samw cr = kcred; 13385331Samw } 13395331Samw 13405772Sas200622 smb_node_start_crit(snode, RW_READER); 13415772Sas200622 rc = nbl_svmand(snode->vp, cr, &svmand); 13425772Sas200622 if (rc) { 13435772Sas200622 smb_node_end_crit(snode); 13445772Sas200622 return (rc); 13455772Sas200622 } 13465772Sas200622 13475772Sas200622 rc = nbl_lock_conflict(snode->vp, NBL_READ, uio->uio_loffset, 13485772Sas200622 uio->uio_iov->iov_len, svmand, &smb_ct); 13495772Sas200622 13505772Sas200622 if (rc) { 13515772Sas200622 smb_node_end_crit(snode); 13525772Sas200622 return (rc); 13535772Sas200622 } 13545772Sas200622 rc = smb_vop_read(snode->vp, uio, cr); 13555772Sas200622 13565772Sas200622 if (rc == 0 && ret_attr) { 13575331Samw /* 13585772Sas200622 * Use kcred to update the node attr because this 13595772Sas200622 * call is not being made on behalf of the user. 13605331Samw */ 13615331Samw ret_attr->sa_mask = SMB_AT_ALL; 13625772Sas200622 if (smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0, 13635772Sas200622 kcred) == 0) { 13645772Sas200622 snode->attr = *ret_attr; 13655772Sas200622 } 13665331Samw } 13675331Samw 13685772Sas200622 smb_node_end_crit(snode); 13695772Sas200622 13705331Samw return (rc); 13715331Samw } 13725331Samw 13735331Samw /* 13745331Samw * smb_fsop_write 13755331Samw * 13765331Samw * This is a wrapper function used for smb_write and smb_write_raw operations. 13775331Samw * 13785331Samw * It is assumed that a reference exists on snode coming into this routine. 13795331Samw */ 13805331Samw int 13815331Samw smb_fsop_write( 1382*6139Sjb150015 smb_request_t *sr, 13835331Samw cred_t *cr, 13845331Samw smb_node_t *snode, 13855331Samw uio_t *uio, 13865331Samw uint32_t *lcount, 13875331Samw smb_attr_t *ret_attr, 13885331Samw uint32_t *flag) 13895331Samw { 13905331Samw smb_node_t *unnamed_node; 13915331Samw vnode_t *unnamed_vp = NULL; 13925772Sas200622 int svmand; 13935331Samw int rc; 13945331Samw 13955331Samw ASSERT(cr); 13965331Samw ASSERT(snode); 13975331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 13985331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 13995331Samw 14005331Samw ASSERT(sr); 14015331Samw ASSERT(sr->tid_tree); 14025331Samw ASSERT(sr->fid_ofile); 14035331Samw 14045331Samw if (SMB_TREE_IS_READ_ONLY(sr)) 14055331Samw return (EROFS); 14065772Sas200622 14075331Samw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_WRITE_DATA); 14085772Sas200622 if (rc != NT_STATUS_SUCCESS) { 14095772Sas200622 rc = smb_ofile_access(sr->fid_ofile, cr, FILE_APPEND_DATA); 14105772Sas200622 if (rc != NT_STATUS_SUCCESS) 14115772Sas200622 return (EACCES); 14125772Sas200622 } 14135331Samw 14145331Samw unnamed_node = SMB_IS_STREAM(snode); 14155331Samw 14165331Samw if (unnamed_node) { 14175331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 14185331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 14195331Samw unnamed_vp = unnamed_node->vp; 14205331Samw /* 14215331Samw * Streams permission are checked against the unnamed stream, 14225331Samw * but in FS level they have their own permissions. To avoid 14235331Samw * rejection by FS due to lack of permission on the actual 14245331Samw * extended attr kcred is passed for streams. 14255331Samw */ 14265331Samw cr = kcred; 14275331Samw } 14285331Samw 14295772Sas200622 smb_node_start_crit(snode, RW_READER); 14305772Sas200622 rc = nbl_svmand(snode->vp, cr, &svmand); 14315772Sas200622 if (rc) { 14325772Sas200622 smb_node_end_crit(snode); 14335772Sas200622 return (rc); 14345772Sas200622 } 14355772Sas200622 rc = nbl_lock_conflict(snode->vp, NBL_WRITE, uio->uio_loffset, 14365772Sas200622 uio->uio_iov->iov_len, svmand, &smb_ct); 14375772Sas200622 14385772Sas200622 if (rc) { 14395772Sas200622 smb_node_end_crit(snode); 14405772Sas200622 return (rc); 14415772Sas200622 } 14425772Sas200622 rc = smb_vop_write(snode->vp, uio, flag, lcount, cr); 14435772Sas200622 14445772Sas200622 if (rc == 0 && ret_attr) { 14455331Samw /* 14465772Sas200622 * Use kcred to update the node attr because this 14475772Sas200622 * call is not being made on behalf of the user. 14485331Samw */ 14495331Samw ret_attr->sa_mask = SMB_AT_ALL; 14505772Sas200622 if (smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0, 14515772Sas200622 kcred) == 0) { 14525772Sas200622 snode->attr = *ret_attr; 14535772Sas200622 } 14545331Samw } 14555331Samw 14565772Sas200622 smb_node_end_crit(snode); 14575772Sas200622 14585331Samw return (rc); 14595331Samw } 14605331Samw 14615331Samw /* 14625331Samw * smb_fsop_statfs 14635331Samw * 14645331Samw * This is a wrapper function used for stat operations. 14655331Samw */ 14665331Samw int 14675331Samw smb_fsop_statfs( 14685331Samw cred_t *cr, 14695331Samw smb_node_t *snode, 14705331Samw struct statvfs64 *statp) 14715331Samw { 14725331Samw ASSERT(cr); 14735331Samw ASSERT(snode); 14745331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 14755331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 14765331Samw 14775331Samw return (smb_vop_statfs(snode->vp, statp, cr)); 14785331Samw } 14795331Samw 14805331Samw /* 14815331Samw * smb_fsop_access 14825331Samw */ 14835331Samw int 14845331Samw smb_fsop_access(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 14855331Samw uint32_t faccess) 14865331Samw { 14875331Samw int access = 0; 14885331Samw int error; 14895331Samw vnode_t *dir_vp; 14905331Samw boolean_t acl_check = B_TRUE; 14915331Samw smb_node_t *unnamed_node; 14925331Samw 14935331Samw ASSERT(cr); 14945331Samw ASSERT(snode); 14955331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 14965331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 14975331Samw 14985331Samw if (faccess == 0) 14995331Samw return (NT_STATUS_SUCCESS); 15005331Samw 15015331Samw if (SMB_TREE_IS_READ_ONLY(sr)) { 15025331Samw if (faccess & (FILE_WRITE_DATA|FILE_APPEND_DATA| 15035331Samw FILE_WRITE_EA|FILE_DELETE_CHILD|FILE_WRITE_ATTRIBUTES| 15045331Samw DELETE|WRITE_DAC|WRITE_OWNER)) { 15055331Samw return (NT_STATUS_ACCESS_DENIED); 15065331Samw } 15075331Samw } 15085331Samw 15095331Samw unnamed_node = SMB_IS_STREAM(snode); 15105331Samw if (unnamed_node) { 15115331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 15125331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 15135331Samw /* 15145331Samw * Streams authorization should be performed against the 15155331Samw * unnamed stream. 15165331Samw */ 15175331Samw snode = unnamed_node; 15185331Samw } 15195331Samw 15205331Samw if (faccess & ACCESS_SYSTEM_SECURITY) { 15215331Samw /* 15225331Samw * This permission is required for reading/writing SACL and 15235331Samw * it's not part of DACL. It's only granted via proper 15245331Samw * privileges. 15255331Samw */ 15265331Samw if ((sr->uid_user->u_privileges & 15275331Samw (SMB_USER_PRIV_BACKUP | 15285331Samw SMB_USER_PRIV_RESTORE | 15295331Samw SMB_USER_PRIV_SECURITY)) == 0) 15305331Samw return (NT_STATUS_PRIVILEGE_NOT_HELD); 15315331Samw 15325331Samw faccess &= ~ACCESS_SYSTEM_SECURITY; 15335331Samw } 15345331Samw 15355331Samw /* Links don't have ACL */ 15365331Samw if (((sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS) == 0) || 15375331Samw (snode->attr.sa_vattr.va_type == VLNK)) 15385331Samw acl_check = B_FALSE; 15395331Samw 15405331Samw if (acl_check) { 15415331Samw dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL; 15425331Samw error = smb_vop_access(snode->vp, faccess, V_ACE_MASK, dir_vp, 15435331Samw cr); 15445331Samw } else { 15455331Samw /* 15465331Samw * FS doesn't understand 32-bit mask, need to map 15475331Samw */ 15485331Samw if (faccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) 15495331Samw access |= VWRITE; 15505331Samw 15515331Samw if (faccess & FILE_READ_DATA) 15525331Samw access |= VREAD; 15535331Samw 15545331Samw if (faccess & FILE_EXECUTE) 15555331Samw access |= VEXEC; 15565331Samw 15575331Samw error = smb_vop_access(snode->vp, access, 0, NULL, cr); 15585331Samw } 15595331Samw 15605331Samw return ((error) ? NT_STATUS_ACCESS_DENIED : NT_STATUS_SUCCESS); 15615331Samw } 15625331Samw 15635331Samw /* 15645331Samw * smb_fsop_lookup_name() 15655331Samw * 15665331Samw * Sanity checks on dir_snode done in smb_fsop_lookup(). 15675331Samw * 15685331Samw * Note: This function is called only from the open path. 15695331Samw * It will check if the file is a stream. 15705331Samw * It will also return an error if the looked-up file is in 15715331Samw * a child mount. 15725331Samw */ 15735331Samw 15745331Samw int 15755331Samw smb_fsop_lookup_name( 1576*6139Sjb150015 smb_request_t *sr, 15775331Samw cred_t *cr, 15785331Samw int flags, 15795331Samw smb_node_t *root_node, 15805331Samw smb_node_t *dir_snode, 15815331Samw char *name, 15825331Samw smb_node_t **ret_snode, 15835331Samw smb_attr_t *ret_attr) 15845331Samw { 1585*6139Sjb150015 smb_node_t *fnode; 1586*6139Sjb150015 smb_attr_t file_attr; 1587*6139Sjb150015 vnode_t *xattrdirvp; 1588*6139Sjb150015 vnode_t *vp; 1589*6139Sjb150015 char *od_name; 1590*6139Sjb150015 char *fname; 1591*6139Sjb150015 char *sname; 1592*6139Sjb150015 int rc; 15935331Samw 15945331Samw ASSERT(cr); 15955331Samw ASSERT(dir_snode); 15965331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 15975331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 15985331Samw 15995331Samw /* 16005331Samw * The following check is required for streams processing, below 16015331Samw */ 16025331Samw 16035331Samw if (SMB_TREE_CASE_INSENSITIVE(sr)) 16045331Samw flags |= SMB_IGNORE_CASE; 16055331Samw 16065331Samw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 16075331Samw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 16085331Samw 16095331Samw if (smb_stream_parse_name(name, fname, sname)) { 16105331Samw /* 16115331Samw * Look up the unnamed stream (i.e. fname). 16125331Samw * Unmangle processing will be done on fname 16135331Samw * as well as any link target. 16145331Samw */ 16155331Samw rc = smb_fsop_lookup(sr, cr, flags, root_node, dir_snode, fname, 16165331Samw &fnode, &file_attr, NULL, NULL); 16175331Samw 16185331Samw if (rc != 0) { 16195331Samw kmem_free(fname, MAXNAMELEN); 16205331Samw kmem_free(sname, MAXNAMELEN); 16215331Samw return (rc); 16225331Samw } 16235331Samw 16245331Samw od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 16255331Samw 16265331Samw /* 16275331Samw * od_name is the on-disk name of the stream, except 16285331Samw * without the prepended stream prefix (SMB_STREAM_PREFIX) 16295331Samw */ 16305331Samw 16315331Samw /* 16325331Samw * XXX 16335331Samw * What permissions NTFS requires for stream lookup if any? 16345331Samw */ 16355331Samw rc = smb_vop_stream_lookup(fnode->vp, sname, &vp, od_name, 16365772Sas200622 &xattrdirvp, flags, root_node->vp, cr); 16375331Samw 16385331Samw if (rc != 0) { 16395331Samw smb_node_release(fnode); 16405331Samw kmem_free(fname, MAXNAMELEN); 16415331Samw kmem_free(sname, MAXNAMELEN); 16425331Samw kmem_free(od_name, MAXNAMELEN); 16435331Samw return (rc); 16445331Samw } 16455331Samw 16465331Samw *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, 16475331Samw vp, od_name, ret_attr); 16485331Samw 16495331Samw kmem_free(od_name, MAXNAMELEN); 16505331Samw smb_node_release(fnode); 16515331Samw 16525331Samw if (*ret_snode == NULL) { 16535331Samw VN_RELE(xattrdirvp); 16545331Samw VN_RELE(vp); 16555331Samw kmem_free(fname, MAXNAMELEN); 16565331Samw kmem_free(sname, MAXNAMELEN); 16575331Samw return (ENOMEM); 16585331Samw } 16595331Samw } else { 16605331Samw rc = smb_fsop_lookup(sr, cr, flags, root_node, dir_snode, name, 16615331Samw ret_snode, ret_attr, NULL, NULL); 16625331Samw } 16635331Samw 16645331Samw if (rc == 0) { 16655331Samw ASSERT(ret_snode); 16665331Samw if (SMB_TREE_ROOT_FS(sr, *ret_snode) == 0) { 16675331Samw smb_node_release(*ret_snode); 16685331Samw *ret_snode = NULL; 16695331Samw rc = EACCES; 16705331Samw } 16715331Samw } 16725331Samw 16735331Samw kmem_free(fname, MAXNAMELEN); 16745331Samw kmem_free(sname, MAXNAMELEN); 16755331Samw 16765331Samw return (rc); 16775331Samw } 16785331Samw 16795331Samw /* 16805331Samw * smb_fsop_lookup 16815331Samw * 16825331Samw * All SMB functions should use this smb_vop_lookup wrapper to ensure that 16835331Samw * the smb_vop_lookup is performed with the appropriate credentials and using 16845331Samw * case insensitive compares. Please document any direct call to smb_vop_lookup 16855331Samw * to explain the reason for avoiding this wrapper. 16865331Samw * 16875331Samw * It is assumed that a reference exists on dir_snode coming into this routine 16885331Samw * (and that it is safe from deallocation). 16895331Samw * 16905331Samw * Same with the root_node. 16915331Samw * 16925331Samw * *ret_snode is returned with a reference upon success. No reference is 16935331Samw * taken if an error is returned. 16945331Samw * 16955331Samw * Note: The returned ret_snode may be in a child mount. This is ok for 16965331Samw * readdir and getdents. 16975331Samw * 16985331Samw * Other smb_fsop_* routines will call SMB_TREE_ROOT_FS() to prevent 16995331Samw * operations on files not in the parent mount. 17005331Samw */ 17015331Samw int 17025331Samw smb_fsop_lookup( 1703*6139Sjb150015 smb_request_t *sr, 17045331Samw cred_t *cr, 17055331Samw int flags, 17065331Samw smb_node_t *root_node, 17075331Samw smb_node_t *dir_snode, 17085331Samw char *name, 17095331Samw smb_node_t **ret_snode, 17105331Samw smb_attr_t *ret_attr, 17115331Samw char *ret_shortname, /* Must be at least MANGLE_NAMELEN chars */ 17125331Samw char *ret_name83) /* Must be at least MANGLE_NAMELEN chars */ 17135331Samw { 17145331Samw smb_node_t *lnk_target_node; 17155331Samw smb_node_t *lnk_dnode; 17165331Samw char *longname; 17175331Samw char *od_name; 17185331Samw vnode_t *vp; 17195331Samw int rc; 17205331Samw 17215331Samw ASSERT(cr); 17225331Samw ASSERT(dir_snode); 17235331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 17245331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 17255331Samw 17265331Samw if (name == NULL) 17275331Samw return (EINVAL); 17285331Samw 17295331Samw if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0) 17305331Samw return (EACCES); 17315331Samw 17325331Samw if (SMB_TREE_CASE_INSENSITIVE(sr)) 17335331Samw flags |= SMB_IGNORE_CASE; 17345331Samw 17355331Samw od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 17365331Samw 17375331Samw rc = smb_vop_lookup(dir_snode->vp, name, &vp, od_name, flags, 17385772Sas200622 root_node ? root_node->vp : NULL, cr); 17395331Samw 17405331Samw if (rc != 0) { 17415331Samw if (smb_maybe_mangled_name(name) == 0) { 17425331Samw kmem_free(od_name, MAXNAMELEN); 17435331Samw return (rc); 17445331Samw } 17455331Samw 17465331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 17475331Samw 17485331Samw rc = smb_unmangle_name(sr, cr, dir_snode, name, longname, 17495331Samw MAXNAMELEN, ret_shortname, ret_name83, 1); 17505331Samw 17515331Samw if (rc != 0) { 17525331Samw kmem_free(od_name, MAXNAMELEN); 17535331Samw kmem_free(longname, MAXNAMELEN); 17545331Samw return (rc); 17555331Samw } 17565331Samw 17575331Samw /* 17585331Samw * We passed "1" as the "od" parameter 17595331Samw * to smb_unmangle_name(), such that longname 17605331Samw * is the real (case-sensitive) on-disk name. 17615331Samw * We make sure we do a lookup on this exact 17625331Samw * name, as the name was mangled and denotes 17635331Samw * a unique file. 17645331Samw */ 17655331Samw 17665331Samw if (flags & SMB_IGNORE_CASE) 17675331Samw flags &= ~SMB_IGNORE_CASE; 17685331Samw 17695331Samw rc = smb_vop_lookup(dir_snode->vp, longname, &vp, od_name, 17705772Sas200622 flags, root_node ? root_node->vp : NULL, cr); 17715331Samw 17725331Samw kmem_free(longname, MAXNAMELEN); 17735331Samw 17745331Samw if (rc != 0) { 17755331Samw kmem_free(od_name, MAXNAMELEN); 17765331Samw return (rc); 17775331Samw } 17785331Samw } 17795331Samw 17805331Samw if ((flags & SMB_FOLLOW_LINKS) && (vp->v_type == VLNK)) { 17815331Samw 17825331Samw rc = smb_pathname(sr, od_name, FOLLOW, root_node, dir_snode, 17835331Samw &lnk_dnode, &lnk_target_node, cr); 17845331Samw 17855331Samw if (rc != 0) { 17865331Samw /* 17875331Samw * The link is assumed to be for the last component 17885331Samw * of a path. Hence any ENOTDIR error will be returned 17895331Samw * as ENOENT. 17905331Samw */ 17915331Samw if (rc == ENOTDIR) 17925331Samw rc = ENOENT; 17935331Samw 17945331Samw VN_RELE(vp); 17955331Samw kmem_free(od_name, MAXNAMELEN); 17965331Samw return (rc); 17975331Samw } 17985331Samw 17995331Samw /* 18005331Samw * Release the original VLNK vnode 18015331Samw */ 18025331Samw 18035331Samw VN_RELE(vp); 18045331Samw vp = lnk_target_node->vp; 18055331Samw 18065331Samw rc = smb_vop_traverse_check(&vp); 18075331Samw 18085331Samw if (rc != 0) { 18095331Samw smb_node_release(lnk_dnode); 18105331Samw smb_node_release(lnk_target_node); 18115331Samw kmem_free(od_name, MAXNAMELEN); 18125331Samw return (rc); 18135331Samw } 18145331Samw 18155331Samw /* 18165331Samw * smb_vop_traverse_check() may have returned a different vnode 18175331Samw */ 18185331Samw 18195331Samw if (lnk_target_node->vp == vp) { 18205331Samw *ret_snode = lnk_target_node; 18215331Samw *ret_attr = (*ret_snode)->attr; 18225331Samw } else { 18235331Samw *ret_snode = smb_node_lookup(sr, NULL, cr, vp, 18245331Samw lnk_target_node->od_name, lnk_dnode, NULL, 18255331Samw ret_attr); 18265331Samw 18275331Samw if (*ret_snode == NULL) { 18285331Samw VN_RELE(vp); 18295331Samw rc = ENOMEM; 18305331Samw } 18315331Samw smb_node_release(lnk_target_node); 18325331Samw } 18335331Samw 18345331Samw smb_node_release(lnk_dnode); 18355331Samw 18365331Samw } else { 18375331Samw 18385331Samw rc = smb_vop_traverse_check(&vp); 18395331Samw if (rc) { 18405331Samw VN_RELE(vp); 18415331Samw kmem_free(od_name, MAXNAMELEN); 18425331Samw return (rc); 18435331Samw } 18445331Samw 18455331Samw *ret_snode = smb_node_lookup(sr, NULL, cr, vp, od_name, 18465331Samw dir_snode, NULL, ret_attr); 18475331Samw 18485331Samw if (*ret_snode == NULL) { 18495331Samw VN_RELE(vp); 18505331Samw rc = ENOMEM; 18515331Samw } 18525331Samw } 18535331Samw 18545331Samw kmem_free(od_name, MAXNAMELEN); 18555331Samw return (rc); 18565331Samw } 18575331Samw 18585331Samw /* 18595331Samw * smb_fsop_stream_readdir() 18605331Samw * 18615331Samw * ret_snode and ret_attr are optional parameters (i.e. NULL may be passed in) 18625331Samw * 18635331Samw * This routine will return only NTFS streams. If an NTFS stream is not 18645331Samw * found at the offset specified, the directory will be read until an NTFS 18655331Samw * stream is found or until EOF. 18665331Samw * 18675331Samw * Note: Sanity checks done in caller 18685331Samw * (smb_fsop_readdir(), smb_fsop_remove_streams()) 18695331Samw */ 18705331Samw 18715331Samw int 1872*6139Sjb150015 smb_fsop_stream_readdir(smb_request_t *sr, cred_t *cr, smb_node_t *fnode, 18735331Samw uint32_t *cookiep, struct fs_stream_info *stream_info, 18745331Samw smb_node_t **ret_snode, smb_attr_t *ret_attr) 18755331Samw { 18765331Samw smb_node_t *ret_snodep = NULL; 18775331Samw smb_attr_t tmp_attr; 18785331Samw vnode_t *xattrdirvp; 18795331Samw vnode_t *vp; 18805331Samw int rc = 0; 18815331Samw int flags = 0; 18825331Samw 18835331Samw /* 18845331Samw * XXX NTFS permission requirements if any? 18855331Samw */ 18865331Samw ASSERT(cr); 18875331Samw ASSERT(fnode); 18885331Samw ASSERT(fnode->n_magic == SMB_NODE_MAGIC); 18895331Samw ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING); 18905331Samw 18915331Samw if (SMB_TREE_CASE_INSENSITIVE(sr)) 18925331Samw flags = SMB_IGNORE_CASE; 18935331Samw 18945331Samw rc = smb_vop_stream_readdir(fnode->vp, cookiep, stream_info, &vp, 18955772Sas200622 &xattrdirvp, flags, cr); 18965331Samw 18975331Samw if ((rc != 0) || *cookiep == SMB_EOF) 18985331Samw return (rc); 18995331Samw 19005331Samw ret_snodep = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, vp, 19015331Samw stream_info->name, &tmp_attr); 19025331Samw 19035331Samw if (ret_snodep == NULL) { 19045331Samw VN_RELE(xattrdirvp); 19055331Samw VN_RELE(vp); 19065331Samw return (ENOMEM); 19075331Samw } 19085331Samw 19095331Samw stream_info->size = tmp_attr.sa_vattr.va_size; 19105331Samw 19115331Samw if (ret_attr) 19125331Samw *ret_attr = tmp_attr; 19135331Samw 19145331Samw if (ret_snode) 19155331Samw *ret_snode = ret_snodep; 19165331Samw else 19175331Samw smb_node_release(ret_snodep); 19185331Samw 19195331Samw return (rc); 19205331Samw } 19215331Samw 19225331Samw int /*ARGSUSED*/ 19235331Samw smb_fsop_commit(smb_request_t *sr, cred_t *cr, smb_node_t *snode) 19245331Samw { 19255331Samw ASSERT(cr); 19265331Samw ASSERT(snode); 19275331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 19285331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 19295331Samw 19305331Samw ASSERT(sr); 19315331Samw ASSERT(sr->tid_tree); 19325331Samw if (SMB_TREE_IS_READ_ONLY(sr)) 19335331Samw return (EROFS); 19345331Samw 19355772Sas200622 return (smb_vop_commit(snode->vp, cr)); 19365331Samw } 19375331Samw 19385331Samw /* 19395331Samw * smb_fsop_aclread 19405331Samw * 19415331Samw * Retrieve filesystem ACL. Depends on requested ACLs in 19425331Samw * fs_sd->sd_secinfo, it'll set DACL and SACL pointers in 19435331Samw * fs_sd. Note that requesting a DACL/SACL doesn't mean that 19445331Samw * the corresponding field in fs_sd should be non-NULL upon 19455331Samw * return, since the target ACL might not contain that type of 19465331Samw * entries. 19475331Samw * 19485331Samw * Returned ACL is always in ACE_T (aka ZFS) format. 19495331Samw * If successful the allocated memory for the ACL should be freed 19505521Sas200622 * using smb_fsacl_free() or smb_fssd_term() 19515331Samw */ 19525331Samw int 19535331Samw smb_fsop_aclread(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 19545331Samw smb_fssd_t *fs_sd) 19555331Samw { 19565331Samw int error = 0; 19575331Samw int flags = 0; 19585331Samw int access = 0; 19595331Samw acl_t *acl; 19605331Samw smb_node_t *unnamed_node; 19615331Samw 19625331Samw ASSERT(cr); 19635331Samw 19645331Samw if (sr->fid_ofile) { 19655331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 19665331Samw access = READ_CONTROL; 19675331Samw 19685331Samw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 19695331Samw access |= ACCESS_SYSTEM_SECURITY; 19705331Samw 19715331Samw error = smb_ofile_access(sr->fid_ofile, cr, access); 19725331Samw if (error != NT_STATUS_SUCCESS) { 19735331Samw return (EACCES); 19745331Samw } 19755331Samw } 19765331Samw 19775331Samw unnamed_node = SMB_IS_STREAM(snode); 19785331Samw if (unnamed_node) { 19795331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 19805331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 19815331Samw /* 19825331Samw * Streams don't have ACL, any read ACL attempt on a stream 19835331Samw * should be performed on the unnamed stream. 19845331Samw */ 19855331Samw snode = unnamed_node; 19865331Samw } 19875331Samw 19885331Samw if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS) 19895331Samw flags = ATTR_NOACLCHECK; 19905331Samw 19915331Samw error = smb_vop_acl_read(snode->vp, &acl, flags, 19925772Sas200622 sr->tid_tree->t_acltype, cr); 19935331Samw if (error != 0) { 19945331Samw return (error); 19955331Samw } 19965331Samw 19975331Samw error = acl_translate(acl, _ACL_ACE_ENABLED, 19985331Samw (snode->vp->v_type == VDIR), fs_sd->sd_uid, fs_sd->sd_gid); 19995331Samw 20005331Samw if (error == 0) { 20015521Sas200622 smb_fsacl_split(acl, &fs_sd->sd_zdacl, &fs_sd->sd_zsacl, 20025331Samw fs_sd->sd_secinfo); 20035331Samw } 20045331Samw 20055331Samw acl_free(acl); 20065331Samw return (error); 20075331Samw } 20085331Samw 20095331Samw /* 20105331Samw * smb_fsop_aclwrite 20115331Samw * 20125331Samw * Stores the filesystem ACL provided in fs_sd->sd_acl. 20135331Samw */ 20145331Samw int 20155331Samw smb_fsop_aclwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 20165331Samw smb_fssd_t *fs_sd) 20175331Samw { 20185331Samw int target_flavor; 20195331Samw int error = 0; 20205331Samw int flags = 0; 20215331Samw int access = 0; 20225331Samw acl_t *acl, *dacl, *sacl; 20235331Samw smb_node_t *unnamed_node; 20245331Samw 20255331Samw ASSERT(cr); 20265331Samw 20275331Samw ASSERT(sr); 20285331Samw ASSERT(sr->tid_tree); 20295331Samw if (SMB_TREE_IS_READ_ONLY(sr)) 20305331Samw return (EROFS); 20315331Samw 20325331Samw if (sr->fid_ofile) { 20335331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 20345331Samw access = WRITE_DAC; 20355331Samw 20365331Samw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 20375331Samw access |= ACCESS_SYSTEM_SECURITY; 20385331Samw 20395331Samw error = smb_ofile_access(sr->fid_ofile, cr, access); 20405331Samw if (error != NT_STATUS_SUCCESS) 20415331Samw return (EACCES); 20425331Samw } 20435331Samw 20445331Samw switch (sr->tid_tree->t_acltype) { 20455331Samw case ACLENT_T: 20465331Samw target_flavor = _ACL_ACLENT_ENABLED; 20475331Samw break; 20485331Samw 20495331Samw case ACE_T: 20505331Samw target_flavor = _ACL_ACE_ENABLED; 20515331Samw break; 20525331Samw default: 20535331Samw return (EINVAL); 20545331Samw } 20555331Samw 20565331Samw unnamed_node = SMB_IS_STREAM(snode); 20575331Samw if (unnamed_node) { 20585331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 20595331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 20605331Samw /* 20615331Samw * Streams don't have ACL, any write ACL attempt on a stream 20625331Samw * should be performed on the unnamed stream. 20635331Samw */ 20645331Samw snode = unnamed_node; 20655331Samw } 20665331Samw 20675331Samw dacl = fs_sd->sd_zdacl; 20685331Samw sacl = fs_sd->sd_zsacl; 20695331Samw 20705331Samw ASSERT(dacl || sacl); 20715331Samw if ((dacl == NULL) && (sacl == NULL)) 20725331Samw return (EINVAL); 20735331Samw 20745331Samw if (dacl && sacl) 20755521Sas200622 acl = smb_fsacl_merge(dacl, sacl); 20765331Samw else if (dacl) 20775331Samw acl = dacl; 20785331Samw else 20795331Samw acl = sacl; 20805331Samw 20815331Samw error = acl_translate(acl, target_flavor, (snode->vp->v_type == VDIR), 20825331Samw fs_sd->sd_uid, fs_sd->sd_gid); 20835331Samw if (error == 0) { 20845331Samw if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS) 20855331Samw flags = ATTR_NOACLCHECK; 20865331Samw 20875772Sas200622 error = smb_vop_acl_write(snode->vp, acl, flags, cr); 20885331Samw } 20895331Samw 20905331Samw if (dacl && sacl) 20915331Samw acl_free(acl); 20925331Samw 20935331Samw return (error); 20945331Samw } 20955331Samw 20965331Samw acl_type_t 20975331Samw smb_fsop_acltype(smb_node_t *snode) 20985331Samw { 20995331Samw return (smb_vop_acl_type(snode->vp)); 21005331Samw } 21015331Samw 21025331Samw /* 21035331Samw * smb_fsop_sdread 21045331Samw * 21055331Samw * Read the requested security descriptor items from filesystem. 21065331Samw * The items are specified in fs_sd->sd_secinfo. 21075331Samw */ 21085331Samw int 21095331Samw smb_fsop_sdread(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 21105331Samw smb_fssd_t *fs_sd) 21115331Samw { 21125331Samw int error = 0; 21135331Samw int getowner = 0; 21145331Samw cred_t *ga_cred; 21155331Samw smb_attr_t attr; 21165331Samw 21175331Samw ASSERT(cr); 21185331Samw ASSERT(fs_sd); 21195331Samw 21205331Samw /* 21215331Samw * File's uid/gid is fetched in two cases: 21225331Samw * 21235331Samw * 1. it's explicitly requested 21245331Samw * 21255331Samw * 2. target ACL is ACE_T (ZFS ACL). They're needed for 21265331Samw * owner@/group@ entries. In this case kcred should be used 21275331Samw * because uid/gid are fetched on behalf of smb server. 21285331Samw */ 21295331Samw if (fs_sd->sd_secinfo & (SMB_OWNER_SECINFO | SMB_GROUP_SECINFO)) { 21305331Samw getowner = 1; 21315331Samw ga_cred = cr; 21325331Samw } else if (sr->tid_tree->t_acltype == ACE_T) { 21335331Samw getowner = 1; 21345331Samw ga_cred = kcred; 21355331Samw } 21365331Samw 21375331Samw if (getowner) { 21385331Samw /* 21395331Samw * Windows require READ_CONTROL to read owner/group SID since 21405331Samw * they're part of Security Descriptor. 21415331Samw * ZFS only requires read_attribute. Need to have a explicit 21425331Samw * access check here. 21435331Samw */ 21445331Samw if (sr->fid_ofile == NULL) { 21455331Samw error = smb_fsop_access(sr, ga_cred, snode, 21465331Samw READ_CONTROL); 21475331Samw if (error) 21485331Samw return (error); 21495331Samw } 21505331Samw 21515331Samw attr.sa_mask = SMB_AT_UID | SMB_AT_GID; 21525331Samw error = smb_fsop_getattr(sr, ga_cred, snode, &attr); 21535331Samw if (error == 0) { 21545331Samw fs_sd->sd_uid = attr.sa_vattr.va_uid; 21555331Samw fs_sd->sd_gid = attr.sa_vattr.va_gid; 21565331Samw } else { 21575331Samw return (error); 21585331Samw } 21595331Samw } 21605331Samw 21615331Samw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 21625331Samw error = smb_fsop_aclread(sr, cr, snode, fs_sd); 21635331Samw } 21645331Samw 21655331Samw return (error); 21665331Samw } 21675331Samw 21685331Samw /* 21695331Samw * smb_fsop_sdmerge 21705331Samw * 21715331Samw * From SMB point of view DACL and SACL are two separate list 21725331Samw * which can be manipulated independently without one affecting 21735331Samw * the other, but entries for both DACL and SACL will end up 21745331Samw * in the same ACL if target filesystem supports ACE_T ACLs. 21755331Samw * 21765331Samw * So, if either DACL or SACL is present in the client set request 21775331Samw * the entries corresponding to the non-present ACL shouldn't 21785331Samw * be touched in the FS ACL. 21795331Samw * 21805331Samw * fs_sd parameter contains DACL and SACL specified by SMB 21815331Samw * client to be set on a file/directory. The client could 21825331Samw * specify both or one of these ACLs (if none is specified 21835331Samw * we don't get this far). When both DACL and SACL are given 21845331Samw * by client the existing ACL should be overwritten. If only 21855331Samw * one of them is specified the entries corresponding to the other 21865331Samw * ACL should not be touched. For example, if only DACL 21875331Samw * is specified in input fs_sd, the function reads audit entries 21885331Samw * of the existing ACL of the file and point fs_sd->sd_zsdacl 21895331Samw * pointer to the fetched SACL, this way when smb_fsop_sdwrite() 21905331Samw * function is called the passed fs_sd would point to the specified 21915331Samw * DACL by client and fetched SACL from filesystem, so the file 21925331Samw * will end up with correct ACL. 21935331Samw */ 21945331Samw static int 21955331Samw smb_fsop_sdmerge(smb_request_t *sr, smb_node_t *snode, smb_fssd_t *fs_sd) 21965331Samw { 21975331Samw smb_fssd_t cur_sd; 21985331Samw int error = 0; 21995331Samw 22005331Samw if (sr->tid_tree->t_acltype != ACE_T) 22015331Samw /* Don't bother if target FS doesn't support ACE_T */ 22025331Samw return (0); 22035331Samw 22045331Samw if ((fs_sd->sd_secinfo & SMB_ACL_SECINFO) != SMB_ACL_SECINFO) { 22055331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) { 22065331Samw /* 22075331Samw * Don't overwrite existing audit entries 22085331Samw */ 22095521Sas200622 smb_fssd_init(&cur_sd, SMB_SACL_SECINFO, 22105331Samw fs_sd->sd_flags); 22115331Samw 22125331Samw error = smb_fsop_sdread(sr, kcred, snode, &cur_sd); 22135331Samw if (error == 0) { 22145331Samw ASSERT(fs_sd->sd_zsacl == NULL); 22155331Samw fs_sd->sd_zsacl = cur_sd.sd_zsacl; 22165331Samw if (fs_sd->sd_zsacl && fs_sd->sd_zdacl) 22175331Samw fs_sd->sd_zsacl->acl_flags = 22185331Samw fs_sd->sd_zdacl->acl_flags; 22195331Samw } 22205331Samw } else { 22215331Samw /* 22225331Samw * Don't overwrite existing access entries 22235331Samw */ 22245521Sas200622 smb_fssd_init(&cur_sd, SMB_DACL_SECINFO, 22255331Samw fs_sd->sd_flags); 22265331Samw 22275331Samw error = smb_fsop_sdread(sr, kcred, snode, &cur_sd); 22285331Samw if (error == 0) { 22295331Samw ASSERT(fs_sd->sd_zdacl == NULL); 22305331Samw fs_sd->sd_zdacl = cur_sd.sd_zdacl; 22315331Samw if (fs_sd->sd_zdacl && fs_sd->sd_zsacl) 22325331Samw fs_sd->sd_zdacl->acl_flags = 22335331Samw fs_sd->sd_zsacl->acl_flags; 22345331Samw } 22355331Samw } 22365331Samw 22375331Samw if (error) 22385521Sas200622 smb_fssd_term(&cur_sd); 22395331Samw } 22405331Samw 22415331Samw return (error); 22425331Samw } 22435331Samw 22445331Samw /* 22455331Samw * smb_fsop_sdwrite 22465331Samw * 22475331Samw * Stores the given uid, gid and acl in filesystem. 22485331Samw * Provided items in fs_sd are specified by fs_sd->sd_secinfo. 22495331Samw * 22505331Samw * A SMB security descriptor could contain owner, primary group, 22515331Samw * DACL and SACL. Setting an SD should be atomic but here it has to 22525331Samw * be done via two separate FS operations: VOP_SETATTR and 22535331Samw * VOP_SETSECATTR. Therefore, this function has to simulate the 22545331Samw * atomicity as well as it can. 22555331Samw */ 22565331Samw int 22575331Samw smb_fsop_sdwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 22585331Samw smb_fssd_t *fs_sd, int overwrite) 22595331Samw { 22605331Samw int error = 0; 22615331Samw int access = 0; 22625331Samw smb_attr_t set_attr; 22635331Samw smb_attr_t orig_attr; 22645331Samw 22655331Samw ASSERT(cr); 22665331Samw ASSERT(fs_sd); 22675331Samw 22685331Samw ASSERT(sr); 22695331Samw ASSERT(sr->tid_tree); 22705331Samw if (SMB_TREE_IS_READ_ONLY(sr)) 22715331Samw return (EROFS); 22725331Samw 22735331Samw bzero(&set_attr, sizeof (smb_attr_t)); 22745331Samw 22755331Samw if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 22765331Samw set_attr.sa_vattr.va_uid = fs_sd->sd_uid; 22775331Samw set_attr.sa_mask |= SMB_AT_UID; 22785331Samw } 22795331Samw 22805331Samw if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 22815331Samw set_attr.sa_vattr.va_gid = fs_sd->sd_gid; 22825331Samw set_attr.sa_mask |= SMB_AT_GID; 22835331Samw } 22845331Samw 22855331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 22865331Samw access |= WRITE_DAC; 22875331Samw 22885331Samw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 22895331Samw access |= ACCESS_SYSTEM_SECURITY; 22905331Samw 22915331Samw if (sr->fid_ofile) 22925331Samw error = smb_ofile_access(sr->fid_ofile, cr, access); 22935331Samw else 22945331Samw error = smb_fsop_access(sr, cr, snode, access); 22955331Samw 22965331Samw if (error) 22975331Samw return (EACCES); 22985331Samw 22995331Samw if (set_attr.sa_mask) { 23005331Samw /* 23015331Samw * Get the current uid, gid so if smb_fsop_aclwrite fails 23025331Samw * we can revert uid, gid changes. 23035331Samw * 23045331Samw * We use root cred here so the operation doesn't fail 23055331Samw * due to lack of permission for the user to read the attrs 23065331Samw */ 23075331Samw 23085331Samw orig_attr.sa_mask = SMB_AT_UID | SMB_AT_GID; 23095331Samw error = smb_fsop_getattr(sr, kcred, snode, &orig_attr); 23105331Samw if (error == 0) 23115331Samw error = smb_fsop_setattr(sr, cr, snode, &set_attr, 23125331Samw NULL); 23135331Samw 23145331Samw if (error) 23155331Samw return (error); 23165331Samw } 23175331Samw 23185331Samw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 23195331Samw if (overwrite == 0) { 23205331Samw error = smb_fsop_sdmerge(sr, snode, fs_sd); 23215331Samw if (error) 23225331Samw return (error); 23235331Samw } 23245331Samw 23255331Samw error = smb_fsop_aclwrite(sr, cr, snode, fs_sd); 23265331Samw if (error) { 23275331Samw /* 23285331Samw * Revert uid/gid changes if required. 23295331Samw */ 23305331Samw if (set_attr.sa_mask) { 23315331Samw orig_attr.sa_mask = set_attr.sa_mask; 23325331Samw (void) smb_fsop_setattr(sr, kcred, snode, 23335331Samw &orig_attr, NULL); 23345331Samw } 23355331Samw } 23365331Samw } 23375331Samw 23385331Samw return (error); 23395331Samw } 23405331Samw 23415331Samw /* 23425331Samw * smb_fsop_sdinherit 23435331Samw * 23445331Samw * Inherit the security descriptor from the parent container. 23455331Samw * This function is called after FS has created the file/folder 23465331Samw * so if this doesn't do anything it means FS inheritance is 23475331Samw * in place. 23485331Samw * 23495331Samw * Do inheritance for ZFS internally. 23505331Samw * 23515331Samw * If we want to let ZFS does the inheritance the 23525331Samw * following setting should be true: 23535331Samw * 23545331Samw * - aclinherit = passthrough 23555331Samw * - aclmode = passthrough 23565331Samw * - smbd umask = 0777 23575331Samw * 23585331Samw * This will result in right effective permissions but 23595331Samw * ZFS will always add 6 ACEs for owner, owning group 23605331Samw * and others to be POSIX compliant. This is not what 23615331Samw * Windows clients/users expect, so we decided that CIFS 23625331Samw * implements Windows rules and overwrite whatever ZFS 23635331Samw * comes up with. This way we also don't have to care 23645331Samw * about ZFS aclinherit and aclmode settings. 23655331Samw */ 23665331Samw static int 23675331Samw smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, smb_fssd_t *fs_sd) 23685331Samw { 23695331Samw int is_dir; 23705521Sas200622 acl_t *dacl = NULL; 23715521Sas200622 acl_t *sacl = NULL; 23725331Samw ksid_t *owner_sid; 23735331Samw int error; 23745331Samw 23755331Samw ASSERT(fs_sd); 23765331Samw 23775331Samw if (sr->tid_tree->t_acltype != ACE_T) { 23785331Samw /* 23795331Samw * No forced inheritance for non-ZFS filesystems. 23805331Samw */ 23815331Samw fs_sd->sd_secinfo = 0; 23825331Samw return (0); 23835331Samw } 23845331Samw 23855331Samw 23865331Samw /* Fetch parent directory's ACL */ 23875331Samw error = smb_fsop_sdread(sr, kcred, dnode, fs_sd); 23885331Samw if (error) { 23895331Samw return (error); 23905331Samw } 23915331Samw 23925331Samw is_dir = (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR); 23935331Samw owner_sid = crgetsid(sr->user_cr, KSID_OWNER); 23945331Samw ASSERT(owner_sid); 23955521Sas200622 dacl = smb_fsacl_inherit(fs_sd->sd_zdacl, is_dir, SMB_DACL_SECINFO, 23965331Samw owner_sid->ks_id); 23975521Sas200622 sacl = smb_fsacl_inherit(fs_sd->sd_zsacl, is_dir, SMB_SACL_SECINFO, 23985331Samw (uid_t)-1); 23995331Samw 24005521Sas200622 if (sacl == NULL) 24015521Sas200622 fs_sd->sd_secinfo &= ~SMB_SACL_SECINFO; 24025521Sas200622 24035521Sas200622 smb_fsacl_free(fs_sd->sd_zdacl); 24045521Sas200622 smb_fsacl_free(fs_sd->sd_zsacl); 24055331Samw 24065331Samw fs_sd->sd_zdacl = dacl; 24075331Samw fs_sd->sd_zsacl = sacl; 24085331Samw 24095331Samw return (0); 24105331Samw } 24115331Samw 24125331Samw /* 24135331Samw * smb_fsop_eaccess 24145331Samw * 24155331Samw * Returns the effective permission of the given credential for the 24165331Samw * specified object. 24175331Samw * 24185331Samw * This is just a workaround. We need VFS/FS support for this. 24195331Samw */ 24205331Samw void 24215331Samw smb_fsop_eaccess(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 24225331Samw uint32_t *eaccess) 24235331Samw { 24245331Samw int access = 0; 24255331Samw vnode_t *dir_vp; 24265331Samw smb_node_t *unnamed_node; 24275331Samw 24285331Samw ASSERT(cr); 24295331Samw ASSERT(snode); 24305331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 24315331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 24325331Samw 24335331Samw unnamed_node = SMB_IS_STREAM(snode); 24345331Samw if (unnamed_node) { 24355331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 24365331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 24375331Samw /* 24385331Samw * Streams authorization should be performed against the 24395331Samw * unnamed stream. 24405331Samw */ 24415331Samw snode = unnamed_node; 24425331Samw } 24435331Samw 24445331Samw if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS) { 24455331Samw dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL; 24465331Samw smb_vop_eaccess(snode->vp, (int *)eaccess, V_ACE_MASK, dir_vp, 24475331Samw cr); 24485331Samw return; 24495331Samw } 24505331Samw 24515331Samw /* 24525331Samw * FS doesn't understand 32-bit mask 24535331Samw */ 24545331Samw smb_vop_eaccess(snode->vp, &access, 0, NULL, cr); 24555331Samw 24565331Samw *eaccess = READ_CONTROL | FILE_READ_EA | FILE_READ_ATTRIBUTES; 24575331Samw 24585331Samw if (access & VREAD) 24595331Samw *eaccess |= FILE_READ_DATA; 24605331Samw 24615331Samw if (access & VEXEC) 24625331Samw *eaccess |= FILE_EXECUTE; 24635331Samw 24645331Samw if (access & VWRITE) 24655331Samw *eaccess |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | 24665331Samw FILE_WRITE_EA | FILE_APPEND_DATA | FILE_DELETE_CHILD; 24675331Samw } 24685521Sas200622 24695772Sas200622 /* 24705772Sas200622 * smb_fsop_shrlock 24715772Sas200622 * 24725772Sas200622 * For the current open request, check file sharing rules 24735772Sas200622 * against existing opens. 24745772Sas200622 * 24755772Sas200622 * Returns NT_STATUS_SHARING_VIOLATION if there is any 24765772Sas200622 * sharing conflict. Returns NT_STATUS_SUCCESS otherwise. 24775772Sas200622 * 24785772Sas200622 * Full system-wide share reservation synchronization is available 24795772Sas200622 * when the nbmand (non-blocking mandatory) mount option is set 24805772Sas200622 * (i.e. nbl_need_crit() is true) and nbmand critical regions are used. 24815772Sas200622 * This provides synchronization with NFS and local processes. The 24825772Sas200622 * critical regions are entered in VOP_SHRLOCK()/fs_shrlock() (called 24835772Sas200622 * from smb_open_subr()/smb_fsop_shrlock()/smb_vop_shrlock()) as well 24845772Sas200622 * as the CIFS rename and delete paths. 24855772Sas200622 * 24865772Sas200622 * The CIFS server will also enter the nbl critical region in the open, 24875772Sas200622 * rename, and delete paths when nbmand is not set. There is limited 24885772Sas200622 * coordination with local and VFS share reservations in this case. 24895772Sas200622 * Note that when the nbmand mount option is not set, the VFS layer 24905772Sas200622 * only processes advisory reservations and the delete mode is not checked. 24915772Sas200622 * 24925772Sas200622 * Whether or not the nbmand mount option is set, intra-CIFS share 24935772Sas200622 * checking is done in the open, delete, and rename paths using a CIFS 24945772Sas200622 * critical region (node->n_share_lock). 24955772Sas200622 */ 24965772Sas200622 24975772Sas200622 uint32_t 2498*6139Sjb150015 smb_fsop_shrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid, 24995772Sas200622 uint32_t desired_access, uint32_t share_access) 25005772Sas200622 { 25015772Sas200622 int rc; 25025772Sas200622 25035772Sas200622 if (node->attr.sa_vattr.va_type == VDIR) 25045772Sas200622 return (NT_STATUS_SUCCESS); 25055772Sas200622 25065772Sas200622 /* Allow access if the request is just for meta data */ 25075772Sas200622 if ((desired_access & FILE_DATA_ALL) == 0) 25085772Sas200622 return (NT_STATUS_SUCCESS); 25095772Sas200622 25105772Sas200622 rc = smb_node_open_check(node, cr, desired_access, share_access); 25115772Sas200622 if (rc) 25125772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 25135772Sas200622 25145772Sas200622 rc = smb_vop_shrlock(node->vp, uniq_fid, desired_access, share_access, 25155772Sas200622 cr); 25165772Sas200622 if (rc) 25175772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 25185772Sas200622 25195772Sas200622 return (NT_STATUS_SUCCESS); 25205772Sas200622 } 25215772Sas200622 25225521Sas200622 void 25235772Sas200622 smb_fsop_unshrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid) 25245521Sas200622 { 25255772Sas200622 if (node->attr.sa_vattr.va_type == VDIR) 25265772Sas200622 return; 25275772Sas200622 25285772Sas200622 (void) smb_vop_unshrlock(node->vp, uniq_fid, cr); 25295772Sas200622 } 25305772Sas200622 25315772Sas200622 /* 25325772Sas200622 * smb_fsop_frlock_callback 25335772Sas200622 * 25345772Sas200622 * smb wrapper function for fs_frlock 25355772Sas200622 * this should never happen, as we are not attempting 25365772Sas200622 * to set Mandatory Locks, cmd = F_SETLK_NBMAND 25375772Sas200622 * 25385772Sas200622 */ 25395772Sas200622 25405772Sas200622 static callb_cpr_t * 25415772Sas200622 /* ARGSUSED */ 25425772Sas200622 smb_fsop_frlock_callback(flk_cb_when_t when, void *error) 25435772Sas200622 { 25445772Sas200622 return (0); 25455521Sas200622 } 25465772Sas200622 25475772Sas200622 /* 25485772Sas200622 * smb_fs_frlock 25495772Sas200622 * 25505772Sas200622 * smb wrapper function for fs_frlock 25515772Sas200622 */ 25525772Sas200622 25535772Sas200622 int 25545772Sas200622 smb_fsop_frlock(smb_request_t *sr, smb_node_t *node, smb_lock_t *lock, 25555772Sas200622 boolean_t unlock) 25565772Sas200622 { 2557*6139Sjb150015 vnode_t *vp; 2558*6139Sjb150015 flock64_t bf; 2559*6139Sjb150015 cred_t *cr; 2560*6139Sjb150015 int cmd; 2561*6139Sjb150015 flk_callback_t flk_cb; 2562*6139Sjb150015 offset_t offset = 0; 2563*6139Sjb150015 int flag; 2564*6139Sjb150015 int error; 2565*6139Sjb150015 int i; 25665772Sas200622 25675772Sas200622 flk_init_callback(&flk_cb, smb_fsop_frlock_callback, &error); 25685772Sas200622 cr = sr->user_cr; 25695772Sas200622 vp = node->vp; 25705772Sas200622 cmd = F_SETLK; 25715772Sas200622 25725772Sas200622 if (unlock == B_TRUE) { 25735772Sas200622 bf.l_type = F_UNLCK; 25745772Sas200622 flag = 0; 25755772Sas200622 } else if (lock->l_type == SMB_LOCK_TYPE_READONLY) { 25765772Sas200622 bf.l_type = F_RDLCK; 25775772Sas200622 flag = FREAD; 25785772Sas200622 } else if (lock->l_type == SMB_LOCK_TYPE_READWRITE) { 25795772Sas200622 bf.l_type = F_WRLCK; 25805772Sas200622 flag = FWRITE; 25815772Sas200622 } 25825772Sas200622 25835772Sas200622 bf.l_start = lock->l_start; 25845772Sas200622 bf.l_len = lock->l_length; 25855772Sas200622 bf.l_whence = 0; /* SEEK_SET */ 25865772Sas200622 bf.l_pid = lock->l_pid; 25875772Sas200622 bf.l_sysid = 0; 25885772Sas200622 25895772Sas200622 for (i = 0; i < 4; i++) 25905772Sas200622 bf.l_pad[i] = 0; 25915772Sas200622 2592*6139Sjb150015 error = fs_frlock(vp, cmd, &bf, flag, offset, &flk_cb, cr, &smb_ct); 25935772Sas200622 return (error); 25945772Sas200622 } 2595