1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21da6c28aaSamw /* 227f667e74Sjose borrego * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23da6c28aaSamw * Use is subject to license terms. 24da6c28aaSamw */ 25da6c28aaSamw 26da6c28aaSamw #include <sys/sid.h> 27dc20a302Sas #include <sys/nbmlock.h> 28da6c28aaSamw #include <smbsrv/smb_fsops.h> 2955bf511dSas #include <smbsrv/smb_kproto.h> 3055bf511dSas #include <smbsrv/ntstatus.h> 3155bf511dSas #include <smbsrv/ntaccess.h> 32dc20a302Sas #include <smbsrv/smb_incl.h> 33da6c28aaSamw #include <acl/acl_common.h> 34dc20a302Sas #include <sys/fcntl.h> 35dc20a302Sas #include <sys/flock.h> 36dc20a302Sas #include <fs/fs_subr.h> 37da6c28aaSamw 38faa1795aSjb extern caller_context_t smb_ct; 39faa1795aSjb 408c10a865Sas extern int smb_fem_oplock_install(smb_node_t *); 418c10a865Sas extern void smb_fem_oplock_uninstall(smb_node_t *); 428c10a865Sas 438c10a865Sas extern int smb_vop_other_opens(vnode_t *, int); 448c10a865Sas 45*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int smb_fsop_create_stream(smb_request_t *, cred_t *, smb_node_t *, 46*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States char *, char *, int, smb_attr_t *, smb_node_t **, smb_attr_t *); 47*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 48*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int smb_fsop_create_file(smb_request_t *, cred_t *, smb_node_t *, 49*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States char *, int, smb_attr_t *, smb_node_t **, smb_attr_t *); 50*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 51*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int smb_fsop_create_with_sd(smb_request_t *, cred_t *, smb_node_t *, 52*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States char *, smb_attr_t *, smb_node_t **, smb_attr_t *, smb_fssd_t *); 53*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 54*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int smb_fsop_sdinherit(smb_request_t *, smb_node_t *, smb_fssd_t *); 55da6c28aaSamw 56da6c28aaSamw /* 57da6c28aaSamw * The smb_fsop_* functions have knowledge of CIFS semantics. 58da6c28aaSamw * 59da6c28aaSamw * The smb_vop_* functions have minimal knowledge of CIFS semantics and 60da6c28aaSamw * serve as an interface to the VFS layer. 61da6c28aaSamw * 62da6c28aaSamw * Hence, smb_request_t and smb_node_t structures should not be passed 63da6c28aaSamw * from the smb_fsop_* layer to the smb_vop_* layer. 64da6c28aaSamw * 65da6c28aaSamw * In general, CIFS service code should only ever call smb_fsop_* 66da6c28aaSamw * functions directly, and never smb_vop_* functions directly. 67da6c28aaSamw * 68da6c28aaSamw * smb_fsop_* functions should call smb_vop_* functions where possible, instead 69da6c28aaSamw * of their smb_fsop_* counterparts. However, there are times when 70da6c28aaSamw * this cannot be avoided. 71da6c28aaSamw */ 72da6c28aaSamw 73da6c28aaSamw /* 74da6c28aaSamw * Note: Stream names cannot be mangled. 75da6c28aaSamw */ 76da6c28aaSamw 778c10a865Sas /* 788c10a865Sas * smb_fsop_amask_to_omode 798c10a865Sas * 808c10a865Sas * Convert the access mask to the open mode (for use 818c10a865Sas * with the VOP_OPEN call). 828c10a865Sas * 838c10a865Sas * Note that opening a file for attribute only access 848c10a865Sas * will also translate into an FREAD or FWRITE open mode 858c10a865Sas * (i.e., it's not just for data). 868c10a865Sas * 878c10a865Sas * This is needed so that opens are tracked appropriately 888c10a865Sas * for oplock processing. 898c10a865Sas */ 908c10a865Sas 91da6c28aaSamw int 928c10a865Sas smb_fsop_amask_to_omode(uint32_t access) 93da6c28aaSamw { 948c10a865Sas int mode = 0; 958c10a865Sas 968c10a865Sas if (access & (FILE_READ_DATA | FILE_EXECUTE | 978c10a865Sas FILE_READ_ATTRIBUTES | FILE_READ_EA)) 988c10a865Sas mode |= FREAD; 99da6c28aaSamw 1008c10a865Sas if (access & (FILE_WRITE_DATA | FILE_APPEND_DATA | 1018c10a865Sas FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA)) 1028c10a865Sas mode |= FWRITE; 1038c10a865Sas 1048c10a865Sas if (access & FILE_APPEND_DATA) 1058c10a865Sas mode |= FAPPEND; 1068c10a865Sas 1078c10a865Sas return (mode); 1088c10a865Sas } 109da6c28aaSamw 1108c10a865Sas int 1118c10a865Sas smb_fsop_open(smb_node_t *node, int mode, cred_t *cred) 1128c10a865Sas { 113da6c28aaSamw /* 1148c10a865Sas * Assuming that the same vnode is returned as we had before. 1158c10a865Sas * (I.e., with certain types of files or file systems, a 1168c10a865Sas * different vnode might be returned by VOP_OPEN) 117da6c28aaSamw */ 1188c10a865Sas return (smb_vop_open(&node->vp, mode, cred)); 119da6c28aaSamw } 120da6c28aaSamw 121c8ec8eeaSjose borrego void 1228c10a865Sas smb_fsop_close(smb_node_t *node, int mode, cred_t *cred) 123da6c28aaSamw { 124c8ec8eeaSjose borrego smb_vop_close(node->vp, mode, cred); 125da6c28aaSamw } 126da6c28aaSamw 1278c10a865Sas int 1288c10a865Sas smb_fsop_oplock_install(smb_node_t *node, int mode) 129da6c28aaSamw { 1308c10a865Sas int rc; 131da6c28aaSamw 1328c10a865Sas if (smb_vop_other_opens(node->vp, mode)) 1338c10a865Sas return (EMFILE); 134da6c28aaSamw 1358c10a865Sas if ((rc = smb_fem_oplock_install(node))) 1368c10a865Sas return (rc); 137da6c28aaSamw 1388c10a865Sas if (smb_vop_other_opens(node->vp, mode)) { 1398c10a865Sas (void) smb_fem_oplock_uninstall(node); 1408c10a865Sas return (EMFILE); 1418c10a865Sas } 142da6c28aaSamw 1438c10a865Sas return (0); 1448c10a865Sas } 1458c10a865Sas 1468c10a865Sas void 1478c10a865Sas smb_fsop_oplock_uninstall(smb_node_t *node) 1488c10a865Sas { 1498c10a865Sas smb_fem_oplock_uninstall(node); 150da6c28aaSamw } 151da6c28aaSamw 152da6c28aaSamw static int 153*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_fsop_create_with_sd(smb_request_t *sr, cred_t *cr, 154*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_t *dnode, char *name, 155*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_attr_t *attr, smb_node_t **ret_snode, smb_attr_t *ret_attr, 156*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_fssd_t *fs_sd) 157da6c28aaSamw { 158da6c28aaSamw vsecattr_t *vsap; 159da6c28aaSamw vsecattr_t vsecattr; 160da6c28aaSamw acl_t *acl, *dacl, *sacl; 161da6c28aaSamw smb_attr_t set_attr; 162da6c28aaSamw vnode_t *vp; 163da6c28aaSamw int aclbsize = 0; /* size of acl list in bytes */ 164da6c28aaSamw int flags = 0; 165da6c28aaSamw int rc; 1662c1b14e5Sjose borrego boolean_t is_dir; 167da6c28aaSamw 168da6c28aaSamw ASSERT(fs_sd); 169da6c28aaSamw 170c8ec8eeaSjose borrego if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 171da6c28aaSamw flags = SMB_IGNORE_CASE; 1728b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_SUPPORTS_CATIA(sr)) 1738b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States flags |= SMB_CATIA; 174da6c28aaSamw 175da6c28aaSamw ASSERT(cr); 176da6c28aaSamw 177da6c28aaSamw is_dir = ((fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR) != 0); 178da6c28aaSamw 179c8ec8eeaSjose borrego if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACLONCREATE)) { 180da6c28aaSamw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 181da6c28aaSamw dacl = fs_sd->sd_zdacl; 182da6c28aaSamw sacl = fs_sd->sd_zsacl; 183da6c28aaSamw ASSERT(dacl || sacl); 184da6c28aaSamw if (dacl && sacl) { 18555bf511dSas acl = smb_fsacl_merge(dacl, sacl); 186da6c28aaSamw } else if (dacl) { 187da6c28aaSamw acl = dacl; 188da6c28aaSamw } else { 189da6c28aaSamw acl = sacl; 190da6c28aaSamw } 191da6c28aaSamw 19255bf511dSas rc = smb_fsacl_to_vsa(acl, &vsecattr, &aclbsize); 193da6c28aaSamw 194da6c28aaSamw if (dacl && sacl) 195da6c28aaSamw acl_free(acl); 196da6c28aaSamw 1972c1b14e5Sjose borrego if (rc != 0) 198da6c28aaSamw return (rc); 199da6c28aaSamw 200da6c28aaSamw vsap = &vsecattr; 2012c1b14e5Sjose borrego } else { 202da6c28aaSamw vsap = NULL; 2032c1b14e5Sjose borrego } 204da6c28aaSamw 205743a77edSAlan Wright /* The tree ACEs may prevent a create */ 206743a77edSAlan Wright rc = EACCES; 207da6c28aaSamw if (is_dir) { 208743a77edSAlan Wright if (SMB_TREE_HAS_ACCESS(sr, ACE_ADD_SUBDIRECTORY) != 0) 209*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_mkdir(dnode->vp, name, attr, 210743a77edSAlan Wright &vp, flags, cr, vsap); 211da6c28aaSamw } else { 212743a77edSAlan Wright if (SMB_TREE_HAS_ACCESS(sr, ACE_ADD_FILE) != 0) 213*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_create(dnode->vp, name, attr, 214743a77edSAlan Wright &vp, flags, cr, vsap); 215da6c28aaSamw } 216da6c28aaSamw 217da6c28aaSamw if (vsap != NULL) 218da6c28aaSamw kmem_free(vsap->vsa_aclentp, aclbsize); 219da6c28aaSamw 220da6c28aaSamw if (rc != 0) 221da6c28aaSamw return (rc); 222da6c28aaSamw 223da6c28aaSamw set_attr.sa_mask = 0; 224da6c28aaSamw 225da6c28aaSamw /* 226da6c28aaSamw * Ideally we should be able to specify the owner and owning 227da6c28aaSamw * group at create time along with the ACL. Since we cannot 228da6c28aaSamw * do that right now, kcred is passed to smb_vop_setattr so it 229da6c28aaSamw * doesn't fail due to lack of permission. 230da6c28aaSamw */ 231da6c28aaSamw if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 232da6c28aaSamw set_attr.sa_vattr.va_uid = fs_sd->sd_uid; 233da6c28aaSamw set_attr.sa_mask |= SMB_AT_UID; 234da6c28aaSamw } 235da6c28aaSamw 236da6c28aaSamw if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 237da6c28aaSamw set_attr.sa_vattr.va_gid = fs_sd->sd_gid; 238da6c28aaSamw set_attr.sa_mask |= SMB_AT_GID; 239da6c28aaSamw } 240da6c28aaSamw 2419660e5cbSJanice Chang if (set_attr.sa_mask) 2429660e5cbSJanice Chang rc = smb_vop_setattr(vp, NULL, &set_attr, 0, kcred); 243da6c28aaSamw 2442c1b14e5Sjose borrego if (rc == 0) { 2452c1b14e5Sjose borrego *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp, 246*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States name, dnode, NULL, ret_attr); 2472c1b14e5Sjose borrego 2487f667e74Sjose borrego if (*ret_snode == NULL) 2492c1b14e5Sjose borrego rc = ENOMEM; 2507f667e74Sjose borrego 2517f667e74Sjose borrego VN_RELE(vp); 2522c1b14e5Sjose borrego } 253da6c28aaSamw } else { 254da6c28aaSamw /* 255da6c28aaSamw * For filesystems that don't support ACL-on-create, try 256da6c28aaSamw * to set the specified SD after create, which could actually 257da6c28aaSamw * fail because of conflicts between inherited security 258da6c28aaSamw * attributes upon creation and the specified SD. 259da6c28aaSamw * 260da6c28aaSamw * Passing kcred to smb_fsop_sdwrite() to overcome this issue. 261da6c28aaSamw */ 262da6c28aaSamw 263da6c28aaSamw if (is_dir) { 264*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_mkdir(dnode->vp, name, attr, &vp, 2652c1b14e5Sjose borrego flags, cr, NULL); 266da6c28aaSamw } else { 267*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_create(dnode->vp, name, attr, &vp, 2682c1b14e5Sjose borrego flags, cr, NULL); 269da6c28aaSamw } 270da6c28aaSamw 27155bf511dSas if (rc != 0) 27255bf511dSas return (rc); 27355bf511dSas 2742c1b14e5Sjose borrego *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp, 275*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States name, dnode, NULL, ret_attr); 276da6c28aaSamw 2772c1b14e5Sjose borrego if (*ret_snode != NULL) { 2782c1b14e5Sjose borrego if (!smb_tree_has_feature(sr->tid_tree, 2792c1b14e5Sjose borrego SMB_TREE_NFS_MOUNTED)) 2802c1b14e5Sjose borrego rc = smb_fsop_sdwrite(sr, kcred, *ret_snode, 2812c1b14e5Sjose borrego fs_sd, 1); 2822c1b14e5Sjose borrego } else { 283da6c28aaSamw rc = ENOMEM; 284da6c28aaSamw } 2857f667e74Sjose borrego 2867f667e74Sjose borrego VN_RELE(vp); 287da6c28aaSamw } 288da6c28aaSamw 28955bf511dSas if (rc != 0) { 2902c1b14e5Sjose borrego if (is_dir) 291*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States (void) smb_vop_rmdir(dnode->vp, name, flags, cr); 2922c1b14e5Sjose borrego else 293*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States (void) smb_vop_remove(dnode->vp, name, flags, cr); 29455bf511dSas } 29555bf511dSas 296da6c28aaSamw return (rc); 297da6c28aaSamw } 298da6c28aaSamw 299da6c28aaSamw /* 300da6c28aaSamw * smb_fsop_create 301da6c28aaSamw * 302da6c28aaSamw * All SMB functions should use this wrapper to ensure that 303da6c28aaSamw * all the smb_vop_creates are performed with the appropriate credentials. 304*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * Please document any direct calls to explain the reason for avoiding 305*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * this wrapper. 306da6c28aaSamw * 307da6c28aaSamw * *ret_snode is returned with a reference upon success. No reference is 308da6c28aaSamw * taken if an error is returned. 309da6c28aaSamw */ 310da6c28aaSamw int 311*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_fsop_create(smb_request_t *sr, cred_t *cr, 312*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_t *dnode, char *name, 313*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_attr_t *attr, smb_node_t **ret_snode, smb_attr_t *ret_attr) 314da6c28aaSamw { 315*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States int rc = 0; 316*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States int flags = 0; 317*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States char *fname, *sname; 318*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States char *longname = NULL; 319da6c28aaSamw 320da6c28aaSamw ASSERT(cr); 321*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode); 322*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode->n_magic == SMB_NODE_MAGIC); 323*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING); 324da6c28aaSamw 325da6c28aaSamw ASSERT(ret_snode); 326da6c28aaSamw *ret_snode = 0; 327da6c28aaSamw 328da6c28aaSamw ASSERT(name); 329da6c28aaSamw if (*name == 0) 330da6c28aaSamw return (EINVAL); 331da6c28aaSamw 332da6c28aaSamw ASSERT(sr); 333da6c28aaSamw ASSERT(sr->tid_tree); 334c8ec8eeaSjose borrego 335*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0) 336c8ec8eeaSjose borrego return (EACCES); 337c8ec8eeaSjose borrego 338c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) 339da6c28aaSamw return (EROFS); 340da6c28aaSamw 341c8ec8eeaSjose borrego if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 342da6c28aaSamw flags = SMB_IGNORE_CASE; 3438b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_SUPPORTS_CATIA(sr)) 3448b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States flags |= SMB_CATIA; 345da6c28aaSamw 3468b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (smb_is_stream_name(name)) { 3478b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 3488b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 349*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_stream_parse_name(name, fname, sname); 350da6c28aaSamw 351*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_fsop_create_stream(sr, cr, dnode, 352*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States fname, sname, flags, attr, ret_snode, ret_attr); 353da6c28aaSamw 354*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States kmem_free(fname, MAXNAMELEN); 355*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States kmem_free(sname, MAXNAMELEN); 356*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States return (rc); 357*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States } 358da6c28aaSamw 359*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States /* Not a named stream */ 360da6c28aaSamw 361*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (smb_maybe_mangled_name(name)) { 362*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 363*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN); 364*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States kmem_free(longname, MAXNAMELEN); 365da6c28aaSamw 366*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (rc == 0) 367*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = EEXIST; 368*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (rc != ENOENT) 369da6c28aaSamw return (rc); 370*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States } 371da6c28aaSamw 372*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_fsop_create_file(sr, cr, dnode, name, flags, 373*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States attr, ret_snode, ret_attr); 374*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States return (rc); 3757b59d02dSjb 376*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States } 3777b59d02dSjb 3787b59d02dSjb 379*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States /* 380*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * smb_fsop_create_stream 381*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * 382*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * Create NTFS named stream file (sname) on unnamed stream 383*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * file (fname), creating the unnamed stream file if it 384*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * doesn't exist. 385*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * If we created the unnamed stream file and then creation 386*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * of the named stream file fails, we delete the unnamed stream. 387*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * Since we use the real file name for the smb_vop_remove we 388*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * clear the SMB_IGNORE_CASE flag to ensure a case sensitive 389*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * match. 390*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * 391*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * The second parameter of smb_vop_setattr() is set to 392*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * NULL, even though an unnamed stream exists. This is 393*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * because we want to set the UID and GID on the named 394*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * stream in this case for consistency with the (unnamed 395*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * stream) file (see comments for smb_vop_setattr()). 396*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States */ 397*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int 398*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_fsop_create_stream(smb_request_t *sr, cred_t *cr, 399*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_t *dnode, char *fname, char *sname, int flags, 400*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_attr_t *attr, smb_node_t **ret_snode, smb_attr_t *ret_attr) 401*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States { 402*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_t *fnode; 403*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_attr_t fattr; 404*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States vnode_t *xattrdvp; 405*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States vnode_t *vp; 406*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States int rc = 0; 407*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States boolean_t fcreate = B_FALSE; 4087b59d02dSjb 409*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States /* Look up / create the unnamed stream, fname */ 410*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, 411*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States sr->tid_tree->t_snode, dnode, fname, 412*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States &fnode, &fattr); 413*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (rc == ENOENT) { 414*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States fcreate = B_TRUE; 415*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_fsop_create_file(sr, cr, dnode, fname, flags, 416*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States attr, &fnode, &fattr); 417*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States } 418*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (rc != 0) 419*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States return (rc); 420da6c28aaSamw 421*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States /* create the named stream, sname */ 422*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_stream_create(fnode->vp, sname, attr, &vp, 423*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States &xattrdvp, flags, cr); 424*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (rc != 0) { 425*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (fcreate) { 426*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States flags &= ~SMB_IGNORE_CASE; 427*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States (void) smb_vop_remove(dnode->vp, 428*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States fnode->od_name, flags, cr); 429*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States } 430da6c28aaSamw smb_node_release(fnode); 431*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States return (rc); 432*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States } 433da6c28aaSamw 434*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States attr->sa_vattr.va_uid = fattr.sa_vattr.va_uid; 435*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States attr->sa_vattr.va_gid = fattr.sa_vattr.va_gid; 436*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States attr->sa_mask = SMB_AT_UID | SMB_AT_GID; 437da6c28aaSamw 438*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_setattr(vp, NULL, attr, 0, kcred); 439*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (rc != 0) { 440*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_release(fnode); 4418b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States return (rc); 4428b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States } 443da6c28aaSamw 444*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdvp, 445*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States vp, sname, ret_attr); 4468b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 447*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_release(fnode); 448*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States VN_RELE(xattrdvp); 449*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States VN_RELE(vp); 450*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 451*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (*ret_snode == NULL) 452*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = ENOMEM; 453*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 454*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States return (rc); 455*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States } 456*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 457*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States /* 458*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * smb_fsop_create_file 459*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States */ 460*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States static int 461*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_fsop_create_file(smb_request_t *sr, cred_t *cr, 462*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_t *dnode, char *name, int flags, 463*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_attr_t *attr, smb_node_t **ret_snode, smb_attr_t *ret_attr) 464*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States { 465*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States open_param_t *op = &sr->arg.open; 466*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States vnode_t *vp; 467*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_fssd_t fs_sd; 468*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States uint32_t secinfo; 469*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States uint32_t status; 470*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States int rc = 0; 4718b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 4728b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (op->sd) { 4738b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States /* 4748b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * SD sent by client in Windows format. Needs to be 4758b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * converted to FS format. No inheritance. 4768b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States */ 4778b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States secinfo = smb_sd_get_secinfo(op->sd); 4788b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_fssd_init(&fs_sd, secinfo, 0); 4798b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 4808b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States status = smb_sd_tofs(op->sd, &fs_sd); 4818b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (status == NT_STATUS_SUCCESS) { 482*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_fsop_create_with_sd(sr, cr, dnode, 4838b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States name, attr, ret_snode, ret_attr, &fs_sd); 484da6c28aaSamw } else { 4858b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States rc = EINVAL; 4868b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States } 4878b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_fssd_term(&fs_sd); 4888b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States } else if (sr->tid_tree->t_acltype == ACE_T) { 4898b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States /* 4908b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * No incoming SD and filesystem is ZFS 4918b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * Server applies Windows inheritance rules, 4928b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * see smb_fsop_sdinherit() comments as to why. 4938b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States */ 4948b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, 0); 495*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_fsop_sdinherit(sr, dnode, &fs_sd); 4968b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (rc == 0) { 497*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_fsop_create_with_sd(sr, cr, dnode, 4988b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States name, attr, ret_snode, ret_attr, &fs_sd); 4998b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States } 500da6c28aaSamw 5018b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_fssd_term(&fs_sd); 5028b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States } else { 5038b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States /* 5048b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * No incoming SD and filesystem is not ZFS 5058b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * let the filesystem handles the inheritance. 5068b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States */ 507*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_create(dnode->vp, name, attr, &vp, 5088b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States flags, cr, NULL); 509da6c28aaSamw 5108b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (rc == 0) { 5118b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States *ret_snode = smb_node_lookup(sr, op, cr, vp, 512*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States name, dnode, NULL, ret_attr); 5137f667e74Sjose borrego 5148b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (*ret_snode == NULL) 5158b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States rc = ENOMEM; 516da6c28aaSamw 5178b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States VN_RELE(vp); 518da6c28aaSamw } 5198b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 520da6c28aaSamw } 521da6c28aaSamw return (rc); 522da6c28aaSamw } 523da6c28aaSamw 524da6c28aaSamw /* 525da6c28aaSamw * smb_fsop_mkdir 526da6c28aaSamw * 527da6c28aaSamw * All SMB functions should use this wrapper to ensure that 528da6c28aaSamw * the the calls are performed with the appropriate credentials. 529da6c28aaSamw * Please document any direct call to explain the reason 530da6c28aaSamw * for avoiding this wrapper. 531da6c28aaSamw * 532da6c28aaSamw * It is assumed that a reference exists on snode coming into this routine. 533da6c28aaSamw * 534da6c28aaSamw * *ret_snode is returned with a reference upon success. No reference is 535da6c28aaSamw * taken if an error is returned. 536da6c28aaSamw */ 537da6c28aaSamw int 538da6c28aaSamw smb_fsop_mkdir( 539faa1795aSjb smb_request_t *sr, 540da6c28aaSamw cred_t *cr, 541*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_t *dnode, 542da6c28aaSamw char *name, 543da6c28aaSamw smb_attr_t *attr, 544da6c28aaSamw smb_node_t **ret_snode, 545da6c28aaSamw smb_attr_t *ret_attr) 546da6c28aaSamw { 547da6c28aaSamw struct open_param *op = &sr->arg.open; 548da6c28aaSamw char *longname; 549da6c28aaSamw vnode_t *vp; 550da6c28aaSamw int flags = 0; 551da6c28aaSamw smb_fssd_t fs_sd; 552da6c28aaSamw uint32_t secinfo; 553da6c28aaSamw uint32_t status; 554da6c28aaSamw int rc; 555da6c28aaSamw ASSERT(cr); 556*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode); 557*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode->n_magic == SMB_NODE_MAGIC); 558*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING); 559da6c28aaSamw 560da6c28aaSamw ASSERT(ret_snode); 561da6c28aaSamw *ret_snode = 0; 562da6c28aaSamw 563da6c28aaSamw ASSERT(name); 564da6c28aaSamw if (*name == 0) 565da6c28aaSamw return (EINVAL); 566da6c28aaSamw 567da6c28aaSamw ASSERT(sr); 568da6c28aaSamw ASSERT(sr->tid_tree); 569c8ec8eeaSjose borrego 570*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0) 571c8ec8eeaSjose borrego return (EACCES); 572c8ec8eeaSjose borrego 573c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) 574da6c28aaSamw return (EROFS); 5758b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_SUPPORTS_CATIA(sr)) 5768b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States flags |= SMB_CATIA; 577da6c28aaSamw 578da6c28aaSamw if (smb_maybe_mangled_name(name)) { 579da6c28aaSamw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 580*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN); 581da6c28aaSamw kmem_free(longname, MAXNAMELEN); 582da6c28aaSamw 583da6c28aaSamw /* 584da6c28aaSamw * If the name passed in by the client has an unmangled 585da6c28aaSamw * equivalent that is found in the specified directory, 586da6c28aaSamw * then the mkdir cannot succeed. Return EEXIST. 587da6c28aaSamw * 588da6c28aaSamw * Only if ENOENT is returned will a mkdir be attempted. 589da6c28aaSamw */ 590da6c28aaSamw 591da6c28aaSamw if (rc == 0) 592da6c28aaSamw rc = EEXIST; 593da6c28aaSamw 594da6c28aaSamw if (rc != ENOENT) 595da6c28aaSamw return (rc); 596da6c28aaSamw } 597da6c28aaSamw 598c8ec8eeaSjose borrego if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 599da6c28aaSamw flags = SMB_IGNORE_CASE; 600da6c28aaSamw 60155bf511dSas if (op->sd) { 602da6c28aaSamw /* 603da6c28aaSamw * SD sent by client in Windows format. Needs to be 604da6c28aaSamw * converted to FS format. No inheritance. 605da6c28aaSamw */ 60655bf511dSas secinfo = smb_sd_get_secinfo(op->sd); 60755bf511dSas smb_fssd_init(&fs_sd, secinfo, SMB_FSSD_FLAGS_DIR); 608da6c28aaSamw 60955bf511dSas status = smb_sd_tofs(op->sd, &fs_sd); 610da6c28aaSamw if (status == NT_STATUS_SUCCESS) { 611*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_fsop_create_with_sd(sr, cr, dnode, 612da6c28aaSamw name, attr, ret_snode, ret_attr, &fs_sd); 613da6c28aaSamw } 614da6c28aaSamw else 615da6c28aaSamw rc = EINVAL; 61655bf511dSas smb_fssd_term(&fs_sd); 617da6c28aaSamw } else if (sr->tid_tree->t_acltype == ACE_T) { 618da6c28aaSamw /* 619da6c28aaSamw * No incoming SD and filesystem is ZFS 620da6c28aaSamw * Server applies Windows inheritance rules, 621da6c28aaSamw * see smb_fsop_sdinherit() comments as to why. 622da6c28aaSamw */ 62355bf511dSas smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, SMB_FSSD_FLAGS_DIR); 624*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_fsop_sdinherit(sr, dnode, &fs_sd); 625da6c28aaSamw if (rc == 0) { 626*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_fsop_create_with_sd(sr, cr, dnode, 627da6c28aaSamw name, attr, ret_snode, ret_attr, &fs_sd); 628da6c28aaSamw } 629da6c28aaSamw 63055bf511dSas smb_fssd_term(&fs_sd); 631da6c28aaSamw 632da6c28aaSamw } else { 633*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_mkdir(dnode->vp, name, attr, &vp, flags, cr, 634dc20a302Sas NULL); 635da6c28aaSamw 636da6c28aaSamw if (rc == 0) { 637da6c28aaSamw *ret_snode = smb_node_lookup(sr, op, cr, vp, name, 638*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States dnode, NULL, ret_attr); 639da6c28aaSamw 6407f667e74Sjose borrego if (*ret_snode == NULL) 641da6c28aaSamw rc = ENOMEM; 6427f667e74Sjose borrego 6437f667e74Sjose borrego VN_RELE(vp); 644da6c28aaSamw } 645da6c28aaSamw } 646da6c28aaSamw 647da6c28aaSamw return (rc); 648da6c28aaSamw } 649da6c28aaSamw 650da6c28aaSamw /* 651da6c28aaSamw * smb_fsop_remove 652da6c28aaSamw * 653da6c28aaSamw * All SMB functions should use this wrapper to ensure that 654da6c28aaSamw * the the calls are performed with the appropriate credentials. 655da6c28aaSamw * Please document any direct call to explain the reason 656da6c28aaSamw * for avoiding this wrapper. 657da6c28aaSamw * 658da6c28aaSamw * It is assumed that a reference exists on snode coming into this routine. 659da6c28aaSamw * 660da6c28aaSamw * A null smb_request might be passed to this function. 661da6c28aaSamw */ 662da6c28aaSamw int 663da6c28aaSamw smb_fsop_remove( 664faa1795aSjb smb_request_t *sr, 665faa1795aSjb cred_t *cr, 666*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_t *dnode, 667faa1795aSjb char *name, 6688b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States uint32_t flags) 669da6c28aaSamw { 670faa1795aSjb smb_node_t *fnode; 671faa1795aSjb smb_attr_t file_attr; 672faa1795aSjb char *longname; 673faa1795aSjb char *fname; 674faa1795aSjb char *sname; 675faa1795aSjb int rc; 676da6c28aaSamw 677da6c28aaSamw ASSERT(cr); 678da6c28aaSamw /* 679da6c28aaSamw * The state of the node could be SMB_NODE_STATE_DESTROYING if this 680da6c28aaSamw * function is called during the deletion of the node (because of 681da6c28aaSamw * DELETE_ON_CLOSE). 682da6c28aaSamw */ 683*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode); 684*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode->n_magic == SMB_NODE_MAGIC); 685da6c28aaSamw 686*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0 || 687743a77edSAlan Wright SMB_TREE_HAS_ACCESS(sr, ACE_DELETE) == 0) 688da6c28aaSamw return (EACCES); 689da6c28aaSamw 690c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) 691da6c28aaSamw return (EROFS); 692da6c28aaSamw 693da6c28aaSamw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 694da6c28aaSamw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 695da6c28aaSamw 696*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (dnode->flags & NODE_XATTR_DIR) { 697*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_stream_remove(dnode->dir_snode->vp, 698cbfb650aScp name, flags, cr); 699*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States } else if (smb_is_stream_name(name)) { 700*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_stream_parse_name(name, fname, sname); 7018d7e4166Sjose borrego 702da6c28aaSamw /* 703da6c28aaSamw * Look up the unnamed stream (i.e. fname). 704da6c28aaSamw * Unmangle processing will be done on fname 705da6c28aaSamw * as well as any link target. 706da6c28aaSamw */ 707da6c28aaSamw 708da6c28aaSamw rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, 709*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States sr->tid_tree->t_snode, dnode, fname, 7108b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States &fnode, &file_attr); 711da6c28aaSamw 712da6c28aaSamw if (rc != 0) { 713da6c28aaSamw kmem_free(fname, MAXNAMELEN); 714da6c28aaSamw kmem_free(sname, MAXNAMELEN); 715da6c28aaSamw return (rc); 716da6c28aaSamw } 717da6c28aaSamw 718da6c28aaSamw /* 719da6c28aaSamw * XXX 720da6c28aaSamw * Need to find out what permission is required by NTFS 721da6c28aaSamw * to remove a stream. 722da6c28aaSamw */ 723dc20a302Sas rc = smb_vop_stream_remove(fnode->vp, sname, flags, cr); 724da6c28aaSamw 725da6c28aaSamw smb_node_release(fnode); 726da6c28aaSamw } else { 727*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_remove(dnode->vp, name, flags, cr); 728da6c28aaSamw 729da6c28aaSamw if (rc == ENOENT) { 730da6c28aaSamw if (smb_maybe_mangled_name(name) == 0) { 731da6c28aaSamw kmem_free(fname, MAXNAMELEN); 732da6c28aaSamw kmem_free(sname, MAXNAMELEN); 733da6c28aaSamw return (rc); 734da6c28aaSamw } 735da6c28aaSamw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 736da6c28aaSamw 737*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_unmangle_name(dnode, name, 7388b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States longname, MAXNAMELEN); 739da6c28aaSamw 740da6c28aaSamw if (rc == 0) { 741da6c28aaSamw /* 7428b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * longname is the real (case-sensitive) 7438b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * on-disk name. 744da6c28aaSamw * We make sure we do a remove on this exact 745da6c28aaSamw * name, as the name was mangled and denotes 746da6c28aaSamw * a unique file. 747da6c28aaSamw */ 748da6c28aaSamw flags &= ~SMB_IGNORE_CASE; 749*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_remove(dnode->vp, longname, 750dc20a302Sas flags, cr); 751da6c28aaSamw } 752da6c28aaSamw 753da6c28aaSamw kmem_free(longname, MAXNAMELEN); 754da6c28aaSamw } 755da6c28aaSamw } 756da6c28aaSamw 757da6c28aaSamw kmem_free(fname, MAXNAMELEN); 758da6c28aaSamw kmem_free(sname, MAXNAMELEN); 759da6c28aaSamw return (rc); 760da6c28aaSamw } 761da6c28aaSamw 762da6c28aaSamw /* 763da6c28aaSamw * smb_fsop_remove_streams 764da6c28aaSamw * 765da6c28aaSamw * This function removes a file's streams without removing the 766da6c28aaSamw * file itself. 767da6c28aaSamw * 7687f667e74Sjose borrego * It is assumed that fnode is not a link. 769da6c28aaSamw */ 770da6c28aaSamw int 771faa1795aSjb smb_fsop_remove_streams(smb_request_t *sr, cred_t *cr, smb_node_t *fnode) 772da6c28aaSamw { 7737f667e74Sjose borrego int rc, flags = 0; 7747f667e74Sjose borrego uint16_t odid; 7757f667e74Sjose borrego smb_odir_t *od; 7767f667e74Sjose borrego smb_odirent_t *odirent; 7777f667e74Sjose borrego boolean_t eos; 778da6c28aaSamw 779c8ec8eeaSjose borrego ASSERT(sr); 780da6c28aaSamw ASSERT(cr); 781da6c28aaSamw ASSERT(fnode); 782da6c28aaSamw ASSERT(fnode->n_magic == SMB_NODE_MAGIC); 783da6c28aaSamw ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING); 784da6c28aaSamw 785*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_CONTAINS_NODE(sr, fnode) == 0) { 786*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smbsr_errno(sr, EACCES); 787*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States return (-1); 788*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States } 789da6c28aaSamw 790*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_IS_READONLY(sr)) { 791*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smbsr_errno(sr, EROFS); 792*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States return (-1); 793*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States } 794da6c28aaSamw 795c8ec8eeaSjose borrego if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 796da6c28aaSamw flags = SMB_IGNORE_CASE; 797*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 7988b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_SUPPORTS_CATIA(sr)) 7998b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States flags |= SMB_CATIA; 800da6c28aaSamw 801*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if ((odid = smb_odir_openat(sr, fnode)) == 0) { 802*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smbsr_errno(sr, ENOENT); 803*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States return (-1); 804*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States } 805*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 806*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if ((od = smb_tree_lookup_odir(sr->tid_tree, odid)) == NULL) { 807*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smbsr_errno(sr, ENOENT); 808*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States return (-1); 809*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States } 810da6c28aaSamw 8117f667e74Sjose borrego odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP); 8127f667e74Sjose borrego for (;;) { 8137f667e74Sjose borrego rc = smb_odir_read(sr, od, odirent, &eos); 8147f667e74Sjose borrego if ((rc != 0) || (eos)) 815da6c28aaSamw break; 8167f667e74Sjose borrego (void) smb_vop_remove(od->d_dnode->vp, odirent->od_name, 8177f667e74Sjose borrego flags, cr); 818da6c28aaSamw } 8197f667e74Sjose borrego kmem_free(odirent, sizeof (smb_odirent_t)); 8207f667e74Sjose borrego 8217f667e74Sjose borrego smb_odir_release(od); 8227f667e74Sjose borrego smb_odir_close(od); 823da6c28aaSamw return (rc); 824da6c28aaSamw } 825da6c28aaSamw 826da6c28aaSamw /* 827da6c28aaSamw * smb_fsop_rmdir 828da6c28aaSamw * 829da6c28aaSamw * All SMB functions should use this wrapper to ensure that 830da6c28aaSamw * the the calls are performed with the appropriate credentials. 831da6c28aaSamw * Please document any direct call to explain the reason 832da6c28aaSamw * for avoiding this wrapper. 833da6c28aaSamw * 834da6c28aaSamw * It is assumed that a reference exists on snode coming into this routine. 835da6c28aaSamw */ 836da6c28aaSamw int 837da6c28aaSamw smb_fsop_rmdir( 838faa1795aSjb smb_request_t *sr, 839faa1795aSjb cred_t *cr, 840*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_t *dnode, 841faa1795aSjb char *name, 8428b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States uint32_t flags) 843da6c28aaSamw { 844faa1795aSjb int rc; 845faa1795aSjb char *longname; 846da6c28aaSamw 847da6c28aaSamw ASSERT(cr); 848da6c28aaSamw /* 849da6c28aaSamw * The state of the node could be SMB_NODE_STATE_DESTROYING if this 850da6c28aaSamw * function is called during the deletion of the node (because of 851da6c28aaSamw * DELETE_ON_CLOSE). 852da6c28aaSamw */ 853*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode); 854*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode->n_magic == SMB_NODE_MAGIC); 855da6c28aaSamw 856*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0 || 857743a77edSAlan Wright SMB_TREE_HAS_ACCESS(sr, ACE_DELETE_CHILD) == 0) 858da6c28aaSamw return (EACCES); 859da6c28aaSamw 860c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) 861da6c28aaSamw return (EROFS); 862da6c28aaSamw 863*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_rmdir(dnode->vp, name, flags, cr); 864da6c28aaSamw 865da6c28aaSamw if (rc == ENOENT) { 866da6c28aaSamw if (smb_maybe_mangled_name(name) == 0) 867da6c28aaSamw return (rc); 868da6c28aaSamw 869da6c28aaSamw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 870*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN); 871da6c28aaSamw 872da6c28aaSamw if (rc == 0) { 873da6c28aaSamw /* 8748b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * longname is the real (case-sensitive) 8758b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * on-disk name. 876da6c28aaSamw * We make sure we do a rmdir on this exact 877da6c28aaSamw * name, as the name was mangled and denotes 878da6c28aaSamw * a unique directory. 879da6c28aaSamw */ 880da6c28aaSamw flags &= ~SMB_IGNORE_CASE; 881*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_rmdir(dnode->vp, longname, flags, cr); 882da6c28aaSamw } 883da6c28aaSamw 884da6c28aaSamw kmem_free(longname, MAXNAMELEN); 885da6c28aaSamw } 886da6c28aaSamw 887da6c28aaSamw return (rc); 888da6c28aaSamw } 889da6c28aaSamw 890da6c28aaSamw /* 891da6c28aaSamw * smb_fsop_getattr 892da6c28aaSamw * 893da6c28aaSamw * All SMB functions should use this wrapper to ensure that 894da6c28aaSamw * the the calls are performed with the appropriate credentials. 895da6c28aaSamw * Please document any direct call to explain the reason 896da6c28aaSamw * for avoiding this wrapper. 897da6c28aaSamw * 898da6c28aaSamw * It is assumed that a reference exists on snode coming into this routine. 899da6c28aaSamw */ 900da6c28aaSamw int 901faa1795aSjb smb_fsop_getattr(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 902da6c28aaSamw smb_attr_t *attr) 903da6c28aaSamw { 904da6c28aaSamw smb_node_t *unnamed_node; 905da6c28aaSamw vnode_t *unnamed_vp = NULL; 906da6c28aaSamw uint32_t status; 907da6c28aaSamw uint32_t access = 0; 908da6c28aaSamw int flags = 0; 909dc20a302Sas int rc; 910da6c28aaSamw 911da6c28aaSamw ASSERT(cr); 912da6c28aaSamw ASSERT(snode); 913da6c28aaSamw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 914da6c28aaSamw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 915da6c28aaSamw 916743a77edSAlan Wright if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0 || 917743a77edSAlan Wright SMB_TREE_HAS_ACCESS(sr, ACE_READ_ATTRIBUTES) == 0) 918da6c28aaSamw return (EACCES); 919da6c28aaSamw 920da6c28aaSamw if (sr->fid_ofile) { 921da6c28aaSamw /* if uid and/or gid is requested */ 922da6c28aaSamw if (attr->sa_mask & (SMB_AT_UID|SMB_AT_GID)) 923da6c28aaSamw access |= READ_CONTROL; 924da6c28aaSamw 925da6c28aaSamw /* if anything else is also requested */ 926da6c28aaSamw if (attr->sa_mask & ~(SMB_AT_UID|SMB_AT_GID)) 927da6c28aaSamw access |= FILE_READ_ATTRIBUTES; 928da6c28aaSamw 929da6c28aaSamw status = smb_ofile_access(sr->fid_ofile, cr, access); 930da6c28aaSamw if (status != NT_STATUS_SUCCESS) 931da6c28aaSamw return (EACCES); 932da6c28aaSamw 933c8ec8eeaSjose borrego if (smb_tree_has_feature(sr->tid_tree, 934c8ec8eeaSjose borrego SMB_TREE_ACEMASKONACCESS)) 935da6c28aaSamw flags = ATTR_NOACLCHECK; 936da6c28aaSamw } 937da6c28aaSamw 938da6c28aaSamw unnamed_node = SMB_IS_STREAM(snode); 939da6c28aaSamw 940da6c28aaSamw if (unnamed_node) { 941da6c28aaSamw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 942da6c28aaSamw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 943da6c28aaSamw unnamed_vp = unnamed_node->vp; 944da6c28aaSamw } 945da6c28aaSamw 946dc20a302Sas rc = smb_vop_getattr(snode->vp, unnamed_vp, attr, flags, cr); 947dc20a302Sas if (rc == 0) 948dc20a302Sas snode->attr = *attr; 949dc20a302Sas 950dc20a302Sas return (rc); 951da6c28aaSamw } 952da6c28aaSamw 953da6c28aaSamw /* 954da6c28aaSamw * smb_fsop_rename 955da6c28aaSamw * 956da6c28aaSamw * All SMB functions should use this smb_vop_rename wrapper to ensure that 957da6c28aaSamw * the smb_vop_rename is performed with the appropriate credentials. 958da6c28aaSamw * Please document any direct call to smb_vop_rename to explain the reason 959da6c28aaSamw * for avoiding this wrapper. 960da6c28aaSamw * 961*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * It is assumed that references exist on from_dnode and to_dnode coming 962da6c28aaSamw * into this routine. 963da6c28aaSamw */ 964da6c28aaSamw int 965da6c28aaSamw smb_fsop_rename( 966faa1795aSjb smb_request_t *sr, 967da6c28aaSamw cred_t *cr, 968*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_t *from_dnode, 969da6c28aaSamw char *from_name, 970*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_t *to_dnode, 971da6c28aaSamw char *to_name) 972da6c28aaSamw { 973da6c28aaSamw smb_node_t *from_snode; 974da6c28aaSamw smb_attr_t tmp_attr; 975da6c28aaSamw vnode_t *from_vp; 9768b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States int flags = 0, ret_flags; 977da6c28aaSamw int rc; 978743a77edSAlan Wright boolean_t isdir; 979da6c28aaSamw 980da6c28aaSamw ASSERT(cr); 981*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(from_dnode); 982*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(from_dnode->n_magic == SMB_NODE_MAGIC); 983*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(from_dnode->n_state != SMB_NODE_STATE_DESTROYING); 984da6c28aaSamw 985*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(to_dnode); 986*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(to_dnode->n_magic == SMB_NODE_MAGIC); 987*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(to_dnode->n_state != SMB_NODE_STATE_DESTROYING); 988da6c28aaSamw 989*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_CONTAINS_NODE(sr, from_dnode) == 0) 990da6c28aaSamw return (EACCES); 991da6c28aaSamw 992*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_CONTAINS_NODE(sr, to_dnode) == 0) 993da6c28aaSamw return (EACCES); 994da6c28aaSamw 995da6c28aaSamw ASSERT(sr); 996da6c28aaSamw ASSERT(sr->tid_tree); 997c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) 998da6c28aaSamw return (EROFS); 999da6c28aaSamw 1000da6c28aaSamw /* 1001c8ec8eeaSjose borrego * Note: There is no need to check SMB_TREE_IS_CASEINSENSITIVE 1002da6c28aaSamw * here. 1003da6c28aaSamw * 1004da6c28aaSamw * A case-sensitive rename is always done in this routine 1005da6c28aaSamw * because we are using the on-disk name from an earlier lookup. 1006da6c28aaSamw * If a mangled name was passed in by the caller (denoting a 1007da6c28aaSamw * deterministic lookup), then the exact file must be renamed 1008da6c28aaSamw * (i.e. SMB_IGNORE_CASE must not be passed to VOP_RENAME, or 1009da6c28aaSamw * else the underlying file system might return a "first-match" 1010da6c28aaSamw * on this on-disk name, possibly resulting in the wrong file). 1011da6c28aaSamw */ 1012da6c28aaSamw 10138b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_SUPPORTS_CATIA(sr)) 10148b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States flags |= SMB_CATIA; 10158b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 1016da6c28aaSamw /* 1017da6c28aaSamw * XXX: Lock required through smb_node_release() below? 1018da6c28aaSamw */ 1019da6c28aaSamw 1020*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_lookup(from_dnode->vp, from_name, &from_vp, NULL, 10218b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States flags, &ret_flags, NULL, cr); 1022da6c28aaSamw 1023da6c28aaSamw if (rc != 0) 1024da6c28aaSamw return (rc); 1025da6c28aaSamw 1026743a77edSAlan Wright isdir = from_vp->v_type == VDIR; 1027743a77edSAlan Wright 1028743a77edSAlan Wright if ((isdir && SMB_TREE_HAS_ACCESS(sr, 1029743a77edSAlan Wright ACE_DELETE_CHILD | ACE_ADD_SUBDIRECTORY) != 1030743a77edSAlan Wright (ACE_DELETE_CHILD | ACE_ADD_SUBDIRECTORY)) || 1031743a77edSAlan Wright (!isdir && SMB_TREE_HAS_ACCESS(sr, ACE_DELETE | ACE_ADD_FILE) != 1032743a77edSAlan Wright (ACE_DELETE | ACE_ADD_FILE))) 1033743a77edSAlan Wright return (EACCES); 1034743a77edSAlan Wright 1035*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_rename(from_dnode->vp, from_name, to_dnode->vp, 1036dc20a302Sas to_name, flags, cr); 1037da6c28aaSamw 1038da6c28aaSamw if (rc == 0) { 1039da6c28aaSamw from_snode = smb_node_lookup(sr, NULL, cr, from_vp, from_name, 1040*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States from_dnode, NULL, &tmp_attr); 1041da6c28aaSamw 1042da6c28aaSamw if (from_snode == NULL) { 10437f667e74Sjose borrego rc = ENOMEM; 10447f667e74Sjose borrego } else { 1045*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_rename(from_dnode, from_snode, 1046*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States to_dnode, to_name); 10477f667e74Sjose borrego smb_node_release(from_snode); 1048da6c28aaSamw } 1049da6c28aaSamw } 10507f667e74Sjose borrego VN_RELE(from_vp); 1051da6c28aaSamw 1052da6c28aaSamw /* XXX: unlock */ 1053da6c28aaSamw 1054da6c28aaSamw return (rc); 1055da6c28aaSamw } 1056da6c28aaSamw 1057da6c28aaSamw /* 1058da6c28aaSamw * smb_fsop_setattr 1059da6c28aaSamw * 1060da6c28aaSamw * All SMB functions should use this wrapper to ensure that 1061da6c28aaSamw * the the calls are performed with the appropriate credentials. 1062da6c28aaSamw * Please document any direct call to explain the reason 1063da6c28aaSamw * for avoiding this wrapper. 1064da6c28aaSamw * 1065da6c28aaSamw * It is assumed that a reference exists on snode coming into this routine. 1066da6c28aaSamw * A null smb_request might be passed to this function. 1067da6c28aaSamw */ 1068da6c28aaSamw int 1069da6c28aaSamw smb_fsop_setattr( 1070faa1795aSjb smb_request_t *sr, 1071faa1795aSjb cred_t *cr, 1072faa1795aSjb smb_node_t *snode, 1073faa1795aSjb smb_attr_t *set_attr, 1074faa1795aSjb smb_attr_t *ret_attr) 1075da6c28aaSamw { 1076da6c28aaSamw smb_node_t *unnamed_node; 1077da6c28aaSamw vnode_t *unnamed_vp = NULL; 1078da6c28aaSamw uint32_t status; 10792c1b14e5Sjose borrego uint32_t access; 1080da6c28aaSamw int rc = 0; 1081da6c28aaSamw int flags = 0; 10822c1b14e5Sjose borrego uint_t sa_mask; 1083da6c28aaSamw 1084da6c28aaSamw ASSERT(cr); 1085da6c28aaSamw ASSERT(snode); 1086da6c28aaSamw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 1087da6c28aaSamw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 1088da6c28aaSamw 1089c8ec8eeaSjose borrego if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0) 1090da6c28aaSamw return (EACCES); 1091da6c28aaSamw 1092c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) 1093da6c28aaSamw return (EROFS); 1094da6c28aaSamw 1095743a77edSAlan Wright if (SMB_TREE_HAS_ACCESS(sr, 1096743a77edSAlan Wright ACE_WRITE_ATTRIBUTES | ACE_WRITE_NAMED_ATTRS) == 0) 1097743a77edSAlan Wright return (EACCES); 1098743a77edSAlan Wright 1099c8ec8eeaSjose borrego if (sr && (set_attr->sa_mask & SMB_AT_SIZE)) { 1100c8ec8eeaSjose borrego if (sr->fid_ofile) { 1101c8ec8eeaSjose borrego if (SMB_OFILE_IS_READONLY(sr->fid_ofile)) 1102c8ec8eeaSjose borrego return (EACCES); 1103c8ec8eeaSjose borrego } else { 1104c8ec8eeaSjose borrego if (SMB_PATHFILE_IS_READONLY(sr, snode)) 1105c8ec8eeaSjose borrego return (EACCES); 1106c8ec8eeaSjose borrego } 1107c8ec8eeaSjose borrego } 1108c8ec8eeaSjose borrego 1109da6c28aaSamw /* sr could be NULL in some cases */ 1110da6c28aaSamw if (sr && sr->fid_ofile) { 11112c1b14e5Sjose borrego sa_mask = set_attr->sa_mask; 11122c1b14e5Sjose borrego access = 0; 1113c8ec8eeaSjose borrego 11142c1b14e5Sjose borrego if (sa_mask & SMB_AT_SIZE) { 11152c1b14e5Sjose borrego access |= FILE_WRITE_DATA; 11162c1b14e5Sjose borrego sa_mask &= ~SMB_AT_SIZE; 11172c1b14e5Sjose borrego } 11182c1b14e5Sjose borrego 11192c1b14e5Sjose borrego if (sa_mask & (SMB_AT_UID|SMB_AT_GID)) { 1120da6c28aaSamw access |= WRITE_OWNER; 11212c1b14e5Sjose borrego sa_mask &= ~(SMB_AT_UID|SMB_AT_GID); 11222c1b14e5Sjose borrego } 1123da6c28aaSamw 11242c1b14e5Sjose borrego if (sa_mask) 1125da6c28aaSamw access |= FILE_WRITE_ATTRIBUTES; 1126da6c28aaSamw 1127da6c28aaSamw status = smb_ofile_access(sr->fid_ofile, cr, access); 1128da6c28aaSamw if (status != NT_STATUS_SUCCESS) 1129da6c28aaSamw return (EACCES); 1130da6c28aaSamw 1131c8ec8eeaSjose borrego if (smb_tree_has_feature(sr->tid_tree, 1132c8ec8eeaSjose borrego SMB_TREE_ACEMASKONACCESS)) 1133da6c28aaSamw flags = ATTR_NOACLCHECK; 1134da6c28aaSamw } 1135da6c28aaSamw 1136da6c28aaSamw unnamed_node = SMB_IS_STREAM(snode); 1137da6c28aaSamw 1138da6c28aaSamw if (unnamed_node) { 1139da6c28aaSamw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 1140da6c28aaSamw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 1141da6c28aaSamw unnamed_vp = unnamed_node->vp; 1142da6c28aaSamw } 1143da6c28aaSamw 11449660e5cbSJanice Chang rc = smb_vop_setattr(snode->vp, unnamed_vp, set_attr, flags, cr); 1145da6c28aaSamw 1146da6c28aaSamw if ((rc == 0) && ret_attr) { 1147da6c28aaSamw /* 1148dc20a302Sas * Use kcred to update the node attr because this 1149dc20a302Sas * call is not being made on behalf of the user. 1150da6c28aaSamw */ 1151da6c28aaSamw ret_attr->sa_mask = SMB_AT_ALL; 1152c8ec8eeaSjose borrego rc = smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, flags, 1153c8ec8eeaSjose borrego kcred); 1154dc20a302Sas if (rc == 0) 1155dc20a302Sas snode->attr = *ret_attr; 1156da6c28aaSamw } 1157da6c28aaSamw 1158da6c28aaSamw return (rc); 1159da6c28aaSamw } 1160da6c28aaSamw 1161da6c28aaSamw /* 1162da6c28aaSamw * smb_fsop_read 1163da6c28aaSamw * 1164da6c28aaSamw * All SMB functions should use this wrapper to ensure that 1165da6c28aaSamw * the the calls are performed with the appropriate credentials. 1166da6c28aaSamw * Please document any direct call to explain the reason 1167da6c28aaSamw * for avoiding this wrapper. 1168da6c28aaSamw * 1169da6c28aaSamw * It is assumed that a reference exists on snode coming into this routine. 1170da6c28aaSamw */ 1171da6c28aaSamw int 1172da6c28aaSamw smb_fsop_read( 1173da6c28aaSamw struct smb_request *sr, 1174da6c28aaSamw cred_t *cr, 1175da6c28aaSamw smb_node_t *snode, 1176da6c28aaSamw uio_t *uio, 1177da6c28aaSamw smb_attr_t *ret_attr) 1178da6c28aaSamw { 1179da6c28aaSamw smb_node_t *unnamed_node; 1180da6c28aaSamw vnode_t *unnamed_vp = NULL; 1181c8ec8eeaSjose borrego caller_context_t ct; 1182dc20a302Sas int svmand; 1183da6c28aaSamw int rc; 1184da6c28aaSamw 1185da6c28aaSamw ASSERT(cr); 1186da6c28aaSamw ASSERT(snode); 1187da6c28aaSamw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 1188da6c28aaSamw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 1189da6c28aaSamw 1190da6c28aaSamw ASSERT(sr); 1191da6c28aaSamw ASSERT(sr->fid_ofile); 1192da6c28aaSamw 1193743a77edSAlan Wright if (SMB_TREE_HAS_ACCESS(sr, ACE_READ_DATA) == 0) 1194743a77edSAlan Wright return (EACCES); 1195743a77edSAlan Wright 1196da6c28aaSamw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_READ_DATA); 1197da6c28aaSamw if (rc != NT_STATUS_SUCCESS) { 1198da6c28aaSamw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_EXECUTE); 1199da6c28aaSamw if (rc != NT_STATUS_SUCCESS) 1200da6c28aaSamw return (EACCES); 1201da6c28aaSamw } 1202da6c28aaSamw 1203da6c28aaSamw unnamed_node = SMB_IS_STREAM(snode); 1204da6c28aaSamw if (unnamed_node) { 1205da6c28aaSamw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 1206da6c28aaSamw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 1207da6c28aaSamw unnamed_vp = unnamed_node->vp; 1208da6c28aaSamw /* 1209da6c28aaSamw * Streams permission are checked against the unnamed stream, 1210da6c28aaSamw * but in FS level they have their own permissions. To avoid 1211da6c28aaSamw * rejection by FS due to lack of permission on the actual 1212da6c28aaSamw * extended attr kcred is passed for streams. 1213da6c28aaSamw */ 1214da6c28aaSamw cr = kcred; 1215da6c28aaSamw } 1216da6c28aaSamw 1217dc20a302Sas smb_node_start_crit(snode, RW_READER); 1218c8ec8eeaSjose borrego rc = nbl_svmand(snode->vp, kcred, &svmand); 1219dc20a302Sas if (rc) { 1220dc20a302Sas smb_node_end_crit(snode); 1221dc20a302Sas return (rc); 1222dc20a302Sas } 1223dc20a302Sas 1224c8ec8eeaSjose borrego ct = smb_ct; 1225c8ec8eeaSjose borrego ct.cc_pid = sr->fid_ofile->f_uniqid; 1226dc20a302Sas rc = nbl_lock_conflict(snode->vp, NBL_READ, uio->uio_loffset, 1227c8ec8eeaSjose borrego uio->uio_iov->iov_len, svmand, &ct); 1228da6c28aaSamw 1229dc20a302Sas if (rc) { 1230dc20a302Sas smb_node_end_crit(snode); 12316537f381Sas return (ERANGE); 1232dc20a302Sas } 1233dc20a302Sas rc = smb_vop_read(snode->vp, uio, cr); 1234dc20a302Sas 1235dc20a302Sas if (rc == 0 && ret_attr) { 1236da6c28aaSamw /* 1237dc20a302Sas * Use kcred to update the node attr because this 1238dc20a302Sas * call is not being made on behalf of the user. 1239da6c28aaSamw */ 1240da6c28aaSamw ret_attr->sa_mask = SMB_AT_ALL; 1241dc20a302Sas if (smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0, 1242dc20a302Sas kcred) == 0) { 1243dc20a302Sas snode->attr = *ret_attr; 1244dc20a302Sas } 1245da6c28aaSamw } 1246da6c28aaSamw 1247dc20a302Sas smb_node_end_crit(snode); 1248dc20a302Sas 1249da6c28aaSamw return (rc); 1250da6c28aaSamw } 1251da6c28aaSamw 1252da6c28aaSamw /* 1253da6c28aaSamw * smb_fsop_write 1254da6c28aaSamw * 1255da6c28aaSamw * This is a wrapper function used for smb_write and smb_write_raw operations. 1256da6c28aaSamw * 1257da6c28aaSamw * It is assumed that a reference exists on snode coming into this routine. 1258da6c28aaSamw */ 1259da6c28aaSamw int 1260da6c28aaSamw smb_fsop_write( 1261faa1795aSjb smb_request_t *sr, 1262da6c28aaSamw cred_t *cr, 1263da6c28aaSamw smb_node_t *snode, 1264da6c28aaSamw uio_t *uio, 1265da6c28aaSamw uint32_t *lcount, 1266da6c28aaSamw smb_attr_t *ret_attr, 12673db3f65cSamw int ioflag) 1268da6c28aaSamw { 1269da6c28aaSamw smb_node_t *unnamed_node; 1270da6c28aaSamw vnode_t *unnamed_vp = NULL; 1271c8ec8eeaSjose borrego caller_context_t ct; 1272dc20a302Sas int svmand; 1273da6c28aaSamw int rc; 1274da6c28aaSamw 1275da6c28aaSamw ASSERT(cr); 1276da6c28aaSamw ASSERT(snode); 1277da6c28aaSamw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 1278da6c28aaSamw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 1279da6c28aaSamw 1280da6c28aaSamw ASSERT(sr); 1281da6c28aaSamw ASSERT(sr->tid_tree); 1282da6c28aaSamw ASSERT(sr->fid_ofile); 1283da6c28aaSamw 1284c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) 1285da6c28aaSamw return (EROFS); 1286da6c28aaSamw 1287743a77edSAlan Wright if (SMB_OFILE_IS_READONLY(sr->fid_ofile) || 1288743a77edSAlan Wright SMB_TREE_HAS_ACCESS(sr, ACE_WRITE_DATA | ACE_APPEND_DATA) == 0) 1289c8ec8eeaSjose borrego return (EACCES); 1290c8ec8eeaSjose borrego 1291dc20a302Sas rc = smb_ofile_access(sr->fid_ofile, cr, FILE_WRITE_DATA); 1292dc20a302Sas if (rc != NT_STATUS_SUCCESS) { 1293dc20a302Sas rc = smb_ofile_access(sr->fid_ofile, cr, FILE_APPEND_DATA); 1294dc20a302Sas if (rc != NT_STATUS_SUCCESS) 1295dc20a302Sas return (EACCES); 1296dc20a302Sas } 1297da6c28aaSamw 1298da6c28aaSamw unnamed_node = SMB_IS_STREAM(snode); 1299da6c28aaSamw 1300da6c28aaSamw if (unnamed_node) { 1301da6c28aaSamw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 1302da6c28aaSamw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 1303da6c28aaSamw unnamed_vp = unnamed_node->vp; 1304da6c28aaSamw /* 1305da6c28aaSamw * Streams permission are checked against the unnamed stream, 1306da6c28aaSamw * but in FS level they have their own permissions. To avoid 1307da6c28aaSamw * rejection by FS due to lack of permission on the actual 1308da6c28aaSamw * extended attr kcred is passed for streams. 1309da6c28aaSamw */ 1310da6c28aaSamw cr = kcred; 1311da6c28aaSamw } 1312da6c28aaSamw 1313dc20a302Sas smb_node_start_crit(snode, RW_READER); 1314c8ec8eeaSjose borrego rc = nbl_svmand(snode->vp, kcred, &svmand); 1315dc20a302Sas if (rc) { 1316dc20a302Sas smb_node_end_crit(snode); 1317dc20a302Sas return (rc); 1318dc20a302Sas } 1319c8ec8eeaSjose borrego 1320c8ec8eeaSjose borrego ct = smb_ct; 1321c8ec8eeaSjose borrego ct.cc_pid = sr->fid_ofile->f_uniqid; 1322dc20a302Sas rc = nbl_lock_conflict(snode->vp, NBL_WRITE, uio->uio_loffset, 1323c8ec8eeaSjose borrego uio->uio_iov->iov_len, svmand, &ct); 1324da6c28aaSamw 1325dc20a302Sas if (rc) { 1326dc20a302Sas smb_node_end_crit(snode); 13276537f381Sas return (ERANGE); 1328dc20a302Sas } 13293db3f65cSamw rc = smb_vop_write(snode->vp, uio, ioflag, lcount, cr); 1330dc20a302Sas 1331dc20a302Sas if (rc == 0 && ret_attr) { 1332da6c28aaSamw /* 1333dc20a302Sas * Use kcred to update the node attr because this 1334dc20a302Sas * call is not being made on behalf of the user. 1335da6c28aaSamw */ 1336da6c28aaSamw ret_attr->sa_mask = SMB_AT_ALL; 1337dc20a302Sas if (smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0, 1338dc20a302Sas kcred) == 0) { 1339dc20a302Sas snode->attr = *ret_attr; 1340dc20a302Sas } 1341da6c28aaSamw } 1342da6c28aaSamw 1343dc20a302Sas smb_node_end_crit(snode); 1344dc20a302Sas 1345da6c28aaSamw return (rc); 1346da6c28aaSamw } 1347da6c28aaSamw 1348da6c28aaSamw /* 1349da6c28aaSamw * smb_fsop_statfs 1350da6c28aaSamw * 1351da6c28aaSamw * This is a wrapper function used for stat operations. 1352da6c28aaSamw */ 1353da6c28aaSamw int 1354da6c28aaSamw smb_fsop_statfs( 1355da6c28aaSamw cred_t *cr, 1356da6c28aaSamw smb_node_t *snode, 1357da6c28aaSamw struct statvfs64 *statp) 1358da6c28aaSamw { 1359da6c28aaSamw ASSERT(cr); 1360da6c28aaSamw ASSERT(snode); 1361da6c28aaSamw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 1362da6c28aaSamw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 1363da6c28aaSamw 1364da6c28aaSamw return (smb_vop_statfs(snode->vp, statp, cr)); 1365da6c28aaSamw } 1366da6c28aaSamw 1367da6c28aaSamw /* 1368da6c28aaSamw * smb_fsop_access 1369ee60c47bSjm * 1370ee60c47bSjm * Named streams do not have separate permissions from the associated 1371ee60c47bSjm * unnamed stream. Thus, if node is a named stream, the permissions 1372ee60c47bSjm * check will be performed on the associated unnamed stream. 1373ee60c47bSjm * 1374ee60c47bSjm * However, our named streams do have their own quarantine attribute, 1375ee60c47bSjm * separate from that on the unnamed stream. If READ or EXECUTE 1376ee60c47bSjm * access has been requested on a named stream, an additional access 1377ee60c47bSjm * check is performed on the named stream in case it has been 1378ee60c47bSjm * quarantined. kcred is used to avoid issues with the permissions 1379ee60c47bSjm * set on the extended attribute file representing the named stream. 1380da6c28aaSamw */ 1381da6c28aaSamw int 1382da6c28aaSamw smb_fsop_access(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 1383da6c28aaSamw uint32_t faccess) 1384da6c28aaSamw { 1385da6c28aaSamw int access = 0; 1386da6c28aaSamw int error; 1387da6c28aaSamw vnode_t *dir_vp; 1388da6c28aaSamw boolean_t acl_check = B_TRUE; 1389da6c28aaSamw smb_node_t *unnamed_node; 1390da6c28aaSamw 1391c8ec8eeaSjose borrego ASSERT(sr); 1392da6c28aaSamw ASSERT(cr); 1393da6c28aaSamw ASSERT(snode); 1394da6c28aaSamw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 1395da6c28aaSamw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 1396da6c28aaSamw 1397da6c28aaSamw if (faccess == 0) 1398da6c28aaSamw return (NT_STATUS_SUCCESS); 1399da6c28aaSamw 1400c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) { 1401da6c28aaSamw if (faccess & (FILE_WRITE_DATA|FILE_APPEND_DATA| 1402da6c28aaSamw FILE_WRITE_EA|FILE_DELETE_CHILD|FILE_WRITE_ATTRIBUTES| 1403da6c28aaSamw DELETE|WRITE_DAC|WRITE_OWNER)) { 1404da6c28aaSamw return (NT_STATUS_ACCESS_DENIED); 1405da6c28aaSamw } 1406da6c28aaSamw } 1407da6c28aaSamw 1408da6c28aaSamw unnamed_node = SMB_IS_STREAM(snode); 1409da6c28aaSamw if (unnamed_node) { 1410da6c28aaSamw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 1411da6c28aaSamw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 1412ee60c47bSjm 1413ee60c47bSjm /* 1414ee60c47bSjm * Perform VREAD access check on the named stream in case it 1415ee60c47bSjm * is quarantined. kcred is passed to smb_vop_access so it 1416ee60c47bSjm * doesn't fail due to lack of permission. 1417ee60c47bSjm */ 1418ee60c47bSjm if (faccess & (FILE_READ_DATA | FILE_EXECUTE)) { 1419ee60c47bSjm error = smb_vop_access(snode->vp, VREAD, 1420ee60c47bSjm 0, NULL, kcred); 1421ee60c47bSjm if (error) 1422ee60c47bSjm return (NT_STATUS_ACCESS_DENIED); 1423ee60c47bSjm } 1424ee60c47bSjm 1425da6c28aaSamw /* 1426da6c28aaSamw * Streams authorization should be performed against the 1427da6c28aaSamw * unnamed stream. 1428da6c28aaSamw */ 1429da6c28aaSamw snode = unnamed_node; 1430da6c28aaSamw } 1431da6c28aaSamw 1432da6c28aaSamw if (faccess & ACCESS_SYSTEM_SECURITY) { 1433da6c28aaSamw /* 1434da6c28aaSamw * This permission is required for reading/writing SACL and 1435da6c28aaSamw * it's not part of DACL. It's only granted via proper 1436da6c28aaSamw * privileges. 1437da6c28aaSamw */ 1438da6c28aaSamw if ((sr->uid_user->u_privileges & 1439da6c28aaSamw (SMB_USER_PRIV_BACKUP | 1440da6c28aaSamw SMB_USER_PRIV_RESTORE | 1441da6c28aaSamw SMB_USER_PRIV_SECURITY)) == 0) 1442da6c28aaSamw return (NT_STATUS_PRIVILEGE_NOT_HELD); 1443da6c28aaSamw 1444da6c28aaSamw faccess &= ~ACCESS_SYSTEM_SECURITY; 1445da6c28aaSamw } 1446da6c28aaSamw 1447da6c28aaSamw /* Links don't have ACL */ 1448c8ec8eeaSjose borrego if ((!smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) || 1449da6c28aaSamw (snode->attr.sa_vattr.va_type == VLNK)) 1450da6c28aaSamw acl_check = B_FALSE; 1451da6c28aaSamw 1452743a77edSAlan Wright /* 1453743a77edSAlan Wright * Use the most restrictive parts of both faccess and the 1454743a77edSAlan Wright * share access. An AND of the two value masks gives us that 1455743a77edSAlan Wright * since we've already converted to a mask of what we "can" 1456743a77edSAlan Wright * do. 1457743a77edSAlan Wright */ 1458743a77edSAlan Wright faccess &= sr->tid_tree->t_access; 1459743a77edSAlan Wright 1460da6c28aaSamw if (acl_check) { 1461da6c28aaSamw dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL; 1462da6c28aaSamw error = smb_vop_access(snode->vp, faccess, V_ACE_MASK, dir_vp, 1463da6c28aaSamw cr); 1464da6c28aaSamw } else { 1465da6c28aaSamw /* 1466da6c28aaSamw * FS doesn't understand 32-bit mask, need to map 1467da6c28aaSamw */ 1468da6c28aaSamw if (faccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) 1469da6c28aaSamw access |= VWRITE; 1470da6c28aaSamw 1471da6c28aaSamw if (faccess & FILE_READ_DATA) 1472da6c28aaSamw access |= VREAD; 1473da6c28aaSamw 1474da6c28aaSamw if (faccess & FILE_EXECUTE) 1475da6c28aaSamw access |= VEXEC; 1476da6c28aaSamw 1477da6c28aaSamw error = smb_vop_access(snode->vp, access, 0, NULL, cr); 1478da6c28aaSamw } 1479da6c28aaSamw 1480da6c28aaSamw return ((error) ? NT_STATUS_ACCESS_DENIED : NT_STATUS_SUCCESS); 1481da6c28aaSamw } 1482da6c28aaSamw 1483da6c28aaSamw /* 1484da6c28aaSamw * smb_fsop_lookup_name() 1485da6c28aaSamw * 1486b89a8333Snatalie li - Sun Microsystems - Irvine United States * If name indicates that the file is a stream file, perform 1487b89a8333Snatalie li - Sun Microsystems - Irvine United States * stream specific lookup, otherwise call smb_fsop_lookup. 1488da6c28aaSamw * 1489b89a8333Snatalie li - Sun Microsystems - Irvine United States * Return an error if the looked-up file is in outside the tree. 1490b89a8333Snatalie li - Sun Microsystems - Irvine United States * (Required when invoked from open path.) 1491da6c28aaSamw */ 1492da6c28aaSamw 1493da6c28aaSamw int 1494da6c28aaSamw smb_fsop_lookup_name( 1495faa1795aSjb smb_request_t *sr, 1496da6c28aaSamw cred_t *cr, 1497da6c28aaSamw int flags, 1498da6c28aaSamw smb_node_t *root_node, 1499*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_t *dnode, 1500da6c28aaSamw char *name, 1501da6c28aaSamw smb_node_t **ret_snode, 1502da6c28aaSamw smb_attr_t *ret_attr) 1503da6c28aaSamw { 1504faa1795aSjb smb_node_t *fnode; 1505faa1795aSjb smb_attr_t file_attr; 1506faa1795aSjb vnode_t *xattrdirvp; 1507faa1795aSjb vnode_t *vp; 1508faa1795aSjb char *od_name; 1509faa1795aSjb char *fname; 1510faa1795aSjb char *sname; 1511faa1795aSjb int rc; 1512da6c28aaSamw 1513da6c28aaSamw ASSERT(cr); 1514*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode); 1515*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode->n_magic == SMB_NODE_MAGIC); 1516*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING); 1517da6c28aaSamw 1518da6c28aaSamw /* 1519da6c28aaSamw * The following check is required for streams processing, below 1520da6c28aaSamw */ 1521da6c28aaSamw 1522c8ec8eeaSjose borrego if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 1523da6c28aaSamw flags |= SMB_IGNORE_CASE; 1524da6c28aaSamw 1525da6c28aaSamw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1526da6c28aaSamw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1527da6c28aaSamw 1528*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (smb_is_stream_name(name)) { 1529*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_stream_parse_name(name, fname, sname); 15308d7e4166Sjose borrego 1531da6c28aaSamw /* 1532da6c28aaSamw * Look up the unnamed stream (i.e. fname). 1533da6c28aaSamw * Unmangle processing will be done on fname 1534da6c28aaSamw * as well as any link target. 1535da6c28aaSamw */ 1536*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_fsop_lookup(sr, cr, flags, root_node, dnode, fname, 15378b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States &fnode, &file_attr); 1538da6c28aaSamw 1539da6c28aaSamw if (rc != 0) { 1540da6c28aaSamw kmem_free(fname, MAXNAMELEN); 1541da6c28aaSamw kmem_free(sname, MAXNAMELEN); 1542da6c28aaSamw return (rc); 1543da6c28aaSamw } 1544da6c28aaSamw 1545da6c28aaSamw od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1546da6c28aaSamw 1547da6c28aaSamw /* 1548da6c28aaSamw * od_name is the on-disk name of the stream, except 1549da6c28aaSamw * without the prepended stream prefix (SMB_STREAM_PREFIX) 1550da6c28aaSamw */ 1551da6c28aaSamw 1552da6c28aaSamw /* 1553da6c28aaSamw * XXX 1554da6c28aaSamw * What permissions NTFS requires for stream lookup if any? 1555da6c28aaSamw */ 1556da6c28aaSamw rc = smb_vop_stream_lookup(fnode->vp, sname, &vp, od_name, 1557dc20a302Sas &xattrdirvp, flags, root_node->vp, cr); 1558da6c28aaSamw 1559da6c28aaSamw if (rc != 0) { 1560da6c28aaSamw smb_node_release(fnode); 1561da6c28aaSamw kmem_free(fname, MAXNAMELEN); 1562da6c28aaSamw kmem_free(sname, MAXNAMELEN); 1563da6c28aaSamw kmem_free(od_name, MAXNAMELEN); 1564da6c28aaSamw return (rc); 1565da6c28aaSamw } 1566da6c28aaSamw 1567da6c28aaSamw *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, 1568da6c28aaSamw vp, od_name, ret_attr); 1569da6c28aaSamw 1570da6c28aaSamw kmem_free(od_name, MAXNAMELEN); 1571da6c28aaSamw smb_node_release(fnode); 15727f667e74Sjose borrego VN_RELE(xattrdirvp); 15737f667e74Sjose borrego VN_RELE(vp); 1574da6c28aaSamw 1575da6c28aaSamw if (*ret_snode == NULL) { 1576da6c28aaSamw kmem_free(fname, MAXNAMELEN); 1577da6c28aaSamw kmem_free(sname, MAXNAMELEN); 1578da6c28aaSamw return (ENOMEM); 1579da6c28aaSamw } 1580da6c28aaSamw } else { 1581*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_fsop_lookup(sr, cr, flags, root_node, dnode, name, 15828b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States ret_snode, ret_attr); 1583da6c28aaSamw } 1584da6c28aaSamw 1585da6c28aaSamw if (rc == 0) { 1586da6c28aaSamw ASSERT(ret_snode); 1587c8ec8eeaSjose borrego if (SMB_TREE_CONTAINS_NODE(sr, *ret_snode) == 0) { 1588da6c28aaSamw smb_node_release(*ret_snode); 1589da6c28aaSamw *ret_snode = NULL; 1590da6c28aaSamw rc = EACCES; 1591da6c28aaSamw } 1592da6c28aaSamw } 1593da6c28aaSamw 1594da6c28aaSamw kmem_free(fname, MAXNAMELEN); 1595da6c28aaSamw kmem_free(sname, MAXNAMELEN); 1596da6c28aaSamw 1597da6c28aaSamw return (rc); 1598da6c28aaSamw } 1599da6c28aaSamw 1600da6c28aaSamw /* 1601da6c28aaSamw * smb_fsop_lookup 1602da6c28aaSamw * 1603da6c28aaSamw * All SMB functions should use this smb_vop_lookup wrapper to ensure that 1604da6c28aaSamw * the smb_vop_lookup is performed with the appropriate credentials and using 1605da6c28aaSamw * case insensitive compares. Please document any direct call to smb_vop_lookup 1606da6c28aaSamw * to explain the reason for avoiding this wrapper. 1607da6c28aaSamw * 1608*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * It is assumed that a reference exists on dnode coming into this routine 1609da6c28aaSamw * (and that it is safe from deallocation). 1610da6c28aaSamw * 1611da6c28aaSamw * Same with the root_node. 1612da6c28aaSamw * 1613da6c28aaSamw * *ret_snode is returned with a reference upon success. No reference is 1614da6c28aaSamw * taken if an error is returned. 1615da6c28aaSamw * 1616da6c28aaSamw * Note: The returned ret_snode may be in a child mount. This is ok for 16177f667e74Sjose borrego * readdir. 1618da6c28aaSamw * 1619c8ec8eeaSjose borrego * Other smb_fsop_* routines will call SMB_TREE_CONTAINS_NODE() to prevent 1620da6c28aaSamw * operations on files not in the parent mount. 1621da6c28aaSamw */ 1622da6c28aaSamw int 1623da6c28aaSamw smb_fsop_lookup( 1624faa1795aSjb smb_request_t *sr, 1625da6c28aaSamw cred_t *cr, 1626da6c28aaSamw int flags, 1627da6c28aaSamw smb_node_t *root_node, 1628*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_t *dnode, 1629da6c28aaSamw char *name, 1630da6c28aaSamw smb_node_t **ret_snode, 16318b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_attr_t *ret_attr) 1632da6c28aaSamw { 1633da6c28aaSamw smb_node_t *lnk_target_node; 1634da6c28aaSamw smb_node_t *lnk_dnode; 1635da6c28aaSamw char *longname; 1636da6c28aaSamw char *od_name; 1637da6c28aaSamw vnode_t *vp; 1638da6c28aaSamw int rc; 16398b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States int ret_flags; 1640da6c28aaSamw 1641da6c28aaSamw ASSERT(cr); 1642*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode); 1643*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode->n_magic == SMB_NODE_MAGIC); 1644*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(dnode->n_state != SMB_NODE_STATE_DESTROYING); 1645da6c28aaSamw 1646da6c28aaSamw if (name == NULL) 1647da6c28aaSamw return (EINVAL); 1648da6c28aaSamw 1649*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_CONTAINS_NODE(sr, dnode) == 0) 1650da6c28aaSamw return (EACCES); 1651da6c28aaSamw 1652c8ec8eeaSjose borrego if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 1653da6c28aaSamw flags |= SMB_IGNORE_CASE; 16548b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_TREE_SUPPORTS_CATIA(sr)) 16558b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States flags |= SMB_CATIA; 1656da6c28aaSamw 1657da6c28aaSamw od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1658da6c28aaSamw 1659*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_lookup(dnode->vp, name, &vp, od_name, flags, 16608b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States &ret_flags, root_node ? root_node->vp : NULL, cr); 1661da6c28aaSamw 1662da6c28aaSamw if (rc != 0) { 1663da6c28aaSamw if (smb_maybe_mangled_name(name) == 0) { 1664da6c28aaSamw kmem_free(od_name, MAXNAMELEN); 1665da6c28aaSamw return (rc); 1666da6c28aaSamw } 1667da6c28aaSamw 1668da6c28aaSamw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1669*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN); 1670da6c28aaSamw if (rc != 0) { 1671da6c28aaSamw kmem_free(od_name, MAXNAMELEN); 1672da6c28aaSamw kmem_free(longname, MAXNAMELEN); 1673da6c28aaSamw return (rc); 1674da6c28aaSamw } 1675da6c28aaSamw 1676da6c28aaSamw /* 16778b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * longname is the real (case-sensitive) 16788b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * on-disk name. 1679da6c28aaSamw * We make sure we do a lookup on this exact 1680da6c28aaSamw * name, as the name was mangled and denotes 1681da6c28aaSamw * a unique file. 1682da6c28aaSamw */ 1683da6c28aaSamw 1684da6c28aaSamw if (flags & SMB_IGNORE_CASE) 1685da6c28aaSamw flags &= ~SMB_IGNORE_CASE; 1686da6c28aaSamw 1687*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_vop_lookup(dnode->vp, longname, &vp, od_name, 16888b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States flags, &ret_flags, root_node ? root_node->vp : NULL, cr); 1689da6c28aaSamw 1690da6c28aaSamw kmem_free(longname, MAXNAMELEN); 1691da6c28aaSamw 1692da6c28aaSamw if (rc != 0) { 1693da6c28aaSamw kmem_free(od_name, MAXNAMELEN); 1694da6c28aaSamw return (rc); 1695da6c28aaSamw } 1696da6c28aaSamw } 1697da6c28aaSamw 1698da6c28aaSamw if ((flags & SMB_FOLLOW_LINKS) && (vp->v_type == VLNK)) { 1699da6c28aaSamw 1700*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_pathname(sr, od_name, FOLLOW, root_node, dnode, 1701da6c28aaSamw &lnk_dnode, &lnk_target_node, cr); 1702da6c28aaSamw 1703da6c28aaSamw if (rc != 0) { 1704da6c28aaSamw /* 1705da6c28aaSamw * The link is assumed to be for the last component 1706da6c28aaSamw * of a path. Hence any ENOTDIR error will be returned 1707da6c28aaSamw * as ENOENT. 1708da6c28aaSamw */ 1709da6c28aaSamw if (rc == ENOTDIR) 1710da6c28aaSamw rc = ENOENT; 1711da6c28aaSamw 1712da6c28aaSamw VN_RELE(vp); 1713da6c28aaSamw kmem_free(od_name, MAXNAMELEN); 1714da6c28aaSamw return (rc); 1715da6c28aaSamw } 1716da6c28aaSamw 1717da6c28aaSamw /* 1718da6c28aaSamw * Release the original VLNK vnode 1719da6c28aaSamw */ 1720da6c28aaSamw 1721da6c28aaSamw VN_RELE(vp); 1722da6c28aaSamw vp = lnk_target_node->vp; 1723da6c28aaSamw 1724da6c28aaSamw rc = smb_vop_traverse_check(&vp); 1725da6c28aaSamw 1726da6c28aaSamw if (rc != 0) { 1727da6c28aaSamw smb_node_release(lnk_dnode); 1728da6c28aaSamw smb_node_release(lnk_target_node); 1729da6c28aaSamw kmem_free(od_name, MAXNAMELEN); 1730da6c28aaSamw return (rc); 1731da6c28aaSamw } 1732da6c28aaSamw 1733da6c28aaSamw /* 1734da6c28aaSamw * smb_vop_traverse_check() may have returned a different vnode 1735da6c28aaSamw */ 1736da6c28aaSamw 1737da6c28aaSamw if (lnk_target_node->vp == vp) { 1738da6c28aaSamw *ret_snode = lnk_target_node; 1739da6c28aaSamw *ret_attr = (*ret_snode)->attr; 1740da6c28aaSamw } else { 1741da6c28aaSamw *ret_snode = smb_node_lookup(sr, NULL, cr, vp, 1742da6c28aaSamw lnk_target_node->od_name, lnk_dnode, NULL, 1743da6c28aaSamw ret_attr); 17447f667e74Sjose borrego VN_RELE(vp); 1745da6c28aaSamw 17467f667e74Sjose borrego if (*ret_snode == NULL) 1747da6c28aaSamw rc = ENOMEM; 1748da6c28aaSamw smb_node_release(lnk_target_node); 1749da6c28aaSamw } 1750da6c28aaSamw 1751da6c28aaSamw smb_node_release(lnk_dnode); 1752da6c28aaSamw 1753da6c28aaSamw } else { 1754da6c28aaSamw 1755da6c28aaSamw rc = smb_vop_traverse_check(&vp); 1756da6c28aaSamw if (rc) { 1757da6c28aaSamw VN_RELE(vp); 1758da6c28aaSamw kmem_free(od_name, MAXNAMELEN); 1759da6c28aaSamw return (rc); 1760da6c28aaSamw } 1761da6c28aaSamw 1762da6c28aaSamw *ret_snode = smb_node_lookup(sr, NULL, cr, vp, od_name, 1763*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States dnode, NULL, ret_attr); 17647f667e74Sjose borrego VN_RELE(vp); 1765da6c28aaSamw 17667f667e74Sjose borrego if (*ret_snode == NULL) 1767da6c28aaSamw rc = ENOMEM; 1768da6c28aaSamw } 1769da6c28aaSamw 1770da6c28aaSamw kmem_free(od_name, MAXNAMELEN); 1771da6c28aaSamw return (rc); 1772da6c28aaSamw } 1773da6c28aaSamw 1774da6c28aaSamw int /*ARGSUSED*/ 1775da6c28aaSamw smb_fsop_commit(smb_request_t *sr, cred_t *cr, smb_node_t *snode) 1776da6c28aaSamw { 1777da6c28aaSamw ASSERT(cr); 1778da6c28aaSamw ASSERT(snode); 1779da6c28aaSamw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 1780da6c28aaSamw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 1781da6c28aaSamw 1782da6c28aaSamw ASSERT(sr); 1783da6c28aaSamw ASSERT(sr->tid_tree); 1784c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) 1785da6c28aaSamw return (EROFS); 1786da6c28aaSamw 1787dc20a302Sas return (smb_vop_commit(snode->vp, cr)); 1788da6c28aaSamw } 1789da6c28aaSamw 1790da6c28aaSamw /* 1791da6c28aaSamw * smb_fsop_aclread 1792da6c28aaSamw * 1793da6c28aaSamw * Retrieve filesystem ACL. Depends on requested ACLs in 1794da6c28aaSamw * fs_sd->sd_secinfo, it'll set DACL and SACL pointers in 1795da6c28aaSamw * fs_sd. Note that requesting a DACL/SACL doesn't mean that 1796da6c28aaSamw * the corresponding field in fs_sd should be non-NULL upon 1797da6c28aaSamw * return, since the target ACL might not contain that type of 1798da6c28aaSamw * entries. 1799da6c28aaSamw * 1800da6c28aaSamw * Returned ACL is always in ACE_T (aka ZFS) format. 1801da6c28aaSamw * If successful the allocated memory for the ACL should be freed 180255bf511dSas * using smb_fsacl_free() or smb_fssd_term() 1803da6c28aaSamw */ 1804da6c28aaSamw int 1805da6c28aaSamw smb_fsop_aclread(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 1806da6c28aaSamw smb_fssd_t *fs_sd) 1807da6c28aaSamw { 1808da6c28aaSamw int error = 0; 1809da6c28aaSamw int flags = 0; 1810da6c28aaSamw int access = 0; 1811da6c28aaSamw acl_t *acl; 1812da6c28aaSamw smb_node_t *unnamed_node; 1813da6c28aaSamw 1814da6c28aaSamw ASSERT(cr); 1815da6c28aaSamw 1816743a77edSAlan Wright if (SMB_TREE_HAS_ACCESS(sr, ACE_READ_ACL) == 0) 1817743a77edSAlan Wright return (EACCES); 1818743a77edSAlan Wright 1819da6c28aaSamw if (sr->fid_ofile) { 1820da6c28aaSamw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 1821da6c28aaSamw access = READ_CONTROL; 1822da6c28aaSamw 1823da6c28aaSamw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 1824da6c28aaSamw access |= ACCESS_SYSTEM_SECURITY; 1825da6c28aaSamw 1826da6c28aaSamw error = smb_ofile_access(sr->fid_ofile, cr, access); 1827da6c28aaSamw if (error != NT_STATUS_SUCCESS) { 1828da6c28aaSamw return (EACCES); 1829da6c28aaSamw } 1830da6c28aaSamw } 1831da6c28aaSamw 1832da6c28aaSamw unnamed_node = SMB_IS_STREAM(snode); 1833da6c28aaSamw if (unnamed_node) { 1834da6c28aaSamw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 1835da6c28aaSamw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 1836da6c28aaSamw /* 1837da6c28aaSamw * Streams don't have ACL, any read ACL attempt on a stream 1838da6c28aaSamw * should be performed on the unnamed stream. 1839da6c28aaSamw */ 1840da6c28aaSamw snode = unnamed_node; 1841da6c28aaSamw } 1842da6c28aaSamw 1843c8ec8eeaSjose borrego if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) 1844da6c28aaSamw flags = ATTR_NOACLCHECK; 1845da6c28aaSamw 1846da6c28aaSamw error = smb_vop_acl_read(snode->vp, &acl, flags, 1847dc20a302Sas sr->tid_tree->t_acltype, cr); 1848da6c28aaSamw if (error != 0) { 1849da6c28aaSamw return (error); 1850da6c28aaSamw } 1851da6c28aaSamw 1852da6c28aaSamw error = acl_translate(acl, _ACL_ACE_ENABLED, 1853da6c28aaSamw (snode->vp->v_type == VDIR), fs_sd->sd_uid, fs_sd->sd_gid); 1854da6c28aaSamw 1855da6c28aaSamw if (error == 0) { 185655bf511dSas smb_fsacl_split(acl, &fs_sd->sd_zdacl, &fs_sd->sd_zsacl, 1857da6c28aaSamw fs_sd->sd_secinfo); 1858da6c28aaSamw } 1859da6c28aaSamw 1860da6c28aaSamw acl_free(acl); 1861da6c28aaSamw return (error); 1862da6c28aaSamw } 1863da6c28aaSamw 1864da6c28aaSamw /* 1865da6c28aaSamw * smb_fsop_aclwrite 1866da6c28aaSamw * 1867da6c28aaSamw * Stores the filesystem ACL provided in fs_sd->sd_acl. 1868da6c28aaSamw */ 1869da6c28aaSamw int 1870da6c28aaSamw smb_fsop_aclwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 1871da6c28aaSamw smb_fssd_t *fs_sd) 1872da6c28aaSamw { 1873da6c28aaSamw int target_flavor; 1874da6c28aaSamw int error = 0; 1875da6c28aaSamw int flags = 0; 1876da6c28aaSamw int access = 0; 1877da6c28aaSamw acl_t *acl, *dacl, *sacl; 1878da6c28aaSamw smb_node_t *unnamed_node; 1879da6c28aaSamw 1880da6c28aaSamw ASSERT(cr); 1881da6c28aaSamw 1882da6c28aaSamw ASSERT(sr); 1883da6c28aaSamw ASSERT(sr->tid_tree); 1884c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) 1885da6c28aaSamw return (EROFS); 1886da6c28aaSamw 1887743a77edSAlan Wright if (SMB_TREE_HAS_ACCESS(sr, ACE_WRITE_ACL) == 0) 1888743a77edSAlan Wright return (EACCES); 1889743a77edSAlan Wright 1890da6c28aaSamw if (sr->fid_ofile) { 1891da6c28aaSamw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 1892da6c28aaSamw access = WRITE_DAC; 1893da6c28aaSamw 1894da6c28aaSamw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 1895da6c28aaSamw access |= ACCESS_SYSTEM_SECURITY; 1896da6c28aaSamw 1897da6c28aaSamw error = smb_ofile_access(sr->fid_ofile, cr, access); 1898da6c28aaSamw if (error != NT_STATUS_SUCCESS) 1899da6c28aaSamw return (EACCES); 1900da6c28aaSamw } 1901da6c28aaSamw 1902da6c28aaSamw switch (sr->tid_tree->t_acltype) { 1903da6c28aaSamw case ACLENT_T: 1904da6c28aaSamw target_flavor = _ACL_ACLENT_ENABLED; 1905da6c28aaSamw break; 1906da6c28aaSamw 1907da6c28aaSamw case ACE_T: 1908da6c28aaSamw target_flavor = _ACL_ACE_ENABLED; 1909da6c28aaSamw break; 1910da6c28aaSamw default: 1911da6c28aaSamw return (EINVAL); 1912da6c28aaSamw } 1913da6c28aaSamw 1914da6c28aaSamw unnamed_node = SMB_IS_STREAM(snode); 1915da6c28aaSamw if (unnamed_node) { 1916da6c28aaSamw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 1917da6c28aaSamw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 1918da6c28aaSamw /* 1919da6c28aaSamw * Streams don't have ACL, any write ACL attempt on a stream 1920da6c28aaSamw * should be performed on the unnamed stream. 1921da6c28aaSamw */ 1922da6c28aaSamw snode = unnamed_node; 1923da6c28aaSamw } 1924da6c28aaSamw 1925da6c28aaSamw dacl = fs_sd->sd_zdacl; 1926da6c28aaSamw sacl = fs_sd->sd_zsacl; 1927da6c28aaSamw 1928da6c28aaSamw ASSERT(dacl || sacl); 1929da6c28aaSamw if ((dacl == NULL) && (sacl == NULL)) 1930da6c28aaSamw return (EINVAL); 1931da6c28aaSamw 1932da6c28aaSamw if (dacl && sacl) 193355bf511dSas acl = smb_fsacl_merge(dacl, sacl); 1934da6c28aaSamw else if (dacl) 1935da6c28aaSamw acl = dacl; 1936da6c28aaSamw else 1937da6c28aaSamw acl = sacl; 1938da6c28aaSamw 1939da6c28aaSamw error = acl_translate(acl, target_flavor, (snode->vp->v_type == VDIR), 1940da6c28aaSamw fs_sd->sd_uid, fs_sd->sd_gid); 1941da6c28aaSamw if (error == 0) { 1942c8ec8eeaSjose borrego if (smb_tree_has_feature(sr->tid_tree, 1943c8ec8eeaSjose borrego SMB_TREE_ACEMASKONACCESS)) 1944da6c28aaSamw flags = ATTR_NOACLCHECK; 1945da6c28aaSamw 1946dc20a302Sas error = smb_vop_acl_write(snode->vp, acl, flags, cr); 1947da6c28aaSamw } 1948da6c28aaSamw 1949da6c28aaSamw if (dacl && sacl) 1950da6c28aaSamw acl_free(acl); 1951da6c28aaSamw 1952da6c28aaSamw return (error); 1953da6c28aaSamw } 1954da6c28aaSamw 1955da6c28aaSamw acl_type_t 1956da6c28aaSamw smb_fsop_acltype(smb_node_t *snode) 1957da6c28aaSamw { 1958da6c28aaSamw return (smb_vop_acl_type(snode->vp)); 1959da6c28aaSamw } 1960da6c28aaSamw 1961da6c28aaSamw /* 1962da6c28aaSamw * smb_fsop_sdread 1963da6c28aaSamw * 1964da6c28aaSamw * Read the requested security descriptor items from filesystem. 1965da6c28aaSamw * The items are specified in fs_sd->sd_secinfo. 1966da6c28aaSamw */ 1967da6c28aaSamw int 1968da6c28aaSamw smb_fsop_sdread(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 1969da6c28aaSamw smb_fssd_t *fs_sd) 1970da6c28aaSamw { 1971da6c28aaSamw int error = 0; 1972da6c28aaSamw int getowner = 0; 1973da6c28aaSamw cred_t *ga_cred; 1974da6c28aaSamw smb_attr_t attr; 1975da6c28aaSamw 1976da6c28aaSamw ASSERT(cr); 1977da6c28aaSamw ASSERT(fs_sd); 1978da6c28aaSamw 1979da6c28aaSamw /* 1980da6c28aaSamw * File's uid/gid is fetched in two cases: 1981da6c28aaSamw * 1982da6c28aaSamw * 1. it's explicitly requested 1983da6c28aaSamw * 1984da6c28aaSamw * 2. target ACL is ACE_T (ZFS ACL). They're needed for 1985da6c28aaSamw * owner@/group@ entries. In this case kcred should be used 1986da6c28aaSamw * because uid/gid are fetched on behalf of smb server. 1987da6c28aaSamw */ 1988da6c28aaSamw if (fs_sd->sd_secinfo & (SMB_OWNER_SECINFO | SMB_GROUP_SECINFO)) { 1989da6c28aaSamw getowner = 1; 1990da6c28aaSamw ga_cred = cr; 1991da6c28aaSamw } else if (sr->tid_tree->t_acltype == ACE_T) { 1992da6c28aaSamw getowner = 1; 1993da6c28aaSamw ga_cred = kcred; 1994da6c28aaSamw } 1995da6c28aaSamw 1996da6c28aaSamw if (getowner) { 1997da6c28aaSamw /* 1998da6c28aaSamw * Windows require READ_CONTROL to read owner/group SID since 1999da6c28aaSamw * they're part of Security Descriptor. 2000da6c28aaSamw * ZFS only requires read_attribute. Need to have a explicit 2001da6c28aaSamw * access check here. 2002da6c28aaSamw */ 2003da6c28aaSamw if (sr->fid_ofile == NULL) { 2004da6c28aaSamw error = smb_fsop_access(sr, ga_cred, snode, 2005da6c28aaSamw READ_CONTROL); 2006da6c28aaSamw if (error) 2007da6c28aaSamw return (error); 2008da6c28aaSamw } 2009da6c28aaSamw 2010da6c28aaSamw attr.sa_mask = SMB_AT_UID | SMB_AT_GID; 2011da6c28aaSamw error = smb_fsop_getattr(sr, ga_cred, snode, &attr); 2012da6c28aaSamw if (error == 0) { 2013da6c28aaSamw fs_sd->sd_uid = attr.sa_vattr.va_uid; 2014da6c28aaSamw fs_sd->sd_gid = attr.sa_vattr.va_gid; 2015da6c28aaSamw } else { 2016da6c28aaSamw return (error); 2017da6c28aaSamw } 2018da6c28aaSamw } 2019da6c28aaSamw 2020da6c28aaSamw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 2021da6c28aaSamw error = smb_fsop_aclread(sr, cr, snode, fs_sd); 2022da6c28aaSamw } 2023da6c28aaSamw 2024da6c28aaSamw return (error); 2025da6c28aaSamw } 2026da6c28aaSamw 2027da6c28aaSamw /* 2028da6c28aaSamw * smb_fsop_sdmerge 2029da6c28aaSamw * 2030da6c28aaSamw * From SMB point of view DACL and SACL are two separate list 2031da6c28aaSamw * which can be manipulated independently without one affecting 2032da6c28aaSamw * the other, but entries for both DACL and SACL will end up 2033da6c28aaSamw * in the same ACL if target filesystem supports ACE_T ACLs. 2034da6c28aaSamw * 2035da6c28aaSamw * So, if either DACL or SACL is present in the client set request 2036da6c28aaSamw * the entries corresponding to the non-present ACL shouldn't 2037da6c28aaSamw * be touched in the FS ACL. 2038da6c28aaSamw * 2039da6c28aaSamw * fs_sd parameter contains DACL and SACL specified by SMB 2040da6c28aaSamw * client to be set on a file/directory. The client could 2041da6c28aaSamw * specify both or one of these ACLs (if none is specified 2042da6c28aaSamw * we don't get this far). When both DACL and SACL are given 2043da6c28aaSamw * by client the existing ACL should be overwritten. If only 2044da6c28aaSamw * one of them is specified the entries corresponding to the other 2045da6c28aaSamw * ACL should not be touched. For example, if only DACL 2046da6c28aaSamw * is specified in input fs_sd, the function reads audit entries 2047da6c28aaSamw * of the existing ACL of the file and point fs_sd->sd_zsdacl 2048da6c28aaSamw * pointer to the fetched SACL, this way when smb_fsop_sdwrite() 2049da6c28aaSamw * function is called the passed fs_sd would point to the specified 2050da6c28aaSamw * DACL by client and fetched SACL from filesystem, so the file 2051da6c28aaSamw * will end up with correct ACL. 2052da6c28aaSamw */ 2053da6c28aaSamw static int 2054da6c28aaSamw smb_fsop_sdmerge(smb_request_t *sr, smb_node_t *snode, smb_fssd_t *fs_sd) 2055da6c28aaSamw { 2056da6c28aaSamw smb_fssd_t cur_sd; 2057da6c28aaSamw int error = 0; 2058da6c28aaSamw 2059da6c28aaSamw if (sr->tid_tree->t_acltype != ACE_T) 2060da6c28aaSamw /* Don't bother if target FS doesn't support ACE_T */ 2061da6c28aaSamw return (0); 2062da6c28aaSamw 2063da6c28aaSamw if ((fs_sd->sd_secinfo & SMB_ACL_SECINFO) != SMB_ACL_SECINFO) { 2064da6c28aaSamw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) { 2065da6c28aaSamw /* 2066da6c28aaSamw * Don't overwrite existing audit entries 2067da6c28aaSamw */ 206855bf511dSas smb_fssd_init(&cur_sd, SMB_SACL_SECINFO, 2069da6c28aaSamw fs_sd->sd_flags); 2070da6c28aaSamw 2071da6c28aaSamw error = smb_fsop_sdread(sr, kcred, snode, &cur_sd); 2072da6c28aaSamw if (error == 0) { 2073da6c28aaSamw ASSERT(fs_sd->sd_zsacl == NULL); 2074da6c28aaSamw fs_sd->sd_zsacl = cur_sd.sd_zsacl; 2075da6c28aaSamw if (fs_sd->sd_zsacl && fs_sd->sd_zdacl) 2076da6c28aaSamw fs_sd->sd_zsacl->acl_flags = 2077da6c28aaSamw fs_sd->sd_zdacl->acl_flags; 2078da6c28aaSamw } 2079da6c28aaSamw } else { 2080da6c28aaSamw /* 2081da6c28aaSamw * Don't overwrite existing access entries 2082da6c28aaSamw */ 208355bf511dSas smb_fssd_init(&cur_sd, SMB_DACL_SECINFO, 2084da6c28aaSamw fs_sd->sd_flags); 2085da6c28aaSamw 2086da6c28aaSamw error = smb_fsop_sdread(sr, kcred, snode, &cur_sd); 2087da6c28aaSamw if (error == 0) { 2088da6c28aaSamw ASSERT(fs_sd->sd_zdacl == NULL); 2089da6c28aaSamw fs_sd->sd_zdacl = cur_sd.sd_zdacl; 2090da6c28aaSamw if (fs_sd->sd_zdacl && fs_sd->sd_zsacl) 2091da6c28aaSamw fs_sd->sd_zdacl->acl_flags = 2092da6c28aaSamw fs_sd->sd_zsacl->acl_flags; 2093da6c28aaSamw } 2094da6c28aaSamw } 2095da6c28aaSamw 2096da6c28aaSamw if (error) 209755bf511dSas smb_fssd_term(&cur_sd); 2098da6c28aaSamw } 2099da6c28aaSamw 2100da6c28aaSamw return (error); 2101da6c28aaSamw } 2102da6c28aaSamw 2103da6c28aaSamw /* 2104da6c28aaSamw * smb_fsop_sdwrite 2105da6c28aaSamw * 2106da6c28aaSamw * Stores the given uid, gid and acl in filesystem. 2107da6c28aaSamw * Provided items in fs_sd are specified by fs_sd->sd_secinfo. 2108da6c28aaSamw * 2109da6c28aaSamw * A SMB security descriptor could contain owner, primary group, 2110da6c28aaSamw * DACL and SACL. Setting an SD should be atomic but here it has to 2111da6c28aaSamw * be done via two separate FS operations: VOP_SETATTR and 2112da6c28aaSamw * VOP_SETSECATTR. Therefore, this function has to simulate the 2113da6c28aaSamw * atomicity as well as it can. 21142c1b14e5Sjose borrego * 21152c1b14e5Sjose borrego * Get the current uid, gid before setting the new uid/gid 21162c1b14e5Sjose borrego * so if smb_fsop_aclwrite fails they can be restored. root cred is 21172c1b14e5Sjose borrego * used to get currend uid/gid since this operation is performed on 21182c1b14e5Sjose borrego * behalf of the server not the user. 21192c1b14e5Sjose borrego * 21202c1b14e5Sjose borrego * If setting uid/gid fails with EPERM it means that and invalid 21212c1b14e5Sjose borrego * owner has been specified. Callers should translate this to 21222c1b14e5Sjose borrego * STATUS_INVALID_OWNER which is not the normal mapping for EPERM 21232c1b14e5Sjose borrego * in upper layers, so EPERM is mapped to EBADE. 2124da6c28aaSamw */ 2125da6c28aaSamw int 2126da6c28aaSamw smb_fsop_sdwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 2127da6c28aaSamw smb_fssd_t *fs_sd, int overwrite) 2128da6c28aaSamw { 2129da6c28aaSamw int error = 0; 2130da6c28aaSamw int access = 0; 2131da6c28aaSamw smb_attr_t set_attr; 2132da6c28aaSamw smb_attr_t orig_attr; 2133da6c28aaSamw 2134da6c28aaSamw ASSERT(cr); 2135da6c28aaSamw ASSERT(fs_sd); 2136da6c28aaSamw 2137da6c28aaSamw ASSERT(sr); 2138da6c28aaSamw ASSERT(sr->tid_tree); 2139c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) 2140da6c28aaSamw return (EROFS); 2141da6c28aaSamw 2142da6c28aaSamw bzero(&set_attr, sizeof (smb_attr_t)); 2143da6c28aaSamw 2144da6c28aaSamw if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 2145da6c28aaSamw set_attr.sa_vattr.va_uid = fs_sd->sd_uid; 2146da6c28aaSamw set_attr.sa_mask |= SMB_AT_UID; 21472c1b14e5Sjose borrego access |= WRITE_OWNER; 2148da6c28aaSamw } 2149da6c28aaSamw 2150da6c28aaSamw if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 2151da6c28aaSamw set_attr.sa_vattr.va_gid = fs_sd->sd_gid; 2152da6c28aaSamw set_attr.sa_mask |= SMB_AT_GID; 21532c1b14e5Sjose borrego access |= WRITE_OWNER; 2154da6c28aaSamw } 2155da6c28aaSamw 2156da6c28aaSamw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 2157da6c28aaSamw access |= WRITE_DAC; 2158da6c28aaSamw 2159da6c28aaSamw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 2160da6c28aaSamw access |= ACCESS_SYSTEM_SECURITY; 2161da6c28aaSamw 2162da6c28aaSamw if (sr->fid_ofile) 2163da6c28aaSamw error = smb_ofile_access(sr->fid_ofile, cr, access); 2164da6c28aaSamw else 2165da6c28aaSamw error = smb_fsop_access(sr, cr, snode, access); 2166da6c28aaSamw 2167da6c28aaSamw if (error) 2168da6c28aaSamw return (EACCES); 2169da6c28aaSamw 2170da6c28aaSamw if (set_attr.sa_mask) { 2171da6c28aaSamw orig_attr.sa_mask = SMB_AT_UID | SMB_AT_GID; 2172da6c28aaSamw error = smb_fsop_getattr(sr, kcred, snode, &orig_attr); 21732c1b14e5Sjose borrego if (error == 0) { 2174da6c28aaSamw error = smb_fsop_setattr(sr, cr, snode, &set_attr, 2175da6c28aaSamw NULL); 21762c1b14e5Sjose borrego if (error == EPERM) 21772c1b14e5Sjose borrego error = EBADE; 21782c1b14e5Sjose borrego } 2179da6c28aaSamw 2180da6c28aaSamw if (error) 2181da6c28aaSamw return (error); 2182da6c28aaSamw } 2183da6c28aaSamw 2184da6c28aaSamw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 2185da6c28aaSamw if (overwrite == 0) { 2186da6c28aaSamw error = smb_fsop_sdmerge(sr, snode, fs_sd); 2187da6c28aaSamw if (error) 2188da6c28aaSamw return (error); 2189da6c28aaSamw } 2190da6c28aaSamw 2191da6c28aaSamw error = smb_fsop_aclwrite(sr, cr, snode, fs_sd); 2192da6c28aaSamw if (error) { 2193da6c28aaSamw /* 2194da6c28aaSamw * Revert uid/gid changes if required. 2195da6c28aaSamw */ 2196da6c28aaSamw if (set_attr.sa_mask) { 2197da6c28aaSamw orig_attr.sa_mask = set_attr.sa_mask; 2198da6c28aaSamw (void) smb_fsop_setattr(sr, kcred, snode, 2199da6c28aaSamw &orig_attr, NULL); 2200da6c28aaSamw } 2201da6c28aaSamw } 2202da6c28aaSamw } 2203da6c28aaSamw 2204da6c28aaSamw return (error); 2205da6c28aaSamw } 2206da6c28aaSamw 2207da6c28aaSamw /* 2208da6c28aaSamw * smb_fsop_sdinherit 2209da6c28aaSamw * 2210da6c28aaSamw * Inherit the security descriptor from the parent container. 2211da6c28aaSamw * This function is called after FS has created the file/folder 2212da6c28aaSamw * so if this doesn't do anything it means FS inheritance is 2213da6c28aaSamw * in place. 2214da6c28aaSamw * 2215da6c28aaSamw * Do inheritance for ZFS internally. 2216da6c28aaSamw * 2217da6c28aaSamw * If we want to let ZFS does the inheritance the 2218da6c28aaSamw * following setting should be true: 2219da6c28aaSamw * 2220da6c28aaSamw * - aclinherit = passthrough 2221da6c28aaSamw * - aclmode = passthrough 2222da6c28aaSamw * - smbd umask = 0777 2223da6c28aaSamw * 2224da6c28aaSamw * This will result in right effective permissions but 2225da6c28aaSamw * ZFS will always add 6 ACEs for owner, owning group 2226da6c28aaSamw * and others to be POSIX compliant. This is not what 2227da6c28aaSamw * Windows clients/users expect, so we decided that CIFS 2228da6c28aaSamw * implements Windows rules and overwrite whatever ZFS 2229da6c28aaSamw * comes up with. This way we also don't have to care 2230da6c28aaSamw * about ZFS aclinherit and aclmode settings. 2231da6c28aaSamw */ 2232da6c28aaSamw static int 2233da6c28aaSamw smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, smb_fssd_t *fs_sd) 2234da6c28aaSamw { 2235da6c28aaSamw int is_dir; 223655bf511dSas acl_t *dacl = NULL; 223755bf511dSas acl_t *sacl = NULL; 2238da6c28aaSamw ksid_t *owner_sid; 2239da6c28aaSamw int error; 2240da6c28aaSamw 2241da6c28aaSamw ASSERT(fs_sd); 2242da6c28aaSamw 2243da6c28aaSamw if (sr->tid_tree->t_acltype != ACE_T) { 2244da6c28aaSamw /* 2245da6c28aaSamw * No forced inheritance for non-ZFS filesystems. 2246da6c28aaSamw */ 2247da6c28aaSamw fs_sd->sd_secinfo = 0; 2248da6c28aaSamw return (0); 2249da6c28aaSamw } 2250da6c28aaSamw 2251da6c28aaSamw 2252da6c28aaSamw /* Fetch parent directory's ACL */ 2253da6c28aaSamw error = smb_fsop_sdread(sr, kcred, dnode, fs_sd); 2254da6c28aaSamw if (error) { 2255da6c28aaSamw return (error); 2256da6c28aaSamw } 2257da6c28aaSamw 2258da6c28aaSamw is_dir = (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR); 2259da6c28aaSamw owner_sid = crgetsid(sr->user_cr, KSID_OWNER); 2260da6c28aaSamw ASSERT(owner_sid); 226155bf511dSas dacl = smb_fsacl_inherit(fs_sd->sd_zdacl, is_dir, SMB_DACL_SECINFO, 2262da6c28aaSamw owner_sid->ks_id); 226355bf511dSas sacl = smb_fsacl_inherit(fs_sd->sd_zsacl, is_dir, SMB_SACL_SECINFO, 2264da6c28aaSamw (uid_t)-1); 2265da6c28aaSamw 226655bf511dSas if (sacl == NULL) 226755bf511dSas fs_sd->sd_secinfo &= ~SMB_SACL_SECINFO; 226855bf511dSas 226955bf511dSas smb_fsacl_free(fs_sd->sd_zdacl); 227055bf511dSas smb_fsacl_free(fs_sd->sd_zsacl); 2271da6c28aaSamw 2272da6c28aaSamw fs_sd->sd_zdacl = dacl; 2273da6c28aaSamw fs_sd->sd_zsacl = sacl; 2274da6c28aaSamw 2275da6c28aaSamw return (0); 2276da6c28aaSamw } 2277da6c28aaSamw 2278da6c28aaSamw /* 2279da6c28aaSamw * smb_fsop_eaccess 2280da6c28aaSamw * 2281da6c28aaSamw * Returns the effective permission of the given credential for the 2282da6c28aaSamw * specified object. 2283da6c28aaSamw * 2284da6c28aaSamw * This is just a workaround. We need VFS/FS support for this. 2285da6c28aaSamw */ 2286da6c28aaSamw void 2287da6c28aaSamw smb_fsop_eaccess(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 2288da6c28aaSamw uint32_t *eaccess) 2289da6c28aaSamw { 2290da6c28aaSamw int access = 0; 2291da6c28aaSamw vnode_t *dir_vp; 2292da6c28aaSamw smb_node_t *unnamed_node; 2293da6c28aaSamw 2294da6c28aaSamw ASSERT(cr); 2295da6c28aaSamw ASSERT(snode); 2296da6c28aaSamw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 2297da6c28aaSamw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 2298da6c28aaSamw 2299da6c28aaSamw unnamed_node = SMB_IS_STREAM(snode); 2300da6c28aaSamw if (unnamed_node) { 2301da6c28aaSamw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 2302da6c28aaSamw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 2303da6c28aaSamw /* 2304da6c28aaSamw * Streams authorization should be performed against the 2305da6c28aaSamw * unnamed stream. 2306da6c28aaSamw */ 2307da6c28aaSamw snode = unnamed_node; 2308da6c28aaSamw } 2309da6c28aaSamw 2310c8ec8eeaSjose borrego if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) { 2311da6c28aaSamw dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL; 2312da6c28aaSamw smb_vop_eaccess(snode->vp, (int *)eaccess, V_ACE_MASK, dir_vp, 2313da6c28aaSamw cr); 2314da6c28aaSamw return; 2315da6c28aaSamw } 2316da6c28aaSamw 2317da6c28aaSamw /* 2318da6c28aaSamw * FS doesn't understand 32-bit mask 2319da6c28aaSamw */ 2320da6c28aaSamw smb_vop_eaccess(snode->vp, &access, 0, NULL, cr); 2321743a77edSAlan Wright access &= sr->tid_tree->t_access; 2322da6c28aaSamw 2323da6c28aaSamw *eaccess = READ_CONTROL | FILE_READ_EA | FILE_READ_ATTRIBUTES; 2324da6c28aaSamw 2325da6c28aaSamw if (access & VREAD) 2326da6c28aaSamw *eaccess |= FILE_READ_DATA; 2327da6c28aaSamw 2328da6c28aaSamw if (access & VEXEC) 2329da6c28aaSamw *eaccess |= FILE_EXECUTE; 2330da6c28aaSamw 2331da6c28aaSamw if (access & VWRITE) 2332da6c28aaSamw *eaccess |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | 2333da6c28aaSamw FILE_WRITE_EA | FILE_APPEND_DATA | FILE_DELETE_CHILD; 2334da6c28aaSamw } 233555bf511dSas 2336dc20a302Sas /* 2337dc20a302Sas * smb_fsop_shrlock 2338dc20a302Sas * 2339dc20a302Sas * For the current open request, check file sharing rules 2340dc20a302Sas * against existing opens. 2341dc20a302Sas * 2342dc20a302Sas * Returns NT_STATUS_SHARING_VIOLATION if there is any 2343dc20a302Sas * sharing conflict. Returns NT_STATUS_SUCCESS otherwise. 2344dc20a302Sas * 2345dc20a302Sas * Full system-wide share reservation synchronization is available 2346dc20a302Sas * when the nbmand (non-blocking mandatory) mount option is set 2347dc20a302Sas * (i.e. nbl_need_crit() is true) and nbmand critical regions are used. 2348dc20a302Sas * This provides synchronization with NFS and local processes. The 2349dc20a302Sas * critical regions are entered in VOP_SHRLOCK()/fs_shrlock() (called 2350dc20a302Sas * from smb_open_subr()/smb_fsop_shrlock()/smb_vop_shrlock()) as well 2351dc20a302Sas * as the CIFS rename and delete paths. 2352dc20a302Sas * 2353dc20a302Sas * The CIFS server will also enter the nbl critical region in the open, 2354dc20a302Sas * rename, and delete paths when nbmand is not set. There is limited 2355dc20a302Sas * coordination with local and VFS share reservations in this case. 2356dc20a302Sas * Note that when the nbmand mount option is not set, the VFS layer 2357dc20a302Sas * only processes advisory reservations and the delete mode is not checked. 2358dc20a302Sas * 2359dc20a302Sas * Whether or not the nbmand mount option is set, intra-CIFS share 2360dc20a302Sas * checking is done in the open, delete, and rename paths using a CIFS 2361dc20a302Sas * critical region (node->n_share_lock). 2362dc20a302Sas */ 2363dc20a302Sas 2364dc20a302Sas uint32_t 2365faa1795aSjb smb_fsop_shrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid, 2366dc20a302Sas uint32_t desired_access, uint32_t share_access) 2367dc20a302Sas { 2368dc20a302Sas int rc; 2369dc20a302Sas 2370dc20a302Sas if (node->attr.sa_vattr.va_type == VDIR) 2371dc20a302Sas return (NT_STATUS_SUCCESS); 2372dc20a302Sas 2373dc20a302Sas /* Allow access if the request is just for meta data */ 2374dc20a302Sas if ((desired_access & FILE_DATA_ALL) == 0) 2375dc20a302Sas return (NT_STATUS_SUCCESS); 2376dc20a302Sas 2377dc20a302Sas rc = smb_node_open_check(node, cr, desired_access, share_access); 2378dc20a302Sas if (rc) 2379dc20a302Sas return (NT_STATUS_SHARING_VIOLATION); 2380dc20a302Sas 2381dc20a302Sas rc = smb_vop_shrlock(node->vp, uniq_fid, desired_access, share_access, 2382dc20a302Sas cr); 2383dc20a302Sas if (rc) 2384dc20a302Sas return (NT_STATUS_SHARING_VIOLATION); 2385dc20a302Sas 2386dc20a302Sas return (NT_STATUS_SUCCESS); 2387dc20a302Sas } 2388dc20a302Sas 238955bf511dSas void 2390dc20a302Sas smb_fsop_unshrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid) 2391dc20a302Sas { 2392dc20a302Sas if (node->attr.sa_vattr.va_type == VDIR) 2393dc20a302Sas return; 2394dc20a302Sas 2395dc20a302Sas (void) smb_vop_unshrlock(node->vp, uniq_fid, cr); 2396dc20a302Sas } 23978c10a865Sas 23988c10a865Sas int 23998c10a865Sas smb_fsop_frlock(smb_node_t *node, smb_lock_t *lock, boolean_t unlock, 24008c10a865Sas cred_t *cr) 24018c10a865Sas { 24028c10a865Sas flock64_t bf; 24038c10a865Sas int flag = F_REMOTELOCK; 24048c10a865Sas 24053ad684d6Sjb /* 24063ad684d6Sjb * VOP_FRLOCK() will not be called if: 24073ad684d6Sjb * 24083ad684d6Sjb * 1) The lock has a range of zero bytes. The semantics of Windows and 24093ad684d6Sjb * POSIX are different. In the case of POSIX it asks for the locking 24103ad684d6Sjb * of all the bytes from the offset provided until the end of the 24113ad684d6Sjb * file. In the case of Windows a range of zero locks nothing and 24123ad684d6Sjb * doesn't conflict with any other lock. 24133ad684d6Sjb * 24143ad684d6Sjb * 2) The lock rolls over (start + lenght < start). Solaris will assert 24153ad684d6Sjb * if such a request is submitted. This will not create 24163ad684d6Sjb * incompatibilities between POSIX and Windows. In the Windows world, 24173ad684d6Sjb * if a client submits such a lock, the server will not lock any 24183ad684d6Sjb * bytes. Interestingly if the same lock (same offset and length) is 24193ad684d6Sjb * resubmitted Windows will consider that there is an overlap and 24203ad684d6Sjb * the granting rules will then apply. 24213ad684d6Sjb */ 24223ad684d6Sjb if ((lock->l_length == 0) || 24233ad684d6Sjb ((lock->l_start + lock->l_length - 1) < lock->l_start)) 24243ad684d6Sjb return (0); 24253ad684d6Sjb 24268c10a865Sas bzero(&bf, sizeof (bf)); 24278c10a865Sas 24288c10a865Sas if (unlock) { 24298c10a865Sas bf.l_type = F_UNLCK; 24308c10a865Sas } else if (lock->l_type == SMB_LOCK_TYPE_READONLY) { 24318c10a865Sas bf.l_type = F_RDLCK; 24328c10a865Sas flag |= FREAD; 24338c10a865Sas } else if (lock->l_type == SMB_LOCK_TYPE_READWRITE) { 24348c10a865Sas bf.l_type = F_WRLCK; 24358c10a865Sas flag |= FWRITE; 24368c10a865Sas } 24378c10a865Sas 24388c10a865Sas bf.l_start = lock->l_start; 24398c10a865Sas bf.l_len = lock->l_length; 2440c8ec8eeaSjose borrego bf.l_pid = lock->l_file->f_uniqid; 24418c10a865Sas bf.l_sysid = smb_ct.cc_sysid; 24428c10a865Sas 24438c10a865Sas return (smb_vop_frlock(node->vp, cr, flag, &bf)); 24448c10a865Sas } 2445