15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw /* 228670SJose.Borrego@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw #include <sys/sid.h> 275772Sas200622 #include <sys/nbmlock.h> 285331Samw #include <smbsrv/smb_fsops.h> 295521Sas200622 #include <smbsrv/smb_kproto.h> 305521Sas200622 #include <smbsrv/ntstatus.h> 315521Sas200622 #include <smbsrv/ntaccess.h> 325772Sas200622 #include <smbsrv/smb_incl.h> 335331Samw #include <acl/acl_common.h> 345772Sas200622 #include <sys/fcntl.h> 355772Sas200622 #include <sys/flock.h> 365772Sas200622 #include <fs/fs_subr.h> 375331Samw 386139Sjb150015 extern caller_context_t smb_ct; 396139Sjb150015 406600Sas200622 extern int smb_fem_oplock_install(smb_node_t *); 416600Sas200622 extern void smb_fem_oplock_uninstall(smb_node_t *); 426600Sas200622 436600Sas200622 extern int smb_vop_other_opens(vnode_t *, int); 446600Sas200622 459343SAfshin.Ardakani@Sun.COM static int smb_fsop_create_stream(smb_request_t *, cred_t *, smb_node_t *, 46*10001SJoyce.McIntosh@Sun.COM char *, char *, int, smb_attr_t *, smb_node_t **); 479343SAfshin.Ardakani@Sun.COM 489343SAfshin.Ardakani@Sun.COM static int smb_fsop_create_file(smb_request_t *, cred_t *, smb_node_t *, 49*10001SJoyce.McIntosh@Sun.COM char *, int, smb_attr_t *, smb_node_t **); 509343SAfshin.Ardakani@Sun.COM 519343SAfshin.Ardakani@Sun.COM static int smb_fsop_create_with_sd(smb_request_t *, cred_t *, smb_node_t *, 52*10001SJoyce.McIntosh@Sun.COM char *, smb_attr_t *, smb_node_t **, smb_fssd_t *); 539343SAfshin.Ardakani@Sun.COM 549343SAfshin.Ardakani@Sun.COM static int smb_fsop_sdinherit(smb_request_t *, smb_node_t *, smb_fssd_t *); 555331Samw 565331Samw /* 575331Samw * The smb_fsop_* functions have knowledge of CIFS semantics. 585331Samw * 595331Samw * The smb_vop_* functions have minimal knowledge of CIFS semantics and 605331Samw * serve as an interface to the VFS layer. 615331Samw * 625331Samw * Hence, smb_request_t and smb_node_t structures should not be passed 635331Samw * from the smb_fsop_* layer to the smb_vop_* layer. 645331Samw * 655331Samw * In general, CIFS service code should only ever call smb_fsop_* 665331Samw * functions directly, and never smb_vop_* functions directly. 675331Samw * 685331Samw * smb_fsop_* functions should call smb_vop_* functions where possible, instead 695331Samw * of their smb_fsop_* counterparts. However, there are times when 705331Samw * this cannot be avoided. 715331Samw */ 725331Samw 735331Samw /* 745331Samw * Note: Stream names cannot be mangled. 755331Samw */ 765331Samw 776600Sas200622 /* 786600Sas200622 * smb_fsop_amask_to_omode 796600Sas200622 * 806600Sas200622 * Convert the access mask to the open mode (for use 816600Sas200622 * with the VOP_OPEN call). 826600Sas200622 * 836600Sas200622 * Note that opening a file for attribute only access 846600Sas200622 * will also translate into an FREAD or FWRITE open mode 856600Sas200622 * (i.e., it's not just for data). 866600Sas200622 * 876600Sas200622 * This is needed so that opens are tracked appropriately 886600Sas200622 * for oplock processing. 896600Sas200622 */ 906600Sas200622 915331Samw int 926600Sas200622 smb_fsop_amask_to_omode(uint32_t access) 935331Samw { 946600Sas200622 int mode = 0; 956600Sas200622 966600Sas200622 if (access & (FILE_READ_DATA | FILE_EXECUTE | 976600Sas200622 FILE_READ_ATTRIBUTES | FILE_READ_EA)) 986600Sas200622 mode |= FREAD; 996600Sas200622 1006600Sas200622 if (access & (FILE_WRITE_DATA | FILE_APPEND_DATA | 1016600Sas200622 FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA)) 1026600Sas200622 mode |= FWRITE; 1036600Sas200622 1046600Sas200622 if (access & FILE_APPEND_DATA) 1056600Sas200622 mode |= FAPPEND; 1066600Sas200622 1076600Sas200622 return (mode); 1085331Samw } 1095331Samw 1105331Samw int 1116600Sas200622 smb_fsop_open(smb_node_t *node, int mode, cred_t *cred) 1125331Samw { 1136600Sas200622 /* 1146600Sas200622 * Assuming that the same vnode is returned as we had before. 1156600Sas200622 * (I.e., with certain types of files or file systems, a 1166600Sas200622 * different vnode might be returned by VOP_OPEN) 1176600Sas200622 */ 1186600Sas200622 return (smb_vop_open(&node->vp, mode, cred)); 1195331Samw } 1205331Samw 1217348SJose.Borrego@Sun.COM void 1226600Sas200622 smb_fsop_close(smb_node_t *node, int mode, cred_t *cred) 1236600Sas200622 { 1247348SJose.Borrego@Sun.COM smb_vop_close(node->vp, mode, cred); 1256600Sas200622 } 1266600Sas200622 1276600Sas200622 int 1286600Sas200622 smb_fsop_oplock_install(smb_node_t *node, int mode) 1295331Samw { 1306600Sas200622 int rc; 1316600Sas200622 1326600Sas200622 if (smb_vop_other_opens(node->vp, mode)) 1336600Sas200622 return (EMFILE); 1346600Sas200622 1356600Sas200622 if ((rc = smb_fem_oplock_install(node))) 1366600Sas200622 return (rc); 1376600Sas200622 1386600Sas200622 if (smb_vop_other_opens(node->vp, mode)) { 1396600Sas200622 (void) smb_fem_oplock_uninstall(node); 1406600Sas200622 return (EMFILE); 1416600Sas200622 } 1426600Sas200622 1436600Sas200622 return (0); 1446600Sas200622 } 1456600Sas200622 1466600Sas200622 void 1476600Sas200622 smb_fsop_oplock_uninstall(smb_node_t *node) 1486600Sas200622 { 1496600Sas200622 smb_fem_oplock_uninstall(node); 1505331Samw } 1515331Samw 1525331Samw static int 1539343SAfshin.Ardakani@Sun.COM smb_fsop_create_with_sd(smb_request_t *sr, cred_t *cr, 1549343SAfshin.Ardakani@Sun.COM smb_node_t *dnode, char *name, 155*10001SJoyce.McIntosh@Sun.COM smb_attr_t *attr, smb_node_t **ret_snode, smb_fssd_t *fs_sd) 1565331Samw { 1575331Samw vsecattr_t *vsap; 1585331Samw vsecattr_t vsecattr; 1595331Samw acl_t *acl, *dacl, *sacl; 1605331Samw smb_attr_t set_attr; 1615331Samw vnode_t *vp; 1625331Samw int aclbsize = 0; /* size of acl list in bytes */ 1635331Samw int flags = 0; 1645331Samw int rc; 1657619SJose.Borrego@Sun.COM boolean_t is_dir; 1665331Samw 1675331Samw ASSERT(fs_sd); 1685331Samw 1697348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 1705331Samw flags = SMB_IGNORE_CASE; 1719231SAfshin.Ardakani@Sun.COM if (SMB_TREE_SUPPORTS_CATIA(sr)) 1729231SAfshin.Ardakani@Sun.COM flags |= SMB_CATIA; 1735331Samw 1745331Samw ASSERT(cr); 1755331Samw 1765331Samw is_dir = ((fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR) != 0); 1775331Samw 1787348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACLONCREATE)) { 1795331Samw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 1805331Samw dacl = fs_sd->sd_zdacl; 1815331Samw sacl = fs_sd->sd_zsacl; 1825331Samw ASSERT(dacl || sacl); 1835331Samw if (dacl && sacl) { 1845521Sas200622 acl = smb_fsacl_merge(dacl, sacl); 1855331Samw } else if (dacl) { 1865331Samw acl = dacl; 1875331Samw } else { 1885331Samw acl = sacl; 1895331Samw } 1905331Samw 1915521Sas200622 rc = smb_fsacl_to_vsa(acl, &vsecattr, &aclbsize); 1925331Samw 1935331Samw if (dacl && sacl) 1945331Samw acl_free(acl); 1955331Samw 1967619SJose.Borrego@Sun.COM if (rc != 0) 1975331Samw return (rc); 1985331Samw 1995331Samw vsap = &vsecattr; 2007619SJose.Borrego@Sun.COM } else { 2017619SJose.Borrego@Sun.COM vsap = NULL; 2025331Samw } 2035331Samw 2048845Samw@Sun.COM /* The tree ACEs may prevent a create */ 2058845Samw@Sun.COM rc = EACCES; 2065331Samw if (is_dir) { 2078845Samw@Sun.COM if (SMB_TREE_HAS_ACCESS(sr, ACE_ADD_SUBDIRECTORY) != 0) 2089343SAfshin.Ardakani@Sun.COM rc = smb_vop_mkdir(dnode->vp, name, attr, 2098845Samw@Sun.COM &vp, flags, cr, vsap); 2105331Samw } else { 2118845Samw@Sun.COM if (SMB_TREE_HAS_ACCESS(sr, ACE_ADD_FILE) != 0) 2129343SAfshin.Ardakani@Sun.COM rc = smb_vop_create(dnode->vp, name, attr, 2138845Samw@Sun.COM &vp, flags, cr, vsap); 2145331Samw } 2155331Samw 2165331Samw if (vsap != NULL) 2175331Samw kmem_free(vsap->vsa_aclentp, aclbsize); 2185331Samw 2195331Samw if (rc != 0) 2205331Samw return (rc); 2215331Samw 2225331Samw set_attr.sa_mask = 0; 2235331Samw 2245331Samw /* 2255331Samw * Ideally we should be able to specify the owner and owning 2265331Samw * group at create time along with the ACL. Since we cannot 2275331Samw * do that right now, kcred is passed to smb_vop_setattr so it 2285331Samw * doesn't fail due to lack of permission. 2295331Samw */ 2305331Samw if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 2315331Samw set_attr.sa_vattr.va_uid = fs_sd->sd_uid; 2325331Samw set_attr.sa_mask |= SMB_AT_UID; 2335331Samw } 2345331Samw 2355331Samw if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 2365331Samw set_attr.sa_vattr.va_gid = fs_sd->sd_gid; 2375331Samw set_attr.sa_mask |= SMB_AT_GID; 2385331Samw } 2395331Samw 2407757SJanice.Chang@Sun.COM if (set_attr.sa_mask) 2417757SJanice.Chang@Sun.COM rc = smb_vop_setattr(vp, NULL, &set_attr, 0, kcred); 2425331Samw 2437619SJose.Borrego@Sun.COM if (rc == 0) { 2447619SJose.Borrego@Sun.COM *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp, 245*10001SJoyce.McIntosh@Sun.COM name, dnode, NULL); 2467619SJose.Borrego@Sun.COM 2478670SJose.Borrego@Sun.COM if (*ret_snode == NULL) 2487619SJose.Borrego@Sun.COM rc = ENOMEM; 2498670SJose.Borrego@Sun.COM 2508670SJose.Borrego@Sun.COM VN_RELE(vp); 2517619SJose.Borrego@Sun.COM } 2525331Samw } else { 2535331Samw /* 2545331Samw * For filesystems that don't support ACL-on-create, try 2555331Samw * to set the specified SD after create, which could actually 2565331Samw * fail because of conflicts between inherited security 2575331Samw * attributes upon creation and the specified SD. 2585331Samw * 2595331Samw * Passing kcred to smb_fsop_sdwrite() to overcome this issue. 2605331Samw */ 2615331Samw 2625331Samw if (is_dir) { 2639343SAfshin.Ardakani@Sun.COM rc = smb_vop_mkdir(dnode->vp, name, attr, &vp, 2647619SJose.Borrego@Sun.COM flags, cr, NULL); 2655331Samw } else { 2669343SAfshin.Ardakani@Sun.COM rc = smb_vop_create(dnode->vp, name, attr, &vp, 2677619SJose.Borrego@Sun.COM flags, cr, NULL); 2685331Samw } 2695331Samw 2705521Sas200622 if (rc != 0) 2715521Sas200622 return (rc); 2725521Sas200622 2737619SJose.Borrego@Sun.COM *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp, 274*10001SJoyce.McIntosh@Sun.COM name, dnode, NULL); 2757619SJose.Borrego@Sun.COM 2767619SJose.Borrego@Sun.COM if (*ret_snode != NULL) { 2777619SJose.Borrego@Sun.COM if (!smb_tree_has_feature(sr->tid_tree, 2787619SJose.Borrego@Sun.COM SMB_TREE_NFS_MOUNTED)) 2797619SJose.Borrego@Sun.COM rc = smb_fsop_sdwrite(sr, kcred, *ret_snode, 2807619SJose.Borrego@Sun.COM fs_sd, 1); 2817619SJose.Borrego@Sun.COM } else { 2825331Samw rc = ENOMEM; 2835331Samw } 2848670SJose.Borrego@Sun.COM 2858670SJose.Borrego@Sun.COM VN_RELE(vp); 2865331Samw } 2875331Samw 2885521Sas200622 if (rc != 0) { 2897619SJose.Borrego@Sun.COM if (is_dir) 2909343SAfshin.Ardakani@Sun.COM (void) smb_vop_rmdir(dnode->vp, name, flags, cr); 2917619SJose.Borrego@Sun.COM else 2929343SAfshin.Ardakani@Sun.COM (void) smb_vop_remove(dnode->vp, name, flags, cr); 2935521Sas200622 } 2945521Sas200622 2955331Samw return (rc); 2965331Samw } 2975331Samw 2985331Samw /* 2995331Samw * smb_fsop_create 3005331Samw * 3015331Samw * All SMB functions should use this wrapper to ensure that 3025331Samw * all the smb_vop_creates are performed with the appropriate credentials. 3039343SAfshin.Ardakani@Sun.COM * Please document any direct calls to explain the reason for avoiding 3049343SAfshin.Ardakani@Sun.COM * this wrapper. 3055331Samw * 3065331Samw * *ret_snode is returned with a reference upon success. No reference is 3075331Samw * taken if an error is returned. 3085331Samw */ 3095331Samw int 310*10001SJoyce.McIntosh@Sun.COM smb_fsop_create(smb_request_t *sr, cred_t *cr, smb_node_t *dnode, 311*10001SJoyce.McIntosh@Sun.COM char *name, smb_attr_t *attr, smb_node_t **ret_snode) 3125331Samw { 3139343SAfshin.Ardakani@Sun.COM int rc = 0; 3149343SAfshin.Ardakani@Sun.COM int flags = 0; 3159343SAfshin.Ardakani@Sun.COM char *fname, *sname; 3169343SAfshin.Ardakani@Sun.COM char *longname = NULL; 3175331Samw 3185331Samw ASSERT(cr); 3199343SAfshin.Ardakani@Sun.COM ASSERT(dnode); 3209343SAfshin.Ardakani@Sun.COM ASSERT(dnode->n_magic == SMB_NODE_MAGIC); 3219343SAfshin.Ardakani@Sun.COM ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING); 3225331Samw 3235331Samw ASSERT(ret_snode); 3245331Samw *ret_snode = 0; 3255331Samw 3265331Samw ASSERT(name); 3275331Samw if (*name == 0) 3285331Samw return (EINVAL); 3295331Samw 3305331Samw ASSERT(sr); 3315331Samw ASSERT(sr->tid_tree); 3327348SJose.Borrego@Sun.COM 3339343SAfshin.Ardakani@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0) 3347348SJose.Borrego@Sun.COM return (EACCES); 3357348SJose.Borrego@Sun.COM 3367348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 3375331Samw return (EROFS); 3385331Samw 3397348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 3405331Samw flags = SMB_IGNORE_CASE; 3419231SAfshin.Ardakani@Sun.COM if (SMB_TREE_SUPPORTS_CATIA(sr)) 3429231SAfshin.Ardakani@Sun.COM flags |= SMB_CATIA; 3435331Samw 3449231SAfshin.Ardakani@Sun.COM if (smb_is_stream_name(name)) { 3459231SAfshin.Ardakani@Sun.COM fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 3469231SAfshin.Ardakani@Sun.COM sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 3479343SAfshin.Ardakani@Sun.COM smb_stream_parse_name(name, fname, sname); 3485331Samw 3499343SAfshin.Ardakani@Sun.COM rc = smb_fsop_create_stream(sr, cr, dnode, 350*10001SJoyce.McIntosh@Sun.COM fname, sname, flags, attr, ret_snode); 3519231SAfshin.Ardakani@Sun.COM 3529231SAfshin.Ardakani@Sun.COM kmem_free(fname, MAXNAMELEN); 3539231SAfshin.Ardakani@Sun.COM kmem_free(sname, MAXNAMELEN); 3549231SAfshin.Ardakani@Sun.COM return (rc); 3559231SAfshin.Ardakani@Sun.COM } 3565521Sas200622 3579231SAfshin.Ardakani@Sun.COM /* Not a named stream */ 3589343SAfshin.Ardakani@Sun.COM 3599231SAfshin.Ardakani@Sun.COM if (smb_maybe_mangled_name(name)) { 3609231SAfshin.Ardakani@Sun.COM longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 3619343SAfshin.Ardakani@Sun.COM rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN); 3629231SAfshin.Ardakani@Sun.COM kmem_free(longname, MAXNAMELEN); 3635331Samw 3649231SAfshin.Ardakani@Sun.COM if (rc == 0) 3659231SAfshin.Ardakani@Sun.COM rc = EEXIST; 3669231SAfshin.Ardakani@Sun.COM if (rc != ENOENT) 3679231SAfshin.Ardakani@Sun.COM return (rc); 3685331Samw } 3695331Samw 3709343SAfshin.Ardakani@Sun.COM rc = smb_fsop_create_file(sr, cr, dnode, name, flags, 371*10001SJoyce.McIntosh@Sun.COM attr, ret_snode); 3729343SAfshin.Ardakani@Sun.COM return (rc); 3739343SAfshin.Ardakani@Sun.COM 3749343SAfshin.Ardakani@Sun.COM } 3759343SAfshin.Ardakani@Sun.COM 3769343SAfshin.Ardakani@Sun.COM 3779343SAfshin.Ardakani@Sun.COM /* 3789343SAfshin.Ardakani@Sun.COM * smb_fsop_create_stream 3799343SAfshin.Ardakani@Sun.COM * 3809343SAfshin.Ardakani@Sun.COM * Create NTFS named stream file (sname) on unnamed stream 3819343SAfshin.Ardakani@Sun.COM * file (fname), creating the unnamed stream file if it 3829343SAfshin.Ardakani@Sun.COM * doesn't exist. 3839343SAfshin.Ardakani@Sun.COM * If we created the unnamed stream file and then creation 3849343SAfshin.Ardakani@Sun.COM * of the named stream file fails, we delete the unnamed stream. 3859343SAfshin.Ardakani@Sun.COM * Since we use the real file name for the smb_vop_remove we 3869343SAfshin.Ardakani@Sun.COM * clear the SMB_IGNORE_CASE flag to ensure a case sensitive 3879343SAfshin.Ardakani@Sun.COM * match. 3889343SAfshin.Ardakani@Sun.COM * 3899343SAfshin.Ardakani@Sun.COM * The second parameter of smb_vop_setattr() is set to 3909343SAfshin.Ardakani@Sun.COM * NULL, even though an unnamed stream exists. This is 3919343SAfshin.Ardakani@Sun.COM * because we want to set the UID and GID on the named 3929343SAfshin.Ardakani@Sun.COM * stream in this case for consistency with the (unnamed 3939343SAfshin.Ardakani@Sun.COM * stream) file (see comments for smb_vop_setattr()). 3949343SAfshin.Ardakani@Sun.COM */ 3959343SAfshin.Ardakani@Sun.COM static int 3969343SAfshin.Ardakani@Sun.COM smb_fsop_create_stream(smb_request_t *sr, cred_t *cr, 3979343SAfshin.Ardakani@Sun.COM smb_node_t *dnode, char *fname, char *sname, int flags, 398*10001SJoyce.McIntosh@Sun.COM smb_attr_t *attr, smb_node_t **ret_snode) 3999343SAfshin.Ardakani@Sun.COM { 4009343SAfshin.Ardakani@Sun.COM smb_node_t *fnode; 4019343SAfshin.Ardakani@Sun.COM smb_attr_t fattr; 4029343SAfshin.Ardakani@Sun.COM vnode_t *xattrdvp; 4039343SAfshin.Ardakani@Sun.COM vnode_t *vp; 4049343SAfshin.Ardakani@Sun.COM int rc = 0; 4059343SAfshin.Ardakani@Sun.COM boolean_t fcreate = B_FALSE; 4069343SAfshin.Ardakani@Sun.COM 4079343SAfshin.Ardakani@Sun.COM /* Look up / create the unnamed stream, fname */ 4089343SAfshin.Ardakani@Sun.COM rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, 409*10001SJoyce.McIntosh@Sun.COM sr->tid_tree->t_snode, dnode, fname, &fnode); 4109343SAfshin.Ardakani@Sun.COM if (rc == ENOENT) { 4119343SAfshin.Ardakani@Sun.COM fcreate = B_TRUE; 4129343SAfshin.Ardakani@Sun.COM rc = smb_fsop_create_file(sr, cr, dnode, fname, flags, 413*10001SJoyce.McIntosh@Sun.COM attr, &fnode); 4149343SAfshin.Ardakani@Sun.COM } 4159343SAfshin.Ardakani@Sun.COM if (rc != 0) 4169343SAfshin.Ardakani@Sun.COM return (rc); 4179343SAfshin.Ardakani@Sun.COM 418*10001SJoyce.McIntosh@Sun.COM fattr.sa_mask = SMB_AT_UID | SMB_AT_GID; 419*10001SJoyce.McIntosh@Sun.COM rc = smb_vop_getattr(fnode->vp, NULL, &fattr, 0, kcred); 420*10001SJoyce.McIntosh@Sun.COM 421*10001SJoyce.McIntosh@Sun.COM if (rc == 0) { 422*10001SJoyce.McIntosh@Sun.COM /* create the named stream, sname */ 423*10001SJoyce.McIntosh@Sun.COM rc = smb_vop_stream_create(fnode->vp, sname, attr, 424*10001SJoyce.McIntosh@Sun.COM &vp, &xattrdvp, flags, cr); 425*10001SJoyce.McIntosh@Sun.COM } 4269343SAfshin.Ardakani@Sun.COM if (rc != 0) { 4279343SAfshin.Ardakani@Sun.COM if (fcreate) { 4289343SAfshin.Ardakani@Sun.COM flags &= ~SMB_IGNORE_CASE; 4299343SAfshin.Ardakani@Sun.COM (void) smb_vop_remove(dnode->vp, 4309343SAfshin.Ardakani@Sun.COM fnode->od_name, flags, cr); 4319343SAfshin.Ardakani@Sun.COM } 4329343SAfshin.Ardakani@Sun.COM smb_node_release(fnode); 4339343SAfshin.Ardakani@Sun.COM return (rc); 4349343SAfshin.Ardakani@Sun.COM } 4359343SAfshin.Ardakani@Sun.COM 4369343SAfshin.Ardakani@Sun.COM attr->sa_vattr.va_uid = fattr.sa_vattr.va_uid; 4379343SAfshin.Ardakani@Sun.COM attr->sa_vattr.va_gid = fattr.sa_vattr.va_gid; 4389343SAfshin.Ardakani@Sun.COM attr->sa_mask = SMB_AT_UID | SMB_AT_GID; 4399343SAfshin.Ardakani@Sun.COM 4409343SAfshin.Ardakani@Sun.COM rc = smb_vop_setattr(vp, NULL, attr, 0, kcred); 4419343SAfshin.Ardakani@Sun.COM if (rc != 0) { 4429343SAfshin.Ardakani@Sun.COM smb_node_release(fnode); 4439343SAfshin.Ardakani@Sun.COM return (rc); 4449343SAfshin.Ardakani@Sun.COM } 4459343SAfshin.Ardakani@Sun.COM 4469343SAfshin.Ardakani@Sun.COM *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdvp, 447*10001SJoyce.McIntosh@Sun.COM vp, sname); 4489343SAfshin.Ardakani@Sun.COM 4499343SAfshin.Ardakani@Sun.COM smb_node_release(fnode); 4509343SAfshin.Ardakani@Sun.COM VN_RELE(xattrdvp); 4519343SAfshin.Ardakani@Sun.COM VN_RELE(vp); 4529343SAfshin.Ardakani@Sun.COM 4539343SAfshin.Ardakani@Sun.COM if (*ret_snode == NULL) 4549343SAfshin.Ardakani@Sun.COM rc = ENOMEM; 4559343SAfshin.Ardakani@Sun.COM 4569343SAfshin.Ardakani@Sun.COM return (rc); 4579343SAfshin.Ardakani@Sun.COM } 4589343SAfshin.Ardakani@Sun.COM 4599343SAfshin.Ardakani@Sun.COM /* 4609343SAfshin.Ardakani@Sun.COM * smb_fsop_create_file 4619343SAfshin.Ardakani@Sun.COM */ 4629343SAfshin.Ardakani@Sun.COM static int 4639343SAfshin.Ardakani@Sun.COM smb_fsop_create_file(smb_request_t *sr, cred_t *cr, 4649343SAfshin.Ardakani@Sun.COM smb_node_t *dnode, char *name, int flags, 465*10001SJoyce.McIntosh@Sun.COM smb_attr_t *attr, smb_node_t **ret_snode) 4669343SAfshin.Ardakani@Sun.COM { 4679343SAfshin.Ardakani@Sun.COM open_param_t *op = &sr->arg.open; 4689343SAfshin.Ardakani@Sun.COM vnode_t *vp; 4699343SAfshin.Ardakani@Sun.COM smb_fssd_t fs_sd; 4709343SAfshin.Ardakani@Sun.COM uint32_t secinfo; 4719343SAfshin.Ardakani@Sun.COM uint32_t status; 4729343SAfshin.Ardakani@Sun.COM int rc = 0; 4739343SAfshin.Ardakani@Sun.COM 4749231SAfshin.Ardakani@Sun.COM if (op->sd) { 4759231SAfshin.Ardakani@Sun.COM /* 4769231SAfshin.Ardakani@Sun.COM * SD sent by client in Windows format. Needs to be 4779231SAfshin.Ardakani@Sun.COM * converted to FS format. No inheritance. 4789231SAfshin.Ardakani@Sun.COM */ 4799231SAfshin.Ardakani@Sun.COM secinfo = smb_sd_get_secinfo(op->sd); 4809231SAfshin.Ardakani@Sun.COM smb_fssd_init(&fs_sd, secinfo, 0); 4819231SAfshin.Ardakani@Sun.COM 4829231SAfshin.Ardakani@Sun.COM status = smb_sd_tofs(op->sd, &fs_sd); 4839231SAfshin.Ardakani@Sun.COM if (status == NT_STATUS_SUCCESS) { 4849343SAfshin.Ardakani@Sun.COM rc = smb_fsop_create_with_sd(sr, cr, dnode, 485*10001SJoyce.McIntosh@Sun.COM name, attr, ret_snode, &fs_sd); 4869231SAfshin.Ardakani@Sun.COM } else { 4879231SAfshin.Ardakani@Sun.COM rc = EINVAL; 4889231SAfshin.Ardakani@Sun.COM } 4899231SAfshin.Ardakani@Sun.COM smb_fssd_term(&fs_sd); 4909231SAfshin.Ardakani@Sun.COM } else if (sr->tid_tree->t_acltype == ACE_T) { 4919231SAfshin.Ardakani@Sun.COM /* 4929231SAfshin.Ardakani@Sun.COM * No incoming SD and filesystem is ZFS 4939231SAfshin.Ardakani@Sun.COM * Server applies Windows inheritance rules, 4949231SAfshin.Ardakani@Sun.COM * see smb_fsop_sdinherit() comments as to why. 4959231SAfshin.Ardakani@Sun.COM */ 4969231SAfshin.Ardakani@Sun.COM smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, 0); 4979343SAfshin.Ardakani@Sun.COM rc = smb_fsop_sdinherit(sr, dnode, &fs_sd); 4989231SAfshin.Ardakani@Sun.COM if (rc == 0) { 4999343SAfshin.Ardakani@Sun.COM rc = smb_fsop_create_with_sd(sr, cr, dnode, 500*10001SJoyce.McIntosh@Sun.COM name, attr, ret_snode, &fs_sd); 5019231SAfshin.Ardakani@Sun.COM } 5029231SAfshin.Ardakani@Sun.COM 5039231SAfshin.Ardakani@Sun.COM smb_fssd_term(&fs_sd); 5049231SAfshin.Ardakani@Sun.COM } else { 5059231SAfshin.Ardakani@Sun.COM /* 5069231SAfshin.Ardakani@Sun.COM * No incoming SD and filesystem is not ZFS 5079231SAfshin.Ardakani@Sun.COM * let the filesystem handles the inheritance. 5089231SAfshin.Ardakani@Sun.COM */ 5099343SAfshin.Ardakani@Sun.COM rc = smb_vop_create(dnode->vp, name, attr, &vp, 5109231SAfshin.Ardakani@Sun.COM flags, cr, NULL); 5119231SAfshin.Ardakani@Sun.COM 5129231SAfshin.Ardakani@Sun.COM if (rc == 0) { 5139231SAfshin.Ardakani@Sun.COM *ret_snode = smb_node_lookup(sr, op, cr, vp, 514*10001SJoyce.McIntosh@Sun.COM name, dnode, NULL); 5159231SAfshin.Ardakani@Sun.COM 5169231SAfshin.Ardakani@Sun.COM if (*ret_snode == NULL) 5179231SAfshin.Ardakani@Sun.COM rc = ENOMEM; 5189231SAfshin.Ardakani@Sun.COM 5199231SAfshin.Ardakani@Sun.COM VN_RELE(vp); 5209231SAfshin.Ardakani@Sun.COM } 5219231SAfshin.Ardakani@Sun.COM 5229231SAfshin.Ardakani@Sun.COM } 5235331Samw return (rc); 5245331Samw } 5255331Samw 5265331Samw /* 5275331Samw * smb_fsop_mkdir 5285331Samw * 5295331Samw * All SMB functions should use this wrapper to ensure that 5305331Samw * the the calls are performed with the appropriate credentials. 5315331Samw * Please document any direct call to explain the reason 5325331Samw * for avoiding this wrapper. 5335331Samw * 5345331Samw * It is assumed that a reference exists on snode coming into this routine. 5355331Samw * 5365331Samw * *ret_snode is returned with a reference upon success. No reference is 5375331Samw * taken if an error is returned. 5385331Samw */ 5395331Samw int 5405331Samw smb_fsop_mkdir( 5416139Sjb150015 smb_request_t *sr, 5425331Samw cred_t *cr, 5439343SAfshin.Ardakani@Sun.COM smb_node_t *dnode, 5445331Samw char *name, 5455331Samw smb_attr_t *attr, 546*10001SJoyce.McIntosh@Sun.COM smb_node_t **ret_snode) 5475331Samw { 5485331Samw struct open_param *op = &sr->arg.open; 5495331Samw char *longname; 5505331Samw vnode_t *vp; 5515331Samw int flags = 0; 5525331Samw smb_fssd_t fs_sd; 5535331Samw uint32_t secinfo; 5545331Samw uint32_t status; 5555331Samw int rc; 5565331Samw ASSERT(cr); 5579343SAfshin.Ardakani@Sun.COM ASSERT(dnode); 5589343SAfshin.Ardakani@Sun.COM ASSERT(dnode->n_magic == SMB_NODE_MAGIC); 5599343SAfshin.Ardakani@Sun.COM ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING); 5605331Samw 5615331Samw ASSERT(ret_snode); 5625331Samw *ret_snode = 0; 5635331Samw 5645331Samw ASSERT(name); 5655331Samw if (*name == 0) 5665331Samw return (EINVAL); 5675331Samw 5685331Samw ASSERT(sr); 5695331Samw ASSERT(sr->tid_tree); 5707348SJose.Borrego@Sun.COM 5719343SAfshin.Ardakani@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0) 5727348SJose.Borrego@Sun.COM return (EACCES); 5737348SJose.Borrego@Sun.COM 5747348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 5755331Samw return (EROFS); 5769231SAfshin.Ardakani@Sun.COM if (SMB_TREE_SUPPORTS_CATIA(sr)) 5779231SAfshin.Ardakani@Sun.COM flags |= SMB_CATIA; 5785331Samw 5795331Samw if (smb_maybe_mangled_name(name)) { 5805331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 5819343SAfshin.Ardakani@Sun.COM rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN); 5825331Samw kmem_free(longname, MAXNAMELEN); 5835331Samw 5845331Samw /* 5855331Samw * If the name passed in by the client has an unmangled 5865331Samw * equivalent that is found in the specified directory, 5875331Samw * then the mkdir cannot succeed. Return EEXIST. 5885331Samw * 5895331Samw * Only if ENOENT is returned will a mkdir be attempted. 5905331Samw */ 5915331Samw 5925331Samw if (rc == 0) 5935331Samw rc = EEXIST; 5945331Samw 5955331Samw if (rc != ENOENT) 5965331Samw return (rc); 5975331Samw } 5985331Samw 5997348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 6005331Samw flags = SMB_IGNORE_CASE; 6015331Samw 6025521Sas200622 if (op->sd) { 6035331Samw /* 6045331Samw * SD sent by client in Windows format. Needs to be 6055331Samw * converted to FS format. No inheritance. 6065331Samw */ 6075521Sas200622 secinfo = smb_sd_get_secinfo(op->sd); 6085521Sas200622 smb_fssd_init(&fs_sd, secinfo, SMB_FSSD_FLAGS_DIR); 6095521Sas200622 6105521Sas200622 status = smb_sd_tofs(op->sd, &fs_sd); 6115331Samw if (status == NT_STATUS_SUCCESS) { 6129343SAfshin.Ardakani@Sun.COM rc = smb_fsop_create_with_sd(sr, cr, dnode, 613*10001SJoyce.McIntosh@Sun.COM name, attr, ret_snode, &fs_sd); 6145331Samw } 6155331Samw else 6165331Samw rc = EINVAL; 6175521Sas200622 smb_fssd_term(&fs_sd); 6185331Samw } else if (sr->tid_tree->t_acltype == ACE_T) { 6195331Samw /* 6205331Samw * No incoming SD and filesystem is ZFS 6215331Samw * Server applies Windows inheritance rules, 6225331Samw * see smb_fsop_sdinherit() comments as to why. 6235331Samw */ 6245521Sas200622 smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, SMB_FSSD_FLAGS_DIR); 6259343SAfshin.Ardakani@Sun.COM rc = smb_fsop_sdinherit(sr, dnode, &fs_sd); 6265331Samw if (rc == 0) { 6279343SAfshin.Ardakani@Sun.COM rc = smb_fsop_create_with_sd(sr, cr, dnode, 628*10001SJoyce.McIntosh@Sun.COM name, attr, ret_snode, &fs_sd); 6295331Samw } 6305331Samw 6315521Sas200622 smb_fssd_term(&fs_sd); 6325331Samw 6335331Samw } else { 6349343SAfshin.Ardakani@Sun.COM rc = smb_vop_mkdir(dnode->vp, name, attr, &vp, flags, cr, 6355772Sas200622 NULL); 6365331Samw 6375331Samw if (rc == 0) { 6385331Samw *ret_snode = smb_node_lookup(sr, op, cr, vp, name, 639*10001SJoyce.McIntosh@Sun.COM dnode, NULL); 6405331Samw 6418670SJose.Borrego@Sun.COM if (*ret_snode == NULL) 6425331Samw rc = ENOMEM; 6438670SJose.Borrego@Sun.COM 6448670SJose.Borrego@Sun.COM VN_RELE(vp); 6455331Samw } 6465331Samw } 6475331Samw 6485331Samw return (rc); 6495331Samw } 6505331Samw 6515331Samw /* 6525331Samw * smb_fsop_remove 6535331Samw * 6545331Samw * All SMB functions should use this wrapper to ensure that 6555331Samw * the the calls are performed with the appropriate credentials. 6565331Samw * Please document any direct call to explain the reason 6575331Samw * for avoiding this wrapper. 6585331Samw * 6595331Samw * It is assumed that a reference exists on snode coming into this routine. 6605331Samw * 6615331Samw * A null smb_request might be passed to this function. 6625331Samw */ 6635331Samw int 6645331Samw smb_fsop_remove( 6656139Sjb150015 smb_request_t *sr, 6666139Sjb150015 cred_t *cr, 6679343SAfshin.Ardakani@Sun.COM smb_node_t *dnode, 6686139Sjb150015 char *name, 6699231SAfshin.Ardakani@Sun.COM uint32_t flags) 6705331Samw { 6716139Sjb150015 smb_node_t *fnode; 6726139Sjb150015 char *longname; 6736139Sjb150015 char *fname; 6746139Sjb150015 char *sname; 6756139Sjb150015 int rc; 6765331Samw 6775331Samw ASSERT(cr); 6785331Samw /* 6795331Samw * The state of the node could be SMB_NODE_STATE_DESTROYING if this 6805331Samw * function is called during the deletion of the node (because of 6815331Samw * DELETE_ON_CLOSE). 6825331Samw */ 6839343SAfshin.Ardakani@Sun.COM ASSERT(dnode); 6849343SAfshin.Ardakani@Sun.COM ASSERT(dnode->n_magic == SMB_NODE_MAGIC); 6855331Samw 6869343SAfshin.Ardakani@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0 || 6878845Samw@Sun.COM SMB_TREE_HAS_ACCESS(sr, ACE_DELETE) == 0) 6885331Samw return (EACCES); 6895331Samw 6907348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 6915331Samw return (EROFS); 6925331Samw 6935331Samw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 6945331Samw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 6955331Samw 6969343SAfshin.Ardakani@Sun.COM if (dnode->flags & NODE_XATTR_DIR) { 6979343SAfshin.Ardakani@Sun.COM rc = smb_vop_stream_remove(dnode->dir_snode->vp, 6985967Scp160787 name, flags, cr); 6999343SAfshin.Ardakani@Sun.COM } else if (smb_is_stream_name(name)) { 7009343SAfshin.Ardakani@Sun.COM smb_stream_parse_name(name, fname, sname); 7018334SJose.Borrego@Sun.COM 7025967Scp160787 /* 7035331Samw * Look up the unnamed stream (i.e. fname). 7045331Samw * Unmangle processing will be done on fname 7055331Samw * as well as any link target. 7065331Samw */ 7075331Samw 7085331Samw rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, 709*10001SJoyce.McIntosh@Sun.COM sr->tid_tree->t_snode, dnode, fname, &fnode); 7105331Samw 7115331Samw if (rc != 0) { 7125331Samw kmem_free(fname, MAXNAMELEN); 7135331Samw kmem_free(sname, MAXNAMELEN); 7145331Samw return (rc); 7155331Samw } 7165331Samw 7175331Samw /* 7185331Samw * XXX 7195331Samw * Need to find out what permission is required by NTFS 7205331Samw * to remove a stream. 7215331Samw */ 7225772Sas200622 rc = smb_vop_stream_remove(fnode->vp, sname, flags, cr); 7235331Samw 7245331Samw smb_node_release(fnode); 7255331Samw } else { 7269343SAfshin.Ardakani@Sun.COM rc = smb_vop_remove(dnode->vp, name, flags, cr); 7275331Samw 7285331Samw if (rc == ENOENT) { 7295331Samw if (smb_maybe_mangled_name(name) == 0) { 7305331Samw kmem_free(fname, MAXNAMELEN); 7315331Samw kmem_free(sname, MAXNAMELEN); 7325331Samw return (rc); 7335331Samw } 7345331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 7355331Samw 7369343SAfshin.Ardakani@Sun.COM rc = smb_unmangle_name(dnode, name, 7379231SAfshin.Ardakani@Sun.COM longname, MAXNAMELEN); 7385331Samw 7395331Samw if (rc == 0) { 7405331Samw /* 7419231SAfshin.Ardakani@Sun.COM * longname is the real (case-sensitive) 7429231SAfshin.Ardakani@Sun.COM * on-disk name. 7435331Samw * We make sure we do a remove on this exact 7445331Samw * name, as the name was mangled and denotes 7455331Samw * a unique file. 7465331Samw */ 7475331Samw flags &= ~SMB_IGNORE_CASE; 7489343SAfshin.Ardakani@Sun.COM rc = smb_vop_remove(dnode->vp, longname, 7495772Sas200622 flags, cr); 7505331Samw } 7515331Samw 7525331Samw kmem_free(longname, MAXNAMELEN); 7535331Samw } 7545331Samw } 7555331Samw 7565331Samw kmem_free(fname, MAXNAMELEN); 7575331Samw kmem_free(sname, MAXNAMELEN); 7585331Samw return (rc); 7595331Samw } 7605331Samw 7615331Samw /* 7625331Samw * smb_fsop_remove_streams 7635331Samw * 7645331Samw * This function removes a file's streams without removing the 7655331Samw * file itself. 7665331Samw * 7678670SJose.Borrego@Sun.COM * It is assumed that fnode is not a link. 7685331Samw */ 7695331Samw int 7706139Sjb150015 smb_fsop_remove_streams(smb_request_t *sr, cred_t *cr, smb_node_t *fnode) 7715331Samw { 7728670SJose.Borrego@Sun.COM int rc, flags = 0; 7738670SJose.Borrego@Sun.COM uint16_t odid; 7748670SJose.Borrego@Sun.COM smb_odir_t *od; 7758670SJose.Borrego@Sun.COM smb_odirent_t *odirent; 7768670SJose.Borrego@Sun.COM boolean_t eos; 7775331Samw 7787348SJose.Borrego@Sun.COM ASSERT(sr); 7795331Samw ASSERT(cr); 7805331Samw ASSERT(fnode); 7815331Samw ASSERT(fnode->n_magic == SMB_NODE_MAGIC); 7825331Samw ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING); 7835331Samw 7849343SAfshin.Ardakani@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, fnode) == 0) { 7859343SAfshin.Ardakani@Sun.COM smbsr_errno(sr, EACCES); 7869343SAfshin.Ardakani@Sun.COM return (-1); 7879343SAfshin.Ardakani@Sun.COM } 7885331Samw 7899343SAfshin.Ardakani@Sun.COM if (SMB_TREE_IS_READONLY(sr)) { 7909343SAfshin.Ardakani@Sun.COM smbsr_errno(sr, EROFS); 7919343SAfshin.Ardakani@Sun.COM return (-1); 7929343SAfshin.Ardakani@Sun.COM } 7935331Samw 7947348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 7955331Samw flags = SMB_IGNORE_CASE; 7969343SAfshin.Ardakani@Sun.COM 7979231SAfshin.Ardakani@Sun.COM if (SMB_TREE_SUPPORTS_CATIA(sr)) 7989231SAfshin.Ardakani@Sun.COM flags |= SMB_CATIA; 7995331Samw 8009343SAfshin.Ardakani@Sun.COM if ((odid = smb_odir_openat(sr, fnode)) == 0) { 8019343SAfshin.Ardakani@Sun.COM smbsr_errno(sr, ENOENT); 8029343SAfshin.Ardakani@Sun.COM return (-1); 8039343SAfshin.Ardakani@Sun.COM } 8049343SAfshin.Ardakani@Sun.COM 8059343SAfshin.Ardakani@Sun.COM if ((od = smb_tree_lookup_odir(sr->tid_tree, odid)) == NULL) { 8069343SAfshin.Ardakani@Sun.COM smbsr_errno(sr, ENOENT); 8079343SAfshin.Ardakani@Sun.COM return (-1); 8089343SAfshin.Ardakani@Sun.COM } 8095331Samw 8108670SJose.Borrego@Sun.COM odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP); 8118670SJose.Borrego@Sun.COM for (;;) { 8128670SJose.Borrego@Sun.COM rc = smb_odir_read(sr, od, odirent, &eos); 8138670SJose.Borrego@Sun.COM if ((rc != 0) || (eos)) 8145331Samw break; 8158670SJose.Borrego@Sun.COM (void) smb_vop_remove(od->d_dnode->vp, odirent->od_name, 8168670SJose.Borrego@Sun.COM flags, cr); 8178670SJose.Borrego@Sun.COM } 8188670SJose.Borrego@Sun.COM kmem_free(odirent, sizeof (smb_odirent_t)); 8195331Samw 8209635SJoyce.McIntosh@Sun.COM smb_odir_close(od); 8218670SJose.Borrego@Sun.COM smb_odir_release(od); 8225331Samw return (rc); 8235331Samw } 8245331Samw 8255331Samw /* 8265331Samw * smb_fsop_rmdir 8275331Samw * 8285331Samw * All SMB functions should use this wrapper to ensure that 8295331Samw * the the calls are performed with the appropriate credentials. 8305331Samw * Please document any direct call to explain the reason 8315331Samw * for avoiding this wrapper. 8325331Samw * 8335331Samw * It is assumed that a reference exists on snode coming into this routine. 8345331Samw */ 8355331Samw int 8365331Samw smb_fsop_rmdir( 8376139Sjb150015 smb_request_t *sr, 8386139Sjb150015 cred_t *cr, 8399343SAfshin.Ardakani@Sun.COM smb_node_t *dnode, 8406139Sjb150015 char *name, 8419231SAfshin.Ardakani@Sun.COM uint32_t flags) 8425331Samw { 8436139Sjb150015 int rc; 8446139Sjb150015 char *longname; 8455331Samw 8465331Samw ASSERT(cr); 8475331Samw /* 8485331Samw * The state of the node could be SMB_NODE_STATE_DESTROYING if this 8495331Samw * function is called during the deletion of the node (because of 8505331Samw * DELETE_ON_CLOSE). 8515331Samw */ 8529343SAfshin.Ardakani@Sun.COM ASSERT(dnode); 8539343SAfshin.Ardakani@Sun.COM ASSERT(dnode->n_magic == SMB_NODE_MAGIC); 8545331Samw 8559343SAfshin.Ardakani@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0 || 8568845Samw@Sun.COM SMB_TREE_HAS_ACCESS(sr, ACE_DELETE_CHILD) == 0) 8575331Samw return (EACCES); 8585331Samw 8597348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 8605331Samw return (EROFS); 8615331Samw 8629343SAfshin.Ardakani@Sun.COM rc = smb_vop_rmdir(dnode->vp, name, flags, cr); 8635331Samw 8645331Samw if (rc == ENOENT) { 8655331Samw if (smb_maybe_mangled_name(name) == 0) 8665331Samw return (rc); 8675331Samw 8685331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 8699343SAfshin.Ardakani@Sun.COM rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN); 8705331Samw 8715331Samw if (rc == 0) { 8725331Samw /* 8739231SAfshin.Ardakani@Sun.COM * longname is the real (case-sensitive) 8749231SAfshin.Ardakani@Sun.COM * on-disk name. 8755331Samw * We make sure we do a rmdir on this exact 8765331Samw * name, as the name was mangled and denotes 8775331Samw * a unique directory. 8785331Samw */ 8795331Samw flags &= ~SMB_IGNORE_CASE; 8809343SAfshin.Ardakani@Sun.COM rc = smb_vop_rmdir(dnode->vp, longname, flags, cr); 8815331Samw } 8825331Samw 8835331Samw kmem_free(longname, MAXNAMELEN); 8845331Samw } 8855331Samw 8865331Samw return (rc); 8875331Samw } 8885331Samw 8895331Samw /* 8905331Samw * smb_fsop_getattr 8915331Samw * 8925331Samw * All SMB functions should use this wrapper to ensure that 8935331Samw * the the calls are performed with the appropriate credentials. 8945331Samw * Please document any direct call to explain the reason 8955331Samw * for avoiding this wrapper. 8965331Samw * 8975331Samw * It is assumed that a reference exists on snode coming into this routine. 8985331Samw */ 8995331Samw int 9006139Sjb150015 smb_fsop_getattr(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 9015331Samw smb_attr_t *attr) 9025331Samw { 9035331Samw smb_node_t *unnamed_node; 9045331Samw vnode_t *unnamed_vp = NULL; 9055331Samw uint32_t status; 9065331Samw uint32_t access = 0; 9075331Samw int flags = 0; 9085772Sas200622 int rc; 9095331Samw 9105331Samw ASSERT(cr); 9115331Samw ASSERT(snode); 9125331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 9135331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 9145331Samw 9158845Samw@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0 || 9168845Samw@Sun.COM SMB_TREE_HAS_ACCESS(sr, ACE_READ_ATTRIBUTES) == 0) 9175331Samw return (EACCES); 9185331Samw 919*10001SJoyce.McIntosh@Sun.COM /* sr could be NULL in some cases */ 920*10001SJoyce.McIntosh@Sun.COM if (sr && sr->fid_ofile) { 9215331Samw /* if uid and/or gid is requested */ 9225331Samw if (attr->sa_mask & (SMB_AT_UID|SMB_AT_GID)) 9235331Samw access |= READ_CONTROL; 9245331Samw 9255331Samw /* if anything else is also requested */ 9265331Samw if (attr->sa_mask & ~(SMB_AT_UID|SMB_AT_GID)) 9275331Samw access |= FILE_READ_ATTRIBUTES; 9285331Samw 9295331Samw status = smb_ofile_access(sr->fid_ofile, cr, access); 9305331Samw if (status != NT_STATUS_SUCCESS) 9315331Samw return (EACCES); 9325331Samw 9337348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, 9347348SJose.Borrego@Sun.COM SMB_TREE_ACEMASKONACCESS)) 9355331Samw flags = ATTR_NOACLCHECK; 9365331Samw } 9375331Samw 9385331Samw unnamed_node = SMB_IS_STREAM(snode); 9395331Samw 9405331Samw if (unnamed_node) { 9415331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 9425331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 9435331Samw unnamed_vp = unnamed_node->vp; 9445331Samw } 9455331Samw 9465772Sas200622 rc = smb_vop_getattr(snode->vp, unnamed_vp, attr, flags, cr); 9475772Sas200622 return (rc); 9485331Samw } 9495331Samw 9505331Samw /* 9519914Samw@Sun.COM * smb_fsop_link 9529914Samw@Sun.COM * 9539914Samw@Sun.COM * All SMB functions should use this smb_vop_link wrapper to ensure that 9549914Samw@Sun.COM * the smb_vop_link is performed with the appropriate credentials. 9559914Samw@Sun.COM * Please document any direct call to smb_vop_link to explain the reason 9569914Samw@Sun.COM * for avoiding this wrapper. 9579914Samw@Sun.COM * 9589914Samw@Sun.COM * It is assumed that references exist on from_dnode and to_dnode coming 9599914Samw@Sun.COM * into this routine. 9609914Samw@Sun.COM */ 9619914Samw@Sun.COM int 9629914Samw@Sun.COM smb_fsop_link(smb_request_t *sr, cred_t *cr, smb_node_t *to_dnode, 9639914Samw@Sun.COM smb_node_t *from_fnode, char *to_name) 9649914Samw@Sun.COM { 9659914Samw@Sun.COM char *longname = NULL; 9669914Samw@Sun.COM int flags = 0; 9679914Samw@Sun.COM int rc; 9689914Samw@Sun.COM 9699914Samw@Sun.COM ASSERT(sr); 9709914Samw@Sun.COM ASSERT(sr->tid_tree); 9719914Samw@Sun.COM ASSERT(cr); 9729914Samw@Sun.COM ASSERT(to_dnode); 9739914Samw@Sun.COM ASSERT(to_dnode->n_magic == SMB_NODE_MAGIC); 9749914Samw@Sun.COM ASSERT(to_dnode->n_state != SMB_NODE_STATE_DESTROYING); 9759914Samw@Sun.COM ASSERT(from_fnode); 9769914Samw@Sun.COM ASSERT(from_fnode->n_magic == SMB_NODE_MAGIC); 9779914Samw@Sun.COM ASSERT(from_fnode->n_state != SMB_NODE_STATE_DESTROYING); 9789914Samw@Sun.COM 9799914Samw@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, from_fnode) == 0) 9809914Samw@Sun.COM return (EACCES); 9819914Samw@Sun.COM 9829914Samw@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, to_dnode) == 0) 9839914Samw@Sun.COM return (EACCES); 9849914Samw@Sun.COM 9859914Samw@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 9869914Samw@Sun.COM return (EROFS); 9879914Samw@Sun.COM 9889914Samw@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 9899914Samw@Sun.COM flags = SMB_IGNORE_CASE; 9909914Samw@Sun.COM if (SMB_TREE_SUPPORTS_CATIA(sr)) 9919914Samw@Sun.COM flags |= SMB_CATIA; 9929914Samw@Sun.COM 9939914Samw@Sun.COM if (smb_maybe_mangled_name(to_name)) { 9949914Samw@Sun.COM longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 9959914Samw@Sun.COM rc = smb_unmangle_name(to_dnode, to_name, longname, MAXNAMELEN); 9969914Samw@Sun.COM kmem_free(longname, MAXNAMELEN); 9979914Samw@Sun.COM 9989914Samw@Sun.COM if (rc == 0) 9999914Samw@Sun.COM rc = EEXIST; 10009914Samw@Sun.COM if (rc != ENOENT) 10019914Samw@Sun.COM return (rc); 10029914Samw@Sun.COM } 10039914Samw@Sun.COM 10049914Samw@Sun.COM rc = smb_vop_link(to_dnode->vp, from_fnode->vp, to_name, flags, cr); 10059914Samw@Sun.COM return (rc); 10069914Samw@Sun.COM } 10079914Samw@Sun.COM 10089914Samw@Sun.COM /* 10095331Samw * smb_fsop_rename 10105331Samw * 10115331Samw * All SMB functions should use this smb_vop_rename wrapper to ensure that 10125331Samw * the smb_vop_rename is performed with the appropriate credentials. 10135331Samw * Please document any direct call to smb_vop_rename to explain the reason 10145331Samw * for avoiding this wrapper. 10155331Samw * 10169343SAfshin.Ardakani@Sun.COM * It is assumed that references exist on from_dnode and to_dnode coming 10175331Samw * into this routine. 10185331Samw */ 10195331Samw int 10205331Samw smb_fsop_rename( 10216139Sjb150015 smb_request_t *sr, 10225331Samw cred_t *cr, 10239343SAfshin.Ardakani@Sun.COM smb_node_t *from_dnode, 10245331Samw char *from_name, 10259343SAfshin.Ardakani@Sun.COM smb_node_t *to_dnode, 10265331Samw char *to_name) 10275331Samw { 10285331Samw smb_node_t *from_snode; 10295331Samw vnode_t *from_vp; 10309231SAfshin.Ardakani@Sun.COM int flags = 0, ret_flags; 10315331Samw int rc; 10328845Samw@Sun.COM boolean_t isdir; 10335331Samw 10345331Samw ASSERT(cr); 10359343SAfshin.Ardakani@Sun.COM ASSERT(from_dnode); 10369343SAfshin.Ardakani@Sun.COM ASSERT(from_dnode->n_magic == SMB_NODE_MAGIC); 10379343SAfshin.Ardakani@Sun.COM ASSERT(from_dnode->n_state != SMB_NODE_STATE_DESTROYING); 10385331Samw 10399343SAfshin.Ardakani@Sun.COM ASSERT(to_dnode); 10409343SAfshin.Ardakani@Sun.COM ASSERT(to_dnode->n_magic == SMB_NODE_MAGIC); 10419343SAfshin.Ardakani@Sun.COM ASSERT(to_dnode->n_state != SMB_NODE_STATE_DESTROYING); 10425331Samw 10439343SAfshin.Ardakani@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, from_dnode) == 0) 10445331Samw return (EACCES); 10455331Samw 10469343SAfshin.Ardakani@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, to_dnode) == 0) 10475331Samw return (EACCES); 10485331Samw 10495331Samw ASSERT(sr); 10505331Samw ASSERT(sr->tid_tree); 10517348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 10525331Samw return (EROFS); 10535331Samw 10545331Samw /* 10557348SJose.Borrego@Sun.COM * Note: There is no need to check SMB_TREE_IS_CASEINSENSITIVE 10565331Samw * here. 10575331Samw * 10585331Samw * A case-sensitive rename is always done in this routine 10595331Samw * because we are using the on-disk name from an earlier lookup. 10605331Samw * If a mangled name was passed in by the caller (denoting a 10615331Samw * deterministic lookup), then the exact file must be renamed 10625331Samw * (i.e. SMB_IGNORE_CASE must not be passed to VOP_RENAME, or 10635331Samw * else the underlying file system might return a "first-match" 10645331Samw * on this on-disk name, possibly resulting in the wrong file). 10655331Samw */ 10665331Samw 10679231SAfshin.Ardakani@Sun.COM if (SMB_TREE_SUPPORTS_CATIA(sr)) 10689231SAfshin.Ardakani@Sun.COM flags |= SMB_CATIA; 10699231SAfshin.Ardakani@Sun.COM 10705331Samw /* 10715331Samw * XXX: Lock required through smb_node_release() below? 10725331Samw */ 10735331Samw 10749343SAfshin.Ardakani@Sun.COM rc = smb_vop_lookup(from_dnode->vp, from_name, &from_vp, NULL, 10759231SAfshin.Ardakani@Sun.COM flags, &ret_flags, NULL, cr); 10765331Samw 10775331Samw if (rc != 0) 10785331Samw return (rc); 10795331Samw 10808845Samw@Sun.COM isdir = from_vp->v_type == VDIR; 10818845Samw@Sun.COM 10828845Samw@Sun.COM if ((isdir && SMB_TREE_HAS_ACCESS(sr, 10838845Samw@Sun.COM ACE_DELETE_CHILD | ACE_ADD_SUBDIRECTORY) != 10848845Samw@Sun.COM (ACE_DELETE_CHILD | ACE_ADD_SUBDIRECTORY)) || 10858845Samw@Sun.COM (!isdir && SMB_TREE_HAS_ACCESS(sr, ACE_DELETE | ACE_ADD_FILE) != 10868845Samw@Sun.COM (ACE_DELETE | ACE_ADD_FILE))) 10878845Samw@Sun.COM return (EACCES); 10888845Samw@Sun.COM 10899343SAfshin.Ardakani@Sun.COM rc = smb_vop_rename(from_dnode->vp, from_name, to_dnode->vp, 10905772Sas200622 to_name, flags, cr); 10915331Samw 10925331Samw if (rc == 0) { 10935331Samw from_snode = smb_node_lookup(sr, NULL, cr, from_vp, from_name, 1094*10001SJoyce.McIntosh@Sun.COM from_dnode, NULL); 10955331Samw 10965331Samw if (from_snode == NULL) { 10978670SJose.Borrego@Sun.COM rc = ENOMEM; 10988670SJose.Borrego@Sun.COM } else { 10999343SAfshin.Ardakani@Sun.COM smb_node_rename(from_dnode, from_snode, 11009343SAfshin.Ardakani@Sun.COM to_dnode, to_name); 11018670SJose.Borrego@Sun.COM smb_node_release(from_snode); 11025331Samw } 11035331Samw } 11048670SJose.Borrego@Sun.COM VN_RELE(from_vp); 11055331Samw 11065331Samw /* XXX: unlock */ 11075331Samw 11085331Samw return (rc); 11095331Samw } 11105331Samw 11115331Samw /* 11125331Samw * smb_fsop_setattr 11135331Samw * 11145331Samw * All SMB functions should use this wrapper to ensure that 11155331Samw * the the calls are performed with the appropriate credentials. 11165331Samw * Please document any direct call to explain the reason 11175331Samw * for avoiding this wrapper. 11185331Samw * 11195331Samw * It is assumed that a reference exists on snode coming into this routine. 11205331Samw * A null smb_request might be passed to this function. 11215331Samw */ 11225331Samw int 11235331Samw smb_fsop_setattr( 11246139Sjb150015 smb_request_t *sr, 11256139Sjb150015 cred_t *cr, 11266139Sjb150015 smb_node_t *snode, 1127*10001SJoyce.McIntosh@Sun.COM smb_attr_t *set_attr) 11285331Samw { 11295331Samw smb_node_t *unnamed_node; 11305331Samw vnode_t *unnamed_vp = NULL; 11315331Samw uint32_t status; 11327619SJose.Borrego@Sun.COM uint32_t access; 11335331Samw int rc = 0; 11345331Samw int flags = 0; 11357619SJose.Borrego@Sun.COM uint_t sa_mask; 11365331Samw 11375331Samw ASSERT(cr); 11385331Samw ASSERT(snode); 11395331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 11405331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 11415331Samw 11427348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0) 11435331Samw return (EACCES); 11445331Samw 11457348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 11465331Samw return (EROFS); 11475331Samw 11488845Samw@Sun.COM if (SMB_TREE_HAS_ACCESS(sr, 11498845Samw@Sun.COM ACE_WRITE_ATTRIBUTES | ACE_WRITE_NAMED_ATTRS) == 0) 11508845Samw@Sun.COM return (EACCES); 11518845Samw@Sun.COM 11527348SJose.Borrego@Sun.COM if (sr && (set_attr->sa_mask & SMB_AT_SIZE)) { 11537348SJose.Borrego@Sun.COM if (sr->fid_ofile) { 11547348SJose.Borrego@Sun.COM if (SMB_OFILE_IS_READONLY(sr->fid_ofile)) 11557348SJose.Borrego@Sun.COM return (EACCES); 11567348SJose.Borrego@Sun.COM } else { 11577348SJose.Borrego@Sun.COM if (SMB_PATHFILE_IS_READONLY(sr, snode)) 11587348SJose.Borrego@Sun.COM return (EACCES); 11597348SJose.Borrego@Sun.COM } 11607348SJose.Borrego@Sun.COM } 11617348SJose.Borrego@Sun.COM 11625331Samw /* sr could be NULL in some cases */ 11635331Samw if (sr && sr->fid_ofile) { 11647619SJose.Borrego@Sun.COM sa_mask = set_attr->sa_mask; 11657619SJose.Borrego@Sun.COM access = 0; 11667619SJose.Borrego@Sun.COM 11677619SJose.Borrego@Sun.COM if (sa_mask & SMB_AT_SIZE) { 11687619SJose.Borrego@Sun.COM access |= FILE_WRITE_DATA; 11697619SJose.Borrego@Sun.COM sa_mask &= ~SMB_AT_SIZE; 11707619SJose.Borrego@Sun.COM } 11717619SJose.Borrego@Sun.COM 11727619SJose.Borrego@Sun.COM if (sa_mask & (SMB_AT_UID|SMB_AT_GID)) { 11735331Samw access |= WRITE_OWNER; 11747619SJose.Borrego@Sun.COM sa_mask &= ~(SMB_AT_UID|SMB_AT_GID); 11757619SJose.Borrego@Sun.COM } 11767619SJose.Borrego@Sun.COM 11777619SJose.Borrego@Sun.COM if (sa_mask) 11785331Samw access |= FILE_WRITE_ATTRIBUTES; 11795331Samw 11805331Samw status = smb_ofile_access(sr->fid_ofile, cr, access); 11815331Samw if (status != NT_STATUS_SUCCESS) 11825331Samw return (EACCES); 11835331Samw 11847348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, 11857348SJose.Borrego@Sun.COM SMB_TREE_ACEMASKONACCESS)) 11865331Samw flags = ATTR_NOACLCHECK; 11875331Samw } 11885331Samw 11895331Samw unnamed_node = SMB_IS_STREAM(snode); 11905331Samw 11915331Samw if (unnamed_node) { 11925331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 11935331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 11945331Samw unnamed_vp = unnamed_node->vp; 11955331Samw } 11967757SJanice.Chang@Sun.COM 11977757SJanice.Chang@Sun.COM rc = smb_vop_setattr(snode->vp, unnamed_vp, set_attr, flags, cr); 11985331Samw return (rc); 11995331Samw } 12005331Samw 12015331Samw /* 12025331Samw * smb_fsop_read 12035331Samw * 12045331Samw * All SMB functions should use this wrapper to ensure that 12055331Samw * the the calls are performed with the appropriate credentials. 12065331Samw * Please document any direct call to explain the reason 12075331Samw * for avoiding this wrapper. 12085331Samw * 12095331Samw * It is assumed that a reference exists on snode coming into this routine. 12105331Samw */ 12115331Samw int 1212*10001SJoyce.McIntosh@Sun.COM smb_fsop_read(smb_request_t *sr, cred_t *cr, smb_node_t *snode, uio_t *uio) 12135331Samw { 12147348SJose.Borrego@Sun.COM caller_context_t ct; 12155772Sas200622 int svmand; 12165331Samw int rc; 12175331Samw 12185331Samw ASSERT(cr); 12195331Samw ASSERT(snode); 12205331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 12215331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 12225331Samw 12235331Samw ASSERT(sr); 12245331Samw ASSERT(sr->fid_ofile); 12255331Samw 12268845Samw@Sun.COM if (SMB_TREE_HAS_ACCESS(sr, ACE_READ_DATA) == 0) 12278845Samw@Sun.COM return (EACCES); 12288845Samw@Sun.COM 12295331Samw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_READ_DATA); 12305331Samw if (rc != NT_STATUS_SUCCESS) { 12315331Samw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_EXECUTE); 12325331Samw if (rc != NT_STATUS_SUCCESS) 12335331Samw return (EACCES); 12345331Samw } 12355331Samw 1236*10001SJoyce.McIntosh@Sun.COM /* 1237*10001SJoyce.McIntosh@Sun.COM * Streams permission are checked against the unnamed stream, 1238*10001SJoyce.McIntosh@Sun.COM * but in FS level they have their own permissions. To avoid 1239*10001SJoyce.McIntosh@Sun.COM * rejection by FS due to lack of permission on the actual 1240*10001SJoyce.McIntosh@Sun.COM * extended attr kcred is passed for streams. 1241*10001SJoyce.McIntosh@Sun.COM */ 1242*10001SJoyce.McIntosh@Sun.COM if (SMB_IS_STREAM(snode)) 12435331Samw cr = kcred; 12445331Samw 12455772Sas200622 smb_node_start_crit(snode, RW_READER); 12467348SJose.Borrego@Sun.COM rc = nbl_svmand(snode->vp, kcred, &svmand); 12475772Sas200622 if (rc) { 12485772Sas200622 smb_node_end_crit(snode); 12495772Sas200622 return (rc); 12505772Sas200622 } 12515772Sas200622 12527348SJose.Borrego@Sun.COM ct = smb_ct; 12537348SJose.Borrego@Sun.COM ct.cc_pid = sr->fid_ofile->f_uniqid; 12545772Sas200622 rc = nbl_lock_conflict(snode->vp, NBL_READ, uio->uio_loffset, 12557348SJose.Borrego@Sun.COM uio->uio_iov->iov_len, svmand, &ct); 12565772Sas200622 12575772Sas200622 if (rc) { 12585772Sas200622 smb_node_end_crit(snode); 12596432Sas200622 return (ERANGE); 12605772Sas200622 } 1261*10001SJoyce.McIntosh@Sun.COM 12625772Sas200622 rc = smb_vop_read(snode->vp, uio, cr); 12635772Sas200622 smb_node_end_crit(snode); 12645772Sas200622 12655331Samw return (rc); 12665331Samw } 12675331Samw 12685331Samw /* 12695331Samw * smb_fsop_write 12705331Samw * 12715331Samw * This is a wrapper function used for smb_write and smb_write_raw operations. 12725331Samw * 12735331Samw * It is assumed that a reference exists on snode coming into this routine. 12745331Samw */ 12755331Samw int 12765331Samw smb_fsop_write( 12776139Sjb150015 smb_request_t *sr, 12785331Samw cred_t *cr, 12795331Samw smb_node_t *snode, 12805331Samw uio_t *uio, 12815331Samw uint32_t *lcount, 12827052Samw int ioflag) 12835331Samw { 12847348SJose.Borrego@Sun.COM caller_context_t ct; 12855772Sas200622 int svmand; 12865331Samw int rc; 12875331Samw 12885331Samw ASSERT(cr); 12895331Samw ASSERT(snode); 12905331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 12915331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 12925331Samw 12935331Samw ASSERT(sr); 12945331Samw ASSERT(sr->tid_tree); 12955331Samw ASSERT(sr->fid_ofile); 12965331Samw 12977348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 12985331Samw return (EROFS); 12995772Sas200622 13008845Samw@Sun.COM if (SMB_OFILE_IS_READONLY(sr->fid_ofile) || 13018845Samw@Sun.COM SMB_TREE_HAS_ACCESS(sr, ACE_WRITE_DATA | ACE_APPEND_DATA) == 0) 13027348SJose.Borrego@Sun.COM return (EACCES); 13037348SJose.Borrego@Sun.COM 13045331Samw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_WRITE_DATA); 13055772Sas200622 if (rc != NT_STATUS_SUCCESS) { 13065772Sas200622 rc = smb_ofile_access(sr->fid_ofile, cr, FILE_APPEND_DATA); 13075772Sas200622 if (rc != NT_STATUS_SUCCESS) 13085772Sas200622 return (EACCES); 13095772Sas200622 } 13105331Samw 1311*10001SJoyce.McIntosh@Sun.COM /* 1312*10001SJoyce.McIntosh@Sun.COM * Streams permission are checked against the unnamed stream, 1313*10001SJoyce.McIntosh@Sun.COM * but in FS level they have their own permissions. To avoid 1314*10001SJoyce.McIntosh@Sun.COM * rejection by FS due to lack of permission on the actual 1315*10001SJoyce.McIntosh@Sun.COM * extended attr kcred is passed for streams. 1316*10001SJoyce.McIntosh@Sun.COM */ 1317*10001SJoyce.McIntosh@Sun.COM if (SMB_IS_STREAM(snode)) 13185331Samw cr = kcred; 13195331Samw 13205772Sas200622 smb_node_start_crit(snode, RW_READER); 13217348SJose.Borrego@Sun.COM rc = nbl_svmand(snode->vp, kcred, &svmand); 13225772Sas200622 if (rc) { 13235772Sas200622 smb_node_end_crit(snode); 13245772Sas200622 return (rc); 13255772Sas200622 } 13267348SJose.Borrego@Sun.COM 13277348SJose.Borrego@Sun.COM ct = smb_ct; 13287348SJose.Borrego@Sun.COM ct.cc_pid = sr->fid_ofile->f_uniqid; 13295772Sas200622 rc = nbl_lock_conflict(snode->vp, NBL_WRITE, uio->uio_loffset, 13307348SJose.Borrego@Sun.COM uio->uio_iov->iov_len, svmand, &ct); 13315772Sas200622 13325772Sas200622 if (rc) { 13335772Sas200622 smb_node_end_crit(snode); 13346432Sas200622 return (ERANGE); 13355772Sas200622 } 1336*10001SJoyce.McIntosh@Sun.COM 13377052Samw rc = smb_vop_write(snode->vp, uio, ioflag, lcount, cr); 13385772Sas200622 smb_node_end_crit(snode); 13395772Sas200622 13405331Samw return (rc); 13415331Samw } 13425331Samw 13435331Samw /* 13445331Samw * smb_fsop_statfs 13455331Samw * 13465331Samw * This is a wrapper function used for stat operations. 13475331Samw */ 13485331Samw int 13495331Samw smb_fsop_statfs( 13505331Samw cred_t *cr, 13515331Samw smb_node_t *snode, 13525331Samw struct statvfs64 *statp) 13535331Samw { 13545331Samw ASSERT(cr); 13555331Samw ASSERT(snode); 13565331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 13575331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 13585331Samw 13595331Samw return (smb_vop_statfs(snode->vp, statp, cr)); 13605331Samw } 13615331Samw 13625331Samw /* 13635331Samw * smb_fsop_access 13646700Sjm199354 * 13656700Sjm199354 * Named streams do not have separate permissions from the associated 13666700Sjm199354 * unnamed stream. Thus, if node is a named stream, the permissions 13676700Sjm199354 * check will be performed on the associated unnamed stream. 13686700Sjm199354 * 13696700Sjm199354 * However, our named streams do have their own quarantine attribute, 13706700Sjm199354 * separate from that on the unnamed stream. If READ or EXECUTE 13716700Sjm199354 * access has been requested on a named stream, an additional access 13726700Sjm199354 * check is performed on the named stream in case it has been 13736700Sjm199354 * quarantined. kcred is used to avoid issues with the permissions 13746700Sjm199354 * set on the extended attribute file representing the named stream. 13755331Samw */ 13765331Samw int 13775331Samw smb_fsop_access(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 13785331Samw uint32_t faccess) 13795331Samw { 13805331Samw int access = 0; 13815331Samw int error; 13825331Samw vnode_t *dir_vp; 13835331Samw boolean_t acl_check = B_TRUE; 13845331Samw smb_node_t *unnamed_node; 13855331Samw 13867348SJose.Borrego@Sun.COM ASSERT(sr); 13875331Samw ASSERT(cr); 13885331Samw ASSERT(snode); 13895331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 13905331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 13915331Samw 13925331Samw if (faccess == 0) 13935331Samw return (NT_STATUS_SUCCESS); 13945331Samw 13957348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) { 13965331Samw if (faccess & (FILE_WRITE_DATA|FILE_APPEND_DATA| 13975331Samw FILE_WRITE_EA|FILE_DELETE_CHILD|FILE_WRITE_ATTRIBUTES| 13985331Samw DELETE|WRITE_DAC|WRITE_OWNER)) { 13995331Samw return (NT_STATUS_ACCESS_DENIED); 14005331Samw } 14015331Samw } 14025331Samw 14035331Samw unnamed_node = SMB_IS_STREAM(snode); 14045331Samw if (unnamed_node) { 14055331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 14065331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 14076700Sjm199354 14086700Sjm199354 /* 14096700Sjm199354 * Perform VREAD access check on the named stream in case it 14106700Sjm199354 * is quarantined. kcred is passed to smb_vop_access so it 14116700Sjm199354 * doesn't fail due to lack of permission. 14126700Sjm199354 */ 14136700Sjm199354 if (faccess & (FILE_READ_DATA | FILE_EXECUTE)) { 14146700Sjm199354 error = smb_vop_access(snode->vp, VREAD, 14156700Sjm199354 0, NULL, kcred); 14166700Sjm199354 if (error) 14176700Sjm199354 return (NT_STATUS_ACCESS_DENIED); 14186700Sjm199354 } 14196700Sjm199354 14205331Samw /* 14215331Samw * Streams authorization should be performed against the 14225331Samw * unnamed stream. 14235331Samw */ 14245331Samw snode = unnamed_node; 14255331Samw } 14265331Samw 14275331Samw if (faccess & ACCESS_SYSTEM_SECURITY) { 14285331Samw /* 14295331Samw * This permission is required for reading/writing SACL and 14305331Samw * it's not part of DACL. It's only granted via proper 14315331Samw * privileges. 14325331Samw */ 14335331Samw if ((sr->uid_user->u_privileges & 14345331Samw (SMB_USER_PRIV_BACKUP | 14355331Samw SMB_USER_PRIV_RESTORE | 14365331Samw SMB_USER_PRIV_SECURITY)) == 0) 14375331Samw return (NT_STATUS_PRIVILEGE_NOT_HELD); 14385331Samw 14395331Samw faccess &= ~ACCESS_SYSTEM_SECURITY; 14405331Samw } 14415331Samw 14425331Samw /* Links don't have ACL */ 14437348SJose.Borrego@Sun.COM if ((!smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) || 1444*10001SJoyce.McIntosh@Sun.COM smb_node_is_link(snode)) 14455331Samw acl_check = B_FALSE; 14465331Samw 14478845Samw@Sun.COM /* 14488845Samw@Sun.COM * Use the most restrictive parts of both faccess and the 14498845Samw@Sun.COM * share access. An AND of the two value masks gives us that 14508845Samw@Sun.COM * since we've already converted to a mask of what we "can" 14518845Samw@Sun.COM * do. 14528845Samw@Sun.COM */ 14538845Samw@Sun.COM faccess &= sr->tid_tree->t_access; 14548845Samw@Sun.COM 14555331Samw if (acl_check) { 14565331Samw dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL; 14575331Samw error = smb_vop_access(snode->vp, faccess, V_ACE_MASK, dir_vp, 14585331Samw cr); 14595331Samw } else { 14605331Samw /* 14615331Samw * FS doesn't understand 32-bit mask, need to map 14625331Samw */ 14635331Samw if (faccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) 14645331Samw access |= VWRITE; 14655331Samw 14665331Samw if (faccess & FILE_READ_DATA) 14675331Samw access |= VREAD; 14685331Samw 14695331Samw if (faccess & FILE_EXECUTE) 14705331Samw access |= VEXEC; 14715331Samw 14725331Samw error = smb_vop_access(snode->vp, access, 0, NULL, cr); 14735331Samw } 14745331Samw 14755331Samw return ((error) ? NT_STATUS_ACCESS_DENIED : NT_STATUS_SUCCESS); 14765331Samw } 14775331Samw 14785331Samw /* 14795331Samw * smb_fsop_lookup_name() 14805331Samw * 14817961SNatalie.Li@Sun.COM * If name indicates that the file is a stream file, perform 14827961SNatalie.Li@Sun.COM * stream specific lookup, otherwise call smb_fsop_lookup. 14835331Samw * 14847961SNatalie.Li@Sun.COM * Return an error if the looked-up file is in outside the tree. 14857961SNatalie.Li@Sun.COM * (Required when invoked from open path.) 14865331Samw */ 14875331Samw 14885331Samw int 14895331Samw smb_fsop_lookup_name( 14906139Sjb150015 smb_request_t *sr, 14915331Samw cred_t *cr, 14925331Samw int flags, 14935331Samw smb_node_t *root_node, 14949343SAfshin.Ardakani@Sun.COM smb_node_t *dnode, 14955331Samw char *name, 1496*10001SJoyce.McIntosh@Sun.COM smb_node_t **ret_snode) 14975331Samw { 14986139Sjb150015 smb_node_t *fnode; 14996139Sjb150015 vnode_t *xattrdirvp; 15006139Sjb150015 vnode_t *vp; 15016139Sjb150015 char *od_name; 15026139Sjb150015 char *fname; 15036139Sjb150015 char *sname; 15046139Sjb150015 int rc; 15055331Samw 15065331Samw ASSERT(cr); 15079343SAfshin.Ardakani@Sun.COM ASSERT(dnode); 15089343SAfshin.Ardakani@Sun.COM ASSERT(dnode->n_magic == SMB_NODE_MAGIC); 15099343SAfshin.Ardakani@Sun.COM ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING); 15105331Samw 15115331Samw /* 15125331Samw * The following check is required for streams processing, below 15135331Samw */ 15145331Samw 15157348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 15165331Samw flags |= SMB_IGNORE_CASE; 15175331Samw 15185331Samw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 15195331Samw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 15205331Samw 15219343SAfshin.Ardakani@Sun.COM if (smb_is_stream_name(name)) { 15229343SAfshin.Ardakani@Sun.COM smb_stream_parse_name(name, fname, sname); 15238334SJose.Borrego@Sun.COM 15245331Samw /* 15255331Samw * Look up the unnamed stream (i.e. fname). 15265331Samw * Unmangle processing will be done on fname 15275331Samw * as well as any link target. 15285331Samw */ 1529*10001SJoyce.McIntosh@Sun.COM rc = smb_fsop_lookup(sr, cr, flags, root_node, dnode, 1530*10001SJoyce.McIntosh@Sun.COM fname, &fnode); 15315331Samw 15325331Samw if (rc != 0) { 15335331Samw kmem_free(fname, MAXNAMELEN); 15345331Samw kmem_free(sname, MAXNAMELEN); 15355331Samw return (rc); 15365331Samw } 15375331Samw 15385331Samw od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 15395331Samw 15405331Samw /* 15415331Samw * od_name is the on-disk name of the stream, except 15425331Samw * without the prepended stream prefix (SMB_STREAM_PREFIX) 15435331Samw */ 15445331Samw 15455331Samw /* 15465331Samw * XXX 15475331Samw * What permissions NTFS requires for stream lookup if any? 15485331Samw */ 15495331Samw rc = smb_vop_stream_lookup(fnode->vp, sname, &vp, od_name, 15505772Sas200622 &xattrdirvp, flags, root_node->vp, cr); 15515331Samw 15525331Samw if (rc != 0) { 15535331Samw smb_node_release(fnode); 15545331Samw kmem_free(fname, MAXNAMELEN); 15555331Samw kmem_free(sname, MAXNAMELEN); 15565331Samw kmem_free(od_name, MAXNAMELEN); 15575331Samw return (rc); 15585331Samw } 15595331Samw 15605331Samw *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, 1561*10001SJoyce.McIntosh@Sun.COM vp, od_name); 15625331Samw 15635331Samw kmem_free(od_name, MAXNAMELEN); 15645331Samw smb_node_release(fnode); 15658670SJose.Borrego@Sun.COM VN_RELE(xattrdirvp); 15668670SJose.Borrego@Sun.COM VN_RELE(vp); 15675331Samw 15685331Samw if (*ret_snode == NULL) { 15695331Samw kmem_free(fname, MAXNAMELEN); 15705331Samw kmem_free(sname, MAXNAMELEN); 15715331Samw return (ENOMEM); 15725331Samw } 15735331Samw } else { 15749343SAfshin.Ardakani@Sun.COM rc = smb_fsop_lookup(sr, cr, flags, root_node, dnode, name, 1575*10001SJoyce.McIntosh@Sun.COM ret_snode); 15765331Samw } 15775331Samw 15785331Samw if (rc == 0) { 15795331Samw ASSERT(ret_snode); 15807348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, *ret_snode) == 0) { 15815331Samw smb_node_release(*ret_snode); 15825331Samw *ret_snode = NULL; 15835331Samw rc = EACCES; 15845331Samw } 15855331Samw } 15865331Samw 15875331Samw kmem_free(fname, MAXNAMELEN); 15885331Samw kmem_free(sname, MAXNAMELEN); 15895331Samw 15905331Samw return (rc); 15915331Samw } 15925331Samw 15935331Samw /* 15945331Samw * smb_fsop_lookup 15955331Samw * 15965331Samw * All SMB functions should use this smb_vop_lookup wrapper to ensure that 15975331Samw * the smb_vop_lookup is performed with the appropriate credentials and using 15985331Samw * case insensitive compares. Please document any direct call to smb_vop_lookup 15995331Samw * to explain the reason for avoiding this wrapper. 16005331Samw * 16019343SAfshin.Ardakani@Sun.COM * It is assumed that a reference exists on dnode coming into this routine 16025331Samw * (and that it is safe from deallocation). 16035331Samw * 16045331Samw * Same with the root_node. 16055331Samw * 16065331Samw * *ret_snode is returned with a reference upon success. No reference is 16075331Samw * taken if an error is returned. 16085331Samw * 16095331Samw * Note: The returned ret_snode may be in a child mount. This is ok for 16108670SJose.Borrego@Sun.COM * readdir. 16115331Samw * 16127348SJose.Borrego@Sun.COM * Other smb_fsop_* routines will call SMB_TREE_CONTAINS_NODE() to prevent 16135331Samw * operations on files not in the parent mount. 16145331Samw */ 16155331Samw int 16165331Samw smb_fsop_lookup( 16176139Sjb150015 smb_request_t *sr, 16185331Samw cred_t *cr, 16195331Samw int flags, 16205331Samw smb_node_t *root_node, 16219343SAfshin.Ardakani@Sun.COM smb_node_t *dnode, 16225331Samw char *name, 1623*10001SJoyce.McIntosh@Sun.COM smb_node_t **ret_snode) 16245331Samw { 16255331Samw smb_node_t *lnk_target_node; 16265331Samw smb_node_t *lnk_dnode; 16275331Samw char *longname; 16285331Samw char *od_name; 16295331Samw vnode_t *vp; 16305331Samw int rc; 16319231SAfshin.Ardakani@Sun.COM int ret_flags; 16325331Samw 16335331Samw ASSERT(cr); 16349343SAfshin.Ardakani@Sun.COM ASSERT(dnode); 16359343SAfshin.Ardakani@Sun.COM ASSERT(dnode->n_magic == SMB_NODE_MAGIC); 16369343SAfshin.Ardakani@Sun.COM ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING); 16375331Samw 16385331Samw if (name == NULL) 16395331Samw return (EINVAL); 16405331Samw 16419343SAfshin.Ardakani@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0) 16425331Samw return (EACCES); 16435331Samw 16447348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 16455331Samw flags |= SMB_IGNORE_CASE; 16469231SAfshin.Ardakani@Sun.COM if (SMB_TREE_SUPPORTS_CATIA(sr)) 16479231SAfshin.Ardakani@Sun.COM flags |= SMB_CATIA; 16485331Samw 16495331Samw od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 16505331Samw 16519343SAfshin.Ardakani@Sun.COM rc = smb_vop_lookup(dnode->vp, name, &vp, od_name, flags, 16529231SAfshin.Ardakani@Sun.COM &ret_flags, root_node ? root_node->vp : NULL, cr); 16535331Samw 16545331Samw if (rc != 0) { 16555331Samw if (smb_maybe_mangled_name(name) == 0) { 16565331Samw kmem_free(od_name, MAXNAMELEN); 16575331Samw return (rc); 16585331Samw } 16595331Samw 16605331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 16619343SAfshin.Ardakani@Sun.COM rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN); 16625331Samw if (rc != 0) { 16635331Samw kmem_free(od_name, MAXNAMELEN); 16645331Samw kmem_free(longname, MAXNAMELEN); 16655331Samw return (rc); 16665331Samw } 16675331Samw 16685331Samw /* 16699231SAfshin.Ardakani@Sun.COM * longname is the real (case-sensitive) 16709231SAfshin.Ardakani@Sun.COM * on-disk name. 16715331Samw * We make sure we do a lookup on this exact 16725331Samw * name, as the name was mangled and denotes 16735331Samw * a unique file. 16745331Samw */ 16755331Samw 16765331Samw if (flags & SMB_IGNORE_CASE) 16775331Samw flags &= ~SMB_IGNORE_CASE; 16785331Samw 16799343SAfshin.Ardakani@Sun.COM rc = smb_vop_lookup(dnode->vp, longname, &vp, od_name, 16809231SAfshin.Ardakani@Sun.COM flags, &ret_flags, root_node ? root_node->vp : NULL, cr); 16815331Samw 16825331Samw kmem_free(longname, MAXNAMELEN); 16835331Samw 16845331Samw if (rc != 0) { 16855331Samw kmem_free(od_name, MAXNAMELEN); 16865331Samw return (rc); 16875331Samw } 16885331Samw } 16895331Samw 16905331Samw if ((flags & SMB_FOLLOW_LINKS) && (vp->v_type == VLNK)) { 16915331Samw 16929343SAfshin.Ardakani@Sun.COM rc = smb_pathname(sr, od_name, FOLLOW, root_node, dnode, 16935331Samw &lnk_dnode, &lnk_target_node, cr); 16945331Samw 16955331Samw if (rc != 0) { 16965331Samw /* 16975331Samw * The link is assumed to be for the last component 16985331Samw * of a path. Hence any ENOTDIR error will be returned 16995331Samw * as ENOENT. 17005331Samw */ 17015331Samw if (rc == ENOTDIR) 17025331Samw rc = ENOENT; 17035331Samw 17045331Samw VN_RELE(vp); 17055331Samw kmem_free(od_name, MAXNAMELEN); 17065331Samw return (rc); 17075331Samw } 17085331Samw 17095331Samw /* 17105331Samw * Release the original VLNK vnode 17115331Samw */ 17125331Samw 17135331Samw VN_RELE(vp); 17145331Samw vp = lnk_target_node->vp; 17155331Samw 17165331Samw rc = smb_vop_traverse_check(&vp); 17175331Samw 17185331Samw if (rc != 0) { 17195331Samw smb_node_release(lnk_dnode); 17205331Samw smb_node_release(lnk_target_node); 17215331Samw kmem_free(od_name, MAXNAMELEN); 17225331Samw return (rc); 17235331Samw } 17245331Samw 17255331Samw /* 17265331Samw * smb_vop_traverse_check() may have returned a different vnode 17275331Samw */ 17285331Samw 17295331Samw if (lnk_target_node->vp == vp) { 17305331Samw *ret_snode = lnk_target_node; 17315331Samw } else { 17325331Samw *ret_snode = smb_node_lookup(sr, NULL, cr, vp, 1733*10001SJoyce.McIntosh@Sun.COM lnk_target_node->od_name, lnk_dnode, NULL); 17348670SJose.Borrego@Sun.COM VN_RELE(vp); 17355331Samw 17368670SJose.Borrego@Sun.COM if (*ret_snode == NULL) 17375331Samw rc = ENOMEM; 17385331Samw smb_node_release(lnk_target_node); 17395331Samw } 17405331Samw 17415331Samw smb_node_release(lnk_dnode); 17425331Samw 17435331Samw } else { 17445331Samw 17455331Samw rc = smb_vop_traverse_check(&vp); 17465331Samw if (rc) { 17475331Samw VN_RELE(vp); 17485331Samw kmem_free(od_name, MAXNAMELEN); 17495331Samw return (rc); 17505331Samw } 17515331Samw 17525331Samw *ret_snode = smb_node_lookup(sr, NULL, cr, vp, od_name, 1753*10001SJoyce.McIntosh@Sun.COM dnode, NULL); 17548670SJose.Borrego@Sun.COM VN_RELE(vp); 17555331Samw 17568670SJose.Borrego@Sun.COM if (*ret_snode == NULL) 17575331Samw rc = ENOMEM; 17585331Samw } 17595331Samw 17605331Samw kmem_free(od_name, MAXNAMELEN); 17615331Samw return (rc); 17625331Samw } 17635331Samw 17645331Samw int /*ARGSUSED*/ 17655331Samw smb_fsop_commit(smb_request_t *sr, cred_t *cr, smb_node_t *snode) 17665331Samw { 17675331Samw ASSERT(cr); 17685331Samw ASSERT(snode); 17695331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 17705331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 17715331Samw 17725331Samw ASSERT(sr); 17735331Samw ASSERT(sr->tid_tree); 17747348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 17755331Samw return (EROFS); 17765331Samw 17775772Sas200622 return (smb_vop_commit(snode->vp, cr)); 17785331Samw } 17795331Samw 17805331Samw /* 17815331Samw * smb_fsop_aclread 17825331Samw * 17835331Samw * Retrieve filesystem ACL. Depends on requested ACLs in 17845331Samw * fs_sd->sd_secinfo, it'll set DACL and SACL pointers in 17855331Samw * fs_sd. Note that requesting a DACL/SACL doesn't mean that 17865331Samw * the corresponding field in fs_sd should be non-NULL upon 17875331Samw * return, since the target ACL might not contain that type of 17885331Samw * entries. 17895331Samw * 17905331Samw * Returned ACL is always in ACE_T (aka ZFS) format. 17915331Samw * If successful the allocated memory for the ACL should be freed 17925521Sas200622 * using smb_fsacl_free() or smb_fssd_term() 17935331Samw */ 17945331Samw int 17955331Samw smb_fsop_aclread(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 17965331Samw smb_fssd_t *fs_sd) 17975331Samw { 17985331Samw int error = 0; 17995331Samw int flags = 0; 18005331Samw int access = 0; 18015331Samw acl_t *acl; 18025331Samw smb_node_t *unnamed_node; 18035331Samw 18045331Samw ASSERT(cr); 18055331Samw 18068845Samw@Sun.COM if (SMB_TREE_HAS_ACCESS(sr, ACE_READ_ACL) == 0) 18078845Samw@Sun.COM return (EACCES); 18088845Samw@Sun.COM 18095331Samw if (sr->fid_ofile) { 18105331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 18115331Samw access = READ_CONTROL; 18125331Samw 18135331Samw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 18145331Samw access |= ACCESS_SYSTEM_SECURITY; 18155331Samw 18165331Samw error = smb_ofile_access(sr->fid_ofile, cr, access); 18175331Samw if (error != NT_STATUS_SUCCESS) { 18185331Samw return (EACCES); 18195331Samw } 18205331Samw } 18215331Samw 18225331Samw unnamed_node = SMB_IS_STREAM(snode); 18235331Samw if (unnamed_node) { 18245331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 18255331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 18265331Samw /* 18275331Samw * Streams don't have ACL, any read ACL attempt on a stream 18285331Samw * should be performed on the unnamed stream. 18295331Samw */ 18305331Samw snode = unnamed_node; 18315331Samw } 18325331Samw 18337348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) 18345331Samw flags = ATTR_NOACLCHECK; 18355331Samw 18365331Samw error = smb_vop_acl_read(snode->vp, &acl, flags, 18375772Sas200622 sr->tid_tree->t_acltype, cr); 18385331Samw if (error != 0) { 18395331Samw return (error); 18405331Samw } 18415331Samw 18425331Samw error = acl_translate(acl, _ACL_ACE_ENABLED, 18435331Samw (snode->vp->v_type == VDIR), fs_sd->sd_uid, fs_sd->sd_gid); 18445331Samw 18455331Samw if (error == 0) { 18465521Sas200622 smb_fsacl_split(acl, &fs_sd->sd_zdacl, &fs_sd->sd_zsacl, 18475331Samw fs_sd->sd_secinfo); 18485331Samw } 18495331Samw 18505331Samw acl_free(acl); 18515331Samw return (error); 18525331Samw } 18535331Samw 18545331Samw /* 18555331Samw * smb_fsop_aclwrite 18565331Samw * 18575331Samw * Stores the filesystem ACL provided in fs_sd->sd_acl. 18585331Samw */ 18595331Samw int 18605331Samw smb_fsop_aclwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 18615331Samw smb_fssd_t *fs_sd) 18625331Samw { 18635331Samw int target_flavor; 18645331Samw int error = 0; 18655331Samw int flags = 0; 18665331Samw int access = 0; 18675331Samw acl_t *acl, *dacl, *sacl; 18685331Samw smb_node_t *unnamed_node; 18695331Samw 18705331Samw ASSERT(cr); 18715331Samw 18725331Samw ASSERT(sr); 18735331Samw ASSERT(sr->tid_tree); 18747348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 18755331Samw return (EROFS); 18765331Samw 18778845Samw@Sun.COM if (SMB_TREE_HAS_ACCESS(sr, ACE_WRITE_ACL) == 0) 18788845Samw@Sun.COM return (EACCES); 18798845Samw@Sun.COM 18805331Samw if (sr->fid_ofile) { 18815331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 18825331Samw access = WRITE_DAC; 18835331Samw 18845331Samw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 18855331Samw access |= ACCESS_SYSTEM_SECURITY; 18865331Samw 18875331Samw error = smb_ofile_access(sr->fid_ofile, cr, access); 18885331Samw if (error != NT_STATUS_SUCCESS) 18895331Samw return (EACCES); 18905331Samw } 18915331Samw 18925331Samw switch (sr->tid_tree->t_acltype) { 18935331Samw case ACLENT_T: 18945331Samw target_flavor = _ACL_ACLENT_ENABLED; 18955331Samw break; 18965331Samw 18975331Samw case ACE_T: 18985331Samw target_flavor = _ACL_ACE_ENABLED; 18995331Samw break; 19005331Samw default: 19015331Samw return (EINVAL); 19025331Samw } 19035331Samw 19045331Samw unnamed_node = SMB_IS_STREAM(snode); 19055331Samw if (unnamed_node) { 19065331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 19075331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 19085331Samw /* 19095331Samw * Streams don't have ACL, any write ACL attempt on a stream 19105331Samw * should be performed on the unnamed stream. 19115331Samw */ 19125331Samw snode = unnamed_node; 19135331Samw } 19145331Samw 19155331Samw dacl = fs_sd->sd_zdacl; 19165331Samw sacl = fs_sd->sd_zsacl; 19175331Samw 19185331Samw ASSERT(dacl || sacl); 19195331Samw if ((dacl == NULL) && (sacl == NULL)) 19205331Samw return (EINVAL); 19215331Samw 19225331Samw if (dacl && sacl) 19235521Sas200622 acl = smb_fsacl_merge(dacl, sacl); 19245331Samw else if (dacl) 19255331Samw acl = dacl; 19265331Samw else 19275331Samw acl = sacl; 19285331Samw 19295331Samw error = acl_translate(acl, target_flavor, (snode->vp->v_type == VDIR), 19305331Samw fs_sd->sd_uid, fs_sd->sd_gid); 19315331Samw if (error == 0) { 19327348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, 19337348SJose.Borrego@Sun.COM SMB_TREE_ACEMASKONACCESS)) 19345331Samw flags = ATTR_NOACLCHECK; 19355331Samw 19365772Sas200622 error = smb_vop_acl_write(snode->vp, acl, flags, cr); 19375331Samw } 19385331Samw 19395331Samw if (dacl && sacl) 19405331Samw acl_free(acl); 19415331Samw 19425331Samw return (error); 19435331Samw } 19445331Samw 19455331Samw acl_type_t 19465331Samw smb_fsop_acltype(smb_node_t *snode) 19475331Samw { 19485331Samw return (smb_vop_acl_type(snode->vp)); 19495331Samw } 19505331Samw 19515331Samw /* 19525331Samw * smb_fsop_sdread 19535331Samw * 19545331Samw * Read the requested security descriptor items from filesystem. 19555331Samw * The items are specified in fs_sd->sd_secinfo. 19565331Samw */ 19575331Samw int 19585331Samw smb_fsop_sdread(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 19595331Samw smb_fssd_t *fs_sd) 19605331Samw { 19615331Samw int error = 0; 19625331Samw int getowner = 0; 19635331Samw cred_t *ga_cred; 19645331Samw smb_attr_t attr; 19655331Samw 19665331Samw ASSERT(cr); 19675331Samw ASSERT(fs_sd); 19685331Samw 19695331Samw /* 19705331Samw * File's uid/gid is fetched in two cases: 19715331Samw * 19725331Samw * 1. it's explicitly requested 19735331Samw * 19745331Samw * 2. target ACL is ACE_T (ZFS ACL). They're needed for 19755331Samw * owner@/group@ entries. In this case kcred should be used 19765331Samw * because uid/gid are fetched on behalf of smb server. 19775331Samw */ 19785331Samw if (fs_sd->sd_secinfo & (SMB_OWNER_SECINFO | SMB_GROUP_SECINFO)) { 19795331Samw getowner = 1; 19805331Samw ga_cred = cr; 19815331Samw } else if (sr->tid_tree->t_acltype == ACE_T) { 19825331Samw getowner = 1; 19835331Samw ga_cred = kcred; 19845331Samw } 19855331Samw 19865331Samw if (getowner) { 19875331Samw /* 19885331Samw * Windows require READ_CONTROL to read owner/group SID since 19895331Samw * they're part of Security Descriptor. 19905331Samw * ZFS only requires read_attribute. Need to have a explicit 19915331Samw * access check here. 19925331Samw */ 19935331Samw if (sr->fid_ofile == NULL) { 19945331Samw error = smb_fsop_access(sr, ga_cred, snode, 19955331Samw READ_CONTROL); 19965331Samw if (error) 19979914Samw@Sun.COM return (EACCES); 19985331Samw } 19995331Samw 20005331Samw attr.sa_mask = SMB_AT_UID | SMB_AT_GID; 20015331Samw error = smb_fsop_getattr(sr, ga_cred, snode, &attr); 20025331Samw if (error == 0) { 20035331Samw fs_sd->sd_uid = attr.sa_vattr.va_uid; 20045331Samw fs_sd->sd_gid = attr.sa_vattr.va_gid; 20055331Samw } else { 20065331Samw return (error); 20075331Samw } 20085331Samw } 20095331Samw 20105331Samw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 20115331Samw error = smb_fsop_aclread(sr, cr, snode, fs_sd); 20125331Samw } 20135331Samw 20145331Samw return (error); 20155331Samw } 20165331Samw 20175331Samw /* 20185331Samw * smb_fsop_sdmerge 20195331Samw * 20205331Samw * From SMB point of view DACL and SACL are two separate list 20215331Samw * which can be manipulated independently without one affecting 20225331Samw * the other, but entries for both DACL and SACL will end up 20235331Samw * in the same ACL if target filesystem supports ACE_T ACLs. 20245331Samw * 20255331Samw * So, if either DACL or SACL is present in the client set request 20265331Samw * the entries corresponding to the non-present ACL shouldn't 20275331Samw * be touched in the FS ACL. 20285331Samw * 20295331Samw * fs_sd parameter contains DACL and SACL specified by SMB 20305331Samw * client to be set on a file/directory. The client could 20315331Samw * specify both or one of these ACLs (if none is specified 20325331Samw * we don't get this far). When both DACL and SACL are given 20335331Samw * by client the existing ACL should be overwritten. If only 20345331Samw * one of them is specified the entries corresponding to the other 20355331Samw * ACL should not be touched. For example, if only DACL 20365331Samw * is specified in input fs_sd, the function reads audit entries 20375331Samw * of the existing ACL of the file and point fs_sd->sd_zsdacl 20385331Samw * pointer to the fetched SACL, this way when smb_fsop_sdwrite() 20395331Samw * function is called the passed fs_sd would point to the specified 20405331Samw * DACL by client and fetched SACL from filesystem, so the file 20415331Samw * will end up with correct ACL. 20425331Samw */ 20435331Samw static int 20445331Samw smb_fsop_sdmerge(smb_request_t *sr, smb_node_t *snode, smb_fssd_t *fs_sd) 20455331Samw { 20465331Samw smb_fssd_t cur_sd; 20475331Samw int error = 0; 20485331Samw 20495331Samw if (sr->tid_tree->t_acltype != ACE_T) 20505331Samw /* Don't bother if target FS doesn't support ACE_T */ 20515331Samw return (0); 20525331Samw 20535331Samw if ((fs_sd->sd_secinfo & SMB_ACL_SECINFO) != SMB_ACL_SECINFO) { 20545331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) { 20555331Samw /* 20565331Samw * Don't overwrite existing audit entries 20575331Samw */ 20585521Sas200622 smb_fssd_init(&cur_sd, SMB_SACL_SECINFO, 20595331Samw fs_sd->sd_flags); 20605331Samw 20615331Samw error = smb_fsop_sdread(sr, kcred, snode, &cur_sd); 20625331Samw if (error == 0) { 20635331Samw ASSERT(fs_sd->sd_zsacl == NULL); 20645331Samw fs_sd->sd_zsacl = cur_sd.sd_zsacl; 20655331Samw if (fs_sd->sd_zsacl && fs_sd->sd_zdacl) 20665331Samw fs_sd->sd_zsacl->acl_flags = 20675331Samw fs_sd->sd_zdacl->acl_flags; 20685331Samw } 20695331Samw } else { 20705331Samw /* 20715331Samw * Don't overwrite existing access entries 20725331Samw */ 20735521Sas200622 smb_fssd_init(&cur_sd, SMB_DACL_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_zdacl == NULL); 20795331Samw fs_sd->sd_zdacl = cur_sd.sd_zdacl; 20805331Samw if (fs_sd->sd_zdacl && fs_sd->sd_zsacl) 20815331Samw fs_sd->sd_zdacl->acl_flags = 20825331Samw fs_sd->sd_zsacl->acl_flags; 20835331Samw } 20845331Samw } 20855331Samw 20865331Samw if (error) 20875521Sas200622 smb_fssd_term(&cur_sd); 20885331Samw } 20895331Samw 20905331Samw return (error); 20915331Samw } 20925331Samw 20935331Samw /* 20945331Samw * smb_fsop_sdwrite 20955331Samw * 20965331Samw * Stores the given uid, gid and acl in filesystem. 20975331Samw * Provided items in fs_sd are specified by fs_sd->sd_secinfo. 20985331Samw * 20995331Samw * A SMB security descriptor could contain owner, primary group, 21005331Samw * DACL and SACL. Setting an SD should be atomic but here it has to 21015331Samw * be done via two separate FS operations: VOP_SETATTR and 21025331Samw * VOP_SETSECATTR. Therefore, this function has to simulate the 21035331Samw * atomicity as well as it can. 21047619SJose.Borrego@Sun.COM * 21057619SJose.Borrego@Sun.COM * Get the current uid, gid before setting the new uid/gid 21067619SJose.Borrego@Sun.COM * so if smb_fsop_aclwrite fails they can be restored. root cred is 21077619SJose.Borrego@Sun.COM * used to get currend uid/gid since this operation is performed on 21087619SJose.Borrego@Sun.COM * behalf of the server not the user. 21097619SJose.Borrego@Sun.COM * 21107619SJose.Borrego@Sun.COM * If setting uid/gid fails with EPERM it means that and invalid 21117619SJose.Borrego@Sun.COM * owner has been specified. Callers should translate this to 21127619SJose.Borrego@Sun.COM * STATUS_INVALID_OWNER which is not the normal mapping for EPERM 21137619SJose.Borrego@Sun.COM * in upper layers, so EPERM is mapped to EBADE. 21145331Samw */ 21155331Samw int 21165331Samw smb_fsop_sdwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 21175331Samw smb_fssd_t *fs_sd, int overwrite) 21185331Samw { 21195331Samw int error = 0; 21205331Samw int access = 0; 21215331Samw smb_attr_t set_attr; 21225331Samw smb_attr_t orig_attr; 21235331Samw 21245331Samw ASSERT(cr); 21255331Samw ASSERT(fs_sd); 21265331Samw 21275331Samw ASSERT(sr); 21285331Samw ASSERT(sr->tid_tree); 21297348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 21305331Samw return (EROFS); 21315331Samw 21325331Samw bzero(&set_attr, sizeof (smb_attr_t)); 21335331Samw 21345331Samw if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 21355331Samw set_attr.sa_vattr.va_uid = fs_sd->sd_uid; 21365331Samw set_attr.sa_mask |= SMB_AT_UID; 21377619SJose.Borrego@Sun.COM access |= WRITE_OWNER; 21385331Samw } 21395331Samw 21405331Samw if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 21415331Samw set_attr.sa_vattr.va_gid = fs_sd->sd_gid; 21425331Samw set_attr.sa_mask |= SMB_AT_GID; 21437619SJose.Borrego@Sun.COM access |= WRITE_OWNER; 21445331Samw } 21455331Samw 21465331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 21475331Samw access |= WRITE_DAC; 21485331Samw 21495331Samw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 21505331Samw access |= ACCESS_SYSTEM_SECURITY; 21515331Samw 21525331Samw if (sr->fid_ofile) 21535331Samw error = smb_ofile_access(sr->fid_ofile, cr, access); 21545331Samw else 21555331Samw error = smb_fsop_access(sr, cr, snode, access); 21565331Samw 21575331Samw if (error) 21585331Samw return (EACCES); 21595331Samw 21605331Samw if (set_attr.sa_mask) { 21615331Samw orig_attr.sa_mask = SMB_AT_UID | SMB_AT_GID; 21625331Samw error = smb_fsop_getattr(sr, kcred, snode, &orig_attr); 21637619SJose.Borrego@Sun.COM if (error == 0) { 2164*10001SJoyce.McIntosh@Sun.COM error = smb_fsop_setattr(sr, cr, snode, &set_attr); 21657619SJose.Borrego@Sun.COM if (error == EPERM) 21667619SJose.Borrego@Sun.COM error = EBADE; 21677619SJose.Borrego@Sun.COM } 21685331Samw 21695331Samw if (error) 21705331Samw return (error); 21715331Samw } 21725331Samw 21735331Samw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 21745331Samw if (overwrite == 0) { 21755331Samw error = smb_fsop_sdmerge(sr, snode, fs_sd); 21765331Samw if (error) 21775331Samw return (error); 21785331Samw } 21795331Samw 21805331Samw error = smb_fsop_aclwrite(sr, cr, snode, fs_sd); 21815331Samw if (error) { 21825331Samw /* 21835331Samw * Revert uid/gid changes if required. 21845331Samw */ 21855331Samw if (set_attr.sa_mask) { 21865331Samw orig_attr.sa_mask = set_attr.sa_mask; 21875331Samw (void) smb_fsop_setattr(sr, kcred, snode, 2188*10001SJoyce.McIntosh@Sun.COM &orig_attr); 21895331Samw } 21905331Samw } 21915331Samw } 21925331Samw 21935331Samw return (error); 21945331Samw } 21955331Samw 21965331Samw /* 21975331Samw * smb_fsop_sdinherit 21985331Samw * 21995331Samw * Inherit the security descriptor from the parent container. 22005331Samw * This function is called after FS has created the file/folder 22015331Samw * so if this doesn't do anything it means FS inheritance is 22025331Samw * in place. 22035331Samw * 22045331Samw * Do inheritance for ZFS internally. 22055331Samw * 22065331Samw * If we want to let ZFS does the inheritance the 22075331Samw * following setting should be true: 22085331Samw * 22095331Samw * - aclinherit = passthrough 22105331Samw * - aclmode = passthrough 22115331Samw * - smbd umask = 0777 22125331Samw * 22135331Samw * This will result in right effective permissions but 22145331Samw * ZFS will always add 6 ACEs for owner, owning group 22155331Samw * and others to be POSIX compliant. This is not what 22165331Samw * Windows clients/users expect, so we decided that CIFS 22175331Samw * implements Windows rules and overwrite whatever ZFS 22185331Samw * comes up with. This way we also don't have to care 22195331Samw * about ZFS aclinherit and aclmode settings. 22205331Samw */ 22215331Samw static int 22225331Samw smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, smb_fssd_t *fs_sd) 22235331Samw { 22245331Samw int is_dir; 22255521Sas200622 acl_t *dacl = NULL; 22265521Sas200622 acl_t *sacl = NULL; 22275331Samw ksid_t *owner_sid; 22285331Samw int error; 22295331Samw 22305331Samw ASSERT(fs_sd); 22315331Samw 22325331Samw if (sr->tid_tree->t_acltype != ACE_T) { 22335331Samw /* 22345331Samw * No forced inheritance for non-ZFS filesystems. 22355331Samw */ 22365331Samw fs_sd->sd_secinfo = 0; 22375331Samw return (0); 22385331Samw } 22395331Samw 22405331Samw 22415331Samw /* Fetch parent directory's ACL */ 22425331Samw error = smb_fsop_sdread(sr, kcred, dnode, fs_sd); 22435331Samw if (error) { 22445331Samw return (error); 22455331Samw } 22465331Samw 22475331Samw is_dir = (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR); 22485331Samw owner_sid = crgetsid(sr->user_cr, KSID_OWNER); 22495331Samw ASSERT(owner_sid); 22505521Sas200622 dacl = smb_fsacl_inherit(fs_sd->sd_zdacl, is_dir, SMB_DACL_SECINFO, 22515331Samw owner_sid->ks_id); 22525521Sas200622 sacl = smb_fsacl_inherit(fs_sd->sd_zsacl, is_dir, SMB_SACL_SECINFO, 22535331Samw (uid_t)-1); 22545331Samw 22555521Sas200622 if (sacl == NULL) 22565521Sas200622 fs_sd->sd_secinfo &= ~SMB_SACL_SECINFO; 22575521Sas200622 22585521Sas200622 smb_fsacl_free(fs_sd->sd_zdacl); 22595521Sas200622 smb_fsacl_free(fs_sd->sd_zsacl); 22605331Samw 22615331Samw fs_sd->sd_zdacl = dacl; 22625331Samw fs_sd->sd_zsacl = sacl; 22635331Samw 22645331Samw return (0); 22655331Samw } 22665331Samw 22675331Samw /* 22685331Samw * smb_fsop_eaccess 22695331Samw * 22705331Samw * Returns the effective permission of the given credential for the 22715331Samw * specified object. 22725331Samw * 22735331Samw * This is just a workaround. We need VFS/FS support for this. 22745331Samw */ 22755331Samw void 22765331Samw smb_fsop_eaccess(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 22775331Samw uint32_t *eaccess) 22785331Samw { 22795331Samw int access = 0; 22805331Samw vnode_t *dir_vp; 22815331Samw smb_node_t *unnamed_node; 22825331Samw 22835331Samw ASSERT(cr); 22845331Samw ASSERT(snode); 22855331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 22865331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 22875331Samw 22885331Samw unnamed_node = SMB_IS_STREAM(snode); 22895331Samw if (unnamed_node) { 22905331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 22915331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 22925331Samw /* 22935331Samw * Streams authorization should be performed against the 22945331Samw * unnamed stream. 22955331Samw */ 22965331Samw snode = unnamed_node; 22975331Samw } 22985331Samw 22997348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) { 23005331Samw dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL; 23015331Samw smb_vop_eaccess(snode->vp, (int *)eaccess, V_ACE_MASK, dir_vp, 23025331Samw cr); 23035331Samw return; 23045331Samw } 23055331Samw 23065331Samw /* 23075331Samw * FS doesn't understand 32-bit mask 23085331Samw */ 23095331Samw smb_vop_eaccess(snode->vp, &access, 0, NULL, cr); 23108845Samw@Sun.COM access &= sr->tid_tree->t_access; 23115331Samw 23125331Samw *eaccess = READ_CONTROL | FILE_READ_EA | FILE_READ_ATTRIBUTES; 23135331Samw 23145331Samw if (access & VREAD) 23155331Samw *eaccess |= FILE_READ_DATA; 23165331Samw 23175331Samw if (access & VEXEC) 23185331Samw *eaccess |= FILE_EXECUTE; 23195331Samw 23205331Samw if (access & VWRITE) 23215331Samw *eaccess |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | 23225331Samw FILE_WRITE_EA | FILE_APPEND_DATA | FILE_DELETE_CHILD; 23235331Samw } 23245521Sas200622 23255772Sas200622 /* 23265772Sas200622 * smb_fsop_shrlock 23275772Sas200622 * 23285772Sas200622 * For the current open request, check file sharing rules 23295772Sas200622 * against existing opens. 23305772Sas200622 * 23315772Sas200622 * Returns NT_STATUS_SHARING_VIOLATION if there is any 23325772Sas200622 * sharing conflict. Returns NT_STATUS_SUCCESS otherwise. 23335772Sas200622 * 23345772Sas200622 * Full system-wide share reservation synchronization is available 23355772Sas200622 * when the nbmand (non-blocking mandatory) mount option is set 23365772Sas200622 * (i.e. nbl_need_crit() is true) and nbmand critical regions are used. 23375772Sas200622 * This provides synchronization with NFS and local processes. The 23385772Sas200622 * critical regions are entered in VOP_SHRLOCK()/fs_shrlock() (called 23395772Sas200622 * from smb_open_subr()/smb_fsop_shrlock()/smb_vop_shrlock()) as well 23405772Sas200622 * as the CIFS rename and delete paths. 23415772Sas200622 * 23425772Sas200622 * The CIFS server will also enter the nbl critical region in the open, 23435772Sas200622 * rename, and delete paths when nbmand is not set. There is limited 23445772Sas200622 * coordination with local and VFS share reservations in this case. 23455772Sas200622 * Note that when the nbmand mount option is not set, the VFS layer 23465772Sas200622 * only processes advisory reservations and the delete mode is not checked. 23475772Sas200622 * 23485772Sas200622 * Whether or not the nbmand mount option is set, intra-CIFS share 23495772Sas200622 * checking is done in the open, delete, and rename paths using a CIFS 23505772Sas200622 * critical region (node->n_share_lock). 23515772Sas200622 */ 23525772Sas200622 23535772Sas200622 uint32_t 23546139Sjb150015 smb_fsop_shrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid, 23555772Sas200622 uint32_t desired_access, uint32_t share_access) 23565772Sas200622 { 23575772Sas200622 int rc; 23585772Sas200622 2359*10001SJoyce.McIntosh@Sun.COM if (smb_node_is_dir(node)) 23605772Sas200622 return (NT_STATUS_SUCCESS); 23615772Sas200622 23625772Sas200622 /* Allow access if the request is just for meta data */ 23635772Sas200622 if ((desired_access & FILE_DATA_ALL) == 0) 23645772Sas200622 return (NT_STATUS_SUCCESS); 23655772Sas200622 23665772Sas200622 rc = smb_node_open_check(node, cr, desired_access, share_access); 23675772Sas200622 if (rc) 23685772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 23695772Sas200622 23705772Sas200622 rc = smb_vop_shrlock(node->vp, uniq_fid, desired_access, share_access, 23715772Sas200622 cr); 23725772Sas200622 if (rc) 23735772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 23745772Sas200622 23755772Sas200622 return (NT_STATUS_SUCCESS); 23765772Sas200622 } 23775772Sas200622 23785521Sas200622 void 23795772Sas200622 smb_fsop_unshrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid) 23805521Sas200622 { 2381*10001SJoyce.McIntosh@Sun.COM if (smb_node_is_dir(node)) 23825772Sas200622 return; 23835772Sas200622 23845772Sas200622 (void) smb_vop_unshrlock(node->vp, uniq_fid, cr); 23855772Sas200622 } 23866600Sas200622 23876600Sas200622 int 23886600Sas200622 smb_fsop_frlock(smb_node_t *node, smb_lock_t *lock, boolean_t unlock, 23896600Sas200622 cred_t *cr) 23906600Sas200622 { 23916600Sas200622 flock64_t bf; 23926600Sas200622 int flag = F_REMOTELOCK; 23936600Sas200622 23946771Sjb150015 /* 23956771Sjb150015 * VOP_FRLOCK() will not be called if: 23966771Sjb150015 * 23976771Sjb150015 * 1) The lock has a range of zero bytes. The semantics of Windows and 23986771Sjb150015 * POSIX are different. In the case of POSIX it asks for the locking 23996771Sjb150015 * of all the bytes from the offset provided until the end of the 24006771Sjb150015 * file. In the case of Windows a range of zero locks nothing and 24016771Sjb150015 * doesn't conflict with any other lock. 24026771Sjb150015 * 24036771Sjb150015 * 2) The lock rolls over (start + lenght < start). Solaris will assert 24046771Sjb150015 * if such a request is submitted. This will not create 24056771Sjb150015 * incompatibilities between POSIX and Windows. In the Windows world, 24066771Sjb150015 * if a client submits such a lock, the server will not lock any 24076771Sjb150015 * bytes. Interestingly if the same lock (same offset and length) is 24086771Sjb150015 * resubmitted Windows will consider that there is an overlap and 24096771Sjb150015 * the granting rules will then apply. 24106771Sjb150015 */ 24116771Sjb150015 if ((lock->l_length == 0) || 24126771Sjb150015 ((lock->l_start + lock->l_length - 1) < lock->l_start)) 24136771Sjb150015 return (0); 24146771Sjb150015 24156600Sas200622 bzero(&bf, sizeof (bf)); 24166600Sas200622 24176600Sas200622 if (unlock) { 24186600Sas200622 bf.l_type = F_UNLCK; 24196600Sas200622 } else if (lock->l_type == SMB_LOCK_TYPE_READONLY) { 24206600Sas200622 bf.l_type = F_RDLCK; 24216600Sas200622 flag |= FREAD; 24226600Sas200622 } else if (lock->l_type == SMB_LOCK_TYPE_READWRITE) { 24236600Sas200622 bf.l_type = F_WRLCK; 24246600Sas200622 flag |= FWRITE; 24256600Sas200622 } 24266600Sas200622 24276600Sas200622 bf.l_start = lock->l_start; 24286600Sas200622 bf.l_len = lock->l_length; 24297348SJose.Borrego@Sun.COM bf.l_pid = lock->l_file->f_uniqid; 24306600Sas200622 bf.l_sysid = smb_ct.cc_sysid; 24316600Sas200622 24326600Sas200622 return (smb_vop_frlock(node->vp, cr, flag, &bf)); 24336600Sas200622 } 2434