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 /* 22*8670SJose.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 2005331Samw if (is_dir) { 2017619SJose.Borrego@Sun.COM rc = smb_vop_mkdir(dir_snode->vp, name, attr, &vp, 2027619SJose.Borrego@Sun.COM flags, cr, vsap); 2035331Samw } else { 2047619SJose.Borrego@Sun.COM rc = smb_vop_create(dir_snode->vp, name, attr, &vp, 2057619SJose.Borrego@Sun.COM flags, cr, vsap); 2065331Samw } 2075331Samw 2085331Samw if (vsap != NULL) 2095331Samw kmem_free(vsap->vsa_aclentp, aclbsize); 2105331Samw 2115331Samw if (rc != 0) 2125331Samw return (rc); 2135331Samw 2145331Samw set_attr.sa_mask = 0; 2155331Samw 2165331Samw /* 2175331Samw * Ideally we should be able to specify the owner and owning 2185331Samw * group at create time along with the ACL. Since we cannot 2195331Samw * do that right now, kcred is passed to smb_vop_setattr so it 2205331Samw * doesn't fail due to lack of permission. 2215331Samw */ 2225331Samw if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 2235331Samw set_attr.sa_vattr.va_uid = fs_sd->sd_uid; 2245331Samw set_attr.sa_mask |= SMB_AT_UID; 2255331Samw } 2265331Samw 2275331Samw if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 2285331Samw set_attr.sa_vattr.va_gid = fs_sd->sd_gid; 2295331Samw set_attr.sa_mask |= SMB_AT_GID; 2305331Samw } 2315331Samw 2327757SJanice.Chang@Sun.COM if (set_attr.sa_mask) 2337757SJanice.Chang@Sun.COM rc = smb_vop_setattr(vp, NULL, &set_attr, 0, kcred); 2345331Samw 2357619SJose.Borrego@Sun.COM if (rc == 0) { 2367619SJose.Borrego@Sun.COM *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp, 2377619SJose.Borrego@Sun.COM name, dir_snode, NULL, ret_attr); 2387619SJose.Borrego@Sun.COM 239*8670SJose.Borrego@Sun.COM if (*ret_snode == NULL) 2407619SJose.Borrego@Sun.COM rc = ENOMEM; 241*8670SJose.Borrego@Sun.COM 242*8670SJose.Borrego@Sun.COM VN_RELE(vp); 2437619SJose.Borrego@Sun.COM } 2445331Samw } else { 2455331Samw /* 2465331Samw * For filesystems that don't support ACL-on-create, try 2475331Samw * to set the specified SD after create, which could actually 2485331Samw * fail because of conflicts between inherited security 2495331Samw * attributes upon creation and the specified SD. 2505331Samw * 2515331Samw * Passing kcred to smb_fsop_sdwrite() to overcome this issue. 2525331Samw */ 2535331Samw 2545331Samw if (is_dir) { 2557619SJose.Borrego@Sun.COM rc = smb_vop_mkdir(dir_snode->vp, name, attr, &vp, 2567619SJose.Borrego@Sun.COM flags, cr, NULL); 2575331Samw } else { 2587619SJose.Borrego@Sun.COM rc = smb_vop_create(dir_snode->vp, name, attr, &vp, 2597619SJose.Borrego@Sun.COM flags, cr, NULL); 2605331Samw } 2615331Samw 2625521Sas200622 if (rc != 0) 2635521Sas200622 return (rc); 2645521Sas200622 2657619SJose.Borrego@Sun.COM *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp, 2667619SJose.Borrego@Sun.COM name, dir_snode, NULL, ret_attr); 2677619SJose.Borrego@Sun.COM 2687619SJose.Borrego@Sun.COM if (*ret_snode != NULL) { 2697619SJose.Borrego@Sun.COM if (!smb_tree_has_feature(sr->tid_tree, 2707619SJose.Borrego@Sun.COM SMB_TREE_NFS_MOUNTED)) 2717619SJose.Borrego@Sun.COM rc = smb_fsop_sdwrite(sr, kcred, *ret_snode, 2727619SJose.Borrego@Sun.COM fs_sd, 1); 2737619SJose.Borrego@Sun.COM } else { 2745331Samw rc = ENOMEM; 2755331Samw } 276*8670SJose.Borrego@Sun.COM 277*8670SJose.Borrego@Sun.COM VN_RELE(vp); 2785331Samw } 2795331Samw 2805521Sas200622 if (rc != 0) { 2817619SJose.Borrego@Sun.COM if (is_dir) 2827619SJose.Borrego@Sun.COM (void) smb_vop_rmdir(dir_snode->vp, name, flags, cr); 2837619SJose.Borrego@Sun.COM else 2847619SJose.Borrego@Sun.COM (void) smb_vop_remove(dir_snode->vp, name, flags, cr); 2855521Sas200622 } 2865521Sas200622 2875331Samw return (rc); 2885331Samw } 2895331Samw 2905331Samw /* 2915331Samw * smb_fsop_create 2925331Samw * 2935331Samw * All SMB functions should use this wrapper to ensure that 2945331Samw * all the smb_vop_creates are performed with the appropriate credentials. 2955331Samw * Please document any direct calls to explain the reason 2965331Samw * for avoiding this wrapper. 2975331Samw * 2985331Samw * It is assumed that a reference exists on snode coming into this routine. 2995331Samw * 3005331Samw * *ret_snode is returned with a reference upon success. No reference is 3015331Samw * taken if an error is returned. 3025331Samw */ 3035331Samw 3045331Samw int 3055331Samw smb_fsop_create( 3066139Sjb150015 smb_request_t *sr, 3076139Sjb150015 cred_t *cr, 3086139Sjb150015 smb_node_t *dir_snode, 3096139Sjb150015 char *name, 3106139Sjb150015 smb_attr_t *attr, 3116139Sjb150015 smb_node_t **ret_snode, 3126139Sjb150015 smb_attr_t *ret_attr) 3135331Samw { 3145331Samw struct open_param *op = &sr->arg.open; 3156139Sjb150015 smb_node_t *fnode; 3166139Sjb150015 smb_attr_t file_attr; 3176139Sjb150015 vnode_t *xattrdirvp; 3186139Sjb150015 vnode_t *vp; 3196139Sjb150015 char *longname = NULL; 3206139Sjb150015 char *namep; 3216139Sjb150015 char *fname; 3226139Sjb150015 char *sname; 3236139Sjb150015 int is_stream; 3246139Sjb150015 int flags = 0; 3256139Sjb150015 int rc = 0; 3266139Sjb150015 smb_fssd_t fs_sd; 3276139Sjb150015 uint32_t secinfo; 3286139Sjb150015 uint32_t status; 3295331Samw 3305331Samw ASSERT(cr); 3315331Samw ASSERT(dir_snode); 3325331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 3335331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 3345331Samw 3355331Samw ASSERT(ret_snode); 3365331Samw *ret_snode = 0; 3375331Samw 3385331Samw ASSERT(name); 3395331Samw if (*name == 0) 3405331Samw return (EINVAL); 3415331Samw 3425331Samw ASSERT(sr); 3435331Samw ASSERT(sr->tid_tree); 3447348SJose.Borrego@Sun.COM 3457348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 3467348SJose.Borrego@Sun.COM return (EACCES); 3477348SJose.Borrego@Sun.COM 3487348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 3495331Samw return (EROFS); 3505331Samw 3517348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 3525331Samw flags = SMB_IGNORE_CASE; 3535331Samw 3545331Samw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 3555331Samw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 3565331Samw 3575331Samw is_stream = smb_stream_parse_name(name, fname, sname); 3588334SJose.Borrego@Sun.COM if (is_stream == -1) { 3598334SJose.Borrego@Sun.COM kmem_free(fname, MAXNAMELEN); 3608334SJose.Borrego@Sun.COM kmem_free(sname, MAXNAMELEN); 3618334SJose.Borrego@Sun.COM return (EINVAL); 3628334SJose.Borrego@Sun.COM } 3635331Samw 3645331Samw if (is_stream) 3655331Samw namep = fname; 3665331Samw else 3675331Samw namep = name; 3685331Samw 3695331Samw if (smb_maybe_mangled_name(namep)) { 3705331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 3715331Samw 3725331Samw rc = smb_unmangle_name(sr, cr, dir_snode, namep, longname, 3735331Samw MAXNAMELEN, NULL, NULL, 1); 3745331Samw 3755331Samw if ((is_stream == 0) && (rc == 0)) 3765331Samw rc = EEXIST; 3775331Samw 3785331Samw if ((is_stream && rc) || 3795331Samw ((is_stream == 0) && (rc != ENOENT))) { 3805331Samw kmem_free(longname, MAXNAMELEN); 3815331Samw kmem_free(fname, MAXNAMELEN); 3825331Samw kmem_free(sname, MAXNAMELEN); 3835331Samw return (rc); 3845331Samw } 3855331Samw 3865331Samw if (is_stream) 3875331Samw namep = longname; 3885331Samw else 3895331Samw kmem_free(longname, MAXNAMELEN); 3905331Samw } 3915331Samw 3925331Samw if (is_stream) { 3935331Samw /* 3945331Samw * Look up the unnamed stream. 3955331Samw * 3965331Samw * Mangle processing in smb_fsop_lookup() for the unnamed 3975331Samw * stream won't be needed (as it was done above), but 3985331Samw * it may be needed on any link target (which 3995331Samw * smb_fsop_lookup() will provide). 4005331Samw */ 4015331Samw rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, 4025331Samw sr->tid_tree->t_snode, dir_snode, namep, &fnode, &file_attr, 4035331Samw 0, 0); 4045331Samw 4055331Samw if (longname) { 4065331Samw kmem_free(longname, MAXNAMELEN); 4075331Samw namep = NULL; 4085331Samw } 4095331Samw 4105331Samw if (rc != 0) { 4115331Samw kmem_free(fname, MAXNAMELEN); 4125331Samw kmem_free(sname, MAXNAMELEN); 4135331Samw return (rc); 4145331Samw } 4155331Samw 4165331Samw rc = smb_vop_stream_create(fnode->vp, sname, attr, &vp, 4175772Sas200622 &xattrdirvp, flags, cr); 4185331Samw 4195331Samw if (rc != 0) { 4205331Samw smb_node_release(fnode); 4215331Samw kmem_free(fname, MAXNAMELEN); 4225331Samw kmem_free(sname, MAXNAMELEN); 4235331Samw return (rc); 4245331Samw } 4255331Samw 4266030Sjb150015 attr->sa_vattr.va_uid = file_attr.sa_vattr.va_uid; 4276030Sjb150015 attr->sa_vattr.va_gid = file_attr.sa_vattr.va_gid; 4286030Sjb150015 attr->sa_mask = SMB_AT_UID | SMB_AT_GID; 4296030Sjb150015 4306030Sjb150015 /* 4316030Sjb150015 * The second parameter of smb_vop_setattr() is set to 4326030Sjb150015 * NULL, even though an unnamed stream exists. This is 4336030Sjb150015 * because we want to set the UID and GID on the named 4346030Sjb150015 * stream in this case for consistency with the (unnamed 4356030Sjb150015 * stream) file (see comments for smb_vop_setattr()). 4366030Sjb150015 */ 4376030Sjb150015 4387757SJanice.Chang@Sun.COM rc = smb_vop_setattr(vp, NULL, attr, 0, kcred); 4396030Sjb150015 4406030Sjb150015 if (rc != 0) { 4416030Sjb150015 smb_node_release(fnode); 4426030Sjb150015 kmem_free(fname, MAXNAMELEN); 4436030Sjb150015 kmem_free(sname, MAXNAMELEN); 4446030Sjb150015 return (rc); 4456030Sjb150015 } 4466030Sjb150015 4475331Samw *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, 4485331Samw vp, sname, ret_attr); 4495331Samw 4505331Samw smb_node_release(fnode); 451*8670SJose.Borrego@Sun.COM VN_RELE(xattrdirvp); 452*8670SJose.Borrego@Sun.COM VN_RELE(vp); 4535331Samw 4545331Samw if (*ret_snode == NULL) { 4555331Samw kmem_free(fname, MAXNAMELEN); 4565331Samw kmem_free(sname, MAXNAMELEN); 4575331Samw return (ENOMEM); 4585331Samw } 4595331Samw } else { 4605521Sas200622 if (op->sd) { 4615331Samw /* 4625331Samw * SD sent by client in Windows format. Needs to be 4635331Samw * converted to FS format. No inheritance. 4645331Samw */ 4655521Sas200622 secinfo = smb_sd_get_secinfo(op->sd); 4665521Sas200622 smb_fssd_init(&fs_sd, secinfo, 0); 4675521Sas200622 4685521Sas200622 status = smb_sd_tofs(op->sd, &fs_sd); 4695331Samw if (status == NT_STATUS_SUCCESS) { 4705331Samw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 4715331Samw name, attr, ret_snode, ret_attr, &fs_sd); 4725331Samw } 4735331Samw else 4745331Samw rc = EINVAL; 4755521Sas200622 smb_fssd_term(&fs_sd); 4765331Samw } else if (sr->tid_tree->t_acltype == ACE_T) { 4775331Samw /* 4785331Samw * No incoming SD and filesystem is ZFS 4795331Samw * Server applies Windows inheritance rules, 4805331Samw * see smb_fsop_sdinherit() comments as to why. 4815331Samw */ 4825521Sas200622 smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, 0); 4835331Samw rc = smb_fsop_sdinherit(sr, dir_snode, &fs_sd); 4845331Samw if (rc == 0) { 4855331Samw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 4865331Samw name, attr, ret_snode, ret_attr, &fs_sd); 4875331Samw } 4885331Samw 4895521Sas200622 smb_fssd_term(&fs_sd); 4905331Samw } else { 4915331Samw /* 4925331Samw * No incoming SD and filesystem is not ZFS 4935331Samw * let the filesystem handles the inheritance. 4945331Samw */ 4955331Samw rc = smb_vop_create(dir_snode->vp, name, attr, &vp, 4965772Sas200622 flags, cr, NULL); 4975331Samw 4985331Samw if (rc == 0) { 4995331Samw *ret_snode = smb_node_lookup(sr, op, cr, vp, 5005331Samw name, dir_snode, NULL, ret_attr); 5015331Samw 502*8670SJose.Borrego@Sun.COM if (*ret_snode == NULL) 5035331Samw rc = ENOMEM; 504*8670SJose.Borrego@Sun.COM 505*8670SJose.Borrego@Sun.COM VN_RELE(vp); 5065331Samw } 5075331Samw 5085331Samw } 5095331Samw } 5105331Samw 5115331Samw kmem_free(fname, MAXNAMELEN); 5125331Samw kmem_free(sname, MAXNAMELEN); 5135331Samw return (rc); 5145331Samw } 5155331Samw 5165331Samw /* 5175331Samw * smb_fsop_mkdir 5185331Samw * 5195331Samw * All SMB functions should use this wrapper to ensure that 5205331Samw * the the calls are performed with the appropriate credentials. 5215331Samw * Please document any direct call to explain the reason 5225331Samw * for avoiding this wrapper. 5235331Samw * 5245331Samw * It is assumed that a reference exists on snode coming into this routine. 5255331Samw * 5265331Samw * *ret_snode is returned with a reference upon success. No reference is 5275331Samw * taken if an error is returned. 5285331Samw */ 5295331Samw int 5305331Samw smb_fsop_mkdir( 5316139Sjb150015 smb_request_t *sr, 5325331Samw cred_t *cr, 5335331Samw smb_node_t *dir_snode, 5345331Samw char *name, 5355331Samw smb_attr_t *attr, 5365331Samw smb_node_t **ret_snode, 5375331Samw smb_attr_t *ret_attr) 5385331Samw { 5395331Samw struct open_param *op = &sr->arg.open; 5405331Samw char *longname; 5415331Samw vnode_t *vp; 5425331Samw int flags = 0; 5435331Samw smb_fssd_t fs_sd; 5445331Samw uint32_t secinfo; 5455331Samw uint32_t status; 5465331Samw int rc; 5475331Samw ASSERT(cr); 5485331Samw ASSERT(dir_snode); 5495331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 5505331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 5515331Samw 5525331Samw ASSERT(ret_snode); 5535331Samw *ret_snode = 0; 5545331Samw 5555331Samw ASSERT(name); 5565331Samw if (*name == 0) 5575331Samw return (EINVAL); 5585331Samw 5595331Samw ASSERT(sr); 5605331Samw ASSERT(sr->tid_tree); 5617348SJose.Borrego@Sun.COM 5627348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 5637348SJose.Borrego@Sun.COM return (EACCES); 5647348SJose.Borrego@Sun.COM 5657348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 5665331Samw return (EROFS); 5675331Samw 5685331Samw if (smb_maybe_mangled_name(name)) { 5695331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 5705331Samw rc = smb_unmangle_name(sr, cr, dir_snode, name, longname, 5715331Samw MAXNAMELEN, NULL, NULL, 1); 5725331Samw 5735331Samw kmem_free(longname, MAXNAMELEN); 5745331Samw 5755331Samw /* 5765331Samw * If the name passed in by the client has an unmangled 5775331Samw * equivalent that is found in the specified directory, 5785331Samw * then the mkdir cannot succeed. Return EEXIST. 5795331Samw * 5805331Samw * Only if ENOENT is returned will a mkdir be attempted. 5815331Samw */ 5825331Samw 5835331Samw if (rc == 0) 5845331Samw rc = EEXIST; 5855331Samw 5865331Samw if (rc != ENOENT) 5875331Samw return (rc); 5885331Samw } 5895331Samw 5907348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 5915331Samw flags = SMB_IGNORE_CASE; 5925331Samw 5935521Sas200622 if (op->sd) { 5945331Samw /* 5955331Samw * SD sent by client in Windows format. Needs to be 5965331Samw * converted to FS format. No inheritance. 5975331Samw */ 5985521Sas200622 secinfo = smb_sd_get_secinfo(op->sd); 5995521Sas200622 smb_fssd_init(&fs_sd, secinfo, SMB_FSSD_FLAGS_DIR); 6005521Sas200622 6015521Sas200622 status = smb_sd_tofs(op->sd, &fs_sd); 6025331Samw if (status == NT_STATUS_SUCCESS) { 6035331Samw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 6045331Samw name, attr, ret_snode, ret_attr, &fs_sd); 6055331Samw } 6065331Samw else 6075331Samw rc = EINVAL; 6085521Sas200622 smb_fssd_term(&fs_sd); 6095331Samw } else if (sr->tid_tree->t_acltype == ACE_T) { 6105331Samw /* 6115331Samw * No incoming SD and filesystem is ZFS 6125331Samw * Server applies Windows inheritance rules, 6135331Samw * see smb_fsop_sdinherit() comments as to why. 6145331Samw */ 6155521Sas200622 smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, SMB_FSSD_FLAGS_DIR); 6165331Samw rc = smb_fsop_sdinherit(sr, dir_snode, &fs_sd); 6175331Samw if (rc == 0) { 6185331Samw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 6195331Samw name, attr, ret_snode, ret_attr, &fs_sd); 6205331Samw } 6215331Samw 6225521Sas200622 smb_fssd_term(&fs_sd); 6235331Samw 6245331Samw } else { 6255331Samw rc = smb_vop_mkdir(dir_snode->vp, name, attr, &vp, flags, cr, 6265772Sas200622 NULL); 6275331Samw 6285331Samw if (rc == 0) { 6295331Samw *ret_snode = smb_node_lookup(sr, op, cr, vp, name, 6305331Samw dir_snode, NULL, ret_attr); 6315331Samw 632*8670SJose.Borrego@Sun.COM if (*ret_snode == NULL) 6335331Samw rc = ENOMEM; 634*8670SJose.Borrego@Sun.COM 635*8670SJose.Borrego@Sun.COM VN_RELE(vp); 6365331Samw } 6375331Samw } 6385331Samw 6395331Samw return (rc); 6405331Samw } 6415331Samw 6425331Samw /* 6435331Samw * smb_fsop_remove 6445331Samw * 6455331Samw * All SMB functions should use this wrapper to ensure that 6465331Samw * the the calls are performed with the appropriate credentials. 6475331Samw * Please document any direct call to explain the reason 6485331Samw * for avoiding this wrapper. 6495331Samw * 6505331Samw * It is assumed that a reference exists on snode coming into this routine. 6515331Samw * 6525331Samw * od: This means that the name passed in is an on-disk name. 6535331Samw * A null smb_request might be passed to this function. 6545331Samw */ 6555331Samw 6565331Samw int 6575331Samw smb_fsop_remove( 6586139Sjb150015 smb_request_t *sr, 6596139Sjb150015 cred_t *cr, 6606139Sjb150015 smb_node_t *dir_snode, 6616139Sjb150015 char *name, 6626139Sjb150015 int od) 6635331Samw { 6646139Sjb150015 smb_node_t *fnode; 6656139Sjb150015 smb_attr_t file_attr; 6666139Sjb150015 char *longname; 6676139Sjb150015 char *fname; 6686139Sjb150015 char *sname; 6696139Sjb150015 int flags = 0; 6706139Sjb150015 int rc; 6715331Samw 6725331Samw ASSERT(cr); 6735331Samw /* 6745331Samw * The state of the node could be SMB_NODE_STATE_DESTROYING if this 6755331Samw * function is called during the deletion of the node (because of 6765331Samw * DELETE_ON_CLOSE). 6775331Samw */ 6785331Samw ASSERT(dir_snode); 6795331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 6805331Samw 6817348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 6825331Samw return (EACCES); 6835331Samw 6847348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 6855331Samw return (EROFS); 6865331Samw 6875331Samw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 6885331Samw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 6895331Samw 6905967Scp160787 /* 6915967Scp160787 * If the passed-in name is an on-disk name, 6925967Scp160787 * then we need to do a case-sensitive remove. 6935967Scp160787 * This is important if the on-disk name 6945967Scp160787 * corresponds to a mangled name passed in by 6955967Scp160787 * the client. We want to make sure to remove 6965967Scp160787 * the exact file specified by the client, 6975967Scp160787 * instead of letting the underlying file system 6985967Scp160787 * do a remove on the "first match." 6995967Scp160787 */ 7005967Scp160787 7017348SJose.Borrego@Sun.COM if ((od == 0) && SMB_TREE_IS_CASEINSENSITIVE(sr)) 7025967Scp160787 flags = SMB_IGNORE_CASE; 7035967Scp160787 7045967Scp160787 if (dir_snode->flags & NODE_XATTR_DIR) { 7055967Scp160787 rc = smb_vop_stream_remove(dir_snode->dir_snode->vp, 7065967Scp160787 name, flags, cr); 7078334SJose.Borrego@Sun.COM } else if ((rc = smb_stream_parse_name(name, fname, sname)) != 0) { 7088334SJose.Borrego@Sun.COM if (rc == -1) { 7098334SJose.Borrego@Sun.COM kmem_free(fname, MAXNAMELEN); 7108334SJose.Borrego@Sun.COM kmem_free(sname, MAXNAMELEN); 7118334SJose.Borrego@Sun.COM return (EINVAL); 7128334SJose.Borrego@Sun.COM } 7138334SJose.Borrego@Sun.COM 7145967Scp160787 /* 7155967Scp160787 * It is assumed that "name" corresponds to the path 7165967Scp160787 * passed in by the client, and no need of suppressing 7175967Scp160787 * case-insensitive lookups is needed. 7185967Scp160787 */ 7195331Samw 7205331Samw ASSERT(od == 0); 7215331Samw 7225331Samw /* 7235331Samw * Look up the unnamed stream (i.e. fname). 7245331Samw * Unmangle processing will be done on fname 7255331Samw * as well as any link target. 7265331Samw */ 7275331Samw 7285331Samw rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, 7295331Samw sr->tid_tree->t_snode, dir_snode, fname, &fnode, &file_attr, 7305331Samw 0, 0); 7315331Samw 7325331Samw if (rc != 0) { 7335331Samw kmem_free(fname, MAXNAMELEN); 7345331Samw kmem_free(sname, MAXNAMELEN); 7355331Samw return (rc); 7365331Samw } 7375331Samw 7385331Samw /* 7395331Samw * XXX 7405331Samw * Need to find out what permission is required by NTFS 7415331Samw * to remove a stream. 7425331Samw */ 7435772Sas200622 rc = smb_vop_stream_remove(fnode->vp, sname, flags, cr); 7445331Samw 7455331Samw smb_node_release(fnode); 7465331Samw } else { 7475772Sas200622 rc = smb_vop_remove(dir_snode->vp, name, flags, cr); 7485331Samw 7495331Samw if (rc == ENOENT) { 7505331Samw if (smb_maybe_mangled_name(name) == 0) { 7515331Samw kmem_free(fname, MAXNAMELEN); 7525331Samw kmem_free(sname, MAXNAMELEN); 7535331Samw return (rc); 7545331Samw } 7555331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 7565331Samw 7575331Samw rc = smb_unmangle_name(sr, cr, dir_snode, name, 7585331Samw longname, MAXNAMELEN, NULL, NULL, 1); 7595331Samw 7605331Samw if (rc == 0) { 7615331Samw /* 7625331Samw * We passed "1" as the "od" parameter 7635331Samw * to smb_unmangle_name(), such that longname 7645331Samw * is the real (case-sensitive) on-disk name. 7655331Samw * We make sure we do a remove on this exact 7665331Samw * name, as the name was mangled and denotes 7675331Samw * a unique file. 7685331Samw */ 7695331Samw flags &= ~SMB_IGNORE_CASE; 7705331Samw rc = smb_vop_remove(dir_snode->vp, longname, 7715772Sas200622 flags, cr); 7725331Samw } 7735331Samw 7745331Samw kmem_free(longname, MAXNAMELEN); 7755331Samw } 7765331Samw } 7775331Samw 7785331Samw kmem_free(fname, MAXNAMELEN); 7795331Samw kmem_free(sname, MAXNAMELEN); 7805331Samw return (rc); 7815331Samw } 7825331Samw 7835331Samw /* 7845331Samw * smb_fsop_remove_streams 7855331Samw * 7865331Samw * This function removes a file's streams without removing the 7875331Samw * file itself. 7885331Samw * 789*8670SJose.Borrego@Sun.COM * It is assumed that fnode is not a link. 7905331Samw */ 7915331Samw int 7926139Sjb150015 smb_fsop_remove_streams(smb_request_t *sr, cred_t *cr, smb_node_t *fnode) 7935331Samw { 794*8670SJose.Borrego@Sun.COM int rc, flags = 0; 795*8670SJose.Borrego@Sun.COM uint16_t odid; 796*8670SJose.Borrego@Sun.COM smb_odir_t *od; 797*8670SJose.Borrego@Sun.COM smb_odirent_t *odirent; 798*8670SJose.Borrego@Sun.COM boolean_t eos; 7995331Samw 8007348SJose.Borrego@Sun.COM ASSERT(sr); 8015331Samw ASSERT(cr); 8025331Samw ASSERT(fnode); 8035331Samw ASSERT(fnode->n_magic == SMB_NODE_MAGIC); 8045331Samw ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING); 8055331Samw 8067348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, fnode) == 0) 8075331Samw return (EACCES); 8085331Samw 8097348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 8105331Samw return (EROFS); 8115331Samw 8127348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 8135331Samw flags = SMB_IGNORE_CASE; 8145331Samw 815*8670SJose.Borrego@Sun.COM /* TBD - error codes */ 816*8670SJose.Borrego@Sun.COM if ((odid = smb_odir_openat(sr, fnode)) == 0) 817*8670SJose.Borrego@Sun.COM return (ENOENT); 818*8670SJose.Borrego@Sun.COM if ((od = smb_tree_lookup_odir(sr->tid_tree, odid)) == NULL) 819*8670SJose.Borrego@Sun.COM return (ENOENT); 8205331Samw 821*8670SJose.Borrego@Sun.COM odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP); 822*8670SJose.Borrego@Sun.COM for (;;) { 823*8670SJose.Borrego@Sun.COM rc = smb_odir_read(sr, od, odirent, &eos); 824*8670SJose.Borrego@Sun.COM if ((rc != 0) || (eos)) 8255331Samw break; 826*8670SJose.Borrego@Sun.COM (void) smb_vop_remove(od->d_dnode->vp, odirent->od_name, 827*8670SJose.Borrego@Sun.COM flags, cr); 828*8670SJose.Borrego@Sun.COM } 829*8670SJose.Borrego@Sun.COM kmem_free(odirent, sizeof (smb_odirent_t)); 8305331Samw 831*8670SJose.Borrego@Sun.COM smb_odir_release(od); 832*8670SJose.Borrego@Sun.COM smb_odir_close(od); 8335331Samw return (rc); 8345331Samw } 8355331Samw 8365331Samw /* 8375331Samw * smb_fsop_rmdir 8385331Samw * 8395331Samw * All SMB functions should use this wrapper to ensure that 8405331Samw * the the calls are performed with the appropriate credentials. 8415331Samw * Please document any direct call to explain the reason 8425331Samw * for avoiding this wrapper. 8435331Samw * 8445331Samw * It is assumed that a reference exists on snode coming into this routine. 8455331Samw * 8465331Samw * od: This means that the name passed in is an on-disk name. 8475331Samw */ 8485331Samw 8495331Samw int 8505331Samw smb_fsop_rmdir( 8516139Sjb150015 smb_request_t *sr, 8526139Sjb150015 cred_t *cr, 8536139Sjb150015 smb_node_t *dir_snode, 8546139Sjb150015 char *name, 8556139Sjb150015 int od) 8565331Samw { 8576139Sjb150015 int rc; 8586139Sjb150015 int flags = 0; 8596139Sjb150015 char *longname; 8605331Samw 8615331Samw ASSERT(cr); 8625331Samw /* 8635331Samw * The state of the node could be SMB_NODE_STATE_DESTROYING if this 8645331Samw * function is called during the deletion of the node (because of 8655331Samw * DELETE_ON_CLOSE). 8665331Samw */ 8675331Samw ASSERT(dir_snode); 8685331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 8695331Samw 8707348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 8715331Samw return (EACCES); 8725331Samw 8737348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 8745331Samw return (EROFS); 8755331Samw 8765331Samw /* 8775331Samw * If the passed-in name is an on-disk name, 8785331Samw * then we need to do a case-sensitive rmdir. 8795331Samw * This is important if the on-disk name 8805331Samw * corresponds to a mangled name passed in by 8815331Samw * the client. We want to make sure to remove 8825331Samw * the exact directory specified by the client, 8835331Samw * instead of letting the underlying file system 8845331Samw * do a rmdir on the "first match." 8855331Samw */ 8865331Samw 8877348SJose.Borrego@Sun.COM if ((od == 0) && SMB_TREE_IS_CASEINSENSITIVE(sr)) 8885331Samw flags = SMB_IGNORE_CASE; 8895331Samw 8905772Sas200622 rc = smb_vop_rmdir(dir_snode->vp, name, flags, cr); 8915331Samw 8925331Samw if (rc == ENOENT) { 8935331Samw if (smb_maybe_mangled_name(name) == 0) 8945331Samw return (rc); 8955331Samw 8965331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 8975331Samw 8985331Samw rc = smb_unmangle_name(sr, cr, dir_snode, 8995331Samw name, longname, MAXNAMELEN, NULL, 9005331Samw NULL, 1); 9015331Samw 9025331Samw if (rc == 0) { 9035331Samw /* 9045331Samw * We passed "1" as the "od" parameter 9055331Samw * to smb_unmangle_name(), such that longname 9065331Samw * is the real (case-sensitive) on-disk name. 9075331Samw * We make sure we do a rmdir on this exact 9085331Samw * name, as the name was mangled and denotes 9095331Samw * a unique directory. 9105331Samw */ 9115331Samw flags &= ~SMB_IGNORE_CASE; 9125772Sas200622 rc = smb_vop_rmdir(dir_snode->vp, longname, flags, cr); 9135331Samw } 9145331Samw 9155331Samw kmem_free(longname, MAXNAMELEN); 9165331Samw } 9175331Samw 9185331Samw return (rc); 9195331Samw } 9205331Samw 9215331Samw /* 9225331Samw * smb_fsop_getattr 9235331Samw * 9245331Samw * All SMB functions should use this wrapper to ensure that 9255331Samw * the the calls are performed with the appropriate credentials. 9265331Samw * Please document any direct call to explain the reason 9275331Samw * for avoiding this wrapper. 9285331Samw * 9295331Samw * It is assumed that a reference exists on snode coming into this routine. 9305331Samw */ 9315331Samw int 9326139Sjb150015 smb_fsop_getattr(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 9335331Samw smb_attr_t *attr) 9345331Samw { 9355331Samw smb_node_t *unnamed_node; 9365331Samw vnode_t *unnamed_vp = NULL; 9375331Samw uint32_t status; 9385331Samw uint32_t access = 0; 9395331Samw int flags = 0; 9405772Sas200622 int rc; 9415331Samw 9425331Samw ASSERT(cr); 9435331Samw ASSERT(snode); 9445331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 9455331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 9465331Samw 9477348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0) 9485331Samw return (EACCES); 9495331Samw 9505331Samw if (sr->fid_ofile) { 9515331Samw /* if uid and/or gid is requested */ 9525331Samw if (attr->sa_mask & (SMB_AT_UID|SMB_AT_GID)) 9535331Samw access |= READ_CONTROL; 9545331Samw 9555331Samw /* if anything else is also requested */ 9565331Samw if (attr->sa_mask & ~(SMB_AT_UID|SMB_AT_GID)) 9575331Samw access |= FILE_READ_ATTRIBUTES; 9585331Samw 9595331Samw status = smb_ofile_access(sr->fid_ofile, cr, access); 9605331Samw if (status != NT_STATUS_SUCCESS) 9615331Samw return (EACCES); 9625331Samw 9637348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, 9647348SJose.Borrego@Sun.COM SMB_TREE_ACEMASKONACCESS)) 9655331Samw flags = ATTR_NOACLCHECK; 9665331Samw } 9675331Samw 9685331Samw unnamed_node = SMB_IS_STREAM(snode); 9695331Samw 9705331Samw if (unnamed_node) { 9715331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 9725331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 9735331Samw unnamed_vp = unnamed_node->vp; 9745331Samw } 9755331Samw 9765772Sas200622 rc = smb_vop_getattr(snode->vp, unnamed_vp, attr, flags, cr); 9775772Sas200622 if (rc == 0) 9785772Sas200622 snode->attr = *attr; 9795772Sas200622 9805772Sas200622 return (rc); 9815331Samw } 9825331Samw 9835331Samw /* 9845331Samw * smb_fsop_rename 9855331Samw * 9865331Samw * All SMB functions should use this smb_vop_rename wrapper to ensure that 9875331Samw * the smb_vop_rename is performed with the appropriate credentials. 9885331Samw * Please document any direct call to smb_vop_rename to explain the reason 9895331Samw * for avoiding this wrapper. 9905331Samw * 9915331Samw * It is assumed that references exist on from_dir_snode and to_dir_snode coming 9925331Samw * into this routine. 9935331Samw */ 9945331Samw int 9955331Samw smb_fsop_rename( 9966139Sjb150015 smb_request_t *sr, 9975331Samw cred_t *cr, 9985331Samw smb_node_t *from_dir_snode, 9995331Samw char *from_name, 10005331Samw smb_node_t *to_dir_snode, 10015331Samw char *to_name) 10025331Samw { 10035331Samw smb_node_t *from_snode; 10045331Samw smb_attr_t tmp_attr; 10055331Samw vnode_t *from_vp; 10065331Samw int flags = 0; 10075331Samw int rc; 10085331Samw 10095331Samw ASSERT(cr); 10105331Samw ASSERT(from_dir_snode); 10115331Samw ASSERT(from_dir_snode->n_magic == SMB_NODE_MAGIC); 10125331Samw ASSERT(from_dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 10135331Samw 10145331Samw ASSERT(to_dir_snode); 10155331Samw ASSERT(to_dir_snode->n_magic == SMB_NODE_MAGIC); 10165331Samw ASSERT(to_dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 10175331Samw 10187348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, from_dir_snode) == 0) 10195331Samw return (EACCES); 10205331Samw 10217348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, to_dir_snode) == 0) 10225331Samw return (EACCES); 10235331Samw 10245331Samw ASSERT(sr); 10255331Samw ASSERT(sr->tid_tree); 10267348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 10275331Samw return (EROFS); 10285331Samw 10295331Samw /* 10307348SJose.Borrego@Sun.COM * Note: There is no need to check SMB_TREE_IS_CASEINSENSITIVE 10315331Samw * here. 10325331Samw * 10335331Samw * A case-sensitive rename is always done in this routine 10345331Samw * because we are using the on-disk name from an earlier lookup. 10355331Samw * If a mangled name was passed in by the caller (denoting a 10365331Samw * deterministic lookup), then the exact file must be renamed 10375331Samw * (i.e. SMB_IGNORE_CASE must not be passed to VOP_RENAME, or 10385331Samw * else the underlying file system might return a "first-match" 10395331Samw * on this on-disk name, possibly resulting in the wrong file). 10405331Samw */ 10415331Samw 10425331Samw /* 10435331Samw * XXX: Lock required through smb_node_release() below? 10445331Samw */ 10455331Samw 10465331Samw rc = smb_vop_lookup(from_dir_snode->vp, from_name, &from_vp, NULL, 0, 10475772Sas200622 NULL, cr); 10485331Samw 10495331Samw if (rc != 0) 10505331Samw return (rc); 10515331Samw 10525331Samw rc = smb_vop_rename(from_dir_snode->vp, from_name, to_dir_snode->vp, 10535772Sas200622 to_name, flags, cr); 10545331Samw 10555331Samw if (rc == 0) { 10565331Samw from_snode = smb_node_lookup(sr, NULL, cr, from_vp, from_name, 10575331Samw from_dir_snode, NULL, &tmp_attr); 10585331Samw 10595331Samw if (from_snode == NULL) { 1060*8670SJose.Borrego@Sun.COM rc = ENOMEM; 1061*8670SJose.Borrego@Sun.COM } else { 1062*8670SJose.Borrego@Sun.COM (void) smb_node_rename(from_dir_snode, from_snode, 1063*8670SJose.Borrego@Sun.COM to_dir_snode, to_name); 1064*8670SJose.Borrego@Sun.COM smb_node_release(from_snode); 10655331Samw } 10665331Samw } 1067*8670SJose.Borrego@Sun.COM VN_RELE(from_vp); 10685331Samw 10695331Samw /* XXX: unlock */ 10705331Samw 10715331Samw return (rc); 10725331Samw } 10735331Samw 10745331Samw /* 10755331Samw * smb_fsop_setattr 10765331Samw * 10775331Samw * All SMB functions should use this wrapper to ensure that 10785331Samw * the the calls are performed with the appropriate credentials. 10795331Samw * Please document any direct call to explain the reason 10805331Samw * for avoiding this wrapper. 10815331Samw * 10825331Samw * It is assumed that a reference exists on snode coming into this routine. 10835331Samw * A null smb_request might be passed to this function. 10845331Samw */ 10855331Samw int 10865331Samw smb_fsop_setattr( 10876139Sjb150015 smb_request_t *sr, 10886139Sjb150015 cred_t *cr, 10896139Sjb150015 smb_node_t *snode, 10906139Sjb150015 smb_attr_t *set_attr, 10916139Sjb150015 smb_attr_t *ret_attr) 10925331Samw { 10935331Samw smb_node_t *unnamed_node; 10945331Samw vnode_t *unnamed_vp = NULL; 10955331Samw uint32_t status; 10967619SJose.Borrego@Sun.COM uint32_t access; 10975331Samw int rc = 0; 10985331Samw int flags = 0; 10997619SJose.Borrego@Sun.COM uint_t sa_mask; 11005331Samw 11015331Samw ASSERT(cr); 11025331Samw ASSERT(snode); 11035331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 11045331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 11055331Samw 11067348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0) 11075331Samw return (EACCES); 11085331Samw 11097348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 11105331Samw return (EROFS); 11115331Samw 11127348SJose.Borrego@Sun.COM if (sr && (set_attr->sa_mask & SMB_AT_SIZE)) { 11137348SJose.Borrego@Sun.COM if (sr->fid_ofile) { 11147348SJose.Borrego@Sun.COM if (SMB_OFILE_IS_READONLY(sr->fid_ofile)) 11157348SJose.Borrego@Sun.COM return (EACCES); 11167348SJose.Borrego@Sun.COM } else { 11177348SJose.Borrego@Sun.COM if (SMB_PATHFILE_IS_READONLY(sr, snode)) 11187348SJose.Borrego@Sun.COM return (EACCES); 11197348SJose.Borrego@Sun.COM } 11207348SJose.Borrego@Sun.COM } 11217348SJose.Borrego@Sun.COM 11225331Samw /* sr could be NULL in some cases */ 11235331Samw if (sr && sr->fid_ofile) { 11247619SJose.Borrego@Sun.COM sa_mask = set_attr->sa_mask; 11257619SJose.Borrego@Sun.COM access = 0; 11267619SJose.Borrego@Sun.COM 11277619SJose.Borrego@Sun.COM if (sa_mask & SMB_AT_SIZE) { 11287619SJose.Borrego@Sun.COM access |= FILE_WRITE_DATA; 11297619SJose.Borrego@Sun.COM sa_mask &= ~SMB_AT_SIZE; 11307619SJose.Borrego@Sun.COM } 11317619SJose.Borrego@Sun.COM 11327619SJose.Borrego@Sun.COM if (sa_mask & (SMB_AT_UID|SMB_AT_GID)) { 11335331Samw access |= WRITE_OWNER; 11347619SJose.Borrego@Sun.COM sa_mask &= ~(SMB_AT_UID|SMB_AT_GID); 11357619SJose.Borrego@Sun.COM } 11367619SJose.Borrego@Sun.COM 11377619SJose.Borrego@Sun.COM if (sa_mask) 11385331Samw access |= FILE_WRITE_ATTRIBUTES; 11395331Samw 11405331Samw status = smb_ofile_access(sr->fid_ofile, cr, access); 11415331Samw if (status != NT_STATUS_SUCCESS) 11425331Samw return (EACCES); 11435331Samw 11447348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, 11457348SJose.Borrego@Sun.COM SMB_TREE_ACEMASKONACCESS)) 11465331Samw flags = ATTR_NOACLCHECK; 11475331Samw } 11485331Samw 11495331Samw unnamed_node = SMB_IS_STREAM(snode); 11505331Samw 11515331Samw if (unnamed_node) { 11525331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 11535331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 11545331Samw unnamed_vp = unnamed_node->vp; 11555331Samw } 11567757SJanice.Chang@Sun.COM 11577757SJanice.Chang@Sun.COM rc = smb_vop_setattr(snode->vp, unnamed_vp, set_attr, flags, cr); 11585331Samw 11595331Samw if ((rc == 0) && ret_attr) { 11605331Samw /* 11615772Sas200622 * Use kcred to update the node attr because this 11625772Sas200622 * call is not being made on behalf of the user. 11635331Samw */ 11645331Samw ret_attr->sa_mask = SMB_AT_ALL; 11657348SJose.Borrego@Sun.COM rc = smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, flags, 11667348SJose.Borrego@Sun.COM kcred); 11675772Sas200622 if (rc == 0) 11685772Sas200622 snode->attr = *ret_attr; 11695331Samw } 11705331Samw 11715331Samw return (rc); 11725331Samw } 11735331Samw 11745331Samw /* 11755331Samw * smb_fsop_read 11765331Samw * 11775331Samw * All SMB functions should use this wrapper to ensure that 11785331Samw * the the calls are performed with the appropriate credentials. 11795331Samw * Please document any direct call to explain the reason 11805331Samw * for avoiding this wrapper. 11815331Samw * 11825331Samw * It is assumed that a reference exists on snode coming into this routine. 11835331Samw */ 11845331Samw int 11855331Samw smb_fsop_read( 11865331Samw struct smb_request *sr, 11875331Samw cred_t *cr, 11885331Samw smb_node_t *snode, 11895331Samw uio_t *uio, 11905331Samw smb_attr_t *ret_attr) 11915331Samw { 11925331Samw smb_node_t *unnamed_node; 11935331Samw vnode_t *unnamed_vp = NULL; 11947348SJose.Borrego@Sun.COM caller_context_t ct; 11955772Sas200622 int svmand; 11965331Samw int rc; 11975331Samw 11985331Samw ASSERT(cr); 11995331Samw ASSERT(snode); 12005331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 12015331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 12025331Samw 12035331Samw ASSERT(sr); 12045331Samw ASSERT(sr->fid_ofile); 12055331Samw 12065331Samw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_READ_DATA); 12075331Samw if (rc != NT_STATUS_SUCCESS) { 12085331Samw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_EXECUTE); 12095331Samw if (rc != NT_STATUS_SUCCESS) 12105331Samw return (EACCES); 12115331Samw } 12125331Samw 12135331Samw unnamed_node = SMB_IS_STREAM(snode); 12145331Samw if (unnamed_node) { 12155331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 12165331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 12175331Samw unnamed_vp = unnamed_node->vp; 12185331Samw /* 12195331Samw * Streams permission are checked against the unnamed stream, 12205331Samw * but in FS level they have their own permissions. To avoid 12215331Samw * rejection by FS due to lack of permission on the actual 12225331Samw * extended attr kcred is passed for streams. 12235331Samw */ 12245331Samw cr = kcred; 12255331Samw } 12265331Samw 12275772Sas200622 smb_node_start_crit(snode, RW_READER); 12287348SJose.Borrego@Sun.COM rc = nbl_svmand(snode->vp, kcred, &svmand); 12295772Sas200622 if (rc) { 12305772Sas200622 smb_node_end_crit(snode); 12315772Sas200622 return (rc); 12325772Sas200622 } 12335772Sas200622 12347348SJose.Borrego@Sun.COM ct = smb_ct; 12357348SJose.Borrego@Sun.COM ct.cc_pid = sr->fid_ofile->f_uniqid; 12365772Sas200622 rc = nbl_lock_conflict(snode->vp, NBL_READ, uio->uio_loffset, 12377348SJose.Borrego@Sun.COM uio->uio_iov->iov_len, svmand, &ct); 12385772Sas200622 12395772Sas200622 if (rc) { 12405772Sas200622 smb_node_end_crit(snode); 12416432Sas200622 return (ERANGE); 12425772Sas200622 } 12435772Sas200622 rc = smb_vop_read(snode->vp, uio, cr); 12445772Sas200622 12455772Sas200622 if (rc == 0 && ret_attr) { 12465331Samw /* 12475772Sas200622 * Use kcred to update the node attr because this 12485772Sas200622 * call is not being made on behalf of the user. 12495331Samw */ 12505331Samw ret_attr->sa_mask = SMB_AT_ALL; 12515772Sas200622 if (smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0, 12525772Sas200622 kcred) == 0) { 12535772Sas200622 snode->attr = *ret_attr; 12545772Sas200622 } 12555331Samw } 12565331Samw 12575772Sas200622 smb_node_end_crit(snode); 12585772Sas200622 12595331Samw return (rc); 12605331Samw } 12615331Samw 12625331Samw /* 12635331Samw * smb_fsop_write 12645331Samw * 12655331Samw * This is a wrapper function used for smb_write and smb_write_raw operations. 12665331Samw * 12675331Samw * It is assumed that a reference exists on snode coming into this routine. 12685331Samw */ 12695331Samw int 12705331Samw smb_fsop_write( 12716139Sjb150015 smb_request_t *sr, 12725331Samw cred_t *cr, 12735331Samw smb_node_t *snode, 12745331Samw uio_t *uio, 12755331Samw uint32_t *lcount, 12765331Samw smb_attr_t *ret_attr, 12777052Samw int ioflag) 12785331Samw { 12795331Samw smb_node_t *unnamed_node; 12805331Samw vnode_t *unnamed_vp = NULL; 12817348SJose.Borrego@Sun.COM caller_context_t ct; 12825772Sas200622 int svmand; 12835331Samw int rc; 12845331Samw 12855331Samw ASSERT(cr); 12865331Samw ASSERT(snode); 12875331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 12885331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 12895331Samw 12905331Samw ASSERT(sr); 12915331Samw ASSERT(sr->tid_tree); 12925331Samw ASSERT(sr->fid_ofile); 12935331Samw 12947348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 12955331Samw return (EROFS); 12965772Sas200622 12977348SJose.Borrego@Sun.COM if (SMB_OFILE_IS_READONLY(sr->fid_ofile)) 12987348SJose.Borrego@Sun.COM return (EACCES); 12997348SJose.Borrego@Sun.COM 13005331Samw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_WRITE_DATA); 13015772Sas200622 if (rc != NT_STATUS_SUCCESS) { 13025772Sas200622 rc = smb_ofile_access(sr->fid_ofile, cr, FILE_APPEND_DATA); 13035772Sas200622 if (rc != NT_STATUS_SUCCESS) 13045772Sas200622 return (EACCES); 13055772Sas200622 } 13065331Samw 13075331Samw unnamed_node = SMB_IS_STREAM(snode); 13085331Samw 13095331Samw if (unnamed_node) { 13105331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 13115331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 13125331Samw unnamed_vp = unnamed_node->vp; 13135331Samw /* 13145331Samw * Streams permission are checked against the unnamed stream, 13155331Samw * but in FS level they have their own permissions. To avoid 13165331Samw * rejection by FS due to lack of permission on the actual 13175331Samw * extended attr kcred is passed for streams. 13185331Samw */ 13195331Samw cr = kcred; 13205331Samw } 13215331Samw 13225772Sas200622 smb_node_start_crit(snode, RW_READER); 13237348SJose.Borrego@Sun.COM rc = nbl_svmand(snode->vp, kcred, &svmand); 13245772Sas200622 if (rc) { 13255772Sas200622 smb_node_end_crit(snode); 13265772Sas200622 return (rc); 13275772Sas200622 } 13287348SJose.Borrego@Sun.COM 13297348SJose.Borrego@Sun.COM ct = smb_ct; 13307348SJose.Borrego@Sun.COM ct.cc_pid = sr->fid_ofile->f_uniqid; 13315772Sas200622 rc = nbl_lock_conflict(snode->vp, NBL_WRITE, uio->uio_loffset, 13327348SJose.Borrego@Sun.COM uio->uio_iov->iov_len, svmand, &ct); 13335772Sas200622 13345772Sas200622 if (rc) { 13355772Sas200622 smb_node_end_crit(snode); 13366432Sas200622 return (ERANGE); 13375772Sas200622 } 13387052Samw rc = smb_vop_write(snode->vp, uio, ioflag, lcount, cr); 13395772Sas200622 13405772Sas200622 if (rc == 0 && ret_attr) { 13415331Samw /* 13425772Sas200622 * Use kcred to update the node attr because this 13435772Sas200622 * call is not being made on behalf of the user. 13445331Samw */ 13455331Samw ret_attr->sa_mask = SMB_AT_ALL; 13465772Sas200622 if (smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0, 13475772Sas200622 kcred) == 0) { 13485772Sas200622 snode->attr = *ret_attr; 13495772Sas200622 } 13505331Samw } 13515331Samw 13525772Sas200622 smb_node_end_crit(snode); 13535772Sas200622 13545331Samw return (rc); 13555331Samw } 13565331Samw 13575331Samw /* 13585331Samw * smb_fsop_statfs 13595331Samw * 13605331Samw * This is a wrapper function used for stat operations. 13615331Samw */ 13625331Samw int 13635331Samw smb_fsop_statfs( 13645331Samw cred_t *cr, 13655331Samw smb_node_t *snode, 13665331Samw struct statvfs64 *statp) 13675331Samw { 13685331Samw ASSERT(cr); 13695331Samw ASSERT(snode); 13705331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 13715331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 13725331Samw 13735331Samw return (smb_vop_statfs(snode->vp, statp, cr)); 13745331Samw } 13755331Samw 13765331Samw /* 13775331Samw * smb_fsop_access 13786700Sjm199354 * 13796700Sjm199354 * Named streams do not have separate permissions from the associated 13806700Sjm199354 * unnamed stream. Thus, if node is a named stream, the permissions 13816700Sjm199354 * check will be performed on the associated unnamed stream. 13826700Sjm199354 * 13836700Sjm199354 * However, our named streams do have their own quarantine attribute, 13846700Sjm199354 * separate from that on the unnamed stream. If READ or EXECUTE 13856700Sjm199354 * access has been requested on a named stream, an additional access 13866700Sjm199354 * check is performed on the named stream in case it has been 13876700Sjm199354 * quarantined. kcred is used to avoid issues with the permissions 13886700Sjm199354 * set on the extended attribute file representing the named stream. 13895331Samw */ 13905331Samw int 13915331Samw smb_fsop_access(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 13925331Samw uint32_t faccess) 13935331Samw { 13945331Samw int access = 0; 13955331Samw int error; 13965331Samw vnode_t *dir_vp; 13975331Samw boolean_t acl_check = B_TRUE; 13985331Samw smb_node_t *unnamed_node; 13995331Samw 14007348SJose.Borrego@Sun.COM ASSERT(sr); 14015331Samw ASSERT(cr); 14025331Samw ASSERT(snode); 14035331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 14045331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 14055331Samw 14065331Samw if (faccess == 0) 14075331Samw return (NT_STATUS_SUCCESS); 14085331Samw 14097348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) { 14105331Samw if (faccess & (FILE_WRITE_DATA|FILE_APPEND_DATA| 14115331Samw FILE_WRITE_EA|FILE_DELETE_CHILD|FILE_WRITE_ATTRIBUTES| 14125331Samw DELETE|WRITE_DAC|WRITE_OWNER)) { 14135331Samw return (NT_STATUS_ACCESS_DENIED); 14145331Samw } 14155331Samw } 14165331Samw 14175331Samw unnamed_node = SMB_IS_STREAM(snode); 14185331Samw if (unnamed_node) { 14195331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 14205331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 14216700Sjm199354 14226700Sjm199354 /* 14236700Sjm199354 * Perform VREAD access check on the named stream in case it 14246700Sjm199354 * is quarantined. kcred is passed to smb_vop_access so it 14256700Sjm199354 * doesn't fail due to lack of permission. 14266700Sjm199354 */ 14276700Sjm199354 if (faccess & (FILE_READ_DATA | FILE_EXECUTE)) { 14286700Sjm199354 error = smb_vop_access(snode->vp, VREAD, 14296700Sjm199354 0, NULL, kcred); 14306700Sjm199354 if (error) 14316700Sjm199354 return (NT_STATUS_ACCESS_DENIED); 14326700Sjm199354 } 14336700Sjm199354 14345331Samw /* 14355331Samw * Streams authorization should be performed against the 14365331Samw * unnamed stream. 14375331Samw */ 14385331Samw snode = unnamed_node; 14395331Samw } 14405331Samw 14415331Samw if (faccess & ACCESS_SYSTEM_SECURITY) { 14425331Samw /* 14435331Samw * This permission is required for reading/writing SACL and 14445331Samw * it's not part of DACL. It's only granted via proper 14455331Samw * privileges. 14465331Samw */ 14475331Samw if ((sr->uid_user->u_privileges & 14485331Samw (SMB_USER_PRIV_BACKUP | 14495331Samw SMB_USER_PRIV_RESTORE | 14505331Samw SMB_USER_PRIV_SECURITY)) == 0) 14515331Samw return (NT_STATUS_PRIVILEGE_NOT_HELD); 14525331Samw 14535331Samw faccess &= ~ACCESS_SYSTEM_SECURITY; 14545331Samw } 14555331Samw 14565331Samw /* Links don't have ACL */ 14577348SJose.Borrego@Sun.COM if ((!smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) || 14585331Samw (snode->attr.sa_vattr.va_type == VLNK)) 14595331Samw acl_check = B_FALSE; 14605331Samw 14615331Samw if (acl_check) { 14625331Samw dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL; 14635331Samw error = smb_vop_access(snode->vp, faccess, V_ACE_MASK, dir_vp, 14645331Samw cr); 14655331Samw } else { 14665331Samw /* 14675331Samw * FS doesn't understand 32-bit mask, need to map 14685331Samw */ 14695331Samw if (faccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) 14705331Samw access |= VWRITE; 14715331Samw 14725331Samw if (faccess & FILE_READ_DATA) 14735331Samw access |= VREAD; 14745331Samw 14755331Samw if (faccess & FILE_EXECUTE) 14765331Samw access |= VEXEC; 14775331Samw 14785331Samw error = smb_vop_access(snode->vp, access, 0, NULL, cr); 14795331Samw } 14805331Samw 14815331Samw return ((error) ? NT_STATUS_ACCESS_DENIED : NT_STATUS_SUCCESS); 14825331Samw } 14835331Samw 14845331Samw /* 14855331Samw * smb_fsop_lookup_name() 14865331Samw * 14877961SNatalie.Li@Sun.COM * If name indicates that the file is a stream file, perform 14887961SNatalie.Li@Sun.COM * stream specific lookup, otherwise call smb_fsop_lookup. 14895331Samw * 14907961SNatalie.Li@Sun.COM * Return an error if the looked-up file is in outside the tree. 14917961SNatalie.Li@Sun.COM * (Required when invoked from open path.) 14925331Samw */ 14935331Samw 14945331Samw int 14955331Samw smb_fsop_lookup_name( 14966139Sjb150015 smb_request_t *sr, 14975331Samw cred_t *cr, 14985331Samw int flags, 14995331Samw smb_node_t *root_node, 15005331Samw smb_node_t *dir_snode, 15015331Samw char *name, 15025331Samw smb_node_t **ret_snode, 15035331Samw smb_attr_t *ret_attr) 15045331Samw { 15056139Sjb150015 smb_node_t *fnode; 15066139Sjb150015 smb_attr_t file_attr; 15076139Sjb150015 vnode_t *xattrdirvp; 15086139Sjb150015 vnode_t *vp; 15096139Sjb150015 char *od_name; 15106139Sjb150015 char *fname; 15116139Sjb150015 char *sname; 15126139Sjb150015 int rc; 15135331Samw 15145331Samw ASSERT(cr); 15155331Samw ASSERT(dir_snode); 15165331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 15175331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 15185331Samw 15195331Samw /* 15205331Samw * The following check is required for streams processing, below 15215331Samw */ 15225331Samw 15237348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 15245331Samw flags |= SMB_IGNORE_CASE; 15255331Samw 15265331Samw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 15275331Samw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 15285331Samw 15298334SJose.Borrego@Sun.COM if ((rc = smb_stream_parse_name(name, fname, sname)) != 0) { 15308334SJose.Borrego@Sun.COM if (rc == -1) { 15318334SJose.Borrego@Sun.COM kmem_free(fname, MAXNAMELEN); 15328334SJose.Borrego@Sun.COM kmem_free(sname, MAXNAMELEN); 15338334SJose.Borrego@Sun.COM return (EINVAL); 15348334SJose.Borrego@Sun.COM } 15358334SJose.Borrego@Sun.COM 15365331Samw /* 15375331Samw * Look up the unnamed stream (i.e. fname). 15385331Samw * Unmangle processing will be done on fname 15395331Samw * as well as any link target. 15405331Samw */ 15415331Samw rc = smb_fsop_lookup(sr, cr, flags, root_node, dir_snode, fname, 15425331Samw &fnode, &file_attr, NULL, NULL); 15435331Samw 15445331Samw if (rc != 0) { 15455331Samw kmem_free(fname, MAXNAMELEN); 15465331Samw kmem_free(sname, MAXNAMELEN); 15475331Samw return (rc); 15485331Samw } 15495331Samw 15505331Samw od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 15515331Samw 15525331Samw /* 15535331Samw * od_name is the on-disk name of the stream, except 15545331Samw * without the prepended stream prefix (SMB_STREAM_PREFIX) 15555331Samw */ 15565331Samw 15575331Samw /* 15585331Samw * XXX 15595331Samw * What permissions NTFS requires for stream lookup if any? 15605331Samw */ 15615331Samw rc = smb_vop_stream_lookup(fnode->vp, sname, &vp, od_name, 15625772Sas200622 &xattrdirvp, flags, root_node->vp, cr); 15635331Samw 15645331Samw if (rc != 0) { 15655331Samw smb_node_release(fnode); 15665331Samw kmem_free(fname, MAXNAMELEN); 15675331Samw kmem_free(sname, MAXNAMELEN); 15685331Samw kmem_free(od_name, MAXNAMELEN); 15695331Samw return (rc); 15705331Samw } 15715331Samw 15725331Samw *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, 15735331Samw vp, od_name, ret_attr); 15745331Samw 15755331Samw kmem_free(od_name, MAXNAMELEN); 15765331Samw smb_node_release(fnode); 1577*8670SJose.Borrego@Sun.COM VN_RELE(xattrdirvp); 1578*8670SJose.Borrego@Sun.COM VN_RELE(vp); 15795331Samw 15805331Samw if (*ret_snode == NULL) { 15815331Samw kmem_free(fname, MAXNAMELEN); 15825331Samw kmem_free(sname, MAXNAMELEN); 15835331Samw return (ENOMEM); 15845331Samw } 15855331Samw } else { 15865331Samw rc = smb_fsop_lookup(sr, cr, flags, root_node, dir_snode, name, 15875331Samw ret_snode, ret_attr, NULL, NULL); 15885331Samw } 15895331Samw 15905331Samw if (rc == 0) { 15915331Samw ASSERT(ret_snode); 15927348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, *ret_snode) == 0) { 15935331Samw smb_node_release(*ret_snode); 15945331Samw *ret_snode = NULL; 15955331Samw rc = EACCES; 15965331Samw } 15975331Samw } 15985331Samw 15995331Samw kmem_free(fname, MAXNAMELEN); 16005331Samw kmem_free(sname, MAXNAMELEN); 16015331Samw 16025331Samw return (rc); 16035331Samw } 16045331Samw 16055331Samw /* 16065331Samw * smb_fsop_lookup 16075331Samw * 16085331Samw * All SMB functions should use this smb_vop_lookup wrapper to ensure that 16095331Samw * the smb_vop_lookup is performed with the appropriate credentials and using 16105331Samw * case insensitive compares. Please document any direct call to smb_vop_lookup 16115331Samw * to explain the reason for avoiding this wrapper. 16125331Samw * 16135331Samw * It is assumed that a reference exists on dir_snode coming into this routine 16145331Samw * (and that it is safe from deallocation). 16155331Samw * 16165331Samw * Same with the root_node. 16175331Samw * 16185331Samw * *ret_snode is returned with a reference upon success. No reference is 16195331Samw * taken if an error is returned. 16205331Samw * 16215331Samw * Note: The returned ret_snode may be in a child mount. This is ok for 1622*8670SJose.Borrego@Sun.COM * readdir. 16235331Samw * 16247348SJose.Borrego@Sun.COM * ret_shortname and ret_name83 must each point to buffers of at least 16257348SJose.Borrego@Sun.COM * SMB_SHORTNAMELEN bytes. 16267348SJose.Borrego@Sun.COM * 16277348SJose.Borrego@Sun.COM * Other smb_fsop_* routines will call SMB_TREE_CONTAINS_NODE() to prevent 16285331Samw * operations on files not in the parent mount. 16295331Samw */ 16305331Samw int 16315331Samw smb_fsop_lookup( 16326139Sjb150015 smb_request_t *sr, 16335331Samw cred_t *cr, 16345331Samw int flags, 16355331Samw smb_node_t *root_node, 16365331Samw smb_node_t *dir_snode, 16375331Samw char *name, 16385331Samw smb_node_t **ret_snode, 16395331Samw smb_attr_t *ret_attr, 16407348SJose.Borrego@Sun.COM char *ret_shortname, 16417348SJose.Borrego@Sun.COM char *ret_name83) 16425331Samw { 16435331Samw smb_node_t *lnk_target_node; 16445331Samw smb_node_t *lnk_dnode; 16455331Samw char *longname; 16465331Samw char *od_name; 16475331Samw vnode_t *vp; 16485331Samw int rc; 16495331Samw 16505331Samw ASSERT(cr); 16515331Samw ASSERT(dir_snode); 16525331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 16535331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 16545331Samw 16555331Samw if (name == NULL) 16565331Samw return (EINVAL); 16575331Samw 16587348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 16595331Samw return (EACCES); 16605331Samw 16617348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 16625331Samw flags |= SMB_IGNORE_CASE; 16635331Samw 16645331Samw od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 16655331Samw 16665331Samw rc = smb_vop_lookup(dir_snode->vp, name, &vp, od_name, flags, 16675772Sas200622 root_node ? root_node->vp : NULL, cr); 16685331Samw 16695331Samw if (rc != 0) { 16705331Samw if (smb_maybe_mangled_name(name) == 0) { 16715331Samw kmem_free(od_name, MAXNAMELEN); 16725331Samw return (rc); 16735331Samw } 16745331Samw 16755331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 16765331Samw 16775331Samw rc = smb_unmangle_name(sr, cr, dir_snode, name, longname, 16785331Samw MAXNAMELEN, ret_shortname, ret_name83, 1); 16795331Samw 16805331Samw if (rc != 0) { 16815331Samw kmem_free(od_name, MAXNAMELEN); 16825331Samw kmem_free(longname, MAXNAMELEN); 16835331Samw return (rc); 16845331Samw } 16855331Samw 16865331Samw /* 16875331Samw * We passed "1" as the "od" parameter 16885331Samw * to smb_unmangle_name(), such that longname 16895331Samw * is the real (case-sensitive) on-disk name. 16905331Samw * We make sure we do a lookup on this exact 16915331Samw * name, as the name was mangled and denotes 16925331Samw * a unique file. 16935331Samw */ 16945331Samw 16955331Samw if (flags & SMB_IGNORE_CASE) 16965331Samw flags &= ~SMB_IGNORE_CASE; 16975331Samw 16985331Samw rc = smb_vop_lookup(dir_snode->vp, longname, &vp, od_name, 16995772Sas200622 flags, root_node ? root_node->vp : NULL, cr); 17005331Samw 17015331Samw kmem_free(longname, MAXNAMELEN); 17025331Samw 17035331Samw if (rc != 0) { 17045331Samw kmem_free(od_name, MAXNAMELEN); 17055331Samw return (rc); 17065331Samw } 17075331Samw } 17085331Samw 17095331Samw if ((flags & SMB_FOLLOW_LINKS) && (vp->v_type == VLNK)) { 17105331Samw 17115331Samw rc = smb_pathname(sr, od_name, FOLLOW, root_node, dir_snode, 17125331Samw &lnk_dnode, &lnk_target_node, cr); 17135331Samw 17145331Samw if (rc != 0) { 17155331Samw /* 17165331Samw * The link is assumed to be for the last component 17175331Samw * of a path. Hence any ENOTDIR error will be returned 17185331Samw * as ENOENT. 17195331Samw */ 17205331Samw if (rc == ENOTDIR) 17215331Samw rc = ENOENT; 17225331Samw 17235331Samw VN_RELE(vp); 17245331Samw kmem_free(od_name, MAXNAMELEN); 17255331Samw return (rc); 17265331Samw } 17275331Samw 17285331Samw /* 17295331Samw * Release the original VLNK vnode 17305331Samw */ 17315331Samw 17325331Samw VN_RELE(vp); 17335331Samw vp = lnk_target_node->vp; 17345331Samw 17355331Samw rc = smb_vop_traverse_check(&vp); 17365331Samw 17375331Samw if (rc != 0) { 17385331Samw smb_node_release(lnk_dnode); 17395331Samw smb_node_release(lnk_target_node); 17405331Samw kmem_free(od_name, MAXNAMELEN); 17415331Samw return (rc); 17425331Samw } 17435331Samw 17445331Samw /* 17455331Samw * smb_vop_traverse_check() may have returned a different vnode 17465331Samw */ 17475331Samw 17485331Samw if (lnk_target_node->vp == vp) { 17495331Samw *ret_snode = lnk_target_node; 17505331Samw *ret_attr = (*ret_snode)->attr; 17515331Samw } else { 17525331Samw *ret_snode = smb_node_lookup(sr, NULL, cr, vp, 17535331Samw lnk_target_node->od_name, lnk_dnode, NULL, 17545331Samw ret_attr); 1755*8670SJose.Borrego@Sun.COM VN_RELE(vp); 17565331Samw 1757*8670SJose.Borrego@Sun.COM if (*ret_snode == NULL) 17585331Samw rc = ENOMEM; 17595331Samw smb_node_release(lnk_target_node); 17605331Samw } 17615331Samw 17625331Samw smb_node_release(lnk_dnode); 17635331Samw 17645331Samw } else { 17655331Samw 17665331Samw rc = smb_vop_traverse_check(&vp); 17675331Samw if (rc) { 17685331Samw VN_RELE(vp); 17695331Samw kmem_free(od_name, MAXNAMELEN); 17705331Samw return (rc); 17715331Samw } 17725331Samw 17735331Samw *ret_snode = smb_node_lookup(sr, NULL, cr, vp, od_name, 17745331Samw dir_snode, NULL, ret_attr); 1775*8670SJose.Borrego@Sun.COM VN_RELE(vp); 17765331Samw 1777*8670SJose.Borrego@Sun.COM if (*ret_snode == NULL) 17785331Samw rc = ENOMEM; 17795331Samw } 17805331Samw 17815331Samw kmem_free(od_name, MAXNAMELEN); 17825331Samw return (rc); 17835331Samw } 17845331Samw 17855331Samw int /*ARGSUSED*/ 17865331Samw smb_fsop_commit(smb_request_t *sr, cred_t *cr, smb_node_t *snode) 17875331Samw { 17885331Samw ASSERT(cr); 17895331Samw ASSERT(snode); 17905331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 17915331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 17925331Samw 17935331Samw ASSERT(sr); 17945331Samw ASSERT(sr->tid_tree); 17957348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 17965331Samw return (EROFS); 17975331Samw 17985772Sas200622 return (smb_vop_commit(snode->vp, cr)); 17995331Samw } 18005331Samw 18015331Samw /* 18025331Samw * smb_fsop_aclread 18035331Samw * 18045331Samw * Retrieve filesystem ACL. Depends on requested ACLs in 18055331Samw * fs_sd->sd_secinfo, it'll set DACL and SACL pointers in 18065331Samw * fs_sd. Note that requesting a DACL/SACL doesn't mean that 18075331Samw * the corresponding field in fs_sd should be non-NULL upon 18085331Samw * return, since the target ACL might not contain that type of 18095331Samw * entries. 18105331Samw * 18115331Samw * Returned ACL is always in ACE_T (aka ZFS) format. 18125331Samw * If successful the allocated memory for the ACL should be freed 18135521Sas200622 * using smb_fsacl_free() or smb_fssd_term() 18145331Samw */ 18155331Samw int 18165331Samw smb_fsop_aclread(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 18175331Samw smb_fssd_t *fs_sd) 18185331Samw { 18195331Samw int error = 0; 18205331Samw int flags = 0; 18215331Samw int access = 0; 18225331Samw acl_t *acl; 18235331Samw smb_node_t *unnamed_node; 18245331Samw 18255331Samw ASSERT(cr); 18265331Samw 18275331Samw if (sr->fid_ofile) { 18285331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 18295331Samw access = READ_CONTROL; 18305331Samw 18315331Samw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 18325331Samw access |= ACCESS_SYSTEM_SECURITY; 18335331Samw 18345331Samw error = smb_ofile_access(sr->fid_ofile, cr, access); 18355331Samw if (error != NT_STATUS_SUCCESS) { 18365331Samw return (EACCES); 18375331Samw } 18385331Samw } 18395331Samw 18405331Samw unnamed_node = SMB_IS_STREAM(snode); 18415331Samw if (unnamed_node) { 18425331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 18435331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 18445331Samw /* 18455331Samw * Streams don't have ACL, any read ACL attempt on a stream 18465331Samw * should be performed on the unnamed stream. 18475331Samw */ 18485331Samw snode = unnamed_node; 18495331Samw } 18505331Samw 18517348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) 18525331Samw flags = ATTR_NOACLCHECK; 18535331Samw 18545331Samw error = smb_vop_acl_read(snode->vp, &acl, flags, 18555772Sas200622 sr->tid_tree->t_acltype, cr); 18565331Samw if (error != 0) { 18575331Samw return (error); 18585331Samw } 18595331Samw 18605331Samw error = acl_translate(acl, _ACL_ACE_ENABLED, 18615331Samw (snode->vp->v_type == VDIR), fs_sd->sd_uid, fs_sd->sd_gid); 18625331Samw 18635331Samw if (error == 0) { 18645521Sas200622 smb_fsacl_split(acl, &fs_sd->sd_zdacl, &fs_sd->sd_zsacl, 18655331Samw fs_sd->sd_secinfo); 18665331Samw } 18675331Samw 18685331Samw acl_free(acl); 18695331Samw return (error); 18705331Samw } 18715331Samw 18725331Samw /* 18735331Samw * smb_fsop_aclwrite 18745331Samw * 18755331Samw * Stores the filesystem ACL provided in fs_sd->sd_acl. 18765331Samw */ 18775331Samw int 18785331Samw smb_fsop_aclwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 18795331Samw smb_fssd_t *fs_sd) 18805331Samw { 18815331Samw int target_flavor; 18825331Samw int error = 0; 18835331Samw int flags = 0; 18845331Samw int access = 0; 18855331Samw acl_t *acl, *dacl, *sacl; 18865331Samw smb_node_t *unnamed_node; 18875331Samw 18885331Samw ASSERT(cr); 18895331Samw 18905331Samw ASSERT(sr); 18915331Samw ASSERT(sr->tid_tree); 18927348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 18935331Samw return (EROFS); 18945331Samw 18955331Samw if (sr->fid_ofile) { 18965331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 18975331Samw access = WRITE_DAC; 18985331Samw 18995331Samw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 19005331Samw access |= ACCESS_SYSTEM_SECURITY; 19015331Samw 19025331Samw error = smb_ofile_access(sr->fid_ofile, cr, access); 19035331Samw if (error != NT_STATUS_SUCCESS) 19045331Samw return (EACCES); 19055331Samw } 19065331Samw 19075331Samw switch (sr->tid_tree->t_acltype) { 19085331Samw case ACLENT_T: 19095331Samw target_flavor = _ACL_ACLENT_ENABLED; 19105331Samw break; 19115331Samw 19125331Samw case ACE_T: 19135331Samw target_flavor = _ACL_ACE_ENABLED; 19145331Samw break; 19155331Samw default: 19165331Samw return (EINVAL); 19175331Samw } 19185331Samw 19195331Samw unnamed_node = SMB_IS_STREAM(snode); 19205331Samw if (unnamed_node) { 19215331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 19225331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 19235331Samw /* 19245331Samw * Streams don't have ACL, any write ACL attempt on a stream 19255331Samw * should be performed on the unnamed stream. 19265331Samw */ 19275331Samw snode = unnamed_node; 19285331Samw } 19295331Samw 19305331Samw dacl = fs_sd->sd_zdacl; 19315331Samw sacl = fs_sd->sd_zsacl; 19325331Samw 19335331Samw ASSERT(dacl || sacl); 19345331Samw if ((dacl == NULL) && (sacl == NULL)) 19355331Samw return (EINVAL); 19365331Samw 19375331Samw if (dacl && sacl) 19385521Sas200622 acl = smb_fsacl_merge(dacl, sacl); 19395331Samw else if (dacl) 19405331Samw acl = dacl; 19415331Samw else 19425331Samw acl = sacl; 19435331Samw 19445331Samw error = acl_translate(acl, target_flavor, (snode->vp->v_type == VDIR), 19455331Samw fs_sd->sd_uid, fs_sd->sd_gid); 19465331Samw if (error == 0) { 19477348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, 19487348SJose.Borrego@Sun.COM SMB_TREE_ACEMASKONACCESS)) 19495331Samw flags = ATTR_NOACLCHECK; 19505331Samw 19515772Sas200622 error = smb_vop_acl_write(snode->vp, acl, flags, cr); 19525331Samw } 19535331Samw 19545331Samw if (dacl && sacl) 19555331Samw acl_free(acl); 19565331Samw 19575331Samw return (error); 19585331Samw } 19595331Samw 19605331Samw acl_type_t 19615331Samw smb_fsop_acltype(smb_node_t *snode) 19625331Samw { 19635331Samw return (smb_vop_acl_type(snode->vp)); 19645331Samw } 19655331Samw 19665331Samw /* 19675331Samw * smb_fsop_sdread 19685331Samw * 19695331Samw * Read the requested security descriptor items from filesystem. 19705331Samw * The items are specified in fs_sd->sd_secinfo. 19715331Samw */ 19725331Samw int 19735331Samw smb_fsop_sdread(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 19745331Samw smb_fssd_t *fs_sd) 19755331Samw { 19765331Samw int error = 0; 19775331Samw int getowner = 0; 19785331Samw cred_t *ga_cred; 19795331Samw smb_attr_t attr; 19805331Samw 19815331Samw ASSERT(cr); 19825331Samw ASSERT(fs_sd); 19835331Samw 19845331Samw /* 19855331Samw * File's uid/gid is fetched in two cases: 19865331Samw * 19875331Samw * 1. it's explicitly requested 19885331Samw * 19895331Samw * 2. target ACL is ACE_T (ZFS ACL). They're needed for 19905331Samw * owner@/group@ entries. In this case kcred should be used 19915331Samw * because uid/gid are fetched on behalf of smb server. 19925331Samw */ 19935331Samw if (fs_sd->sd_secinfo & (SMB_OWNER_SECINFO | SMB_GROUP_SECINFO)) { 19945331Samw getowner = 1; 19955331Samw ga_cred = cr; 19965331Samw } else if (sr->tid_tree->t_acltype == ACE_T) { 19975331Samw getowner = 1; 19985331Samw ga_cred = kcred; 19995331Samw } 20005331Samw 20015331Samw if (getowner) { 20025331Samw /* 20035331Samw * Windows require READ_CONTROL to read owner/group SID since 20045331Samw * they're part of Security Descriptor. 20055331Samw * ZFS only requires read_attribute. Need to have a explicit 20065331Samw * access check here. 20075331Samw */ 20085331Samw if (sr->fid_ofile == NULL) { 20095331Samw error = smb_fsop_access(sr, ga_cred, snode, 20105331Samw READ_CONTROL); 20115331Samw if (error) 20125331Samw return (error); 20135331Samw } 20145331Samw 20155331Samw attr.sa_mask = SMB_AT_UID | SMB_AT_GID; 20165331Samw error = smb_fsop_getattr(sr, ga_cred, snode, &attr); 20175331Samw if (error == 0) { 20185331Samw fs_sd->sd_uid = attr.sa_vattr.va_uid; 20195331Samw fs_sd->sd_gid = attr.sa_vattr.va_gid; 20205331Samw } else { 20215331Samw return (error); 20225331Samw } 20235331Samw } 20245331Samw 20255331Samw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 20265331Samw error = smb_fsop_aclread(sr, cr, snode, fs_sd); 20275331Samw } 20285331Samw 20295331Samw return (error); 20305331Samw } 20315331Samw 20325331Samw /* 20335331Samw * smb_fsop_sdmerge 20345331Samw * 20355331Samw * From SMB point of view DACL and SACL are two separate list 20365331Samw * which can be manipulated independently without one affecting 20375331Samw * the other, but entries for both DACL and SACL will end up 20385331Samw * in the same ACL if target filesystem supports ACE_T ACLs. 20395331Samw * 20405331Samw * So, if either DACL or SACL is present in the client set request 20415331Samw * the entries corresponding to the non-present ACL shouldn't 20425331Samw * be touched in the FS ACL. 20435331Samw * 20445331Samw * fs_sd parameter contains DACL and SACL specified by SMB 20455331Samw * client to be set on a file/directory. The client could 20465331Samw * specify both or one of these ACLs (if none is specified 20475331Samw * we don't get this far). When both DACL and SACL are given 20485331Samw * by client the existing ACL should be overwritten. If only 20495331Samw * one of them is specified the entries corresponding to the other 20505331Samw * ACL should not be touched. For example, if only DACL 20515331Samw * is specified in input fs_sd, the function reads audit entries 20525331Samw * of the existing ACL of the file and point fs_sd->sd_zsdacl 20535331Samw * pointer to the fetched SACL, this way when smb_fsop_sdwrite() 20545331Samw * function is called the passed fs_sd would point to the specified 20555331Samw * DACL by client and fetched SACL from filesystem, so the file 20565331Samw * will end up with correct ACL. 20575331Samw */ 20585331Samw static int 20595331Samw smb_fsop_sdmerge(smb_request_t *sr, smb_node_t *snode, smb_fssd_t *fs_sd) 20605331Samw { 20615331Samw smb_fssd_t cur_sd; 20625331Samw int error = 0; 20635331Samw 20645331Samw if (sr->tid_tree->t_acltype != ACE_T) 20655331Samw /* Don't bother if target FS doesn't support ACE_T */ 20665331Samw return (0); 20675331Samw 20685331Samw if ((fs_sd->sd_secinfo & SMB_ACL_SECINFO) != SMB_ACL_SECINFO) { 20695331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) { 20705331Samw /* 20715331Samw * Don't overwrite existing audit entries 20725331Samw */ 20735521Sas200622 smb_fssd_init(&cur_sd, SMB_SACL_SECINFO, 20745331Samw fs_sd->sd_flags); 20755331Samw 20765331Samw error = smb_fsop_sdread(sr, kcred, snode, &cur_sd); 20775331Samw if (error == 0) { 20785331Samw ASSERT(fs_sd->sd_zsacl == NULL); 20795331Samw fs_sd->sd_zsacl = cur_sd.sd_zsacl; 20805331Samw if (fs_sd->sd_zsacl && fs_sd->sd_zdacl) 20815331Samw fs_sd->sd_zsacl->acl_flags = 20825331Samw fs_sd->sd_zdacl->acl_flags; 20835331Samw } 20845331Samw } else { 20855331Samw /* 20865331Samw * Don't overwrite existing access entries 20875331Samw */ 20885521Sas200622 smb_fssd_init(&cur_sd, SMB_DACL_SECINFO, 20895331Samw fs_sd->sd_flags); 20905331Samw 20915331Samw error = smb_fsop_sdread(sr, kcred, snode, &cur_sd); 20925331Samw if (error == 0) { 20935331Samw ASSERT(fs_sd->sd_zdacl == NULL); 20945331Samw fs_sd->sd_zdacl = cur_sd.sd_zdacl; 20955331Samw if (fs_sd->sd_zdacl && fs_sd->sd_zsacl) 20965331Samw fs_sd->sd_zdacl->acl_flags = 20975331Samw fs_sd->sd_zsacl->acl_flags; 20985331Samw } 20995331Samw } 21005331Samw 21015331Samw if (error) 21025521Sas200622 smb_fssd_term(&cur_sd); 21035331Samw } 21045331Samw 21055331Samw return (error); 21065331Samw } 21075331Samw 21085331Samw /* 21095331Samw * smb_fsop_sdwrite 21105331Samw * 21115331Samw * Stores the given uid, gid and acl in filesystem. 21125331Samw * Provided items in fs_sd are specified by fs_sd->sd_secinfo. 21135331Samw * 21145331Samw * A SMB security descriptor could contain owner, primary group, 21155331Samw * DACL and SACL. Setting an SD should be atomic but here it has to 21165331Samw * be done via two separate FS operations: VOP_SETATTR and 21175331Samw * VOP_SETSECATTR. Therefore, this function has to simulate the 21185331Samw * atomicity as well as it can. 21197619SJose.Borrego@Sun.COM * 21207619SJose.Borrego@Sun.COM * Get the current uid, gid before setting the new uid/gid 21217619SJose.Borrego@Sun.COM * so if smb_fsop_aclwrite fails they can be restored. root cred is 21227619SJose.Borrego@Sun.COM * used to get currend uid/gid since this operation is performed on 21237619SJose.Borrego@Sun.COM * behalf of the server not the user. 21247619SJose.Borrego@Sun.COM * 21257619SJose.Borrego@Sun.COM * If setting uid/gid fails with EPERM it means that and invalid 21267619SJose.Borrego@Sun.COM * owner has been specified. Callers should translate this to 21277619SJose.Borrego@Sun.COM * STATUS_INVALID_OWNER which is not the normal mapping for EPERM 21287619SJose.Borrego@Sun.COM * in upper layers, so EPERM is mapped to EBADE. 21295331Samw */ 21305331Samw int 21315331Samw smb_fsop_sdwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 21325331Samw smb_fssd_t *fs_sd, int overwrite) 21335331Samw { 21345331Samw int error = 0; 21355331Samw int access = 0; 21365331Samw smb_attr_t set_attr; 21375331Samw smb_attr_t orig_attr; 21385331Samw 21395331Samw ASSERT(cr); 21405331Samw ASSERT(fs_sd); 21415331Samw 21425331Samw ASSERT(sr); 21435331Samw ASSERT(sr->tid_tree); 21447348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 21455331Samw return (EROFS); 21465331Samw 21475331Samw bzero(&set_attr, sizeof (smb_attr_t)); 21485331Samw 21495331Samw if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 21505331Samw set_attr.sa_vattr.va_uid = fs_sd->sd_uid; 21515331Samw set_attr.sa_mask |= SMB_AT_UID; 21527619SJose.Borrego@Sun.COM access |= WRITE_OWNER; 21535331Samw } 21545331Samw 21555331Samw if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 21565331Samw set_attr.sa_vattr.va_gid = fs_sd->sd_gid; 21575331Samw set_attr.sa_mask |= SMB_AT_GID; 21587619SJose.Borrego@Sun.COM access |= WRITE_OWNER; 21595331Samw } 21605331Samw 21615331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 21625331Samw access |= WRITE_DAC; 21635331Samw 21645331Samw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 21655331Samw access |= ACCESS_SYSTEM_SECURITY; 21665331Samw 21675331Samw if (sr->fid_ofile) 21685331Samw error = smb_ofile_access(sr->fid_ofile, cr, access); 21695331Samw else 21705331Samw error = smb_fsop_access(sr, cr, snode, access); 21715331Samw 21725331Samw if (error) 21735331Samw return (EACCES); 21745331Samw 21755331Samw if (set_attr.sa_mask) { 21765331Samw orig_attr.sa_mask = SMB_AT_UID | SMB_AT_GID; 21775331Samw error = smb_fsop_getattr(sr, kcred, snode, &orig_attr); 21787619SJose.Borrego@Sun.COM if (error == 0) { 21795331Samw error = smb_fsop_setattr(sr, cr, snode, &set_attr, 21805331Samw NULL); 21817619SJose.Borrego@Sun.COM if (error == EPERM) 21827619SJose.Borrego@Sun.COM error = EBADE; 21837619SJose.Borrego@Sun.COM } 21845331Samw 21855331Samw if (error) 21865331Samw return (error); 21875331Samw } 21885331Samw 21895331Samw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 21905331Samw if (overwrite == 0) { 21915331Samw error = smb_fsop_sdmerge(sr, snode, fs_sd); 21925331Samw if (error) 21935331Samw return (error); 21945331Samw } 21955331Samw 21965331Samw error = smb_fsop_aclwrite(sr, cr, snode, fs_sd); 21975331Samw if (error) { 21985331Samw /* 21995331Samw * Revert uid/gid changes if required. 22005331Samw */ 22015331Samw if (set_attr.sa_mask) { 22025331Samw orig_attr.sa_mask = set_attr.sa_mask; 22035331Samw (void) smb_fsop_setattr(sr, kcred, snode, 22045331Samw &orig_attr, NULL); 22055331Samw } 22065331Samw } 22075331Samw } 22085331Samw 22095331Samw return (error); 22105331Samw } 22115331Samw 22125331Samw /* 22135331Samw * smb_fsop_sdinherit 22145331Samw * 22155331Samw * Inherit the security descriptor from the parent container. 22165331Samw * This function is called after FS has created the file/folder 22175331Samw * so if this doesn't do anything it means FS inheritance is 22185331Samw * in place. 22195331Samw * 22205331Samw * Do inheritance for ZFS internally. 22215331Samw * 22225331Samw * If we want to let ZFS does the inheritance the 22235331Samw * following setting should be true: 22245331Samw * 22255331Samw * - aclinherit = passthrough 22265331Samw * - aclmode = passthrough 22275331Samw * - smbd umask = 0777 22285331Samw * 22295331Samw * This will result in right effective permissions but 22305331Samw * ZFS will always add 6 ACEs for owner, owning group 22315331Samw * and others to be POSIX compliant. This is not what 22325331Samw * Windows clients/users expect, so we decided that CIFS 22335331Samw * implements Windows rules and overwrite whatever ZFS 22345331Samw * comes up with. This way we also don't have to care 22355331Samw * about ZFS aclinherit and aclmode settings. 22365331Samw */ 22375331Samw static int 22385331Samw smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, smb_fssd_t *fs_sd) 22395331Samw { 22405331Samw int is_dir; 22415521Sas200622 acl_t *dacl = NULL; 22425521Sas200622 acl_t *sacl = NULL; 22435331Samw ksid_t *owner_sid; 22445331Samw int error; 22455331Samw 22465331Samw ASSERT(fs_sd); 22475331Samw 22485331Samw if (sr->tid_tree->t_acltype != ACE_T) { 22495331Samw /* 22505331Samw * No forced inheritance for non-ZFS filesystems. 22515331Samw */ 22525331Samw fs_sd->sd_secinfo = 0; 22535331Samw return (0); 22545331Samw } 22555331Samw 22565331Samw 22575331Samw /* Fetch parent directory's ACL */ 22585331Samw error = smb_fsop_sdread(sr, kcred, dnode, fs_sd); 22595331Samw if (error) { 22605331Samw return (error); 22615331Samw } 22625331Samw 22635331Samw is_dir = (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR); 22645331Samw owner_sid = crgetsid(sr->user_cr, KSID_OWNER); 22655331Samw ASSERT(owner_sid); 22665521Sas200622 dacl = smb_fsacl_inherit(fs_sd->sd_zdacl, is_dir, SMB_DACL_SECINFO, 22675331Samw owner_sid->ks_id); 22685521Sas200622 sacl = smb_fsacl_inherit(fs_sd->sd_zsacl, is_dir, SMB_SACL_SECINFO, 22695331Samw (uid_t)-1); 22705331Samw 22715521Sas200622 if (sacl == NULL) 22725521Sas200622 fs_sd->sd_secinfo &= ~SMB_SACL_SECINFO; 22735521Sas200622 22745521Sas200622 smb_fsacl_free(fs_sd->sd_zdacl); 22755521Sas200622 smb_fsacl_free(fs_sd->sd_zsacl); 22765331Samw 22775331Samw fs_sd->sd_zdacl = dacl; 22785331Samw fs_sd->sd_zsacl = sacl; 22795331Samw 22805331Samw return (0); 22815331Samw } 22825331Samw 22835331Samw /* 22845331Samw * smb_fsop_eaccess 22855331Samw * 22865331Samw * Returns the effective permission of the given credential for the 22875331Samw * specified object. 22885331Samw * 22895331Samw * This is just a workaround. We need VFS/FS support for this. 22905331Samw */ 22915331Samw void 22925331Samw smb_fsop_eaccess(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 22935331Samw uint32_t *eaccess) 22945331Samw { 22955331Samw int access = 0; 22965331Samw vnode_t *dir_vp; 22975331Samw smb_node_t *unnamed_node; 22985331Samw 22995331Samw ASSERT(cr); 23005331Samw ASSERT(snode); 23015331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 23025331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 23035331Samw 23045331Samw unnamed_node = SMB_IS_STREAM(snode); 23055331Samw if (unnamed_node) { 23065331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 23075331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 23085331Samw /* 23095331Samw * Streams authorization should be performed against the 23105331Samw * unnamed stream. 23115331Samw */ 23125331Samw snode = unnamed_node; 23135331Samw } 23145331Samw 23157348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) { 23165331Samw dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL; 23175331Samw smb_vop_eaccess(snode->vp, (int *)eaccess, V_ACE_MASK, dir_vp, 23185331Samw cr); 23195331Samw return; 23205331Samw } 23215331Samw 23225331Samw /* 23235331Samw * FS doesn't understand 32-bit mask 23245331Samw */ 23255331Samw smb_vop_eaccess(snode->vp, &access, 0, NULL, cr); 23265331Samw 23275331Samw *eaccess = READ_CONTROL | FILE_READ_EA | FILE_READ_ATTRIBUTES; 23285331Samw 23295331Samw if (access & VREAD) 23305331Samw *eaccess |= FILE_READ_DATA; 23315331Samw 23325331Samw if (access & VEXEC) 23335331Samw *eaccess |= FILE_EXECUTE; 23345331Samw 23355331Samw if (access & VWRITE) 23365331Samw *eaccess |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | 23375331Samw FILE_WRITE_EA | FILE_APPEND_DATA | FILE_DELETE_CHILD; 23385331Samw } 23395521Sas200622 23405772Sas200622 /* 23415772Sas200622 * smb_fsop_shrlock 23425772Sas200622 * 23435772Sas200622 * For the current open request, check file sharing rules 23445772Sas200622 * against existing opens. 23455772Sas200622 * 23465772Sas200622 * Returns NT_STATUS_SHARING_VIOLATION if there is any 23475772Sas200622 * sharing conflict. Returns NT_STATUS_SUCCESS otherwise. 23485772Sas200622 * 23495772Sas200622 * Full system-wide share reservation synchronization is available 23505772Sas200622 * when the nbmand (non-blocking mandatory) mount option is set 23515772Sas200622 * (i.e. nbl_need_crit() is true) and nbmand critical regions are used. 23525772Sas200622 * This provides synchronization with NFS and local processes. The 23535772Sas200622 * critical regions are entered in VOP_SHRLOCK()/fs_shrlock() (called 23545772Sas200622 * from smb_open_subr()/smb_fsop_shrlock()/smb_vop_shrlock()) as well 23555772Sas200622 * as the CIFS rename and delete paths. 23565772Sas200622 * 23575772Sas200622 * The CIFS server will also enter the nbl critical region in the open, 23585772Sas200622 * rename, and delete paths when nbmand is not set. There is limited 23595772Sas200622 * coordination with local and VFS share reservations in this case. 23605772Sas200622 * Note that when the nbmand mount option is not set, the VFS layer 23615772Sas200622 * only processes advisory reservations and the delete mode is not checked. 23625772Sas200622 * 23635772Sas200622 * Whether or not the nbmand mount option is set, intra-CIFS share 23645772Sas200622 * checking is done in the open, delete, and rename paths using a CIFS 23655772Sas200622 * critical region (node->n_share_lock). 23665772Sas200622 */ 23675772Sas200622 23685772Sas200622 uint32_t 23696139Sjb150015 smb_fsop_shrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid, 23705772Sas200622 uint32_t desired_access, uint32_t share_access) 23715772Sas200622 { 23725772Sas200622 int rc; 23735772Sas200622 23745772Sas200622 if (node->attr.sa_vattr.va_type == VDIR) 23755772Sas200622 return (NT_STATUS_SUCCESS); 23765772Sas200622 23775772Sas200622 /* Allow access if the request is just for meta data */ 23785772Sas200622 if ((desired_access & FILE_DATA_ALL) == 0) 23795772Sas200622 return (NT_STATUS_SUCCESS); 23805772Sas200622 23815772Sas200622 rc = smb_node_open_check(node, cr, desired_access, share_access); 23825772Sas200622 if (rc) 23835772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 23845772Sas200622 23855772Sas200622 rc = smb_vop_shrlock(node->vp, uniq_fid, desired_access, share_access, 23865772Sas200622 cr); 23875772Sas200622 if (rc) 23885772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 23895772Sas200622 23905772Sas200622 return (NT_STATUS_SUCCESS); 23915772Sas200622 } 23925772Sas200622 23935521Sas200622 void 23945772Sas200622 smb_fsop_unshrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid) 23955521Sas200622 { 23965772Sas200622 if (node->attr.sa_vattr.va_type == VDIR) 23975772Sas200622 return; 23985772Sas200622 23995772Sas200622 (void) smb_vop_unshrlock(node->vp, uniq_fid, cr); 24005772Sas200622 } 24016600Sas200622 24026600Sas200622 int 24036600Sas200622 smb_fsop_frlock(smb_node_t *node, smb_lock_t *lock, boolean_t unlock, 24046600Sas200622 cred_t *cr) 24056600Sas200622 { 24066600Sas200622 flock64_t bf; 24076600Sas200622 int flag = F_REMOTELOCK; 24086600Sas200622 24096771Sjb150015 /* 24106771Sjb150015 * VOP_FRLOCK() will not be called if: 24116771Sjb150015 * 24126771Sjb150015 * 1) The lock has a range of zero bytes. The semantics of Windows and 24136771Sjb150015 * POSIX are different. In the case of POSIX it asks for the locking 24146771Sjb150015 * of all the bytes from the offset provided until the end of the 24156771Sjb150015 * file. In the case of Windows a range of zero locks nothing and 24166771Sjb150015 * doesn't conflict with any other lock. 24176771Sjb150015 * 24186771Sjb150015 * 2) The lock rolls over (start + lenght < start). Solaris will assert 24196771Sjb150015 * if such a request is submitted. This will not create 24206771Sjb150015 * incompatibilities between POSIX and Windows. In the Windows world, 24216771Sjb150015 * if a client submits such a lock, the server will not lock any 24226771Sjb150015 * bytes. Interestingly if the same lock (same offset and length) is 24236771Sjb150015 * resubmitted Windows will consider that there is an overlap and 24246771Sjb150015 * the granting rules will then apply. 24256771Sjb150015 */ 24266771Sjb150015 if ((lock->l_length == 0) || 24276771Sjb150015 ((lock->l_start + lock->l_length - 1) < lock->l_start)) 24286771Sjb150015 return (0); 24296771Sjb150015 24306600Sas200622 bzero(&bf, sizeof (bf)); 24316600Sas200622 24326600Sas200622 if (unlock) { 24336600Sas200622 bf.l_type = F_UNLCK; 24346600Sas200622 } else if (lock->l_type == SMB_LOCK_TYPE_READONLY) { 24356600Sas200622 bf.l_type = F_RDLCK; 24366600Sas200622 flag |= FREAD; 24376600Sas200622 } else if (lock->l_type == SMB_LOCK_TYPE_READWRITE) { 24386600Sas200622 bf.l_type = F_WRLCK; 24396600Sas200622 flag |= FWRITE; 24406600Sas200622 } 24416600Sas200622 24426600Sas200622 bf.l_start = lock->l_start; 24436600Sas200622 bf.l_len = lock->l_length; 24447348SJose.Borrego@Sun.COM bf.l_pid = lock->l_file->f_uniqid; 24456600Sas200622 bf.l_sysid = smb_ct.cc_sysid; 24466600Sas200622 24476600Sas200622 return (smb_vop_frlock(node->vp, cr, flag, &bf)); 24486600Sas200622 } 2449