smb_path_name_reduction.c revision b89a8333f5e1f75ec0c269b22524bd2eccb972ba
/*
* 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 "@(#)smb_path_name_reduction.c 1.6 08/08/07 SMI"
#include <smbsrv/smb_incl.h>
#include <smbsrv/smb_fsops.h>
#include <sys/pathname.h>
smb_is_executable(char *path)
{
char extension[5];
(void) utf8_strupr(extension);
return (NODE_FLAGS_EXECUTABLE);
return (NODE_FLAGS_EXECUTABLE);
return (NODE_FLAGS_EXECUTABLE);
return (NODE_FLAGS_EXECUTABLE);
}
return (0);
}
/*
* smbd_fs_query
*
* Upon success, the caller will need to call smb_node_release() on
* fqi.last_snode (if it isn't already set to NULL by this routine) and
* and fqi.dir_snode. These pointers will not be used after the caller
* is done with them and should be released immediately. (The position
* of smb_fqi in a union in the smb_request structure makes it difficult
* to free these pointers at smb_request deallocation time.)
*
* If smbd_fs_query() returns error, no smb_nodes will need to be released
* by callers as a result of references taken in this routine, and
* fqi.last_snode and fqi.dir_snode will be set to NULL.
*/
int
{
int rc;
fqi->last_comp_was_found = 0;
if (rc)
return (rc);
if (rc == 0) {
if (fqm == FQM_PATH_MUST_NOT_EXIST) {
return (EEXIST);
}
return (0);
}
if (fqm == FQM_PATH_MUST_EXIST) {
return (rc);
}
return (0);
}
return (rc);
}
/*
* smb_pathname_reduce
*
* smb_pathname_reduce() takes a path and returns the smb_node for the
* second-to-last component of the path. It also returns the name of the last
* component. Pointers for both of these fields must be supplied by the caller.
*
* Upon success, 0 is returned.
*
* Upon error, *dir_node will be set to 0.
*
* *sr (in)
* ---
* smb_request structure pointer
*
* *cred (in)
* -----
* credential
*
* *path (in)
* -----
* pathname to be looked up
*
* *share_root_node (in)
* ----------------
* File operations which are share-relative should pass sr->tid_tree->t_snode.
* If the call is not for a share-relative operation, this parameter must be 0
* (e.g. the call from smbsr_setup_share()). (Such callers will have path
* operations done using root_smb_node.) This parameter is used to determine
* whether mount points can be crossed.
*
* share_root_node should have at least one reference on it. This reference
* will stay intact throughout this routine.
*
* *cur_node (in)
* ---------
* The smb_node for the current directory (for relative paths).
* cur_node should have at least one reference on it.
* This reference will stay intact throughout this routine.
*
* **dir_node (out)
* ----------
* Directory for the penultimate component of the original path.
* (Note that this is not the same as the parent directory of the ultimate
* target in the case of a link.)
*
* The directory smb_node is returned held. The caller will need to release
* the hold or otherwise make sure it will get released (e.g. in a destroy
* routine if made part of a global structure).
*
* last_component (out)
* --------------
* The last component of the path. (This may be different from the name of any
* link target to which the last component may resolve.)
*
*
* ____________________________
*
* The CIFS server lookup path needs to have logic equivalent to that of
* smb_fsop_lookup(), smb_vop_lookup() and other smb_vop_*() routines in the
* following areas:
*
* - non-traversal of child mounts (handled by smb_pathname_reduce)
* - unmangling (handled in smb_pathname)
* - "chroot" behavior of share root (handled by lookuppnvp)
*
* In addition, it needs to replace backslashes with forward slashes. It also
* ensures that link processing is done correctly, and that directory
* information requested by the caller is correctly returned (i.e. for paths
* with a link in the last component, the directory information of the
* link and not the target needs to be returned).
*/
int
const char *path,
char *last_component)
{
char *usepath;
int lookup_flags = FOLLOW;
int trailing_slash = 0;
int err = 0;
int len;
*last_component = '\0';
return (EACCES);
}
return (EINVAL);
if (*path == '\0')
return (ENOENT);
return (ENAMETOOLONG);
}
trailing_slash = 1;
if (share_root_node)
else
return (err);
}
/*
* If a path does not have a trailing slash, strip off the
* last component. (We only need to return an smb_node for
* the second to last component; a name is returned for the
* last component.)
*/
if (trailing_slash) {
} else {
(void) pn_setlast(&ppn);
}
} else {
}
/*
* Prevent access to anything outside of the share root, except
* when mapping a share because that may require traversal from
* / to a mounted file system. share_root_node is NULL when
* mapping a share.
*
* Note that we disregard whether the traversal of the path went
* outside of the file system and then came back (say via a link).
*/
if ((err == 0) && share_root_node) {
}
if (err) {
if (*dir_node) {
(void) smb_node_release(*dir_node);
}
*last_component = 0;
}
return (err);
}
/*
* smb_pathname() - wrapper to lookuppnvp(). Handles name unmangling.
*
* *dir_node is the true directory of the target *node.
*
* If any component but the last in the path is not found, ENOTDIR instead of
* ENOENT will be returned.
*
* Path components are processed one at a time so that smb_nodes can be
* created for each component. This allows the dir_snode field in the
* smb_node to be properly populated.
*
* Mangle checking is also done on each component.
*/
int
char *path,
int flags,
{
char *namep;
int err = 0;
int nlink = 0;
int local_flags;
return (EINVAL);
if (dir_node)
return (err);
}
/*
* Path components are processed one at a time so that smb_nodes
* can be created for each component. This allows the dir_snode
* field in the smb_node to be properly populated.
*
* Because of the above, links are also processed in this routine
* (i.e., we do not pass the FOLLOW flag to lookuppnvp()). This
* will allow smb_nodes to be created for each component of a link.
*
* Mangle checking is per component.
*/
if (fnode) {
}
break;
if (smb_maybe_mangled_name(component)) {
1)) != 0)
break;
/*
* Do not pass FIGNORECASE to lookuppnvp().
* This is because we would like to do a lookup
* on the real name just obtained (which
* corresponds to the mangled name).
*/
local_flags = 0;
} else {
/*
* Pass FIGNORECASE to lookuppnvp().
* This will cause the file system to
* return "first match" in the event of
* a case collision.
*/
}
break;
/*
* Holds on dvp and rootvp (if not rootdir) are
* required by lookuppnvp() and will be released within
* that routine.
*/
cred);
if (err)
break;
if (++nlink > MAXSYMLINKS) {
break;
}
if (err) {
break;
}
if (pn_pathleft(&link_pn) == 0)
if (err)
break;
if (upn.pn_pathlen == 0) {
break;
}
}
if (pn_fixslash(&upn))
} else {
if (flags & FIGNORECASE) {
pn_setlast(&rpn);
} else
break;
}
}
upn.pn_pathlen--;
}
}
/*
* Since no parent vp was passed to lookuppnvp(), all
* ENOENT errors are returned as ENOENT
*/
if (err) {
if (fnode)
if (dnode)
} else {
if (dir_node)
else
}
return (err);
}