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