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 #include <sys/sid.h> 275772Sas200622 #include <sys/nbmlock.h> 285331Samw #include <smbsrv/smb_fsops.h> 295521Sas200622 #include <smbsrv/smb_kproto.h> 305521Sas200622 #include <smbsrv/ntstatus.h> 315521Sas200622 #include <smbsrv/ntaccess.h> 325772Sas200622 #include <smbsrv/smb_incl.h> 335331Samw #include <acl/acl_common.h> 345772Sas200622 #include <sys/fcntl.h> 355772Sas200622 #include <sys/flock.h> 365772Sas200622 #include <fs/fs_subr.h> 375331Samw 386139Sjb150015 extern caller_context_t smb_ct; 396139Sjb150015 406600Sas200622 extern int smb_fem_oplock_install(smb_node_t *); 416600Sas200622 extern void smb_fem_oplock_uninstall(smb_node_t *); 426600Sas200622 436600Sas200622 extern int smb_vop_other_opens(vnode_t *, int); 446600Sas200622 455331Samw static int smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, 465331Samw smb_fssd_t *fs_sd); 475331Samw 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 696600Sas200622 /* 706600Sas200622 * smb_fsop_amask_to_omode 716600Sas200622 * 726600Sas200622 * Convert the access mask to the open mode (for use 736600Sas200622 * with the VOP_OPEN call). 746600Sas200622 * 756600Sas200622 * Note that opening a file for attribute only access 766600Sas200622 * will also translate into an FREAD or FWRITE open mode 776600Sas200622 * (i.e., it's not just for data). 786600Sas200622 * 796600Sas200622 * This is needed so that opens are tracked appropriately 806600Sas200622 * for oplock processing. 816600Sas200622 */ 826600Sas200622 835331Samw int 846600Sas200622 smb_fsop_amask_to_omode(uint32_t access) 855331Samw { 866600Sas200622 int mode = 0; 876600Sas200622 886600Sas200622 if (access & (FILE_READ_DATA | FILE_EXECUTE | 896600Sas200622 FILE_READ_ATTRIBUTES | FILE_READ_EA)) 906600Sas200622 mode |= FREAD; 916600Sas200622 926600Sas200622 if (access & (FILE_WRITE_DATA | FILE_APPEND_DATA | 936600Sas200622 FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA)) 946600Sas200622 mode |= FWRITE; 956600Sas200622 966600Sas200622 if (access & FILE_APPEND_DATA) 976600Sas200622 mode |= FAPPEND; 986600Sas200622 996600Sas200622 return (mode); 1005331Samw } 1015331Samw 1025331Samw int 1036600Sas200622 smb_fsop_open(smb_node_t *node, int mode, cred_t *cred) 1045331Samw { 1056600Sas200622 /* 1066600Sas200622 * Assuming that the same vnode is returned as we had before. 1076600Sas200622 * (I.e., with certain types of files or file systems, a 1086600Sas200622 * different vnode might be returned by VOP_OPEN) 1096600Sas200622 */ 1106600Sas200622 return (smb_vop_open(&node->vp, mode, cred)); 1115331Samw } 1125331Samw 1137348SJose.Borrego@Sun.COM void 1146600Sas200622 smb_fsop_close(smb_node_t *node, int mode, cred_t *cred) 1156600Sas200622 { 1167348SJose.Borrego@Sun.COM smb_vop_close(node->vp, mode, cred); 1176600Sas200622 } 1186600Sas200622 1196600Sas200622 int 1206600Sas200622 smb_fsop_oplock_install(smb_node_t *node, int mode) 1215331Samw { 1226600Sas200622 int rc; 1236600Sas200622 1246600Sas200622 if (smb_vop_other_opens(node->vp, mode)) 1256600Sas200622 return (EMFILE); 1266600Sas200622 1276600Sas200622 if ((rc = smb_fem_oplock_install(node))) 1286600Sas200622 return (rc); 1296600Sas200622 1306600Sas200622 if (smb_vop_other_opens(node->vp, mode)) { 1316600Sas200622 (void) smb_fem_oplock_uninstall(node); 1326600Sas200622 return (EMFILE); 1336600Sas200622 } 1346600Sas200622 1356600Sas200622 return (0); 1366600Sas200622 } 1376600Sas200622 1386600Sas200622 void 1396600Sas200622 smb_fsop_oplock_uninstall(smb_node_t *node) 1406600Sas200622 { 1416600Sas200622 smb_fem_oplock_uninstall(node); 1425331Samw } 1435331Samw 1445331Samw static int 1455331Samw smb_fsop_create_with_sd( 1466139Sjb150015 smb_request_t *sr, 1475331Samw cred_t *cr, 1487619SJose.Borrego@Sun.COM smb_node_t *dir_snode, 1495331Samw char *name, 1505331Samw smb_attr_t *attr, 1515331Samw smb_node_t **ret_snode, 1525331Samw smb_attr_t *ret_attr, 1535331Samw smb_fssd_t *fs_sd) 1545331Samw { 1555331Samw vsecattr_t *vsap; 1565331Samw vsecattr_t vsecattr; 1575331Samw acl_t *acl, *dacl, *sacl; 1585331Samw smb_attr_t set_attr; 1595331Samw vnode_t *vp; 1605331Samw int aclbsize = 0; /* size of acl list in bytes */ 1615331Samw int flags = 0; 1625331Samw int rc; 1637619SJose.Borrego@Sun.COM boolean_t is_dir; 1645331Samw 1655331Samw ASSERT(fs_sd); 1665331Samw 1677348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 1685331Samw flags = SMB_IGNORE_CASE; 1695331Samw 1705331Samw ASSERT(cr); 1715331Samw 1725331Samw is_dir = ((fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR) != 0); 1735331Samw 1747348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACLONCREATE)) { 1755331Samw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 1765331Samw dacl = fs_sd->sd_zdacl; 1775331Samw sacl = fs_sd->sd_zsacl; 1785331Samw ASSERT(dacl || sacl); 1795331Samw if (dacl && sacl) { 1805521Sas200622 acl = smb_fsacl_merge(dacl, sacl); 1815331Samw } else if (dacl) { 1825331Samw acl = dacl; 1835331Samw } else { 1845331Samw acl = sacl; 1855331Samw } 1865331Samw 1875521Sas200622 rc = smb_fsacl_to_vsa(acl, &vsecattr, &aclbsize); 1885331Samw 1895331Samw if (dacl && sacl) 1905331Samw acl_free(acl); 1915331Samw 1927619SJose.Borrego@Sun.COM if (rc != 0) 1935331Samw return (rc); 1945331Samw 1955331Samw vsap = &vsecattr; 1967619SJose.Borrego@Sun.COM } else { 1977619SJose.Borrego@Sun.COM vsap = NULL; 1985331Samw } 1995331Samw 2005331Samw if (is_dir) { 2017619SJose.Borrego@Sun.COM rc = smb_vop_mkdir(dir_snode->vp, name, attr, &vp, 2027619SJose.Borrego@Sun.COM flags, cr, vsap); 2035331Samw } else { 2047619SJose.Borrego@Sun.COM rc = smb_vop_create(dir_snode->vp, name, attr, &vp, 2057619SJose.Borrego@Sun.COM flags, cr, vsap); 2065331Samw } 2075331Samw 2085331Samw if (vsap != NULL) 2095331Samw kmem_free(vsap->vsa_aclentp, aclbsize); 2105331Samw 2115331Samw if (rc != 0) 2125331Samw return (rc); 2135331Samw 2145331Samw set_attr.sa_mask = 0; 2155331Samw 2165331Samw /* 2175331Samw * Ideally we should be able to specify the owner and owning 2185331Samw * group at create time along with the ACL. Since we cannot 2195331Samw * do that right now, kcred is passed to smb_vop_setattr so it 2205331Samw * doesn't fail due to lack of permission. 2215331Samw */ 2225331Samw if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 2235331Samw set_attr.sa_vattr.va_uid = fs_sd->sd_uid; 2245331Samw set_attr.sa_mask |= SMB_AT_UID; 2255331Samw } 2265331Samw 2275331Samw if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 2285331Samw set_attr.sa_vattr.va_gid = fs_sd->sd_gid; 2295331Samw set_attr.sa_mask |= SMB_AT_GID; 2305331Samw } 2315331Samw 232*7757SJanice.Chang@Sun.COM if (set_attr.sa_mask) 233*7757SJanice.Chang@Sun.COM rc = smb_vop_setattr(vp, NULL, &set_attr, 0, kcred); 2345331Samw 2357619SJose.Borrego@Sun.COM if (rc == 0) { 2367619SJose.Borrego@Sun.COM *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp, 2377619SJose.Borrego@Sun.COM name, dir_snode, NULL, ret_attr); 2387619SJose.Borrego@Sun.COM 2397619SJose.Borrego@Sun.COM if (*ret_snode == NULL) { 2407619SJose.Borrego@Sun.COM VN_RELE(vp); 2417619SJose.Borrego@Sun.COM rc = ENOMEM; 2427619SJose.Borrego@Sun.COM } 2437619SJose.Borrego@Sun.COM } 2445331Samw } else { 2455331Samw /* 2465331Samw * For filesystems that don't support ACL-on-create, try 2475331Samw * to set the specified SD after create, which could actually 2485331Samw * fail because of conflicts between inherited security 2495331Samw * attributes upon creation and the specified SD. 2505331Samw * 2515331Samw * Passing kcred to smb_fsop_sdwrite() to overcome this issue. 2525331Samw */ 2535331Samw 2545331Samw if (is_dir) { 2557619SJose.Borrego@Sun.COM rc = smb_vop_mkdir(dir_snode->vp, name, attr, &vp, 2567619SJose.Borrego@Sun.COM flags, cr, NULL); 2575331Samw } else { 2587619SJose.Borrego@Sun.COM rc = smb_vop_create(dir_snode->vp, name, attr, &vp, 2597619SJose.Borrego@Sun.COM flags, cr, NULL); 2605331Samw } 2615331Samw 2625521Sas200622 if (rc != 0) 2635521Sas200622 return (rc); 2645521Sas200622 2657619SJose.Borrego@Sun.COM *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp, 2667619SJose.Borrego@Sun.COM name, dir_snode, NULL, ret_attr); 2677619SJose.Borrego@Sun.COM 2687619SJose.Borrego@Sun.COM if (*ret_snode != NULL) { 2697619SJose.Borrego@Sun.COM if (!smb_tree_has_feature(sr->tid_tree, 2707619SJose.Borrego@Sun.COM SMB_TREE_NFS_MOUNTED)) 2717619SJose.Borrego@Sun.COM rc = smb_fsop_sdwrite(sr, kcred, *ret_snode, 2727619SJose.Borrego@Sun.COM fs_sd, 1); 2737619SJose.Borrego@Sun.COM } else { 2745331Samw VN_RELE(vp); 2755331Samw rc = ENOMEM; 2765331Samw } 2775331Samw } 2785331Samw 2795521Sas200622 if (rc != 0) { 2807619SJose.Borrego@Sun.COM if (is_dir) 2817619SJose.Borrego@Sun.COM (void) smb_vop_rmdir(dir_snode->vp, name, flags, cr); 2827619SJose.Borrego@Sun.COM else 2837619SJose.Borrego@Sun.COM (void) smb_vop_remove(dir_snode->vp, name, flags, cr); 2845521Sas200622 } 2855521Sas200622 2865331Samw return (rc); 2875331Samw } 2885331Samw 2895331Samw /* 2905331Samw * smb_fsop_create 2915331Samw * 2925331Samw * All SMB functions should use this wrapper to ensure that 2935331Samw * all the smb_vop_creates are performed with the appropriate credentials. 2945331Samw * Please document any direct calls to explain the reason 2955331Samw * for avoiding this wrapper. 2965331Samw * 2975331Samw * It is assumed that a reference exists on snode coming into this routine. 2985331Samw * 2995331Samw * *ret_snode is returned with a reference upon success. No reference is 3005331Samw * taken if an error is returned. 3015331Samw */ 3025331Samw 3035331Samw int 3045331Samw smb_fsop_create( 3056139Sjb150015 smb_request_t *sr, 3066139Sjb150015 cred_t *cr, 3076139Sjb150015 smb_node_t *dir_snode, 3086139Sjb150015 char *name, 3096139Sjb150015 smb_attr_t *attr, 3106139Sjb150015 smb_node_t **ret_snode, 3116139Sjb150015 smb_attr_t *ret_attr) 3125331Samw { 3135331Samw struct open_param *op = &sr->arg.open; 3146139Sjb150015 smb_node_t *fnode; 3156139Sjb150015 smb_attr_t file_attr; 3166139Sjb150015 vnode_t *xattrdirvp; 3176139Sjb150015 vnode_t *vp; 3186139Sjb150015 char *longname = NULL; 3196139Sjb150015 char *namep; 3206139Sjb150015 char *fname; 3216139Sjb150015 char *sname; 3226139Sjb150015 int is_stream; 3236139Sjb150015 int flags = 0; 3246139Sjb150015 int rc = 0; 3256139Sjb150015 smb_fssd_t fs_sd; 3266139Sjb150015 uint32_t secinfo; 3276139Sjb150015 uint32_t status; 3285331Samw 3295331Samw ASSERT(cr); 3305331Samw ASSERT(dir_snode); 3315331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 3325331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 3335331Samw 3345331Samw ASSERT(ret_snode); 3355331Samw *ret_snode = 0; 3365331Samw 3375331Samw ASSERT(name); 3385331Samw if (*name == 0) 3395331Samw return (EINVAL); 3405331Samw 3415331Samw ASSERT(sr); 3425331Samw ASSERT(sr->tid_tree); 3437348SJose.Borrego@Sun.COM 3447348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 3457348SJose.Borrego@Sun.COM return (EACCES); 3467348SJose.Borrego@Sun.COM 3477348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 3485331Samw return (EROFS); 3495331Samw 3507348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 3515331Samw flags = SMB_IGNORE_CASE; 3525331Samw 3535331Samw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 3545331Samw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 3555331Samw 3565331Samw is_stream = smb_stream_parse_name(name, fname, sname); 3575331Samw 3585331Samw if (is_stream) 3595331Samw namep = fname; 3605331Samw else 3615331Samw namep = name; 3625331Samw 3635331Samw if (smb_maybe_mangled_name(namep)) { 3645331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 3655331Samw 3665331Samw rc = smb_unmangle_name(sr, cr, dir_snode, namep, longname, 3675331Samw MAXNAMELEN, NULL, NULL, 1); 3685331Samw 3695331Samw if ((is_stream == 0) && (rc == 0)) 3705331Samw rc = EEXIST; 3715331Samw 3725331Samw if ((is_stream && rc) || 3735331Samw ((is_stream == 0) && (rc != ENOENT))) { 3745331Samw kmem_free(longname, MAXNAMELEN); 3755331Samw kmem_free(fname, MAXNAMELEN); 3765331Samw kmem_free(sname, MAXNAMELEN); 3775331Samw return (rc); 3785331Samw } 3795331Samw 3805331Samw if (is_stream) 3815331Samw namep = longname; 3825331Samw else 3835331Samw kmem_free(longname, MAXNAMELEN); 3845331Samw } 3855331Samw 3865331Samw if (is_stream) { 3875331Samw /* 3885331Samw * Look up the unnamed stream. 3895331Samw * 3905331Samw * Mangle processing in smb_fsop_lookup() for the unnamed 3915331Samw * stream won't be needed (as it was done above), but 3925331Samw * it may be needed on any link target (which 3935331Samw * smb_fsop_lookup() will provide). 3945331Samw */ 3955331Samw rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, 3965331Samw sr->tid_tree->t_snode, dir_snode, namep, &fnode, &file_attr, 3975331Samw 0, 0); 3985331Samw 3995331Samw if (longname) { 4005331Samw kmem_free(longname, MAXNAMELEN); 4015331Samw namep = NULL; 4025331Samw } 4035331Samw 4045331Samw if (rc != 0) { 4055331Samw kmem_free(fname, MAXNAMELEN); 4065331Samw kmem_free(sname, MAXNAMELEN); 4075331Samw return (rc); 4085331Samw } 4095331Samw 4105331Samw rc = smb_vop_stream_create(fnode->vp, sname, attr, &vp, 4115772Sas200622 &xattrdirvp, flags, cr); 4125331Samw 4135331Samw if (rc != 0) { 4145331Samw smb_node_release(fnode); 4155331Samw kmem_free(fname, MAXNAMELEN); 4165331Samw kmem_free(sname, MAXNAMELEN); 4175331Samw return (rc); 4185331Samw } 4195331Samw 4206030Sjb150015 attr->sa_vattr.va_uid = file_attr.sa_vattr.va_uid; 4216030Sjb150015 attr->sa_vattr.va_gid = file_attr.sa_vattr.va_gid; 4226030Sjb150015 attr->sa_mask = SMB_AT_UID | SMB_AT_GID; 4236030Sjb150015 4246030Sjb150015 /* 4256030Sjb150015 * The second parameter of smb_vop_setattr() is set to 4266030Sjb150015 * NULL, even though an unnamed stream exists. This is 4276030Sjb150015 * because we want to set the UID and GID on the named 4286030Sjb150015 * stream in this case for consistency with the (unnamed 4296030Sjb150015 * stream) file (see comments for smb_vop_setattr()). 4306030Sjb150015 */ 4316030Sjb150015 432*7757SJanice.Chang@Sun.COM rc = smb_vop_setattr(vp, NULL, attr, 0, kcred); 4336030Sjb150015 4346030Sjb150015 if (rc != 0) { 4356030Sjb150015 smb_node_release(fnode); 4366030Sjb150015 kmem_free(fname, MAXNAMELEN); 4376030Sjb150015 kmem_free(sname, MAXNAMELEN); 4386030Sjb150015 return (rc); 4396030Sjb150015 } 4406030Sjb150015 4415331Samw *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, 4425331Samw vp, sname, ret_attr); 4435331Samw 4445331Samw smb_node_release(fnode); 4455331Samw 4465331Samw if (*ret_snode == NULL) { 4475331Samw VN_RELE(xattrdirvp); 4485331Samw VN_RELE(vp); 4495331Samw kmem_free(fname, MAXNAMELEN); 4505331Samw kmem_free(sname, MAXNAMELEN); 4515331Samw return (ENOMEM); 4525331Samw } 4535331Samw } else { 4545521Sas200622 if (op->sd) { 4555331Samw /* 4565331Samw * SD sent by client in Windows format. Needs to be 4575331Samw * converted to FS format. No inheritance. 4585331Samw */ 4595521Sas200622 secinfo = smb_sd_get_secinfo(op->sd); 4605521Sas200622 smb_fssd_init(&fs_sd, secinfo, 0); 4615521Sas200622 4625521Sas200622 status = smb_sd_tofs(op->sd, &fs_sd); 4635331Samw if (status == NT_STATUS_SUCCESS) { 4645331Samw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 4655331Samw name, attr, ret_snode, ret_attr, &fs_sd); 4665331Samw } 4675331Samw else 4685331Samw rc = EINVAL; 4695521Sas200622 smb_fssd_term(&fs_sd); 4705331Samw } else if (sr->tid_tree->t_acltype == ACE_T) { 4715331Samw /* 4725331Samw * No incoming SD and filesystem is ZFS 4735331Samw * Server applies Windows inheritance rules, 4745331Samw * see smb_fsop_sdinherit() comments as to why. 4755331Samw */ 4765521Sas200622 smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, 0); 4775331Samw rc = smb_fsop_sdinherit(sr, dir_snode, &fs_sd); 4785331Samw if (rc == 0) { 4795331Samw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 4805331Samw name, attr, ret_snode, ret_attr, &fs_sd); 4815331Samw } 4825331Samw 4835521Sas200622 smb_fssd_term(&fs_sd); 4845331Samw } else { 4855331Samw /* 4865331Samw * No incoming SD and filesystem is not ZFS 4875331Samw * let the filesystem handles the inheritance. 4885331Samw */ 4895331Samw rc = smb_vop_create(dir_snode->vp, name, attr, &vp, 4905772Sas200622 flags, cr, NULL); 4915331Samw 4925331Samw if (rc == 0) { 4935331Samw *ret_snode = smb_node_lookup(sr, op, cr, vp, 4945331Samw name, dir_snode, NULL, ret_attr); 4955331Samw 4965331Samw if (*ret_snode == NULL) { 4975331Samw VN_RELE(vp); 4985331Samw rc = ENOMEM; 4995331Samw } 5005331Samw } 5015331Samw 5025331Samw } 5035331Samw } 5045331Samw 5055331Samw kmem_free(fname, MAXNAMELEN); 5065331Samw kmem_free(sname, MAXNAMELEN); 5075331Samw return (rc); 5085331Samw } 5095331Samw 5105331Samw /* 5115331Samw * smb_fsop_mkdir 5125331Samw * 5135331Samw * All SMB functions should use this wrapper to ensure that 5145331Samw * the the calls are performed with the appropriate credentials. 5155331Samw * Please document any direct call to explain the reason 5165331Samw * for avoiding this wrapper. 5175331Samw * 5185331Samw * It is assumed that a reference exists on snode coming into this routine. 5195331Samw * 5205331Samw * *ret_snode is returned with a reference upon success. No reference is 5215331Samw * taken if an error is returned. 5225331Samw */ 5235331Samw int 5245331Samw smb_fsop_mkdir( 5256139Sjb150015 smb_request_t *sr, 5265331Samw cred_t *cr, 5275331Samw smb_node_t *dir_snode, 5285331Samw char *name, 5295331Samw smb_attr_t *attr, 5305331Samw smb_node_t **ret_snode, 5315331Samw smb_attr_t *ret_attr) 5325331Samw { 5335331Samw struct open_param *op = &sr->arg.open; 5345331Samw char *longname; 5355331Samw vnode_t *vp; 5365331Samw int flags = 0; 5375331Samw smb_fssd_t fs_sd; 5385331Samw uint32_t secinfo; 5395331Samw uint32_t status; 5405331Samw int rc; 5415331Samw ASSERT(cr); 5425331Samw ASSERT(dir_snode); 5435331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 5445331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 5455331Samw 5465331Samw ASSERT(ret_snode); 5475331Samw *ret_snode = 0; 5485331Samw 5495331Samw ASSERT(name); 5505331Samw if (*name == 0) 5515331Samw return (EINVAL); 5525331Samw 5535331Samw ASSERT(sr); 5545331Samw ASSERT(sr->tid_tree); 5557348SJose.Borrego@Sun.COM 5567348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 5577348SJose.Borrego@Sun.COM return (EACCES); 5587348SJose.Borrego@Sun.COM 5597348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 5605331Samw return (EROFS); 5615331Samw 5625331Samw if (smb_maybe_mangled_name(name)) { 5635331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 5645331Samw rc = smb_unmangle_name(sr, cr, dir_snode, name, longname, 5655331Samw MAXNAMELEN, NULL, NULL, 1); 5665331Samw 5675331Samw kmem_free(longname, MAXNAMELEN); 5685331Samw 5695331Samw /* 5705331Samw * If the name passed in by the client has an unmangled 5715331Samw * equivalent that is found in the specified directory, 5725331Samw * then the mkdir cannot succeed. Return EEXIST. 5735331Samw * 5745331Samw * Only if ENOENT is returned will a mkdir be attempted. 5755331Samw */ 5765331Samw 5775331Samw if (rc == 0) 5785331Samw rc = EEXIST; 5795331Samw 5805331Samw if (rc != ENOENT) 5815331Samw return (rc); 5825331Samw } 5835331Samw 5847348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 5855331Samw flags = SMB_IGNORE_CASE; 5865331Samw 5875521Sas200622 if (op->sd) { 5885331Samw /* 5895331Samw * SD sent by client in Windows format. Needs to be 5905331Samw * converted to FS format. No inheritance. 5915331Samw */ 5925521Sas200622 secinfo = smb_sd_get_secinfo(op->sd); 5935521Sas200622 smb_fssd_init(&fs_sd, secinfo, SMB_FSSD_FLAGS_DIR); 5945521Sas200622 5955521Sas200622 status = smb_sd_tofs(op->sd, &fs_sd); 5965331Samw if (status == NT_STATUS_SUCCESS) { 5975331Samw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 5985331Samw name, attr, ret_snode, ret_attr, &fs_sd); 5995331Samw } 6005331Samw else 6015331Samw rc = EINVAL; 6025521Sas200622 smb_fssd_term(&fs_sd); 6035331Samw } else if (sr->tid_tree->t_acltype == ACE_T) { 6045331Samw /* 6055331Samw * No incoming SD and filesystem is ZFS 6065331Samw * Server applies Windows inheritance rules, 6075331Samw * see smb_fsop_sdinherit() comments as to why. 6085331Samw */ 6095521Sas200622 smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, SMB_FSSD_FLAGS_DIR); 6105331Samw rc = smb_fsop_sdinherit(sr, dir_snode, &fs_sd); 6115331Samw if (rc == 0) { 6125331Samw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 6135331Samw name, attr, ret_snode, ret_attr, &fs_sd); 6145331Samw } 6155331Samw 6165521Sas200622 smb_fssd_term(&fs_sd); 6175331Samw 6185331Samw } else { 6195331Samw rc = smb_vop_mkdir(dir_snode->vp, name, attr, &vp, flags, cr, 6205772Sas200622 NULL); 6215331Samw 6225331Samw if (rc == 0) { 6235331Samw *ret_snode = smb_node_lookup(sr, op, cr, vp, name, 6245331Samw dir_snode, NULL, ret_attr); 6255331Samw 6265331Samw if (*ret_snode == NULL) { 6275331Samw VN_RELE(vp); 6285331Samw rc = ENOMEM; 6295331Samw } 6305331Samw } 6315331Samw } 6325331Samw 6335331Samw return (rc); 6345331Samw } 6355331Samw 6365331Samw /* 6375331Samw * smb_fsop_remove 6385331Samw * 6395331Samw * All SMB functions should use this wrapper to ensure that 6405331Samw * the the calls are performed with the appropriate credentials. 6415331Samw * Please document any direct call to explain the reason 6425331Samw * for avoiding this wrapper. 6435331Samw * 6445331Samw * It is assumed that a reference exists on snode coming into this routine. 6455331Samw * 6465331Samw * od: This means that the name passed in is an on-disk name. 6475331Samw * A null smb_request might be passed to this function. 6485331Samw */ 6495331Samw 6505331Samw int 6515331Samw smb_fsop_remove( 6526139Sjb150015 smb_request_t *sr, 6536139Sjb150015 cred_t *cr, 6546139Sjb150015 smb_node_t *dir_snode, 6556139Sjb150015 char *name, 6566139Sjb150015 int od) 6575331Samw { 6586139Sjb150015 smb_node_t *fnode; 6596139Sjb150015 smb_attr_t file_attr; 6606139Sjb150015 char *longname; 6616139Sjb150015 char *fname; 6626139Sjb150015 char *sname; 6636139Sjb150015 int flags = 0; 6646139Sjb150015 int rc; 6655331Samw 6665331Samw ASSERT(cr); 6675331Samw /* 6685331Samw * The state of the node could be SMB_NODE_STATE_DESTROYING if this 6695331Samw * function is called during the deletion of the node (because of 6705331Samw * DELETE_ON_CLOSE). 6715331Samw */ 6725331Samw ASSERT(dir_snode); 6735331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 6745331Samw 6757348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 6765331Samw return (EACCES); 6775331Samw 6787348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 6795331Samw return (EROFS); 6805331Samw 6815331Samw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 6825331Samw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 6835331Samw 6845967Scp160787 /* 6855967Scp160787 * If the passed-in name is an on-disk name, 6865967Scp160787 * then we need to do a case-sensitive remove. 6875967Scp160787 * This is important if the on-disk name 6885967Scp160787 * corresponds to a mangled name passed in by 6895967Scp160787 * the client. We want to make sure to remove 6905967Scp160787 * the exact file specified by the client, 6915967Scp160787 * instead of letting the underlying file system 6925967Scp160787 * do a remove on the "first match." 6935967Scp160787 */ 6945967Scp160787 6957348SJose.Borrego@Sun.COM if ((od == 0) && SMB_TREE_IS_CASEINSENSITIVE(sr)) 6965967Scp160787 flags = SMB_IGNORE_CASE; 6975967Scp160787 6985967Scp160787 if (dir_snode->flags & NODE_XATTR_DIR) { 6995967Scp160787 rc = smb_vop_stream_remove(dir_snode->dir_snode->vp, 7005967Scp160787 name, flags, cr); 7015967Scp160787 } else if (smb_stream_parse_name(name, fname, sname)) { 7025967Scp160787 /* 7035967Scp160787 * It is assumed that "name" corresponds to the path 7045967Scp160787 * passed in by the client, and no need of suppressing 7055967Scp160787 * case-insensitive lookups is needed. 7065967Scp160787 */ 7075331Samw 7085331Samw ASSERT(od == 0); 7095331Samw 7105331Samw /* 7115331Samw * Look up the unnamed stream (i.e. fname). 7125331Samw * Unmangle processing will be done on fname 7135331Samw * as well as any link target. 7145331Samw */ 7155331Samw 7165331Samw rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, 7175331Samw sr->tid_tree->t_snode, dir_snode, fname, &fnode, &file_attr, 7185331Samw 0, 0); 7195331Samw 7205331Samw if (rc != 0) { 7215331Samw kmem_free(fname, MAXNAMELEN); 7225331Samw kmem_free(sname, MAXNAMELEN); 7235331Samw return (rc); 7245331Samw } 7255331Samw 7265331Samw /* 7275331Samw * XXX 7285331Samw * Need to find out what permission is required by NTFS 7295331Samw * to remove a stream. 7305331Samw */ 7315772Sas200622 rc = smb_vop_stream_remove(fnode->vp, sname, flags, cr); 7325331Samw 7335331Samw smb_node_release(fnode); 7345331Samw } else { 7355772Sas200622 rc = smb_vop_remove(dir_snode->vp, name, flags, cr); 7365331Samw 7375331Samw if (rc == ENOENT) { 7385331Samw if (smb_maybe_mangled_name(name) == 0) { 7395331Samw kmem_free(fname, MAXNAMELEN); 7405331Samw kmem_free(sname, MAXNAMELEN); 7415331Samw return (rc); 7425331Samw } 7435331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 7445331Samw 7455331Samw rc = smb_unmangle_name(sr, cr, dir_snode, name, 7465331Samw longname, MAXNAMELEN, NULL, NULL, 1); 7475331Samw 7485331Samw if (rc == 0) { 7495331Samw /* 7505331Samw * We passed "1" as the "od" parameter 7515331Samw * to smb_unmangle_name(), such that longname 7525331Samw * is the real (case-sensitive) on-disk name. 7535331Samw * We make sure we do a remove on this exact 7545331Samw * name, as the name was mangled and denotes 7555331Samw * a unique file. 7565331Samw */ 7575331Samw flags &= ~SMB_IGNORE_CASE; 7585331Samw rc = smb_vop_remove(dir_snode->vp, longname, 7595772Sas200622 flags, cr); 7605331Samw } 7615331Samw 7625331Samw kmem_free(longname, MAXNAMELEN); 7635331Samw } 7645331Samw } 7655331Samw 7665331Samw kmem_free(fname, MAXNAMELEN); 7675331Samw kmem_free(sname, MAXNAMELEN); 7685331Samw return (rc); 7695331Samw } 7705331Samw 7715331Samw /* 7725331Samw * smb_fsop_remove_streams 7735331Samw * 7745331Samw * This function removes a file's streams without removing the 7755331Samw * file itself. 7765331Samw * 7775331Samw * It is assumed that snode is not a link. 7785331Samw */ 7795331Samw int 7806139Sjb150015 smb_fsop_remove_streams(smb_request_t *sr, cred_t *cr, smb_node_t *fnode) 7815331Samw { 7825331Samw struct fs_stream_info stream_info; 7835331Samw uint32_t cookie = 0; 7845331Samw int flags = 0; 7855331Samw int rc; 7865331Samw 7877348SJose.Borrego@Sun.COM ASSERT(sr); 7885331Samw ASSERT(cr); 7895331Samw ASSERT(fnode); 7905331Samw ASSERT(fnode->n_magic == SMB_NODE_MAGIC); 7915331Samw ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING); 7925331Samw 7937348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, fnode) == 0) 7945331Samw return (EACCES); 7955331Samw 7967348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 7975331Samw return (EROFS); 7985331Samw 7997348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 8005331Samw flags = SMB_IGNORE_CASE; 8015331Samw 8025331Samw for (;;) { 8035331Samw rc = smb_vop_stream_readdir(fnode->vp, &cookie, &stream_info, 8045772Sas200622 NULL, NULL, flags, cr); 8055331Samw 8065331Samw if ((rc != 0) || (cookie == SMB_EOF)) 8075331Samw break; 8085331Samw 8095331Samw (void) smb_vop_stream_remove(fnode->vp, stream_info.name, flags, 8105772Sas200622 cr); 8115331Samw } 8125331Samw return (rc); 8135331Samw } 8145331Samw 8155331Samw /* 8165331Samw * smb_fsop_rmdir 8175331Samw * 8185331Samw * All SMB functions should use this wrapper to ensure that 8195331Samw * the the calls are performed with the appropriate credentials. 8205331Samw * Please document any direct call to explain the reason 8215331Samw * for avoiding this wrapper. 8225331Samw * 8235331Samw * It is assumed that a reference exists on snode coming into this routine. 8245331Samw * 8255331Samw * od: This means that the name passed in is an on-disk name. 8265331Samw */ 8275331Samw 8285331Samw int 8295331Samw smb_fsop_rmdir( 8306139Sjb150015 smb_request_t *sr, 8316139Sjb150015 cred_t *cr, 8326139Sjb150015 smb_node_t *dir_snode, 8336139Sjb150015 char *name, 8346139Sjb150015 int od) 8355331Samw { 8366139Sjb150015 int rc; 8376139Sjb150015 int flags = 0; 8386139Sjb150015 char *longname; 8395331Samw 8405331Samw ASSERT(cr); 8415331Samw /* 8425331Samw * The state of the node could be SMB_NODE_STATE_DESTROYING if this 8435331Samw * function is called during the deletion of the node (because of 8445331Samw * DELETE_ON_CLOSE). 8455331Samw */ 8465331Samw ASSERT(dir_snode); 8475331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 8485331Samw 8497348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 8505331Samw return (EACCES); 8515331Samw 8527348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 8535331Samw return (EROFS); 8545331Samw 8555331Samw /* 8565331Samw * If the passed-in name is an on-disk name, 8575331Samw * then we need to do a case-sensitive rmdir. 8585331Samw * This is important if the on-disk name 8595331Samw * corresponds to a mangled name passed in by 8605331Samw * the client. We want to make sure to remove 8615331Samw * the exact directory specified by the client, 8625331Samw * instead of letting the underlying file system 8635331Samw * do a rmdir on the "first match." 8645331Samw */ 8655331Samw 8667348SJose.Borrego@Sun.COM if ((od == 0) && SMB_TREE_IS_CASEINSENSITIVE(sr)) 8675331Samw flags = SMB_IGNORE_CASE; 8685331Samw 8695772Sas200622 rc = smb_vop_rmdir(dir_snode->vp, name, flags, cr); 8705331Samw 8715331Samw if (rc == ENOENT) { 8725331Samw if (smb_maybe_mangled_name(name) == 0) 8735331Samw return (rc); 8745331Samw 8755331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 8765331Samw 8775331Samw rc = smb_unmangle_name(sr, cr, dir_snode, 8785331Samw name, longname, MAXNAMELEN, NULL, 8795331Samw NULL, 1); 8805331Samw 8815331Samw if (rc == 0) { 8825331Samw /* 8835331Samw * We passed "1" as the "od" parameter 8845331Samw * to smb_unmangle_name(), such that longname 8855331Samw * is the real (case-sensitive) on-disk name. 8865331Samw * We make sure we do a rmdir on this exact 8875331Samw * name, as the name was mangled and denotes 8885331Samw * a unique directory. 8895331Samw */ 8905331Samw flags &= ~SMB_IGNORE_CASE; 8915772Sas200622 rc = smb_vop_rmdir(dir_snode->vp, longname, flags, cr); 8925331Samw } 8935331Samw 8945331Samw kmem_free(longname, MAXNAMELEN); 8955331Samw } 8965331Samw 8975331Samw return (rc); 8985331Samw } 8995331Samw 9005331Samw /* 9015331Samw * smb_fsop_getattr 9025331Samw * 9035331Samw * All SMB functions should use this wrapper to ensure that 9045331Samw * the the calls are performed with the appropriate credentials. 9055331Samw * Please document any direct call to explain the reason 9065331Samw * for avoiding this wrapper. 9075331Samw * 9085331Samw * It is assumed that a reference exists on snode coming into this routine. 9095331Samw */ 9105331Samw int 9116139Sjb150015 smb_fsop_getattr(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 9125331Samw smb_attr_t *attr) 9135331Samw { 9145331Samw smb_node_t *unnamed_node; 9155331Samw vnode_t *unnamed_vp = NULL; 9165331Samw uint32_t status; 9175331Samw uint32_t access = 0; 9185331Samw int flags = 0; 9195772Sas200622 int rc; 9205331Samw 9215331Samw ASSERT(cr); 9225331Samw ASSERT(snode); 9235331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 9245331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 9255331Samw 9267348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0) 9275331Samw return (EACCES); 9285331Samw 9295331Samw if (sr->fid_ofile) { 9305331Samw /* if uid and/or gid is requested */ 9315331Samw if (attr->sa_mask & (SMB_AT_UID|SMB_AT_GID)) 9325331Samw access |= READ_CONTROL; 9335331Samw 9345331Samw /* if anything else is also requested */ 9355331Samw if (attr->sa_mask & ~(SMB_AT_UID|SMB_AT_GID)) 9365331Samw access |= FILE_READ_ATTRIBUTES; 9375331Samw 9385331Samw status = smb_ofile_access(sr->fid_ofile, cr, access); 9395331Samw if (status != NT_STATUS_SUCCESS) 9405331Samw return (EACCES); 9415331Samw 9427348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, 9437348SJose.Borrego@Sun.COM SMB_TREE_ACEMASKONACCESS)) 9445331Samw flags = ATTR_NOACLCHECK; 9455331Samw } 9465331Samw 9475331Samw unnamed_node = SMB_IS_STREAM(snode); 9485331Samw 9495331Samw if (unnamed_node) { 9505331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 9515331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 9525331Samw unnamed_vp = unnamed_node->vp; 9535331Samw } 9545331Samw 9555772Sas200622 rc = smb_vop_getattr(snode->vp, unnamed_vp, attr, flags, cr); 9565772Sas200622 if (rc == 0) 9575772Sas200622 snode->attr = *attr; 9585772Sas200622 9595772Sas200622 return (rc); 9605331Samw } 9615331Samw 9625331Samw /* 9635331Samw * smb_fsop_readdir 9645331Samw * 9655331Samw * All SMB functions should use this smb_fsop_readdir wrapper to ensure that 9665331Samw * the smb_vop_readdir is performed with the appropriate credentials. 9675331Samw * Please document any direct call to smb_vop_readdir to explain the reason 9685331Samw * for avoiding this wrapper. 9695331Samw * 9705331Samw * It is assumed that a reference exists on snode coming into this routine. 9715331Samw */ 9725331Samw int 9735331Samw smb_fsop_readdir( 9746139Sjb150015 smb_request_t *sr, 9755331Samw cred_t *cr, 9765331Samw smb_node_t *dir_snode, 9775331Samw uint32_t *cookie, 9785331Samw char *name, 9795331Samw int *namelen, 9805331Samw ino64_t *fileid, 9815331Samw struct fs_stream_info *stream_info, 9825331Samw smb_node_t **ret_snode, 9835331Samw smb_attr_t *ret_attr) 9845331Samw { 9856139Sjb150015 smb_node_t *ret_snodep; 9866139Sjb150015 smb_node_t *fnode; 9876139Sjb150015 smb_attr_t tmp_attr; 9886139Sjb150015 vnode_t *xattrdirvp; 9896139Sjb150015 vnode_t *fvp; 9906139Sjb150015 vnode_t *vp = NULL; 9916139Sjb150015 char *od_name; 9926139Sjb150015 int rc; 9936139Sjb150015 int flags = 0; 9945331Samw 9955331Samw ASSERT(cr); 9965331Samw ASSERT(dir_snode); 9975331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 9985331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 9995331Samw 10007348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 10015331Samw return (EACCES); 10025331Samw 10035331Samw if (*cookie == SMB_EOF) { 10045331Samw *namelen = 0; 10055331Samw return (0); 10065331Samw } 10075331Samw 10087348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 10095331Samw flags = SMB_IGNORE_CASE; 10105331Samw 10115331Samw od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 10125331Samw 10135331Samw if (stream_info) { 10145331Samw rc = smb_vop_lookup(dir_snode->vp, name, &fvp, od_name, 10155772Sas200622 SMB_FOLLOW_LINKS, sr->tid_tree->t_snode->vp, cr); 10165331Samw 10175331Samw if (rc != 0) { 10185331Samw kmem_free(od_name, MAXNAMELEN); 10195331Samw return (rc); 10205331Samw } 10215331Samw 10225331Samw fnode = smb_node_lookup(sr, NULL, cr, fvp, od_name, dir_snode, 10235331Samw NULL, ret_attr); 10245331Samw 10255331Samw kmem_free(od_name, MAXNAMELEN); 10265331Samw 10275331Samw if (fnode == NULL) { 10285331Samw VN_RELE(fvp); 10295331Samw return (ENOMEM); 10305331Samw } 10315331Samw 10325331Samw /* 10335331Samw * XXX 10345331Samw * Need to find out what permission(s) NTFS requires for getting 10355331Samw * a file's streams list. 10365331Samw * 10375331Samw * Might have to use kcred. 10385331Samw */ 10395331Samw rc = smb_vop_stream_readdir(fvp, cookie, stream_info, &vp, 10405772Sas200622 &xattrdirvp, flags, cr); 10415331Samw 10425331Samw if ((rc != 0) || (*cookie == SMB_EOF)) { 10435331Samw smb_node_release(fnode); 10445331Samw return (rc); 10455331Samw } 10465331Samw 10475331Samw ret_snodep = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, 10485331Samw vp, stream_info->name, &tmp_attr); 10495331Samw 10505331Samw smb_node_release(fnode); 10515331Samw 10525331Samw if (ret_snodep == NULL) { 10535331Samw VN_RELE(xattrdirvp); 10545331Samw VN_RELE(vp); 10555331Samw return (ENOMEM); 10565331Samw } 10575331Samw 10585331Samw stream_info->size = tmp_attr.sa_vattr.va_size; 10595331Samw 10605331Samw if (ret_attr) 10615331Samw *ret_attr = tmp_attr; 10625331Samw 10635331Samw if (ret_snode) 10645331Samw *ret_snode = ret_snodep; 10655331Samw else 10665331Samw smb_node_release(ret_snodep); 10675331Samw 10685331Samw } else { 10695331Samw rc = smb_vop_readdir(dir_snode->vp, cookie, name, namelen, 10705772Sas200622 fileid, &vp, od_name, flags, cr); 10715331Samw 10725331Samw if (rc != 0) { 10735331Samw kmem_free(od_name, MAXNAMELEN); 10745331Samw return (rc); 10755331Samw } 10765331Samw 10775331Samw if (*namelen) { 10785331Samw ASSERT(vp); 10795331Samw if (ret_attr || ret_snode) { 10805331Samw ret_snodep = smb_node_lookup(sr, NULL, cr, vp, 10815331Samw od_name, dir_snode, NULL, &tmp_attr); 10825331Samw 10835331Samw if (ret_snodep == NULL) { 10845331Samw kmem_free(od_name, MAXNAMELEN); 10855331Samw VN_RELE(vp); 10865331Samw return (ENOMEM); 10875331Samw } 10885331Samw 10895331Samw if (ret_attr) 10905331Samw *ret_attr = tmp_attr; 10915331Samw 10925331Samw if (ret_snode) 10935331Samw *ret_snode = ret_snodep; 10945331Samw else 10955331Samw smb_node_release(ret_snodep); 10965331Samw } 10975331Samw } 10985331Samw 10995331Samw kmem_free(od_name, MAXNAMELEN); 11005331Samw } 11015331Samw 11025331Samw return (rc); 11035331Samw } 11045331Samw 11055331Samw /* 11065331Samw * smb_fsop_getdents 11075331Samw * 11085331Samw * All SMB functions should use this smb_vop_getdents wrapper to ensure that 11095331Samw * the smb_vop_getdents is performed with the appropriate credentials. 11105331Samw * Please document any direct call to smb_vop_getdents to explain the reason 11115331Samw * for avoiding this wrapper. 11125331Samw * 11135331Samw * It is assumed that a reference exists on snode coming into this routine. 11145331Samw */ 11155331Samw /*ARGSUSED*/ 11165331Samw int 11175331Samw smb_fsop_getdents( 11185331Samw struct smb_request *sr, 11195331Samw cred_t *cr, 11205331Samw smb_node_t *dir_snode, 11215331Samw uint32_t *cookie, 11225331Samw uint64_t *verifierp, 11235331Samw int32_t *maxcnt, 11245331Samw char *args, 11255331Samw char *pattern) 11265331Samw { 11275331Samw int flags = 0; 11285331Samw 11295331Samw ASSERT(cr); 11305331Samw ASSERT(dir_snode); 11315331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 11325331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 11335331Samw 11347348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 11355331Samw return (EACCES); 11365331Samw 11377348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 11385331Samw flags = SMB_IGNORE_CASE; 11395331Samw 11405331Samw return (smb_vop_getdents(dir_snode, cookie, 0, maxcnt, args, pattern, 11415772Sas200622 flags, sr, cr)); 11425331Samw } 11435331Samw 11445331Samw /* 11455331Samw * smb_fsop_rename 11465331Samw * 11475331Samw * All SMB functions should use this smb_vop_rename wrapper to ensure that 11485331Samw * the smb_vop_rename is performed with the appropriate credentials. 11495331Samw * Please document any direct call to smb_vop_rename to explain the reason 11505331Samw * for avoiding this wrapper. 11515331Samw * 11525331Samw * It is assumed that references exist on from_dir_snode and to_dir_snode coming 11535331Samw * into this routine. 11545331Samw */ 11555331Samw int 11565331Samw smb_fsop_rename( 11576139Sjb150015 smb_request_t *sr, 11585331Samw cred_t *cr, 11595331Samw smb_node_t *from_dir_snode, 11605331Samw char *from_name, 11615331Samw smb_node_t *to_dir_snode, 11625331Samw char *to_name) 11635331Samw { 11645331Samw smb_node_t *from_snode; 11655331Samw smb_attr_t tmp_attr; 11665331Samw vnode_t *from_vp; 11675331Samw int flags = 0; 11685331Samw int rc; 11695331Samw 11705331Samw ASSERT(cr); 11715331Samw ASSERT(from_dir_snode); 11725331Samw ASSERT(from_dir_snode->n_magic == SMB_NODE_MAGIC); 11735331Samw ASSERT(from_dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 11745331Samw 11755331Samw ASSERT(to_dir_snode); 11765331Samw ASSERT(to_dir_snode->n_magic == SMB_NODE_MAGIC); 11775331Samw ASSERT(to_dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 11785331Samw 11797348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, from_dir_snode) == 0) 11805331Samw return (EACCES); 11815331Samw 11827348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, to_dir_snode) == 0) 11835331Samw return (EACCES); 11845331Samw 11855331Samw ASSERT(sr); 11865331Samw ASSERT(sr->tid_tree); 11877348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 11885331Samw return (EROFS); 11895331Samw 11905331Samw /* 11917348SJose.Borrego@Sun.COM * Note: There is no need to check SMB_TREE_IS_CASEINSENSITIVE 11925331Samw * here. 11935331Samw * 11945331Samw * A case-sensitive rename is always done in this routine 11955331Samw * because we are using the on-disk name from an earlier lookup. 11965331Samw * If a mangled name was passed in by the caller (denoting a 11975331Samw * deterministic lookup), then the exact file must be renamed 11985331Samw * (i.e. SMB_IGNORE_CASE must not be passed to VOP_RENAME, or 11995331Samw * else the underlying file system might return a "first-match" 12005331Samw * on this on-disk name, possibly resulting in the wrong file). 12015331Samw */ 12025331Samw 12035331Samw /* 12045331Samw * XXX: Lock required through smb_node_release() below? 12055331Samw */ 12065331Samw 12075331Samw rc = smb_vop_lookup(from_dir_snode->vp, from_name, &from_vp, NULL, 0, 12085772Sas200622 NULL, cr); 12095331Samw 12105331Samw if (rc != 0) 12115331Samw return (rc); 12125331Samw 12135331Samw rc = smb_vop_rename(from_dir_snode->vp, from_name, to_dir_snode->vp, 12145772Sas200622 to_name, flags, cr); 12155331Samw 12165331Samw if (rc == 0) { 12175331Samw from_snode = smb_node_lookup(sr, NULL, cr, from_vp, from_name, 12185331Samw from_dir_snode, NULL, &tmp_attr); 12195331Samw 12205331Samw if (from_snode == NULL) { 12215331Samw VN_RELE(from_vp); 12225331Samw return (ENOMEM); 12235331Samw } 12245331Samw 12255331Samw (void) smb_node_rename(from_dir_snode, from_snode, to_dir_snode, 12265331Samw to_name); 12275331Samw 12285331Samw smb_node_release(from_snode); 12295331Samw } else { 12305331Samw VN_RELE(from_vp); 12315331Samw } 12325331Samw 12335331Samw /* XXX: unlock */ 12345331Samw 12355331Samw return (rc); 12365331Samw } 12375331Samw 12385331Samw /* 12395331Samw * smb_fsop_setattr 12405331Samw * 12415331Samw * All SMB functions should use this wrapper to ensure that 12425331Samw * the the calls are performed with the appropriate credentials. 12435331Samw * Please document any direct call to explain the reason 12445331Samw * for avoiding this wrapper. 12455331Samw * 12465331Samw * It is assumed that a reference exists on snode coming into this routine. 12475331Samw * A null smb_request might be passed to this function. 12485331Samw */ 12495331Samw int 12505331Samw smb_fsop_setattr( 12516139Sjb150015 smb_request_t *sr, 12526139Sjb150015 cred_t *cr, 12536139Sjb150015 smb_node_t *snode, 12546139Sjb150015 smb_attr_t *set_attr, 12556139Sjb150015 smb_attr_t *ret_attr) 12565331Samw { 12575331Samw smb_node_t *unnamed_node; 12585331Samw vnode_t *unnamed_vp = NULL; 12595331Samw uint32_t status; 12607619SJose.Borrego@Sun.COM uint32_t access; 12615331Samw int rc = 0; 12625331Samw int flags = 0; 12637619SJose.Borrego@Sun.COM uint_t sa_mask; 12645331Samw 12655331Samw ASSERT(cr); 12665331Samw ASSERT(snode); 12675331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 12685331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 12695331Samw 12707348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0) 12715331Samw return (EACCES); 12725331Samw 12737348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 12745331Samw return (EROFS); 12755331Samw 12767348SJose.Borrego@Sun.COM if (sr && (set_attr->sa_mask & SMB_AT_SIZE)) { 12777348SJose.Borrego@Sun.COM if (sr->fid_ofile) { 12787348SJose.Borrego@Sun.COM if (SMB_OFILE_IS_READONLY(sr->fid_ofile)) 12797348SJose.Borrego@Sun.COM return (EACCES); 12807348SJose.Borrego@Sun.COM } else { 12817348SJose.Borrego@Sun.COM if (SMB_PATHFILE_IS_READONLY(sr, snode)) 12827348SJose.Borrego@Sun.COM return (EACCES); 12837348SJose.Borrego@Sun.COM } 12847348SJose.Borrego@Sun.COM } 12857348SJose.Borrego@Sun.COM 12865331Samw /* sr could be NULL in some cases */ 12875331Samw if (sr && sr->fid_ofile) { 12887619SJose.Borrego@Sun.COM sa_mask = set_attr->sa_mask; 12897619SJose.Borrego@Sun.COM access = 0; 12907619SJose.Borrego@Sun.COM 12917619SJose.Borrego@Sun.COM if (sa_mask & SMB_AT_SIZE) { 12927619SJose.Borrego@Sun.COM access |= FILE_WRITE_DATA; 12937619SJose.Borrego@Sun.COM sa_mask &= ~SMB_AT_SIZE; 12947619SJose.Borrego@Sun.COM } 12957619SJose.Borrego@Sun.COM 12967619SJose.Borrego@Sun.COM if (sa_mask & (SMB_AT_UID|SMB_AT_GID)) { 12975331Samw access |= WRITE_OWNER; 12987619SJose.Borrego@Sun.COM sa_mask &= ~(SMB_AT_UID|SMB_AT_GID); 12997619SJose.Borrego@Sun.COM } 13007619SJose.Borrego@Sun.COM 13017619SJose.Borrego@Sun.COM if (sa_mask) 13025331Samw access |= FILE_WRITE_ATTRIBUTES; 13035331Samw 13045331Samw status = smb_ofile_access(sr->fid_ofile, cr, access); 13055331Samw if (status != NT_STATUS_SUCCESS) 13065331Samw return (EACCES); 13075331Samw 13087348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, 13097348SJose.Borrego@Sun.COM SMB_TREE_ACEMASKONACCESS)) 13105331Samw flags = ATTR_NOACLCHECK; 13115331Samw } 13125331Samw 13135331Samw unnamed_node = SMB_IS_STREAM(snode); 13145331Samw 13155331Samw if (unnamed_node) { 13165331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 13175331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 13185331Samw unnamed_vp = unnamed_node->vp; 13195331Samw } 1320*7757SJanice.Chang@Sun.COM 1321*7757SJanice.Chang@Sun.COM rc = smb_vop_setattr(snode->vp, unnamed_vp, set_attr, flags, cr); 13225331Samw 13235331Samw if ((rc == 0) && ret_attr) { 13245331Samw /* 13255772Sas200622 * Use kcred to update the node attr because this 13265772Sas200622 * call is not being made on behalf of the user. 13275331Samw */ 13285331Samw ret_attr->sa_mask = SMB_AT_ALL; 13297348SJose.Borrego@Sun.COM rc = smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, flags, 13307348SJose.Borrego@Sun.COM kcred); 13315772Sas200622 if (rc == 0) 13325772Sas200622 snode->attr = *ret_attr; 13335331Samw } 13345331Samw 13355331Samw return (rc); 13365331Samw } 13375331Samw 13385331Samw /* 13395331Samw * smb_fsop_read 13405331Samw * 13415331Samw * All SMB functions should use this wrapper to ensure that 13425331Samw * the the calls are performed with the appropriate credentials. 13435331Samw * Please document any direct call to explain the reason 13445331Samw * for avoiding this wrapper. 13455331Samw * 13465331Samw * It is assumed that a reference exists on snode coming into this routine. 13475331Samw */ 13485331Samw int 13495331Samw smb_fsop_read( 13505331Samw struct smb_request *sr, 13515331Samw cred_t *cr, 13525331Samw smb_node_t *snode, 13535331Samw uio_t *uio, 13545331Samw smb_attr_t *ret_attr) 13555331Samw { 13565331Samw smb_node_t *unnamed_node; 13575331Samw vnode_t *unnamed_vp = NULL; 13587348SJose.Borrego@Sun.COM caller_context_t ct; 13595772Sas200622 int svmand; 13605331Samw int rc; 13615331Samw 13625331Samw ASSERT(cr); 13635331Samw ASSERT(snode); 13645331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 13655331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 13665331Samw 13675331Samw ASSERT(sr); 13685331Samw ASSERT(sr->fid_ofile); 13695331Samw 13705331Samw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_READ_DATA); 13715331Samw if (rc != NT_STATUS_SUCCESS) { 13725331Samw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_EXECUTE); 13735331Samw if (rc != NT_STATUS_SUCCESS) 13745331Samw return (EACCES); 13755331Samw } 13765331Samw 13775331Samw unnamed_node = SMB_IS_STREAM(snode); 13785331Samw if (unnamed_node) { 13795331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 13805331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 13815331Samw unnamed_vp = unnamed_node->vp; 13825331Samw /* 13835331Samw * Streams permission are checked against the unnamed stream, 13845331Samw * but in FS level they have their own permissions. To avoid 13855331Samw * rejection by FS due to lack of permission on the actual 13865331Samw * extended attr kcred is passed for streams. 13875331Samw */ 13885331Samw cr = kcred; 13895331Samw } 13905331Samw 13915772Sas200622 smb_node_start_crit(snode, RW_READER); 13927348SJose.Borrego@Sun.COM rc = nbl_svmand(snode->vp, kcred, &svmand); 13935772Sas200622 if (rc) { 13945772Sas200622 smb_node_end_crit(snode); 13955772Sas200622 return (rc); 13965772Sas200622 } 13975772Sas200622 13987348SJose.Borrego@Sun.COM ct = smb_ct; 13997348SJose.Borrego@Sun.COM ct.cc_pid = sr->fid_ofile->f_uniqid; 14005772Sas200622 rc = nbl_lock_conflict(snode->vp, NBL_READ, uio->uio_loffset, 14017348SJose.Borrego@Sun.COM uio->uio_iov->iov_len, svmand, &ct); 14025772Sas200622 14035772Sas200622 if (rc) { 14045772Sas200622 smb_node_end_crit(snode); 14056432Sas200622 return (ERANGE); 14065772Sas200622 } 14075772Sas200622 rc = smb_vop_read(snode->vp, uio, cr); 14085772Sas200622 14095772Sas200622 if (rc == 0 && ret_attr) { 14105331Samw /* 14115772Sas200622 * Use kcred to update the node attr because this 14125772Sas200622 * call is not being made on behalf of the user. 14135331Samw */ 14145331Samw ret_attr->sa_mask = SMB_AT_ALL; 14155772Sas200622 if (smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0, 14165772Sas200622 kcred) == 0) { 14175772Sas200622 snode->attr = *ret_attr; 14185772Sas200622 } 14195331Samw } 14205331Samw 14215772Sas200622 smb_node_end_crit(snode); 14225772Sas200622 14235331Samw return (rc); 14245331Samw } 14255331Samw 14265331Samw /* 14275331Samw * smb_fsop_write 14285331Samw * 14295331Samw * This is a wrapper function used for smb_write and smb_write_raw operations. 14305331Samw * 14315331Samw * It is assumed that a reference exists on snode coming into this routine. 14325331Samw */ 14335331Samw int 14345331Samw smb_fsop_write( 14356139Sjb150015 smb_request_t *sr, 14365331Samw cred_t *cr, 14375331Samw smb_node_t *snode, 14385331Samw uio_t *uio, 14395331Samw uint32_t *lcount, 14405331Samw smb_attr_t *ret_attr, 14417052Samw int ioflag) 14425331Samw { 14435331Samw smb_node_t *unnamed_node; 14445331Samw vnode_t *unnamed_vp = NULL; 14457348SJose.Borrego@Sun.COM caller_context_t ct; 14465772Sas200622 int svmand; 14475331Samw int rc; 14485331Samw 14495331Samw ASSERT(cr); 14505331Samw ASSERT(snode); 14515331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 14525331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 14535331Samw 14545331Samw ASSERT(sr); 14555331Samw ASSERT(sr->tid_tree); 14565331Samw ASSERT(sr->fid_ofile); 14575331Samw 14587348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 14595331Samw return (EROFS); 14605772Sas200622 14617348SJose.Borrego@Sun.COM if (SMB_OFILE_IS_READONLY(sr->fid_ofile)) 14627348SJose.Borrego@Sun.COM return (EACCES); 14637348SJose.Borrego@Sun.COM 14645331Samw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_WRITE_DATA); 14655772Sas200622 if (rc != NT_STATUS_SUCCESS) { 14665772Sas200622 rc = smb_ofile_access(sr->fid_ofile, cr, FILE_APPEND_DATA); 14675772Sas200622 if (rc != NT_STATUS_SUCCESS) 14685772Sas200622 return (EACCES); 14695772Sas200622 } 14705331Samw 14715331Samw unnamed_node = SMB_IS_STREAM(snode); 14725331Samw 14735331Samw if (unnamed_node) { 14745331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 14755331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 14765331Samw unnamed_vp = unnamed_node->vp; 14775331Samw /* 14785331Samw * Streams permission are checked against the unnamed stream, 14795331Samw * but in FS level they have their own permissions. To avoid 14805331Samw * rejection by FS due to lack of permission on the actual 14815331Samw * extended attr kcred is passed for streams. 14825331Samw */ 14835331Samw cr = kcred; 14845331Samw } 14855331Samw 14865772Sas200622 smb_node_start_crit(snode, RW_READER); 14877348SJose.Borrego@Sun.COM rc = nbl_svmand(snode->vp, kcred, &svmand); 14885772Sas200622 if (rc) { 14895772Sas200622 smb_node_end_crit(snode); 14905772Sas200622 return (rc); 14915772Sas200622 } 14927348SJose.Borrego@Sun.COM 14937348SJose.Borrego@Sun.COM ct = smb_ct; 14947348SJose.Borrego@Sun.COM ct.cc_pid = sr->fid_ofile->f_uniqid; 14955772Sas200622 rc = nbl_lock_conflict(snode->vp, NBL_WRITE, uio->uio_loffset, 14967348SJose.Borrego@Sun.COM uio->uio_iov->iov_len, svmand, &ct); 14975772Sas200622 14985772Sas200622 if (rc) { 14995772Sas200622 smb_node_end_crit(snode); 15006432Sas200622 return (ERANGE); 15015772Sas200622 } 15027052Samw rc = smb_vop_write(snode->vp, uio, ioflag, lcount, cr); 15035772Sas200622 15045772Sas200622 if (rc == 0 && ret_attr) { 15055331Samw /* 15065772Sas200622 * Use kcred to update the node attr because this 15075772Sas200622 * call is not being made on behalf of the user. 15085331Samw */ 15095331Samw ret_attr->sa_mask = SMB_AT_ALL; 15105772Sas200622 if (smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0, 15115772Sas200622 kcred) == 0) { 15125772Sas200622 snode->attr = *ret_attr; 15135772Sas200622 } 15145331Samw } 15155331Samw 15165772Sas200622 smb_node_end_crit(snode); 15175772Sas200622 15185331Samw return (rc); 15195331Samw } 15205331Samw 15215331Samw /* 15225331Samw * smb_fsop_statfs 15235331Samw * 15245331Samw * This is a wrapper function used for stat operations. 15255331Samw */ 15265331Samw int 15275331Samw smb_fsop_statfs( 15285331Samw cred_t *cr, 15295331Samw smb_node_t *snode, 15305331Samw struct statvfs64 *statp) 15315331Samw { 15325331Samw ASSERT(cr); 15335331Samw ASSERT(snode); 15345331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 15355331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 15365331Samw 15375331Samw return (smb_vop_statfs(snode->vp, statp, cr)); 15385331Samw } 15395331Samw 15405331Samw /* 15415331Samw * smb_fsop_access 15426700Sjm199354 * 15436700Sjm199354 * Named streams do not have separate permissions from the associated 15446700Sjm199354 * unnamed stream. Thus, if node is a named stream, the permissions 15456700Sjm199354 * check will be performed on the associated unnamed stream. 15466700Sjm199354 * 15476700Sjm199354 * However, our named streams do have their own quarantine attribute, 15486700Sjm199354 * separate from that on the unnamed stream. If READ or EXECUTE 15496700Sjm199354 * access has been requested on a named stream, an additional access 15506700Sjm199354 * check is performed on the named stream in case it has been 15516700Sjm199354 * quarantined. kcred is used to avoid issues with the permissions 15526700Sjm199354 * set on the extended attribute file representing the named stream. 15535331Samw */ 15545331Samw int 15555331Samw smb_fsop_access(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 15565331Samw uint32_t faccess) 15575331Samw { 15585331Samw int access = 0; 15595331Samw int error; 15605331Samw vnode_t *dir_vp; 15615331Samw boolean_t acl_check = B_TRUE; 15625331Samw smb_node_t *unnamed_node; 15635331Samw 15647348SJose.Borrego@Sun.COM ASSERT(sr); 15655331Samw ASSERT(cr); 15665331Samw ASSERT(snode); 15675331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 15685331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 15695331Samw 15705331Samw if (faccess == 0) 15715331Samw return (NT_STATUS_SUCCESS); 15725331Samw 15737348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) { 15745331Samw if (faccess & (FILE_WRITE_DATA|FILE_APPEND_DATA| 15755331Samw FILE_WRITE_EA|FILE_DELETE_CHILD|FILE_WRITE_ATTRIBUTES| 15765331Samw DELETE|WRITE_DAC|WRITE_OWNER)) { 15775331Samw return (NT_STATUS_ACCESS_DENIED); 15785331Samw } 15795331Samw } 15805331Samw 15815331Samw unnamed_node = SMB_IS_STREAM(snode); 15825331Samw if (unnamed_node) { 15835331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 15845331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 15856700Sjm199354 15866700Sjm199354 /* 15876700Sjm199354 * Perform VREAD access check on the named stream in case it 15886700Sjm199354 * is quarantined. kcred is passed to smb_vop_access so it 15896700Sjm199354 * doesn't fail due to lack of permission. 15906700Sjm199354 */ 15916700Sjm199354 if (faccess & (FILE_READ_DATA | FILE_EXECUTE)) { 15926700Sjm199354 error = smb_vop_access(snode->vp, VREAD, 15936700Sjm199354 0, NULL, kcred); 15946700Sjm199354 if (error) 15956700Sjm199354 return (NT_STATUS_ACCESS_DENIED); 15966700Sjm199354 } 15976700Sjm199354 15985331Samw /* 15995331Samw * Streams authorization should be performed against the 16005331Samw * unnamed stream. 16015331Samw */ 16025331Samw snode = unnamed_node; 16035331Samw } 16045331Samw 16055331Samw if (faccess & ACCESS_SYSTEM_SECURITY) { 16065331Samw /* 16075331Samw * This permission is required for reading/writing SACL and 16085331Samw * it's not part of DACL. It's only granted via proper 16095331Samw * privileges. 16105331Samw */ 16115331Samw if ((sr->uid_user->u_privileges & 16125331Samw (SMB_USER_PRIV_BACKUP | 16135331Samw SMB_USER_PRIV_RESTORE | 16145331Samw SMB_USER_PRIV_SECURITY)) == 0) 16155331Samw return (NT_STATUS_PRIVILEGE_NOT_HELD); 16165331Samw 16175331Samw faccess &= ~ACCESS_SYSTEM_SECURITY; 16185331Samw } 16195331Samw 16205331Samw /* Links don't have ACL */ 16217348SJose.Borrego@Sun.COM if ((!smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) || 16225331Samw (snode->attr.sa_vattr.va_type == VLNK)) 16235331Samw acl_check = B_FALSE; 16245331Samw 16255331Samw if (acl_check) { 16265331Samw dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL; 16275331Samw error = smb_vop_access(snode->vp, faccess, V_ACE_MASK, dir_vp, 16285331Samw cr); 16295331Samw } else { 16305331Samw /* 16315331Samw * FS doesn't understand 32-bit mask, need to map 16325331Samw */ 16335331Samw if (faccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) 16345331Samw access |= VWRITE; 16355331Samw 16365331Samw if (faccess & FILE_READ_DATA) 16375331Samw access |= VREAD; 16385331Samw 16395331Samw if (faccess & FILE_EXECUTE) 16405331Samw access |= VEXEC; 16415331Samw 16425331Samw error = smb_vop_access(snode->vp, access, 0, NULL, cr); 16435331Samw } 16445331Samw 16455331Samw return ((error) ? NT_STATUS_ACCESS_DENIED : NT_STATUS_SUCCESS); 16465331Samw } 16475331Samw 16485331Samw /* 16495331Samw * smb_fsop_lookup_name() 16505331Samw * 16515331Samw * Sanity checks on dir_snode done in smb_fsop_lookup(). 16525331Samw * 16535331Samw * Note: This function is called only from the open path. 16545331Samw * It will check if the file is a stream. 16555331Samw * It will also return an error if the looked-up file is in 16565331Samw * a child mount. 16575331Samw */ 16585331Samw 16595331Samw int 16605331Samw smb_fsop_lookup_name( 16616139Sjb150015 smb_request_t *sr, 16625331Samw cred_t *cr, 16635331Samw int flags, 16645331Samw smb_node_t *root_node, 16655331Samw smb_node_t *dir_snode, 16665331Samw char *name, 16675331Samw smb_node_t **ret_snode, 16685331Samw smb_attr_t *ret_attr) 16695331Samw { 16706139Sjb150015 smb_node_t *fnode; 16716139Sjb150015 smb_attr_t file_attr; 16726139Sjb150015 vnode_t *xattrdirvp; 16736139Sjb150015 vnode_t *vp; 16746139Sjb150015 char *od_name; 16756139Sjb150015 char *fname; 16766139Sjb150015 char *sname; 16776139Sjb150015 int rc; 16785331Samw 16795331Samw ASSERT(cr); 16805331Samw ASSERT(dir_snode); 16815331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 16825331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 16835331Samw 16845331Samw /* 16855331Samw * The following check is required for streams processing, below 16865331Samw */ 16875331Samw 16887348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 16895331Samw flags |= SMB_IGNORE_CASE; 16905331Samw 16915331Samw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 16925331Samw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 16935331Samw 16945331Samw if (smb_stream_parse_name(name, fname, sname)) { 16955331Samw /* 16965331Samw * Look up the unnamed stream (i.e. fname). 16975331Samw * Unmangle processing will be done on fname 16985331Samw * as well as any link target. 16995331Samw */ 17005331Samw rc = smb_fsop_lookup(sr, cr, flags, root_node, dir_snode, fname, 17015331Samw &fnode, &file_attr, NULL, NULL); 17025331Samw 17035331Samw if (rc != 0) { 17045331Samw kmem_free(fname, MAXNAMELEN); 17055331Samw kmem_free(sname, MAXNAMELEN); 17065331Samw return (rc); 17075331Samw } 17085331Samw 17095331Samw od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 17105331Samw 17115331Samw /* 17125331Samw * od_name is the on-disk name of the stream, except 17135331Samw * without the prepended stream prefix (SMB_STREAM_PREFIX) 17145331Samw */ 17155331Samw 17165331Samw /* 17175331Samw * XXX 17185331Samw * What permissions NTFS requires for stream lookup if any? 17195331Samw */ 17205331Samw rc = smb_vop_stream_lookup(fnode->vp, sname, &vp, od_name, 17215772Sas200622 &xattrdirvp, flags, root_node->vp, cr); 17225331Samw 17235331Samw if (rc != 0) { 17245331Samw smb_node_release(fnode); 17255331Samw kmem_free(fname, MAXNAMELEN); 17265331Samw kmem_free(sname, MAXNAMELEN); 17275331Samw kmem_free(od_name, MAXNAMELEN); 17285331Samw return (rc); 17295331Samw } 17305331Samw 17315331Samw *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, 17325331Samw vp, od_name, ret_attr); 17335331Samw 17345331Samw kmem_free(od_name, MAXNAMELEN); 17355331Samw smb_node_release(fnode); 17365331Samw 17375331Samw if (*ret_snode == NULL) { 17385331Samw VN_RELE(xattrdirvp); 17395331Samw VN_RELE(vp); 17405331Samw kmem_free(fname, MAXNAMELEN); 17415331Samw kmem_free(sname, MAXNAMELEN); 17425331Samw return (ENOMEM); 17435331Samw } 17445331Samw } else { 17455331Samw rc = smb_fsop_lookup(sr, cr, flags, root_node, dir_snode, name, 17465331Samw ret_snode, ret_attr, NULL, NULL); 17475331Samw } 17485331Samw 17495331Samw if (rc == 0) { 17505331Samw ASSERT(ret_snode); 17517348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, *ret_snode) == 0) { 17525331Samw smb_node_release(*ret_snode); 17535331Samw *ret_snode = NULL; 17545331Samw rc = EACCES; 17555331Samw } 17565331Samw } 17575331Samw 17585331Samw kmem_free(fname, MAXNAMELEN); 17595331Samw kmem_free(sname, MAXNAMELEN); 17605331Samw 17615331Samw return (rc); 17625331Samw } 17635331Samw 17645331Samw /* 17655331Samw * smb_fsop_lookup 17665331Samw * 17675331Samw * All SMB functions should use this smb_vop_lookup wrapper to ensure that 17685331Samw * the smb_vop_lookup is performed with the appropriate credentials and using 17695331Samw * case insensitive compares. Please document any direct call to smb_vop_lookup 17705331Samw * to explain the reason for avoiding this wrapper. 17715331Samw * 17725331Samw * It is assumed that a reference exists on dir_snode coming into this routine 17735331Samw * (and that it is safe from deallocation). 17745331Samw * 17755331Samw * Same with the root_node. 17765331Samw * 17775331Samw * *ret_snode is returned with a reference upon success. No reference is 17785331Samw * taken if an error is returned. 17795331Samw * 17805331Samw * Note: The returned ret_snode may be in a child mount. This is ok for 17815331Samw * readdir and getdents. 17825331Samw * 17837348SJose.Borrego@Sun.COM * ret_shortname and ret_name83 must each point to buffers of at least 17847348SJose.Borrego@Sun.COM * SMB_SHORTNAMELEN bytes. 17857348SJose.Borrego@Sun.COM * 17867348SJose.Borrego@Sun.COM * Other smb_fsop_* routines will call SMB_TREE_CONTAINS_NODE() to prevent 17875331Samw * operations on files not in the parent mount. 17885331Samw */ 17895331Samw int 17905331Samw smb_fsop_lookup( 17916139Sjb150015 smb_request_t *sr, 17925331Samw cred_t *cr, 17935331Samw int flags, 17945331Samw smb_node_t *root_node, 17955331Samw smb_node_t *dir_snode, 17965331Samw char *name, 17975331Samw smb_node_t **ret_snode, 17985331Samw smb_attr_t *ret_attr, 17997348SJose.Borrego@Sun.COM char *ret_shortname, 18007348SJose.Borrego@Sun.COM char *ret_name83) 18015331Samw { 18025331Samw smb_node_t *lnk_target_node; 18035331Samw smb_node_t *lnk_dnode; 18045331Samw char *longname; 18055331Samw char *od_name; 18065331Samw vnode_t *vp; 18075331Samw int rc; 18085331Samw 18095331Samw ASSERT(cr); 18105331Samw ASSERT(dir_snode); 18115331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 18125331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 18135331Samw 18145331Samw if (name == NULL) 18155331Samw return (EINVAL); 18165331Samw 18177348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 18185331Samw return (EACCES); 18195331Samw 18207348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 18215331Samw flags |= SMB_IGNORE_CASE; 18225331Samw 18235331Samw od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 18245331Samw 18255331Samw rc = smb_vop_lookup(dir_snode->vp, name, &vp, od_name, flags, 18265772Sas200622 root_node ? root_node->vp : NULL, cr); 18275331Samw 18285331Samw if (rc != 0) { 18295331Samw if (smb_maybe_mangled_name(name) == 0) { 18305331Samw kmem_free(od_name, MAXNAMELEN); 18315331Samw return (rc); 18325331Samw } 18335331Samw 18345331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 18355331Samw 18365331Samw rc = smb_unmangle_name(sr, cr, dir_snode, name, longname, 18375331Samw MAXNAMELEN, ret_shortname, ret_name83, 1); 18385331Samw 18395331Samw if (rc != 0) { 18405331Samw kmem_free(od_name, MAXNAMELEN); 18415331Samw kmem_free(longname, MAXNAMELEN); 18425331Samw return (rc); 18435331Samw } 18445331Samw 18455331Samw /* 18465331Samw * We passed "1" as the "od" parameter 18475331Samw * to smb_unmangle_name(), such that longname 18485331Samw * is the real (case-sensitive) on-disk name. 18495331Samw * We make sure we do a lookup on this exact 18505331Samw * name, as the name was mangled and denotes 18515331Samw * a unique file. 18525331Samw */ 18535331Samw 18545331Samw if (flags & SMB_IGNORE_CASE) 18555331Samw flags &= ~SMB_IGNORE_CASE; 18565331Samw 18575331Samw rc = smb_vop_lookup(dir_snode->vp, longname, &vp, od_name, 18585772Sas200622 flags, root_node ? root_node->vp : NULL, cr); 18595331Samw 18605331Samw kmem_free(longname, MAXNAMELEN); 18615331Samw 18625331Samw if (rc != 0) { 18635331Samw kmem_free(od_name, MAXNAMELEN); 18645331Samw return (rc); 18655331Samw } 18665331Samw } 18675331Samw 18685331Samw if ((flags & SMB_FOLLOW_LINKS) && (vp->v_type == VLNK)) { 18695331Samw 18705331Samw rc = smb_pathname(sr, od_name, FOLLOW, root_node, dir_snode, 18715331Samw &lnk_dnode, &lnk_target_node, cr); 18725331Samw 18735331Samw if (rc != 0) { 18745331Samw /* 18755331Samw * The link is assumed to be for the last component 18765331Samw * of a path. Hence any ENOTDIR error will be returned 18775331Samw * as ENOENT. 18785331Samw */ 18795331Samw if (rc == ENOTDIR) 18805331Samw rc = ENOENT; 18815331Samw 18825331Samw VN_RELE(vp); 18835331Samw kmem_free(od_name, MAXNAMELEN); 18845331Samw return (rc); 18855331Samw } 18865331Samw 18875331Samw /* 18885331Samw * Release the original VLNK vnode 18895331Samw */ 18905331Samw 18915331Samw VN_RELE(vp); 18925331Samw vp = lnk_target_node->vp; 18935331Samw 18945331Samw rc = smb_vop_traverse_check(&vp); 18955331Samw 18965331Samw if (rc != 0) { 18975331Samw smb_node_release(lnk_dnode); 18985331Samw smb_node_release(lnk_target_node); 18995331Samw kmem_free(od_name, MAXNAMELEN); 19005331Samw return (rc); 19015331Samw } 19025331Samw 19035331Samw /* 19045331Samw * smb_vop_traverse_check() may have returned a different vnode 19055331Samw */ 19065331Samw 19075331Samw if (lnk_target_node->vp == vp) { 19085331Samw *ret_snode = lnk_target_node; 19095331Samw *ret_attr = (*ret_snode)->attr; 19105331Samw } else { 19115331Samw *ret_snode = smb_node_lookup(sr, NULL, cr, vp, 19125331Samw lnk_target_node->od_name, lnk_dnode, NULL, 19135331Samw ret_attr); 19145331Samw 19155331Samw if (*ret_snode == NULL) { 19165331Samw VN_RELE(vp); 19175331Samw rc = ENOMEM; 19185331Samw } 19195331Samw smb_node_release(lnk_target_node); 19205331Samw } 19215331Samw 19225331Samw smb_node_release(lnk_dnode); 19235331Samw 19245331Samw } else { 19255331Samw 19265331Samw rc = smb_vop_traverse_check(&vp); 19275331Samw if (rc) { 19285331Samw VN_RELE(vp); 19295331Samw kmem_free(od_name, MAXNAMELEN); 19305331Samw return (rc); 19315331Samw } 19325331Samw 19335331Samw *ret_snode = smb_node_lookup(sr, NULL, cr, vp, od_name, 19345331Samw dir_snode, NULL, ret_attr); 19355331Samw 19365331Samw if (*ret_snode == NULL) { 19375331Samw VN_RELE(vp); 19385331Samw rc = ENOMEM; 19395331Samw } 19405331Samw } 19415331Samw 19425331Samw kmem_free(od_name, MAXNAMELEN); 19435331Samw return (rc); 19445331Samw } 19455331Samw 19465331Samw /* 19475331Samw * smb_fsop_stream_readdir() 19485331Samw * 19495331Samw * ret_snode and ret_attr are optional parameters (i.e. NULL may be passed in) 19505331Samw * 19515331Samw * This routine will return only NTFS streams. If an NTFS stream is not 19525331Samw * found at the offset specified, the directory will be read until an NTFS 19535331Samw * stream is found or until EOF. 19545331Samw * 19555331Samw * Note: Sanity checks done in caller 19565331Samw * (smb_fsop_readdir(), smb_fsop_remove_streams()) 19575331Samw */ 19585331Samw 19595331Samw int 19606139Sjb150015 smb_fsop_stream_readdir(smb_request_t *sr, cred_t *cr, smb_node_t *fnode, 19615331Samw uint32_t *cookiep, struct fs_stream_info *stream_info, 19625331Samw smb_node_t **ret_snode, smb_attr_t *ret_attr) 19635331Samw { 19645331Samw smb_node_t *ret_snodep = NULL; 19655331Samw smb_attr_t tmp_attr; 19665331Samw vnode_t *xattrdirvp; 19675331Samw vnode_t *vp; 19685331Samw int rc = 0; 19695331Samw int flags = 0; 19705331Samw 19715331Samw /* 19725331Samw * XXX NTFS permission requirements if any? 19735331Samw */ 19745331Samw ASSERT(cr); 19755331Samw ASSERT(fnode); 19765331Samw ASSERT(fnode->n_magic == SMB_NODE_MAGIC); 19775331Samw ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING); 19785331Samw 19797348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 19805331Samw flags = SMB_IGNORE_CASE; 19815331Samw 19825331Samw rc = smb_vop_stream_readdir(fnode->vp, cookiep, stream_info, &vp, 19835772Sas200622 &xattrdirvp, flags, cr); 19845331Samw 19855331Samw if ((rc != 0) || *cookiep == SMB_EOF) 19865331Samw return (rc); 19875331Samw 19885331Samw ret_snodep = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, vp, 19895331Samw stream_info->name, &tmp_attr); 19905331Samw 19915331Samw if (ret_snodep == NULL) { 19925331Samw VN_RELE(xattrdirvp); 19935331Samw VN_RELE(vp); 19945331Samw return (ENOMEM); 19955331Samw } 19965331Samw 19975331Samw stream_info->size = tmp_attr.sa_vattr.va_size; 19985331Samw 19995331Samw if (ret_attr) 20005331Samw *ret_attr = tmp_attr; 20015331Samw 20025331Samw if (ret_snode) 20035331Samw *ret_snode = ret_snodep; 20045331Samw else 20055331Samw smb_node_release(ret_snodep); 20065331Samw 20075331Samw return (rc); 20085331Samw } 20095331Samw 20105331Samw int /*ARGSUSED*/ 20115331Samw smb_fsop_commit(smb_request_t *sr, cred_t *cr, smb_node_t *snode) 20125331Samw { 20135331Samw ASSERT(cr); 20145331Samw ASSERT(snode); 20155331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 20165331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 20175331Samw 20185331Samw ASSERT(sr); 20195331Samw ASSERT(sr->tid_tree); 20207348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 20215331Samw return (EROFS); 20225331Samw 20235772Sas200622 return (smb_vop_commit(snode->vp, cr)); 20245331Samw } 20255331Samw 20265331Samw /* 20275331Samw * smb_fsop_aclread 20285331Samw * 20295331Samw * Retrieve filesystem ACL. Depends on requested ACLs in 20305331Samw * fs_sd->sd_secinfo, it'll set DACL and SACL pointers in 20315331Samw * fs_sd. Note that requesting a DACL/SACL doesn't mean that 20325331Samw * the corresponding field in fs_sd should be non-NULL upon 20335331Samw * return, since the target ACL might not contain that type of 20345331Samw * entries. 20355331Samw * 20365331Samw * Returned ACL is always in ACE_T (aka ZFS) format. 20375331Samw * If successful the allocated memory for the ACL should be freed 20385521Sas200622 * using smb_fsacl_free() or smb_fssd_term() 20395331Samw */ 20405331Samw int 20415331Samw smb_fsop_aclread(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 20425331Samw smb_fssd_t *fs_sd) 20435331Samw { 20445331Samw int error = 0; 20455331Samw int flags = 0; 20465331Samw int access = 0; 20475331Samw acl_t *acl; 20485331Samw smb_node_t *unnamed_node; 20495331Samw 20505331Samw ASSERT(cr); 20515331Samw 20525331Samw if (sr->fid_ofile) { 20535331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 20545331Samw access = READ_CONTROL; 20555331Samw 20565331Samw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 20575331Samw access |= ACCESS_SYSTEM_SECURITY; 20585331Samw 20595331Samw error = smb_ofile_access(sr->fid_ofile, cr, access); 20605331Samw if (error != NT_STATUS_SUCCESS) { 20615331Samw return (EACCES); 20625331Samw } 20635331Samw } 20645331Samw 20655331Samw unnamed_node = SMB_IS_STREAM(snode); 20665331Samw if (unnamed_node) { 20675331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 20685331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 20695331Samw /* 20705331Samw * Streams don't have ACL, any read ACL attempt on a stream 20715331Samw * should be performed on the unnamed stream. 20725331Samw */ 20735331Samw snode = unnamed_node; 20745331Samw } 20755331Samw 20767348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) 20775331Samw flags = ATTR_NOACLCHECK; 20785331Samw 20795331Samw error = smb_vop_acl_read(snode->vp, &acl, flags, 20805772Sas200622 sr->tid_tree->t_acltype, cr); 20815331Samw if (error != 0) { 20825331Samw return (error); 20835331Samw } 20845331Samw 20855331Samw error = acl_translate(acl, _ACL_ACE_ENABLED, 20865331Samw (snode->vp->v_type == VDIR), fs_sd->sd_uid, fs_sd->sd_gid); 20875331Samw 20885331Samw if (error == 0) { 20895521Sas200622 smb_fsacl_split(acl, &fs_sd->sd_zdacl, &fs_sd->sd_zsacl, 20905331Samw fs_sd->sd_secinfo); 20915331Samw } 20925331Samw 20935331Samw acl_free(acl); 20945331Samw return (error); 20955331Samw } 20965331Samw 20975331Samw /* 20985331Samw * smb_fsop_aclwrite 20995331Samw * 21005331Samw * Stores the filesystem ACL provided in fs_sd->sd_acl. 21015331Samw */ 21025331Samw int 21035331Samw smb_fsop_aclwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 21045331Samw smb_fssd_t *fs_sd) 21055331Samw { 21065331Samw int target_flavor; 21075331Samw int error = 0; 21085331Samw int flags = 0; 21095331Samw int access = 0; 21105331Samw acl_t *acl, *dacl, *sacl; 21115331Samw smb_node_t *unnamed_node; 21125331Samw 21135331Samw ASSERT(cr); 21145331Samw 21155331Samw ASSERT(sr); 21165331Samw ASSERT(sr->tid_tree); 21177348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 21185331Samw return (EROFS); 21195331Samw 21205331Samw if (sr->fid_ofile) { 21215331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 21225331Samw access = WRITE_DAC; 21235331Samw 21245331Samw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 21255331Samw access |= ACCESS_SYSTEM_SECURITY; 21265331Samw 21275331Samw error = smb_ofile_access(sr->fid_ofile, cr, access); 21285331Samw if (error != NT_STATUS_SUCCESS) 21295331Samw return (EACCES); 21305331Samw } 21315331Samw 21325331Samw switch (sr->tid_tree->t_acltype) { 21335331Samw case ACLENT_T: 21345331Samw target_flavor = _ACL_ACLENT_ENABLED; 21355331Samw break; 21365331Samw 21375331Samw case ACE_T: 21385331Samw target_flavor = _ACL_ACE_ENABLED; 21395331Samw break; 21405331Samw default: 21415331Samw return (EINVAL); 21425331Samw } 21435331Samw 21445331Samw unnamed_node = SMB_IS_STREAM(snode); 21455331Samw if (unnamed_node) { 21465331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 21475331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 21485331Samw /* 21495331Samw * Streams don't have ACL, any write ACL attempt on a stream 21505331Samw * should be performed on the unnamed stream. 21515331Samw */ 21525331Samw snode = unnamed_node; 21535331Samw } 21545331Samw 21555331Samw dacl = fs_sd->sd_zdacl; 21565331Samw sacl = fs_sd->sd_zsacl; 21575331Samw 21585331Samw ASSERT(dacl || sacl); 21595331Samw if ((dacl == NULL) && (sacl == NULL)) 21605331Samw return (EINVAL); 21615331Samw 21625331Samw if (dacl && sacl) 21635521Sas200622 acl = smb_fsacl_merge(dacl, sacl); 21645331Samw else if (dacl) 21655331Samw acl = dacl; 21665331Samw else 21675331Samw acl = sacl; 21685331Samw 21695331Samw error = acl_translate(acl, target_flavor, (snode->vp->v_type == VDIR), 21705331Samw fs_sd->sd_uid, fs_sd->sd_gid); 21715331Samw if (error == 0) { 21727348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, 21737348SJose.Borrego@Sun.COM SMB_TREE_ACEMASKONACCESS)) 21745331Samw flags = ATTR_NOACLCHECK; 21755331Samw 21765772Sas200622 error = smb_vop_acl_write(snode->vp, acl, flags, cr); 21775331Samw } 21785331Samw 21795331Samw if (dacl && sacl) 21805331Samw acl_free(acl); 21815331Samw 21825331Samw return (error); 21835331Samw } 21845331Samw 21855331Samw acl_type_t 21865331Samw smb_fsop_acltype(smb_node_t *snode) 21875331Samw { 21885331Samw return (smb_vop_acl_type(snode->vp)); 21895331Samw } 21905331Samw 21915331Samw /* 21925331Samw * smb_fsop_sdread 21935331Samw * 21945331Samw * Read the requested security descriptor items from filesystem. 21955331Samw * The items are specified in fs_sd->sd_secinfo. 21965331Samw */ 21975331Samw int 21985331Samw smb_fsop_sdread(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 21995331Samw smb_fssd_t *fs_sd) 22005331Samw { 22015331Samw int error = 0; 22025331Samw int getowner = 0; 22035331Samw cred_t *ga_cred; 22045331Samw smb_attr_t attr; 22055331Samw 22065331Samw ASSERT(cr); 22075331Samw ASSERT(fs_sd); 22085331Samw 22095331Samw /* 22105331Samw * File's uid/gid is fetched in two cases: 22115331Samw * 22125331Samw * 1. it's explicitly requested 22135331Samw * 22145331Samw * 2. target ACL is ACE_T (ZFS ACL). They're needed for 22155331Samw * owner@/group@ entries. In this case kcred should be used 22165331Samw * because uid/gid are fetched on behalf of smb server. 22175331Samw */ 22185331Samw if (fs_sd->sd_secinfo & (SMB_OWNER_SECINFO | SMB_GROUP_SECINFO)) { 22195331Samw getowner = 1; 22205331Samw ga_cred = cr; 22215331Samw } else if (sr->tid_tree->t_acltype == ACE_T) { 22225331Samw getowner = 1; 22235331Samw ga_cred = kcred; 22245331Samw } 22255331Samw 22265331Samw if (getowner) { 22275331Samw /* 22285331Samw * Windows require READ_CONTROL to read owner/group SID since 22295331Samw * they're part of Security Descriptor. 22305331Samw * ZFS only requires read_attribute. Need to have a explicit 22315331Samw * access check here. 22325331Samw */ 22335331Samw if (sr->fid_ofile == NULL) { 22345331Samw error = smb_fsop_access(sr, ga_cred, snode, 22355331Samw READ_CONTROL); 22365331Samw if (error) 22375331Samw return (error); 22385331Samw } 22395331Samw 22405331Samw attr.sa_mask = SMB_AT_UID | SMB_AT_GID; 22415331Samw error = smb_fsop_getattr(sr, ga_cred, snode, &attr); 22425331Samw if (error == 0) { 22435331Samw fs_sd->sd_uid = attr.sa_vattr.va_uid; 22445331Samw fs_sd->sd_gid = attr.sa_vattr.va_gid; 22455331Samw } else { 22465331Samw return (error); 22475331Samw } 22485331Samw } 22495331Samw 22505331Samw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 22515331Samw error = smb_fsop_aclread(sr, cr, snode, fs_sd); 22525331Samw } 22535331Samw 22545331Samw return (error); 22555331Samw } 22565331Samw 22575331Samw /* 22585331Samw * smb_fsop_sdmerge 22595331Samw * 22605331Samw * From SMB point of view DACL and SACL are two separate list 22615331Samw * which can be manipulated independently without one affecting 22625331Samw * the other, but entries for both DACL and SACL will end up 22635331Samw * in the same ACL if target filesystem supports ACE_T ACLs. 22645331Samw * 22655331Samw * So, if either DACL or SACL is present in the client set request 22665331Samw * the entries corresponding to the non-present ACL shouldn't 22675331Samw * be touched in the FS ACL. 22685331Samw * 22695331Samw * fs_sd parameter contains DACL and SACL specified by SMB 22705331Samw * client to be set on a file/directory. The client could 22715331Samw * specify both or one of these ACLs (if none is specified 22725331Samw * we don't get this far). When both DACL and SACL are given 22735331Samw * by client the existing ACL should be overwritten. If only 22745331Samw * one of them is specified the entries corresponding to the other 22755331Samw * ACL should not be touched. For example, if only DACL 22765331Samw * is specified in input fs_sd, the function reads audit entries 22775331Samw * of the existing ACL of the file and point fs_sd->sd_zsdacl 22785331Samw * pointer to the fetched SACL, this way when smb_fsop_sdwrite() 22795331Samw * function is called the passed fs_sd would point to the specified 22805331Samw * DACL by client and fetched SACL from filesystem, so the file 22815331Samw * will end up with correct ACL. 22825331Samw */ 22835331Samw static int 22845331Samw smb_fsop_sdmerge(smb_request_t *sr, smb_node_t *snode, smb_fssd_t *fs_sd) 22855331Samw { 22865331Samw smb_fssd_t cur_sd; 22875331Samw int error = 0; 22885331Samw 22895331Samw if (sr->tid_tree->t_acltype != ACE_T) 22905331Samw /* Don't bother if target FS doesn't support ACE_T */ 22915331Samw return (0); 22925331Samw 22935331Samw if ((fs_sd->sd_secinfo & SMB_ACL_SECINFO) != SMB_ACL_SECINFO) { 22945331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) { 22955331Samw /* 22965331Samw * Don't overwrite existing audit entries 22975331Samw */ 22985521Sas200622 smb_fssd_init(&cur_sd, SMB_SACL_SECINFO, 22995331Samw fs_sd->sd_flags); 23005331Samw 23015331Samw error = smb_fsop_sdread(sr, kcred, snode, &cur_sd); 23025331Samw if (error == 0) { 23035331Samw ASSERT(fs_sd->sd_zsacl == NULL); 23045331Samw fs_sd->sd_zsacl = cur_sd.sd_zsacl; 23055331Samw if (fs_sd->sd_zsacl && fs_sd->sd_zdacl) 23065331Samw fs_sd->sd_zsacl->acl_flags = 23075331Samw fs_sd->sd_zdacl->acl_flags; 23085331Samw } 23095331Samw } else { 23105331Samw /* 23115331Samw * Don't overwrite existing access entries 23125331Samw */ 23135521Sas200622 smb_fssd_init(&cur_sd, SMB_DACL_SECINFO, 23145331Samw fs_sd->sd_flags); 23155331Samw 23165331Samw error = smb_fsop_sdread(sr, kcred, snode, &cur_sd); 23175331Samw if (error == 0) { 23185331Samw ASSERT(fs_sd->sd_zdacl == NULL); 23195331Samw fs_sd->sd_zdacl = cur_sd.sd_zdacl; 23205331Samw if (fs_sd->sd_zdacl && fs_sd->sd_zsacl) 23215331Samw fs_sd->sd_zdacl->acl_flags = 23225331Samw fs_sd->sd_zsacl->acl_flags; 23235331Samw } 23245331Samw } 23255331Samw 23265331Samw if (error) 23275521Sas200622 smb_fssd_term(&cur_sd); 23285331Samw } 23295331Samw 23305331Samw return (error); 23315331Samw } 23325331Samw 23335331Samw /* 23345331Samw * smb_fsop_sdwrite 23355331Samw * 23365331Samw * Stores the given uid, gid and acl in filesystem. 23375331Samw * Provided items in fs_sd are specified by fs_sd->sd_secinfo. 23385331Samw * 23395331Samw * A SMB security descriptor could contain owner, primary group, 23405331Samw * DACL and SACL. Setting an SD should be atomic but here it has to 23415331Samw * be done via two separate FS operations: VOP_SETATTR and 23425331Samw * VOP_SETSECATTR. Therefore, this function has to simulate the 23435331Samw * atomicity as well as it can. 23447619SJose.Borrego@Sun.COM * 23457619SJose.Borrego@Sun.COM * Get the current uid, gid before setting the new uid/gid 23467619SJose.Borrego@Sun.COM * so if smb_fsop_aclwrite fails they can be restored. root cred is 23477619SJose.Borrego@Sun.COM * used to get currend uid/gid since this operation is performed on 23487619SJose.Borrego@Sun.COM * behalf of the server not the user. 23497619SJose.Borrego@Sun.COM * 23507619SJose.Borrego@Sun.COM * If setting uid/gid fails with EPERM it means that and invalid 23517619SJose.Borrego@Sun.COM * owner has been specified. Callers should translate this to 23527619SJose.Borrego@Sun.COM * STATUS_INVALID_OWNER which is not the normal mapping for EPERM 23537619SJose.Borrego@Sun.COM * in upper layers, so EPERM is mapped to EBADE. 23545331Samw */ 23555331Samw int 23565331Samw smb_fsop_sdwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 23575331Samw smb_fssd_t *fs_sd, int overwrite) 23585331Samw { 23595331Samw int error = 0; 23605331Samw int access = 0; 23615331Samw smb_attr_t set_attr; 23625331Samw smb_attr_t orig_attr; 23635331Samw 23645331Samw ASSERT(cr); 23655331Samw ASSERT(fs_sd); 23665331Samw 23675331Samw ASSERT(sr); 23685331Samw ASSERT(sr->tid_tree); 23697348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 23705331Samw return (EROFS); 23715331Samw 23725331Samw bzero(&set_attr, sizeof (smb_attr_t)); 23735331Samw 23745331Samw if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 23755331Samw set_attr.sa_vattr.va_uid = fs_sd->sd_uid; 23765331Samw set_attr.sa_mask |= SMB_AT_UID; 23777619SJose.Borrego@Sun.COM access |= WRITE_OWNER; 23785331Samw } 23795331Samw 23805331Samw if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 23815331Samw set_attr.sa_vattr.va_gid = fs_sd->sd_gid; 23825331Samw set_attr.sa_mask |= SMB_AT_GID; 23837619SJose.Borrego@Sun.COM access |= WRITE_OWNER; 23845331Samw } 23855331Samw 23865331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 23875331Samw access |= WRITE_DAC; 23885331Samw 23895331Samw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 23905331Samw access |= ACCESS_SYSTEM_SECURITY; 23915331Samw 23925331Samw if (sr->fid_ofile) 23935331Samw error = smb_ofile_access(sr->fid_ofile, cr, access); 23945331Samw else 23955331Samw error = smb_fsop_access(sr, cr, snode, access); 23965331Samw 23975331Samw if (error) 23985331Samw return (EACCES); 23995331Samw 24005331Samw if (set_attr.sa_mask) { 24015331Samw orig_attr.sa_mask = SMB_AT_UID | SMB_AT_GID; 24025331Samw error = smb_fsop_getattr(sr, kcred, snode, &orig_attr); 24037619SJose.Borrego@Sun.COM if (error == 0) { 24045331Samw error = smb_fsop_setattr(sr, cr, snode, &set_attr, 24055331Samw NULL); 24067619SJose.Borrego@Sun.COM if (error == EPERM) 24077619SJose.Borrego@Sun.COM error = EBADE; 24087619SJose.Borrego@Sun.COM } 24095331Samw 24105331Samw if (error) 24115331Samw return (error); 24125331Samw } 24135331Samw 24145331Samw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 24155331Samw if (overwrite == 0) { 24165331Samw error = smb_fsop_sdmerge(sr, snode, fs_sd); 24175331Samw if (error) 24185331Samw return (error); 24195331Samw } 24205331Samw 24215331Samw error = smb_fsop_aclwrite(sr, cr, snode, fs_sd); 24225331Samw if (error) { 24235331Samw /* 24245331Samw * Revert uid/gid changes if required. 24255331Samw */ 24265331Samw if (set_attr.sa_mask) { 24275331Samw orig_attr.sa_mask = set_attr.sa_mask; 24285331Samw (void) smb_fsop_setattr(sr, kcred, snode, 24295331Samw &orig_attr, NULL); 24305331Samw } 24315331Samw } 24325331Samw } 24335331Samw 24345331Samw return (error); 24355331Samw } 24365331Samw 24375331Samw /* 24385331Samw * smb_fsop_sdinherit 24395331Samw * 24405331Samw * Inherit the security descriptor from the parent container. 24415331Samw * This function is called after FS has created the file/folder 24425331Samw * so if this doesn't do anything it means FS inheritance is 24435331Samw * in place. 24445331Samw * 24455331Samw * Do inheritance for ZFS internally. 24465331Samw * 24475331Samw * If we want to let ZFS does the inheritance the 24485331Samw * following setting should be true: 24495331Samw * 24505331Samw * - aclinherit = passthrough 24515331Samw * - aclmode = passthrough 24525331Samw * - smbd umask = 0777 24535331Samw * 24545331Samw * This will result in right effective permissions but 24555331Samw * ZFS will always add 6 ACEs for owner, owning group 24565331Samw * and others to be POSIX compliant. This is not what 24575331Samw * Windows clients/users expect, so we decided that CIFS 24585331Samw * implements Windows rules and overwrite whatever ZFS 24595331Samw * comes up with. This way we also don't have to care 24605331Samw * about ZFS aclinherit and aclmode settings. 24615331Samw */ 24625331Samw static int 24635331Samw smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, smb_fssd_t *fs_sd) 24645331Samw { 24655331Samw int is_dir; 24665521Sas200622 acl_t *dacl = NULL; 24675521Sas200622 acl_t *sacl = NULL; 24685331Samw ksid_t *owner_sid; 24695331Samw int error; 24705331Samw 24715331Samw ASSERT(fs_sd); 24725331Samw 24735331Samw if (sr->tid_tree->t_acltype != ACE_T) { 24745331Samw /* 24755331Samw * No forced inheritance for non-ZFS filesystems. 24765331Samw */ 24775331Samw fs_sd->sd_secinfo = 0; 24785331Samw return (0); 24795331Samw } 24805331Samw 24815331Samw 24825331Samw /* Fetch parent directory's ACL */ 24835331Samw error = smb_fsop_sdread(sr, kcred, dnode, fs_sd); 24845331Samw if (error) { 24855331Samw return (error); 24865331Samw } 24875331Samw 24885331Samw is_dir = (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR); 24895331Samw owner_sid = crgetsid(sr->user_cr, KSID_OWNER); 24905331Samw ASSERT(owner_sid); 24915521Sas200622 dacl = smb_fsacl_inherit(fs_sd->sd_zdacl, is_dir, SMB_DACL_SECINFO, 24925331Samw owner_sid->ks_id); 24935521Sas200622 sacl = smb_fsacl_inherit(fs_sd->sd_zsacl, is_dir, SMB_SACL_SECINFO, 24945331Samw (uid_t)-1); 24955331Samw 24965521Sas200622 if (sacl == NULL) 24975521Sas200622 fs_sd->sd_secinfo &= ~SMB_SACL_SECINFO; 24985521Sas200622 24995521Sas200622 smb_fsacl_free(fs_sd->sd_zdacl); 25005521Sas200622 smb_fsacl_free(fs_sd->sd_zsacl); 25015331Samw 25025331Samw fs_sd->sd_zdacl = dacl; 25035331Samw fs_sd->sd_zsacl = sacl; 25045331Samw 25055331Samw return (0); 25065331Samw } 25075331Samw 25085331Samw /* 25095331Samw * smb_fsop_eaccess 25105331Samw * 25115331Samw * Returns the effective permission of the given credential for the 25125331Samw * specified object. 25135331Samw * 25145331Samw * This is just a workaround. We need VFS/FS support for this. 25155331Samw */ 25165331Samw void 25175331Samw smb_fsop_eaccess(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 25185331Samw uint32_t *eaccess) 25195331Samw { 25205331Samw int access = 0; 25215331Samw vnode_t *dir_vp; 25225331Samw smb_node_t *unnamed_node; 25235331Samw 25245331Samw ASSERT(cr); 25255331Samw ASSERT(snode); 25265331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 25275331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 25285331Samw 25295331Samw unnamed_node = SMB_IS_STREAM(snode); 25305331Samw if (unnamed_node) { 25315331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 25325331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 25335331Samw /* 25345331Samw * Streams authorization should be performed against the 25355331Samw * unnamed stream. 25365331Samw */ 25375331Samw snode = unnamed_node; 25385331Samw } 25395331Samw 25407348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) { 25415331Samw dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL; 25425331Samw smb_vop_eaccess(snode->vp, (int *)eaccess, V_ACE_MASK, dir_vp, 25435331Samw cr); 25445331Samw return; 25455331Samw } 25465331Samw 25475331Samw /* 25485331Samw * FS doesn't understand 32-bit mask 25495331Samw */ 25505331Samw smb_vop_eaccess(snode->vp, &access, 0, NULL, cr); 25515331Samw 25525331Samw *eaccess = READ_CONTROL | FILE_READ_EA | FILE_READ_ATTRIBUTES; 25535331Samw 25545331Samw if (access & VREAD) 25555331Samw *eaccess |= FILE_READ_DATA; 25565331Samw 25575331Samw if (access & VEXEC) 25585331Samw *eaccess |= FILE_EXECUTE; 25595331Samw 25605331Samw if (access & VWRITE) 25615331Samw *eaccess |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | 25625331Samw FILE_WRITE_EA | FILE_APPEND_DATA | FILE_DELETE_CHILD; 25635331Samw } 25645521Sas200622 25655772Sas200622 /* 25665772Sas200622 * smb_fsop_shrlock 25675772Sas200622 * 25685772Sas200622 * For the current open request, check file sharing rules 25695772Sas200622 * against existing opens. 25705772Sas200622 * 25715772Sas200622 * Returns NT_STATUS_SHARING_VIOLATION if there is any 25725772Sas200622 * sharing conflict. Returns NT_STATUS_SUCCESS otherwise. 25735772Sas200622 * 25745772Sas200622 * Full system-wide share reservation synchronization is available 25755772Sas200622 * when the nbmand (non-blocking mandatory) mount option is set 25765772Sas200622 * (i.e. nbl_need_crit() is true) and nbmand critical regions are used. 25775772Sas200622 * This provides synchronization with NFS and local processes. The 25785772Sas200622 * critical regions are entered in VOP_SHRLOCK()/fs_shrlock() (called 25795772Sas200622 * from smb_open_subr()/smb_fsop_shrlock()/smb_vop_shrlock()) as well 25805772Sas200622 * as the CIFS rename and delete paths. 25815772Sas200622 * 25825772Sas200622 * The CIFS server will also enter the nbl critical region in the open, 25835772Sas200622 * rename, and delete paths when nbmand is not set. There is limited 25845772Sas200622 * coordination with local and VFS share reservations in this case. 25855772Sas200622 * Note that when the nbmand mount option is not set, the VFS layer 25865772Sas200622 * only processes advisory reservations and the delete mode is not checked. 25875772Sas200622 * 25885772Sas200622 * Whether or not the nbmand mount option is set, intra-CIFS share 25895772Sas200622 * checking is done in the open, delete, and rename paths using a CIFS 25905772Sas200622 * critical region (node->n_share_lock). 25915772Sas200622 */ 25925772Sas200622 25935772Sas200622 uint32_t 25946139Sjb150015 smb_fsop_shrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid, 25955772Sas200622 uint32_t desired_access, uint32_t share_access) 25965772Sas200622 { 25975772Sas200622 int rc; 25985772Sas200622 25995772Sas200622 if (node->attr.sa_vattr.va_type == VDIR) 26005772Sas200622 return (NT_STATUS_SUCCESS); 26015772Sas200622 26025772Sas200622 /* Allow access if the request is just for meta data */ 26035772Sas200622 if ((desired_access & FILE_DATA_ALL) == 0) 26045772Sas200622 return (NT_STATUS_SUCCESS); 26055772Sas200622 26065772Sas200622 rc = smb_node_open_check(node, cr, desired_access, share_access); 26075772Sas200622 if (rc) 26085772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 26095772Sas200622 26105772Sas200622 rc = smb_vop_shrlock(node->vp, uniq_fid, desired_access, share_access, 26115772Sas200622 cr); 26125772Sas200622 if (rc) 26135772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 26145772Sas200622 26155772Sas200622 return (NT_STATUS_SUCCESS); 26165772Sas200622 } 26175772Sas200622 26185521Sas200622 void 26195772Sas200622 smb_fsop_unshrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid) 26205521Sas200622 { 26215772Sas200622 if (node->attr.sa_vattr.va_type == VDIR) 26225772Sas200622 return; 26235772Sas200622 26245772Sas200622 (void) smb_vop_unshrlock(node->vp, uniq_fid, cr); 26255772Sas200622 } 26266600Sas200622 26276600Sas200622 int 26286600Sas200622 smb_fsop_frlock(smb_node_t *node, smb_lock_t *lock, boolean_t unlock, 26296600Sas200622 cred_t *cr) 26306600Sas200622 { 26316600Sas200622 flock64_t bf; 26326600Sas200622 int flag = F_REMOTELOCK; 26336600Sas200622 26346771Sjb150015 /* 26356771Sjb150015 * VOP_FRLOCK() will not be called if: 26366771Sjb150015 * 26376771Sjb150015 * 1) The lock has a range of zero bytes. The semantics of Windows and 26386771Sjb150015 * POSIX are different. In the case of POSIX it asks for the locking 26396771Sjb150015 * of all the bytes from the offset provided until the end of the 26406771Sjb150015 * file. In the case of Windows a range of zero locks nothing and 26416771Sjb150015 * doesn't conflict with any other lock. 26426771Sjb150015 * 26436771Sjb150015 * 2) The lock rolls over (start + lenght < start). Solaris will assert 26446771Sjb150015 * if such a request is submitted. This will not create 26456771Sjb150015 * incompatibilities between POSIX and Windows. In the Windows world, 26466771Sjb150015 * if a client submits such a lock, the server will not lock any 26476771Sjb150015 * bytes. Interestingly if the same lock (same offset and length) is 26486771Sjb150015 * resubmitted Windows will consider that there is an overlap and 26496771Sjb150015 * the granting rules will then apply. 26506771Sjb150015 */ 26516771Sjb150015 if ((lock->l_length == 0) || 26526771Sjb150015 ((lock->l_start + lock->l_length - 1) < lock->l_start)) 26536771Sjb150015 return (0); 26546771Sjb150015 26556600Sas200622 bzero(&bf, sizeof (bf)); 26566600Sas200622 26576600Sas200622 if (unlock) { 26586600Sas200622 bf.l_type = F_UNLCK; 26596600Sas200622 } else if (lock->l_type == SMB_LOCK_TYPE_READONLY) { 26606600Sas200622 bf.l_type = F_RDLCK; 26616600Sas200622 flag |= FREAD; 26626600Sas200622 } else if (lock->l_type == SMB_LOCK_TYPE_READWRITE) { 26636600Sas200622 bf.l_type = F_WRLCK; 26646600Sas200622 flag |= FWRITE; 26656600Sas200622 } 26666600Sas200622 26676600Sas200622 bf.l_start = lock->l_start; 26686600Sas200622 bf.l_len = lock->l_length; 26697348SJose.Borrego@Sun.COM bf.l_pid = lock->l_file->f_uniqid; 26706600Sas200622 bf.l_sysid = smb_ct.cc_sysid; 26716600Sas200622 26726600Sas200622 return (smb_vop_frlock(node->vp, cr, flag, &bf)); 26736600Sas200622 } 2674