smb_fsops.c revision 3ad684d66b78e06edd37e2c4fd3b3949f095194b
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <smbsrv/smb_fsops.h>
#include <smbsrv/smb_kproto.h>
#include <smbsrv/ntstatus.h>
#include <smbsrv/ntaccess.h>
#include <smbsrv/smb_incl.h>
#include <acl/acl_common.h>
extern caller_context_t smb_ct;
extern int smb_fem_oplock_install(smb_node_t *);
extern void smb_fem_oplock_uninstall(smb_node_t *);
extern int smb_vop_other_opens(vnode_t *, int);
smb_fssd_t *fs_sd);
/*
* The smb_fsop_* functions have knowledge of CIFS semantics.
*
* The smb_vop_* functions have minimal knowledge of CIFS semantics and
* serve as an interface to the VFS layer.
*
* Hence, smb_request_t and smb_node_t structures should not be passed
* from the smb_fsop_* layer to the smb_vop_* layer.
*
* In general, CIFS service code should only ever call smb_fsop_*
* functions directly, and never smb_vop_* functions directly.
*
* smb_fsop_* functions should call smb_vop_* functions where possible, instead
* of their smb_fsop_* counterparts. However, there are times when
* this cannot be avoided.
*/
/*
* Note: Stream names cannot be mangled.
*/
/*
* smb_fsop_amask_to_omode
*
* Convert the access mask to the open mode (for use
* with the VOP_OPEN call).
*
* Note that opening a file for attribute only access
* will also translate into an FREAD or FWRITE open mode
* (i.e., it's not just for data).
*
* This is needed so that opens are tracked appropriately
* for oplock processing.
*/
int
{
int mode = 0;
if (access & FILE_APPEND_DATA)
return (mode);
}
int
{
/*
* Assuming that the same vnode is returned as we had before.
* (I.e., with certain types of files or file systems, a
* different vnode might be returned by VOP_OPEN)
*/
}
int
{
}
int
{
int rc;
return (EMFILE);
return (rc);
(void) smb_fem_oplock_uninstall(node);
return (EMFILE);
}
return (0);
}
void
{
}
static int
char *name,
{
int aclbsize = 0; /* size of acl list in bytes */
int flags = 0;
int is_dir;
int rc;
if (SMB_TREE_CASE_INSENSITIVE(sr))
} else if (dacl) {
} else {
}
if (rc)
return (rc);
}
else
if (is_dir) {
} else {
}
if (rc != 0)
return (rc);
/*
* Ideally we should be able to specify the owner and owning
* group at create time along with the ACL. Since we cannot
* do that right now, kcred is passed to smb_vop_setattr so it
* doesn't fail due to lack of permission.
*/
}
}
}
} else {
/*
* For filesystems that don't support ACL-on-create, try
* to set the specified SD after create, which could actually
* fail because of conflicts between inherited security
* attributes upon creation and the specified SD.
*
* Passing kcred to smb_fsop_sdwrite() to overcome this issue.
*/
if (is_dir) {
} else {
}
if (rc != 0)
return (rc);
}
if (rc == 0) {
}
}
if (rc != 0) {
if (is_dir) {
} else {
}
}
return (rc);
}
/*
* smb_fsop_create
*
* All SMB functions should use this wrapper to ensure that
* all the smb_vop_creates are performed with the appropriate credentials.
* Please document any direct calls to explain the reason
* for avoiding this wrapper.
*
* It is assumed that a reference exists on snode coming into this routine.
*
* *ret_snode is returned with a reference upon success. No reference is
* taken if an error is returned.
*/
int
char *name,
{
char *namep;
char *fname;
char *sname;
int is_stream;
int flags = 0;
int rc = 0;
*ret_snode = 0;
if (*name == 0)
return (EINVAL);
return (EACCES);
if (SMB_TREE_IS_READ_ONLY(sr))
return (EROFS);
if (SMB_TREE_CASE_INSENSITIVE(sr))
if (is_stream)
else
if (smb_maybe_mangled_name(namep)) {
return (rc);
}
if (is_stream)
else
}
if (is_stream) {
/*
* Look up the unnamed stream.
*
* Mangle processing in smb_fsop_lookup() for the unnamed
* stream won't be needed (as it was done above), but
* it may be needed on any link target (which
* smb_fsop_lookup() will provide).
*/
0, 0);
if (longname) {
}
if (rc != 0) {
return (rc);
}
if (rc != 0) {
return (rc);
}
/*
* The second parameter of smb_vop_setattr() is set to
* NULL, even though an unnamed stream exists. This is
* because we want to set the UID and GID on the named
* stream in this case for consistency with the (unnamed
* stream) file (see comments for smb_vop_setattr()).
*/
if (rc != 0) {
return (rc);
}
return (ENOMEM);
}
} else {
/*
* SD sent by client in Windows format. Needs to be
* converted to FS format. No inheritance.
*/
if (status == NT_STATUS_SUCCESS) {
}
else
/*
* No incoming SD and filesystem is ZFS
* Server applies Windows inheritance rules,
* see smb_fsop_sdinherit() comments as to why.
*/
if (rc == 0) {
}
} else {
/*
* No incoming SD and filesystem is not ZFS
* let the filesystem handles the inheritance.
*/
if (rc == 0) {
}
}
}
}
return (rc);
}
/*
* smb_fsop_mkdir
*
* All SMB functions should use this wrapper to ensure that
* the the calls are performed with the appropriate credentials.
* Please document any direct call to explain the reason
* for avoiding this wrapper.
*
* It is assumed that a reference exists on snode coming into this routine.
*
* *ret_snode is returned with a reference upon success. No reference is
* taken if an error is returned.
*/
int
char *name,
{
char *longname;
int flags = 0;
int rc;
*ret_snode = 0;
if (*name == 0)
return (EINVAL);
return (EACCES);
if (SMB_TREE_IS_READ_ONLY(sr))
return (EROFS);
if (smb_maybe_mangled_name(name)) {
/*
* If the name passed in by the client has an unmangled
* equivalent that is found in the specified directory,
* then the mkdir cannot succeed. Return EEXIST.
*
* Only if ENOENT is returned will a mkdir be attempted.
*/
if (rc == 0)
return (rc);
}
if (SMB_TREE_CASE_INSENSITIVE(sr))
/*
* SD sent by client in Windows format. Needs to be
* converted to FS format. No inheritance.
*/
if (status == NT_STATUS_SUCCESS) {
}
else
/*
* No incoming SD and filesystem is ZFS
* Server applies Windows inheritance rules,
* see smb_fsop_sdinherit() comments as to why.
*/
if (rc == 0) {
}
} else {
NULL);
if (rc == 0) {
}
}
}
return (rc);
}
/*
* smb_fsop_remove
*
* All SMB functions should use this wrapper to ensure that
* the the calls are performed with the appropriate credentials.
* Please document any direct call to explain the reason
* for avoiding this wrapper.
*
* It is assumed that a reference exists on snode coming into this routine.
*
* od: This means that the name passed in is an on-disk name.
* A null smb_request might be passed to this function.
*/
int
char *name,
int od)
{
char *longname;
char *fname;
char *sname;
int flags = 0;
int rc;
/*
* The state of the node could be SMB_NODE_STATE_DESTROYING if this
* function is called during the deletion of the node (because of
* DELETE_ON_CLOSE).
*/
return (EACCES);
if (SMB_TREE_IS_READ_ONLY(sr))
return (EROFS);
/*
* If the passed-in name is an on-disk name,
* then we need to do a case-sensitive remove.
* This is important if the on-disk name
* corresponds to a mangled name passed in by
* the client. We want to make sure to remove
* the exact file specified by the client,
* instead of letting the underlying file system
* do a remove on the "first match."
*/
/*
* It is assumed that "name" corresponds to the path
* passed in by the client, and no need of suppressing
* case-insensitive lookups is needed.
*/
/*
* Look up the unnamed stream (i.e. fname).
* Unmangle processing will be done on fname
* as well as any link target.
*/
0, 0);
if (rc != 0) {
return (rc);
}
/*
* XXX
* Need to find out what permission is required by NTFS
* to remove a stream.
*/
} else {
if (smb_maybe_mangled_name(name) == 0) {
return (rc);
}
if (rc == 0) {
/*
* We passed "1" as the "od" parameter
* to smb_unmangle_name(), such that longname
* is the real (case-sensitive) on-disk name.
* We make sure we do a remove on this exact
* name, as the name was mangled and denotes
* a unique file.
*/
flags &= ~SMB_IGNORE_CASE;
}
}
}
return (rc);
}
/*
* smb_fsop_remove_streams
*
* This function removes a file's streams without removing the
* file itself.
*
* It is assumed that snode is not a link.
*/
int
{
struct fs_stream_info stream_info;
int flags = 0;
int rc;
return (EACCES);
if (SMB_TREE_IS_READ_ONLY(sr))
return (EROFS);
if (SMB_TREE_CASE_INSENSITIVE(sr))
for (;;) {
break;
cr);
}
return (rc);
}
/*
* smb_fsop_rmdir
*
* All SMB functions should use this wrapper to ensure that
* the the calls are performed with the appropriate credentials.
* Please document any direct call to explain the reason
* for avoiding this wrapper.
*
* It is assumed that a reference exists on snode coming into this routine.
*
* od: This means that the name passed in is an on-disk name.
*/
int
char *name,
int od)
{
int rc;
int flags = 0;
char *longname;
/*
* The state of the node could be SMB_NODE_STATE_DESTROYING if this
* function is called during the deletion of the node (because of
* DELETE_ON_CLOSE).
*/
return (EACCES);
if (SMB_TREE_IS_READ_ONLY(sr))
return (EROFS);
/*
* If the passed-in name is an on-disk name,
* then we need to do a case-sensitive rmdir.
* This is important if the on-disk name
* corresponds to a mangled name passed in by
* the client. We want to make sure to remove
* the exact directory specified by the client,
* instead of letting the underlying file system
* do a rmdir on the "first match."
*/
if (smb_maybe_mangled_name(name) == 0)
return (rc);
NULL, 1);
if (rc == 0) {
/*
* We passed "1" as the "od" parameter
* to smb_unmangle_name(), such that longname
* is the real (case-sensitive) on-disk name.
* We make sure we do a rmdir on this exact
* name, as the name was mangled and denotes
* a unique directory.
*/
flags &= ~SMB_IGNORE_CASE;
}
}
return (rc);
}
/*
* smb_fsop_getattr
*
* All SMB functions should use this wrapper to ensure that
* the the calls are performed with the appropriate credentials.
* Please document any direct call to explain the reason
* for avoiding this wrapper.
*
* It is assumed that a reference exists on snode coming into this routine.
*/
int
{
int flags = 0;
int rc;
return (EACCES);
access |= READ_CONTROL;
/* if anything else is also requested */
if (status != NT_STATUS_SUCCESS)
return (EACCES);
}
if (unnamed_node) {
}
if (rc == 0)
return (rc);
}
/*
* smb_fsop_readdir
*
* All SMB functions should use this smb_fsop_readdir wrapper to ensure that
* the smb_vop_readdir is performed with the appropriate credentials.
* Please document any direct call to smb_vop_readdir to explain the reason
* for avoiding this wrapper.
*
* It is assumed that a reference exists on snode coming into this routine.
*/
int
char *name,
int *namelen,
struct fs_stream_info *stream_info,
{
char *od_name;
int rc;
int flags = 0;
return (EACCES);
*namelen = 0;
return (0);
}
if (SMB_TREE_CASE_INSENSITIVE(sr))
if (stream_info) {
if (rc != 0) {
return (rc);
}
return (ENOMEM);
}
/*
* XXX
* Need to find out what permission(s) NTFS requires for getting
* a file's streams list.
*
* Might have to use kcred.
*/
return (rc);
}
if (ret_snodep == NULL) {
return (ENOMEM);
}
if (ret_attr)
if (ret_snode)
*ret_snode = ret_snodep;
else
} else {
if (rc != 0) {
return (rc);
}
if (*namelen) {
if (ret_snodep == NULL) {
return (ENOMEM);
}
if (ret_attr)
if (ret_snode)
*ret_snode = ret_snodep;
else
}
}
}
return (rc);
}
/*
* smb_fsop_getdents
*
* All SMB functions should use this smb_vop_getdents wrapper to ensure that
* the smb_vop_getdents is performed with the appropriate credentials.
* Please document any direct call to smb_vop_getdents to explain the reason
* for avoiding this wrapper.
*
* It is assumed that a reference exists on snode coming into this routine.
*/
/*ARGSUSED*/
int
struct smb_request *sr,
char *args,
char *pattern)
{
int flags = 0;
return (EACCES);
if (SMB_TREE_CASE_INSENSITIVE(sr))
}
/*
* smb_fsop_rename
*
* All SMB functions should use this smb_vop_rename wrapper to ensure that
* the smb_vop_rename is performed with the appropriate credentials.
* Please document any direct call to smb_vop_rename to explain the reason
* for avoiding this wrapper.
*
* It is assumed that references exist on from_dir_snode and to_dir_snode coming
* into this routine.
*/
int
char *from_name,
char *to_name)
{
int flags = 0;
int rc;
return (EACCES);
return (EACCES);
if (SMB_TREE_IS_READ_ONLY(sr))
return (EROFS);
/*
* Note: There is no need to check SMB_TREE_CASE_INSENSITIVE(sr)
* here.
*
* A case-sensitive rename is always done in this routine
* because we are using the on-disk name from an earlier lookup.
* If a mangled name was passed in by the caller (denoting a
* deterministic lookup), then the exact file must be renamed
* (i.e. SMB_IGNORE_CASE must not be passed to VOP_RENAME, or
* else the underlying file system might return a "first-match"
* on this on-disk name, possibly resulting in the wrong file).
*/
/*
* XXX: Lock required through smb_node_release() below?
*/
if (rc != 0)
return (rc);
if (rc == 0) {
if (from_snode == NULL) {
return (ENOMEM);
}
to_name);
} else {
}
/* XXX: unlock */
return (rc);
}
/*
* smb_fsop_setattr
*
* All SMB functions should use this wrapper to ensure that
* the the calls are performed with the appropriate credentials.
* Please document any direct call to explain the reason
* for avoiding this wrapper.
*
* It is assumed that a reference exists on snode coming into this routine.
* A null smb_request might be passed to this function.
*/
int
{
int rc = 0;
int flags = 0;
return (EACCES);
if (SMB_TREE_IS_READ_ONLY(sr))
return (EROFS);
/* sr could be NULL in some cases */
access |= WRITE_OWNER;
/* if anything else is also requested */
if (status != NT_STATUS_SUCCESS)
return (EACCES);
}
if (unnamed_node) {
}
/*
* Use kcred to update the node attr because this
* call is not being made on behalf of the user.
*/
if (rc == 0)
}
return (rc);
}
/*
* smb_fsop_read
*
* All SMB functions should use this wrapper to ensure that
* the the calls are performed with the appropriate credentials.
* Please document any direct call to explain the reason
* for avoiding this wrapper.
*
* It is assumed that a reference exists on snode coming into this routine.
*/
int
struct smb_request *sr,
{
int svmand;
int rc;
if (rc != NT_STATUS_SUCCESS) {
if (rc != NT_STATUS_SUCCESS)
return (EACCES);
}
if (unnamed_node) {
/*
* Streams permission are checked against the unnamed stream,
* but in FS level they have their own permissions. To avoid
* rejection by FS due to lack of permission on the actual
* extended attr kcred is passed for streams.
*/
}
if (rc) {
return (rc);
}
if (rc) {
return (ERANGE);
}
/*
* Use kcred to update the node attr because this
* call is not being made on behalf of the user.
*/
kcred) == 0) {
}
}
return (rc);
}
/*
* smb_fsop_write
*
* This is a wrapper function used for smb_write and smb_write_raw operations.
*
* It is assumed that a reference exists on snode coming into this routine.
*/
int
{
int svmand;
int rc;
if (SMB_TREE_IS_READ_ONLY(sr))
return (EROFS);
if (rc != NT_STATUS_SUCCESS) {
if (rc != NT_STATUS_SUCCESS)
return (EACCES);
}
if (unnamed_node) {
/*
* Streams permission are checked against the unnamed stream,
* but in FS level they have their own permissions. To avoid
* rejection by FS due to lack of permission on the actual
* extended attr kcred is passed for streams.
*/
}
if (rc) {
return (rc);
}
if (rc) {
return (ERANGE);
}
/*
* Use kcred to update the node attr because this
* call is not being made on behalf of the user.
*/
kcred) == 0) {
}
}
return (rc);
}
/*
* smb_fsop_statfs
*
* This is a wrapper function used for stat operations.
*/
int
{
}
/*
* smb_fsop_access
*
* Named streams do not have separate permissions from the associated
* unnamed stream. Thus, if node is a named stream, the permissions
* check will be performed on the associated unnamed stream.
*
* However, our named streams do have their own quarantine attribute,
* separate from that on the unnamed stream. If READ or EXECUTE
* access has been requested on a named stream, an additional access
* check is performed on the named stream in case it has been
* quarantined. kcred is used to avoid issues with the permissions
* set on the extended attribute file representing the named stream.
*/
int
{
int access = 0;
int error;
if (faccess == 0)
return (NT_STATUS_SUCCESS);
if (SMB_TREE_IS_READ_ONLY(sr)) {
return (NT_STATUS_ACCESS_DENIED);
}
}
if (unnamed_node) {
/*
* Perform VREAD access check on the named stream in case it
* is quarantined. kcred is passed to smb_vop_access so it
* doesn't fail due to lack of permission.
*/
if (error)
return (NT_STATUS_ACCESS_DENIED);
}
/*
* Streams authorization should be performed against the
* unnamed stream.
*/
}
if (faccess & ACCESS_SYSTEM_SECURITY) {
/*
* it's not part of DACL. It's only granted via proper
* privileges.
*/
SMB_USER_PRIV_SECURITY)) == 0)
return (NT_STATUS_PRIVILEGE_NOT_HELD);
}
/* Links don't have ACL */
if (acl_check) {
cr);
} else {
/*
* FS doesn't understand 32-bit mask, need to map
*/
if (faccess & FILE_READ_DATA)
if (faccess & FILE_EXECUTE)
}
}
/*
* smb_fsop_lookup_name()
*
* Sanity checks on dir_snode done in smb_fsop_lookup().
*
* Note: This function is called only from the open path.
* It will check if the file is a stream.
* It will also return an error if the looked-up file is in
* a child mount.
*/
int
int flags,
char *name,
{
char *od_name;
char *fname;
char *sname;
int rc;
/*
* The following check is required for streams processing, below
*/
if (SMB_TREE_CASE_INSENSITIVE(sr))
flags |= SMB_IGNORE_CASE;
/*
* Look up the unnamed stream (i.e. fname).
* Unmangle processing will be done on fname
* as well as any link target.
*/
if (rc != 0) {
return (rc);
}
/*
* od_name is the on-disk name of the stream, except
* without the prepended stream prefix (SMB_STREAM_PREFIX)
*/
/*
* XXX
* What permissions NTFS requires for stream lookup if any?
*/
if (rc != 0) {
return (rc);
}
return (ENOMEM);
}
} else {
}
if (rc == 0) {
}
}
return (rc);
}
/*
* smb_fsop_lookup
*
* All SMB functions should use this smb_vop_lookup wrapper to ensure that
* the smb_vop_lookup is performed with the appropriate credentials and using
* case insensitive compares. Please document any direct call to smb_vop_lookup
* to explain the reason for avoiding this wrapper.
*
* It is assumed that a reference exists on dir_snode coming into this routine
* (and that it is safe from deallocation).
*
* Same with the root_node.
*
* *ret_snode is returned with a reference upon success. No reference is
* taken if an error is returned.
*
* Note: The returned ret_snode may be in a child mount. This is ok for
* readdir and getdents.
*
* Other smb_fsop_* routines will call SMB_TREE_ROOT_FS() to prevent
* operations on files not in the parent mount.
*/
int
int flags,
char *name,
char *ret_shortname, /* Must be at least MANGLE_NAMELEN chars */
char *ret_name83) /* Must be at least MANGLE_NAMELEN chars */
{
char *longname;
char *od_name;
int rc;
return (EINVAL);
return (EACCES);
if (SMB_TREE_CASE_INSENSITIVE(sr))
flags |= SMB_IGNORE_CASE;
if (rc != 0) {
if (smb_maybe_mangled_name(name) == 0) {
return (rc);
}
if (rc != 0) {
return (rc);
}
/*
* We passed "1" as the "od" parameter
* to smb_unmangle_name(), such that longname
* is the real (case-sensitive) on-disk name.
* We make sure we do a lookup on this exact
* name, as the name was mangled and denotes
* a unique file.
*/
if (flags & SMB_IGNORE_CASE)
flags &= ~SMB_IGNORE_CASE;
if (rc != 0) {
return (rc);
}
}
if (rc != 0) {
/*
* The link is assumed to be for the last component
* of a path. Hence any ENOTDIR error will be returned
* as ENOENT.
*/
return (rc);
}
/*
* Release the original VLNK vnode
*/
if (rc != 0) {
return (rc);
}
/*
* smb_vop_traverse_check() may have returned a different vnode
*/
} else {
ret_attr);
}
}
} else {
if (rc) {
return (rc);
}
}
}
return (rc);
}
/*
* smb_fsop_stream_readdir()
*
* ret_snode and ret_attr are optional parameters (i.e. NULL may be passed in)
*
* This routine will return only NTFS streams. If an NTFS stream is not
* found at the offset specified, the directory will be read until an NTFS
* stream is found or until EOF.
*
* Note: Sanity checks done in caller
* (smb_fsop_readdir(), smb_fsop_remove_streams())
*/
int
{
int rc = 0;
int flags = 0;
/*
* XXX NTFS permission requirements if any?
*/
if (SMB_TREE_CASE_INSENSITIVE(sr))
return (rc);
if (ret_snodep == NULL) {
return (ENOMEM);
}
if (ret_attr)
if (ret_snode)
*ret_snode = ret_snodep;
else
return (rc);
}
int /*ARGSUSED*/
{
if (SMB_TREE_IS_READ_ONLY(sr))
return (EROFS);
}
/*
* smb_fsop_aclread
*
* Retrieve filesystem ACL. Depends on requested ACLs in
* fs_sd->sd_secinfo, it'll set DACL and SACL pointers in
* the corresponding field in fs_sd should be non-NULL upon
* return, since the target ACL might not contain that type of
* entries.
*
* Returned ACL is always in ACE_T (aka ZFS) format.
* If successful the allocated memory for the ACL should be freed
* using smb_fsacl_free() or smb_fssd_term()
*/
int
{
int error = 0;
int flags = 0;
int access = 0;
if (error != NT_STATUS_SUCCESS) {
return (EACCES);
}
}
if (unnamed_node) {
/*
* Streams don't have ACL, any read ACL attempt on a stream
* should be performed on the unnamed stream.
*/
}
if (error != 0) {
return (error);
}
if (error == 0) {
fs_sd->sd_secinfo);
}
return (error);
}
/*
* smb_fsop_aclwrite
*
* Stores the filesystem ACL provided in fs_sd->sd_acl.
*/
int
{
int target_flavor;
int error = 0;
int flags = 0;
int access = 0;
if (SMB_TREE_IS_READ_ONLY(sr))
return (EROFS);
if (error != NT_STATUS_SUCCESS)
return (EACCES);
}
case ACLENT_T:
break;
case ACE_T:
break;
default:
return (EINVAL);
}
if (unnamed_node) {
/*
* Streams don't have ACL, any write ACL attempt on a stream
* should be performed on the unnamed stream.
*/
}
return (EINVAL);
else if (dacl)
else
if (error == 0) {
}
return (error);
}
{
}
/*
* smb_fsop_sdread
*
* Read the requested security descriptor items from filesystem.
* The items are specified in fs_sd->sd_secinfo.
*/
int
{
int error = 0;
int getowner = 0;
/*
*
* 1. it's explicitly requested
*
* 2. target ACL is ACE_T (ZFS ACL). They're needed for
* owner@/group@ entries. In this case kcred should be used
*/
getowner = 1;
getowner = 1;
}
if (getowner) {
/*
* they're part of Security Descriptor.
* ZFS only requires read_attribute. Need to have a explicit
* access check here.
*/
if (error)
return (error);
}
if (error == 0) {
} else {
return (error);
}
}
}
return (error);
}
/*
* smb_fsop_sdmerge
*
* From SMB point of view DACL and SACL are two separate list
* which can be manipulated independently without one affecting
* the other, but entries for both DACL and SACL will end up
* in the same ACL if target filesystem supports ACE_T ACLs.
*
* So, if either DACL or SACL is present in the client set request
* the entries corresponding to the non-present ACL shouldn't
* be touched in the FS ACL.
*
* fs_sd parameter contains DACL and SACL specified by SMB
* specify both or one of these ACLs (if none is specified
* we don't get this far). When both DACL and SACL are given
* by client the existing ACL should be overwritten. If only
* one of them is specified the entries corresponding to the other
* ACL should not be touched. For example, if only DACL
* is specified in input fs_sd, the function reads audit entries
* of the existing ACL of the file and point fs_sd->sd_zsdacl
* pointer to the fetched SACL, this way when smb_fsop_sdwrite()
* function is called the passed fs_sd would point to the specified
* DACL by client and fetched SACL from filesystem, so the file
* will end up with correct ACL.
*/
static int
{
int error = 0;
/* Don't bother if target FS doesn't support ACE_T */
return (0);
/*
* Don't overwrite existing audit entries
*/
if (error == 0) {
}
} else {
/*
* Don't overwrite existing access entries
*/
if (error == 0) {
}
}
if (error)
}
return (error);
}
/*
* smb_fsop_sdwrite
*
* Stores the given uid, gid and acl in filesystem.
* Provided items in fs_sd are specified by fs_sd->sd_secinfo.
*
* A SMB security descriptor could contain owner, primary group,
* DACL and SACL. Setting an SD should be atomic but here it has to
* be done via two separate FS operations: VOP_SETATTR and
* VOP_SETSECATTR. Therefore, this function has to simulate the
* atomicity as well as it can.
*/
int
{
int error = 0;
int access = 0;
if (SMB_TREE_IS_READ_ONLY(sr))
return (EROFS);
}
}
else
if (error)
return (EACCES);
/*
* Get the current uid, gid so if smb_fsop_aclwrite fails
* we can revert uid, gid changes.
*
* We use root cred here so the operation doesn't fail
* due to lack of permission for the user to read the attrs
*/
if (error == 0)
NULL);
if (error)
return (error);
}
if (overwrite == 0) {
if (error)
return (error);
}
if (error) {
/*
*/
}
}
}
return (error);
}
/*
* smb_fsop_sdinherit
*
* Inherit the security descriptor from the parent container.
* so if this doesn't do anything it means FS inheritance is
* in place.
*
* Do inheritance for ZFS internally.
*
* If we want to let ZFS does the inheritance the
* following setting should be true:
*
* - aclinherit = passthrough
* - aclmode = passthrough
* - smbd umask = 0777
*
* This will result in right effective permissions but
* ZFS will always add 6 ACEs for owner, owning group
* and others to be POSIX compliant. This is not what
* implements Windows rules and overwrite whatever ZFS
* comes up with. This way we also don't have to care
* about ZFS aclinherit and aclmode settings.
*/
static int
{
int is_dir;
int error;
/*
* No forced inheritance for non-ZFS filesystems.
*/
fs_sd->sd_secinfo = 0;
return (0);
}
/* Fetch parent directory's ACL */
if (error) {
return (error);
}
(uid_t)-1);
return (0);
}
/*
* smb_fsop_eaccess
*
* Returns the effective permission of the given credential for the
* specified object.
*
*/
void
{
int access = 0;
if (unnamed_node) {
/*
* Streams authorization should be performed against the
* unnamed stream.
*/
}
cr);
return;
}
/*
* FS doesn't understand 32-bit mask
*/
*eaccess |= FILE_READ_DATA;
*eaccess |= FILE_EXECUTE;
}
/*
* smb_fsop_shrlock
*
* For the current open request, check file sharing rules
* against existing opens.
*
* Returns NT_STATUS_SHARING_VIOLATION if there is any
* sharing conflict. Returns NT_STATUS_SUCCESS otherwise.
*
* Full system-wide share reservation synchronization is available
* when the nbmand (non-blocking mandatory) mount option is set
* (i.e. nbl_need_crit() is true) and nbmand critical regions are used.
* This provides synchronization with NFS and local processes. The
* critical regions are entered in VOP_SHRLOCK()/fs_shrlock() (called
* from smb_open_subr()/smb_fsop_shrlock()/smb_vop_shrlock()) as well
* as the CIFS rename and delete paths.
*
* The CIFS server will also enter the nbl critical region in the open,
* rename, and delete paths when nbmand is not set. There is limited
* coordination with local and VFS share reservations in this case.
* Note that when the nbmand mount option is not set, the VFS layer
* only processes advisory reservations and the delete mode is not checked.
*
* Whether or not the nbmand mount option is set, intra-CIFS share
* checking is done in the open, delete, and rename paths using a CIFS
* critical region (node->n_share_lock).
*/
{
int rc;
return (NT_STATUS_SUCCESS);
/* Allow access if the request is just for meta data */
if ((desired_access & FILE_DATA_ALL) == 0)
return (NT_STATUS_SUCCESS);
if (rc)
return (NT_STATUS_SHARING_VIOLATION);
cr);
if (rc)
return (NT_STATUS_SHARING_VIOLATION);
return (NT_STATUS_SUCCESS);
}
void
{
return;
}
int
{
int flag = F_REMOTELOCK;
/*
* VOP_FRLOCK() will not be called if:
*
* 1) The lock has a range of zero bytes. The semantics of Windows and
* POSIX are different. In the case of POSIX it asks for the locking
* of all the bytes from the offset provided until the end of the
* file. In the case of Windows a range of zero locks nothing and
* doesn't conflict with any other lock.
*
* 2) The lock rolls over (start + lenght < start). Solaris will assert
* if such a request is submitted. This will not create
* incompatibilities between POSIX and Windows. In the Windows world,
* if a client submits such a lock, the server will not lock any
* bytes. Interestingly if the same lock (same offset and length) is
* resubmitted Windows will consider that there is an overlap and
* the granting rules will then apply.
*/
return (0);
if (unlock) {
}
}