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 /* 228670SJose.Borrego@Sun.COM * Copyright 2009 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 2008845Samw@Sun.COM /* The tree ACEs may prevent a create */ 2018845Samw@Sun.COM rc = EACCES; 2025331Samw if (is_dir) { 2038845Samw@Sun.COM if (SMB_TREE_HAS_ACCESS(sr, ACE_ADD_SUBDIRECTORY) != 0) 2048845Samw@Sun.COM rc = smb_vop_mkdir(dir_snode->vp, name, attr, 2058845Samw@Sun.COM &vp, flags, cr, vsap); 2065331Samw } else { 2078845Samw@Sun.COM if (SMB_TREE_HAS_ACCESS(sr, ACE_ADD_FILE) != 0) 2088845Samw@Sun.COM rc = smb_vop_create(dir_snode->vp, name, attr, 2098845Samw@Sun.COM &vp, flags, cr, vsap); 2105331Samw } 2115331Samw 2125331Samw if (vsap != NULL) 2135331Samw kmem_free(vsap->vsa_aclentp, aclbsize); 2145331Samw 2155331Samw if (rc != 0) 2165331Samw return (rc); 2175331Samw 2185331Samw set_attr.sa_mask = 0; 2195331Samw 2205331Samw /* 2215331Samw * Ideally we should be able to specify the owner and owning 2225331Samw * group at create time along with the ACL. Since we cannot 2235331Samw * do that right now, kcred is passed to smb_vop_setattr so it 2245331Samw * doesn't fail due to lack of permission. 2255331Samw */ 2265331Samw if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 2275331Samw set_attr.sa_vattr.va_uid = fs_sd->sd_uid; 2285331Samw set_attr.sa_mask |= SMB_AT_UID; 2295331Samw } 2305331Samw 2315331Samw if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 2325331Samw set_attr.sa_vattr.va_gid = fs_sd->sd_gid; 2335331Samw set_attr.sa_mask |= SMB_AT_GID; 2345331Samw } 2355331Samw 2367757SJanice.Chang@Sun.COM if (set_attr.sa_mask) 2377757SJanice.Chang@Sun.COM rc = smb_vop_setattr(vp, NULL, &set_attr, 0, kcred); 2385331Samw 2397619SJose.Borrego@Sun.COM if (rc == 0) { 2407619SJose.Borrego@Sun.COM *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp, 2417619SJose.Borrego@Sun.COM name, dir_snode, NULL, ret_attr); 2427619SJose.Borrego@Sun.COM 2438670SJose.Borrego@Sun.COM if (*ret_snode == NULL) 2447619SJose.Borrego@Sun.COM rc = ENOMEM; 2458670SJose.Borrego@Sun.COM 2468670SJose.Borrego@Sun.COM VN_RELE(vp); 2477619SJose.Borrego@Sun.COM } 2485331Samw } else { 2495331Samw /* 2505331Samw * For filesystems that don't support ACL-on-create, try 2515331Samw * to set the specified SD after create, which could actually 2525331Samw * fail because of conflicts between inherited security 2535331Samw * attributes upon creation and the specified SD. 2545331Samw * 2555331Samw * Passing kcred to smb_fsop_sdwrite() to overcome this issue. 2565331Samw */ 2575331Samw 2585331Samw if (is_dir) { 2597619SJose.Borrego@Sun.COM rc = smb_vop_mkdir(dir_snode->vp, name, attr, &vp, 2607619SJose.Borrego@Sun.COM flags, cr, NULL); 2615331Samw } else { 2627619SJose.Borrego@Sun.COM rc = smb_vop_create(dir_snode->vp, name, attr, &vp, 2637619SJose.Borrego@Sun.COM flags, cr, NULL); 2645331Samw } 2655331Samw 2665521Sas200622 if (rc != 0) 2675521Sas200622 return (rc); 2685521Sas200622 2697619SJose.Borrego@Sun.COM *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp, 2707619SJose.Borrego@Sun.COM name, dir_snode, NULL, ret_attr); 2717619SJose.Borrego@Sun.COM 2727619SJose.Borrego@Sun.COM if (*ret_snode != NULL) { 2737619SJose.Borrego@Sun.COM if (!smb_tree_has_feature(sr->tid_tree, 2747619SJose.Borrego@Sun.COM SMB_TREE_NFS_MOUNTED)) 2757619SJose.Borrego@Sun.COM rc = smb_fsop_sdwrite(sr, kcred, *ret_snode, 2767619SJose.Borrego@Sun.COM fs_sd, 1); 2777619SJose.Borrego@Sun.COM } else { 2785331Samw rc = ENOMEM; 2795331Samw } 2808670SJose.Borrego@Sun.COM 2818670SJose.Borrego@Sun.COM VN_RELE(vp); 2825331Samw } 2835331Samw 2845521Sas200622 if (rc != 0) { 2857619SJose.Borrego@Sun.COM if (is_dir) 2867619SJose.Borrego@Sun.COM (void) smb_vop_rmdir(dir_snode->vp, name, flags, cr); 2877619SJose.Borrego@Sun.COM else 2887619SJose.Borrego@Sun.COM (void) smb_vop_remove(dir_snode->vp, name, flags, cr); 2895521Sas200622 } 2905521Sas200622 2915331Samw return (rc); 2925331Samw } 2935331Samw 2945331Samw /* 2955331Samw * smb_fsop_create 2965331Samw * 2975331Samw * All SMB functions should use this wrapper to ensure that 2985331Samw * all the smb_vop_creates are performed with the appropriate credentials. 2995331Samw * Please document any direct calls to explain the reason 3005331Samw * for avoiding this wrapper. 3015331Samw * 3025331Samw * It is assumed that a reference exists on snode coming into this routine. 3035331Samw * 3045331Samw * *ret_snode is returned with a reference upon success. No reference is 3055331Samw * taken if an error is returned. 3065331Samw */ 3075331Samw int 3085331Samw smb_fsop_create( 3096139Sjb150015 smb_request_t *sr, 3106139Sjb150015 cred_t *cr, 3116139Sjb150015 smb_node_t *dir_snode, 3126139Sjb150015 char *name, 3136139Sjb150015 smb_attr_t *attr, 3146139Sjb150015 smb_node_t **ret_snode, 3156139Sjb150015 smb_attr_t *ret_attr) 3165331Samw { 3175331Samw struct open_param *op = &sr->arg.open; 3186139Sjb150015 smb_node_t *fnode; 3196139Sjb150015 smb_attr_t file_attr; 3206139Sjb150015 vnode_t *xattrdirvp; 3216139Sjb150015 vnode_t *vp; 3226139Sjb150015 char *longname = NULL; 3236139Sjb150015 char *namep; 3246139Sjb150015 char *fname; 3256139Sjb150015 char *sname; 3266139Sjb150015 int is_stream; 3276139Sjb150015 int flags = 0; 3286139Sjb150015 int rc = 0; 3296139Sjb150015 smb_fssd_t fs_sd; 3306139Sjb150015 uint32_t secinfo; 3316139Sjb150015 uint32_t status; 3325331Samw 3335331Samw ASSERT(cr); 3345331Samw ASSERT(dir_snode); 3355331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 3365331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 3375331Samw 3385331Samw ASSERT(ret_snode); 3395331Samw *ret_snode = 0; 3405331Samw 3415331Samw ASSERT(name); 3425331Samw if (*name == 0) 3435331Samw return (EINVAL); 3445331Samw 3455331Samw ASSERT(sr); 3465331Samw ASSERT(sr->tid_tree); 3477348SJose.Borrego@Sun.COM 3487348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 3497348SJose.Borrego@Sun.COM return (EACCES); 3507348SJose.Borrego@Sun.COM 3517348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 3525331Samw return (EROFS); 3535331Samw 3547348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 3555331Samw flags = SMB_IGNORE_CASE; 3565331Samw 3575331Samw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 3585331Samw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 3595331Samw 3605331Samw is_stream = smb_stream_parse_name(name, fname, sname); 3618334SJose.Borrego@Sun.COM if (is_stream == -1) { 3628334SJose.Borrego@Sun.COM kmem_free(fname, MAXNAMELEN); 3638334SJose.Borrego@Sun.COM kmem_free(sname, MAXNAMELEN); 3648334SJose.Borrego@Sun.COM return (EINVAL); 3658334SJose.Borrego@Sun.COM } 3665331Samw 3675331Samw if (is_stream) 3685331Samw namep = fname; 3695331Samw else 3705331Samw namep = name; 3715331Samw 3725331Samw if (smb_maybe_mangled_name(namep)) { 3735331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 3745331Samw 3755331Samw rc = smb_unmangle_name(sr, cr, dir_snode, namep, longname, 3765331Samw MAXNAMELEN, NULL, NULL, 1); 3775331Samw 3785331Samw if ((is_stream == 0) && (rc == 0)) 3795331Samw rc = EEXIST; 3805331Samw 3815331Samw if ((is_stream && rc) || 3825331Samw ((is_stream == 0) && (rc != ENOENT))) { 3835331Samw kmem_free(longname, MAXNAMELEN); 3845331Samw kmem_free(fname, MAXNAMELEN); 3855331Samw kmem_free(sname, MAXNAMELEN); 3865331Samw return (rc); 3875331Samw } 3885331Samw 3895331Samw if (is_stream) 3905331Samw namep = longname; 3915331Samw else 3925331Samw kmem_free(longname, MAXNAMELEN); 3935331Samw } 3945331Samw 3955331Samw if (is_stream) { 3965331Samw /* 3975331Samw * Look up the unnamed stream. 3985331Samw * 3995331Samw * Mangle processing in smb_fsop_lookup() for the unnamed 4005331Samw * stream won't be needed (as it was done above), but 4015331Samw * it may be needed on any link target (which 4025331Samw * smb_fsop_lookup() will provide). 4035331Samw */ 4045331Samw rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, 4055331Samw sr->tid_tree->t_snode, dir_snode, namep, &fnode, &file_attr, 4065331Samw 0, 0); 4075331Samw 4085331Samw if (longname) { 4095331Samw kmem_free(longname, MAXNAMELEN); 4105331Samw namep = NULL; 4115331Samw } 4125331Samw 4135331Samw if (rc != 0) { 4145331Samw kmem_free(fname, MAXNAMELEN); 4155331Samw kmem_free(sname, MAXNAMELEN); 4165331Samw return (rc); 4175331Samw } 4185331Samw 4195331Samw rc = smb_vop_stream_create(fnode->vp, sname, attr, &vp, 4205772Sas200622 &xattrdirvp, flags, cr); 4215331Samw 4225331Samw if (rc != 0) { 4235331Samw smb_node_release(fnode); 4245331Samw kmem_free(fname, MAXNAMELEN); 4255331Samw kmem_free(sname, MAXNAMELEN); 4265331Samw return (rc); 4275331Samw } 4285331Samw 4296030Sjb150015 attr->sa_vattr.va_uid = file_attr.sa_vattr.va_uid; 4306030Sjb150015 attr->sa_vattr.va_gid = file_attr.sa_vattr.va_gid; 4316030Sjb150015 attr->sa_mask = SMB_AT_UID | SMB_AT_GID; 4326030Sjb150015 4336030Sjb150015 /* 4346030Sjb150015 * The second parameter of smb_vop_setattr() is set to 4356030Sjb150015 * NULL, even though an unnamed stream exists. This is 4366030Sjb150015 * because we want to set the UID and GID on the named 4376030Sjb150015 * stream in this case for consistency with the (unnamed 4386030Sjb150015 * stream) file (see comments for smb_vop_setattr()). 4396030Sjb150015 */ 4406030Sjb150015 4417757SJanice.Chang@Sun.COM rc = smb_vop_setattr(vp, NULL, attr, 0, kcred); 4426030Sjb150015 4436030Sjb150015 if (rc != 0) { 4446030Sjb150015 smb_node_release(fnode); 4456030Sjb150015 kmem_free(fname, MAXNAMELEN); 4466030Sjb150015 kmem_free(sname, MAXNAMELEN); 4476030Sjb150015 return (rc); 4486030Sjb150015 } 4496030Sjb150015 4505331Samw *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, 4515331Samw vp, sname, ret_attr); 4525331Samw 4535331Samw smb_node_release(fnode); 4548670SJose.Borrego@Sun.COM VN_RELE(xattrdirvp); 4558670SJose.Borrego@Sun.COM VN_RELE(vp); 4565331Samw 4575331Samw if (*ret_snode == NULL) { 4585331Samw kmem_free(fname, MAXNAMELEN); 4595331Samw kmem_free(sname, MAXNAMELEN); 4605331Samw return (ENOMEM); 4615331Samw } 4625331Samw } else { 4635521Sas200622 if (op->sd) { 4645331Samw /* 4655331Samw * SD sent by client in Windows format. Needs to be 4665331Samw * converted to FS format. No inheritance. 4675331Samw */ 4685521Sas200622 secinfo = smb_sd_get_secinfo(op->sd); 4695521Sas200622 smb_fssd_init(&fs_sd, secinfo, 0); 4705521Sas200622 4715521Sas200622 status = smb_sd_tofs(op->sd, &fs_sd); 4725331Samw if (status == NT_STATUS_SUCCESS) { 4735331Samw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 4745331Samw name, attr, ret_snode, ret_attr, &fs_sd); 4755331Samw } 4765331Samw else 4775331Samw rc = EINVAL; 4785521Sas200622 smb_fssd_term(&fs_sd); 4795331Samw } else if (sr->tid_tree->t_acltype == ACE_T) { 4805331Samw /* 4815331Samw * No incoming SD and filesystem is ZFS 4825331Samw * Server applies Windows inheritance rules, 4835331Samw * see smb_fsop_sdinherit() comments as to why. 4845331Samw */ 4855521Sas200622 smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, 0); 4865331Samw rc = smb_fsop_sdinherit(sr, dir_snode, &fs_sd); 4875331Samw if (rc == 0) { 4885331Samw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 4895331Samw name, attr, ret_snode, ret_attr, &fs_sd); 4905331Samw } 4915331Samw 4925521Sas200622 smb_fssd_term(&fs_sd); 4935331Samw } else { 4945331Samw /* 4955331Samw * No incoming SD and filesystem is not ZFS 4965331Samw * let the filesystem handles the inheritance. 4975331Samw */ 4985331Samw rc = smb_vop_create(dir_snode->vp, name, attr, &vp, 4995772Sas200622 flags, cr, NULL); 5005331Samw 5015331Samw if (rc == 0) { 5025331Samw *ret_snode = smb_node_lookup(sr, op, cr, vp, 5035331Samw name, dir_snode, NULL, ret_attr); 5045331Samw 5058670SJose.Borrego@Sun.COM if (*ret_snode == NULL) 5065331Samw rc = ENOMEM; 5078670SJose.Borrego@Sun.COM 5088670SJose.Borrego@Sun.COM VN_RELE(vp); 5095331Samw } 5105331Samw 5115331Samw } 5125331Samw } 5135331Samw 5145331Samw kmem_free(fname, MAXNAMELEN); 5155331Samw kmem_free(sname, MAXNAMELEN); 5165331Samw return (rc); 5175331Samw } 5185331Samw 5195331Samw /* 5205331Samw * smb_fsop_mkdir 5215331Samw * 5225331Samw * All SMB functions should use this wrapper to ensure that 5235331Samw * the the calls are performed with the appropriate credentials. 5245331Samw * Please document any direct call to explain the reason 5255331Samw * for avoiding this wrapper. 5265331Samw * 5275331Samw * It is assumed that a reference exists on snode coming into this routine. 5285331Samw * 5295331Samw * *ret_snode is returned with a reference upon success. No reference is 5305331Samw * taken if an error is returned. 5315331Samw */ 5325331Samw int 5335331Samw smb_fsop_mkdir( 5346139Sjb150015 smb_request_t *sr, 5355331Samw cred_t *cr, 5365331Samw smb_node_t *dir_snode, 5375331Samw char *name, 5385331Samw smb_attr_t *attr, 5395331Samw smb_node_t **ret_snode, 5405331Samw smb_attr_t *ret_attr) 5415331Samw { 5425331Samw struct open_param *op = &sr->arg.open; 5435331Samw char *longname; 5445331Samw vnode_t *vp; 5455331Samw int flags = 0; 5465331Samw smb_fssd_t fs_sd; 5475331Samw uint32_t secinfo; 5485331Samw uint32_t status; 5495331Samw int rc; 5505331Samw ASSERT(cr); 5515331Samw ASSERT(dir_snode); 5525331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 5535331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 5545331Samw 5555331Samw ASSERT(ret_snode); 5565331Samw *ret_snode = 0; 5575331Samw 5585331Samw ASSERT(name); 5595331Samw if (*name == 0) 5605331Samw return (EINVAL); 5615331Samw 5625331Samw ASSERT(sr); 5635331Samw ASSERT(sr->tid_tree); 5647348SJose.Borrego@Sun.COM 5657348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 5667348SJose.Borrego@Sun.COM return (EACCES); 5677348SJose.Borrego@Sun.COM 5687348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 5695331Samw return (EROFS); 5705331Samw 5715331Samw if (smb_maybe_mangled_name(name)) { 5725331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 5735331Samw rc = smb_unmangle_name(sr, cr, dir_snode, name, longname, 5745331Samw MAXNAMELEN, NULL, NULL, 1); 5755331Samw 5765331Samw kmem_free(longname, MAXNAMELEN); 5775331Samw 5785331Samw /* 5795331Samw * If the name passed in by the client has an unmangled 5805331Samw * equivalent that is found in the specified directory, 5815331Samw * then the mkdir cannot succeed. Return EEXIST. 5825331Samw * 5835331Samw * Only if ENOENT is returned will a mkdir be attempted. 5845331Samw */ 5855331Samw 5865331Samw if (rc == 0) 5875331Samw rc = EEXIST; 5885331Samw 5895331Samw if (rc != ENOENT) 5905331Samw return (rc); 5915331Samw } 5925331Samw 5937348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 5945331Samw flags = SMB_IGNORE_CASE; 5955331Samw 5965521Sas200622 if (op->sd) { 5975331Samw /* 5985331Samw * SD sent by client in Windows format. Needs to be 5995331Samw * converted to FS format. No inheritance. 6005331Samw */ 6015521Sas200622 secinfo = smb_sd_get_secinfo(op->sd); 6025521Sas200622 smb_fssd_init(&fs_sd, secinfo, SMB_FSSD_FLAGS_DIR); 6035521Sas200622 6045521Sas200622 status = smb_sd_tofs(op->sd, &fs_sd); 6055331Samw if (status == NT_STATUS_SUCCESS) { 6065331Samw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 6075331Samw name, attr, ret_snode, ret_attr, &fs_sd); 6085331Samw } 6095331Samw else 6105331Samw rc = EINVAL; 6115521Sas200622 smb_fssd_term(&fs_sd); 6125331Samw } else if (sr->tid_tree->t_acltype == ACE_T) { 6135331Samw /* 6145331Samw * No incoming SD and filesystem is ZFS 6155331Samw * Server applies Windows inheritance rules, 6165331Samw * see smb_fsop_sdinherit() comments as to why. 6175331Samw */ 6185521Sas200622 smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, SMB_FSSD_FLAGS_DIR); 6195331Samw rc = smb_fsop_sdinherit(sr, dir_snode, &fs_sd); 6205331Samw if (rc == 0) { 6215331Samw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 6225331Samw name, attr, ret_snode, ret_attr, &fs_sd); 6235331Samw } 6245331Samw 6255521Sas200622 smb_fssd_term(&fs_sd); 6265331Samw 6275331Samw } else { 6285331Samw rc = smb_vop_mkdir(dir_snode->vp, name, attr, &vp, flags, cr, 6295772Sas200622 NULL); 6305331Samw 6315331Samw if (rc == 0) { 6325331Samw *ret_snode = smb_node_lookup(sr, op, cr, vp, name, 6335331Samw dir_snode, NULL, ret_attr); 6345331Samw 6358670SJose.Borrego@Sun.COM if (*ret_snode == NULL) 6365331Samw rc = ENOMEM; 6378670SJose.Borrego@Sun.COM 6388670SJose.Borrego@Sun.COM VN_RELE(vp); 6395331Samw } 6405331Samw } 6415331Samw 6425331Samw return (rc); 6435331Samw } 6445331Samw 6455331Samw /* 6465331Samw * smb_fsop_remove 6475331Samw * 6485331Samw * All SMB functions should use this wrapper to ensure that 6495331Samw * the the calls are performed with the appropriate credentials. 6505331Samw * Please document any direct call to explain the reason 6515331Samw * for avoiding this wrapper. 6525331Samw * 6535331Samw * It is assumed that a reference exists on snode coming into this routine. 6545331Samw * 6555331Samw * od: This means that the name passed in is an on-disk name. 6565331Samw * A null smb_request might be passed to this function. 6575331Samw */ 6585331Samw 6595331Samw int 6605331Samw smb_fsop_remove( 6616139Sjb150015 smb_request_t *sr, 6626139Sjb150015 cred_t *cr, 6636139Sjb150015 smb_node_t *dir_snode, 6646139Sjb150015 char *name, 6656139Sjb150015 int od) 6665331Samw { 6676139Sjb150015 smb_node_t *fnode; 6686139Sjb150015 smb_attr_t file_attr; 6696139Sjb150015 char *longname; 6706139Sjb150015 char *fname; 6716139Sjb150015 char *sname; 6726139Sjb150015 int flags = 0; 6736139Sjb150015 int rc; 6745331Samw 6755331Samw ASSERT(cr); 6765331Samw /* 6775331Samw * The state of the node could be SMB_NODE_STATE_DESTROYING if this 6785331Samw * function is called during the deletion of the node (because of 6795331Samw * DELETE_ON_CLOSE). 6805331Samw */ 6815331Samw ASSERT(dir_snode); 6825331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 6835331Samw 6848845Samw@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0 || 6858845Samw@Sun.COM SMB_TREE_HAS_ACCESS(sr, ACE_DELETE) == 0) 6865331Samw return (EACCES); 6875331Samw 6887348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 6895331Samw return (EROFS); 6905331Samw 6915331Samw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 6925331Samw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 6935331Samw 6945967Scp160787 /* 6955967Scp160787 * If the passed-in name is an on-disk name, 6965967Scp160787 * then we need to do a case-sensitive remove. 6975967Scp160787 * This is important if the on-disk name 6985967Scp160787 * corresponds to a mangled name passed in by 6995967Scp160787 * the client. We want to make sure to remove 7005967Scp160787 * the exact file specified by the client, 7015967Scp160787 * instead of letting the underlying file system 7025967Scp160787 * do a remove on the "first match." 7035967Scp160787 */ 7045967Scp160787 7057348SJose.Borrego@Sun.COM if ((od == 0) && SMB_TREE_IS_CASEINSENSITIVE(sr)) 7065967Scp160787 flags = SMB_IGNORE_CASE; 7075967Scp160787 7085967Scp160787 if (dir_snode->flags & NODE_XATTR_DIR) { 7095967Scp160787 rc = smb_vop_stream_remove(dir_snode->dir_snode->vp, 7105967Scp160787 name, flags, cr); 7118334SJose.Borrego@Sun.COM } else if ((rc = smb_stream_parse_name(name, fname, sname)) != 0) { 7128334SJose.Borrego@Sun.COM if (rc == -1) { 7138334SJose.Borrego@Sun.COM kmem_free(fname, MAXNAMELEN); 7148334SJose.Borrego@Sun.COM kmem_free(sname, MAXNAMELEN); 7158334SJose.Borrego@Sun.COM return (EINVAL); 7168334SJose.Borrego@Sun.COM } 7178334SJose.Borrego@Sun.COM 7185967Scp160787 /* 7195967Scp160787 * It is assumed that "name" corresponds to the path 7205967Scp160787 * passed in by the client, and no need of suppressing 7215967Scp160787 * case-insensitive lookups is needed. 7225967Scp160787 */ 7235331Samw 7245331Samw ASSERT(od == 0); 7255331Samw 7265331Samw /* 7275331Samw * Look up the unnamed stream (i.e. fname). 7285331Samw * Unmangle processing will be done on fname 7295331Samw * as well as any link target. 7305331Samw */ 7315331Samw 7325331Samw rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, 7335331Samw sr->tid_tree->t_snode, dir_snode, fname, &fnode, &file_attr, 7345331Samw 0, 0); 7355331Samw 7365331Samw if (rc != 0) { 7375331Samw kmem_free(fname, MAXNAMELEN); 7385331Samw kmem_free(sname, MAXNAMELEN); 7395331Samw return (rc); 7405331Samw } 7415331Samw 7425331Samw /* 7435331Samw * XXX 7445331Samw * Need to find out what permission is required by NTFS 7455331Samw * to remove a stream. 7465331Samw */ 7475772Sas200622 rc = smb_vop_stream_remove(fnode->vp, sname, flags, cr); 7485331Samw 7495331Samw smb_node_release(fnode); 7505331Samw } else { 7515772Sas200622 rc = smb_vop_remove(dir_snode->vp, name, flags, cr); 7525331Samw 7535331Samw if (rc == ENOENT) { 7545331Samw if (smb_maybe_mangled_name(name) == 0) { 7555331Samw kmem_free(fname, MAXNAMELEN); 7565331Samw kmem_free(sname, MAXNAMELEN); 7575331Samw return (rc); 7585331Samw } 7595331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 7605331Samw 7615331Samw rc = smb_unmangle_name(sr, cr, dir_snode, name, 7625331Samw longname, MAXNAMELEN, NULL, NULL, 1); 7635331Samw 7645331Samw if (rc == 0) { 7655331Samw /* 7665331Samw * We passed "1" as the "od" parameter 7675331Samw * to smb_unmangle_name(), such that longname 7685331Samw * is the real (case-sensitive) on-disk name. 7695331Samw * We make sure we do a remove on this exact 7705331Samw * name, as the name was mangled and denotes 7715331Samw * a unique file. 7725331Samw */ 7735331Samw flags &= ~SMB_IGNORE_CASE; 7745331Samw rc = smb_vop_remove(dir_snode->vp, longname, 7755772Sas200622 flags, cr); 7765331Samw } 7775331Samw 7785331Samw kmem_free(longname, MAXNAMELEN); 7795331Samw } 7805331Samw } 7815331Samw 7825331Samw kmem_free(fname, MAXNAMELEN); 7835331Samw kmem_free(sname, MAXNAMELEN); 7845331Samw return (rc); 7855331Samw } 7865331Samw 7875331Samw /* 7885331Samw * smb_fsop_remove_streams 7895331Samw * 7905331Samw * This function removes a file's streams without removing the 7915331Samw * file itself. 7925331Samw * 7938670SJose.Borrego@Sun.COM * It is assumed that fnode is not a link. 7945331Samw */ 7955331Samw int 7966139Sjb150015 smb_fsop_remove_streams(smb_request_t *sr, cred_t *cr, smb_node_t *fnode) 7975331Samw { 7988670SJose.Borrego@Sun.COM int rc, flags = 0; 7998670SJose.Borrego@Sun.COM uint16_t odid; 8008670SJose.Borrego@Sun.COM smb_odir_t *od; 8018670SJose.Borrego@Sun.COM smb_odirent_t *odirent; 8028670SJose.Borrego@Sun.COM boolean_t eos; 8035331Samw 8047348SJose.Borrego@Sun.COM ASSERT(sr); 8055331Samw ASSERT(cr); 8065331Samw ASSERT(fnode); 8075331Samw ASSERT(fnode->n_magic == SMB_NODE_MAGIC); 8085331Samw ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING); 8095331Samw 8107348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, fnode) == 0) 8115331Samw return (EACCES); 8125331Samw 8137348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 8145331Samw return (EROFS); 8155331Samw 8167348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 8175331Samw flags = SMB_IGNORE_CASE; 8185331Samw 8198670SJose.Borrego@Sun.COM /* TBD - error codes */ 8208670SJose.Borrego@Sun.COM if ((odid = smb_odir_openat(sr, fnode)) == 0) 8218670SJose.Borrego@Sun.COM return (ENOENT); 8228670SJose.Borrego@Sun.COM if ((od = smb_tree_lookup_odir(sr->tid_tree, odid)) == NULL) 8238670SJose.Borrego@Sun.COM return (ENOENT); 8245331Samw 8258670SJose.Borrego@Sun.COM odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP); 8268670SJose.Borrego@Sun.COM for (;;) { 8278670SJose.Borrego@Sun.COM rc = smb_odir_read(sr, od, odirent, &eos); 8288670SJose.Borrego@Sun.COM if ((rc != 0) || (eos)) 8295331Samw break; 8308670SJose.Borrego@Sun.COM (void) smb_vop_remove(od->d_dnode->vp, odirent->od_name, 8318670SJose.Borrego@Sun.COM flags, cr); 8328670SJose.Borrego@Sun.COM } 8338670SJose.Borrego@Sun.COM kmem_free(odirent, sizeof (smb_odirent_t)); 8345331Samw 8358670SJose.Borrego@Sun.COM smb_odir_release(od); 8368670SJose.Borrego@Sun.COM smb_odir_close(od); 8375331Samw return (rc); 8385331Samw } 8395331Samw 8405331Samw /* 8415331Samw * smb_fsop_rmdir 8425331Samw * 8435331Samw * All SMB functions should use this wrapper to ensure that 8445331Samw * the the calls are performed with the appropriate credentials. 8455331Samw * Please document any direct call to explain the reason 8465331Samw * for avoiding this wrapper. 8475331Samw * 8485331Samw * It is assumed that a reference exists on snode coming into this routine. 8495331Samw * 8505331Samw * od: This means that the name passed in is an on-disk name. 8515331Samw */ 8525331Samw 8535331Samw int 8545331Samw smb_fsop_rmdir( 8556139Sjb150015 smb_request_t *sr, 8566139Sjb150015 cred_t *cr, 8576139Sjb150015 smb_node_t *dir_snode, 8586139Sjb150015 char *name, 8596139Sjb150015 int od) 8605331Samw { 8616139Sjb150015 int rc; 8626139Sjb150015 int flags = 0; 8636139Sjb150015 char *longname; 8645331Samw 8655331Samw ASSERT(cr); 8665331Samw /* 8675331Samw * The state of the node could be SMB_NODE_STATE_DESTROYING if this 8685331Samw * function is called during the deletion of the node (because of 8695331Samw * DELETE_ON_CLOSE). 8705331Samw */ 8715331Samw ASSERT(dir_snode); 8725331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 8735331Samw 8748845Samw@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0 || 8758845Samw@Sun.COM SMB_TREE_HAS_ACCESS(sr, ACE_DELETE_CHILD) == 0) 8765331Samw return (EACCES); 8775331Samw 8787348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 8795331Samw return (EROFS); 8805331Samw 8815331Samw /* 8825331Samw * If the passed-in name is an on-disk name, 8835331Samw * then we need to do a case-sensitive rmdir. 8845331Samw * This is important if the on-disk name 8855331Samw * corresponds to a mangled name passed in by 8865331Samw * the client. We want to make sure to remove 8875331Samw * the exact directory specified by the client, 8885331Samw * instead of letting the underlying file system 8895331Samw * do a rmdir on the "first match." 8905331Samw */ 8915331Samw 8927348SJose.Borrego@Sun.COM if ((od == 0) && SMB_TREE_IS_CASEINSENSITIVE(sr)) 8935331Samw flags = SMB_IGNORE_CASE; 8945331Samw 8955772Sas200622 rc = smb_vop_rmdir(dir_snode->vp, name, flags, cr); 8965331Samw 8975331Samw if (rc == ENOENT) { 8985331Samw if (smb_maybe_mangled_name(name) == 0) 8995331Samw return (rc); 9005331Samw 9015331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 9025331Samw 9035331Samw rc = smb_unmangle_name(sr, cr, dir_snode, 9045331Samw name, longname, MAXNAMELEN, NULL, 9055331Samw NULL, 1); 9065331Samw 9075331Samw if (rc == 0) { 9085331Samw /* 9095331Samw * We passed "1" as the "od" parameter 9105331Samw * to smb_unmangle_name(), such that longname 9115331Samw * is the real (case-sensitive) on-disk name. 9125331Samw * We make sure we do a rmdir on this exact 9135331Samw * name, as the name was mangled and denotes 9145331Samw * a unique directory. 9155331Samw */ 9165331Samw flags &= ~SMB_IGNORE_CASE; 9175772Sas200622 rc = smb_vop_rmdir(dir_snode->vp, longname, flags, cr); 9185331Samw } 9195331Samw 9205331Samw kmem_free(longname, MAXNAMELEN); 9215331Samw } 9225331Samw 9235331Samw return (rc); 9245331Samw } 9255331Samw 9265331Samw /* 9275331Samw * smb_fsop_getattr 9285331Samw * 9295331Samw * All SMB functions should use this wrapper to ensure that 9305331Samw * the the calls are performed with the appropriate credentials. 9315331Samw * Please document any direct call to explain the reason 9325331Samw * for avoiding this wrapper. 9335331Samw * 9345331Samw * It is assumed that a reference exists on snode coming into this routine. 9355331Samw */ 9365331Samw int 9376139Sjb150015 smb_fsop_getattr(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 9385331Samw smb_attr_t *attr) 9395331Samw { 9405331Samw smb_node_t *unnamed_node; 9415331Samw vnode_t *unnamed_vp = NULL; 9425331Samw uint32_t status; 9435331Samw uint32_t access = 0; 9445331Samw int flags = 0; 9455772Sas200622 int rc; 9465331Samw 9475331Samw ASSERT(cr); 9485331Samw ASSERT(snode); 9495331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 9505331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 9515331Samw 9528845Samw@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0 || 9538845Samw@Sun.COM SMB_TREE_HAS_ACCESS(sr, ACE_READ_ATTRIBUTES) == 0) 9545331Samw return (EACCES); 9555331Samw 9565331Samw if (sr->fid_ofile) { 9575331Samw /* if uid and/or gid is requested */ 9585331Samw if (attr->sa_mask & (SMB_AT_UID|SMB_AT_GID)) 9595331Samw access |= READ_CONTROL; 9605331Samw 9615331Samw /* if anything else is also requested */ 9625331Samw if (attr->sa_mask & ~(SMB_AT_UID|SMB_AT_GID)) 9635331Samw access |= FILE_READ_ATTRIBUTES; 9645331Samw 9655331Samw status = smb_ofile_access(sr->fid_ofile, cr, access); 9665331Samw if (status != NT_STATUS_SUCCESS) 9675331Samw return (EACCES); 9685331Samw 9697348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, 9707348SJose.Borrego@Sun.COM SMB_TREE_ACEMASKONACCESS)) 9715331Samw flags = ATTR_NOACLCHECK; 9725331Samw } 9735331Samw 9745331Samw unnamed_node = SMB_IS_STREAM(snode); 9755331Samw 9765331Samw if (unnamed_node) { 9775331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 9785331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 9795331Samw unnamed_vp = unnamed_node->vp; 9805331Samw } 9815331Samw 9825772Sas200622 rc = smb_vop_getattr(snode->vp, unnamed_vp, attr, flags, cr); 9835772Sas200622 if (rc == 0) 9845772Sas200622 snode->attr = *attr; 9855772Sas200622 9865772Sas200622 return (rc); 9875331Samw } 9885331Samw 9895331Samw /* 9905331Samw * smb_fsop_rename 9915331Samw * 9925331Samw * All SMB functions should use this smb_vop_rename wrapper to ensure that 9935331Samw * the smb_vop_rename is performed with the appropriate credentials. 9945331Samw * Please document any direct call to smb_vop_rename to explain the reason 9955331Samw * for avoiding this wrapper. 9965331Samw * 9975331Samw * It is assumed that references exist on from_dir_snode and to_dir_snode coming 9985331Samw * into this routine. 9995331Samw */ 10005331Samw int 10015331Samw smb_fsop_rename( 10026139Sjb150015 smb_request_t *sr, 10035331Samw cred_t *cr, 10045331Samw smb_node_t *from_dir_snode, 10055331Samw char *from_name, 10065331Samw smb_node_t *to_dir_snode, 10075331Samw char *to_name) 10085331Samw { 10095331Samw smb_node_t *from_snode; 10105331Samw smb_attr_t tmp_attr; 10115331Samw vnode_t *from_vp; 10125331Samw int flags = 0; 10135331Samw int rc; 10148845Samw@Sun.COM boolean_t isdir; 10155331Samw 10165331Samw ASSERT(cr); 10175331Samw ASSERT(from_dir_snode); 10185331Samw ASSERT(from_dir_snode->n_magic == SMB_NODE_MAGIC); 10195331Samw ASSERT(from_dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 10205331Samw 10215331Samw ASSERT(to_dir_snode); 10225331Samw ASSERT(to_dir_snode->n_magic == SMB_NODE_MAGIC); 10235331Samw ASSERT(to_dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 10245331Samw 10257348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, from_dir_snode) == 0) 10265331Samw return (EACCES); 10275331Samw 10287348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, to_dir_snode) == 0) 10295331Samw return (EACCES); 10305331Samw 10315331Samw ASSERT(sr); 10325331Samw ASSERT(sr->tid_tree); 10337348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 10345331Samw return (EROFS); 10355331Samw 10365331Samw /* 10377348SJose.Borrego@Sun.COM * Note: There is no need to check SMB_TREE_IS_CASEINSENSITIVE 10385331Samw * here. 10395331Samw * 10405331Samw * A case-sensitive rename is always done in this routine 10415331Samw * because we are using the on-disk name from an earlier lookup. 10425331Samw * If a mangled name was passed in by the caller (denoting a 10435331Samw * deterministic lookup), then the exact file must be renamed 10445331Samw * (i.e. SMB_IGNORE_CASE must not be passed to VOP_RENAME, or 10455331Samw * else the underlying file system might return a "first-match" 10465331Samw * on this on-disk name, possibly resulting in the wrong file). 10475331Samw */ 10485331Samw 10495331Samw /* 10505331Samw * XXX: Lock required through smb_node_release() below? 10515331Samw */ 10525331Samw 10535331Samw rc = smb_vop_lookup(from_dir_snode->vp, from_name, &from_vp, NULL, 0, 10545772Sas200622 NULL, cr); 10555331Samw 10565331Samw if (rc != 0) 10575331Samw return (rc); 10585331Samw 10598845Samw@Sun.COM isdir = from_vp->v_type == VDIR; 10608845Samw@Sun.COM 10618845Samw@Sun.COM if ((isdir && SMB_TREE_HAS_ACCESS(sr, 10628845Samw@Sun.COM ACE_DELETE_CHILD | ACE_ADD_SUBDIRECTORY) != 10638845Samw@Sun.COM (ACE_DELETE_CHILD | ACE_ADD_SUBDIRECTORY)) || 10648845Samw@Sun.COM (!isdir && SMB_TREE_HAS_ACCESS(sr, ACE_DELETE | ACE_ADD_FILE) != 10658845Samw@Sun.COM (ACE_DELETE | ACE_ADD_FILE))) 10668845Samw@Sun.COM return (EACCES); 10678845Samw@Sun.COM 10685331Samw rc = smb_vop_rename(from_dir_snode->vp, from_name, to_dir_snode->vp, 10695772Sas200622 to_name, flags, cr); 10705331Samw 10715331Samw if (rc == 0) { 10725331Samw from_snode = smb_node_lookup(sr, NULL, cr, from_vp, from_name, 10735331Samw from_dir_snode, NULL, &tmp_attr); 10745331Samw 10755331Samw if (from_snode == NULL) { 10768670SJose.Borrego@Sun.COM rc = ENOMEM; 10778670SJose.Borrego@Sun.COM } else { 1078*8934SJose.Borrego@Sun.COM smb_node_rename(from_dir_snode, from_snode, 10798670SJose.Borrego@Sun.COM to_dir_snode, to_name); 10808670SJose.Borrego@Sun.COM smb_node_release(from_snode); 10815331Samw } 10825331Samw } 10838670SJose.Borrego@Sun.COM VN_RELE(from_vp); 10845331Samw 10855331Samw /* XXX: unlock */ 10865331Samw 10875331Samw return (rc); 10885331Samw } 10895331Samw 10905331Samw /* 10915331Samw * smb_fsop_setattr 10925331Samw * 10935331Samw * All SMB functions should use this wrapper to ensure that 10945331Samw * the the calls are performed with the appropriate credentials. 10955331Samw * Please document any direct call to explain the reason 10965331Samw * for avoiding this wrapper. 10975331Samw * 10985331Samw * It is assumed that a reference exists on snode coming into this routine. 10995331Samw * A null smb_request might be passed to this function. 11005331Samw */ 11015331Samw int 11025331Samw smb_fsop_setattr( 11036139Sjb150015 smb_request_t *sr, 11046139Sjb150015 cred_t *cr, 11056139Sjb150015 smb_node_t *snode, 11066139Sjb150015 smb_attr_t *set_attr, 11076139Sjb150015 smb_attr_t *ret_attr) 11085331Samw { 11095331Samw smb_node_t *unnamed_node; 11105331Samw vnode_t *unnamed_vp = NULL; 11115331Samw uint32_t status; 11127619SJose.Borrego@Sun.COM uint32_t access; 11135331Samw int rc = 0; 11145331Samw int flags = 0; 11157619SJose.Borrego@Sun.COM uint_t sa_mask; 11165331Samw 11175331Samw ASSERT(cr); 11185331Samw ASSERT(snode); 11195331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 11205331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 11215331Samw 11227348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0) 11235331Samw return (EACCES); 11245331Samw 11257348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 11265331Samw return (EROFS); 11275331Samw 11288845Samw@Sun.COM if (SMB_TREE_HAS_ACCESS(sr, 11298845Samw@Sun.COM ACE_WRITE_ATTRIBUTES | ACE_WRITE_NAMED_ATTRS) == 0) 11308845Samw@Sun.COM return (EACCES); 11318845Samw@Sun.COM 11327348SJose.Borrego@Sun.COM if (sr && (set_attr->sa_mask & SMB_AT_SIZE)) { 11337348SJose.Borrego@Sun.COM if (sr->fid_ofile) { 11347348SJose.Borrego@Sun.COM if (SMB_OFILE_IS_READONLY(sr->fid_ofile)) 11357348SJose.Borrego@Sun.COM return (EACCES); 11367348SJose.Borrego@Sun.COM } else { 11377348SJose.Borrego@Sun.COM if (SMB_PATHFILE_IS_READONLY(sr, snode)) 11387348SJose.Borrego@Sun.COM return (EACCES); 11397348SJose.Borrego@Sun.COM } 11407348SJose.Borrego@Sun.COM } 11417348SJose.Borrego@Sun.COM 11425331Samw /* sr could be NULL in some cases */ 11435331Samw if (sr && sr->fid_ofile) { 11447619SJose.Borrego@Sun.COM sa_mask = set_attr->sa_mask; 11457619SJose.Borrego@Sun.COM access = 0; 11467619SJose.Borrego@Sun.COM 11477619SJose.Borrego@Sun.COM if (sa_mask & SMB_AT_SIZE) { 11487619SJose.Borrego@Sun.COM access |= FILE_WRITE_DATA; 11497619SJose.Borrego@Sun.COM sa_mask &= ~SMB_AT_SIZE; 11507619SJose.Borrego@Sun.COM } 11517619SJose.Borrego@Sun.COM 11527619SJose.Borrego@Sun.COM if (sa_mask & (SMB_AT_UID|SMB_AT_GID)) { 11535331Samw access |= WRITE_OWNER; 11547619SJose.Borrego@Sun.COM sa_mask &= ~(SMB_AT_UID|SMB_AT_GID); 11557619SJose.Borrego@Sun.COM } 11567619SJose.Borrego@Sun.COM 11577619SJose.Borrego@Sun.COM if (sa_mask) 11585331Samw access |= FILE_WRITE_ATTRIBUTES; 11595331Samw 11605331Samw status = smb_ofile_access(sr->fid_ofile, cr, access); 11615331Samw if (status != NT_STATUS_SUCCESS) 11625331Samw return (EACCES); 11635331Samw 11647348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, 11657348SJose.Borrego@Sun.COM SMB_TREE_ACEMASKONACCESS)) 11665331Samw flags = ATTR_NOACLCHECK; 11675331Samw } 11685331Samw 11695331Samw unnamed_node = SMB_IS_STREAM(snode); 11705331Samw 11715331Samw if (unnamed_node) { 11725331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 11735331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 11745331Samw unnamed_vp = unnamed_node->vp; 11755331Samw } 11767757SJanice.Chang@Sun.COM 11777757SJanice.Chang@Sun.COM rc = smb_vop_setattr(snode->vp, unnamed_vp, set_attr, flags, cr); 11785331Samw 11795331Samw if ((rc == 0) && ret_attr) { 11805331Samw /* 11815772Sas200622 * Use kcred to update the node attr because this 11825772Sas200622 * call is not being made on behalf of the user. 11835331Samw */ 11845331Samw ret_attr->sa_mask = SMB_AT_ALL; 11857348SJose.Borrego@Sun.COM rc = smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, flags, 11867348SJose.Borrego@Sun.COM kcred); 11875772Sas200622 if (rc == 0) 11885772Sas200622 snode->attr = *ret_attr; 11895331Samw } 11905331Samw 11915331Samw return (rc); 11925331Samw } 11935331Samw 11945331Samw /* 11955331Samw * smb_fsop_read 11965331Samw * 11975331Samw * All SMB functions should use this wrapper to ensure that 11985331Samw * the the calls are performed with the appropriate credentials. 11995331Samw * Please document any direct call to explain the reason 12005331Samw * for avoiding this wrapper. 12015331Samw * 12025331Samw * It is assumed that a reference exists on snode coming into this routine. 12035331Samw */ 12045331Samw int 12055331Samw smb_fsop_read( 12065331Samw struct smb_request *sr, 12075331Samw cred_t *cr, 12085331Samw smb_node_t *snode, 12095331Samw uio_t *uio, 12105331Samw smb_attr_t *ret_attr) 12115331Samw { 12125331Samw smb_node_t *unnamed_node; 12135331Samw vnode_t *unnamed_vp = NULL; 12147348SJose.Borrego@Sun.COM caller_context_t ct; 12155772Sas200622 int svmand; 12165331Samw int rc; 12175331Samw 12185331Samw ASSERT(cr); 12195331Samw ASSERT(snode); 12205331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 12215331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 12225331Samw 12235331Samw ASSERT(sr); 12245331Samw ASSERT(sr->fid_ofile); 12255331Samw 12268845Samw@Sun.COM if (SMB_TREE_HAS_ACCESS(sr, ACE_READ_DATA) == 0) 12278845Samw@Sun.COM return (EACCES); 12288845Samw@Sun.COM 12295331Samw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_READ_DATA); 12305331Samw if (rc != NT_STATUS_SUCCESS) { 12315331Samw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_EXECUTE); 12325331Samw if (rc != NT_STATUS_SUCCESS) 12335331Samw return (EACCES); 12345331Samw } 12355331Samw 12365331Samw unnamed_node = SMB_IS_STREAM(snode); 12375331Samw if (unnamed_node) { 12385331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 12395331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 12405331Samw unnamed_vp = unnamed_node->vp; 12415331Samw /* 12425331Samw * Streams permission are checked against the unnamed stream, 12435331Samw * but in FS level they have their own permissions. To avoid 12445331Samw * rejection by FS due to lack of permission on the actual 12455331Samw * extended attr kcred is passed for streams. 12465331Samw */ 12475331Samw cr = kcred; 12485331Samw } 12495331Samw 12505772Sas200622 smb_node_start_crit(snode, RW_READER); 12517348SJose.Borrego@Sun.COM rc = nbl_svmand(snode->vp, kcred, &svmand); 12525772Sas200622 if (rc) { 12535772Sas200622 smb_node_end_crit(snode); 12545772Sas200622 return (rc); 12555772Sas200622 } 12565772Sas200622 12577348SJose.Borrego@Sun.COM ct = smb_ct; 12587348SJose.Borrego@Sun.COM ct.cc_pid = sr->fid_ofile->f_uniqid; 12595772Sas200622 rc = nbl_lock_conflict(snode->vp, NBL_READ, uio->uio_loffset, 12607348SJose.Borrego@Sun.COM uio->uio_iov->iov_len, svmand, &ct); 12615772Sas200622 12625772Sas200622 if (rc) { 12635772Sas200622 smb_node_end_crit(snode); 12646432Sas200622 return (ERANGE); 12655772Sas200622 } 12665772Sas200622 rc = smb_vop_read(snode->vp, uio, cr); 12675772Sas200622 12685772Sas200622 if (rc == 0 && ret_attr) { 12695331Samw /* 12705772Sas200622 * Use kcred to update the node attr because this 12715772Sas200622 * call is not being made on behalf of the user. 12725331Samw */ 12735331Samw ret_attr->sa_mask = SMB_AT_ALL; 12745772Sas200622 if (smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0, 12755772Sas200622 kcred) == 0) { 12765772Sas200622 snode->attr = *ret_attr; 12775772Sas200622 } 12785331Samw } 12795331Samw 12805772Sas200622 smb_node_end_crit(snode); 12815772Sas200622 12825331Samw return (rc); 12835331Samw } 12845331Samw 12855331Samw /* 12865331Samw * smb_fsop_write 12875331Samw * 12885331Samw * This is a wrapper function used for smb_write and smb_write_raw operations. 12895331Samw * 12905331Samw * It is assumed that a reference exists on snode coming into this routine. 12915331Samw */ 12925331Samw int 12935331Samw smb_fsop_write( 12946139Sjb150015 smb_request_t *sr, 12955331Samw cred_t *cr, 12965331Samw smb_node_t *snode, 12975331Samw uio_t *uio, 12985331Samw uint32_t *lcount, 12995331Samw smb_attr_t *ret_attr, 13007052Samw int ioflag) 13015331Samw { 13025331Samw smb_node_t *unnamed_node; 13035331Samw vnode_t *unnamed_vp = NULL; 13047348SJose.Borrego@Sun.COM caller_context_t ct; 13055772Sas200622 int svmand; 13065331Samw int rc; 13075331Samw 13085331Samw ASSERT(cr); 13095331Samw ASSERT(snode); 13105331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 13115331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 13125331Samw 13135331Samw ASSERT(sr); 13145331Samw ASSERT(sr->tid_tree); 13155331Samw ASSERT(sr->fid_ofile); 13165331Samw 13177348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 13185331Samw return (EROFS); 13195772Sas200622 13208845Samw@Sun.COM if (SMB_OFILE_IS_READONLY(sr->fid_ofile) || 13218845Samw@Sun.COM SMB_TREE_HAS_ACCESS(sr, ACE_WRITE_DATA | ACE_APPEND_DATA) == 0) 13227348SJose.Borrego@Sun.COM return (EACCES); 13237348SJose.Borrego@Sun.COM 13245331Samw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_WRITE_DATA); 13255772Sas200622 if (rc != NT_STATUS_SUCCESS) { 13265772Sas200622 rc = smb_ofile_access(sr->fid_ofile, cr, FILE_APPEND_DATA); 13275772Sas200622 if (rc != NT_STATUS_SUCCESS) 13285772Sas200622 return (EACCES); 13295772Sas200622 } 13305331Samw 13315331Samw unnamed_node = SMB_IS_STREAM(snode); 13325331Samw 13335331Samw if (unnamed_node) { 13345331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 13355331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 13365331Samw unnamed_vp = unnamed_node->vp; 13375331Samw /* 13385331Samw * Streams permission are checked against the unnamed stream, 13395331Samw * but in FS level they have their own permissions. To avoid 13405331Samw * rejection by FS due to lack of permission on the actual 13415331Samw * extended attr kcred is passed for streams. 13425331Samw */ 13435331Samw cr = kcred; 13445331Samw } 13455331Samw 13465772Sas200622 smb_node_start_crit(snode, RW_READER); 13477348SJose.Borrego@Sun.COM rc = nbl_svmand(snode->vp, kcred, &svmand); 13485772Sas200622 if (rc) { 13495772Sas200622 smb_node_end_crit(snode); 13505772Sas200622 return (rc); 13515772Sas200622 } 13527348SJose.Borrego@Sun.COM 13537348SJose.Borrego@Sun.COM ct = smb_ct; 13547348SJose.Borrego@Sun.COM ct.cc_pid = sr->fid_ofile->f_uniqid; 13555772Sas200622 rc = nbl_lock_conflict(snode->vp, NBL_WRITE, uio->uio_loffset, 13567348SJose.Borrego@Sun.COM uio->uio_iov->iov_len, svmand, &ct); 13575772Sas200622 13585772Sas200622 if (rc) { 13595772Sas200622 smb_node_end_crit(snode); 13606432Sas200622 return (ERANGE); 13615772Sas200622 } 13627052Samw rc = smb_vop_write(snode->vp, uio, ioflag, lcount, cr); 13635772Sas200622 13645772Sas200622 if (rc == 0 && ret_attr) { 13655331Samw /* 13665772Sas200622 * Use kcred to update the node attr because this 13675772Sas200622 * call is not being made on behalf of the user. 13685331Samw */ 13695331Samw ret_attr->sa_mask = SMB_AT_ALL; 13705772Sas200622 if (smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0, 13715772Sas200622 kcred) == 0) { 13725772Sas200622 snode->attr = *ret_attr; 13735772Sas200622 } 13745331Samw } 13755331Samw 13765772Sas200622 smb_node_end_crit(snode); 13775772Sas200622 13785331Samw return (rc); 13795331Samw } 13805331Samw 13815331Samw /* 13825331Samw * smb_fsop_statfs 13835331Samw * 13845331Samw * This is a wrapper function used for stat operations. 13855331Samw */ 13865331Samw int 13875331Samw smb_fsop_statfs( 13885331Samw cred_t *cr, 13895331Samw smb_node_t *snode, 13905331Samw struct statvfs64 *statp) 13915331Samw { 13925331Samw ASSERT(cr); 13935331Samw ASSERT(snode); 13945331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 13955331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 13965331Samw 13975331Samw return (smb_vop_statfs(snode->vp, statp, cr)); 13985331Samw } 13995331Samw 14005331Samw /* 14015331Samw * smb_fsop_access 14026700Sjm199354 * 14036700Sjm199354 * Named streams do not have separate permissions from the associated 14046700Sjm199354 * unnamed stream. Thus, if node is a named stream, the permissions 14056700Sjm199354 * check will be performed on the associated unnamed stream. 14066700Sjm199354 * 14076700Sjm199354 * However, our named streams do have their own quarantine attribute, 14086700Sjm199354 * separate from that on the unnamed stream. If READ or EXECUTE 14096700Sjm199354 * access has been requested on a named stream, an additional access 14106700Sjm199354 * check is performed on the named stream in case it has been 14116700Sjm199354 * quarantined. kcred is used to avoid issues with the permissions 14126700Sjm199354 * set on the extended attribute file representing the named stream. 14135331Samw */ 14145331Samw int 14155331Samw smb_fsop_access(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 14165331Samw uint32_t faccess) 14175331Samw { 14185331Samw int access = 0; 14195331Samw int error; 14205331Samw vnode_t *dir_vp; 14215331Samw boolean_t acl_check = B_TRUE; 14225331Samw smb_node_t *unnamed_node; 14235331Samw 14247348SJose.Borrego@Sun.COM ASSERT(sr); 14255331Samw ASSERT(cr); 14265331Samw ASSERT(snode); 14275331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 14285331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 14295331Samw 14305331Samw if (faccess == 0) 14315331Samw return (NT_STATUS_SUCCESS); 14325331Samw 14337348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) { 14345331Samw if (faccess & (FILE_WRITE_DATA|FILE_APPEND_DATA| 14355331Samw FILE_WRITE_EA|FILE_DELETE_CHILD|FILE_WRITE_ATTRIBUTES| 14365331Samw DELETE|WRITE_DAC|WRITE_OWNER)) { 14375331Samw return (NT_STATUS_ACCESS_DENIED); 14385331Samw } 14395331Samw } 14405331Samw 14415331Samw unnamed_node = SMB_IS_STREAM(snode); 14425331Samw if (unnamed_node) { 14435331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 14445331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 14456700Sjm199354 14466700Sjm199354 /* 14476700Sjm199354 * Perform VREAD access check on the named stream in case it 14486700Sjm199354 * is quarantined. kcred is passed to smb_vop_access so it 14496700Sjm199354 * doesn't fail due to lack of permission. 14506700Sjm199354 */ 14516700Sjm199354 if (faccess & (FILE_READ_DATA | FILE_EXECUTE)) { 14526700Sjm199354 error = smb_vop_access(snode->vp, VREAD, 14536700Sjm199354 0, NULL, kcred); 14546700Sjm199354 if (error) 14556700Sjm199354 return (NT_STATUS_ACCESS_DENIED); 14566700Sjm199354 } 14576700Sjm199354 14585331Samw /* 14595331Samw * Streams authorization should be performed against the 14605331Samw * unnamed stream. 14615331Samw */ 14625331Samw snode = unnamed_node; 14635331Samw } 14645331Samw 14655331Samw if (faccess & ACCESS_SYSTEM_SECURITY) { 14665331Samw /* 14675331Samw * This permission is required for reading/writing SACL and 14685331Samw * it's not part of DACL. It's only granted via proper 14695331Samw * privileges. 14705331Samw */ 14715331Samw if ((sr->uid_user->u_privileges & 14725331Samw (SMB_USER_PRIV_BACKUP | 14735331Samw SMB_USER_PRIV_RESTORE | 14745331Samw SMB_USER_PRIV_SECURITY)) == 0) 14755331Samw return (NT_STATUS_PRIVILEGE_NOT_HELD); 14765331Samw 14775331Samw faccess &= ~ACCESS_SYSTEM_SECURITY; 14785331Samw } 14795331Samw 14805331Samw /* Links don't have ACL */ 14817348SJose.Borrego@Sun.COM if ((!smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) || 14825331Samw (snode->attr.sa_vattr.va_type == VLNK)) 14835331Samw acl_check = B_FALSE; 14845331Samw 14858845Samw@Sun.COM /* 14868845Samw@Sun.COM * Use the most restrictive parts of both faccess and the 14878845Samw@Sun.COM * share access. An AND of the two value masks gives us that 14888845Samw@Sun.COM * since we've already converted to a mask of what we "can" 14898845Samw@Sun.COM * do. 14908845Samw@Sun.COM */ 14918845Samw@Sun.COM faccess &= sr->tid_tree->t_access; 14928845Samw@Sun.COM 14935331Samw if (acl_check) { 14945331Samw dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL; 14955331Samw error = smb_vop_access(snode->vp, faccess, V_ACE_MASK, dir_vp, 14965331Samw cr); 14975331Samw } else { 14985331Samw /* 14995331Samw * FS doesn't understand 32-bit mask, need to map 15005331Samw */ 15015331Samw if (faccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) 15025331Samw access |= VWRITE; 15035331Samw 15045331Samw if (faccess & FILE_READ_DATA) 15055331Samw access |= VREAD; 15065331Samw 15075331Samw if (faccess & FILE_EXECUTE) 15085331Samw access |= VEXEC; 15095331Samw 15105331Samw error = smb_vop_access(snode->vp, access, 0, NULL, cr); 15115331Samw } 15125331Samw 15135331Samw return ((error) ? NT_STATUS_ACCESS_DENIED : NT_STATUS_SUCCESS); 15145331Samw } 15155331Samw 15165331Samw /* 15175331Samw * smb_fsop_lookup_name() 15185331Samw * 15197961SNatalie.Li@Sun.COM * If name indicates that the file is a stream file, perform 15207961SNatalie.Li@Sun.COM * stream specific lookup, otherwise call smb_fsop_lookup. 15215331Samw * 15227961SNatalie.Li@Sun.COM * Return an error if the looked-up file is in outside the tree. 15237961SNatalie.Li@Sun.COM * (Required when invoked from open path.) 15245331Samw */ 15255331Samw 15265331Samw int 15275331Samw smb_fsop_lookup_name( 15286139Sjb150015 smb_request_t *sr, 15295331Samw cred_t *cr, 15305331Samw int flags, 15315331Samw smb_node_t *root_node, 15325331Samw smb_node_t *dir_snode, 15335331Samw char *name, 15345331Samw smb_node_t **ret_snode, 15355331Samw smb_attr_t *ret_attr) 15365331Samw { 15376139Sjb150015 smb_node_t *fnode; 15386139Sjb150015 smb_attr_t file_attr; 15396139Sjb150015 vnode_t *xattrdirvp; 15406139Sjb150015 vnode_t *vp; 15416139Sjb150015 char *od_name; 15426139Sjb150015 char *fname; 15436139Sjb150015 char *sname; 15446139Sjb150015 int rc; 15455331Samw 15465331Samw ASSERT(cr); 15475331Samw ASSERT(dir_snode); 15485331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 15495331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 15505331Samw 15515331Samw /* 15525331Samw * The following check is required for streams processing, below 15535331Samw */ 15545331Samw 15557348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 15565331Samw flags |= SMB_IGNORE_CASE; 15575331Samw 15585331Samw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 15595331Samw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 15605331Samw 15618334SJose.Borrego@Sun.COM if ((rc = smb_stream_parse_name(name, fname, sname)) != 0) { 15628334SJose.Borrego@Sun.COM if (rc == -1) { 15638334SJose.Borrego@Sun.COM kmem_free(fname, MAXNAMELEN); 15648334SJose.Borrego@Sun.COM kmem_free(sname, MAXNAMELEN); 15658334SJose.Borrego@Sun.COM return (EINVAL); 15668334SJose.Borrego@Sun.COM } 15678334SJose.Borrego@Sun.COM 15685331Samw /* 15695331Samw * Look up the unnamed stream (i.e. fname). 15705331Samw * Unmangle processing will be done on fname 15715331Samw * as well as any link target. 15725331Samw */ 15735331Samw rc = smb_fsop_lookup(sr, cr, flags, root_node, dir_snode, fname, 15745331Samw &fnode, &file_attr, NULL, NULL); 15755331Samw 15765331Samw if (rc != 0) { 15775331Samw kmem_free(fname, MAXNAMELEN); 15785331Samw kmem_free(sname, MAXNAMELEN); 15795331Samw return (rc); 15805331Samw } 15815331Samw 15825331Samw od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 15835331Samw 15845331Samw /* 15855331Samw * od_name is the on-disk name of the stream, except 15865331Samw * without the prepended stream prefix (SMB_STREAM_PREFIX) 15875331Samw */ 15885331Samw 15895331Samw /* 15905331Samw * XXX 15915331Samw * What permissions NTFS requires for stream lookup if any? 15925331Samw */ 15935331Samw rc = smb_vop_stream_lookup(fnode->vp, sname, &vp, od_name, 15945772Sas200622 &xattrdirvp, flags, root_node->vp, cr); 15955331Samw 15965331Samw if (rc != 0) { 15975331Samw smb_node_release(fnode); 15985331Samw kmem_free(fname, MAXNAMELEN); 15995331Samw kmem_free(sname, MAXNAMELEN); 16005331Samw kmem_free(od_name, MAXNAMELEN); 16015331Samw return (rc); 16025331Samw } 16035331Samw 16045331Samw *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, 16055331Samw vp, od_name, ret_attr); 16065331Samw 16075331Samw kmem_free(od_name, MAXNAMELEN); 16085331Samw smb_node_release(fnode); 16098670SJose.Borrego@Sun.COM VN_RELE(xattrdirvp); 16108670SJose.Borrego@Sun.COM VN_RELE(vp); 16115331Samw 16125331Samw if (*ret_snode == NULL) { 16135331Samw kmem_free(fname, MAXNAMELEN); 16145331Samw kmem_free(sname, MAXNAMELEN); 16155331Samw return (ENOMEM); 16165331Samw } 16175331Samw } else { 16185331Samw rc = smb_fsop_lookup(sr, cr, flags, root_node, dir_snode, name, 16195331Samw ret_snode, ret_attr, NULL, NULL); 16205331Samw } 16215331Samw 16225331Samw if (rc == 0) { 16235331Samw ASSERT(ret_snode); 16247348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, *ret_snode) == 0) { 16255331Samw smb_node_release(*ret_snode); 16265331Samw *ret_snode = NULL; 16275331Samw rc = EACCES; 16285331Samw } 16295331Samw } 16305331Samw 16315331Samw kmem_free(fname, MAXNAMELEN); 16325331Samw kmem_free(sname, MAXNAMELEN); 16335331Samw 16345331Samw return (rc); 16355331Samw } 16365331Samw 16375331Samw /* 16385331Samw * smb_fsop_lookup 16395331Samw * 16405331Samw * All SMB functions should use this smb_vop_lookup wrapper to ensure that 16415331Samw * the smb_vop_lookup is performed with the appropriate credentials and using 16425331Samw * case insensitive compares. Please document any direct call to smb_vop_lookup 16435331Samw * to explain the reason for avoiding this wrapper. 16445331Samw * 16455331Samw * It is assumed that a reference exists on dir_snode coming into this routine 16465331Samw * (and that it is safe from deallocation). 16475331Samw * 16485331Samw * Same with the root_node. 16495331Samw * 16505331Samw * *ret_snode is returned with a reference upon success. No reference is 16515331Samw * taken if an error is returned. 16525331Samw * 16535331Samw * Note: The returned ret_snode may be in a child mount. This is ok for 16548670SJose.Borrego@Sun.COM * readdir. 16555331Samw * 16567348SJose.Borrego@Sun.COM * ret_shortname and ret_name83 must each point to buffers of at least 16577348SJose.Borrego@Sun.COM * SMB_SHORTNAMELEN bytes. 16587348SJose.Borrego@Sun.COM * 16597348SJose.Borrego@Sun.COM * Other smb_fsop_* routines will call SMB_TREE_CONTAINS_NODE() to prevent 16605331Samw * operations on files not in the parent mount. 16615331Samw */ 16625331Samw int 16635331Samw smb_fsop_lookup( 16646139Sjb150015 smb_request_t *sr, 16655331Samw cred_t *cr, 16665331Samw int flags, 16675331Samw smb_node_t *root_node, 16685331Samw smb_node_t *dir_snode, 16695331Samw char *name, 16705331Samw smb_node_t **ret_snode, 16715331Samw smb_attr_t *ret_attr, 16727348SJose.Borrego@Sun.COM char *ret_shortname, 16737348SJose.Borrego@Sun.COM char *ret_name83) 16745331Samw { 16755331Samw smb_node_t *lnk_target_node; 16765331Samw smb_node_t *lnk_dnode; 16775331Samw char *longname; 16785331Samw char *od_name; 16795331Samw vnode_t *vp; 16805331Samw int rc; 16815331Samw 16825331Samw ASSERT(cr); 16835331Samw ASSERT(dir_snode); 16845331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 16855331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 16865331Samw 16875331Samw if (name == NULL) 16885331Samw return (EINVAL); 16895331Samw 16907348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 16915331Samw return (EACCES); 16925331Samw 16937348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 16945331Samw flags |= SMB_IGNORE_CASE; 16955331Samw 16965331Samw od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 16975331Samw 16985331Samw rc = smb_vop_lookup(dir_snode->vp, name, &vp, od_name, flags, 16995772Sas200622 root_node ? root_node->vp : NULL, cr); 17005331Samw 17015331Samw if (rc != 0) { 17025331Samw if (smb_maybe_mangled_name(name) == 0) { 17035331Samw kmem_free(od_name, MAXNAMELEN); 17045331Samw return (rc); 17055331Samw } 17065331Samw 17075331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 17085331Samw 17095331Samw rc = smb_unmangle_name(sr, cr, dir_snode, name, longname, 17105331Samw MAXNAMELEN, ret_shortname, ret_name83, 1); 17115331Samw 17125331Samw if (rc != 0) { 17135331Samw kmem_free(od_name, MAXNAMELEN); 17145331Samw kmem_free(longname, MAXNAMELEN); 17155331Samw return (rc); 17165331Samw } 17175331Samw 17185331Samw /* 17195331Samw * We passed "1" as the "od" parameter 17205331Samw * to smb_unmangle_name(), such that longname 17215331Samw * is the real (case-sensitive) on-disk name. 17225331Samw * We make sure we do a lookup on this exact 17235331Samw * name, as the name was mangled and denotes 17245331Samw * a unique file. 17255331Samw */ 17265331Samw 17275331Samw if (flags & SMB_IGNORE_CASE) 17285331Samw flags &= ~SMB_IGNORE_CASE; 17295331Samw 17305331Samw rc = smb_vop_lookup(dir_snode->vp, longname, &vp, od_name, 17315772Sas200622 flags, root_node ? root_node->vp : NULL, cr); 17325331Samw 17335331Samw kmem_free(longname, MAXNAMELEN); 17345331Samw 17355331Samw if (rc != 0) { 17365331Samw kmem_free(od_name, MAXNAMELEN); 17375331Samw return (rc); 17385331Samw } 17395331Samw } 17405331Samw 17415331Samw if ((flags & SMB_FOLLOW_LINKS) && (vp->v_type == VLNK)) { 17425331Samw 17435331Samw rc = smb_pathname(sr, od_name, FOLLOW, root_node, dir_snode, 17445331Samw &lnk_dnode, &lnk_target_node, cr); 17455331Samw 17465331Samw if (rc != 0) { 17475331Samw /* 17485331Samw * The link is assumed to be for the last component 17495331Samw * of a path. Hence any ENOTDIR error will be returned 17505331Samw * as ENOENT. 17515331Samw */ 17525331Samw if (rc == ENOTDIR) 17535331Samw rc = ENOENT; 17545331Samw 17555331Samw VN_RELE(vp); 17565331Samw kmem_free(od_name, MAXNAMELEN); 17575331Samw return (rc); 17585331Samw } 17595331Samw 17605331Samw /* 17615331Samw * Release the original VLNK vnode 17625331Samw */ 17635331Samw 17645331Samw VN_RELE(vp); 17655331Samw vp = lnk_target_node->vp; 17665331Samw 17675331Samw rc = smb_vop_traverse_check(&vp); 17685331Samw 17695331Samw if (rc != 0) { 17705331Samw smb_node_release(lnk_dnode); 17715331Samw smb_node_release(lnk_target_node); 17725331Samw kmem_free(od_name, MAXNAMELEN); 17735331Samw return (rc); 17745331Samw } 17755331Samw 17765331Samw /* 17775331Samw * smb_vop_traverse_check() may have returned a different vnode 17785331Samw */ 17795331Samw 17805331Samw if (lnk_target_node->vp == vp) { 17815331Samw *ret_snode = lnk_target_node; 17825331Samw *ret_attr = (*ret_snode)->attr; 17835331Samw } else { 17845331Samw *ret_snode = smb_node_lookup(sr, NULL, cr, vp, 17855331Samw lnk_target_node->od_name, lnk_dnode, NULL, 17865331Samw ret_attr); 17878670SJose.Borrego@Sun.COM VN_RELE(vp); 17885331Samw 17898670SJose.Borrego@Sun.COM if (*ret_snode == NULL) 17905331Samw rc = ENOMEM; 17915331Samw smb_node_release(lnk_target_node); 17925331Samw } 17935331Samw 17945331Samw smb_node_release(lnk_dnode); 17955331Samw 17965331Samw } else { 17975331Samw 17985331Samw rc = smb_vop_traverse_check(&vp); 17995331Samw if (rc) { 18005331Samw VN_RELE(vp); 18015331Samw kmem_free(od_name, MAXNAMELEN); 18025331Samw return (rc); 18035331Samw } 18045331Samw 18055331Samw *ret_snode = smb_node_lookup(sr, NULL, cr, vp, od_name, 18065331Samw dir_snode, NULL, ret_attr); 18078670SJose.Borrego@Sun.COM VN_RELE(vp); 18085331Samw 18098670SJose.Borrego@Sun.COM if (*ret_snode == NULL) 18105331Samw rc = ENOMEM; 18115331Samw } 18125331Samw 18135331Samw kmem_free(od_name, MAXNAMELEN); 18145331Samw return (rc); 18155331Samw } 18165331Samw 18175331Samw int /*ARGSUSED*/ 18185331Samw smb_fsop_commit(smb_request_t *sr, cred_t *cr, smb_node_t *snode) 18195331Samw { 18205331Samw ASSERT(cr); 18215331Samw ASSERT(snode); 18225331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 18235331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 18245331Samw 18255331Samw ASSERT(sr); 18265331Samw ASSERT(sr->tid_tree); 18277348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 18285331Samw return (EROFS); 18295331Samw 18305772Sas200622 return (smb_vop_commit(snode->vp, cr)); 18315331Samw } 18325331Samw 18335331Samw /* 18345331Samw * smb_fsop_aclread 18355331Samw * 18365331Samw * Retrieve filesystem ACL. Depends on requested ACLs in 18375331Samw * fs_sd->sd_secinfo, it'll set DACL and SACL pointers in 18385331Samw * fs_sd. Note that requesting a DACL/SACL doesn't mean that 18395331Samw * the corresponding field in fs_sd should be non-NULL upon 18405331Samw * return, since the target ACL might not contain that type of 18415331Samw * entries. 18425331Samw * 18435331Samw * Returned ACL is always in ACE_T (aka ZFS) format. 18445331Samw * If successful the allocated memory for the ACL should be freed 18455521Sas200622 * using smb_fsacl_free() or smb_fssd_term() 18465331Samw */ 18475331Samw int 18485331Samw smb_fsop_aclread(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 18495331Samw smb_fssd_t *fs_sd) 18505331Samw { 18515331Samw int error = 0; 18525331Samw int flags = 0; 18535331Samw int access = 0; 18545331Samw acl_t *acl; 18555331Samw smb_node_t *unnamed_node; 18565331Samw 18575331Samw ASSERT(cr); 18585331Samw 18598845Samw@Sun.COM if (SMB_TREE_HAS_ACCESS(sr, ACE_READ_ACL) == 0) 18608845Samw@Sun.COM return (EACCES); 18618845Samw@Sun.COM 18625331Samw if (sr->fid_ofile) { 18635331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 18645331Samw access = READ_CONTROL; 18655331Samw 18665331Samw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 18675331Samw access |= ACCESS_SYSTEM_SECURITY; 18685331Samw 18695331Samw error = smb_ofile_access(sr->fid_ofile, cr, access); 18705331Samw if (error != NT_STATUS_SUCCESS) { 18715331Samw return (EACCES); 18725331Samw } 18735331Samw } 18745331Samw 18755331Samw unnamed_node = SMB_IS_STREAM(snode); 18765331Samw if (unnamed_node) { 18775331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 18785331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 18795331Samw /* 18805331Samw * Streams don't have ACL, any read ACL attempt on a stream 18815331Samw * should be performed on the unnamed stream. 18825331Samw */ 18835331Samw snode = unnamed_node; 18845331Samw } 18855331Samw 18867348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) 18875331Samw flags = ATTR_NOACLCHECK; 18885331Samw 18895331Samw error = smb_vop_acl_read(snode->vp, &acl, flags, 18905772Sas200622 sr->tid_tree->t_acltype, cr); 18915331Samw if (error != 0) { 18925331Samw return (error); 18935331Samw } 18945331Samw 18955331Samw error = acl_translate(acl, _ACL_ACE_ENABLED, 18965331Samw (snode->vp->v_type == VDIR), fs_sd->sd_uid, fs_sd->sd_gid); 18975331Samw 18985331Samw if (error == 0) { 18995521Sas200622 smb_fsacl_split(acl, &fs_sd->sd_zdacl, &fs_sd->sd_zsacl, 19005331Samw fs_sd->sd_secinfo); 19015331Samw } 19025331Samw 19035331Samw acl_free(acl); 19045331Samw return (error); 19055331Samw } 19065331Samw 19075331Samw /* 19085331Samw * smb_fsop_aclwrite 19095331Samw * 19105331Samw * Stores the filesystem ACL provided in fs_sd->sd_acl. 19115331Samw */ 19125331Samw int 19135331Samw smb_fsop_aclwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 19145331Samw smb_fssd_t *fs_sd) 19155331Samw { 19165331Samw int target_flavor; 19175331Samw int error = 0; 19185331Samw int flags = 0; 19195331Samw int access = 0; 19205331Samw acl_t *acl, *dacl, *sacl; 19215331Samw smb_node_t *unnamed_node; 19225331Samw 19235331Samw ASSERT(cr); 19245331Samw 19255331Samw ASSERT(sr); 19265331Samw ASSERT(sr->tid_tree); 19277348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 19285331Samw return (EROFS); 19295331Samw 19308845Samw@Sun.COM if (SMB_TREE_HAS_ACCESS(sr, ACE_WRITE_ACL) == 0) 19318845Samw@Sun.COM return (EACCES); 19328845Samw@Sun.COM 19335331Samw if (sr->fid_ofile) { 19345331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 19355331Samw access = WRITE_DAC; 19365331Samw 19375331Samw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 19385331Samw access |= ACCESS_SYSTEM_SECURITY; 19395331Samw 19405331Samw error = smb_ofile_access(sr->fid_ofile, cr, access); 19415331Samw if (error != NT_STATUS_SUCCESS) 19425331Samw return (EACCES); 19435331Samw } 19445331Samw 19455331Samw switch (sr->tid_tree->t_acltype) { 19465331Samw case ACLENT_T: 19475331Samw target_flavor = _ACL_ACLENT_ENABLED; 19485331Samw break; 19495331Samw 19505331Samw case ACE_T: 19515331Samw target_flavor = _ACL_ACE_ENABLED; 19525331Samw break; 19535331Samw default: 19545331Samw return (EINVAL); 19555331Samw } 19565331Samw 19575331Samw unnamed_node = SMB_IS_STREAM(snode); 19585331Samw if (unnamed_node) { 19595331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 19605331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 19615331Samw /* 19625331Samw * Streams don't have ACL, any write ACL attempt on a stream 19635331Samw * should be performed on the unnamed stream. 19645331Samw */ 19655331Samw snode = unnamed_node; 19665331Samw } 19675331Samw 19685331Samw dacl = fs_sd->sd_zdacl; 19695331Samw sacl = fs_sd->sd_zsacl; 19705331Samw 19715331Samw ASSERT(dacl || sacl); 19725331Samw if ((dacl == NULL) && (sacl == NULL)) 19735331Samw return (EINVAL); 19745331Samw 19755331Samw if (dacl && sacl) 19765521Sas200622 acl = smb_fsacl_merge(dacl, sacl); 19775331Samw else if (dacl) 19785331Samw acl = dacl; 19795331Samw else 19805331Samw acl = sacl; 19815331Samw 19825331Samw error = acl_translate(acl, target_flavor, (snode->vp->v_type == VDIR), 19835331Samw fs_sd->sd_uid, fs_sd->sd_gid); 19845331Samw if (error == 0) { 19857348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, 19867348SJose.Borrego@Sun.COM SMB_TREE_ACEMASKONACCESS)) 19875331Samw flags = ATTR_NOACLCHECK; 19885331Samw 19895772Sas200622 error = smb_vop_acl_write(snode->vp, acl, flags, cr); 19905331Samw } 19915331Samw 19925331Samw if (dacl && sacl) 19935331Samw acl_free(acl); 19945331Samw 19955331Samw return (error); 19965331Samw } 19975331Samw 19985331Samw acl_type_t 19995331Samw smb_fsop_acltype(smb_node_t *snode) 20005331Samw { 20015331Samw return (smb_vop_acl_type(snode->vp)); 20025331Samw } 20035331Samw 20045331Samw /* 20055331Samw * smb_fsop_sdread 20065331Samw * 20075331Samw * Read the requested security descriptor items from filesystem. 20085331Samw * The items are specified in fs_sd->sd_secinfo. 20095331Samw */ 20105331Samw int 20115331Samw smb_fsop_sdread(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 20125331Samw smb_fssd_t *fs_sd) 20135331Samw { 20145331Samw int error = 0; 20155331Samw int getowner = 0; 20165331Samw cred_t *ga_cred; 20175331Samw smb_attr_t attr; 20185331Samw 20195331Samw ASSERT(cr); 20205331Samw ASSERT(fs_sd); 20215331Samw 20225331Samw /* 20235331Samw * File's uid/gid is fetched in two cases: 20245331Samw * 20255331Samw * 1. it's explicitly requested 20265331Samw * 20275331Samw * 2. target ACL is ACE_T (ZFS ACL). They're needed for 20285331Samw * owner@/group@ entries. In this case kcred should be used 20295331Samw * because uid/gid are fetched on behalf of smb server. 20305331Samw */ 20315331Samw if (fs_sd->sd_secinfo & (SMB_OWNER_SECINFO | SMB_GROUP_SECINFO)) { 20325331Samw getowner = 1; 20335331Samw ga_cred = cr; 20345331Samw } else if (sr->tid_tree->t_acltype == ACE_T) { 20355331Samw getowner = 1; 20365331Samw ga_cred = kcred; 20375331Samw } 20385331Samw 20395331Samw if (getowner) { 20405331Samw /* 20415331Samw * Windows require READ_CONTROL to read owner/group SID since 20425331Samw * they're part of Security Descriptor. 20435331Samw * ZFS only requires read_attribute. Need to have a explicit 20445331Samw * access check here. 20455331Samw */ 20465331Samw if (sr->fid_ofile == NULL) { 20475331Samw error = smb_fsop_access(sr, ga_cred, snode, 20485331Samw READ_CONTROL); 20495331Samw if (error) 20505331Samw return (error); 20515331Samw } 20525331Samw 20535331Samw attr.sa_mask = SMB_AT_UID | SMB_AT_GID; 20545331Samw error = smb_fsop_getattr(sr, ga_cred, snode, &attr); 20555331Samw if (error == 0) { 20565331Samw fs_sd->sd_uid = attr.sa_vattr.va_uid; 20575331Samw fs_sd->sd_gid = attr.sa_vattr.va_gid; 20585331Samw } else { 20595331Samw return (error); 20605331Samw } 20615331Samw } 20625331Samw 20635331Samw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 20645331Samw error = smb_fsop_aclread(sr, cr, snode, fs_sd); 20655331Samw } 20665331Samw 20675331Samw return (error); 20685331Samw } 20695331Samw 20705331Samw /* 20715331Samw * smb_fsop_sdmerge 20725331Samw * 20735331Samw * From SMB point of view DACL and SACL are two separate list 20745331Samw * which can be manipulated independently without one affecting 20755331Samw * the other, but entries for both DACL and SACL will end up 20765331Samw * in the same ACL if target filesystem supports ACE_T ACLs. 20775331Samw * 20785331Samw * So, if either DACL or SACL is present in the client set request 20795331Samw * the entries corresponding to the non-present ACL shouldn't 20805331Samw * be touched in the FS ACL. 20815331Samw * 20825331Samw * fs_sd parameter contains DACL and SACL specified by SMB 20835331Samw * client to be set on a file/directory. The client could 20845331Samw * specify both or one of these ACLs (if none is specified 20855331Samw * we don't get this far). When both DACL and SACL are given 20865331Samw * by client the existing ACL should be overwritten. If only 20875331Samw * one of them is specified the entries corresponding to the other 20885331Samw * ACL should not be touched. For example, if only DACL 20895331Samw * is specified in input fs_sd, the function reads audit entries 20905331Samw * of the existing ACL of the file and point fs_sd->sd_zsdacl 20915331Samw * pointer to the fetched SACL, this way when smb_fsop_sdwrite() 20925331Samw * function is called the passed fs_sd would point to the specified 20935331Samw * DACL by client and fetched SACL from filesystem, so the file 20945331Samw * will end up with correct ACL. 20955331Samw */ 20965331Samw static int 20975331Samw smb_fsop_sdmerge(smb_request_t *sr, smb_node_t *snode, smb_fssd_t *fs_sd) 20985331Samw { 20995331Samw smb_fssd_t cur_sd; 21005331Samw int error = 0; 21015331Samw 21025331Samw if (sr->tid_tree->t_acltype != ACE_T) 21035331Samw /* Don't bother if target FS doesn't support ACE_T */ 21045331Samw return (0); 21055331Samw 21065331Samw if ((fs_sd->sd_secinfo & SMB_ACL_SECINFO) != SMB_ACL_SECINFO) { 21075331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) { 21085331Samw /* 21095331Samw * Don't overwrite existing audit entries 21105331Samw */ 21115521Sas200622 smb_fssd_init(&cur_sd, SMB_SACL_SECINFO, 21125331Samw fs_sd->sd_flags); 21135331Samw 21145331Samw error = smb_fsop_sdread(sr, kcred, snode, &cur_sd); 21155331Samw if (error == 0) { 21165331Samw ASSERT(fs_sd->sd_zsacl == NULL); 21175331Samw fs_sd->sd_zsacl = cur_sd.sd_zsacl; 21185331Samw if (fs_sd->sd_zsacl && fs_sd->sd_zdacl) 21195331Samw fs_sd->sd_zsacl->acl_flags = 21205331Samw fs_sd->sd_zdacl->acl_flags; 21215331Samw } 21225331Samw } else { 21235331Samw /* 21245331Samw * Don't overwrite existing access entries 21255331Samw */ 21265521Sas200622 smb_fssd_init(&cur_sd, SMB_DACL_SECINFO, 21275331Samw fs_sd->sd_flags); 21285331Samw 21295331Samw error = smb_fsop_sdread(sr, kcred, snode, &cur_sd); 21305331Samw if (error == 0) { 21315331Samw ASSERT(fs_sd->sd_zdacl == NULL); 21325331Samw fs_sd->sd_zdacl = cur_sd.sd_zdacl; 21335331Samw if (fs_sd->sd_zdacl && fs_sd->sd_zsacl) 21345331Samw fs_sd->sd_zdacl->acl_flags = 21355331Samw fs_sd->sd_zsacl->acl_flags; 21365331Samw } 21375331Samw } 21385331Samw 21395331Samw if (error) 21405521Sas200622 smb_fssd_term(&cur_sd); 21415331Samw } 21425331Samw 21435331Samw return (error); 21445331Samw } 21455331Samw 21465331Samw /* 21475331Samw * smb_fsop_sdwrite 21485331Samw * 21495331Samw * Stores the given uid, gid and acl in filesystem. 21505331Samw * Provided items in fs_sd are specified by fs_sd->sd_secinfo. 21515331Samw * 21525331Samw * A SMB security descriptor could contain owner, primary group, 21535331Samw * DACL and SACL. Setting an SD should be atomic but here it has to 21545331Samw * be done via two separate FS operations: VOP_SETATTR and 21555331Samw * VOP_SETSECATTR. Therefore, this function has to simulate the 21565331Samw * atomicity as well as it can. 21577619SJose.Borrego@Sun.COM * 21587619SJose.Borrego@Sun.COM * Get the current uid, gid before setting the new uid/gid 21597619SJose.Borrego@Sun.COM * so if smb_fsop_aclwrite fails they can be restored. root cred is 21607619SJose.Borrego@Sun.COM * used to get currend uid/gid since this operation is performed on 21617619SJose.Borrego@Sun.COM * behalf of the server not the user. 21627619SJose.Borrego@Sun.COM * 21637619SJose.Borrego@Sun.COM * If setting uid/gid fails with EPERM it means that and invalid 21647619SJose.Borrego@Sun.COM * owner has been specified. Callers should translate this to 21657619SJose.Borrego@Sun.COM * STATUS_INVALID_OWNER which is not the normal mapping for EPERM 21667619SJose.Borrego@Sun.COM * in upper layers, so EPERM is mapped to EBADE. 21675331Samw */ 21685331Samw int 21695331Samw smb_fsop_sdwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 21705331Samw smb_fssd_t *fs_sd, int overwrite) 21715331Samw { 21725331Samw int error = 0; 21735331Samw int access = 0; 21745331Samw smb_attr_t set_attr; 21755331Samw smb_attr_t orig_attr; 21765331Samw 21775331Samw ASSERT(cr); 21785331Samw ASSERT(fs_sd); 21795331Samw 21805331Samw ASSERT(sr); 21815331Samw ASSERT(sr->tid_tree); 21827348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 21835331Samw return (EROFS); 21845331Samw 21855331Samw bzero(&set_attr, sizeof (smb_attr_t)); 21865331Samw 21875331Samw if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 21885331Samw set_attr.sa_vattr.va_uid = fs_sd->sd_uid; 21895331Samw set_attr.sa_mask |= SMB_AT_UID; 21907619SJose.Borrego@Sun.COM access |= WRITE_OWNER; 21915331Samw } 21925331Samw 21935331Samw if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 21945331Samw set_attr.sa_vattr.va_gid = fs_sd->sd_gid; 21955331Samw set_attr.sa_mask |= SMB_AT_GID; 21967619SJose.Borrego@Sun.COM access |= WRITE_OWNER; 21975331Samw } 21985331Samw 21995331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 22005331Samw access |= WRITE_DAC; 22015331Samw 22025331Samw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 22035331Samw access |= ACCESS_SYSTEM_SECURITY; 22045331Samw 22055331Samw if (sr->fid_ofile) 22065331Samw error = smb_ofile_access(sr->fid_ofile, cr, access); 22075331Samw else 22085331Samw error = smb_fsop_access(sr, cr, snode, access); 22095331Samw 22105331Samw if (error) 22115331Samw return (EACCES); 22125331Samw 22135331Samw if (set_attr.sa_mask) { 22145331Samw orig_attr.sa_mask = SMB_AT_UID | SMB_AT_GID; 22155331Samw error = smb_fsop_getattr(sr, kcred, snode, &orig_attr); 22167619SJose.Borrego@Sun.COM if (error == 0) { 22175331Samw error = smb_fsop_setattr(sr, cr, snode, &set_attr, 22185331Samw NULL); 22197619SJose.Borrego@Sun.COM if (error == EPERM) 22207619SJose.Borrego@Sun.COM error = EBADE; 22217619SJose.Borrego@Sun.COM } 22225331Samw 22235331Samw if (error) 22245331Samw return (error); 22255331Samw } 22265331Samw 22275331Samw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 22285331Samw if (overwrite == 0) { 22295331Samw error = smb_fsop_sdmerge(sr, snode, fs_sd); 22305331Samw if (error) 22315331Samw return (error); 22325331Samw } 22335331Samw 22345331Samw error = smb_fsop_aclwrite(sr, cr, snode, fs_sd); 22355331Samw if (error) { 22365331Samw /* 22375331Samw * Revert uid/gid changes if required. 22385331Samw */ 22395331Samw if (set_attr.sa_mask) { 22405331Samw orig_attr.sa_mask = set_attr.sa_mask; 22415331Samw (void) smb_fsop_setattr(sr, kcred, snode, 22425331Samw &orig_attr, NULL); 22435331Samw } 22445331Samw } 22455331Samw } 22465331Samw 22475331Samw return (error); 22485331Samw } 22495331Samw 22505331Samw /* 22515331Samw * smb_fsop_sdinherit 22525331Samw * 22535331Samw * Inherit the security descriptor from the parent container. 22545331Samw * This function is called after FS has created the file/folder 22555331Samw * so if this doesn't do anything it means FS inheritance is 22565331Samw * in place. 22575331Samw * 22585331Samw * Do inheritance for ZFS internally. 22595331Samw * 22605331Samw * If we want to let ZFS does the inheritance the 22615331Samw * following setting should be true: 22625331Samw * 22635331Samw * - aclinherit = passthrough 22645331Samw * - aclmode = passthrough 22655331Samw * - smbd umask = 0777 22665331Samw * 22675331Samw * This will result in right effective permissions but 22685331Samw * ZFS will always add 6 ACEs for owner, owning group 22695331Samw * and others to be POSIX compliant. This is not what 22705331Samw * Windows clients/users expect, so we decided that CIFS 22715331Samw * implements Windows rules and overwrite whatever ZFS 22725331Samw * comes up with. This way we also don't have to care 22735331Samw * about ZFS aclinherit and aclmode settings. 22745331Samw */ 22755331Samw static int 22765331Samw smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, smb_fssd_t *fs_sd) 22775331Samw { 22785331Samw int is_dir; 22795521Sas200622 acl_t *dacl = NULL; 22805521Sas200622 acl_t *sacl = NULL; 22815331Samw ksid_t *owner_sid; 22825331Samw int error; 22835331Samw 22845331Samw ASSERT(fs_sd); 22855331Samw 22865331Samw if (sr->tid_tree->t_acltype != ACE_T) { 22875331Samw /* 22885331Samw * No forced inheritance for non-ZFS filesystems. 22895331Samw */ 22905331Samw fs_sd->sd_secinfo = 0; 22915331Samw return (0); 22925331Samw } 22935331Samw 22945331Samw 22955331Samw /* Fetch parent directory's ACL */ 22965331Samw error = smb_fsop_sdread(sr, kcred, dnode, fs_sd); 22975331Samw if (error) { 22985331Samw return (error); 22995331Samw } 23005331Samw 23015331Samw is_dir = (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR); 23025331Samw owner_sid = crgetsid(sr->user_cr, KSID_OWNER); 23035331Samw ASSERT(owner_sid); 23045521Sas200622 dacl = smb_fsacl_inherit(fs_sd->sd_zdacl, is_dir, SMB_DACL_SECINFO, 23055331Samw owner_sid->ks_id); 23065521Sas200622 sacl = smb_fsacl_inherit(fs_sd->sd_zsacl, is_dir, SMB_SACL_SECINFO, 23075331Samw (uid_t)-1); 23085331Samw 23095521Sas200622 if (sacl == NULL) 23105521Sas200622 fs_sd->sd_secinfo &= ~SMB_SACL_SECINFO; 23115521Sas200622 23125521Sas200622 smb_fsacl_free(fs_sd->sd_zdacl); 23135521Sas200622 smb_fsacl_free(fs_sd->sd_zsacl); 23145331Samw 23155331Samw fs_sd->sd_zdacl = dacl; 23165331Samw fs_sd->sd_zsacl = sacl; 23175331Samw 23185331Samw return (0); 23195331Samw } 23205331Samw 23215331Samw /* 23225331Samw * smb_fsop_eaccess 23235331Samw * 23245331Samw * Returns the effective permission of the given credential for the 23255331Samw * specified object. 23265331Samw * 23275331Samw * This is just a workaround. We need VFS/FS support for this. 23285331Samw */ 23295331Samw void 23305331Samw smb_fsop_eaccess(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 23315331Samw uint32_t *eaccess) 23325331Samw { 23335331Samw int access = 0; 23345331Samw vnode_t *dir_vp; 23355331Samw smb_node_t *unnamed_node; 23365331Samw 23375331Samw ASSERT(cr); 23385331Samw ASSERT(snode); 23395331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 23405331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 23415331Samw 23425331Samw unnamed_node = SMB_IS_STREAM(snode); 23435331Samw if (unnamed_node) { 23445331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 23455331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 23465331Samw /* 23475331Samw * Streams authorization should be performed against the 23485331Samw * unnamed stream. 23495331Samw */ 23505331Samw snode = unnamed_node; 23515331Samw } 23525331Samw 23537348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) { 23545331Samw dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL; 23555331Samw smb_vop_eaccess(snode->vp, (int *)eaccess, V_ACE_MASK, dir_vp, 23565331Samw cr); 23575331Samw return; 23585331Samw } 23595331Samw 23605331Samw /* 23615331Samw * FS doesn't understand 32-bit mask 23625331Samw */ 23635331Samw smb_vop_eaccess(snode->vp, &access, 0, NULL, cr); 23648845Samw@Sun.COM access &= sr->tid_tree->t_access; 23655331Samw 23665331Samw *eaccess = READ_CONTROL | FILE_READ_EA | FILE_READ_ATTRIBUTES; 23675331Samw 23685331Samw if (access & VREAD) 23695331Samw *eaccess |= FILE_READ_DATA; 23705331Samw 23715331Samw if (access & VEXEC) 23725331Samw *eaccess |= FILE_EXECUTE; 23735331Samw 23745331Samw if (access & VWRITE) 23755331Samw *eaccess |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | 23765331Samw FILE_WRITE_EA | FILE_APPEND_DATA | FILE_DELETE_CHILD; 23775331Samw } 23785521Sas200622 23795772Sas200622 /* 23805772Sas200622 * smb_fsop_shrlock 23815772Sas200622 * 23825772Sas200622 * For the current open request, check file sharing rules 23835772Sas200622 * against existing opens. 23845772Sas200622 * 23855772Sas200622 * Returns NT_STATUS_SHARING_VIOLATION if there is any 23865772Sas200622 * sharing conflict. Returns NT_STATUS_SUCCESS otherwise. 23875772Sas200622 * 23885772Sas200622 * Full system-wide share reservation synchronization is available 23895772Sas200622 * when the nbmand (non-blocking mandatory) mount option is set 23905772Sas200622 * (i.e. nbl_need_crit() is true) and nbmand critical regions are used. 23915772Sas200622 * This provides synchronization with NFS and local processes. The 23925772Sas200622 * critical regions are entered in VOP_SHRLOCK()/fs_shrlock() (called 23935772Sas200622 * from smb_open_subr()/smb_fsop_shrlock()/smb_vop_shrlock()) as well 23945772Sas200622 * as the CIFS rename and delete paths. 23955772Sas200622 * 23965772Sas200622 * The CIFS server will also enter the nbl critical region in the open, 23975772Sas200622 * rename, and delete paths when nbmand is not set. There is limited 23985772Sas200622 * coordination with local and VFS share reservations in this case. 23995772Sas200622 * Note that when the nbmand mount option is not set, the VFS layer 24005772Sas200622 * only processes advisory reservations and the delete mode is not checked. 24015772Sas200622 * 24025772Sas200622 * Whether or not the nbmand mount option is set, intra-CIFS share 24035772Sas200622 * checking is done in the open, delete, and rename paths using a CIFS 24045772Sas200622 * critical region (node->n_share_lock). 24055772Sas200622 */ 24065772Sas200622 24075772Sas200622 uint32_t 24086139Sjb150015 smb_fsop_shrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid, 24095772Sas200622 uint32_t desired_access, uint32_t share_access) 24105772Sas200622 { 24115772Sas200622 int rc; 24125772Sas200622 24135772Sas200622 if (node->attr.sa_vattr.va_type == VDIR) 24145772Sas200622 return (NT_STATUS_SUCCESS); 24155772Sas200622 24165772Sas200622 /* Allow access if the request is just for meta data */ 24175772Sas200622 if ((desired_access & FILE_DATA_ALL) == 0) 24185772Sas200622 return (NT_STATUS_SUCCESS); 24195772Sas200622 24205772Sas200622 rc = smb_node_open_check(node, cr, desired_access, share_access); 24215772Sas200622 if (rc) 24225772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 24235772Sas200622 24245772Sas200622 rc = smb_vop_shrlock(node->vp, uniq_fid, desired_access, share_access, 24255772Sas200622 cr); 24265772Sas200622 if (rc) 24275772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 24285772Sas200622 24295772Sas200622 return (NT_STATUS_SUCCESS); 24305772Sas200622 } 24315772Sas200622 24325521Sas200622 void 24335772Sas200622 smb_fsop_unshrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid) 24345521Sas200622 { 24355772Sas200622 if (node->attr.sa_vattr.va_type == VDIR) 24365772Sas200622 return; 24375772Sas200622 24385772Sas200622 (void) smb_vop_unshrlock(node->vp, uniq_fid, cr); 24395772Sas200622 } 24406600Sas200622 24416600Sas200622 int 24426600Sas200622 smb_fsop_frlock(smb_node_t *node, smb_lock_t *lock, boolean_t unlock, 24436600Sas200622 cred_t *cr) 24446600Sas200622 { 24456600Sas200622 flock64_t bf; 24466600Sas200622 int flag = F_REMOTELOCK; 24476600Sas200622 24486771Sjb150015 /* 24496771Sjb150015 * VOP_FRLOCK() will not be called if: 24506771Sjb150015 * 24516771Sjb150015 * 1) The lock has a range of zero bytes. The semantics of Windows and 24526771Sjb150015 * POSIX are different. In the case of POSIX it asks for the locking 24536771Sjb150015 * of all the bytes from the offset provided until the end of the 24546771Sjb150015 * file. In the case of Windows a range of zero locks nothing and 24556771Sjb150015 * doesn't conflict with any other lock. 24566771Sjb150015 * 24576771Sjb150015 * 2) The lock rolls over (start + lenght < start). Solaris will assert 24586771Sjb150015 * if such a request is submitted. This will not create 24596771Sjb150015 * incompatibilities between POSIX and Windows. In the Windows world, 24606771Sjb150015 * if a client submits such a lock, the server will not lock any 24616771Sjb150015 * bytes. Interestingly if the same lock (same offset and length) is 24626771Sjb150015 * resubmitted Windows will consider that there is an overlap and 24636771Sjb150015 * the granting rules will then apply. 24646771Sjb150015 */ 24656771Sjb150015 if ((lock->l_length == 0) || 24666771Sjb150015 ((lock->l_start + lock->l_length - 1) < lock->l_start)) 24676771Sjb150015 return (0); 24686771Sjb150015 24696600Sas200622 bzero(&bf, sizeof (bf)); 24706600Sas200622 24716600Sas200622 if (unlock) { 24726600Sas200622 bf.l_type = F_UNLCK; 24736600Sas200622 } else if (lock->l_type == SMB_LOCK_TYPE_READONLY) { 24746600Sas200622 bf.l_type = F_RDLCK; 24756600Sas200622 flag |= FREAD; 24766600Sas200622 } else if (lock->l_type == SMB_LOCK_TYPE_READWRITE) { 24776600Sas200622 bf.l_type = F_WRLCK; 24786600Sas200622 flag |= FWRITE; 24796600Sas200622 } 24806600Sas200622 24816600Sas200622 bf.l_start = lock->l_start; 24826600Sas200622 bf.l_len = lock->l_length; 24837348SJose.Borrego@Sun.COM bf.l_pid = lock->l_file->f_uniqid; 24846600Sas200622 bf.l_sysid = smb_ct.cc_sysid; 24856600Sas200622 24866600Sas200622 return (smb_vop_frlock(node->vp, cr, flag, &bf)); 24876600Sas200622 } 2488