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 /* 22dc20a302Sas * Copyright 2008 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 45da6c28aaSamw static int smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, 46da6c28aaSamw smb_fssd_t *fs_sd); 47da6c28aaSamw 48da6c28aaSamw /* 49da6c28aaSamw * The smb_fsop_* functions have knowledge of CIFS semantics. 50da6c28aaSamw * 51da6c28aaSamw * The smb_vop_* functions have minimal knowledge of CIFS semantics and 52da6c28aaSamw * serve as an interface to the VFS layer. 53da6c28aaSamw * 54da6c28aaSamw * Hence, smb_request_t and smb_node_t structures should not be passed 55da6c28aaSamw * from the smb_fsop_* layer to the smb_vop_* layer. 56da6c28aaSamw * 57da6c28aaSamw * In general, CIFS service code should only ever call smb_fsop_* 58da6c28aaSamw * functions directly, and never smb_vop_* functions directly. 59da6c28aaSamw * 60da6c28aaSamw * smb_fsop_* functions should call smb_vop_* functions where possible, instead 61da6c28aaSamw * of their smb_fsop_* counterparts. However, there are times when 62da6c28aaSamw * this cannot be avoided. 63da6c28aaSamw */ 64da6c28aaSamw 65da6c28aaSamw /* 66da6c28aaSamw * Note: Stream names cannot be mangled. 67da6c28aaSamw */ 68da6c28aaSamw 698c10a865Sas /* 708c10a865Sas * smb_fsop_amask_to_omode 718c10a865Sas * 728c10a865Sas * Convert the access mask to the open mode (for use 738c10a865Sas * with the VOP_OPEN call). 748c10a865Sas * 758c10a865Sas * Note that opening a file for attribute only access 768c10a865Sas * will also translate into an FREAD or FWRITE open mode 778c10a865Sas * (i.e., it's not just for data). 788c10a865Sas * 798c10a865Sas * This is needed so that opens are tracked appropriately 808c10a865Sas * for oplock processing. 818c10a865Sas */ 828c10a865Sas 83da6c28aaSamw int 848c10a865Sas smb_fsop_amask_to_omode(uint32_t access) 85da6c28aaSamw { 868c10a865Sas int mode = 0; 878c10a865Sas 888c10a865Sas if (access & (FILE_READ_DATA | FILE_EXECUTE | 898c10a865Sas FILE_READ_ATTRIBUTES | FILE_READ_EA)) 908c10a865Sas mode |= FREAD; 91da6c28aaSamw 928c10a865Sas if (access & (FILE_WRITE_DATA | FILE_APPEND_DATA | 938c10a865Sas FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA)) 948c10a865Sas mode |= FWRITE; 958c10a865Sas 968c10a865Sas if (access & FILE_APPEND_DATA) 978c10a865Sas mode |= FAPPEND; 988c10a865Sas 998c10a865Sas return (mode); 1008c10a865Sas } 101da6c28aaSamw 1028c10a865Sas int 1038c10a865Sas smb_fsop_open(smb_node_t *node, int mode, cred_t *cred) 1048c10a865Sas { 105da6c28aaSamw /* 1068c10a865Sas * Assuming that the same vnode is returned as we had before. 1078c10a865Sas * (I.e., with certain types of files or file systems, a 1088c10a865Sas * different vnode might be returned by VOP_OPEN) 109da6c28aaSamw */ 1108c10a865Sas return (smb_vop_open(&node->vp, mode, cred)); 111da6c28aaSamw } 112da6c28aaSamw 113c8ec8eeaSjose borrego void 1148c10a865Sas smb_fsop_close(smb_node_t *node, int mode, cred_t *cred) 115da6c28aaSamw { 116c8ec8eeaSjose borrego smb_vop_close(node->vp, mode, cred); 117da6c28aaSamw } 118da6c28aaSamw 1198c10a865Sas int 1208c10a865Sas smb_fsop_oplock_install(smb_node_t *node, int mode) 121da6c28aaSamw { 1228c10a865Sas int rc; 123da6c28aaSamw 1248c10a865Sas if (smb_vop_other_opens(node->vp, mode)) 1258c10a865Sas return (EMFILE); 126da6c28aaSamw 1278c10a865Sas if ((rc = smb_fem_oplock_install(node))) 1288c10a865Sas return (rc); 129da6c28aaSamw 1308c10a865Sas if (smb_vop_other_opens(node->vp, mode)) { 1318c10a865Sas (void) smb_fem_oplock_uninstall(node); 1328c10a865Sas return (EMFILE); 1338c10a865Sas } 134da6c28aaSamw 1358c10a865Sas return (0); 1368c10a865Sas } 1378c10a865Sas 1388c10a865Sas void 1398c10a865Sas smb_fsop_oplock_uninstall(smb_node_t *node) 1408c10a865Sas { 1418c10a865Sas smb_fem_oplock_uninstall(node); 142da6c28aaSamw } 143da6c28aaSamw 144da6c28aaSamw static int 145da6c28aaSamw smb_fsop_create_with_sd( 146faa1795aSjb smb_request_t *sr, 147da6c28aaSamw cred_t *cr, 148*2c1b14e5Sjose borrego smb_node_t *dir_snode, 149da6c28aaSamw char *name, 150da6c28aaSamw smb_attr_t *attr, 151da6c28aaSamw smb_node_t **ret_snode, 152da6c28aaSamw smb_attr_t *ret_attr, 153da6c28aaSamw smb_fssd_t *fs_sd) 154da6c28aaSamw { 155da6c28aaSamw vsecattr_t *vsap; 156da6c28aaSamw vsecattr_t vsecattr; 157da6c28aaSamw acl_t *acl, *dacl, *sacl; 158da6c28aaSamw smb_attr_t set_attr; 159da6c28aaSamw vnode_t *vp; 160da6c28aaSamw int aclbsize = 0; /* size of acl list in bytes */ 161da6c28aaSamw int flags = 0; 162da6c28aaSamw int rc; 163*2c1b14e5Sjose borrego boolean_t is_dir; 16455bf511dSas boolean_t no_xvattr = B_FALSE; 165da6c28aaSamw 166da6c28aaSamw ASSERT(fs_sd); 167da6c28aaSamw 168c8ec8eeaSjose borrego if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 169da6c28aaSamw flags = SMB_IGNORE_CASE; 170da6c28aaSamw 171da6c28aaSamw ASSERT(cr); 172da6c28aaSamw 173da6c28aaSamw is_dir = ((fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR) != 0); 174da6c28aaSamw 175c8ec8eeaSjose borrego if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACLONCREATE)) { 176da6c28aaSamw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 177da6c28aaSamw dacl = fs_sd->sd_zdacl; 178da6c28aaSamw sacl = fs_sd->sd_zsacl; 179da6c28aaSamw ASSERT(dacl || sacl); 180da6c28aaSamw if (dacl && sacl) { 18155bf511dSas acl = smb_fsacl_merge(dacl, sacl); 182da6c28aaSamw } else if (dacl) { 183da6c28aaSamw acl = dacl; 184da6c28aaSamw } else { 185da6c28aaSamw acl = sacl; 186da6c28aaSamw } 187da6c28aaSamw 18855bf511dSas rc = smb_fsacl_to_vsa(acl, &vsecattr, &aclbsize); 189da6c28aaSamw 190da6c28aaSamw if (dacl && sacl) 191da6c28aaSamw acl_free(acl); 192da6c28aaSamw 193*2c1b14e5Sjose borrego if (rc != 0) 194da6c28aaSamw return (rc); 195da6c28aaSamw 196da6c28aaSamw vsap = &vsecattr; 197*2c1b14e5Sjose borrego } else { 198da6c28aaSamw vsap = NULL; 199*2c1b14e5Sjose borrego } 200da6c28aaSamw 201da6c28aaSamw if (is_dir) { 202*2c1b14e5Sjose borrego rc = smb_vop_mkdir(dir_snode->vp, name, attr, &vp, 203*2c1b14e5Sjose borrego flags, cr, vsap); 204da6c28aaSamw } else { 205*2c1b14e5Sjose borrego rc = smb_vop_create(dir_snode->vp, name, attr, &vp, 206*2c1b14e5Sjose borrego flags, cr, vsap); 207da6c28aaSamw } 208da6c28aaSamw 209da6c28aaSamw if (vsap != NULL) 210da6c28aaSamw kmem_free(vsap->vsa_aclentp, aclbsize); 211da6c28aaSamw 212da6c28aaSamw if (rc != 0) 213da6c28aaSamw return (rc); 214da6c28aaSamw 215da6c28aaSamw set_attr.sa_mask = 0; 216da6c28aaSamw 217da6c28aaSamw /* 218da6c28aaSamw * Ideally we should be able to specify the owner and owning 219da6c28aaSamw * group at create time along with the ACL. Since we cannot 220da6c28aaSamw * do that right now, kcred is passed to smb_vop_setattr so it 221da6c28aaSamw * doesn't fail due to lack of permission. 222da6c28aaSamw */ 223da6c28aaSamw if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 224da6c28aaSamw set_attr.sa_vattr.va_uid = fs_sd->sd_uid; 225da6c28aaSamw set_attr.sa_mask |= SMB_AT_UID; 226da6c28aaSamw } 227da6c28aaSamw 228da6c28aaSamw if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 229da6c28aaSamw set_attr.sa_vattr.va_gid = fs_sd->sd_gid; 230da6c28aaSamw set_attr.sa_mask |= SMB_AT_GID; 231da6c28aaSamw } 232da6c28aaSamw 233da6c28aaSamw if (set_attr.sa_mask) { 234c8ec8eeaSjose borrego if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_UFS)) 235c8ec8eeaSjose borrego no_xvattr = B_TRUE; 236*2c1b14e5Sjose borrego rc = smb_vop_setattr(vp, NULL, &set_attr, 0, kcred, 237*2c1b14e5Sjose borrego no_xvattr); 238da6c28aaSamw } 239da6c28aaSamw 240*2c1b14e5Sjose borrego if (rc == 0) { 241*2c1b14e5Sjose borrego *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp, 242*2c1b14e5Sjose borrego name, dir_snode, NULL, ret_attr); 243*2c1b14e5Sjose borrego 244*2c1b14e5Sjose borrego if (*ret_snode == NULL) { 245*2c1b14e5Sjose borrego VN_RELE(vp); 246*2c1b14e5Sjose borrego rc = ENOMEM; 247*2c1b14e5Sjose borrego } 248*2c1b14e5Sjose borrego } 249da6c28aaSamw } else { 250da6c28aaSamw /* 251da6c28aaSamw * For filesystems that don't support ACL-on-create, try 252da6c28aaSamw * to set the specified SD after create, which could actually 253da6c28aaSamw * fail because of conflicts between inherited security 254da6c28aaSamw * attributes upon creation and the specified SD. 255da6c28aaSamw * 256da6c28aaSamw * Passing kcred to smb_fsop_sdwrite() to overcome this issue. 257da6c28aaSamw */ 258da6c28aaSamw 259da6c28aaSamw if (is_dir) { 260*2c1b14e5Sjose borrego rc = smb_vop_mkdir(dir_snode->vp, name, attr, &vp, 261*2c1b14e5Sjose borrego flags, cr, NULL); 262da6c28aaSamw } else { 263*2c1b14e5Sjose borrego rc = smb_vop_create(dir_snode->vp, name, attr, &vp, 264*2c1b14e5Sjose borrego flags, cr, NULL); 265da6c28aaSamw } 266da6c28aaSamw 26755bf511dSas if (rc != 0) 26855bf511dSas return (rc); 26955bf511dSas 270*2c1b14e5Sjose borrego *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp, 271*2c1b14e5Sjose borrego name, dir_snode, NULL, ret_attr); 272da6c28aaSamw 273*2c1b14e5Sjose borrego if (*ret_snode != NULL) { 274*2c1b14e5Sjose borrego if (!smb_tree_has_feature(sr->tid_tree, 275*2c1b14e5Sjose borrego SMB_TREE_NFS_MOUNTED)) 276*2c1b14e5Sjose borrego rc = smb_fsop_sdwrite(sr, kcred, *ret_snode, 277*2c1b14e5Sjose borrego fs_sd, 1); 278*2c1b14e5Sjose borrego } else { 279da6c28aaSamw VN_RELE(vp); 280da6c28aaSamw rc = ENOMEM; 281da6c28aaSamw } 282da6c28aaSamw } 283da6c28aaSamw 28455bf511dSas if (rc != 0) { 285*2c1b14e5Sjose borrego if (is_dir) 286*2c1b14e5Sjose borrego (void) smb_vop_rmdir(dir_snode->vp, name, flags, cr); 287*2c1b14e5Sjose borrego else 288*2c1b14e5Sjose borrego (void) smb_vop_remove(dir_snode->vp, name, flags, cr); 28955bf511dSas } 29055bf511dSas 291da6c28aaSamw return (rc); 292da6c28aaSamw } 293da6c28aaSamw 294da6c28aaSamw /* 295da6c28aaSamw * smb_fsop_create 296da6c28aaSamw * 297da6c28aaSamw * All SMB functions should use this wrapper to ensure that 298da6c28aaSamw * all the smb_vop_creates are performed with the appropriate credentials. 299da6c28aaSamw * Please document any direct calls to explain the reason 300da6c28aaSamw * for avoiding this wrapper. 301da6c28aaSamw * 302da6c28aaSamw * It is assumed that a reference exists on snode coming into this routine. 303da6c28aaSamw * 304da6c28aaSamw * *ret_snode is returned with a reference upon success. No reference is 305da6c28aaSamw * taken if an error is returned. 306da6c28aaSamw */ 307da6c28aaSamw 308da6c28aaSamw int 309da6c28aaSamw smb_fsop_create( 310faa1795aSjb smb_request_t *sr, 311faa1795aSjb cred_t *cr, 312faa1795aSjb smb_node_t *dir_snode, 313faa1795aSjb char *name, 314faa1795aSjb smb_attr_t *attr, 315faa1795aSjb smb_node_t **ret_snode, 316faa1795aSjb smb_attr_t *ret_attr) 317da6c28aaSamw { 318da6c28aaSamw struct open_param *op = &sr->arg.open; 319faa1795aSjb boolean_t no_xvattr = B_FALSE; 320faa1795aSjb smb_node_t *fnode; 321faa1795aSjb smb_attr_t file_attr; 322faa1795aSjb vnode_t *xattrdirvp; 323faa1795aSjb vnode_t *vp; 324faa1795aSjb char *longname = NULL; 325faa1795aSjb char *namep; 326faa1795aSjb char *fname; 327faa1795aSjb char *sname; 328faa1795aSjb int is_stream; 329faa1795aSjb int flags = 0; 330faa1795aSjb int rc = 0; 331faa1795aSjb smb_fssd_t fs_sd; 332faa1795aSjb uint32_t secinfo; 333faa1795aSjb uint32_t status; 334da6c28aaSamw 335da6c28aaSamw ASSERT(cr); 336da6c28aaSamw ASSERT(dir_snode); 337da6c28aaSamw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 338da6c28aaSamw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 339da6c28aaSamw 340da6c28aaSamw ASSERT(ret_snode); 341da6c28aaSamw *ret_snode = 0; 342da6c28aaSamw 343da6c28aaSamw ASSERT(name); 344da6c28aaSamw if (*name == 0) 345da6c28aaSamw return (EINVAL); 346da6c28aaSamw 347da6c28aaSamw ASSERT(sr); 348da6c28aaSamw ASSERT(sr->tid_tree); 349c8ec8eeaSjose borrego 350c8ec8eeaSjose borrego if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 351c8ec8eeaSjose borrego return (EACCES); 352c8ec8eeaSjose borrego 353c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) 354da6c28aaSamw return (EROFS); 355da6c28aaSamw 356c8ec8eeaSjose borrego if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 357da6c28aaSamw flags = SMB_IGNORE_CASE; 358da6c28aaSamw 359da6c28aaSamw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 360da6c28aaSamw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 361da6c28aaSamw 362da6c28aaSamw is_stream = smb_stream_parse_name(name, fname, sname); 363da6c28aaSamw 364da6c28aaSamw if (is_stream) 365da6c28aaSamw namep = fname; 366da6c28aaSamw else 367da6c28aaSamw namep = name; 368da6c28aaSamw 369da6c28aaSamw if (smb_maybe_mangled_name(namep)) { 370da6c28aaSamw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 371da6c28aaSamw 372da6c28aaSamw rc = smb_unmangle_name(sr, cr, dir_snode, namep, longname, 373da6c28aaSamw MAXNAMELEN, NULL, NULL, 1); 374da6c28aaSamw 375da6c28aaSamw if ((is_stream == 0) && (rc == 0)) 376da6c28aaSamw rc = EEXIST; 377da6c28aaSamw 378da6c28aaSamw if ((is_stream && rc) || 379da6c28aaSamw ((is_stream == 0) && (rc != ENOENT))) { 380da6c28aaSamw kmem_free(longname, MAXNAMELEN); 381da6c28aaSamw kmem_free(fname, MAXNAMELEN); 382da6c28aaSamw kmem_free(sname, MAXNAMELEN); 383da6c28aaSamw return (rc); 384da6c28aaSamw } 385da6c28aaSamw 386da6c28aaSamw if (is_stream) 387da6c28aaSamw namep = longname; 388da6c28aaSamw else 389da6c28aaSamw kmem_free(longname, MAXNAMELEN); 390da6c28aaSamw } 391da6c28aaSamw 392da6c28aaSamw if (is_stream) { 393da6c28aaSamw /* 394da6c28aaSamw * Look up the unnamed stream. 395da6c28aaSamw * 396da6c28aaSamw * Mangle processing in smb_fsop_lookup() for the unnamed 397da6c28aaSamw * stream won't be needed (as it was done above), but 398da6c28aaSamw * it may be needed on any link target (which 399da6c28aaSamw * smb_fsop_lookup() will provide). 400da6c28aaSamw */ 401da6c28aaSamw rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, 402da6c28aaSamw sr->tid_tree->t_snode, dir_snode, namep, &fnode, &file_attr, 403da6c28aaSamw 0, 0); 404da6c28aaSamw 405da6c28aaSamw if (longname) { 406da6c28aaSamw kmem_free(longname, MAXNAMELEN); 407da6c28aaSamw namep = NULL; 408da6c28aaSamw } 409da6c28aaSamw 410da6c28aaSamw if (rc != 0) { 411da6c28aaSamw kmem_free(fname, MAXNAMELEN); 412da6c28aaSamw kmem_free(sname, MAXNAMELEN); 413da6c28aaSamw return (rc); 414da6c28aaSamw } 415da6c28aaSamw 416da6c28aaSamw rc = smb_vop_stream_create(fnode->vp, sname, attr, &vp, 417dc20a302Sas &xattrdirvp, flags, cr); 418da6c28aaSamw 419da6c28aaSamw if (rc != 0) { 420da6c28aaSamw smb_node_release(fnode); 421da6c28aaSamw kmem_free(fname, MAXNAMELEN); 422da6c28aaSamw kmem_free(sname, MAXNAMELEN); 423da6c28aaSamw return (rc); 424da6c28aaSamw } 425da6c28aaSamw 426c8ec8eeaSjose borrego if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_UFS)) 427c8ec8eeaSjose borrego no_xvattr = B_TRUE; 4287b59d02dSjb 4297b59d02dSjb attr->sa_vattr.va_uid = file_attr.sa_vattr.va_uid; 4307b59d02dSjb attr->sa_vattr.va_gid = file_attr.sa_vattr.va_gid; 4317b59d02dSjb attr->sa_mask = SMB_AT_UID | SMB_AT_GID; 4327b59d02dSjb 4337b59d02dSjb /* 4347b59d02dSjb * The second parameter of smb_vop_setattr() is set to 4357b59d02dSjb * NULL, even though an unnamed stream exists. This is 4367b59d02dSjb * because we want to set the UID and GID on the named 4377b59d02dSjb * stream in this case for consistency with the (unnamed 4387b59d02dSjb * stream) file (see comments for smb_vop_setattr()). 4397b59d02dSjb */ 4407b59d02dSjb 4417b59d02dSjb rc = smb_vop_setattr(vp, NULL, attr, 0, kcred, no_xvattr); 4427b59d02dSjb 4437b59d02dSjb if (rc != 0) { 4447b59d02dSjb smb_node_release(fnode); 4457b59d02dSjb kmem_free(fname, MAXNAMELEN); 4467b59d02dSjb kmem_free(sname, MAXNAMELEN); 4477b59d02dSjb return (rc); 4487b59d02dSjb } 4497b59d02dSjb 450da6c28aaSamw *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, 451da6c28aaSamw vp, sname, ret_attr); 452da6c28aaSamw 453da6c28aaSamw smb_node_release(fnode); 454da6c28aaSamw 455da6c28aaSamw if (*ret_snode == NULL) { 456da6c28aaSamw VN_RELE(xattrdirvp); 457da6c28aaSamw VN_RELE(vp); 458da6c28aaSamw kmem_free(fname, MAXNAMELEN); 459da6c28aaSamw kmem_free(sname, MAXNAMELEN); 460da6c28aaSamw return (ENOMEM); 461da6c28aaSamw } 462da6c28aaSamw } else { 46355bf511dSas if (op->sd) { 464da6c28aaSamw /* 465da6c28aaSamw * SD sent by client in Windows format. Needs to be 466da6c28aaSamw * converted to FS format. No inheritance. 467da6c28aaSamw */ 46855bf511dSas secinfo = smb_sd_get_secinfo(op->sd); 46955bf511dSas smb_fssd_init(&fs_sd, secinfo, 0); 470da6c28aaSamw 47155bf511dSas status = smb_sd_tofs(op->sd, &fs_sd); 472da6c28aaSamw if (status == NT_STATUS_SUCCESS) { 473da6c28aaSamw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 474da6c28aaSamw name, attr, ret_snode, ret_attr, &fs_sd); 475da6c28aaSamw } 476da6c28aaSamw else 477da6c28aaSamw rc = EINVAL; 47855bf511dSas smb_fssd_term(&fs_sd); 479da6c28aaSamw } else if (sr->tid_tree->t_acltype == ACE_T) { 480da6c28aaSamw /* 481da6c28aaSamw * No incoming SD and filesystem is ZFS 482da6c28aaSamw * Server applies Windows inheritance rules, 483da6c28aaSamw * see smb_fsop_sdinherit() comments as to why. 484da6c28aaSamw */ 48555bf511dSas smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, 0); 486da6c28aaSamw rc = smb_fsop_sdinherit(sr, dir_snode, &fs_sd); 487da6c28aaSamw if (rc == 0) { 488da6c28aaSamw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 489da6c28aaSamw name, attr, ret_snode, ret_attr, &fs_sd); 490da6c28aaSamw } 491da6c28aaSamw 49255bf511dSas smb_fssd_term(&fs_sd); 493da6c28aaSamw } else { 494da6c28aaSamw /* 495da6c28aaSamw * No incoming SD and filesystem is not ZFS 496da6c28aaSamw * let the filesystem handles the inheritance. 497da6c28aaSamw */ 498da6c28aaSamw rc = smb_vop_create(dir_snode->vp, name, attr, &vp, 499dc20a302Sas flags, cr, NULL); 500da6c28aaSamw 501da6c28aaSamw if (rc == 0) { 502da6c28aaSamw *ret_snode = smb_node_lookup(sr, op, cr, vp, 503da6c28aaSamw name, dir_snode, NULL, ret_attr); 504da6c28aaSamw 505da6c28aaSamw if (*ret_snode == NULL) { 506da6c28aaSamw VN_RELE(vp); 507da6c28aaSamw rc = ENOMEM; 508da6c28aaSamw } 509da6c28aaSamw } 510da6c28aaSamw 511da6c28aaSamw } 512da6c28aaSamw } 513da6c28aaSamw 514da6c28aaSamw kmem_free(fname, MAXNAMELEN); 515da6c28aaSamw kmem_free(sname, MAXNAMELEN); 516da6c28aaSamw return (rc); 517da6c28aaSamw } 518da6c28aaSamw 519da6c28aaSamw /* 520da6c28aaSamw * smb_fsop_mkdir 521da6c28aaSamw * 522da6c28aaSamw * All SMB functions should use this wrapper to ensure that 523da6c28aaSamw * the the calls are performed with the appropriate credentials. 524da6c28aaSamw * Please document any direct call to explain the reason 525da6c28aaSamw * for avoiding this wrapper. 526da6c28aaSamw * 527da6c28aaSamw * It is assumed that a reference exists on snode coming into this routine. 528da6c28aaSamw * 529da6c28aaSamw * *ret_snode is returned with a reference upon success. No reference is 530da6c28aaSamw * taken if an error is returned. 531da6c28aaSamw */ 532da6c28aaSamw int 533da6c28aaSamw smb_fsop_mkdir( 534faa1795aSjb smb_request_t *sr, 535da6c28aaSamw cred_t *cr, 536da6c28aaSamw smb_node_t *dir_snode, 537da6c28aaSamw char *name, 538da6c28aaSamw smb_attr_t *attr, 539da6c28aaSamw smb_node_t **ret_snode, 540da6c28aaSamw smb_attr_t *ret_attr) 541da6c28aaSamw { 542da6c28aaSamw struct open_param *op = &sr->arg.open; 543da6c28aaSamw char *longname; 544da6c28aaSamw vnode_t *vp; 545da6c28aaSamw int flags = 0; 546da6c28aaSamw smb_fssd_t fs_sd; 547da6c28aaSamw uint32_t secinfo; 548da6c28aaSamw uint32_t status; 549da6c28aaSamw int rc; 550da6c28aaSamw ASSERT(cr); 551da6c28aaSamw ASSERT(dir_snode); 552da6c28aaSamw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 553da6c28aaSamw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 554da6c28aaSamw 555da6c28aaSamw ASSERT(ret_snode); 556da6c28aaSamw *ret_snode = 0; 557da6c28aaSamw 558da6c28aaSamw ASSERT(name); 559da6c28aaSamw if (*name == 0) 560da6c28aaSamw return (EINVAL); 561da6c28aaSamw 562da6c28aaSamw ASSERT(sr); 563da6c28aaSamw ASSERT(sr->tid_tree); 564c8ec8eeaSjose borrego 565c8ec8eeaSjose borrego if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 566c8ec8eeaSjose borrego return (EACCES); 567c8ec8eeaSjose borrego 568c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) 569da6c28aaSamw return (EROFS); 570da6c28aaSamw 571da6c28aaSamw if (smb_maybe_mangled_name(name)) { 572da6c28aaSamw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 573da6c28aaSamw rc = smb_unmangle_name(sr, cr, dir_snode, name, longname, 574da6c28aaSamw MAXNAMELEN, NULL, NULL, 1); 575da6c28aaSamw 576da6c28aaSamw kmem_free(longname, MAXNAMELEN); 577da6c28aaSamw 578da6c28aaSamw /* 579da6c28aaSamw * If the name passed in by the client has an unmangled 580da6c28aaSamw * equivalent that is found in the specified directory, 581da6c28aaSamw * then the mkdir cannot succeed. Return EEXIST. 582da6c28aaSamw * 583da6c28aaSamw * Only if ENOENT is returned will a mkdir be attempted. 584da6c28aaSamw */ 585da6c28aaSamw 586da6c28aaSamw if (rc == 0) 587da6c28aaSamw rc = EEXIST; 588da6c28aaSamw 589da6c28aaSamw if (rc != ENOENT) 590da6c28aaSamw return (rc); 591da6c28aaSamw } 592da6c28aaSamw 593c8ec8eeaSjose borrego if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 594da6c28aaSamw flags = SMB_IGNORE_CASE; 595da6c28aaSamw 59655bf511dSas if (op->sd) { 597da6c28aaSamw /* 598da6c28aaSamw * SD sent by client in Windows format. Needs to be 599da6c28aaSamw * converted to FS format. No inheritance. 600da6c28aaSamw */ 60155bf511dSas secinfo = smb_sd_get_secinfo(op->sd); 60255bf511dSas smb_fssd_init(&fs_sd, secinfo, SMB_FSSD_FLAGS_DIR); 603da6c28aaSamw 60455bf511dSas status = smb_sd_tofs(op->sd, &fs_sd); 605da6c28aaSamw if (status == NT_STATUS_SUCCESS) { 606da6c28aaSamw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 607da6c28aaSamw name, attr, ret_snode, ret_attr, &fs_sd); 608da6c28aaSamw } 609da6c28aaSamw else 610da6c28aaSamw rc = EINVAL; 61155bf511dSas smb_fssd_term(&fs_sd); 612da6c28aaSamw } else if (sr->tid_tree->t_acltype == ACE_T) { 613da6c28aaSamw /* 614da6c28aaSamw * No incoming SD and filesystem is ZFS 615da6c28aaSamw * Server applies Windows inheritance rules, 616da6c28aaSamw * see smb_fsop_sdinherit() comments as to why. 617da6c28aaSamw */ 61855bf511dSas smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, SMB_FSSD_FLAGS_DIR); 619da6c28aaSamw rc = smb_fsop_sdinherit(sr, dir_snode, &fs_sd); 620da6c28aaSamw if (rc == 0) { 621da6c28aaSamw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 622da6c28aaSamw name, attr, ret_snode, ret_attr, &fs_sd); 623da6c28aaSamw } 624da6c28aaSamw 62555bf511dSas smb_fssd_term(&fs_sd); 626da6c28aaSamw 627da6c28aaSamw } else { 628da6c28aaSamw rc = smb_vop_mkdir(dir_snode->vp, name, attr, &vp, flags, cr, 629dc20a302Sas NULL); 630da6c28aaSamw 631da6c28aaSamw if (rc == 0) { 632da6c28aaSamw *ret_snode = smb_node_lookup(sr, op, cr, vp, name, 633da6c28aaSamw dir_snode, NULL, ret_attr); 634da6c28aaSamw 635da6c28aaSamw if (*ret_snode == NULL) { 636da6c28aaSamw VN_RELE(vp); 637da6c28aaSamw rc = ENOMEM; 638da6c28aaSamw } 639da6c28aaSamw } 640da6c28aaSamw } 641da6c28aaSamw 642da6c28aaSamw return (rc); 643da6c28aaSamw } 644da6c28aaSamw 645da6c28aaSamw /* 646da6c28aaSamw * smb_fsop_remove 647da6c28aaSamw * 648da6c28aaSamw * All SMB functions should use this wrapper to ensure that 649da6c28aaSamw * the the calls are performed with the appropriate credentials. 650da6c28aaSamw * Please document any direct call to explain the reason 651da6c28aaSamw * for avoiding this wrapper. 652da6c28aaSamw * 653da6c28aaSamw * It is assumed that a reference exists on snode coming into this routine. 654da6c28aaSamw * 655da6c28aaSamw * od: This means that the name passed in is an on-disk name. 656da6c28aaSamw * A null smb_request might be passed to this function. 657da6c28aaSamw */ 658da6c28aaSamw 659da6c28aaSamw int 660da6c28aaSamw smb_fsop_remove( 661faa1795aSjb smb_request_t *sr, 662faa1795aSjb cred_t *cr, 663faa1795aSjb smb_node_t *dir_snode, 664faa1795aSjb char *name, 665faa1795aSjb int od) 666da6c28aaSamw { 667faa1795aSjb smb_node_t *fnode; 668faa1795aSjb smb_attr_t file_attr; 669faa1795aSjb char *longname; 670faa1795aSjb char *fname; 671faa1795aSjb char *sname; 672faa1795aSjb int flags = 0; 673faa1795aSjb int rc; 674da6c28aaSamw 675da6c28aaSamw ASSERT(cr); 676da6c28aaSamw /* 677da6c28aaSamw * The state of the node could be SMB_NODE_STATE_DESTROYING if this 678da6c28aaSamw * function is called during the deletion of the node (because of 679da6c28aaSamw * DELETE_ON_CLOSE). 680da6c28aaSamw */ 681da6c28aaSamw ASSERT(dir_snode); 682da6c28aaSamw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 683da6c28aaSamw 684c8ec8eeaSjose borrego if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 685da6c28aaSamw return (EACCES); 686da6c28aaSamw 687c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) 688da6c28aaSamw return (EROFS); 689da6c28aaSamw 690da6c28aaSamw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 691da6c28aaSamw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 692da6c28aaSamw 693cbfb650aScp /* 694cbfb650aScp * If the passed-in name is an on-disk name, 695cbfb650aScp * then we need to do a case-sensitive remove. 696cbfb650aScp * This is important if the on-disk name 697cbfb650aScp * corresponds to a mangled name passed in by 698cbfb650aScp * the client. We want to make sure to remove 699cbfb650aScp * the exact file specified by the client, 700cbfb650aScp * instead of letting the underlying file system 701cbfb650aScp * do a remove on the "first match." 702cbfb650aScp */ 703da6c28aaSamw 704c8ec8eeaSjose borrego if ((od == 0) && SMB_TREE_IS_CASEINSENSITIVE(sr)) 705cbfb650aScp flags = SMB_IGNORE_CASE; 706cbfb650aScp 707cbfb650aScp if (dir_snode->flags & NODE_XATTR_DIR) { 708cbfb650aScp rc = smb_vop_stream_remove(dir_snode->dir_snode->vp, 709cbfb650aScp name, flags, cr); 710cbfb650aScp } else if (smb_stream_parse_name(name, fname, sname)) { 711cbfb650aScp /* 712cbfb650aScp * It is assumed that "name" corresponds to the path 713cbfb650aScp * passed in by the client, and no need of suppressing 714cbfb650aScp * case-insensitive lookups is needed. 715cbfb650aScp */ 716da6c28aaSamw 717cbfb650aScp ASSERT(od == 0); 718da6c28aaSamw 719da6c28aaSamw /* 720da6c28aaSamw * Look up the unnamed stream (i.e. fname). 721da6c28aaSamw * Unmangle processing will be done on fname 722da6c28aaSamw * as well as any link target. 723da6c28aaSamw */ 724da6c28aaSamw 725da6c28aaSamw rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, 726da6c28aaSamw sr->tid_tree->t_snode, dir_snode, fname, &fnode, &file_attr, 727da6c28aaSamw 0, 0); 728da6c28aaSamw 729da6c28aaSamw if (rc != 0) { 730da6c28aaSamw kmem_free(fname, MAXNAMELEN); 731da6c28aaSamw kmem_free(sname, MAXNAMELEN); 732da6c28aaSamw return (rc); 733da6c28aaSamw } 734da6c28aaSamw 735da6c28aaSamw /* 736da6c28aaSamw * XXX 737da6c28aaSamw * Need to find out what permission is required by NTFS 738da6c28aaSamw * to remove a stream. 739da6c28aaSamw */ 740dc20a302Sas rc = smb_vop_stream_remove(fnode->vp, sname, flags, cr); 741da6c28aaSamw 742da6c28aaSamw smb_node_release(fnode); 743da6c28aaSamw } else { 744dc20a302Sas rc = smb_vop_remove(dir_snode->vp, name, flags, cr); 745da6c28aaSamw 746da6c28aaSamw if (rc == ENOENT) { 747da6c28aaSamw if (smb_maybe_mangled_name(name) == 0) { 748da6c28aaSamw kmem_free(fname, MAXNAMELEN); 749da6c28aaSamw kmem_free(sname, MAXNAMELEN); 750da6c28aaSamw return (rc); 751da6c28aaSamw } 752da6c28aaSamw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 753da6c28aaSamw 754da6c28aaSamw rc = smb_unmangle_name(sr, cr, dir_snode, name, 755da6c28aaSamw longname, MAXNAMELEN, NULL, NULL, 1); 756da6c28aaSamw 757da6c28aaSamw if (rc == 0) { 758da6c28aaSamw /* 759da6c28aaSamw * We passed "1" as the "od" parameter 760da6c28aaSamw * to smb_unmangle_name(), such that longname 761da6c28aaSamw * is the real (case-sensitive) on-disk name. 762da6c28aaSamw * We make sure we do a remove on this exact 763da6c28aaSamw * name, as the name was mangled and denotes 764da6c28aaSamw * a unique file. 765da6c28aaSamw */ 766da6c28aaSamw flags &= ~SMB_IGNORE_CASE; 767da6c28aaSamw rc = smb_vop_remove(dir_snode->vp, longname, 768dc20a302Sas flags, cr); 769da6c28aaSamw } 770da6c28aaSamw 771da6c28aaSamw kmem_free(longname, MAXNAMELEN); 772da6c28aaSamw } 773da6c28aaSamw } 774da6c28aaSamw 775da6c28aaSamw kmem_free(fname, MAXNAMELEN); 776da6c28aaSamw kmem_free(sname, MAXNAMELEN); 777da6c28aaSamw return (rc); 778da6c28aaSamw } 779da6c28aaSamw 780da6c28aaSamw /* 781da6c28aaSamw * smb_fsop_remove_streams 782da6c28aaSamw * 783da6c28aaSamw * This function removes a file's streams without removing the 784da6c28aaSamw * file itself. 785da6c28aaSamw * 786da6c28aaSamw * It is assumed that snode is not a link. 787da6c28aaSamw */ 788da6c28aaSamw int 789faa1795aSjb smb_fsop_remove_streams(smb_request_t *sr, cred_t *cr, smb_node_t *fnode) 790da6c28aaSamw { 791da6c28aaSamw struct fs_stream_info stream_info; 792da6c28aaSamw uint32_t cookie = 0; 793da6c28aaSamw int flags = 0; 794da6c28aaSamw int rc; 795da6c28aaSamw 796c8ec8eeaSjose borrego ASSERT(sr); 797da6c28aaSamw ASSERT(cr); 798da6c28aaSamw ASSERT(fnode); 799da6c28aaSamw ASSERT(fnode->n_magic == SMB_NODE_MAGIC); 800da6c28aaSamw ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING); 801da6c28aaSamw 802c8ec8eeaSjose borrego if (SMB_TREE_CONTAINS_NODE(sr, fnode) == 0) 803da6c28aaSamw return (EACCES); 804da6c28aaSamw 805c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) 806da6c28aaSamw return (EROFS); 807da6c28aaSamw 808c8ec8eeaSjose borrego if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 809da6c28aaSamw flags = SMB_IGNORE_CASE; 810da6c28aaSamw 811da6c28aaSamw for (;;) { 812da6c28aaSamw rc = smb_vop_stream_readdir(fnode->vp, &cookie, &stream_info, 813dc20a302Sas NULL, NULL, flags, cr); 814da6c28aaSamw 815da6c28aaSamw if ((rc != 0) || (cookie == SMB_EOF)) 816da6c28aaSamw break; 817da6c28aaSamw 818da6c28aaSamw (void) smb_vop_stream_remove(fnode->vp, stream_info.name, flags, 819dc20a302Sas cr); 820da6c28aaSamw } 821da6c28aaSamw return (rc); 822da6c28aaSamw } 823da6c28aaSamw 824da6c28aaSamw /* 825da6c28aaSamw * smb_fsop_rmdir 826da6c28aaSamw * 827da6c28aaSamw * All SMB functions should use this wrapper to ensure that 828da6c28aaSamw * the the calls are performed with the appropriate credentials. 829da6c28aaSamw * Please document any direct call to explain the reason 830da6c28aaSamw * for avoiding this wrapper. 831da6c28aaSamw * 832da6c28aaSamw * It is assumed that a reference exists on snode coming into this routine. 833da6c28aaSamw * 834da6c28aaSamw * od: This means that the name passed in is an on-disk name. 835da6c28aaSamw */ 836da6c28aaSamw 837da6c28aaSamw int 838da6c28aaSamw smb_fsop_rmdir( 839faa1795aSjb smb_request_t *sr, 840faa1795aSjb cred_t *cr, 841faa1795aSjb smb_node_t *dir_snode, 842faa1795aSjb char *name, 843faa1795aSjb int od) 844da6c28aaSamw { 845faa1795aSjb int rc; 846faa1795aSjb int flags = 0; 847faa1795aSjb char *longname; 848da6c28aaSamw 849da6c28aaSamw ASSERT(cr); 850da6c28aaSamw /* 851da6c28aaSamw * The state of the node could be SMB_NODE_STATE_DESTROYING if this 852da6c28aaSamw * function is called during the deletion of the node (because of 853da6c28aaSamw * DELETE_ON_CLOSE). 854da6c28aaSamw */ 855da6c28aaSamw ASSERT(dir_snode); 856da6c28aaSamw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 857da6c28aaSamw 858c8ec8eeaSjose borrego if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 859da6c28aaSamw return (EACCES); 860da6c28aaSamw 861c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) 862da6c28aaSamw return (EROFS); 863da6c28aaSamw 864da6c28aaSamw /* 865da6c28aaSamw * If the passed-in name is an on-disk name, 866da6c28aaSamw * then we need to do a case-sensitive rmdir. 867da6c28aaSamw * This is important if the on-disk name 868da6c28aaSamw * corresponds to a mangled name passed in by 869da6c28aaSamw * the client. We want to make sure to remove 870da6c28aaSamw * the exact directory specified by the client, 871da6c28aaSamw * instead of letting the underlying file system 872da6c28aaSamw * do a rmdir on the "first match." 873da6c28aaSamw */ 874da6c28aaSamw 875c8ec8eeaSjose borrego if ((od == 0) && SMB_TREE_IS_CASEINSENSITIVE(sr)) 876da6c28aaSamw flags = SMB_IGNORE_CASE; 877da6c28aaSamw 878dc20a302Sas rc = smb_vop_rmdir(dir_snode->vp, name, flags, cr); 879da6c28aaSamw 880da6c28aaSamw if (rc == ENOENT) { 881da6c28aaSamw if (smb_maybe_mangled_name(name) == 0) 882da6c28aaSamw return (rc); 883da6c28aaSamw 884da6c28aaSamw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 885da6c28aaSamw 886da6c28aaSamw rc = smb_unmangle_name(sr, cr, dir_snode, 887da6c28aaSamw name, longname, MAXNAMELEN, NULL, 888da6c28aaSamw NULL, 1); 889da6c28aaSamw 890da6c28aaSamw if (rc == 0) { 891da6c28aaSamw /* 892da6c28aaSamw * We passed "1" as the "od" parameter 893da6c28aaSamw * to smb_unmangle_name(), such that longname 894da6c28aaSamw * is the real (case-sensitive) on-disk name. 895da6c28aaSamw * We make sure we do a rmdir on this exact 896da6c28aaSamw * name, as the name was mangled and denotes 897da6c28aaSamw * a unique directory. 898da6c28aaSamw */ 899da6c28aaSamw flags &= ~SMB_IGNORE_CASE; 900dc20a302Sas rc = smb_vop_rmdir(dir_snode->vp, longname, flags, cr); 901da6c28aaSamw } 902da6c28aaSamw 903da6c28aaSamw kmem_free(longname, MAXNAMELEN); 904da6c28aaSamw } 905da6c28aaSamw 906da6c28aaSamw return (rc); 907da6c28aaSamw } 908da6c28aaSamw 909da6c28aaSamw /* 910da6c28aaSamw * smb_fsop_getattr 911da6c28aaSamw * 912da6c28aaSamw * All SMB functions should use this wrapper to ensure that 913da6c28aaSamw * the the calls are performed with the appropriate credentials. 914da6c28aaSamw * Please document any direct call to explain the reason 915da6c28aaSamw * for avoiding this wrapper. 916da6c28aaSamw * 917da6c28aaSamw * It is assumed that a reference exists on snode coming into this routine. 918da6c28aaSamw */ 919da6c28aaSamw int 920faa1795aSjb smb_fsop_getattr(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 921da6c28aaSamw smb_attr_t *attr) 922da6c28aaSamw { 923da6c28aaSamw smb_node_t *unnamed_node; 924da6c28aaSamw vnode_t *unnamed_vp = NULL; 925da6c28aaSamw uint32_t status; 926da6c28aaSamw uint32_t access = 0; 927da6c28aaSamw int flags = 0; 928dc20a302Sas int rc; 929da6c28aaSamw 930da6c28aaSamw ASSERT(cr); 931da6c28aaSamw ASSERT(snode); 932da6c28aaSamw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 933da6c28aaSamw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 934da6c28aaSamw 935c8ec8eeaSjose borrego if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0) 936da6c28aaSamw return (EACCES); 937da6c28aaSamw 938da6c28aaSamw if (sr->fid_ofile) { 939da6c28aaSamw /* if uid and/or gid is requested */ 940da6c28aaSamw if (attr->sa_mask & (SMB_AT_UID|SMB_AT_GID)) 941da6c28aaSamw access |= READ_CONTROL; 942da6c28aaSamw 943da6c28aaSamw /* if anything else is also requested */ 944da6c28aaSamw if (attr->sa_mask & ~(SMB_AT_UID|SMB_AT_GID)) 945da6c28aaSamw access |= FILE_READ_ATTRIBUTES; 946da6c28aaSamw 947da6c28aaSamw status = smb_ofile_access(sr->fid_ofile, cr, access); 948da6c28aaSamw if (status != NT_STATUS_SUCCESS) 949da6c28aaSamw return (EACCES); 950da6c28aaSamw 951c8ec8eeaSjose borrego if (smb_tree_has_feature(sr->tid_tree, 952c8ec8eeaSjose borrego SMB_TREE_ACEMASKONACCESS)) 953da6c28aaSamw flags = ATTR_NOACLCHECK; 954da6c28aaSamw } 955da6c28aaSamw 956da6c28aaSamw unnamed_node = SMB_IS_STREAM(snode); 957da6c28aaSamw 958da6c28aaSamw if (unnamed_node) { 959da6c28aaSamw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 960da6c28aaSamw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 961da6c28aaSamw unnamed_vp = unnamed_node->vp; 962da6c28aaSamw } 963da6c28aaSamw 964dc20a302Sas rc = smb_vop_getattr(snode->vp, unnamed_vp, attr, flags, cr); 965dc20a302Sas if (rc == 0) 966dc20a302Sas snode->attr = *attr; 967dc20a302Sas 968dc20a302Sas return (rc); 969da6c28aaSamw } 970da6c28aaSamw 971da6c28aaSamw /* 972da6c28aaSamw * smb_fsop_readdir 973da6c28aaSamw * 974da6c28aaSamw * All SMB functions should use this smb_fsop_readdir wrapper to ensure that 975da6c28aaSamw * the smb_vop_readdir is performed with the appropriate credentials. 976da6c28aaSamw * Please document any direct call to smb_vop_readdir to explain the reason 977da6c28aaSamw * for avoiding this wrapper. 978da6c28aaSamw * 979da6c28aaSamw * It is assumed that a reference exists on snode coming into this routine. 980da6c28aaSamw */ 981da6c28aaSamw int 982da6c28aaSamw smb_fsop_readdir( 983faa1795aSjb smb_request_t *sr, 984da6c28aaSamw cred_t *cr, 985da6c28aaSamw smb_node_t *dir_snode, 986da6c28aaSamw uint32_t *cookie, 987da6c28aaSamw char *name, 988da6c28aaSamw int *namelen, 989da6c28aaSamw ino64_t *fileid, 990da6c28aaSamw struct fs_stream_info *stream_info, 991da6c28aaSamw smb_node_t **ret_snode, 992da6c28aaSamw smb_attr_t *ret_attr) 993da6c28aaSamw { 994faa1795aSjb smb_node_t *ret_snodep; 995faa1795aSjb smb_node_t *fnode; 996faa1795aSjb smb_attr_t tmp_attr; 997faa1795aSjb vnode_t *xattrdirvp; 998faa1795aSjb vnode_t *fvp; 999faa1795aSjb vnode_t *vp = NULL; 1000faa1795aSjb char *od_name; 1001faa1795aSjb int rc; 1002faa1795aSjb int flags = 0; 1003da6c28aaSamw 1004da6c28aaSamw ASSERT(cr); 1005da6c28aaSamw ASSERT(dir_snode); 1006da6c28aaSamw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 1007da6c28aaSamw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 1008da6c28aaSamw 1009c8ec8eeaSjose borrego if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 1010da6c28aaSamw return (EACCES); 1011da6c28aaSamw 1012da6c28aaSamw if (*cookie == SMB_EOF) { 1013da6c28aaSamw *namelen = 0; 1014da6c28aaSamw return (0); 1015da6c28aaSamw } 1016da6c28aaSamw 1017c8ec8eeaSjose borrego if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 1018da6c28aaSamw flags = SMB_IGNORE_CASE; 1019da6c28aaSamw 1020da6c28aaSamw od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1021da6c28aaSamw 1022da6c28aaSamw if (stream_info) { 1023da6c28aaSamw rc = smb_vop_lookup(dir_snode->vp, name, &fvp, od_name, 1024dc20a302Sas SMB_FOLLOW_LINKS, sr->tid_tree->t_snode->vp, cr); 1025da6c28aaSamw 1026da6c28aaSamw if (rc != 0) { 1027da6c28aaSamw kmem_free(od_name, MAXNAMELEN); 1028da6c28aaSamw return (rc); 1029da6c28aaSamw } 1030da6c28aaSamw 1031da6c28aaSamw fnode = smb_node_lookup(sr, NULL, cr, fvp, od_name, dir_snode, 1032da6c28aaSamw NULL, ret_attr); 1033da6c28aaSamw 1034da6c28aaSamw kmem_free(od_name, MAXNAMELEN); 1035da6c28aaSamw 1036da6c28aaSamw if (fnode == NULL) { 1037da6c28aaSamw VN_RELE(fvp); 1038da6c28aaSamw return (ENOMEM); 1039da6c28aaSamw } 1040da6c28aaSamw 1041da6c28aaSamw /* 1042da6c28aaSamw * XXX 1043da6c28aaSamw * Need to find out what permission(s) NTFS requires for getting 1044da6c28aaSamw * a file's streams list. 1045da6c28aaSamw * 1046da6c28aaSamw * Might have to use kcred. 1047da6c28aaSamw */ 1048da6c28aaSamw rc = smb_vop_stream_readdir(fvp, cookie, stream_info, &vp, 1049dc20a302Sas &xattrdirvp, flags, cr); 1050da6c28aaSamw 1051da6c28aaSamw if ((rc != 0) || (*cookie == SMB_EOF)) { 1052da6c28aaSamw smb_node_release(fnode); 1053da6c28aaSamw return (rc); 1054da6c28aaSamw } 1055da6c28aaSamw 1056da6c28aaSamw ret_snodep = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, 1057da6c28aaSamw vp, stream_info->name, &tmp_attr); 1058da6c28aaSamw 1059da6c28aaSamw smb_node_release(fnode); 1060da6c28aaSamw 1061da6c28aaSamw if (ret_snodep == NULL) { 1062da6c28aaSamw VN_RELE(xattrdirvp); 1063da6c28aaSamw VN_RELE(vp); 1064da6c28aaSamw return (ENOMEM); 1065da6c28aaSamw } 1066da6c28aaSamw 1067da6c28aaSamw stream_info->size = tmp_attr.sa_vattr.va_size; 1068da6c28aaSamw 1069da6c28aaSamw if (ret_attr) 1070da6c28aaSamw *ret_attr = tmp_attr; 1071da6c28aaSamw 1072da6c28aaSamw if (ret_snode) 1073da6c28aaSamw *ret_snode = ret_snodep; 1074da6c28aaSamw else 1075da6c28aaSamw smb_node_release(ret_snodep); 1076da6c28aaSamw 1077da6c28aaSamw } else { 1078da6c28aaSamw rc = smb_vop_readdir(dir_snode->vp, cookie, name, namelen, 1079dc20a302Sas fileid, &vp, od_name, flags, cr); 1080da6c28aaSamw 1081da6c28aaSamw if (rc != 0) { 1082da6c28aaSamw kmem_free(od_name, MAXNAMELEN); 1083da6c28aaSamw return (rc); 1084da6c28aaSamw } 1085da6c28aaSamw 1086da6c28aaSamw if (*namelen) { 1087da6c28aaSamw ASSERT(vp); 1088da6c28aaSamw if (ret_attr || ret_snode) { 1089da6c28aaSamw ret_snodep = smb_node_lookup(sr, NULL, cr, vp, 1090da6c28aaSamw od_name, dir_snode, NULL, &tmp_attr); 1091da6c28aaSamw 1092da6c28aaSamw if (ret_snodep == NULL) { 1093da6c28aaSamw kmem_free(od_name, MAXNAMELEN); 1094da6c28aaSamw VN_RELE(vp); 1095da6c28aaSamw return (ENOMEM); 1096da6c28aaSamw } 1097da6c28aaSamw 1098da6c28aaSamw if (ret_attr) 1099da6c28aaSamw *ret_attr = tmp_attr; 1100da6c28aaSamw 1101da6c28aaSamw if (ret_snode) 1102da6c28aaSamw *ret_snode = ret_snodep; 1103da6c28aaSamw else 1104da6c28aaSamw smb_node_release(ret_snodep); 1105da6c28aaSamw } 1106da6c28aaSamw } 1107da6c28aaSamw 1108da6c28aaSamw kmem_free(od_name, MAXNAMELEN); 1109da6c28aaSamw } 1110da6c28aaSamw 1111da6c28aaSamw return (rc); 1112da6c28aaSamw } 1113da6c28aaSamw 1114da6c28aaSamw /* 1115da6c28aaSamw * smb_fsop_getdents 1116da6c28aaSamw * 1117da6c28aaSamw * All SMB functions should use this smb_vop_getdents wrapper to ensure that 1118da6c28aaSamw * the smb_vop_getdents is performed with the appropriate credentials. 1119da6c28aaSamw * Please document any direct call to smb_vop_getdents to explain the reason 1120da6c28aaSamw * for avoiding this wrapper. 1121da6c28aaSamw * 1122da6c28aaSamw * It is assumed that a reference exists on snode coming into this routine. 1123da6c28aaSamw */ 1124da6c28aaSamw /*ARGSUSED*/ 1125da6c28aaSamw int 1126da6c28aaSamw smb_fsop_getdents( 1127da6c28aaSamw struct smb_request *sr, 1128da6c28aaSamw cred_t *cr, 1129da6c28aaSamw smb_node_t *dir_snode, 1130da6c28aaSamw uint32_t *cookie, 1131da6c28aaSamw uint64_t *verifierp, 1132da6c28aaSamw int32_t *maxcnt, 1133da6c28aaSamw char *args, 1134da6c28aaSamw char *pattern) 1135da6c28aaSamw { 1136da6c28aaSamw int flags = 0; 1137da6c28aaSamw 1138da6c28aaSamw ASSERT(cr); 1139da6c28aaSamw ASSERT(dir_snode); 1140da6c28aaSamw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 1141da6c28aaSamw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 1142da6c28aaSamw 1143c8ec8eeaSjose borrego if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 1144da6c28aaSamw return (EACCES); 1145da6c28aaSamw 1146c8ec8eeaSjose borrego if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 1147da6c28aaSamw flags = SMB_IGNORE_CASE; 1148da6c28aaSamw 1149da6c28aaSamw return (smb_vop_getdents(dir_snode, cookie, 0, maxcnt, args, pattern, 1150dc20a302Sas flags, sr, cr)); 1151da6c28aaSamw } 1152da6c28aaSamw 1153da6c28aaSamw /* 1154da6c28aaSamw * smb_fsop_rename 1155da6c28aaSamw * 1156da6c28aaSamw * All SMB functions should use this smb_vop_rename wrapper to ensure that 1157da6c28aaSamw * the smb_vop_rename is performed with the appropriate credentials. 1158da6c28aaSamw * Please document any direct call to smb_vop_rename to explain the reason 1159da6c28aaSamw * for avoiding this wrapper. 1160da6c28aaSamw * 1161da6c28aaSamw * It is assumed that references exist on from_dir_snode and to_dir_snode coming 1162da6c28aaSamw * into this routine. 1163da6c28aaSamw */ 1164da6c28aaSamw int 1165da6c28aaSamw smb_fsop_rename( 1166faa1795aSjb smb_request_t *sr, 1167da6c28aaSamw cred_t *cr, 1168da6c28aaSamw smb_node_t *from_dir_snode, 1169da6c28aaSamw char *from_name, 1170da6c28aaSamw smb_node_t *to_dir_snode, 1171da6c28aaSamw char *to_name) 1172da6c28aaSamw { 1173da6c28aaSamw smb_node_t *from_snode; 1174da6c28aaSamw smb_attr_t tmp_attr; 1175da6c28aaSamw vnode_t *from_vp; 1176da6c28aaSamw int flags = 0; 1177da6c28aaSamw int rc; 1178da6c28aaSamw 1179da6c28aaSamw ASSERT(cr); 1180da6c28aaSamw ASSERT(from_dir_snode); 1181da6c28aaSamw ASSERT(from_dir_snode->n_magic == SMB_NODE_MAGIC); 1182da6c28aaSamw ASSERT(from_dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 1183da6c28aaSamw 1184da6c28aaSamw ASSERT(to_dir_snode); 1185da6c28aaSamw ASSERT(to_dir_snode->n_magic == SMB_NODE_MAGIC); 1186da6c28aaSamw ASSERT(to_dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 1187da6c28aaSamw 1188c8ec8eeaSjose borrego if (SMB_TREE_CONTAINS_NODE(sr, from_dir_snode) == 0) 1189da6c28aaSamw return (EACCES); 1190da6c28aaSamw 1191c8ec8eeaSjose borrego if (SMB_TREE_CONTAINS_NODE(sr, to_dir_snode) == 0) 1192da6c28aaSamw return (EACCES); 1193da6c28aaSamw 1194da6c28aaSamw ASSERT(sr); 1195da6c28aaSamw ASSERT(sr->tid_tree); 1196c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) 1197da6c28aaSamw return (EROFS); 1198da6c28aaSamw 1199da6c28aaSamw /* 1200c8ec8eeaSjose borrego * Note: There is no need to check SMB_TREE_IS_CASEINSENSITIVE 1201da6c28aaSamw * here. 1202da6c28aaSamw * 1203da6c28aaSamw * A case-sensitive rename is always done in this routine 1204da6c28aaSamw * because we are using the on-disk name from an earlier lookup. 1205da6c28aaSamw * If a mangled name was passed in by the caller (denoting a 1206da6c28aaSamw * deterministic lookup), then the exact file must be renamed 1207da6c28aaSamw * (i.e. SMB_IGNORE_CASE must not be passed to VOP_RENAME, or 1208da6c28aaSamw * else the underlying file system might return a "first-match" 1209da6c28aaSamw * on this on-disk name, possibly resulting in the wrong file). 1210da6c28aaSamw */ 1211da6c28aaSamw 1212da6c28aaSamw /* 1213da6c28aaSamw * XXX: Lock required through smb_node_release() below? 1214da6c28aaSamw */ 1215da6c28aaSamw 1216da6c28aaSamw rc = smb_vop_lookup(from_dir_snode->vp, from_name, &from_vp, NULL, 0, 1217dc20a302Sas NULL, cr); 1218da6c28aaSamw 1219da6c28aaSamw if (rc != 0) 1220da6c28aaSamw return (rc); 1221da6c28aaSamw 1222da6c28aaSamw rc = smb_vop_rename(from_dir_snode->vp, from_name, to_dir_snode->vp, 1223dc20a302Sas to_name, flags, cr); 1224da6c28aaSamw 1225da6c28aaSamw if (rc == 0) { 1226da6c28aaSamw from_snode = smb_node_lookup(sr, NULL, cr, from_vp, from_name, 1227da6c28aaSamw from_dir_snode, NULL, &tmp_attr); 1228da6c28aaSamw 1229da6c28aaSamw if (from_snode == NULL) { 1230da6c28aaSamw VN_RELE(from_vp); 1231da6c28aaSamw return (ENOMEM); 1232da6c28aaSamw } 1233da6c28aaSamw 1234da6c28aaSamw (void) smb_node_rename(from_dir_snode, from_snode, to_dir_snode, 1235da6c28aaSamw to_name); 1236da6c28aaSamw 1237da6c28aaSamw smb_node_release(from_snode); 1238da6c28aaSamw } else { 1239da6c28aaSamw VN_RELE(from_vp); 1240da6c28aaSamw } 1241da6c28aaSamw 1242da6c28aaSamw /* XXX: unlock */ 1243da6c28aaSamw 1244da6c28aaSamw return (rc); 1245da6c28aaSamw } 1246da6c28aaSamw 1247da6c28aaSamw /* 1248da6c28aaSamw * smb_fsop_setattr 1249da6c28aaSamw * 1250da6c28aaSamw * All SMB functions should use this wrapper to ensure that 1251da6c28aaSamw * the the calls are performed with the appropriate credentials. 1252da6c28aaSamw * Please document any direct call to explain the reason 1253da6c28aaSamw * for avoiding this wrapper. 1254da6c28aaSamw * 1255da6c28aaSamw * It is assumed that a reference exists on snode coming into this routine. 1256da6c28aaSamw * A null smb_request might be passed to this function. 1257da6c28aaSamw */ 1258da6c28aaSamw int 1259da6c28aaSamw smb_fsop_setattr( 1260faa1795aSjb smb_request_t *sr, 1261faa1795aSjb cred_t *cr, 1262faa1795aSjb smb_node_t *snode, 1263faa1795aSjb smb_attr_t *set_attr, 1264faa1795aSjb smb_attr_t *ret_attr) 1265da6c28aaSamw { 1266da6c28aaSamw smb_node_t *unnamed_node; 1267da6c28aaSamw vnode_t *unnamed_vp = NULL; 1268da6c28aaSamw uint32_t status; 1269*2c1b14e5Sjose borrego uint32_t access; 1270da6c28aaSamw int rc = 0; 1271da6c28aaSamw int flags = 0; 1272*2c1b14e5Sjose borrego uint_t sa_mask; 127355bf511dSas boolean_t no_xvattr = B_FALSE; 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 1280c8ec8eeaSjose borrego if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0) 1281da6c28aaSamw return (EACCES); 1282da6c28aaSamw 1283c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) 1284da6c28aaSamw return (EROFS); 1285da6c28aaSamw 1286c8ec8eeaSjose borrego if (sr && (set_attr->sa_mask & SMB_AT_SIZE)) { 1287c8ec8eeaSjose borrego if (sr->fid_ofile) { 1288c8ec8eeaSjose borrego if (SMB_OFILE_IS_READONLY(sr->fid_ofile)) 1289c8ec8eeaSjose borrego return (EACCES); 1290c8ec8eeaSjose borrego } else { 1291c8ec8eeaSjose borrego if (SMB_PATHFILE_IS_READONLY(sr, snode)) 1292c8ec8eeaSjose borrego return (EACCES); 1293c8ec8eeaSjose borrego } 1294c8ec8eeaSjose borrego } 1295c8ec8eeaSjose borrego 1296da6c28aaSamw /* sr could be NULL in some cases */ 1297da6c28aaSamw if (sr && sr->fid_ofile) { 1298*2c1b14e5Sjose borrego sa_mask = set_attr->sa_mask; 1299*2c1b14e5Sjose borrego access = 0; 1300c8ec8eeaSjose borrego 1301*2c1b14e5Sjose borrego if (sa_mask & SMB_AT_SIZE) { 1302*2c1b14e5Sjose borrego access |= FILE_WRITE_DATA; 1303*2c1b14e5Sjose borrego sa_mask &= ~SMB_AT_SIZE; 1304*2c1b14e5Sjose borrego } 1305*2c1b14e5Sjose borrego 1306*2c1b14e5Sjose borrego if (sa_mask & (SMB_AT_UID|SMB_AT_GID)) { 1307da6c28aaSamw access |= WRITE_OWNER; 1308*2c1b14e5Sjose borrego sa_mask &= ~(SMB_AT_UID|SMB_AT_GID); 1309*2c1b14e5Sjose borrego } 1310da6c28aaSamw 1311*2c1b14e5Sjose borrego if (sa_mask) 1312da6c28aaSamw access |= FILE_WRITE_ATTRIBUTES; 1313da6c28aaSamw 1314da6c28aaSamw status = smb_ofile_access(sr->fid_ofile, cr, access); 1315da6c28aaSamw if (status != NT_STATUS_SUCCESS) 1316da6c28aaSamw return (EACCES); 1317da6c28aaSamw 1318c8ec8eeaSjose borrego if (smb_tree_has_feature(sr->tid_tree, 1319c8ec8eeaSjose borrego SMB_TREE_ACEMASKONACCESS)) 1320da6c28aaSamw flags = ATTR_NOACLCHECK; 1321da6c28aaSamw } 1322da6c28aaSamw 1323da6c28aaSamw unnamed_node = SMB_IS_STREAM(snode); 1324da6c28aaSamw 1325da6c28aaSamw if (unnamed_node) { 1326da6c28aaSamw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 1327da6c28aaSamw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 1328da6c28aaSamw unnamed_vp = unnamed_node->vp; 1329da6c28aaSamw } 133055bf511dSas if (sr && sr->tid_tree) 1331c8ec8eeaSjose borrego if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_UFS)) 133255bf511dSas no_xvattr = B_TRUE; 1333da6c28aaSamw 1334dc20a302Sas rc = smb_vop_setattr(snode->vp, unnamed_vp, set_attr, flags, cr, 1335dc20a302Sas no_xvattr); 1336da6c28aaSamw 1337da6c28aaSamw if ((rc == 0) && ret_attr) { 1338da6c28aaSamw /* 1339dc20a302Sas * Use kcred to update the node attr because this 1340dc20a302Sas * call is not being made on behalf of the user. 1341da6c28aaSamw */ 1342da6c28aaSamw ret_attr->sa_mask = SMB_AT_ALL; 1343c8ec8eeaSjose borrego rc = smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, flags, 1344c8ec8eeaSjose borrego kcred); 1345dc20a302Sas if (rc == 0) 1346dc20a302Sas snode->attr = *ret_attr; 1347da6c28aaSamw } 1348da6c28aaSamw 1349da6c28aaSamw return (rc); 1350da6c28aaSamw } 1351da6c28aaSamw 1352da6c28aaSamw /* 1353da6c28aaSamw * smb_fsop_read 1354da6c28aaSamw * 1355da6c28aaSamw * All SMB functions should use this wrapper to ensure that 1356da6c28aaSamw * the the calls are performed with the appropriate credentials. 1357da6c28aaSamw * Please document any direct call to explain the reason 1358da6c28aaSamw * for avoiding this wrapper. 1359da6c28aaSamw * 1360da6c28aaSamw * It is assumed that a reference exists on snode coming into this routine. 1361da6c28aaSamw */ 1362da6c28aaSamw int 1363da6c28aaSamw smb_fsop_read( 1364da6c28aaSamw struct smb_request *sr, 1365da6c28aaSamw cred_t *cr, 1366da6c28aaSamw smb_node_t *snode, 1367da6c28aaSamw uio_t *uio, 1368da6c28aaSamw smb_attr_t *ret_attr) 1369da6c28aaSamw { 1370da6c28aaSamw smb_node_t *unnamed_node; 1371da6c28aaSamw vnode_t *unnamed_vp = NULL; 1372c8ec8eeaSjose borrego caller_context_t ct; 1373dc20a302Sas int svmand; 1374da6c28aaSamw int rc; 1375da6c28aaSamw 1376da6c28aaSamw ASSERT(cr); 1377da6c28aaSamw ASSERT(snode); 1378da6c28aaSamw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 1379da6c28aaSamw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 1380da6c28aaSamw 1381da6c28aaSamw ASSERT(sr); 1382da6c28aaSamw ASSERT(sr->fid_ofile); 1383da6c28aaSamw 1384da6c28aaSamw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_READ_DATA); 1385da6c28aaSamw if (rc != NT_STATUS_SUCCESS) { 1386da6c28aaSamw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_EXECUTE); 1387da6c28aaSamw if (rc != NT_STATUS_SUCCESS) 1388da6c28aaSamw return (EACCES); 1389da6c28aaSamw } 1390da6c28aaSamw 1391da6c28aaSamw unnamed_node = SMB_IS_STREAM(snode); 1392da6c28aaSamw if (unnamed_node) { 1393da6c28aaSamw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 1394da6c28aaSamw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 1395da6c28aaSamw unnamed_vp = unnamed_node->vp; 1396da6c28aaSamw /* 1397da6c28aaSamw * Streams permission are checked against the unnamed stream, 1398da6c28aaSamw * but in FS level they have their own permissions. To avoid 1399da6c28aaSamw * rejection by FS due to lack of permission on the actual 1400da6c28aaSamw * extended attr kcred is passed for streams. 1401da6c28aaSamw */ 1402da6c28aaSamw cr = kcred; 1403da6c28aaSamw } 1404da6c28aaSamw 1405dc20a302Sas smb_node_start_crit(snode, RW_READER); 1406c8ec8eeaSjose borrego rc = nbl_svmand(snode->vp, kcred, &svmand); 1407dc20a302Sas if (rc) { 1408dc20a302Sas smb_node_end_crit(snode); 1409dc20a302Sas return (rc); 1410dc20a302Sas } 1411dc20a302Sas 1412c8ec8eeaSjose borrego ct = smb_ct; 1413c8ec8eeaSjose borrego ct.cc_pid = sr->fid_ofile->f_uniqid; 1414dc20a302Sas rc = nbl_lock_conflict(snode->vp, NBL_READ, uio->uio_loffset, 1415c8ec8eeaSjose borrego uio->uio_iov->iov_len, svmand, &ct); 1416da6c28aaSamw 1417dc20a302Sas if (rc) { 1418dc20a302Sas smb_node_end_crit(snode); 14196537f381Sas return (ERANGE); 1420dc20a302Sas } 1421dc20a302Sas rc = smb_vop_read(snode->vp, uio, cr); 1422dc20a302Sas 1423dc20a302Sas if (rc == 0 && ret_attr) { 1424da6c28aaSamw /* 1425dc20a302Sas * Use kcred to update the node attr because this 1426dc20a302Sas * call is not being made on behalf of the user. 1427da6c28aaSamw */ 1428da6c28aaSamw ret_attr->sa_mask = SMB_AT_ALL; 1429dc20a302Sas if (smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0, 1430dc20a302Sas kcred) == 0) { 1431dc20a302Sas snode->attr = *ret_attr; 1432dc20a302Sas } 1433da6c28aaSamw } 1434da6c28aaSamw 1435dc20a302Sas smb_node_end_crit(snode); 1436dc20a302Sas 1437da6c28aaSamw return (rc); 1438da6c28aaSamw } 1439da6c28aaSamw 1440da6c28aaSamw /* 1441da6c28aaSamw * smb_fsop_write 1442da6c28aaSamw * 1443da6c28aaSamw * This is a wrapper function used for smb_write and smb_write_raw operations. 1444da6c28aaSamw * 1445da6c28aaSamw * It is assumed that a reference exists on snode coming into this routine. 1446da6c28aaSamw */ 1447da6c28aaSamw int 1448da6c28aaSamw smb_fsop_write( 1449faa1795aSjb smb_request_t *sr, 1450da6c28aaSamw cred_t *cr, 1451da6c28aaSamw smb_node_t *snode, 1452da6c28aaSamw uio_t *uio, 1453da6c28aaSamw uint32_t *lcount, 1454da6c28aaSamw smb_attr_t *ret_attr, 14553db3f65cSamw int ioflag) 1456da6c28aaSamw { 1457da6c28aaSamw smb_node_t *unnamed_node; 1458da6c28aaSamw vnode_t *unnamed_vp = NULL; 1459c8ec8eeaSjose borrego caller_context_t ct; 1460dc20a302Sas int svmand; 1461da6c28aaSamw int rc; 1462da6c28aaSamw 1463da6c28aaSamw ASSERT(cr); 1464da6c28aaSamw ASSERT(snode); 1465da6c28aaSamw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 1466da6c28aaSamw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 1467da6c28aaSamw 1468da6c28aaSamw ASSERT(sr); 1469da6c28aaSamw ASSERT(sr->tid_tree); 1470da6c28aaSamw ASSERT(sr->fid_ofile); 1471da6c28aaSamw 1472c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) 1473da6c28aaSamw return (EROFS); 1474da6c28aaSamw 1475c8ec8eeaSjose borrego if (SMB_OFILE_IS_READONLY(sr->fid_ofile)) 1476c8ec8eeaSjose borrego return (EACCES); 1477c8ec8eeaSjose borrego 1478dc20a302Sas rc = smb_ofile_access(sr->fid_ofile, cr, FILE_WRITE_DATA); 1479dc20a302Sas if (rc != NT_STATUS_SUCCESS) { 1480dc20a302Sas rc = smb_ofile_access(sr->fid_ofile, cr, FILE_APPEND_DATA); 1481dc20a302Sas if (rc != NT_STATUS_SUCCESS) 1482dc20a302Sas return (EACCES); 1483dc20a302Sas } 1484da6c28aaSamw 1485da6c28aaSamw unnamed_node = SMB_IS_STREAM(snode); 1486da6c28aaSamw 1487da6c28aaSamw if (unnamed_node) { 1488da6c28aaSamw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 1489da6c28aaSamw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 1490da6c28aaSamw unnamed_vp = unnamed_node->vp; 1491da6c28aaSamw /* 1492da6c28aaSamw * Streams permission are checked against the unnamed stream, 1493da6c28aaSamw * but in FS level they have their own permissions. To avoid 1494da6c28aaSamw * rejection by FS due to lack of permission on the actual 1495da6c28aaSamw * extended attr kcred is passed for streams. 1496da6c28aaSamw */ 1497da6c28aaSamw cr = kcred; 1498da6c28aaSamw } 1499da6c28aaSamw 1500dc20a302Sas smb_node_start_crit(snode, RW_READER); 1501c8ec8eeaSjose borrego rc = nbl_svmand(snode->vp, kcred, &svmand); 1502dc20a302Sas if (rc) { 1503dc20a302Sas smb_node_end_crit(snode); 1504dc20a302Sas return (rc); 1505dc20a302Sas } 1506c8ec8eeaSjose borrego 1507c8ec8eeaSjose borrego ct = smb_ct; 1508c8ec8eeaSjose borrego ct.cc_pid = sr->fid_ofile->f_uniqid; 1509dc20a302Sas rc = nbl_lock_conflict(snode->vp, NBL_WRITE, uio->uio_loffset, 1510c8ec8eeaSjose borrego uio->uio_iov->iov_len, svmand, &ct); 1511da6c28aaSamw 1512dc20a302Sas if (rc) { 1513dc20a302Sas smb_node_end_crit(snode); 15146537f381Sas return (ERANGE); 1515dc20a302Sas } 15163db3f65cSamw rc = smb_vop_write(snode->vp, uio, ioflag, lcount, cr); 1517dc20a302Sas 1518dc20a302Sas if (rc == 0 && ret_attr) { 1519da6c28aaSamw /* 1520dc20a302Sas * Use kcred to update the node attr because this 1521dc20a302Sas * call is not being made on behalf of the user. 1522da6c28aaSamw */ 1523da6c28aaSamw ret_attr->sa_mask = SMB_AT_ALL; 1524dc20a302Sas if (smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0, 1525dc20a302Sas kcred) == 0) { 1526dc20a302Sas snode->attr = *ret_attr; 1527dc20a302Sas } 1528da6c28aaSamw } 1529da6c28aaSamw 1530dc20a302Sas smb_node_end_crit(snode); 1531dc20a302Sas 1532da6c28aaSamw return (rc); 1533da6c28aaSamw } 1534da6c28aaSamw 1535da6c28aaSamw /* 1536da6c28aaSamw * smb_fsop_statfs 1537da6c28aaSamw * 1538da6c28aaSamw * This is a wrapper function used for stat operations. 1539da6c28aaSamw */ 1540da6c28aaSamw int 1541da6c28aaSamw smb_fsop_statfs( 1542da6c28aaSamw cred_t *cr, 1543da6c28aaSamw smb_node_t *snode, 1544da6c28aaSamw struct statvfs64 *statp) 1545da6c28aaSamw { 1546da6c28aaSamw ASSERT(cr); 1547da6c28aaSamw ASSERT(snode); 1548da6c28aaSamw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 1549da6c28aaSamw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 1550da6c28aaSamw 1551da6c28aaSamw return (smb_vop_statfs(snode->vp, statp, cr)); 1552da6c28aaSamw } 1553da6c28aaSamw 1554da6c28aaSamw /* 1555da6c28aaSamw * smb_fsop_access 1556ee60c47bSjm * 1557ee60c47bSjm * Named streams do not have separate permissions from the associated 1558ee60c47bSjm * unnamed stream. Thus, if node is a named stream, the permissions 1559ee60c47bSjm * check will be performed on the associated unnamed stream. 1560ee60c47bSjm * 1561ee60c47bSjm * However, our named streams do have their own quarantine attribute, 1562ee60c47bSjm * separate from that on the unnamed stream. If READ or EXECUTE 1563ee60c47bSjm * access has been requested on a named stream, an additional access 1564ee60c47bSjm * check is performed on the named stream in case it has been 1565ee60c47bSjm * quarantined. kcred is used to avoid issues with the permissions 1566ee60c47bSjm * set on the extended attribute file representing the named stream. 1567da6c28aaSamw */ 1568da6c28aaSamw int 1569da6c28aaSamw smb_fsop_access(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 1570da6c28aaSamw uint32_t faccess) 1571da6c28aaSamw { 1572da6c28aaSamw int access = 0; 1573da6c28aaSamw int error; 1574da6c28aaSamw vnode_t *dir_vp; 1575da6c28aaSamw boolean_t acl_check = B_TRUE; 1576da6c28aaSamw smb_node_t *unnamed_node; 1577da6c28aaSamw 1578c8ec8eeaSjose borrego ASSERT(sr); 1579da6c28aaSamw ASSERT(cr); 1580da6c28aaSamw ASSERT(snode); 1581da6c28aaSamw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 1582da6c28aaSamw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 1583da6c28aaSamw 1584da6c28aaSamw if (faccess == 0) 1585da6c28aaSamw return (NT_STATUS_SUCCESS); 1586da6c28aaSamw 1587c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) { 1588da6c28aaSamw if (faccess & (FILE_WRITE_DATA|FILE_APPEND_DATA| 1589da6c28aaSamw FILE_WRITE_EA|FILE_DELETE_CHILD|FILE_WRITE_ATTRIBUTES| 1590da6c28aaSamw DELETE|WRITE_DAC|WRITE_OWNER)) { 1591da6c28aaSamw return (NT_STATUS_ACCESS_DENIED); 1592da6c28aaSamw } 1593da6c28aaSamw } 1594da6c28aaSamw 1595da6c28aaSamw unnamed_node = SMB_IS_STREAM(snode); 1596da6c28aaSamw if (unnamed_node) { 1597da6c28aaSamw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 1598da6c28aaSamw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 1599ee60c47bSjm 1600ee60c47bSjm /* 1601ee60c47bSjm * Perform VREAD access check on the named stream in case it 1602ee60c47bSjm * is quarantined. kcred is passed to smb_vop_access so it 1603ee60c47bSjm * doesn't fail due to lack of permission. 1604ee60c47bSjm */ 1605ee60c47bSjm if (faccess & (FILE_READ_DATA | FILE_EXECUTE)) { 1606ee60c47bSjm error = smb_vop_access(snode->vp, VREAD, 1607ee60c47bSjm 0, NULL, kcred); 1608ee60c47bSjm if (error) 1609ee60c47bSjm return (NT_STATUS_ACCESS_DENIED); 1610ee60c47bSjm } 1611ee60c47bSjm 1612da6c28aaSamw /* 1613da6c28aaSamw * Streams authorization should be performed against the 1614da6c28aaSamw * unnamed stream. 1615da6c28aaSamw */ 1616da6c28aaSamw snode = unnamed_node; 1617da6c28aaSamw } 1618da6c28aaSamw 1619da6c28aaSamw if (faccess & ACCESS_SYSTEM_SECURITY) { 1620da6c28aaSamw /* 1621da6c28aaSamw * This permission is required for reading/writing SACL and 1622da6c28aaSamw * it's not part of DACL. It's only granted via proper 1623da6c28aaSamw * privileges. 1624da6c28aaSamw */ 1625da6c28aaSamw if ((sr->uid_user->u_privileges & 1626da6c28aaSamw (SMB_USER_PRIV_BACKUP | 1627da6c28aaSamw SMB_USER_PRIV_RESTORE | 1628da6c28aaSamw SMB_USER_PRIV_SECURITY)) == 0) 1629da6c28aaSamw return (NT_STATUS_PRIVILEGE_NOT_HELD); 1630da6c28aaSamw 1631da6c28aaSamw faccess &= ~ACCESS_SYSTEM_SECURITY; 1632da6c28aaSamw } 1633da6c28aaSamw 1634da6c28aaSamw /* Links don't have ACL */ 1635c8ec8eeaSjose borrego if ((!smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) || 1636da6c28aaSamw (snode->attr.sa_vattr.va_type == VLNK)) 1637da6c28aaSamw acl_check = B_FALSE; 1638da6c28aaSamw 1639da6c28aaSamw if (acl_check) { 1640da6c28aaSamw dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL; 1641da6c28aaSamw error = smb_vop_access(snode->vp, faccess, V_ACE_MASK, dir_vp, 1642da6c28aaSamw cr); 1643da6c28aaSamw } else { 1644da6c28aaSamw /* 1645da6c28aaSamw * FS doesn't understand 32-bit mask, need to map 1646da6c28aaSamw */ 1647da6c28aaSamw if (faccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) 1648da6c28aaSamw access |= VWRITE; 1649da6c28aaSamw 1650da6c28aaSamw if (faccess & FILE_READ_DATA) 1651da6c28aaSamw access |= VREAD; 1652da6c28aaSamw 1653da6c28aaSamw if (faccess & FILE_EXECUTE) 1654da6c28aaSamw access |= VEXEC; 1655da6c28aaSamw 1656da6c28aaSamw error = smb_vop_access(snode->vp, access, 0, NULL, cr); 1657da6c28aaSamw } 1658da6c28aaSamw 1659da6c28aaSamw return ((error) ? NT_STATUS_ACCESS_DENIED : NT_STATUS_SUCCESS); 1660da6c28aaSamw } 1661da6c28aaSamw 1662da6c28aaSamw /* 1663da6c28aaSamw * smb_fsop_lookup_name() 1664da6c28aaSamw * 1665da6c28aaSamw * Sanity checks on dir_snode done in smb_fsop_lookup(). 1666da6c28aaSamw * 1667da6c28aaSamw * Note: This function is called only from the open path. 1668da6c28aaSamw * It will check if the file is a stream. 1669da6c28aaSamw * It will also return an error if the looked-up file is in 1670da6c28aaSamw * a child mount. 1671da6c28aaSamw */ 1672da6c28aaSamw 1673da6c28aaSamw int 1674da6c28aaSamw smb_fsop_lookup_name( 1675faa1795aSjb smb_request_t *sr, 1676da6c28aaSamw cred_t *cr, 1677da6c28aaSamw int flags, 1678da6c28aaSamw smb_node_t *root_node, 1679da6c28aaSamw smb_node_t *dir_snode, 1680da6c28aaSamw char *name, 1681da6c28aaSamw smb_node_t **ret_snode, 1682da6c28aaSamw smb_attr_t *ret_attr) 1683da6c28aaSamw { 1684faa1795aSjb smb_node_t *fnode; 1685faa1795aSjb smb_attr_t file_attr; 1686faa1795aSjb vnode_t *xattrdirvp; 1687faa1795aSjb vnode_t *vp; 1688faa1795aSjb char *od_name; 1689faa1795aSjb char *fname; 1690faa1795aSjb char *sname; 1691faa1795aSjb int rc; 1692da6c28aaSamw 1693da6c28aaSamw ASSERT(cr); 1694da6c28aaSamw ASSERT(dir_snode); 1695da6c28aaSamw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 1696da6c28aaSamw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 1697da6c28aaSamw 1698da6c28aaSamw /* 1699da6c28aaSamw * The following check is required for streams processing, below 1700da6c28aaSamw */ 1701da6c28aaSamw 1702c8ec8eeaSjose borrego if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 1703da6c28aaSamw flags |= SMB_IGNORE_CASE; 1704da6c28aaSamw 1705da6c28aaSamw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1706da6c28aaSamw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1707da6c28aaSamw 1708da6c28aaSamw if (smb_stream_parse_name(name, fname, sname)) { 1709da6c28aaSamw /* 1710da6c28aaSamw * Look up the unnamed stream (i.e. fname). 1711da6c28aaSamw * Unmangle processing will be done on fname 1712da6c28aaSamw * as well as any link target. 1713da6c28aaSamw */ 1714da6c28aaSamw rc = smb_fsop_lookup(sr, cr, flags, root_node, dir_snode, fname, 1715da6c28aaSamw &fnode, &file_attr, NULL, NULL); 1716da6c28aaSamw 1717da6c28aaSamw if (rc != 0) { 1718da6c28aaSamw kmem_free(fname, MAXNAMELEN); 1719da6c28aaSamw kmem_free(sname, MAXNAMELEN); 1720da6c28aaSamw return (rc); 1721da6c28aaSamw } 1722da6c28aaSamw 1723da6c28aaSamw od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1724da6c28aaSamw 1725da6c28aaSamw /* 1726da6c28aaSamw * od_name is the on-disk name of the stream, except 1727da6c28aaSamw * without the prepended stream prefix (SMB_STREAM_PREFIX) 1728da6c28aaSamw */ 1729da6c28aaSamw 1730da6c28aaSamw /* 1731da6c28aaSamw * XXX 1732da6c28aaSamw * What permissions NTFS requires for stream lookup if any? 1733da6c28aaSamw */ 1734da6c28aaSamw rc = smb_vop_stream_lookup(fnode->vp, sname, &vp, od_name, 1735dc20a302Sas &xattrdirvp, flags, root_node->vp, cr); 1736da6c28aaSamw 1737da6c28aaSamw if (rc != 0) { 1738da6c28aaSamw smb_node_release(fnode); 1739da6c28aaSamw kmem_free(fname, MAXNAMELEN); 1740da6c28aaSamw kmem_free(sname, MAXNAMELEN); 1741da6c28aaSamw kmem_free(od_name, MAXNAMELEN); 1742da6c28aaSamw return (rc); 1743da6c28aaSamw } 1744da6c28aaSamw 1745da6c28aaSamw *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, 1746da6c28aaSamw vp, od_name, ret_attr); 1747da6c28aaSamw 1748da6c28aaSamw kmem_free(od_name, MAXNAMELEN); 1749da6c28aaSamw smb_node_release(fnode); 1750da6c28aaSamw 1751da6c28aaSamw if (*ret_snode == NULL) { 1752da6c28aaSamw VN_RELE(xattrdirvp); 1753da6c28aaSamw VN_RELE(vp); 1754da6c28aaSamw kmem_free(fname, MAXNAMELEN); 1755da6c28aaSamw kmem_free(sname, MAXNAMELEN); 1756da6c28aaSamw return (ENOMEM); 1757da6c28aaSamw } 1758da6c28aaSamw } else { 1759da6c28aaSamw rc = smb_fsop_lookup(sr, cr, flags, root_node, dir_snode, name, 1760da6c28aaSamw ret_snode, ret_attr, NULL, NULL); 1761da6c28aaSamw } 1762da6c28aaSamw 1763da6c28aaSamw if (rc == 0) { 1764da6c28aaSamw ASSERT(ret_snode); 1765c8ec8eeaSjose borrego if (SMB_TREE_CONTAINS_NODE(sr, *ret_snode) == 0) { 1766da6c28aaSamw smb_node_release(*ret_snode); 1767da6c28aaSamw *ret_snode = NULL; 1768da6c28aaSamw rc = EACCES; 1769da6c28aaSamw } 1770da6c28aaSamw } 1771da6c28aaSamw 1772da6c28aaSamw kmem_free(fname, MAXNAMELEN); 1773da6c28aaSamw kmem_free(sname, MAXNAMELEN); 1774da6c28aaSamw 1775da6c28aaSamw return (rc); 1776da6c28aaSamw } 1777da6c28aaSamw 1778da6c28aaSamw /* 1779da6c28aaSamw * smb_fsop_lookup 1780da6c28aaSamw * 1781da6c28aaSamw * All SMB functions should use this smb_vop_lookup wrapper to ensure that 1782da6c28aaSamw * the smb_vop_lookup is performed with the appropriate credentials and using 1783da6c28aaSamw * case insensitive compares. Please document any direct call to smb_vop_lookup 1784da6c28aaSamw * to explain the reason for avoiding this wrapper. 1785da6c28aaSamw * 1786da6c28aaSamw * It is assumed that a reference exists on dir_snode coming into this routine 1787da6c28aaSamw * (and that it is safe from deallocation). 1788da6c28aaSamw * 1789da6c28aaSamw * Same with the root_node. 1790da6c28aaSamw * 1791da6c28aaSamw * *ret_snode is returned with a reference upon success. No reference is 1792da6c28aaSamw * taken if an error is returned. 1793da6c28aaSamw * 1794da6c28aaSamw * Note: The returned ret_snode may be in a child mount. This is ok for 1795da6c28aaSamw * readdir and getdents. 1796da6c28aaSamw * 1797c8ec8eeaSjose borrego * ret_shortname and ret_name83 must each point to buffers of at least 1798c8ec8eeaSjose borrego * SMB_SHORTNAMELEN bytes. 1799c8ec8eeaSjose borrego * 1800c8ec8eeaSjose borrego * Other smb_fsop_* routines will call SMB_TREE_CONTAINS_NODE() to prevent 1801da6c28aaSamw * operations on files not in the parent mount. 1802da6c28aaSamw */ 1803da6c28aaSamw int 1804da6c28aaSamw smb_fsop_lookup( 1805faa1795aSjb smb_request_t *sr, 1806da6c28aaSamw cred_t *cr, 1807da6c28aaSamw int flags, 1808da6c28aaSamw smb_node_t *root_node, 1809da6c28aaSamw smb_node_t *dir_snode, 1810da6c28aaSamw char *name, 1811da6c28aaSamw smb_node_t **ret_snode, 1812da6c28aaSamw smb_attr_t *ret_attr, 1813c8ec8eeaSjose borrego char *ret_shortname, 1814c8ec8eeaSjose borrego char *ret_name83) 1815da6c28aaSamw { 1816da6c28aaSamw smb_node_t *lnk_target_node; 1817da6c28aaSamw smb_node_t *lnk_dnode; 1818da6c28aaSamw char *longname; 1819da6c28aaSamw char *od_name; 1820da6c28aaSamw vnode_t *vp; 1821da6c28aaSamw int rc; 1822da6c28aaSamw 1823da6c28aaSamw ASSERT(cr); 1824da6c28aaSamw ASSERT(dir_snode); 1825da6c28aaSamw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 1826da6c28aaSamw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 1827da6c28aaSamw 1828da6c28aaSamw if (name == NULL) 1829da6c28aaSamw return (EINVAL); 1830da6c28aaSamw 1831c8ec8eeaSjose borrego if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 1832da6c28aaSamw return (EACCES); 1833da6c28aaSamw 1834c8ec8eeaSjose borrego if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 1835da6c28aaSamw flags |= SMB_IGNORE_CASE; 1836da6c28aaSamw 1837da6c28aaSamw od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1838da6c28aaSamw 1839da6c28aaSamw rc = smb_vop_lookup(dir_snode->vp, name, &vp, od_name, flags, 1840dc20a302Sas root_node ? root_node->vp : NULL, cr); 1841da6c28aaSamw 1842da6c28aaSamw if (rc != 0) { 1843da6c28aaSamw if (smb_maybe_mangled_name(name) == 0) { 1844da6c28aaSamw kmem_free(od_name, MAXNAMELEN); 1845da6c28aaSamw return (rc); 1846da6c28aaSamw } 1847da6c28aaSamw 1848da6c28aaSamw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1849da6c28aaSamw 1850da6c28aaSamw rc = smb_unmangle_name(sr, cr, dir_snode, name, longname, 1851da6c28aaSamw MAXNAMELEN, ret_shortname, ret_name83, 1); 1852da6c28aaSamw 1853da6c28aaSamw if (rc != 0) { 1854da6c28aaSamw kmem_free(od_name, MAXNAMELEN); 1855da6c28aaSamw kmem_free(longname, MAXNAMELEN); 1856da6c28aaSamw return (rc); 1857da6c28aaSamw } 1858da6c28aaSamw 1859da6c28aaSamw /* 1860da6c28aaSamw * We passed "1" as the "od" parameter 1861da6c28aaSamw * to smb_unmangle_name(), such that longname 1862da6c28aaSamw * is the real (case-sensitive) on-disk name. 1863da6c28aaSamw * We make sure we do a lookup on this exact 1864da6c28aaSamw * name, as the name was mangled and denotes 1865da6c28aaSamw * a unique file. 1866da6c28aaSamw */ 1867da6c28aaSamw 1868da6c28aaSamw if (flags & SMB_IGNORE_CASE) 1869da6c28aaSamw flags &= ~SMB_IGNORE_CASE; 1870da6c28aaSamw 1871da6c28aaSamw rc = smb_vop_lookup(dir_snode->vp, longname, &vp, od_name, 1872dc20a302Sas flags, root_node ? root_node->vp : NULL, cr); 1873da6c28aaSamw 1874da6c28aaSamw kmem_free(longname, MAXNAMELEN); 1875da6c28aaSamw 1876da6c28aaSamw if (rc != 0) { 1877da6c28aaSamw kmem_free(od_name, MAXNAMELEN); 1878da6c28aaSamw return (rc); 1879da6c28aaSamw } 1880da6c28aaSamw } 1881da6c28aaSamw 1882da6c28aaSamw if ((flags & SMB_FOLLOW_LINKS) && (vp->v_type == VLNK)) { 1883da6c28aaSamw 1884da6c28aaSamw rc = smb_pathname(sr, od_name, FOLLOW, root_node, dir_snode, 1885da6c28aaSamw &lnk_dnode, &lnk_target_node, cr); 1886da6c28aaSamw 1887da6c28aaSamw if (rc != 0) { 1888da6c28aaSamw /* 1889da6c28aaSamw * The link is assumed to be for the last component 1890da6c28aaSamw * of a path. Hence any ENOTDIR error will be returned 1891da6c28aaSamw * as ENOENT. 1892da6c28aaSamw */ 1893da6c28aaSamw if (rc == ENOTDIR) 1894da6c28aaSamw rc = ENOENT; 1895da6c28aaSamw 1896da6c28aaSamw VN_RELE(vp); 1897da6c28aaSamw kmem_free(od_name, MAXNAMELEN); 1898da6c28aaSamw return (rc); 1899da6c28aaSamw } 1900da6c28aaSamw 1901da6c28aaSamw /* 1902da6c28aaSamw * Release the original VLNK vnode 1903da6c28aaSamw */ 1904da6c28aaSamw 1905da6c28aaSamw VN_RELE(vp); 1906da6c28aaSamw vp = lnk_target_node->vp; 1907da6c28aaSamw 1908da6c28aaSamw rc = smb_vop_traverse_check(&vp); 1909da6c28aaSamw 1910da6c28aaSamw if (rc != 0) { 1911da6c28aaSamw smb_node_release(lnk_dnode); 1912da6c28aaSamw smb_node_release(lnk_target_node); 1913da6c28aaSamw kmem_free(od_name, MAXNAMELEN); 1914da6c28aaSamw return (rc); 1915da6c28aaSamw } 1916da6c28aaSamw 1917da6c28aaSamw /* 1918da6c28aaSamw * smb_vop_traverse_check() may have returned a different vnode 1919da6c28aaSamw */ 1920da6c28aaSamw 1921da6c28aaSamw if (lnk_target_node->vp == vp) { 1922da6c28aaSamw *ret_snode = lnk_target_node; 1923da6c28aaSamw *ret_attr = (*ret_snode)->attr; 1924da6c28aaSamw } else { 1925da6c28aaSamw *ret_snode = smb_node_lookup(sr, NULL, cr, vp, 1926da6c28aaSamw lnk_target_node->od_name, lnk_dnode, NULL, 1927da6c28aaSamw ret_attr); 1928da6c28aaSamw 1929da6c28aaSamw if (*ret_snode == NULL) { 1930da6c28aaSamw VN_RELE(vp); 1931da6c28aaSamw rc = ENOMEM; 1932da6c28aaSamw } 1933da6c28aaSamw smb_node_release(lnk_target_node); 1934da6c28aaSamw } 1935da6c28aaSamw 1936da6c28aaSamw smb_node_release(lnk_dnode); 1937da6c28aaSamw 1938da6c28aaSamw } else { 1939da6c28aaSamw 1940da6c28aaSamw rc = smb_vop_traverse_check(&vp); 1941da6c28aaSamw if (rc) { 1942da6c28aaSamw VN_RELE(vp); 1943da6c28aaSamw kmem_free(od_name, MAXNAMELEN); 1944da6c28aaSamw return (rc); 1945da6c28aaSamw } 1946da6c28aaSamw 1947da6c28aaSamw *ret_snode = smb_node_lookup(sr, NULL, cr, vp, od_name, 1948da6c28aaSamw dir_snode, NULL, ret_attr); 1949da6c28aaSamw 1950da6c28aaSamw if (*ret_snode == NULL) { 1951da6c28aaSamw VN_RELE(vp); 1952da6c28aaSamw rc = ENOMEM; 1953da6c28aaSamw } 1954da6c28aaSamw } 1955da6c28aaSamw 1956da6c28aaSamw kmem_free(od_name, MAXNAMELEN); 1957da6c28aaSamw return (rc); 1958da6c28aaSamw } 1959da6c28aaSamw 1960da6c28aaSamw /* 1961da6c28aaSamw * smb_fsop_stream_readdir() 1962da6c28aaSamw * 1963da6c28aaSamw * ret_snode and ret_attr are optional parameters (i.e. NULL may be passed in) 1964da6c28aaSamw * 1965da6c28aaSamw * This routine will return only NTFS streams. If an NTFS stream is not 1966da6c28aaSamw * found at the offset specified, the directory will be read until an NTFS 1967da6c28aaSamw * stream is found or until EOF. 1968da6c28aaSamw * 1969da6c28aaSamw * Note: Sanity checks done in caller 1970da6c28aaSamw * (smb_fsop_readdir(), smb_fsop_remove_streams()) 1971da6c28aaSamw */ 1972da6c28aaSamw 1973da6c28aaSamw int 1974faa1795aSjb smb_fsop_stream_readdir(smb_request_t *sr, cred_t *cr, smb_node_t *fnode, 1975da6c28aaSamw uint32_t *cookiep, struct fs_stream_info *stream_info, 1976da6c28aaSamw smb_node_t **ret_snode, smb_attr_t *ret_attr) 1977da6c28aaSamw { 1978da6c28aaSamw smb_node_t *ret_snodep = NULL; 1979da6c28aaSamw smb_attr_t tmp_attr; 1980da6c28aaSamw vnode_t *xattrdirvp; 1981da6c28aaSamw vnode_t *vp; 1982da6c28aaSamw int rc = 0; 1983da6c28aaSamw int flags = 0; 1984da6c28aaSamw 1985da6c28aaSamw /* 1986da6c28aaSamw * XXX NTFS permission requirements if any? 1987da6c28aaSamw */ 1988da6c28aaSamw ASSERT(cr); 1989da6c28aaSamw ASSERT(fnode); 1990da6c28aaSamw ASSERT(fnode->n_magic == SMB_NODE_MAGIC); 1991da6c28aaSamw ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING); 1992da6c28aaSamw 1993c8ec8eeaSjose borrego if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 1994da6c28aaSamw flags = SMB_IGNORE_CASE; 1995da6c28aaSamw 1996da6c28aaSamw rc = smb_vop_stream_readdir(fnode->vp, cookiep, stream_info, &vp, 1997dc20a302Sas &xattrdirvp, flags, cr); 1998da6c28aaSamw 1999da6c28aaSamw if ((rc != 0) || *cookiep == SMB_EOF) 2000da6c28aaSamw return (rc); 2001da6c28aaSamw 2002da6c28aaSamw ret_snodep = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, vp, 2003da6c28aaSamw stream_info->name, &tmp_attr); 2004da6c28aaSamw 2005da6c28aaSamw if (ret_snodep == NULL) { 2006da6c28aaSamw VN_RELE(xattrdirvp); 2007da6c28aaSamw VN_RELE(vp); 2008da6c28aaSamw return (ENOMEM); 2009da6c28aaSamw } 2010da6c28aaSamw 2011da6c28aaSamw stream_info->size = tmp_attr.sa_vattr.va_size; 2012da6c28aaSamw 2013da6c28aaSamw if (ret_attr) 2014da6c28aaSamw *ret_attr = tmp_attr; 2015da6c28aaSamw 2016da6c28aaSamw if (ret_snode) 2017da6c28aaSamw *ret_snode = ret_snodep; 2018da6c28aaSamw else 2019da6c28aaSamw smb_node_release(ret_snodep); 2020da6c28aaSamw 2021da6c28aaSamw return (rc); 2022da6c28aaSamw } 2023da6c28aaSamw 2024da6c28aaSamw int /*ARGSUSED*/ 2025da6c28aaSamw smb_fsop_commit(smb_request_t *sr, cred_t *cr, smb_node_t *snode) 2026da6c28aaSamw { 2027da6c28aaSamw ASSERT(cr); 2028da6c28aaSamw ASSERT(snode); 2029da6c28aaSamw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 2030da6c28aaSamw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 2031da6c28aaSamw 2032da6c28aaSamw ASSERT(sr); 2033da6c28aaSamw ASSERT(sr->tid_tree); 2034c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) 2035da6c28aaSamw return (EROFS); 2036da6c28aaSamw 2037dc20a302Sas return (smb_vop_commit(snode->vp, cr)); 2038da6c28aaSamw } 2039da6c28aaSamw 2040da6c28aaSamw /* 2041da6c28aaSamw * smb_fsop_aclread 2042da6c28aaSamw * 2043da6c28aaSamw * Retrieve filesystem ACL. Depends on requested ACLs in 2044da6c28aaSamw * fs_sd->sd_secinfo, it'll set DACL and SACL pointers in 2045da6c28aaSamw * fs_sd. Note that requesting a DACL/SACL doesn't mean that 2046da6c28aaSamw * the corresponding field in fs_sd should be non-NULL upon 2047da6c28aaSamw * return, since the target ACL might not contain that type of 2048da6c28aaSamw * entries. 2049da6c28aaSamw * 2050da6c28aaSamw * Returned ACL is always in ACE_T (aka ZFS) format. 2051da6c28aaSamw * If successful the allocated memory for the ACL should be freed 205255bf511dSas * using smb_fsacl_free() or smb_fssd_term() 2053da6c28aaSamw */ 2054da6c28aaSamw int 2055da6c28aaSamw smb_fsop_aclread(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 2056da6c28aaSamw smb_fssd_t *fs_sd) 2057da6c28aaSamw { 2058da6c28aaSamw int error = 0; 2059da6c28aaSamw int flags = 0; 2060da6c28aaSamw int access = 0; 2061da6c28aaSamw acl_t *acl; 2062da6c28aaSamw smb_node_t *unnamed_node; 2063da6c28aaSamw 2064da6c28aaSamw ASSERT(cr); 2065da6c28aaSamw 2066da6c28aaSamw if (sr->fid_ofile) { 2067da6c28aaSamw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 2068da6c28aaSamw access = READ_CONTROL; 2069da6c28aaSamw 2070da6c28aaSamw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 2071da6c28aaSamw access |= ACCESS_SYSTEM_SECURITY; 2072da6c28aaSamw 2073da6c28aaSamw error = smb_ofile_access(sr->fid_ofile, cr, access); 2074da6c28aaSamw if (error != NT_STATUS_SUCCESS) { 2075da6c28aaSamw return (EACCES); 2076da6c28aaSamw } 2077da6c28aaSamw } 2078da6c28aaSamw 2079da6c28aaSamw unnamed_node = SMB_IS_STREAM(snode); 2080da6c28aaSamw if (unnamed_node) { 2081da6c28aaSamw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 2082da6c28aaSamw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 2083da6c28aaSamw /* 2084da6c28aaSamw * Streams don't have ACL, any read ACL attempt on a stream 2085da6c28aaSamw * should be performed on the unnamed stream. 2086da6c28aaSamw */ 2087da6c28aaSamw snode = unnamed_node; 2088da6c28aaSamw } 2089da6c28aaSamw 2090c8ec8eeaSjose borrego if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) 2091da6c28aaSamw flags = ATTR_NOACLCHECK; 2092da6c28aaSamw 2093da6c28aaSamw error = smb_vop_acl_read(snode->vp, &acl, flags, 2094dc20a302Sas sr->tid_tree->t_acltype, cr); 2095da6c28aaSamw if (error != 0) { 2096da6c28aaSamw return (error); 2097da6c28aaSamw } 2098da6c28aaSamw 2099da6c28aaSamw error = acl_translate(acl, _ACL_ACE_ENABLED, 2100da6c28aaSamw (snode->vp->v_type == VDIR), fs_sd->sd_uid, fs_sd->sd_gid); 2101da6c28aaSamw 2102da6c28aaSamw if (error == 0) { 210355bf511dSas smb_fsacl_split(acl, &fs_sd->sd_zdacl, &fs_sd->sd_zsacl, 2104da6c28aaSamw fs_sd->sd_secinfo); 2105da6c28aaSamw } 2106da6c28aaSamw 2107da6c28aaSamw acl_free(acl); 2108da6c28aaSamw return (error); 2109da6c28aaSamw } 2110da6c28aaSamw 2111da6c28aaSamw /* 2112da6c28aaSamw * smb_fsop_aclwrite 2113da6c28aaSamw * 2114da6c28aaSamw * Stores the filesystem ACL provided in fs_sd->sd_acl. 2115da6c28aaSamw */ 2116da6c28aaSamw int 2117da6c28aaSamw smb_fsop_aclwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 2118da6c28aaSamw smb_fssd_t *fs_sd) 2119da6c28aaSamw { 2120da6c28aaSamw int target_flavor; 2121da6c28aaSamw int error = 0; 2122da6c28aaSamw int flags = 0; 2123da6c28aaSamw int access = 0; 2124da6c28aaSamw acl_t *acl, *dacl, *sacl; 2125da6c28aaSamw smb_node_t *unnamed_node; 2126da6c28aaSamw 2127da6c28aaSamw ASSERT(cr); 2128da6c28aaSamw 2129da6c28aaSamw ASSERT(sr); 2130da6c28aaSamw ASSERT(sr->tid_tree); 2131c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) 2132da6c28aaSamw return (EROFS); 2133da6c28aaSamw 2134da6c28aaSamw if (sr->fid_ofile) { 2135da6c28aaSamw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 2136da6c28aaSamw access = WRITE_DAC; 2137da6c28aaSamw 2138da6c28aaSamw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 2139da6c28aaSamw access |= ACCESS_SYSTEM_SECURITY; 2140da6c28aaSamw 2141da6c28aaSamw error = smb_ofile_access(sr->fid_ofile, cr, access); 2142da6c28aaSamw if (error != NT_STATUS_SUCCESS) 2143da6c28aaSamw return (EACCES); 2144da6c28aaSamw } 2145da6c28aaSamw 2146da6c28aaSamw switch (sr->tid_tree->t_acltype) { 2147da6c28aaSamw case ACLENT_T: 2148da6c28aaSamw target_flavor = _ACL_ACLENT_ENABLED; 2149da6c28aaSamw break; 2150da6c28aaSamw 2151da6c28aaSamw case ACE_T: 2152da6c28aaSamw target_flavor = _ACL_ACE_ENABLED; 2153da6c28aaSamw break; 2154da6c28aaSamw default: 2155da6c28aaSamw return (EINVAL); 2156da6c28aaSamw } 2157da6c28aaSamw 2158da6c28aaSamw unnamed_node = SMB_IS_STREAM(snode); 2159da6c28aaSamw if (unnamed_node) { 2160da6c28aaSamw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 2161da6c28aaSamw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 2162da6c28aaSamw /* 2163da6c28aaSamw * Streams don't have ACL, any write ACL attempt on a stream 2164da6c28aaSamw * should be performed on the unnamed stream. 2165da6c28aaSamw */ 2166da6c28aaSamw snode = unnamed_node; 2167da6c28aaSamw } 2168da6c28aaSamw 2169da6c28aaSamw dacl = fs_sd->sd_zdacl; 2170da6c28aaSamw sacl = fs_sd->sd_zsacl; 2171da6c28aaSamw 2172da6c28aaSamw ASSERT(dacl || sacl); 2173da6c28aaSamw if ((dacl == NULL) && (sacl == NULL)) 2174da6c28aaSamw return (EINVAL); 2175da6c28aaSamw 2176da6c28aaSamw if (dacl && sacl) 217755bf511dSas acl = smb_fsacl_merge(dacl, sacl); 2178da6c28aaSamw else if (dacl) 2179da6c28aaSamw acl = dacl; 2180da6c28aaSamw else 2181da6c28aaSamw acl = sacl; 2182da6c28aaSamw 2183da6c28aaSamw error = acl_translate(acl, target_flavor, (snode->vp->v_type == VDIR), 2184da6c28aaSamw fs_sd->sd_uid, fs_sd->sd_gid); 2185da6c28aaSamw if (error == 0) { 2186c8ec8eeaSjose borrego if (smb_tree_has_feature(sr->tid_tree, 2187c8ec8eeaSjose borrego SMB_TREE_ACEMASKONACCESS)) 2188da6c28aaSamw flags = ATTR_NOACLCHECK; 2189da6c28aaSamw 2190dc20a302Sas error = smb_vop_acl_write(snode->vp, acl, flags, cr); 2191da6c28aaSamw } 2192da6c28aaSamw 2193da6c28aaSamw if (dacl && sacl) 2194da6c28aaSamw acl_free(acl); 2195da6c28aaSamw 2196da6c28aaSamw return (error); 2197da6c28aaSamw } 2198da6c28aaSamw 2199da6c28aaSamw acl_type_t 2200da6c28aaSamw smb_fsop_acltype(smb_node_t *snode) 2201da6c28aaSamw { 2202da6c28aaSamw return (smb_vop_acl_type(snode->vp)); 2203da6c28aaSamw } 2204da6c28aaSamw 2205da6c28aaSamw /* 2206da6c28aaSamw * smb_fsop_sdread 2207da6c28aaSamw * 2208da6c28aaSamw * Read the requested security descriptor items from filesystem. 2209da6c28aaSamw * The items are specified in fs_sd->sd_secinfo. 2210da6c28aaSamw */ 2211da6c28aaSamw int 2212da6c28aaSamw smb_fsop_sdread(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 2213da6c28aaSamw smb_fssd_t *fs_sd) 2214da6c28aaSamw { 2215da6c28aaSamw int error = 0; 2216da6c28aaSamw int getowner = 0; 2217da6c28aaSamw cred_t *ga_cred; 2218da6c28aaSamw smb_attr_t attr; 2219da6c28aaSamw 2220da6c28aaSamw ASSERT(cr); 2221da6c28aaSamw ASSERT(fs_sd); 2222da6c28aaSamw 2223da6c28aaSamw /* 2224da6c28aaSamw * File's uid/gid is fetched in two cases: 2225da6c28aaSamw * 2226da6c28aaSamw * 1. it's explicitly requested 2227da6c28aaSamw * 2228da6c28aaSamw * 2. target ACL is ACE_T (ZFS ACL). They're needed for 2229da6c28aaSamw * owner@/group@ entries. In this case kcred should be used 2230da6c28aaSamw * because uid/gid are fetched on behalf of smb server. 2231da6c28aaSamw */ 2232da6c28aaSamw if (fs_sd->sd_secinfo & (SMB_OWNER_SECINFO | SMB_GROUP_SECINFO)) { 2233da6c28aaSamw getowner = 1; 2234da6c28aaSamw ga_cred = cr; 2235da6c28aaSamw } else if (sr->tid_tree->t_acltype == ACE_T) { 2236da6c28aaSamw getowner = 1; 2237da6c28aaSamw ga_cred = kcred; 2238da6c28aaSamw } 2239da6c28aaSamw 2240da6c28aaSamw if (getowner) { 2241da6c28aaSamw /* 2242da6c28aaSamw * Windows require READ_CONTROL to read owner/group SID since 2243da6c28aaSamw * they're part of Security Descriptor. 2244da6c28aaSamw * ZFS only requires read_attribute. Need to have a explicit 2245da6c28aaSamw * access check here. 2246da6c28aaSamw */ 2247da6c28aaSamw if (sr->fid_ofile == NULL) { 2248da6c28aaSamw error = smb_fsop_access(sr, ga_cred, snode, 2249da6c28aaSamw READ_CONTROL); 2250da6c28aaSamw if (error) 2251da6c28aaSamw return (error); 2252da6c28aaSamw } 2253da6c28aaSamw 2254da6c28aaSamw attr.sa_mask = SMB_AT_UID | SMB_AT_GID; 2255da6c28aaSamw error = smb_fsop_getattr(sr, ga_cred, snode, &attr); 2256da6c28aaSamw if (error == 0) { 2257da6c28aaSamw fs_sd->sd_uid = attr.sa_vattr.va_uid; 2258da6c28aaSamw fs_sd->sd_gid = attr.sa_vattr.va_gid; 2259da6c28aaSamw } else { 2260da6c28aaSamw return (error); 2261da6c28aaSamw } 2262da6c28aaSamw } 2263da6c28aaSamw 2264da6c28aaSamw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 2265da6c28aaSamw error = smb_fsop_aclread(sr, cr, snode, fs_sd); 2266da6c28aaSamw } 2267da6c28aaSamw 2268da6c28aaSamw return (error); 2269da6c28aaSamw } 2270da6c28aaSamw 2271da6c28aaSamw /* 2272da6c28aaSamw * smb_fsop_sdmerge 2273da6c28aaSamw * 2274da6c28aaSamw * From SMB point of view DACL and SACL are two separate list 2275da6c28aaSamw * which can be manipulated independently without one affecting 2276da6c28aaSamw * the other, but entries for both DACL and SACL will end up 2277da6c28aaSamw * in the same ACL if target filesystem supports ACE_T ACLs. 2278da6c28aaSamw * 2279da6c28aaSamw * So, if either DACL or SACL is present in the client set request 2280da6c28aaSamw * the entries corresponding to the non-present ACL shouldn't 2281da6c28aaSamw * be touched in the FS ACL. 2282da6c28aaSamw * 2283da6c28aaSamw * fs_sd parameter contains DACL and SACL specified by SMB 2284da6c28aaSamw * client to be set on a file/directory. The client could 2285da6c28aaSamw * specify both or one of these ACLs (if none is specified 2286da6c28aaSamw * we don't get this far). When both DACL and SACL are given 2287da6c28aaSamw * by client the existing ACL should be overwritten. If only 2288da6c28aaSamw * one of them is specified the entries corresponding to the other 2289da6c28aaSamw * ACL should not be touched. For example, if only DACL 2290da6c28aaSamw * is specified in input fs_sd, the function reads audit entries 2291da6c28aaSamw * of the existing ACL of the file and point fs_sd->sd_zsdacl 2292da6c28aaSamw * pointer to the fetched SACL, this way when smb_fsop_sdwrite() 2293da6c28aaSamw * function is called the passed fs_sd would point to the specified 2294da6c28aaSamw * DACL by client and fetched SACL from filesystem, so the file 2295da6c28aaSamw * will end up with correct ACL. 2296da6c28aaSamw */ 2297da6c28aaSamw static int 2298da6c28aaSamw smb_fsop_sdmerge(smb_request_t *sr, smb_node_t *snode, smb_fssd_t *fs_sd) 2299da6c28aaSamw { 2300da6c28aaSamw smb_fssd_t cur_sd; 2301da6c28aaSamw int error = 0; 2302da6c28aaSamw 2303da6c28aaSamw if (sr->tid_tree->t_acltype != ACE_T) 2304da6c28aaSamw /* Don't bother if target FS doesn't support ACE_T */ 2305da6c28aaSamw return (0); 2306da6c28aaSamw 2307da6c28aaSamw if ((fs_sd->sd_secinfo & SMB_ACL_SECINFO) != SMB_ACL_SECINFO) { 2308da6c28aaSamw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) { 2309da6c28aaSamw /* 2310da6c28aaSamw * Don't overwrite existing audit entries 2311da6c28aaSamw */ 231255bf511dSas smb_fssd_init(&cur_sd, SMB_SACL_SECINFO, 2313da6c28aaSamw fs_sd->sd_flags); 2314da6c28aaSamw 2315da6c28aaSamw error = smb_fsop_sdread(sr, kcred, snode, &cur_sd); 2316da6c28aaSamw if (error == 0) { 2317da6c28aaSamw ASSERT(fs_sd->sd_zsacl == NULL); 2318da6c28aaSamw fs_sd->sd_zsacl = cur_sd.sd_zsacl; 2319da6c28aaSamw if (fs_sd->sd_zsacl && fs_sd->sd_zdacl) 2320da6c28aaSamw fs_sd->sd_zsacl->acl_flags = 2321da6c28aaSamw fs_sd->sd_zdacl->acl_flags; 2322da6c28aaSamw } 2323da6c28aaSamw } else { 2324da6c28aaSamw /* 2325da6c28aaSamw * Don't overwrite existing access entries 2326da6c28aaSamw */ 232755bf511dSas smb_fssd_init(&cur_sd, SMB_DACL_SECINFO, 2328da6c28aaSamw fs_sd->sd_flags); 2329da6c28aaSamw 2330da6c28aaSamw error = smb_fsop_sdread(sr, kcred, snode, &cur_sd); 2331da6c28aaSamw if (error == 0) { 2332da6c28aaSamw ASSERT(fs_sd->sd_zdacl == NULL); 2333da6c28aaSamw fs_sd->sd_zdacl = cur_sd.sd_zdacl; 2334da6c28aaSamw if (fs_sd->sd_zdacl && fs_sd->sd_zsacl) 2335da6c28aaSamw fs_sd->sd_zdacl->acl_flags = 2336da6c28aaSamw fs_sd->sd_zsacl->acl_flags; 2337da6c28aaSamw } 2338da6c28aaSamw } 2339da6c28aaSamw 2340da6c28aaSamw if (error) 234155bf511dSas smb_fssd_term(&cur_sd); 2342da6c28aaSamw } 2343da6c28aaSamw 2344da6c28aaSamw return (error); 2345da6c28aaSamw } 2346da6c28aaSamw 2347da6c28aaSamw /* 2348da6c28aaSamw * smb_fsop_sdwrite 2349da6c28aaSamw * 2350da6c28aaSamw * Stores the given uid, gid and acl in filesystem. 2351da6c28aaSamw * Provided items in fs_sd are specified by fs_sd->sd_secinfo. 2352da6c28aaSamw * 2353da6c28aaSamw * A SMB security descriptor could contain owner, primary group, 2354da6c28aaSamw * DACL and SACL. Setting an SD should be atomic but here it has to 2355da6c28aaSamw * be done via two separate FS operations: VOP_SETATTR and 2356da6c28aaSamw * VOP_SETSECATTR. Therefore, this function has to simulate the 2357da6c28aaSamw * atomicity as well as it can. 2358*2c1b14e5Sjose borrego * 2359*2c1b14e5Sjose borrego * Get the current uid, gid before setting the new uid/gid 2360*2c1b14e5Sjose borrego * so if smb_fsop_aclwrite fails they can be restored. root cred is 2361*2c1b14e5Sjose borrego * used to get currend uid/gid since this operation is performed on 2362*2c1b14e5Sjose borrego * behalf of the server not the user. 2363*2c1b14e5Sjose borrego * 2364*2c1b14e5Sjose borrego * If setting uid/gid fails with EPERM it means that and invalid 2365*2c1b14e5Sjose borrego * owner has been specified. Callers should translate this to 2366*2c1b14e5Sjose borrego * STATUS_INVALID_OWNER which is not the normal mapping for EPERM 2367*2c1b14e5Sjose borrego * in upper layers, so EPERM is mapped to EBADE. 2368da6c28aaSamw */ 2369da6c28aaSamw int 2370da6c28aaSamw smb_fsop_sdwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 2371da6c28aaSamw smb_fssd_t *fs_sd, int overwrite) 2372da6c28aaSamw { 2373da6c28aaSamw int error = 0; 2374da6c28aaSamw int access = 0; 2375da6c28aaSamw smb_attr_t set_attr; 2376da6c28aaSamw smb_attr_t orig_attr; 2377da6c28aaSamw 2378da6c28aaSamw ASSERT(cr); 2379da6c28aaSamw ASSERT(fs_sd); 2380da6c28aaSamw 2381da6c28aaSamw ASSERT(sr); 2382da6c28aaSamw ASSERT(sr->tid_tree); 2383c8ec8eeaSjose borrego if (SMB_TREE_IS_READONLY(sr)) 2384da6c28aaSamw return (EROFS); 2385da6c28aaSamw 2386da6c28aaSamw bzero(&set_attr, sizeof (smb_attr_t)); 2387da6c28aaSamw 2388da6c28aaSamw if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 2389da6c28aaSamw set_attr.sa_vattr.va_uid = fs_sd->sd_uid; 2390da6c28aaSamw set_attr.sa_mask |= SMB_AT_UID; 2391*2c1b14e5Sjose borrego access |= WRITE_OWNER; 2392da6c28aaSamw } 2393da6c28aaSamw 2394da6c28aaSamw if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 2395da6c28aaSamw set_attr.sa_vattr.va_gid = fs_sd->sd_gid; 2396da6c28aaSamw set_attr.sa_mask |= SMB_AT_GID; 2397*2c1b14e5Sjose borrego access |= WRITE_OWNER; 2398da6c28aaSamw } 2399da6c28aaSamw 2400da6c28aaSamw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 2401da6c28aaSamw access |= WRITE_DAC; 2402da6c28aaSamw 2403da6c28aaSamw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 2404da6c28aaSamw access |= ACCESS_SYSTEM_SECURITY; 2405da6c28aaSamw 2406da6c28aaSamw if (sr->fid_ofile) 2407da6c28aaSamw error = smb_ofile_access(sr->fid_ofile, cr, access); 2408da6c28aaSamw else 2409da6c28aaSamw error = smb_fsop_access(sr, cr, snode, access); 2410da6c28aaSamw 2411da6c28aaSamw if (error) 2412da6c28aaSamw return (EACCES); 2413da6c28aaSamw 2414da6c28aaSamw if (set_attr.sa_mask) { 2415da6c28aaSamw orig_attr.sa_mask = SMB_AT_UID | SMB_AT_GID; 2416da6c28aaSamw error = smb_fsop_getattr(sr, kcred, snode, &orig_attr); 2417*2c1b14e5Sjose borrego if (error == 0) { 2418da6c28aaSamw error = smb_fsop_setattr(sr, cr, snode, &set_attr, 2419da6c28aaSamw NULL); 2420*2c1b14e5Sjose borrego if (error == EPERM) 2421*2c1b14e5Sjose borrego error = EBADE; 2422*2c1b14e5Sjose borrego } 2423da6c28aaSamw 2424da6c28aaSamw if (error) 2425da6c28aaSamw return (error); 2426da6c28aaSamw } 2427da6c28aaSamw 2428da6c28aaSamw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 2429da6c28aaSamw if (overwrite == 0) { 2430da6c28aaSamw error = smb_fsop_sdmerge(sr, snode, fs_sd); 2431da6c28aaSamw if (error) 2432da6c28aaSamw return (error); 2433da6c28aaSamw } 2434da6c28aaSamw 2435da6c28aaSamw error = smb_fsop_aclwrite(sr, cr, snode, fs_sd); 2436da6c28aaSamw if (error) { 2437da6c28aaSamw /* 2438da6c28aaSamw * Revert uid/gid changes if required. 2439da6c28aaSamw */ 2440da6c28aaSamw if (set_attr.sa_mask) { 2441da6c28aaSamw orig_attr.sa_mask = set_attr.sa_mask; 2442da6c28aaSamw (void) smb_fsop_setattr(sr, kcred, snode, 2443da6c28aaSamw &orig_attr, NULL); 2444da6c28aaSamw } 2445da6c28aaSamw } 2446da6c28aaSamw } 2447da6c28aaSamw 2448da6c28aaSamw return (error); 2449da6c28aaSamw } 2450da6c28aaSamw 2451da6c28aaSamw /* 2452da6c28aaSamw * smb_fsop_sdinherit 2453da6c28aaSamw * 2454da6c28aaSamw * Inherit the security descriptor from the parent container. 2455da6c28aaSamw * This function is called after FS has created the file/folder 2456da6c28aaSamw * so if this doesn't do anything it means FS inheritance is 2457da6c28aaSamw * in place. 2458da6c28aaSamw * 2459da6c28aaSamw * Do inheritance for ZFS internally. 2460da6c28aaSamw * 2461da6c28aaSamw * If we want to let ZFS does the inheritance the 2462da6c28aaSamw * following setting should be true: 2463da6c28aaSamw * 2464da6c28aaSamw * - aclinherit = passthrough 2465da6c28aaSamw * - aclmode = passthrough 2466da6c28aaSamw * - smbd umask = 0777 2467da6c28aaSamw * 2468da6c28aaSamw * This will result in right effective permissions but 2469da6c28aaSamw * ZFS will always add 6 ACEs for owner, owning group 2470da6c28aaSamw * and others to be POSIX compliant. This is not what 2471da6c28aaSamw * Windows clients/users expect, so we decided that CIFS 2472da6c28aaSamw * implements Windows rules and overwrite whatever ZFS 2473da6c28aaSamw * comes up with. This way we also don't have to care 2474da6c28aaSamw * about ZFS aclinherit and aclmode settings. 2475da6c28aaSamw */ 2476da6c28aaSamw static int 2477da6c28aaSamw smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, smb_fssd_t *fs_sd) 2478da6c28aaSamw { 2479da6c28aaSamw int is_dir; 248055bf511dSas acl_t *dacl = NULL; 248155bf511dSas acl_t *sacl = NULL; 2482da6c28aaSamw ksid_t *owner_sid; 2483da6c28aaSamw int error; 2484da6c28aaSamw 2485da6c28aaSamw ASSERT(fs_sd); 2486da6c28aaSamw 2487da6c28aaSamw if (sr->tid_tree->t_acltype != ACE_T) { 2488da6c28aaSamw /* 2489da6c28aaSamw * No forced inheritance for non-ZFS filesystems. 2490da6c28aaSamw */ 2491da6c28aaSamw fs_sd->sd_secinfo = 0; 2492da6c28aaSamw return (0); 2493da6c28aaSamw } 2494da6c28aaSamw 2495da6c28aaSamw 2496da6c28aaSamw /* Fetch parent directory's ACL */ 2497da6c28aaSamw error = smb_fsop_sdread(sr, kcred, dnode, fs_sd); 2498da6c28aaSamw if (error) { 2499da6c28aaSamw return (error); 2500da6c28aaSamw } 2501da6c28aaSamw 2502da6c28aaSamw is_dir = (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR); 2503da6c28aaSamw owner_sid = crgetsid(sr->user_cr, KSID_OWNER); 2504da6c28aaSamw ASSERT(owner_sid); 250555bf511dSas dacl = smb_fsacl_inherit(fs_sd->sd_zdacl, is_dir, SMB_DACL_SECINFO, 2506da6c28aaSamw owner_sid->ks_id); 250755bf511dSas sacl = smb_fsacl_inherit(fs_sd->sd_zsacl, is_dir, SMB_SACL_SECINFO, 2508da6c28aaSamw (uid_t)-1); 2509da6c28aaSamw 251055bf511dSas if (sacl == NULL) 251155bf511dSas fs_sd->sd_secinfo &= ~SMB_SACL_SECINFO; 251255bf511dSas 251355bf511dSas smb_fsacl_free(fs_sd->sd_zdacl); 251455bf511dSas smb_fsacl_free(fs_sd->sd_zsacl); 2515da6c28aaSamw 2516da6c28aaSamw fs_sd->sd_zdacl = dacl; 2517da6c28aaSamw fs_sd->sd_zsacl = sacl; 2518da6c28aaSamw 2519da6c28aaSamw return (0); 2520da6c28aaSamw } 2521da6c28aaSamw 2522da6c28aaSamw /* 2523da6c28aaSamw * smb_fsop_eaccess 2524da6c28aaSamw * 2525da6c28aaSamw * Returns the effective permission of the given credential for the 2526da6c28aaSamw * specified object. 2527da6c28aaSamw * 2528da6c28aaSamw * This is just a workaround. We need VFS/FS support for this. 2529da6c28aaSamw */ 2530da6c28aaSamw void 2531da6c28aaSamw smb_fsop_eaccess(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 2532da6c28aaSamw uint32_t *eaccess) 2533da6c28aaSamw { 2534da6c28aaSamw int access = 0; 2535da6c28aaSamw vnode_t *dir_vp; 2536da6c28aaSamw smb_node_t *unnamed_node; 2537da6c28aaSamw 2538da6c28aaSamw ASSERT(cr); 2539da6c28aaSamw ASSERT(snode); 2540da6c28aaSamw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 2541da6c28aaSamw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 2542da6c28aaSamw 2543da6c28aaSamw unnamed_node = SMB_IS_STREAM(snode); 2544da6c28aaSamw if (unnamed_node) { 2545da6c28aaSamw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 2546da6c28aaSamw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 2547da6c28aaSamw /* 2548da6c28aaSamw * Streams authorization should be performed against the 2549da6c28aaSamw * unnamed stream. 2550da6c28aaSamw */ 2551da6c28aaSamw snode = unnamed_node; 2552da6c28aaSamw } 2553da6c28aaSamw 2554c8ec8eeaSjose borrego if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) { 2555da6c28aaSamw dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL; 2556da6c28aaSamw smb_vop_eaccess(snode->vp, (int *)eaccess, V_ACE_MASK, dir_vp, 2557da6c28aaSamw cr); 2558da6c28aaSamw return; 2559da6c28aaSamw } 2560da6c28aaSamw 2561da6c28aaSamw /* 2562da6c28aaSamw * FS doesn't understand 32-bit mask 2563da6c28aaSamw */ 2564da6c28aaSamw smb_vop_eaccess(snode->vp, &access, 0, NULL, cr); 2565da6c28aaSamw 2566da6c28aaSamw *eaccess = READ_CONTROL | FILE_READ_EA | FILE_READ_ATTRIBUTES; 2567da6c28aaSamw 2568da6c28aaSamw if (access & VREAD) 2569da6c28aaSamw *eaccess |= FILE_READ_DATA; 2570da6c28aaSamw 2571da6c28aaSamw if (access & VEXEC) 2572da6c28aaSamw *eaccess |= FILE_EXECUTE; 2573da6c28aaSamw 2574da6c28aaSamw if (access & VWRITE) 2575da6c28aaSamw *eaccess |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | 2576da6c28aaSamw FILE_WRITE_EA | FILE_APPEND_DATA | FILE_DELETE_CHILD; 2577da6c28aaSamw } 257855bf511dSas 2579dc20a302Sas /* 2580dc20a302Sas * smb_fsop_shrlock 2581dc20a302Sas * 2582dc20a302Sas * For the current open request, check file sharing rules 2583dc20a302Sas * against existing opens. 2584dc20a302Sas * 2585dc20a302Sas * Returns NT_STATUS_SHARING_VIOLATION if there is any 2586dc20a302Sas * sharing conflict. Returns NT_STATUS_SUCCESS otherwise. 2587dc20a302Sas * 2588dc20a302Sas * Full system-wide share reservation synchronization is available 2589dc20a302Sas * when the nbmand (non-blocking mandatory) mount option is set 2590dc20a302Sas * (i.e. nbl_need_crit() is true) and nbmand critical regions are used. 2591dc20a302Sas * This provides synchronization with NFS and local processes. The 2592dc20a302Sas * critical regions are entered in VOP_SHRLOCK()/fs_shrlock() (called 2593dc20a302Sas * from smb_open_subr()/smb_fsop_shrlock()/smb_vop_shrlock()) as well 2594dc20a302Sas * as the CIFS rename and delete paths. 2595dc20a302Sas * 2596dc20a302Sas * The CIFS server will also enter the nbl critical region in the open, 2597dc20a302Sas * rename, and delete paths when nbmand is not set. There is limited 2598dc20a302Sas * coordination with local and VFS share reservations in this case. 2599dc20a302Sas * Note that when the nbmand mount option is not set, the VFS layer 2600dc20a302Sas * only processes advisory reservations and the delete mode is not checked. 2601dc20a302Sas * 2602dc20a302Sas * Whether or not the nbmand mount option is set, intra-CIFS share 2603dc20a302Sas * checking is done in the open, delete, and rename paths using a CIFS 2604dc20a302Sas * critical region (node->n_share_lock). 2605dc20a302Sas */ 2606dc20a302Sas 2607dc20a302Sas uint32_t 2608faa1795aSjb smb_fsop_shrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid, 2609dc20a302Sas uint32_t desired_access, uint32_t share_access) 2610dc20a302Sas { 2611dc20a302Sas int rc; 2612dc20a302Sas 2613dc20a302Sas if (node->attr.sa_vattr.va_type == VDIR) 2614dc20a302Sas return (NT_STATUS_SUCCESS); 2615dc20a302Sas 2616dc20a302Sas /* Allow access if the request is just for meta data */ 2617dc20a302Sas if ((desired_access & FILE_DATA_ALL) == 0) 2618dc20a302Sas return (NT_STATUS_SUCCESS); 2619dc20a302Sas 2620dc20a302Sas rc = smb_node_open_check(node, cr, desired_access, share_access); 2621dc20a302Sas if (rc) 2622dc20a302Sas return (NT_STATUS_SHARING_VIOLATION); 2623dc20a302Sas 2624dc20a302Sas rc = smb_vop_shrlock(node->vp, uniq_fid, desired_access, share_access, 2625dc20a302Sas cr); 2626dc20a302Sas if (rc) 2627dc20a302Sas return (NT_STATUS_SHARING_VIOLATION); 2628dc20a302Sas 2629dc20a302Sas return (NT_STATUS_SUCCESS); 2630dc20a302Sas } 2631dc20a302Sas 263255bf511dSas void 2633dc20a302Sas smb_fsop_unshrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid) 2634dc20a302Sas { 2635dc20a302Sas if (node->attr.sa_vattr.va_type == VDIR) 2636dc20a302Sas return; 2637dc20a302Sas 2638dc20a302Sas (void) smb_vop_unshrlock(node->vp, uniq_fid, cr); 2639dc20a302Sas } 26408c10a865Sas 26418c10a865Sas int 26428c10a865Sas smb_fsop_frlock(smb_node_t *node, smb_lock_t *lock, boolean_t unlock, 26438c10a865Sas cred_t *cr) 26448c10a865Sas { 26458c10a865Sas flock64_t bf; 26468c10a865Sas int flag = F_REMOTELOCK; 26478c10a865Sas 26483ad684d6Sjb /* 26493ad684d6Sjb * VOP_FRLOCK() will not be called if: 26503ad684d6Sjb * 26513ad684d6Sjb * 1) The lock has a range of zero bytes. The semantics of Windows and 26523ad684d6Sjb * POSIX are different. In the case of POSIX it asks for the locking 26533ad684d6Sjb * of all the bytes from the offset provided until the end of the 26543ad684d6Sjb * file. In the case of Windows a range of zero locks nothing and 26553ad684d6Sjb * doesn't conflict with any other lock. 26563ad684d6Sjb * 26573ad684d6Sjb * 2) The lock rolls over (start + lenght < start). Solaris will assert 26583ad684d6Sjb * if such a request is submitted. This will not create 26593ad684d6Sjb * incompatibilities between POSIX and Windows. In the Windows world, 26603ad684d6Sjb * if a client submits such a lock, the server will not lock any 26613ad684d6Sjb * bytes. Interestingly if the same lock (same offset and length) is 26623ad684d6Sjb * resubmitted Windows will consider that there is an overlap and 26633ad684d6Sjb * the granting rules will then apply. 26643ad684d6Sjb */ 26653ad684d6Sjb if ((lock->l_length == 0) || 26663ad684d6Sjb ((lock->l_start + lock->l_length - 1) < lock->l_start)) 26673ad684d6Sjb return (0); 26683ad684d6Sjb 26698c10a865Sas bzero(&bf, sizeof (bf)); 26708c10a865Sas 26718c10a865Sas if (unlock) { 26728c10a865Sas bf.l_type = F_UNLCK; 26738c10a865Sas } else if (lock->l_type == SMB_LOCK_TYPE_READONLY) { 26748c10a865Sas bf.l_type = F_RDLCK; 26758c10a865Sas flag |= FREAD; 26768c10a865Sas } else if (lock->l_type == SMB_LOCK_TYPE_READWRITE) { 26778c10a865Sas bf.l_type = F_WRLCK; 26788c10a865Sas flag |= FWRITE; 26798c10a865Sas } 26808c10a865Sas 26818c10a865Sas bf.l_start = lock->l_start; 26828c10a865Sas bf.l_len = lock->l_length; 2683c8ec8eeaSjose borrego bf.l_pid = lock->l_file->f_uniqid; 26848c10a865Sas bf.l_sysid = smb_ct.cc_sysid; 26858c10a865Sas 26868c10a865Sas return (smb_vop_frlock(node->vp, cr, flag, &bf)); 26878c10a865Sas } 2688