smb_fsops.c revision eb1d736b1c19f6abeee90c921a9320b67fedd016
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * CDDL HEADER START
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * The contents of this file are subject to the terms of the
9f49ae270d37efd5c5270cb8046b4229b5380021mlf * Common Development and Distribution License (the "License").
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * You may not use this file except in compliance with the License.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * See the License for the specific language governing permissions
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * and limitations under the License.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * When distributing Covered Code, include this CDDL HEADER in each
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * If applicable, add the following below this CDDL HEADER, with the
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * fields enclosed by brackets "[]" replaced with your own identifying
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * information: Portions Copyright [yyyy] [name of copyright owner]
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * CDDL HEADER END
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
8793b36b40d14ad0a0fecc97738dc118a928f46cNick Todd * Use is subject to license terms.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstatic int smb_fsop_create_stream(smb_request_t *, cred_t *, smb_node_t *,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf char *, char *, int, smb_attr_t *, smb_node_t **, smb_attr_t *);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstatic int smb_fsop_create_file(smb_request_t *, cred_t *, smb_node_t *,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf char *, int, smb_attr_t *, smb_node_t **, smb_attr_t *);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstatic int smb_fsop_create_with_sd(smb_request_t *, cred_t *, smb_node_t *,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf char *, smb_attr_t *, smb_node_t **, smb_attr_t *, smb_fssd_t *);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstatic int smb_fsop_sdinherit(smb_request_t *, smb_node_t *, smb_fssd_t *);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * The smb_fsop_* functions have knowledge of CIFS semantics.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * The smb_vop_* functions have minimal knowledge of CIFS semantics and
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * serve as an interface to the VFS layer.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Hence, smb_request_t and smb_node_t structures should not be passed
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * from the smb_fsop_* layer to the smb_vop_* layer.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * In general, CIFS service code should only ever call smb_fsop_*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * functions directly, and never smb_vop_* functions directly.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * smb_fsop_* functions should call smb_vop_* functions where possible, instead
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * of their smb_fsop_* counterparts. However, there are times when
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * this cannot be avoided.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Note: Stream names cannot be mangled.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * smb_fsop_amask_to_omode
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Convert the access mask to the open mode (for use
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * with the VOP_OPEN call).
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Note that opening a file for attribute only access
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * will also translate into an FREAD or FWRITE open mode
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * (i.e., it's not just for data).
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * This is needed so that opens are tracked appropriately
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * for oplock processing.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Assuming that the same vnode is returned as we had before.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * (I.e., with certain types of files or file systems, a
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * different vnode might be returned by VOP_OPEN)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return (0);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf smb_attr_t *attr, smb_node_t **ret_snode, smb_attr_t *ret_attr,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACLONCREATE)) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf } else if (dacl) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* The tree ACEs may prevent a create */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Ideally we should be able to specify the owner and owning
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * group at create time along with the ACL. Since we cannot
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * do that right now, kcred is passed to smb_vop_setattr so it
9f49ae270d37efd5c5270cb8046b4229b5380021mlf * doesn't fail due to lack of permission.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (rc == 0) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * For filesystems that don't support ACL-on-create, try
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * to set the specified SD after create, which could actually
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * fail because of conflicts between inherited security
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * attributes upon creation and the specified SD.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Passing kcred to smb_fsop_sdwrite() to overcome this issue.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (rc != 0) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * smb_fsop_create
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * All SMB functions should use this wrapper to ensure that
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * all the smb_vop_creates are performed with the appropriate credentials.
9f49ae270d37efd5c5270cb8046b4229b5380021mlf * Please document any direct calls to explain the reason for avoiding
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * this wrapper.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * *ret_snode is returned with a reference upon success. No reference is
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * taken if an error is returned.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf smb_attr_t *attr, smb_node_t **ret_snode, smb_attr_t *ret_attr)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (*name == 0)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* Not a named stream */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * smb_fsop_create_stream
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Create NTFS named stream file (sname) on unnamed stream
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * file (fname), creating the unnamed stream file if it
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * doesn't exist.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * If we created the unnamed stream file and then creation
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * of the named stream file fails, we delete the unnamed stream.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Since we use the real file name for the smb_vop_remove we
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * clear the SMB_IGNORE_CASE flag to ensure a case sensitive
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * The second parameter of smb_vop_setattr() is set to
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * NULL, even though an unnamed stream exists. This is
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * because we want to set the UID and GID on the named
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * stream in this case for consistency with the (unnamed
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * stream) file (see comments for smb_vop_setattr()).
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf smb_attr_t *attr, smb_node_t **ret_snode, smb_attr_t *ret_attr)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* Look up / create the unnamed stream, fname */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* create the named stream, sname */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (rc != 0) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (rc != 0) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdvp,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * smb_fsop_create_file
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf smb_attr_t *attr, smb_node_t **ret_snode, smb_attr_t *ret_attr)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * SD sent by client in Windows format. Needs to be
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * converted to FS format. No inheritance.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * No incoming SD and filesystem is ZFS
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Server applies Windows inheritance rules,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * see smb_fsop_sdinherit() comments as to why.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (rc == 0) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * No incoming SD and filesystem is not ZFS
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * let the filesystem handles the inheritance.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (rc == 0) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * smb_fsop_mkdir
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * All SMB functions should use this wrapper to ensure that
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * the the calls are performed with the appropriate credentials.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Please document any direct call to explain the reason
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * for avoiding this wrapper.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * It is assumed that a reference exists on snode coming into this routine.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * *ret_snode is returned with a reference upon success. No reference is
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * taken if an error is returned.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (*name == 0)
9f49ae270d37efd5c5270cb8046b4229b5380021mlf rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * If the name passed in by the client has an unmangled
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * equivalent that is found in the specified directory,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * then the mkdir cannot succeed. Return EEXIST.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Only if ENOENT is returned will a mkdir be attempted.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * SD sent by client in Windows format. Needs to be
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * converted to FS format. No inheritance.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * No incoming SD and filesystem is ZFS
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Server applies Windows inheritance rules,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * see smb_fsop_sdinherit() comments as to why.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, SMB_FSSD_FLAGS_DIR);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (rc == 0) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf rc = smb_vop_mkdir(dnode->vp, name, attr, &vp, flags, cr,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (rc == 0) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * smb_fsop_remove
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * All SMB functions should use this wrapper to ensure that
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * the the calls are performed with the appropriate credentials.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Please document any direct call to explain the reason
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * for avoiding this wrapper.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * It is assumed that a reference exists on snode coming into this routine.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * A null smb_request might be passed to this function.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * The state of the node could be SMB_NODE_STATE_DESTROYING if this
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * function is called during the deletion of the node (because of
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * DELETE_ON_CLOSE).
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Look up the unnamed stream (i.e. fname).
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Unmangle processing will be done on fname
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * as well as any link target.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (rc != 0) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Need to find out what permission is required by NTFS
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * to remove a stream.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf rc = smb_vop_stream_remove(fnode->vp, sname, flags, cr);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (rc == 0) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * longname is the real (case-sensitive)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * on-disk name.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * We make sure we do a remove on this exact
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * name, as the name was mangled and denotes
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * a unique file.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * smb_fsop_remove_streams
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * This function removes a file's streams without removing the
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * file itself.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * It is assumed that fnode is not a link.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfsmb_fsop_remove_streams(smb_request_t *sr, cred_t *cr, smb_node_t *fnode)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return (-1);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return (-1);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return (-1);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if ((od = smb_tree_lookup_odir(sr->tid_tree, odid)) == NULL) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return (-1);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf for (;;) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf (void) smb_vop_remove(od->d_dnode->vp, odirent->od_name,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * smb_fsop_rmdir
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * All SMB functions should use this wrapper to ensure that
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * the the calls are performed with the appropriate credentials.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Please document any direct call to explain the reason
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * for avoiding this wrapper.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * It is assumed that a reference exists on snode coming into this routine.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * The state of the node could be SMB_NODE_STATE_DESTROYING if this
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * function is called during the deletion of the node (because of
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * DELETE_ON_CLOSE).
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (rc == 0) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * longname is the real (case-sensitive)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * on-disk name.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * We make sure we do a rmdir on this exact
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * name, as the name was mangled and denotes
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * a unique directory.
return (rc);
int flags = 0;
int rc;
return (EACCES);
return (EACCES);
if (unnamed_node) {
if (rc == 0)
return (rc);
char *from_name,
char *to_name)
int rc;
return (EACCES);
return (EACCES);
return (EROFS);
if (rc != 0)
return (rc);
return (EACCES);
if (rc == 0) {
return (rc);
int rc = 0;
int flags = 0;
return (EACCES);
return (EROFS);
return (EACCES);
return (EACCES);
return (EACCES);
access = 0;
if (sa_mask)
return (EACCES);
if (unnamed_node) {
kcred);
if (rc == 0)
return (rc);
int svmand;
int rc;
return (EACCES);
return (EACCES);
if (unnamed_node) {
if (rc) {
return (rc);
if (rc) {
return (ERANGE);
kcred) == 0) {
return (rc);
int ioflag)
int svmand;
int rc;
return (EROFS);
return (EACCES);
return (EACCES);
if (unnamed_node) {
if (rc) {
return (rc);
if (rc) {
return (ERANGE);
kcred) == 0) {
return (rc);
int access = 0;
int error;
if (faccess == 0)
return (NT_STATUS_SUCCESS);
return (NT_STATUS_ACCESS_DENIED);
if (unnamed_node) {
if (error)
return (NT_STATUS_ACCESS_DENIED);
SMB_USER_PRIV_SECURITY)) == 0)
return (NT_STATUS_PRIVILEGE_NOT_HELD);
if (acl_check) {
cr);
int flags,
char *name,
char *od_name;
char *fname;
char *sname;
int rc;
if (rc != 0) {
return (rc);
if (rc != 0) {
return (rc);
return (ENOMEM);
if (rc == 0) {
return (rc);
int flags,
char *name,
char *longname;
char *od_name;
int rc;
int ret_flags;
return (EINVAL);
return (EACCES);
if (rc != 0) {
return (rc);
if (rc != 0) {
return (rc);
if (rc != 0) {
return (rc);
if (rc != 0) {
return (rc);
if (rc != 0) {
return (rc);
ret_attr);
if (rc) {
return (rc);
return (rc);
return (EROFS);
int error = 0;
int flags = 0;
int access = 0;
return (EACCES);
return (EACCES);
if (unnamed_node) {
if (error != 0) {
return (error);
if (error == 0) {
return (error);
int target_flavor;
int error = 0;
int flags = 0;
int access = 0;
return (EROFS);
return (EACCES);
return (EACCES);
case ACLENT_T:
case ACE_T:
return (EINVAL);
if (unnamed_node) {
return (EINVAL);
else if (dacl)
if (error == 0) {
return (error);
int error = 0;
int getowner = 0;
if (getowner) {
if (error)
return (error);
if (error == 0) {
return (error);
return (error);
int error = 0;
if (error == 0) {
if (error == 0) {
if (error)
return (error);
int error = 0;
int access = 0;
return (EROFS);
if (error)
return (EACCES);
if (error == 0) {
NULL);
if (error)
return (error);
if (overwrite == 0) {
if (error)
return (error);
if (error) {
return (error);
int is_dir;
int error;
if (error) {
return (error);
int access = 0;
if (unnamed_node) {
cr);
int rc;
return (NT_STATUS_SUCCESS);
return (NT_STATUS_SUCCESS);
if (rc)
return (NT_STATUS_SHARING_VIOLATION);
cr);
if (rc)
return (NT_STATUS_SHARING_VIOLATION);
return (NT_STATUS_SUCCESS);
if (unlock) {