smb_fsops.c revision b1352070d318187b41b088da3533692976f3f225
/*
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#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);
/*
* 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)
*/
}
void
{
}
int
{
int rc;
return (EMFILE);
return (rc);
(void) smb_fem_oplock_uninstall(node);
return (EMFILE);
}
return (0);
}
void
{
}
static int
{
int aclbsize = 0; /* size of acl list in bytes */
int flags = 0;
int rc;
if (SMB_TREE_SUPPORTS_CATIA(sr))
} else if (dacl) {
} else {
}
if (rc != 0)
return (rc);
} else {
}
/* The tree ACEs may prevent a create */
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.
*/
}
}
if (rc == 0) {
}
} 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);
fs_sd, 1);
} else {
}
}
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.
*
* *ret_snode is returned with a reference upon success. No reference is
* taken if an error is returned.
*/
int
{
int rc = 0;
int flags = 0;
*ret_snode = 0;
if (*name == 0)
return (EINVAL);
return (EACCES);
if (SMB_TREE_IS_READONLY(sr))
return (EROFS);
if (SMB_TREE_SUPPORTS_CATIA(sr))
if (smb_is_stream_name(name)) {
return (rc);
}
/* Not a named stream */
if (smb_maybe_mangled_name(name)) {
if (rc == 0)
return (rc);
}
return (rc);
}
/*
* smb_fsop_create_stream
*
* Create NTFS named stream file (sname) on unnamed stream
* file (fname), creating the unnamed stream file if it
* doesn't exist.
* If we created the unnamed stream file and then creation
* of the named stream file fails, we delete the unnamed stream.
* Since we use the real file name for the smb_vop_remove we
* clear the SMB_IGNORE_CASE flag to ensure a case sensitive
* match.
*
* 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()).
*/
static int
{
int rc = 0;
/* Look up / create the unnamed stream, fname */
}
if (rc != 0)
return (rc);
/* create the named stream, sname */
if (rc != 0) {
if (fcreate) {
flags &= ~SMB_IGNORE_CASE;
}
return (rc);
}
if (rc != 0) {
return (rc);
}
return (rc);
}
/*
* smb_fsop_create_file
*/
static int
{
int rc = 0;
/*
* 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_READONLY(sr))
return (EROFS);
if (SMB_TREE_SUPPORTS_CATIA(sr))
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);
}
/*
* 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.
*
* A null smb_request might be passed to this function.
*/
int
char *name,
{
char *longname;
char *fname;
char *sname;
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_READONLY(sr))
return (EROFS);
} else if (smb_is_stream_name(name)) {
/*
* 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);
}
/*
* 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) {
/*
* 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 fnode is not a link.
*/
int
{
smb_odir_t *od;
return (-1);
}
if (SMB_TREE_IS_READONLY(sr)) {
return (-1);
}
if (SMB_TREE_SUPPORTS_CATIA(sr))
return (-1);
}
return (-1);
}
for (;;) {
break;
}
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.
*/
int
char *name,
{
int rc;
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_READONLY(sr))
return (EROFS);
if (smb_maybe_mangled_name(name) == 0)
return (rc);
if (rc == 0) {
/*
* 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_link
*
* All SMB functions should use this smb_vop_link wrapper to ensure that
* the smb_vop_link is performed with the appropriate credentials.
* Please document any direct call to smb_vop_link to explain the reason
* for avoiding this wrapper.
*
* It is assumed that references exist on from_dnode and to_dnode coming
* into this routine.
*/
int
{
int flags = 0;
int rc;
return (EACCES);
return (EACCES);
if (SMB_TREE_IS_READONLY(sr))
return (EROFS);
if (SMB_TREE_SUPPORTS_CATIA(sr))
if (smb_maybe_mangled_name(to_name)) {
if (rc == 0)
return (rc);
}
return (rc);
}
/*
* 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_dnode and to_dnode coming
* into this routine.
*/
int
char *from_name,
char *to_name)
{
int rc;
return (EACCES);
return (EACCES);
if (SMB_TREE_IS_READONLY(sr))
return (EROFS);
/*
* Note: There is no need to check SMB_TREE_IS_CASEINSENSITIVE
* 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).
*/
if (SMB_TREE_SUPPORTS_CATIA(sr))
/*
* XXX: Lock required through smb_node_release() below?
*/
if (rc != 0)
return (rc);
(ACE_DELETE_CHILD | ACE_ADD_SUBDIRECTORY)) ||
(ACE_DELETE | ACE_ADD_FILE)))
return (EACCES);
if (rc == 0) {
if (from_snode == NULL) {
} 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_READONLY(sr))
return (EROFS);
if (SMB_TREE_HAS_ACCESS(sr,
return (EACCES);
return (EACCES);
} else {
return (EACCES);
}
}
/* sr could be NULL in some cases */
access = 0;
if (sa_mask & SMB_AT_SIZE) {
sa_mask &= ~SMB_AT_SIZE;
}
access |= WRITE_OWNER;
}
if (sa_mask)
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.
*/
kcred);
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;
return (EACCES);
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 ioflag)
{
int svmand;
int rc;
if (SMB_TREE_IS_READONLY(sr))
return (EROFS);
return (EACCES);
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_READONLY(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 */
/*
* Use the most restrictive parts of both faccess and the
* share access. An AND of the two value masks gives us that
* since we've already converted to a mask of what we "can"
* do.
*/
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()
*
* If name indicates that the file is a stream file, perform
* stream specific lookup, otherwise call smb_fsop_lookup.
*
* Return an error if the looked-up file is in outside the tree.
* (Required when invoked from open path.)
*/
int
int flags,
char *name,
{
char *od_name;
char *fname;
char *sname;
int rc;
/*
* The following check is required for streams processing, below
*/
flags |= SMB_IGNORE_CASE;
if (smb_is_stream_name(name)) {
/*
* 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 dnode 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.
*
* Other smb_fsop_* routines will call SMB_TREE_CONTAINS_NODE() to prevent
* operations on files not in the parent mount.
*/
int
int flags,
char *name,
{
char *longname;
char *od_name;
int rc;
int ret_flags;
return (EINVAL);
return (EACCES);
flags |= SMB_IGNORE_CASE;
if (SMB_TREE_SUPPORTS_CATIA(sr))
if (rc != 0) {
if (smb_maybe_mangled_name(name) == 0) {
return (rc);
}
if (rc != 0) {
return (rc);
}
/*
* 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);
}
int /*ARGSUSED*/
{
if (SMB_TREE_IS_READONLY(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;
return (EACCES);
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_READONLY(sr))
return (EROFS);
return (EACCES);
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 (EACCES);
}
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.
*
* so if smb_fsop_aclwrite fails they can be restored. root cred is
* behalf of the server not the user.
*
* owner has been specified. Callers should translate this to
* STATUS_INVALID_OWNER which is not the normal mapping for EPERM
* in upper layers, so EPERM is mapped to EBADE.
*/
int
{
int error = 0;
int access = 0;
if (SMB_TREE_IS_READONLY(sr))
return (EROFS);
access |= WRITE_OWNER;
}
access |= WRITE_OWNER;
}
else
if (error)
return (EACCES);
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) {
}
}