xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_pathname.c (revision 11447:b5b2a9bd508f)
111337SWilliam.Krier@Sun.COM /*
211337SWilliam.Krier@Sun.COM  * CDDL HEADER START
311337SWilliam.Krier@Sun.COM  *
411337SWilliam.Krier@Sun.COM  * The contents of this file are subject to the terms of the
511337SWilliam.Krier@Sun.COM  * Common Development and Distribution License (the "License").
611337SWilliam.Krier@Sun.COM  * You may not use this file except in compliance with the License.
711337SWilliam.Krier@Sun.COM  *
811337SWilliam.Krier@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911337SWilliam.Krier@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1011337SWilliam.Krier@Sun.COM  * See the License for the specific language governing permissions
1111337SWilliam.Krier@Sun.COM  * and limitations under the License.
1211337SWilliam.Krier@Sun.COM  *
1311337SWilliam.Krier@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1411337SWilliam.Krier@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511337SWilliam.Krier@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1611337SWilliam.Krier@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1711337SWilliam.Krier@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1811337SWilliam.Krier@Sun.COM  *
1911337SWilliam.Krier@Sun.COM  * CDDL HEADER END
2011337SWilliam.Krier@Sun.COM  */
2111337SWilliam.Krier@Sun.COM /*
22*11447Samw@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2311337SWilliam.Krier@Sun.COM  * Use is subject to license terms.
2411337SWilliam.Krier@Sun.COM  */
2511337SWilliam.Krier@Sun.COM 
2611337SWilliam.Krier@Sun.COM #include <smbsrv/smb_kproto.h>
2711337SWilliam.Krier@Sun.COM #include <smbsrv/smb_fsops.h>
2811337SWilliam.Krier@Sun.COM #include <sys/pathname.h>
2911337SWilliam.Krier@Sun.COM #include <sys/sdt.h>
3011337SWilliam.Krier@Sun.COM 
3111337SWilliam.Krier@Sun.COM static char *smb_pathname_catia_v5tov4(smb_request_t *, char *, char *, int);
3211337SWilliam.Krier@Sun.COM static char *smb_pathname_catia_v4tov5(smb_request_t *, char *, char *, int);
3311337SWilliam.Krier@Sun.COM static int smb_pathname_lookup(pathname_t *, pathname_t *, int,
3411337SWilliam.Krier@Sun.COM     vnode_t **, vnode_t *, vnode_t *, cred_t *);
3511337SWilliam.Krier@Sun.COM static char *smb_pathname_strdup(smb_request_t *, const char *);
3611337SWilliam.Krier@Sun.COM static char *smb_pathname_strcat(smb_request_t *, char *, const char *);
3711337SWilliam.Krier@Sun.COM static void smb_pathname_preprocess(smb_request_t *, smb_pathname_t *);
3811337SWilliam.Krier@Sun.COM 
3911337SWilliam.Krier@Sun.COM uint32_t
4011337SWilliam.Krier@Sun.COM smb_is_executable(char *path)
4111337SWilliam.Krier@Sun.COM {
4211337SWilliam.Krier@Sun.COM 	char	extension[5];
4311337SWilliam.Krier@Sun.COM 	int	len = strlen(path);
4411337SWilliam.Krier@Sun.COM 
4511337SWilliam.Krier@Sun.COM 	if ((len >= 4) && (path[len - 4] == '.')) {
4611337SWilliam.Krier@Sun.COM 		(void) strcpy(extension, &path[len - 3]);
4711337SWilliam.Krier@Sun.COM 		(void) smb_strupr(extension);
4811337SWilliam.Krier@Sun.COM 
4911337SWilliam.Krier@Sun.COM 		if (strcmp(extension, "EXE") == 0)
5011337SWilliam.Krier@Sun.COM 			return (NODE_FLAGS_EXECUTABLE);
5111337SWilliam.Krier@Sun.COM 
5211337SWilliam.Krier@Sun.COM 		if (strcmp(extension, "COM") == 0)
5311337SWilliam.Krier@Sun.COM 			return (NODE_FLAGS_EXECUTABLE);
5411337SWilliam.Krier@Sun.COM 
5511337SWilliam.Krier@Sun.COM 		if (strcmp(extension, "DLL") == 0)
5611337SWilliam.Krier@Sun.COM 			return (NODE_FLAGS_EXECUTABLE);
5711337SWilliam.Krier@Sun.COM 
5811337SWilliam.Krier@Sun.COM 		if (strcmp(extension, "SYM") == 0)
5911337SWilliam.Krier@Sun.COM 			return (NODE_FLAGS_EXECUTABLE);
6011337SWilliam.Krier@Sun.COM 	}
6111337SWilliam.Krier@Sun.COM 
6211337SWilliam.Krier@Sun.COM 	return (0);
6311337SWilliam.Krier@Sun.COM }
6411337SWilliam.Krier@Sun.COM 
6511337SWilliam.Krier@Sun.COM /*
6611337SWilliam.Krier@Sun.COM  * smb_pathname_reduce
6711337SWilliam.Krier@Sun.COM  *
6811337SWilliam.Krier@Sun.COM  * smb_pathname_reduce() takes a path and returns the smb_node for the
6911337SWilliam.Krier@Sun.COM  * second-to-last component of the path.  It also returns the name of the last
7011337SWilliam.Krier@Sun.COM  * component.  Pointers for both of these fields must be supplied by the caller.
7111337SWilliam.Krier@Sun.COM  *
7211337SWilliam.Krier@Sun.COM  * Upon success, 0 is returned.
7311337SWilliam.Krier@Sun.COM  *
7411337SWilliam.Krier@Sun.COM  * Upon error, *dir_node will be set to 0.
7511337SWilliam.Krier@Sun.COM  *
7611337SWilliam.Krier@Sun.COM  * *sr (in)
7711337SWilliam.Krier@Sun.COM  * ---
7811337SWilliam.Krier@Sun.COM  * smb_request structure pointer
7911337SWilliam.Krier@Sun.COM  *
8011337SWilliam.Krier@Sun.COM  * *cred (in)
8111337SWilliam.Krier@Sun.COM  * -----
8211337SWilliam.Krier@Sun.COM  * credential
8311337SWilliam.Krier@Sun.COM  *
8411337SWilliam.Krier@Sun.COM  * *path (in)
8511337SWilliam.Krier@Sun.COM  * -----
8611337SWilliam.Krier@Sun.COM  * pathname to be looked up
8711337SWilliam.Krier@Sun.COM  *
8811337SWilliam.Krier@Sun.COM  * *share_root_node (in)
8911337SWilliam.Krier@Sun.COM  * ----------------
9011337SWilliam.Krier@Sun.COM  * File operations which are share-relative should pass sr->tid_tree->t_snode.
9111337SWilliam.Krier@Sun.COM  * If the call is not for a share-relative operation, this parameter must be 0
9211337SWilliam.Krier@Sun.COM  * (e.g. the call from smbsr_setup_share()).  (Such callers will have path
9311337SWilliam.Krier@Sun.COM  * operations done using root_smb_node.)  This parameter is used to determine
9411337SWilliam.Krier@Sun.COM  * whether mount points can be crossed.
9511337SWilliam.Krier@Sun.COM  *
9611337SWilliam.Krier@Sun.COM  * share_root_node should have at least one reference on it.  This reference
9711337SWilliam.Krier@Sun.COM  * will stay intact throughout this routine.
9811337SWilliam.Krier@Sun.COM  *
9911337SWilliam.Krier@Sun.COM  * *cur_node (in)
10011337SWilliam.Krier@Sun.COM  * ---------
10111337SWilliam.Krier@Sun.COM  * The smb_node for the current directory (for relative paths).
10211337SWilliam.Krier@Sun.COM  * cur_node should have at least one reference on it.
10311337SWilliam.Krier@Sun.COM  * This reference will stay intact throughout this routine.
10411337SWilliam.Krier@Sun.COM  *
10511337SWilliam.Krier@Sun.COM  * **dir_node (out)
10611337SWilliam.Krier@Sun.COM  * ----------
10711337SWilliam.Krier@Sun.COM  * Directory for the penultimate component of the original path.
10811337SWilliam.Krier@Sun.COM  * (Note that this is not the same as the parent directory of the ultimate
10911337SWilliam.Krier@Sun.COM  * target in the case of a link.)
11011337SWilliam.Krier@Sun.COM  *
11111337SWilliam.Krier@Sun.COM  * The directory smb_node is returned held.  The caller will need to release
11211337SWilliam.Krier@Sun.COM  * the hold or otherwise make sure it will get released (e.g. in a destroy
11311337SWilliam.Krier@Sun.COM  * routine if made part of a global structure).
11411337SWilliam.Krier@Sun.COM  *
11511337SWilliam.Krier@Sun.COM  * last_component (out)
11611337SWilliam.Krier@Sun.COM  * --------------
11711337SWilliam.Krier@Sun.COM  * The last component of the path.  (This may be different from the name of any
11811337SWilliam.Krier@Sun.COM  * link target to which the last component may resolve.)
11911337SWilliam.Krier@Sun.COM  *
12011337SWilliam.Krier@Sun.COM  *
12111337SWilliam.Krier@Sun.COM  * ____________________________
12211337SWilliam.Krier@Sun.COM  *
12311337SWilliam.Krier@Sun.COM  * The CIFS server lookup path needs to have logic equivalent to that of
12411337SWilliam.Krier@Sun.COM  * smb_fsop_lookup(), smb_vop_lookup() and other smb_vop_*() routines in the
12511337SWilliam.Krier@Sun.COM  * following areas:
12611337SWilliam.Krier@Sun.COM  *
12711337SWilliam.Krier@Sun.COM  *	- non-traversal of child mounts		(handled by smb_pathname_reduce)
12811337SWilliam.Krier@Sun.COM  *	- unmangling 				(handled in smb_pathname)
12911337SWilliam.Krier@Sun.COM  *	- "chroot" behavior of share root 	(handled by lookuppnvp)
13011337SWilliam.Krier@Sun.COM  *
13111337SWilliam.Krier@Sun.COM  * In addition, it needs to replace backslashes with forward slashes.  It also
13211337SWilliam.Krier@Sun.COM  * ensures that link processing is done correctly, and that directory
13311337SWilliam.Krier@Sun.COM  * information requested by the caller is correctly returned (i.e. for paths
13411337SWilliam.Krier@Sun.COM  * with a link in the last component, the directory information of the
13511337SWilliam.Krier@Sun.COM  * link and not the target needs to be returned).
13611337SWilliam.Krier@Sun.COM  */
13711337SWilliam.Krier@Sun.COM 
13811337SWilliam.Krier@Sun.COM int
13911337SWilliam.Krier@Sun.COM smb_pathname_reduce(
14011337SWilliam.Krier@Sun.COM     smb_request_t	*sr,
14111337SWilliam.Krier@Sun.COM     cred_t		*cred,
14211337SWilliam.Krier@Sun.COM     const char		*path,
14311337SWilliam.Krier@Sun.COM     smb_node_t		*share_root_node,
14411337SWilliam.Krier@Sun.COM     smb_node_t		*cur_node,
14511337SWilliam.Krier@Sun.COM     smb_node_t		**dir_node,
14611337SWilliam.Krier@Sun.COM     char		*last_component)
14711337SWilliam.Krier@Sun.COM {
14811337SWilliam.Krier@Sun.COM 	smb_node_t	*root_node;
14911337SWilliam.Krier@Sun.COM 	pathname_t	ppn;
15011337SWilliam.Krier@Sun.COM 	char		*usepath;
15111337SWilliam.Krier@Sun.COM 	int		lookup_flags = FOLLOW;
15211337SWilliam.Krier@Sun.COM 	int 		trailing_slash = 0;
15311337SWilliam.Krier@Sun.COM 	int		err = 0;
15411337SWilliam.Krier@Sun.COM 	int		len;
15511337SWilliam.Krier@Sun.COM 	smb_node_t	*vss_cur_node;
15611337SWilliam.Krier@Sun.COM 	smb_node_t	*vss_root_node;
15711337SWilliam.Krier@Sun.COM 	smb_node_t	*local_cur_node;
15811337SWilliam.Krier@Sun.COM 	smb_node_t	*local_root_node;
15911337SWilliam.Krier@Sun.COM 
16011337SWilliam.Krier@Sun.COM 	ASSERT(dir_node);
16111337SWilliam.Krier@Sun.COM 	ASSERT(last_component);
16211337SWilliam.Krier@Sun.COM 
16311337SWilliam.Krier@Sun.COM 	*dir_node = NULL;
16411337SWilliam.Krier@Sun.COM 	*last_component = '\0';
16511337SWilliam.Krier@Sun.COM 	vss_cur_node = NULL;
16611337SWilliam.Krier@Sun.COM 	vss_root_node = NULL;
16711337SWilliam.Krier@Sun.COM 
16811337SWilliam.Krier@Sun.COM 	if (sr && sr->tid_tree) {
169*11447Samw@Sun.COM 		if (STYPE_ISIPC(sr->tid_tree->t_res_type))
17011337SWilliam.Krier@Sun.COM 			return (EACCES);
17111337SWilliam.Krier@Sun.COM 	}
17211337SWilliam.Krier@Sun.COM 
17311337SWilliam.Krier@Sun.COM 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
17411337SWilliam.Krier@Sun.COM 		lookup_flags |= FIGNORECASE;
17511337SWilliam.Krier@Sun.COM 
17611337SWilliam.Krier@Sun.COM 	if (path == NULL)
17711337SWilliam.Krier@Sun.COM 		return (EINVAL);
17811337SWilliam.Krier@Sun.COM 
17911337SWilliam.Krier@Sun.COM 	if (*path == '\0')
18011337SWilliam.Krier@Sun.COM 		return (ENOENT);
18111337SWilliam.Krier@Sun.COM 
18211337SWilliam.Krier@Sun.COM 	usepath = kmem_alloc(MAXPATHLEN, KM_SLEEP);
18311337SWilliam.Krier@Sun.COM 
18411337SWilliam.Krier@Sun.COM 	if ((len = strlcpy(usepath, path, MAXPATHLEN)) >= MAXPATHLEN) {
18511337SWilliam.Krier@Sun.COM 		kmem_free(usepath, MAXPATHLEN);
18611337SWilliam.Krier@Sun.COM 		return (ENAMETOOLONG);
18711337SWilliam.Krier@Sun.COM 	}
18811337SWilliam.Krier@Sun.COM 
18911337SWilliam.Krier@Sun.COM 	(void) strsubst(usepath, '\\', '/');
19011337SWilliam.Krier@Sun.COM 
19111337SWilliam.Krier@Sun.COM 	if (share_root_node)
19211337SWilliam.Krier@Sun.COM 		root_node = share_root_node;
19311337SWilliam.Krier@Sun.COM 	else
19411337SWilliam.Krier@Sun.COM 		root_node = sr->sr_server->si_root_smb_node;
19511337SWilliam.Krier@Sun.COM 
19611337SWilliam.Krier@Sun.COM 	if (cur_node == NULL)
19711337SWilliam.Krier@Sun.COM 		cur_node = root_node;
19811337SWilliam.Krier@Sun.COM 
19911337SWilliam.Krier@Sun.COM 	local_cur_node = cur_node;
20011337SWilliam.Krier@Sun.COM 	local_root_node = root_node;
20111337SWilliam.Krier@Sun.COM 
20211337SWilliam.Krier@Sun.COM 	if (sr && (sr->smb_flg2 & SMB_FLAGS2_REPARSE_PATH)) {
20311337SWilliam.Krier@Sun.COM 		err = smb_vss_lookup_nodes(sr, root_node, cur_node,
20411337SWilliam.Krier@Sun.COM 		    usepath, &vss_cur_node, &vss_root_node);
20511337SWilliam.Krier@Sun.COM 
20611337SWilliam.Krier@Sun.COM 		if (err != 0) {
20711337SWilliam.Krier@Sun.COM 			kmem_free(usepath, MAXPATHLEN);
20811337SWilliam.Krier@Sun.COM 			return (err);
20911337SWilliam.Krier@Sun.COM 		}
21011337SWilliam.Krier@Sun.COM 
21111337SWilliam.Krier@Sun.COM 		len = strlen(usepath);
21211337SWilliam.Krier@Sun.COM 		local_cur_node = vss_cur_node;
21311337SWilliam.Krier@Sun.COM 		local_root_node = vss_root_node;
21411337SWilliam.Krier@Sun.COM 	}
21511337SWilliam.Krier@Sun.COM 
21611337SWilliam.Krier@Sun.COM 	if (usepath[len - 1] == '/')
21711337SWilliam.Krier@Sun.COM 		trailing_slash = 1;
21811337SWilliam.Krier@Sun.COM 
21911337SWilliam.Krier@Sun.COM 	(void) strcanon(usepath, "/");
22011337SWilliam.Krier@Sun.COM 
22111337SWilliam.Krier@Sun.COM 	(void) pn_alloc(&ppn);
22211337SWilliam.Krier@Sun.COM 
22311337SWilliam.Krier@Sun.COM 	if ((err = pn_set(&ppn, usepath)) != 0) {
22411337SWilliam.Krier@Sun.COM 		(void) pn_free(&ppn);
22511337SWilliam.Krier@Sun.COM 		kmem_free(usepath, MAXPATHLEN);
22611337SWilliam.Krier@Sun.COM 		if (vss_cur_node != NULL)
22711337SWilliam.Krier@Sun.COM 			(void) smb_node_release(vss_cur_node);
22811337SWilliam.Krier@Sun.COM 		if (vss_root_node != NULL)
22911337SWilliam.Krier@Sun.COM 			(void) smb_node_release(vss_root_node);
23011337SWilliam.Krier@Sun.COM 		return (err);
23111337SWilliam.Krier@Sun.COM 	}
23211337SWilliam.Krier@Sun.COM 
23311337SWilliam.Krier@Sun.COM 	/*
23411337SWilliam.Krier@Sun.COM 	 * If a path does not have a trailing slash, strip off the
23511337SWilliam.Krier@Sun.COM 	 * last component.  (We only need to return an smb_node for
23611337SWilliam.Krier@Sun.COM 	 * the second to last component; a name is returned for the
23711337SWilliam.Krier@Sun.COM 	 * last component.)
23811337SWilliam.Krier@Sun.COM 	 */
23911337SWilliam.Krier@Sun.COM 
24011337SWilliam.Krier@Sun.COM 	if (trailing_slash) {
24111337SWilliam.Krier@Sun.COM 		(void) strlcpy(last_component, ".", MAXNAMELEN);
24211337SWilliam.Krier@Sun.COM 	} else {
24311337SWilliam.Krier@Sun.COM 		(void) pn_setlast(&ppn);
24411337SWilliam.Krier@Sun.COM 		(void) strlcpy(last_component, ppn.pn_path, MAXNAMELEN);
24511337SWilliam.Krier@Sun.COM 		ppn.pn_path[0] = '\0';
24611337SWilliam.Krier@Sun.COM 	}
24711337SWilliam.Krier@Sun.COM 
24811337SWilliam.Krier@Sun.COM 	if ((strcmp(ppn.pn_buf, "/") == 0) || (ppn.pn_buf[0] == '\0')) {
24911337SWilliam.Krier@Sun.COM 		smb_node_ref(local_cur_node);
25011337SWilliam.Krier@Sun.COM 		*dir_node = local_cur_node;
25111337SWilliam.Krier@Sun.COM 	} else {
25211337SWilliam.Krier@Sun.COM 		err = smb_pathname(sr, ppn.pn_buf, lookup_flags,
25311337SWilliam.Krier@Sun.COM 		    local_root_node, local_cur_node, NULL, dir_node, cred);
25411337SWilliam.Krier@Sun.COM 	}
25511337SWilliam.Krier@Sun.COM 
25611337SWilliam.Krier@Sun.COM 	(void) pn_free(&ppn);
25711337SWilliam.Krier@Sun.COM 	kmem_free(usepath, MAXPATHLEN);
25811337SWilliam.Krier@Sun.COM 
25911337SWilliam.Krier@Sun.COM 	/*
26011337SWilliam.Krier@Sun.COM 	 * Prevent access to anything outside of the share root, except
26111337SWilliam.Krier@Sun.COM 	 * when mapping a share because that may require traversal from
26211337SWilliam.Krier@Sun.COM 	 * / to a mounted file system.  share_root_node is NULL when
26311337SWilliam.Krier@Sun.COM 	 * mapping a share.
26411337SWilliam.Krier@Sun.COM 	 *
26511337SWilliam.Krier@Sun.COM 	 * Note that we disregard whether the traversal of the path went
26611337SWilliam.Krier@Sun.COM 	 * outside of the file system and then came back (say via a link).
26711337SWilliam.Krier@Sun.COM 	 */
26811337SWilliam.Krier@Sun.COM 
26911337SWilliam.Krier@Sun.COM 	if ((err == 0) && share_root_node) {
27011337SWilliam.Krier@Sun.COM 		if (share_root_node->vp->v_vfsp != (*dir_node)->vp->v_vfsp)
27111337SWilliam.Krier@Sun.COM 			err = EACCES;
27211337SWilliam.Krier@Sun.COM 	}
27311337SWilliam.Krier@Sun.COM 
27411337SWilliam.Krier@Sun.COM 	if (err) {
27511337SWilliam.Krier@Sun.COM 		if (*dir_node) {
27611337SWilliam.Krier@Sun.COM 			(void) smb_node_release(*dir_node);
27711337SWilliam.Krier@Sun.COM 			*dir_node = NULL;
27811337SWilliam.Krier@Sun.COM 		}
27911337SWilliam.Krier@Sun.COM 		*last_component = 0;
28011337SWilliam.Krier@Sun.COM 	}
28111337SWilliam.Krier@Sun.COM 
28211337SWilliam.Krier@Sun.COM 	if (vss_cur_node != NULL)
28311337SWilliam.Krier@Sun.COM 		(void) smb_node_release(vss_cur_node);
28411337SWilliam.Krier@Sun.COM 	if (vss_root_node != NULL)
28511337SWilliam.Krier@Sun.COM 		(void) smb_node_release(vss_root_node);
28611337SWilliam.Krier@Sun.COM 
28711337SWilliam.Krier@Sun.COM 	return (err);
28811337SWilliam.Krier@Sun.COM }
28911337SWilliam.Krier@Sun.COM 
29011337SWilliam.Krier@Sun.COM /*
29111337SWilliam.Krier@Sun.COM  * smb_pathname()
29211337SWilliam.Krier@Sun.COM  * wrapper to lookuppnvp().  Handles name unmangling.
29311337SWilliam.Krier@Sun.COM  *
29411337SWilliam.Krier@Sun.COM  * *dir_node is the true directory of the target *node.
29511337SWilliam.Krier@Sun.COM  *
29611337SWilliam.Krier@Sun.COM  * If any component but the last in the path is not found, ENOTDIR instead of
29711337SWilliam.Krier@Sun.COM  * ENOENT will be returned.
29811337SWilliam.Krier@Sun.COM  *
29911337SWilliam.Krier@Sun.COM  * Path components are processed one at a time so that smb_nodes can be
30011337SWilliam.Krier@Sun.COM  * created for each component.  This allows the n_dnode field in the
30111337SWilliam.Krier@Sun.COM  * smb_node to be properly populated.
30211337SWilliam.Krier@Sun.COM  *
30311337SWilliam.Krier@Sun.COM  * Because of the above, links are also processed in this routine
30411337SWilliam.Krier@Sun.COM  * (i.e., we do not pass the FOLLOW flag to lookuppnvp()).  This
30511337SWilliam.Krier@Sun.COM  * will allow smb_nodes to be created for each component of a link.
30611337SWilliam.Krier@Sun.COM  *
30711337SWilliam.Krier@Sun.COM  * Mangle checking is per component. If a name is mangled, when the
30811337SWilliam.Krier@Sun.COM  * unmangled name is passed to smb_pathname_lookup() do not pass
30911337SWilliam.Krier@Sun.COM  * FIGNORECASE, since the unmangled name is the real on-disk name.
31011337SWilliam.Krier@Sun.COM  * Otherwise pass FIGNORECASE if it's set in flags. This will cause the
31111337SWilliam.Krier@Sun.COM  * file system to return "first match" in the event of a case collision.
31211337SWilliam.Krier@Sun.COM  *
31311337SWilliam.Krier@Sun.COM  * If CATIA character translation is enabled it is applied to each
31411337SWilliam.Krier@Sun.COM  * component before passing the component to smb_pathname_lookup().
31511337SWilliam.Krier@Sun.COM  * After smb_pathname_lookup() the reverse translation is applied.
31611337SWilliam.Krier@Sun.COM  */
31711337SWilliam.Krier@Sun.COM 
31811337SWilliam.Krier@Sun.COM int
31911337SWilliam.Krier@Sun.COM smb_pathname(smb_request_t *sr, char *path, int flags,
32011337SWilliam.Krier@Sun.COM     smb_node_t *root_node, smb_node_t *cur_node, smb_node_t **dir_node,
32111337SWilliam.Krier@Sun.COM     smb_node_t **ret_node, cred_t *cred)
32211337SWilliam.Krier@Sun.COM {
32311337SWilliam.Krier@Sun.COM 	char		*component, *real_name, *namep;
32411337SWilliam.Krier@Sun.COM 	pathname_t	pn, rpn, upn, link_pn;
32511337SWilliam.Krier@Sun.COM 	smb_node_t	*dnode, *fnode;
32611337SWilliam.Krier@Sun.COM 	vnode_t		*rootvp, *vp;
32711337SWilliam.Krier@Sun.COM 	size_t		pathleft;
32811337SWilliam.Krier@Sun.COM 	int		err = 0;
32911337SWilliam.Krier@Sun.COM 	int		nlink = 0;
33011337SWilliam.Krier@Sun.COM 	int		local_flags;
33111337SWilliam.Krier@Sun.COM 	uint32_t	abe_flag = 0;
33211337SWilliam.Krier@Sun.COM 	char		namebuf[MAXNAMELEN];
33311337SWilliam.Krier@Sun.COM 
33411337SWilliam.Krier@Sun.COM 	if (path == NULL)
33511337SWilliam.Krier@Sun.COM 		return (EINVAL);
33611337SWilliam.Krier@Sun.COM 
33711337SWilliam.Krier@Sun.COM 	ASSERT(root_node);
33811337SWilliam.Krier@Sun.COM 	ASSERT(cur_node);
33911337SWilliam.Krier@Sun.COM 	ASSERT(ret_node);
34011337SWilliam.Krier@Sun.COM 
34111337SWilliam.Krier@Sun.COM 	*ret_node = NULL;
34211337SWilliam.Krier@Sun.COM 
34311337SWilliam.Krier@Sun.COM 	if (dir_node)
34411337SWilliam.Krier@Sun.COM 		*dir_node = NULL;
34511337SWilliam.Krier@Sun.COM 
34611337SWilliam.Krier@Sun.COM 	(void) pn_alloc(&upn);
34711337SWilliam.Krier@Sun.COM 
34811337SWilliam.Krier@Sun.COM 	if ((err = pn_set(&upn, path)) != 0) {
34911337SWilliam.Krier@Sun.COM 		(void) pn_free(&upn);
35011337SWilliam.Krier@Sun.COM 		return (err);
35111337SWilliam.Krier@Sun.COM 	}
35211337SWilliam.Krier@Sun.COM 
35311337SWilliam.Krier@Sun.COM 	if (SMB_TREE_SUPPORTS_ABE(sr))
35411337SWilliam.Krier@Sun.COM 		abe_flag = SMB_ABE;
35511337SWilliam.Krier@Sun.COM 
35611337SWilliam.Krier@Sun.COM 	(void) pn_alloc(&pn);
35711337SWilliam.Krier@Sun.COM 	(void) pn_alloc(&rpn);
35811337SWilliam.Krier@Sun.COM 
35911337SWilliam.Krier@Sun.COM 	component = kmem_alloc(MAXNAMELEN, KM_SLEEP);
36011337SWilliam.Krier@Sun.COM 	real_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
36111337SWilliam.Krier@Sun.COM 
36211337SWilliam.Krier@Sun.COM 	fnode = NULL;
36311337SWilliam.Krier@Sun.COM 	dnode = cur_node;
36411337SWilliam.Krier@Sun.COM 	smb_node_ref(dnode);
36511337SWilliam.Krier@Sun.COM 	rootvp = root_node->vp;
36611337SWilliam.Krier@Sun.COM 
36711337SWilliam.Krier@Sun.COM 	while ((pathleft = pn_pathleft(&upn)) != 0) {
36811337SWilliam.Krier@Sun.COM 		if (fnode) {
36911337SWilliam.Krier@Sun.COM 			smb_node_release(dnode);
37011337SWilliam.Krier@Sun.COM 			dnode = fnode;
37111337SWilliam.Krier@Sun.COM 			fnode = NULL;
37211337SWilliam.Krier@Sun.COM 		}
37311337SWilliam.Krier@Sun.COM 
37411337SWilliam.Krier@Sun.COM 		if ((err = pn_getcomponent(&upn, component)) != 0)
37511337SWilliam.Krier@Sun.COM 			break;
37611337SWilliam.Krier@Sun.COM 
37711337SWilliam.Krier@Sun.COM 		if ((namep = smb_pathname_catia_v5tov4(sr, component,
37811337SWilliam.Krier@Sun.COM 		    namebuf, sizeof (namebuf))) == NULL) {
37911337SWilliam.Krier@Sun.COM 			err = EILSEQ;
38011337SWilliam.Krier@Sun.COM 			break;
38111337SWilliam.Krier@Sun.COM 		}
38211337SWilliam.Krier@Sun.COM 
38311337SWilliam.Krier@Sun.COM 		if ((err = pn_set(&pn, namep)) != 0)
38411337SWilliam.Krier@Sun.COM 			break;
38511337SWilliam.Krier@Sun.COM 
38611337SWilliam.Krier@Sun.COM 		local_flags = flags & FIGNORECASE;
38711337SWilliam.Krier@Sun.COM 		err = smb_pathname_lookup(&pn, &rpn, local_flags,
38811337SWilliam.Krier@Sun.COM 		    &vp, rootvp, dnode->vp, cred);
38911337SWilliam.Krier@Sun.COM 
39011337SWilliam.Krier@Sun.COM 		if (err) {
39111337SWilliam.Krier@Sun.COM 			if (smb_maybe_mangled_name(component) == 0)
39211337SWilliam.Krier@Sun.COM 				break;
39311337SWilliam.Krier@Sun.COM 
39411337SWilliam.Krier@Sun.COM 			if ((err = smb_unmangle_name(dnode, component,
39511337SWilliam.Krier@Sun.COM 			    real_name, MAXNAMELEN, abe_flag)) != 0)
39611337SWilliam.Krier@Sun.COM 				break;
39711337SWilliam.Krier@Sun.COM 
39811337SWilliam.Krier@Sun.COM 			if ((namep = smb_pathname_catia_v5tov4(sr, real_name,
39911337SWilliam.Krier@Sun.COM 			    namebuf, sizeof (namebuf))) == NULL) {
40011337SWilliam.Krier@Sun.COM 				err = EILSEQ;
40111337SWilliam.Krier@Sun.COM 				break;
40211337SWilliam.Krier@Sun.COM 			}
40311337SWilliam.Krier@Sun.COM 
40411337SWilliam.Krier@Sun.COM 			if ((err = pn_set(&pn, namep)) != 0)
40511337SWilliam.Krier@Sun.COM 				break;
40611337SWilliam.Krier@Sun.COM 
40711337SWilliam.Krier@Sun.COM 			local_flags = 0;
40811337SWilliam.Krier@Sun.COM 			err = smb_pathname_lookup(&pn, &rpn, local_flags,
40911337SWilliam.Krier@Sun.COM 			    &vp, rootvp, dnode->vp, cred);
41011337SWilliam.Krier@Sun.COM 			if (err)
41111337SWilliam.Krier@Sun.COM 				break;
41211337SWilliam.Krier@Sun.COM 		}
41311337SWilliam.Krier@Sun.COM 
41411337SWilliam.Krier@Sun.COM 		if ((vp->v_type == VLNK) &&
41511337SWilliam.Krier@Sun.COM 		    ((flags & FOLLOW) || pn_pathleft(&upn))) {
41611337SWilliam.Krier@Sun.COM 
41711337SWilliam.Krier@Sun.COM 			if (++nlink > MAXSYMLINKS) {
41811337SWilliam.Krier@Sun.COM 				err = ELOOP;
41911337SWilliam.Krier@Sun.COM 				VN_RELE(vp);
42011337SWilliam.Krier@Sun.COM 				break;
42111337SWilliam.Krier@Sun.COM 			}
42211337SWilliam.Krier@Sun.COM 
42311337SWilliam.Krier@Sun.COM 			(void) pn_alloc(&link_pn);
42411337SWilliam.Krier@Sun.COM 			err = pn_getsymlink(vp, &link_pn, cred);
42511337SWilliam.Krier@Sun.COM 			VN_RELE(vp);
42611337SWilliam.Krier@Sun.COM 
42711337SWilliam.Krier@Sun.COM 			if (err == 0) {
42811337SWilliam.Krier@Sun.COM 				if (pn_pathleft(&link_pn) == 0)
42911337SWilliam.Krier@Sun.COM 					(void) pn_set(&link_pn, ".");
43011337SWilliam.Krier@Sun.COM 				err = pn_insert(&upn, &link_pn,
43111337SWilliam.Krier@Sun.COM 				    strlen(component));
43211337SWilliam.Krier@Sun.COM 			}
43311337SWilliam.Krier@Sun.COM 			pn_free(&link_pn);
43411337SWilliam.Krier@Sun.COM 
43511337SWilliam.Krier@Sun.COM 			if (err)
43611337SWilliam.Krier@Sun.COM 				break;
43711337SWilliam.Krier@Sun.COM 
43811337SWilliam.Krier@Sun.COM 			if (upn.pn_pathlen == 0) {
43911337SWilliam.Krier@Sun.COM 				err = ENOENT;
44011337SWilliam.Krier@Sun.COM 				break;
44111337SWilliam.Krier@Sun.COM 			}
44211337SWilliam.Krier@Sun.COM 
44311337SWilliam.Krier@Sun.COM 			if (upn.pn_path[0] == '/') {
44411337SWilliam.Krier@Sun.COM 				fnode = root_node;
44511337SWilliam.Krier@Sun.COM 				smb_node_ref(fnode);
44611337SWilliam.Krier@Sun.COM 			}
44711337SWilliam.Krier@Sun.COM 
44811337SWilliam.Krier@Sun.COM 			if (pn_fixslash(&upn))
44911337SWilliam.Krier@Sun.COM 				flags |= FOLLOW;
45011337SWilliam.Krier@Sun.COM 
45111337SWilliam.Krier@Sun.COM 		} else {
45211337SWilliam.Krier@Sun.COM 			if (flags & FIGNORECASE) {
45311337SWilliam.Krier@Sun.COM 				if (strcmp(rpn.pn_path, "/") != 0)
45411337SWilliam.Krier@Sun.COM 					pn_setlast(&rpn);
45511337SWilliam.Krier@Sun.COM 				namep = rpn.pn_path;
45611337SWilliam.Krier@Sun.COM 			} else {
45711337SWilliam.Krier@Sun.COM 				namep = pn.pn_path;
45811337SWilliam.Krier@Sun.COM 			}
45911337SWilliam.Krier@Sun.COM 
46011337SWilliam.Krier@Sun.COM 			namep = smb_pathname_catia_v4tov5(sr, namep,
46111337SWilliam.Krier@Sun.COM 			    namebuf, sizeof (namebuf));
46211337SWilliam.Krier@Sun.COM 
46311337SWilliam.Krier@Sun.COM 			fnode = smb_node_lookup(sr, NULL, cred, vp, namep,
46411337SWilliam.Krier@Sun.COM 			    dnode, NULL);
46511337SWilliam.Krier@Sun.COM 			VN_RELE(vp);
46611337SWilliam.Krier@Sun.COM 
46711337SWilliam.Krier@Sun.COM 			if (fnode == NULL) {
46811337SWilliam.Krier@Sun.COM 				err = ENOMEM;
46911337SWilliam.Krier@Sun.COM 				break;
47011337SWilliam.Krier@Sun.COM 			}
47111337SWilliam.Krier@Sun.COM 		}
47211337SWilliam.Krier@Sun.COM 
47311337SWilliam.Krier@Sun.COM 		while (upn.pn_path[0] == '/') {
47411337SWilliam.Krier@Sun.COM 			upn.pn_path++;
47511337SWilliam.Krier@Sun.COM 			upn.pn_pathlen--;
47611337SWilliam.Krier@Sun.COM 		}
47711337SWilliam.Krier@Sun.COM 
47811337SWilliam.Krier@Sun.COM 	}
47911337SWilliam.Krier@Sun.COM 
48011337SWilliam.Krier@Sun.COM 	if ((pathleft) && (err == ENOENT))
48111337SWilliam.Krier@Sun.COM 		err = ENOTDIR;
48211337SWilliam.Krier@Sun.COM 
48311337SWilliam.Krier@Sun.COM 	if (err) {
48411337SWilliam.Krier@Sun.COM 		if (fnode)
48511337SWilliam.Krier@Sun.COM 			smb_node_release(fnode);
48611337SWilliam.Krier@Sun.COM 		if (dnode)
48711337SWilliam.Krier@Sun.COM 			smb_node_release(dnode);
48811337SWilliam.Krier@Sun.COM 	} else {
48911337SWilliam.Krier@Sun.COM 		*ret_node = fnode;
49011337SWilliam.Krier@Sun.COM 
49111337SWilliam.Krier@Sun.COM 		if (dir_node)
49211337SWilliam.Krier@Sun.COM 			*dir_node = dnode;
49311337SWilliam.Krier@Sun.COM 		else
49411337SWilliam.Krier@Sun.COM 			smb_node_release(dnode);
49511337SWilliam.Krier@Sun.COM 	}
49611337SWilliam.Krier@Sun.COM 
49711337SWilliam.Krier@Sun.COM 	kmem_free(component, MAXNAMELEN);
49811337SWilliam.Krier@Sun.COM 	kmem_free(real_name, MAXNAMELEN);
49911337SWilliam.Krier@Sun.COM 	(void) pn_free(&pn);
50011337SWilliam.Krier@Sun.COM 	(void) pn_free(&rpn);
50111337SWilliam.Krier@Sun.COM 	(void) pn_free(&upn);
50211337SWilliam.Krier@Sun.COM 
50311337SWilliam.Krier@Sun.COM 	return (err);
50411337SWilliam.Krier@Sun.COM }
50511337SWilliam.Krier@Sun.COM 
50611337SWilliam.Krier@Sun.COM /*
50711337SWilliam.Krier@Sun.COM  * Holds on dvp and rootvp (if not rootdir) are required by lookuppnvp()
50811337SWilliam.Krier@Sun.COM  * and will be released within lookuppnvp().
50911337SWilliam.Krier@Sun.COM  */
51011337SWilliam.Krier@Sun.COM static int
51111337SWilliam.Krier@Sun.COM smb_pathname_lookup(pathname_t *pn, pathname_t *rpn, int flags,
51211337SWilliam.Krier@Sun.COM     vnode_t **vp, vnode_t *rootvp, vnode_t *dvp, cred_t *cred)
51311337SWilliam.Krier@Sun.COM {
51411337SWilliam.Krier@Sun.COM 	int err;
51511337SWilliam.Krier@Sun.COM 
51611337SWilliam.Krier@Sun.COM 	*vp = NULL;
51711337SWilliam.Krier@Sun.COM 	VN_HOLD(dvp);
51811337SWilliam.Krier@Sun.COM 	if (rootvp != rootdir)
51911337SWilliam.Krier@Sun.COM 		VN_HOLD(rootvp);
52011337SWilliam.Krier@Sun.COM 
52111337SWilliam.Krier@Sun.COM 	err = lookuppnvp(pn, rpn, flags, NULL, vp, rootvp, dvp, cred);
52211337SWilliam.Krier@Sun.COM 	return (err);
52311337SWilliam.Krier@Sun.COM }
52411337SWilliam.Krier@Sun.COM 
52511337SWilliam.Krier@Sun.COM /*
52611337SWilliam.Krier@Sun.COM  * CATIA Translation of a pathname component prior to passing it to lookuppnvp
52711337SWilliam.Krier@Sun.COM  *
52811337SWilliam.Krier@Sun.COM  * If the translated component name contains a '/' NULL is returned.
52911337SWilliam.Krier@Sun.COM  * The caller should treat this as error EILSEQ. It is not valid to
53011337SWilliam.Krier@Sun.COM  * have a directory name with a '/'.
53111337SWilliam.Krier@Sun.COM  */
53211337SWilliam.Krier@Sun.COM static char *
53311337SWilliam.Krier@Sun.COM smb_pathname_catia_v5tov4(smb_request_t *sr, char *name,
53411337SWilliam.Krier@Sun.COM     char *namebuf, int buflen)
53511337SWilliam.Krier@Sun.COM {
53611337SWilliam.Krier@Sun.COM 	char *namep;
53711337SWilliam.Krier@Sun.COM 
53811337SWilliam.Krier@Sun.COM 	if (SMB_TREE_SUPPORTS_CATIA(sr)) {
53911337SWilliam.Krier@Sun.COM 		namep = smb_vop_catia_v5tov4(name, namebuf, buflen);
54011337SWilliam.Krier@Sun.COM 		if (strchr(namep, '/') != NULL)
54111337SWilliam.Krier@Sun.COM 			return (NULL);
54211337SWilliam.Krier@Sun.COM 		return (namep);
54311337SWilliam.Krier@Sun.COM 	}
54411337SWilliam.Krier@Sun.COM 
54511337SWilliam.Krier@Sun.COM 	return (name);
54611337SWilliam.Krier@Sun.COM }
54711337SWilliam.Krier@Sun.COM 
54811337SWilliam.Krier@Sun.COM /*
54911337SWilliam.Krier@Sun.COM  * CATIA translation of a pathname component after returning from lookuppnvp
55011337SWilliam.Krier@Sun.COM  */
55111337SWilliam.Krier@Sun.COM static char *
55211337SWilliam.Krier@Sun.COM smb_pathname_catia_v4tov5(smb_request_t *sr, char *name,
55311337SWilliam.Krier@Sun.COM     char *namebuf, int buflen)
55411337SWilliam.Krier@Sun.COM {
55511337SWilliam.Krier@Sun.COM 	if (SMB_TREE_SUPPORTS_CATIA(sr)) {
55611337SWilliam.Krier@Sun.COM 		smb_vop_catia_v4tov5(name, namebuf, buflen);
55711337SWilliam.Krier@Sun.COM 		return (namebuf);
55811337SWilliam.Krier@Sun.COM 	}
55911337SWilliam.Krier@Sun.COM 
56011337SWilliam.Krier@Sun.COM 	return (name);
56111337SWilliam.Krier@Sun.COM }
56211337SWilliam.Krier@Sun.COM 
56311337SWilliam.Krier@Sun.COM /*
56411337SWilliam.Krier@Sun.COM  * sr - needed to check for case sense
56511337SWilliam.Krier@Sun.COM  * path - non mangled path needed to be looked up from the startvp
56611337SWilliam.Krier@Sun.COM  * startvp - the vnode to start the lookup from
56711337SWilliam.Krier@Sun.COM  * rootvp - the vnode of the root of the filesystem
56811337SWilliam.Krier@Sun.COM  * returns the vnode found when starting at startvp and using the path
56911337SWilliam.Krier@Sun.COM  *
57011337SWilliam.Krier@Sun.COM  * Finds a vnode starting at startvp and parsing the non mangled path
57111337SWilliam.Krier@Sun.COM  */
57211337SWilliam.Krier@Sun.COM 
57311337SWilliam.Krier@Sun.COM vnode_t *
57411337SWilliam.Krier@Sun.COM smb_lookuppathvptovp(smb_request_t *sr, char *path, vnode_t *startvp,
57511337SWilliam.Krier@Sun.COM     vnode_t *rootvp)
57611337SWilliam.Krier@Sun.COM {
57711337SWilliam.Krier@Sun.COM 	pathname_t pn;
57811337SWilliam.Krier@Sun.COM 	vnode_t *vp = NULL;
57911337SWilliam.Krier@Sun.COM 	int lookup_flags = FOLLOW;
58011337SWilliam.Krier@Sun.COM 
58111337SWilliam.Krier@Sun.COM 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
58211337SWilliam.Krier@Sun.COM 		lookup_flags |= FIGNORECASE;
58311337SWilliam.Krier@Sun.COM 
58411337SWilliam.Krier@Sun.COM 	(void) pn_alloc(&pn);
58511337SWilliam.Krier@Sun.COM 
58611337SWilliam.Krier@Sun.COM 	if (pn_set(&pn, path) == 0) {
58711337SWilliam.Krier@Sun.COM 		VN_HOLD(startvp);
58811337SWilliam.Krier@Sun.COM 		if (rootvp != rootdir)
58911337SWilliam.Krier@Sun.COM 			VN_HOLD(rootvp);
59011337SWilliam.Krier@Sun.COM 
59111337SWilliam.Krier@Sun.COM 		/* lookuppnvp should release the holds */
59211337SWilliam.Krier@Sun.COM 		if (lookuppnvp(&pn, NULL, lookup_flags, NULL, &vp,
59311337SWilliam.Krier@Sun.COM 		    rootvp, startvp, kcred) != 0) {
59411337SWilliam.Krier@Sun.COM 			pn_free(&pn);
59511337SWilliam.Krier@Sun.COM 			return (NULL);
59611337SWilliam.Krier@Sun.COM 		}
59711337SWilliam.Krier@Sun.COM 	}
59811337SWilliam.Krier@Sun.COM 
59911337SWilliam.Krier@Sun.COM 	pn_free(&pn);
60011337SWilliam.Krier@Sun.COM 	return (vp);
60111337SWilliam.Krier@Sun.COM }
60211337SWilliam.Krier@Sun.COM 
60311337SWilliam.Krier@Sun.COM /*
60411337SWilliam.Krier@Sun.COM  * smb_pathname_init
60511337SWilliam.Krier@Sun.COM  * Parse path: pname\\fname:sname:stype
60611337SWilliam.Krier@Sun.COM  *
60711337SWilliam.Krier@Sun.COM  * Elements of the smb_pathname_t structure are allocated using request
60811337SWilliam.Krier@Sun.COM  * specific storage and will be free'd when the sr is destroyed.
60911337SWilliam.Krier@Sun.COM  *
61011337SWilliam.Krier@Sun.COM  * Populate pn structure elements with the individual elements
61111337SWilliam.Krier@Sun.COM  * of pn->pn_path. pn->pn_sname will contain the whole stream name
61211337SWilliam.Krier@Sun.COM  * including the stream type and preceding colon: :sname:%DATA
61311337SWilliam.Krier@Sun.COM  * pn_stype will point to the stream type within pn_sname.
61411337SWilliam.Krier@Sun.COM  *
61511337SWilliam.Krier@Sun.COM  * If the pname element is missing pn_pname will be set to "\\".
61611337SWilliam.Krier@Sun.COM  * If any other element is missing the pointer in pn will be NULL.
61711337SWilliam.Krier@Sun.COM  */
61811337SWilliam.Krier@Sun.COM void
61911337SWilliam.Krier@Sun.COM smb_pathname_init(smb_request_t *sr, smb_pathname_t *pn, char *path)
62011337SWilliam.Krier@Sun.COM {
62111337SWilliam.Krier@Sun.COM 	char *pname, *fname, *sname;
62211337SWilliam.Krier@Sun.COM 	int len;
62311337SWilliam.Krier@Sun.COM 
62411337SWilliam.Krier@Sun.COM 	bzero(pn, sizeof (smb_pathname_t));
62511337SWilliam.Krier@Sun.COM 	pn->pn_path = smb_pathname_strdup(sr, path);
62611337SWilliam.Krier@Sun.COM 
62711337SWilliam.Krier@Sun.COM 	smb_pathname_preprocess(sr, pn);
62811337SWilliam.Krier@Sun.COM 
62911337SWilliam.Krier@Sun.COM 	/* parse pn->pn_path into its constituent parts */
63011337SWilliam.Krier@Sun.COM 	pname = pn->pn_path;
63111337SWilliam.Krier@Sun.COM 	fname = strrchr(pn->pn_path, '\\');
63211337SWilliam.Krier@Sun.COM 
63311337SWilliam.Krier@Sun.COM 	if (fname) {
63411337SWilliam.Krier@Sun.COM 		if (fname == pname) {
63511337SWilliam.Krier@Sun.COM 			pn->pn_pname = smb_pathname_strdup(sr, "\\");
63611337SWilliam.Krier@Sun.COM 		} else {
63711337SWilliam.Krier@Sun.COM 			*fname = '\0';
63811337SWilliam.Krier@Sun.COM 			pn->pn_pname =
63911337SWilliam.Krier@Sun.COM 			    smb_pathname_strdup(sr, pname);
64011337SWilliam.Krier@Sun.COM 			*fname = '\\';
64111337SWilliam.Krier@Sun.COM 		}
64211337SWilliam.Krier@Sun.COM 		++fname;
64311337SWilliam.Krier@Sun.COM 	} else {
64411337SWilliam.Krier@Sun.COM 		fname = pname;
64511337SWilliam.Krier@Sun.COM 		pn->pn_pname = smb_pathname_strdup(sr, "\\");
64611337SWilliam.Krier@Sun.COM 	}
64711337SWilliam.Krier@Sun.COM 
64811337SWilliam.Krier@Sun.COM 	if (fname[0] == '\0') {
64911337SWilliam.Krier@Sun.COM 		pn->pn_fname = NULL;
65011337SWilliam.Krier@Sun.COM 		return;
65111337SWilliam.Krier@Sun.COM 	}
65211337SWilliam.Krier@Sun.COM 
65311337SWilliam.Krier@Sun.COM 	if (!smb_is_stream_name(fname)) {
65411337SWilliam.Krier@Sun.COM 		pn->pn_fname = smb_pathname_strdup(sr, fname);
65511337SWilliam.Krier@Sun.COM 		return;
65611337SWilliam.Krier@Sun.COM 	}
65711337SWilliam.Krier@Sun.COM 
65811337SWilliam.Krier@Sun.COM 	/*
65911337SWilliam.Krier@Sun.COM 	 * find sname and stype in fname.
66011337SWilliam.Krier@Sun.COM 	 * sname can't be NULL smb_is_stream_name checks this
66111337SWilliam.Krier@Sun.COM 	 */
66211337SWilliam.Krier@Sun.COM 	sname = strchr(fname, ':');
66311337SWilliam.Krier@Sun.COM 	if (sname == fname)
66411337SWilliam.Krier@Sun.COM 		fname = NULL;
66511337SWilliam.Krier@Sun.COM 	else {
66611337SWilliam.Krier@Sun.COM 		*sname = '\0';
66711337SWilliam.Krier@Sun.COM 		pn->pn_fname =
66811337SWilliam.Krier@Sun.COM 		    smb_pathname_strdup(sr, fname);
66911337SWilliam.Krier@Sun.COM 		*sname = ':';
67011337SWilliam.Krier@Sun.COM 	}
67111337SWilliam.Krier@Sun.COM 
67211337SWilliam.Krier@Sun.COM 	pn->pn_sname = smb_pathname_strdup(sr, sname);
67311337SWilliam.Krier@Sun.COM 	pn->pn_stype = strchr(pn->pn_sname + 1, ':');
67411337SWilliam.Krier@Sun.COM 	if (pn->pn_stype) {
67511337SWilliam.Krier@Sun.COM 		(void) smb_strupr(pn->pn_stype);
67611337SWilliam.Krier@Sun.COM 	} else {
67711337SWilliam.Krier@Sun.COM 		len = strlen(pn->pn_sname);
67811337SWilliam.Krier@Sun.COM 		pn->pn_sname = smb_pathname_strcat(sr, pn->pn_sname, ":$DATA");
67911337SWilliam.Krier@Sun.COM 		pn->pn_stype = pn->pn_sname + len;
68011337SWilliam.Krier@Sun.COM 	}
68111337SWilliam.Krier@Sun.COM 	++pn->pn_stype;
68211337SWilliam.Krier@Sun.COM }
68311337SWilliam.Krier@Sun.COM 
68411337SWilliam.Krier@Sun.COM /*
68511337SWilliam.Krier@Sun.COM  * smb_pathname_preprocess
68611337SWilliam.Krier@Sun.COM  *
68711337SWilliam.Krier@Sun.COM  * Perform common pre-processing of pn->pn_path:
68811337SWilliam.Krier@Sun.COM  * - if the pn_path is blank, set it to '\\'
68911337SWilliam.Krier@Sun.COM  * - perform unicode wildcard converstion.
69011337SWilliam.Krier@Sun.COM  * - convert any '/' to '\\'
69111337SWilliam.Krier@Sun.COM  * - eliminate duplicate slashes
69211337SWilliam.Krier@Sun.COM  * - remove trailing slashes
69311337SWilliam.Krier@Sun.COM  */
69411337SWilliam.Krier@Sun.COM static void
69511337SWilliam.Krier@Sun.COM smb_pathname_preprocess(smb_request_t *sr, smb_pathname_t *pn)
69611337SWilliam.Krier@Sun.COM {
69711337SWilliam.Krier@Sun.COM 	char *p;
69811337SWilliam.Krier@Sun.COM 
69911337SWilliam.Krier@Sun.COM 	/* treat empty path as "\\" */
70011337SWilliam.Krier@Sun.COM 	if (strlen(pn->pn_path) == 0) {
70111337SWilliam.Krier@Sun.COM 		pn->pn_path = smb_pathname_strdup(sr, "\\");
70211337SWilliam.Krier@Sun.COM 		return;
70311337SWilliam.Krier@Sun.COM 	}
70411337SWilliam.Krier@Sun.COM 
70511337SWilliam.Krier@Sun.COM 	/* perform unicode wildcard conversion */
70611337SWilliam.Krier@Sun.COM 	smb_convert_wildcards(pn->pn_path);
70711337SWilliam.Krier@Sun.COM 
70811337SWilliam.Krier@Sun.COM 	/* treat '/' as '\\' */
70911337SWilliam.Krier@Sun.COM 	(void) strsubst(pn->pn_path, '/', '\\');
71011337SWilliam.Krier@Sun.COM 
71111337SWilliam.Krier@Sun.COM 	(void) strcanon(pn->pn_path, "\\");
71211337SWilliam.Krier@Sun.COM 
71311337SWilliam.Krier@Sun.COM 	/* remove trailing '\\' */
71411337SWilliam.Krier@Sun.COM 	p = pn->pn_path + strlen(pn->pn_path) - 1;
71511337SWilliam.Krier@Sun.COM 	if ((p != pn->pn_path) && (*p == '\\'))
71611337SWilliam.Krier@Sun.COM 		*p = '\0';
71711337SWilliam.Krier@Sun.COM }
71811337SWilliam.Krier@Sun.COM 
71911337SWilliam.Krier@Sun.COM /*
72011337SWilliam.Krier@Sun.COM  * smb_pathname_strdup
72111337SWilliam.Krier@Sun.COM  *
72211337SWilliam.Krier@Sun.COM  * Duplicate NULL terminated string s.
72311337SWilliam.Krier@Sun.COM  *
72411337SWilliam.Krier@Sun.COM  * The new string is allocated using request specific storage and will
72511337SWilliam.Krier@Sun.COM  * be free'd when the sr is destroyed.
72611337SWilliam.Krier@Sun.COM  */
72711337SWilliam.Krier@Sun.COM static char *
72811337SWilliam.Krier@Sun.COM smb_pathname_strdup(smb_request_t *sr, const char *s)
72911337SWilliam.Krier@Sun.COM {
73011337SWilliam.Krier@Sun.COM 	char *s2;
73111337SWilliam.Krier@Sun.COM 	size_t n;
73211337SWilliam.Krier@Sun.COM 
73311337SWilliam.Krier@Sun.COM 	n = strlen(s) + 1;
73411337SWilliam.Krier@Sun.COM 	s2 = smb_srm_alloc(sr, n);
73511337SWilliam.Krier@Sun.COM 	(void) strlcpy(s2, s, n);
73611337SWilliam.Krier@Sun.COM 	return (s2);
73711337SWilliam.Krier@Sun.COM }
73811337SWilliam.Krier@Sun.COM 
73911337SWilliam.Krier@Sun.COM /*
74011337SWilliam.Krier@Sun.COM  * smb_pathname_strcat
74111337SWilliam.Krier@Sun.COM  *
74211337SWilliam.Krier@Sun.COM  * Reallocate NULL terminated string s1 to accommodate
74311337SWilliam.Krier@Sun.COM  * concatenating  NULL terminated string s2.
74411337SWilliam.Krier@Sun.COM  * Append s2 and return resulting NULL terminated string.
74511337SWilliam.Krier@Sun.COM  *
74611337SWilliam.Krier@Sun.COM  * The string buffer is reallocated using request specific
74711337SWilliam.Krier@Sun.COM  * storage and will be free'd when the sr is destroyed.
74811337SWilliam.Krier@Sun.COM  */
74911337SWilliam.Krier@Sun.COM static char *
75011337SWilliam.Krier@Sun.COM smb_pathname_strcat(smb_request_t *sr, char *s1, const char *s2)
75111337SWilliam.Krier@Sun.COM {
75211337SWilliam.Krier@Sun.COM 	size_t n;
75311337SWilliam.Krier@Sun.COM 
75411337SWilliam.Krier@Sun.COM 	n = strlen(s1) + strlen(s2) + 1;
75511337SWilliam.Krier@Sun.COM 	s1 = smb_srm_realloc(sr, s1, n);
75611337SWilliam.Krier@Sun.COM 	(void) strlcat(s1, s2, n);
75711337SWilliam.Krier@Sun.COM 	return (s1);
75811337SWilliam.Krier@Sun.COM }
75911337SWilliam.Krier@Sun.COM 
76011337SWilliam.Krier@Sun.COM /*
76111337SWilliam.Krier@Sun.COM  * smb_pathname_validate
76211337SWilliam.Krier@Sun.COM  *
76311337SWilliam.Krier@Sun.COM  * Perform basic validation of pn:
76411337SWilliam.Krier@Sun.COM  * - If first component of pn->path is ".." -> PATH_SYNTAX_BAD
76511337SWilliam.Krier@Sun.COM  * - If there are wildcards in pn->pn_pname -> OBJECT_NAME_INVALID
76611337SWilliam.Krier@Sun.COM  * - If fname is "." -> INVALID_OBJECT_NAME
76711337SWilliam.Krier@Sun.COM  *
76811337SWilliam.Krier@Sun.COM  * On unix .. at the root of a file system links to the root. Thus
76911337SWilliam.Krier@Sun.COM  * an attempt to lookup "/../../.." will be the same as looking up "/"
77011337SWilliam.Krier@Sun.COM  * CIFs clients expect the above to result in
77111337SWilliam.Krier@Sun.COM  * NT_STATUS_OBJECT_PATH_SYNTAX_BAD. It is currently not possible
77211337SWilliam.Krier@Sun.COM  * (and questionable if it's desirable) to deal with all cases
77311337SWilliam.Krier@Sun.COM  * but paths beginning with \\.. are handled.
77411337SWilliam.Krier@Sun.COM  *
77511337SWilliam.Krier@Sun.COM  * Returns: B_TRUE if pn is valid,
77611337SWilliam.Krier@Sun.COM  *          otherwise returns B_FALSE and sets error status in sr.
77711337SWilliam.Krier@Sun.COM  */
77811337SWilliam.Krier@Sun.COM boolean_t
77911337SWilliam.Krier@Sun.COM smb_pathname_validate(smb_request_t *sr, smb_pathname_t *pn)
78011337SWilliam.Krier@Sun.COM {
78111337SWilliam.Krier@Sun.COM 	char *path = pn->pn_path;
78211337SWilliam.Krier@Sun.COM 
78311337SWilliam.Krier@Sun.COM 	/* ignore any initial "\\" */
78411337SWilliam.Krier@Sun.COM 	path += strspn(path, "\\");
78511337SWilliam.Krier@Sun.COM 
78611337SWilliam.Krier@Sun.COM 	/* If first component of path is ".." -> PATH_SYNTAX_BAD */
78711337SWilliam.Krier@Sun.COM 	if ((strcmp(path, "..") == 0) || (strncmp(path, "..\\", 3) == 0)) {
78811337SWilliam.Krier@Sun.COM 		smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
78911337SWilliam.Krier@Sun.COM 		    ERRDOS, ERROR_BAD_PATHNAME);
79011337SWilliam.Krier@Sun.COM 		return (B_FALSE);
79111337SWilliam.Krier@Sun.COM 	}
79211337SWilliam.Krier@Sun.COM 
79311337SWilliam.Krier@Sun.COM 	/* If there are wildcards in pn->pn_pname -> OBJECT_NAME_INVALID */
79411337SWilliam.Krier@Sun.COM 	if (pn->pn_pname && smb_contains_wildcards(pn->pn_pname)) {
79511337SWilliam.Krier@Sun.COM 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
79611337SWilliam.Krier@Sun.COM 		    ERRDOS, ERROR_INVALID_NAME);
79711337SWilliam.Krier@Sun.COM 		return (B_FALSE);
79811337SWilliam.Krier@Sun.COM 	}
79911337SWilliam.Krier@Sun.COM 
80011337SWilliam.Krier@Sun.COM 	/* If fname is "." -> INVALID_OBJECT_NAME */
80111337SWilliam.Krier@Sun.COM 	if (pn->pn_fname && (strcmp(pn->pn_fname, ".") == 0)) {
80211337SWilliam.Krier@Sun.COM 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
80311337SWilliam.Krier@Sun.COM 		    ERRDOS, ERROR_PATH_NOT_FOUND);
80411337SWilliam.Krier@Sun.COM 		return (B_FALSE);
80511337SWilliam.Krier@Sun.COM 	}
80611337SWilliam.Krier@Sun.COM 
80711337SWilliam.Krier@Sun.COM 	return (B_TRUE);
80811337SWilliam.Krier@Sun.COM }
80911337SWilliam.Krier@Sun.COM 
81011337SWilliam.Krier@Sun.COM /*
81111337SWilliam.Krier@Sun.COM  * smb_validate_dirname
81211337SWilliam.Krier@Sun.COM  *
81311337SWilliam.Krier@Sun.COM  * smb_pathname_validate() should have already been performed on pn.
81411337SWilliam.Krier@Sun.COM  *
81511337SWilliam.Krier@Sun.COM  * Very basic directory name validation:  checks for colons in a path.
81611337SWilliam.Krier@Sun.COM  * Need to skip the drive prefix since it contains a colon.
81711337SWilliam.Krier@Sun.COM  *
81811337SWilliam.Krier@Sun.COM  * Returns: B_TRUE if the name is valid,
81911337SWilliam.Krier@Sun.COM  *          otherwise returns B_FALSE and sets error status in sr.
82011337SWilliam.Krier@Sun.COM  */
82111337SWilliam.Krier@Sun.COM boolean_t
82211337SWilliam.Krier@Sun.COM smb_validate_dirname(smb_request_t *sr, smb_pathname_t *pn)
82311337SWilliam.Krier@Sun.COM {
82411337SWilliam.Krier@Sun.COM 	char *name;
82511337SWilliam.Krier@Sun.COM 	char *path = pn->pn_path;
82611337SWilliam.Krier@Sun.COM 
82711337SWilliam.Krier@Sun.COM 	if ((name = path) != 0) {
82811337SWilliam.Krier@Sun.COM 		name += strspn(name, "\\");
82911337SWilliam.Krier@Sun.COM 
83011337SWilliam.Krier@Sun.COM 		if (strchr(name, ':') != 0) {
83111337SWilliam.Krier@Sun.COM 			smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
83211337SWilliam.Krier@Sun.COM 			    ERRDOS, ERROR_INVALID_NAME);
83311337SWilliam.Krier@Sun.COM 			return (B_FALSE);
83411337SWilliam.Krier@Sun.COM 		}
83511337SWilliam.Krier@Sun.COM 	}
83611337SWilliam.Krier@Sun.COM 
83711337SWilliam.Krier@Sun.COM 	return (B_TRUE);
83811337SWilliam.Krier@Sun.COM }
83911337SWilliam.Krier@Sun.COM 
84011337SWilliam.Krier@Sun.COM /*
84111337SWilliam.Krier@Sun.COM  * smb_validate_object_name
84211337SWilliam.Krier@Sun.COM  *
84311337SWilliam.Krier@Sun.COM  * smb_pathname_validate() should have already been pertformed on pn.
84411337SWilliam.Krier@Sun.COM  *
84511337SWilliam.Krier@Sun.COM  * Very basic file name validation.
84611337SWilliam.Krier@Sun.COM  * For filenames, we check for names of the form "AAAn:". Names that
84711337SWilliam.Krier@Sun.COM  * contain three characters, a single digit and a colon (:) are reserved
84811337SWilliam.Krier@Sun.COM  * as DOS device names, i.e. "COM1:".
84911337SWilliam.Krier@Sun.COM  * Stream name validation is handed off to smb_validate_stream_name
85011337SWilliam.Krier@Sun.COM  *
85111337SWilliam.Krier@Sun.COM  * Returns: B_TRUE if pn->pn_fname is valid,
85211337SWilliam.Krier@Sun.COM  *          otherwise returns B_FALSE and sets error status in sr.
85311337SWilliam.Krier@Sun.COM  */
85411337SWilliam.Krier@Sun.COM boolean_t
85511337SWilliam.Krier@Sun.COM smb_validate_object_name(smb_request_t *sr, smb_pathname_t *pn)
85611337SWilliam.Krier@Sun.COM {
85711337SWilliam.Krier@Sun.COM 	if (pn->pn_fname &&
85811337SWilliam.Krier@Sun.COM 	    strlen(pn->pn_fname) == 5 &&
85911337SWilliam.Krier@Sun.COM 	    smb_isdigit(pn->pn_fname[3]) &&
86011337SWilliam.Krier@Sun.COM 	    pn->pn_fname[4] == ':') {
86111337SWilliam.Krier@Sun.COM 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
86211337SWilliam.Krier@Sun.COM 		    ERRDOS, ERROR_INVALID_NAME);
86311337SWilliam.Krier@Sun.COM 		return (B_FALSE);
86411337SWilliam.Krier@Sun.COM 	}
86511337SWilliam.Krier@Sun.COM 
86611337SWilliam.Krier@Sun.COM 	if (pn->pn_sname)
86711337SWilliam.Krier@Sun.COM 		return (smb_validate_stream_name(sr, pn));
86811337SWilliam.Krier@Sun.COM 
86911337SWilliam.Krier@Sun.COM 	return (B_TRUE);
87011337SWilliam.Krier@Sun.COM }
87111337SWilliam.Krier@Sun.COM 
87211337SWilliam.Krier@Sun.COM /*
87311337SWilliam.Krier@Sun.COM  * smb_stream_parse_name
87411337SWilliam.Krier@Sun.COM  *
87511337SWilliam.Krier@Sun.COM  * smb_stream_parse_name should only be called for a path that
87611337SWilliam.Krier@Sun.COM  * contains a valid named stream.  Path validation should have
87711337SWilliam.Krier@Sun.COM  * been performed before this function is called.
87811337SWilliam.Krier@Sun.COM  *
87911337SWilliam.Krier@Sun.COM  * Find the last component of path and split it into filename
88011337SWilliam.Krier@Sun.COM  * and stream name.
88111337SWilliam.Krier@Sun.COM  *
88211337SWilliam.Krier@Sun.COM  * On return the named stream type will be present.  The stream
88311337SWilliam.Krier@Sun.COM  * type defaults to ":$DATA", if it has not been defined
88411337SWilliam.Krier@Sun.COM  * For exmaple, 'stream' contains :<sname>:$DATA
88511337SWilliam.Krier@Sun.COM  */
88611337SWilliam.Krier@Sun.COM void
88711337SWilliam.Krier@Sun.COM smb_stream_parse_name(char *path, char *filename, char *stream)
88811337SWilliam.Krier@Sun.COM {
88911337SWilliam.Krier@Sun.COM 	char *fname, *sname, *stype;
89011337SWilliam.Krier@Sun.COM 
89111337SWilliam.Krier@Sun.COM 	ASSERT(path);
89211337SWilliam.Krier@Sun.COM 	ASSERT(filename);
89311337SWilliam.Krier@Sun.COM 	ASSERT(stream);
89411337SWilliam.Krier@Sun.COM 
89511337SWilliam.Krier@Sun.COM 	fname = strrchr(path, '\\');
89611337SWilliam.Krier@Sun.COM 	fname = (fname == NULL) ? path : fname + 1;
89711337SWilliam.Krier@Sun.COM 	(void) strlcpy(filename, fname, MAXNAMELEN);
89811337SWilliam.Krier@Sun.COM 
89911337SWilliam.Krier@Sun.COM 	sname = strchr(filename, ':');
90011337SWilliam.Krier@Sun.COM 	(void) strlcpy(stream, sname, MAXNAMELEN);
90111337SWilliam.Krier@Sun.COM 	*sname = '\0';
90211337SWilliam.Krier@Sun.COM 
90311337SWilliam.Krier@Sun.COM 	stype = strchr(stream + 1, ':');
90411337SWilliam.Krier@Sun.COM 	if (stype == NULL)
90511337SWilliam.Krier@Sun.COM 		(void) strlcat(stream, ":$DATA", MAXNAMELEN);
90611337SWilliam.Krier@Sun.COM 	else
90711337SWilliam.Krier@Sun.COM 		(void) smb_strupr(stype);
90811337SWilliam.Krier@Sun.COM }
90911337SWilliam.Krier@Sun.COM 
91011337SWilliam.Krier@Sun.COM /*
91111337SWilliam.Krier@Sun.COM  * smb_is_stream_name
91211337SWilliam.Krier@Sun.COM  *
91311337SWilliam.Krier@Sun.COM  * Determines if 'path' specifies a named stream.
91411337SWilliam.Krier@Sun.COM  *
91511337SWilliam.Krier@Sun.COM  * path is a NULL terminated string which could be a stream path.
91611337SWilliam.Krier@Sun.COM  * [pathname/]fname[:stream_name[:stream_type]]
91711337SWilliam.Krier@Sun.COM  *
91811337SWilliam.Krier@Sun.COM  * - If there is no colon in the path or it's the last char
91911337SWilliam.Krier@Sun.COM  *   then it's not a stream name
92011337SWilliam.Krier@Sun.COM  *
92111337SWilliam.Krier@Sun.COM  * - '::' is a non-stream and is commonly used by Windows to designate
92211337SWilliam.Krier@Sun.COM  *   the unamed stream in the form "::$DATA"
92311337SWilliam.Krier@Sun.COM  */
92411337SWilliam.Krier@Sun.COM boolean_t
92511337SWilliam.Krier@Sun.COM smb_is_stream_name(char *path)
92611337SWilliam.Krier@Sun.COM {
92711337SWilliam.Krier@Sun.COM 	char *colonp;
92811337SWilliam.Krier@Sun.COM 
92911337SWilliam.Krier@Sun.COM 	if (path == NULL)
93011337SWilliam.Krier@Sun.COM 		return (B_FALSE);
93111337SWilliam.Krier@Sun.COM 
93211337SWilliam.Krier@Sun.COM 	colonp = strchr(path, ':');
93311337SWilliam.Krier@Sun.COM 	if ((colonp == NULL) || (*(colonp+1) == '\0'))
93411337SWilliam.Krier@Sun.COM 		return (B_FALSE);
93511337SWilliam.Krier@Sun.COM 
93611337SWilliam.Krier@Sun.COM 	if (strstr(path, "::"))
93711337SWilliam.Krier@Sun.COM 		return (B_FALSE);
93811337SWilliam.Krier@Sun.COM 
93911337SWilliam.Krier@Sun.COM 	return (B_TRUE);
94011337SWilliam.Krier@Sun.COM }
94111337SWilliam.Krier@Sun.COM 
94211337SWilliam.Krier@Sun.COM /*
94311337SWilliam.Krier@Sun.COM  * smb_validate_stream_name
94411337SWilliam.Krier@Sun.COM  *
94511337SWilliam.Krier@Sun.COM  * B_FALSE will be returned, and the error status ser in the sr, if:
94611337SWilliam.Krier@Sun.COM  * - the path is not a stream name
94711337SWilliam.Krier@Sun.COM  * - a path is specified but the fname is ommitted.
94811337SWilliam.Krier@Sun.COM  * - the stream_type is specified but not valid.
94911337SWilliam.Krier@Sun.COM  *
95011337SWilliam.Krier@Sun.COM  * Note: the stream type is case-insensitive.
95111337SWilliam.Krier@Sun.COM  */
95211337SWilliam.Krier@Sun.COM boolean_t
95311337SWilliam.Krier@Sun.COM smb_validate_stream_name(smb_request_t *sr, smb_pathname_t *pn)
95411337SWilliam.Krier@Sun.COM {
95511337SWilliam.Krier@Sun.COM 	static char *strmtype[] = {
95611337SWilliam.Krier@Sun.COM 		"$DATA",
95711337SWilliam.Krier@Sun.COM 		"$INDEX_ALLOCATION"
95811337SWilliam.Krier@Sun.COM 	};
95911337SWilliam.Krier@Sun.COM 	int i;
96011337SWilliam.Krier@Sun.COM 
96111337SWilliam.Krier@Sun.COM 	ASSERT(pn);
96211337SWilliam.Krier@Sun.COM 	ASSERT(pn->pn_sname);
96311337SWilliam.Krier@Sun.COM 
96411337SWilliam.Krier@Sun.COM 	if ((!(pn->pn_sname)) ||
96511337SWilliam.Krier@Sun.COM 	    ((pn->pn_pname) && !(pn->pn_fname))) {
96611337SWilliam.Krier@Sun.COM 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
96711337SWilliam.Krier@Sun.COM 		    ERRDOS, ERROR_INVALID_NAME);
96811337SWilliam.Krier@Sun.COM 		return (B_FALSE);
96911337SWilliam.Krier@Sun.COM 	}
97011337SWilliam.Krier@Sun.COM 
97111337SWilliam.Krier@Sun.COM 
97211337SWilliam.Krier@Sun.COM 	if (pn->pn_stype != NULL) {
97311337SWilliam.Krier@Sun.COM 		for (i = 0; i < sizeof (strmtype) / sizeof (strmtype[0]); ++i) {
97411337SWilliam.Krier@Sun.COM 			if (strcasecmp(pn->pn_stype, strmtype[i]) == 0)
97511337SWilliam.Krier@Sun.COM 				return (B_TRUE);
97611337SWilliam.Krier@Sun.COM 		}
97711337SWilliam.Krier@Sun.COM 
97811337SWilliam.Krier@Sun.COM 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
97911337SWilliam.Krier@Sun.COM 		    ERRDOS, ERROR_INVALID_NAME);
98011337SWilliam.Krier@Sun.COM 		return (B_FALSE);
98111337SWilliam.Krier@Sun.COM 	}
98211337SWilliam.Krier@Sun.COM 
98311337SWilliam.Krier@Sun.COM 	return (B_TRUE);
98411337SWilliam.Krier@Sun.COM }
985