xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_pathname.c (revision a90cf9f29973990687fa61de9f1f6ea22e924e40)
1fe1c642dSBill Krier /*
2fe1c642dSBill Krier  * CDDL HEADER START
3fe1c642dSBill Krier  *
4fe1c642dSBill Krier  * The contents of this file are subject to the terms of the
5fe1c642dSBill Krier  * Common Development and Distribution License (the "License").
6fe1c642dSBill Krier  * You may not use this file except in compliance with the License.
7fe1c642dSBill Krier  *
8fe1c642dSBill Krier  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fe1c642dSBill Krier  * or http://www.opensolaris.org/os/licensing.
10fe1c642dSBill Krier  * See the License for the specific language governing permissions
11fe1c642dSBill Krier  * and limitations under the License.
12fe1c642dSBill Krier  *
13fe1c642dSBill Krier  * When distributing Covered Code, include this CDDL HEADER in each
14fe1c642dSBill Krier  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fe1c642dSBill Krier  * If applicable, add the following below this CDDL HEADER, with the
16fe1c642dSBill Krier  * fields enclosed by brackets "[]" replaced with your own identifying
17fe1c642dSBill Krier  * information: Portions Copyright [yyyy] [name of copyright owner]
18fe1c642dSBill Krier  *
19fe1c642dSBill Krier  * CDDL HEADER END
20fe1c642dSBill Krier  */
21fe1c642dSBill Krier /*
22148c5f43SAlan Wright  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23*a90cf9f2SGordon Ross  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
24fe1c642dSBill Krier  */
25fe1c642dSBill Krier 
26fe1c642dSBill Krier #include <smbsrv/smb_kproto.h>
27fe1c642dSBill Krier #include <smbsrv/smb_fsops.h>
28fe1c642dSBill Krier #include <sys/pathname.h>
29fe1c642dSBill Krier #include <sys/sdt.h>
30fe1c642dSBill Krier 
31fe1c642dSBill Krier static char *smb_pathname_catia_v5tov4(smb_request_t *, char *, char *, int);
32fe1c642dSBill Krier static char *smb_pathname_catia_v4tov5(smb_request_t *, char *, char *, int);
33fe1c642dSBill Krier static int smb_pathname_lookup(pathname_t *, pathname_t *, int,
349fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States     vnode_t **, vnode_t *, vnode_t *, smb_attr_t *attr, cred_t *);
35fe1c642dSBill Krier static char *smb_pathname_strdup(smb_request_t *, const char *);
36fe1c642dSBill Krier static char *smb_pathname_strcat(smb_request_t *, char *, const char *);
37fe1c642dSBill Krier static void smb_pathname_preprocess(smb_request_t *, smb_pathname_t *);
389fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void smb_pathname_preprocess_quota(smb_request_t *, smb_pathname_t *);
399fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static int smb_pathname_dfs_preprocess(smb_request_t *, char *, size_t);
409fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void smb_pathname_preprocess_adminshare(smb_request_t *,
419fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States     smb_pathname_t *);
429fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
43fe1c642dSBill Krier 
44fe1c642dSBill Krier uint32_t
45fe1c642dSBill Krier smb_is_executable(char *path)
46fe1c642dSBill Krier {
47fe1c642dSBill Krier 	char	extension[5];
48fe1c642dSBill Krier 	int	len = strlen(path);
49fe1c642dSBill Krier 
50fe1c642dSBill Krier 	if ((len >= 4) && (path[len - 4] == '.')) {
51fe1c642dSBill Krier 		(void) strcpy(extension, &path[len - 3]);
52fe1c642dSBill Krier 		(void) smb_strupr(extension);
53fe1c642dSBill Krier 
54fe1c642dSBill Krier 		if (strcmp(extension, "EXE") == 0)
55fe1c642dSBill Krier 			return (NODE_FLAGS_EXECUTABLE);
56fe1c642dSBill Krier 
57fe1c642dSBill Krier 		if (strcmp(extension, "COM") == 0)
58fe1c642dSBill Krier 			return (NODE_FLAGS_EXECUTABLE);
59fe1c642dSBill Krier 
60fe1c642dSBill Krier 		if (strcmp(extension, "DLL") == 0)
61fe1c642dSBill Krier 			return (NODE_FLAGS_EXECUTABLE);
62fe1c642dSBill Krier 
63fe1c642dSBill Krier 		if (strcmp(extension, "SYM") == 0)
64fe1c642dSBill Krier 			return (NODE_FLAGS_EXECUTABLE);
65fe1c642dSBill Krier 	}
66fe1c642dSBill Krier 
67fe1c642dSBill Krier 	return (0);
68fe1c642dSBill Krier }
69fe1c642dSBill Krier 
70fe1c642dSBill Krier /*
71fe1c642dSBill Krier  * smb_pathname_reduce
72fe1c642dSBill Krier  *
73fe1c642dSBill Krier  * smb_pathname_reduce() takes a path and returns the smb_node for the
74fe1c642dSBill Krier  * second-to-last component of the path.  It also returns the name of the last
75fe1c642dSBill Krier  * component.  Pointers for both of these fields must be supplied by the caller.
76fe1c642dSBill Krier  *
77fe1c642dSBill Krier  * Upon success, 0 is returned.
78fe1c642dSBill Krier  *
79fe1c642dSBill Krier  * Upon error, *dir_node will be set to 0.
80fe1c642dSBill Krier  *
81fe1c642dSBill Krier  * *sr (in)
82fe1c642dSBill Krier  * ---
83fe1c642dSBill Krier  * smb_request structure pointer
84fe1c642dSBill Krier  *
85fe1c642dSBill Krier  * *cred (in)
86fe1c642dSBill Krier  * -----
87fe1c642dSBill Krier  * credential
88fe1c642dSBill Krier  *
89fe1c642dSBill Krier  * *path (in)
90fe1c642dSBill Krier  * -----
91fe1c642dSBill Krier  * pathname to be looked up
92fe1c642dSBill Krier  *
93fe1c642dSBill Krier  * *share_root_node (in)
94fe1c642dSBill Krier  * ----------------
95fe1c642dSBill Krier  * File operations which are share-relative should pass sr->tid_tree->t_snode.
96fe1c642dSBill Krier  * If the call is not for a share-relative operation, this parameter must be 0
97fe1c642dSBill Krier  * (e.g. the call from smbsr_setup_share()).  (Such callers will have path
98fe1c642dSBill Krier  * operations done using root_smb_node.)  This parameter is used to determine
99fe1c642dSBill Krier  * whether mount points can be crossed.
100fe1c642dSBill Krier  *
101fe1c642dSBill Krier  * share_root_node should have at least one reference on it.  This reference
102fe1c642dSBill Krier  * will stay intact throughout this routine.
103fe1c642dSBill Krier  *
104fe1c642dSBill Krier  * *cur_node (in)
105fe1c642dSBill Krier  * ---------
106fe1c642dSBill Krier  * The smb_node for the current directory (for relative paths).
107fe1c642dSBill Krier  * cur_node should have at least one reference on it.
108fe1c642dSBill Krier  * This reference will stay intact throughout this routine.
109fe1c642dSBill Krier  *
110fe1c642dSBill Krier  * **dir_node (out)
111fe1c642dSBill Krier  * ----------
112fe1c642dSBill Krier  * Directory for the penultimate component of the original path.
113fe1c642dSBill Krier  * (Note that this is not the same as the parent directory of the ultimate
114fe1c642dSBill Krier  * target in the case of a link.)
115fe1c642dSBill Krier  *
116fe1c642dSBill Krier  * The directory smb_node is returned held.  The caller will need to release
117fe1c642dSBill Krier  * the hold or otherwise make sure it will get released (e.g. in a destroy
118fe1c642dSBill Krier  * routine if made part of a global structure).
119fe1c642dSBill Krier  *
120fe1c642dSBill Krier  * last_component (out)
121fe1c642dSBill Krier  * --------------
122fe1c642dSBill Krier  * The last component of the path.  (This may be different from the name of any
123fe1c642dSBill Krier  * link target to which the last component may resolve.)
124fe1c642dSBill Krier  *
125fe1c642dSBill Krier  *
126fe1c642dSBill Krier  * ____________________________
127fe1c642dSBill Krier  *
128fe1c642dSBill Krier  * The CIFS server lookup path needs to have logic equivalent to that of
129fe1c642dSBill Krier  * smb_fsop_lookup(), smb_vop_lookup() and other smb_vop_*() routines in the
130fe1c642dSBill Krier  * following areas:
131fe1c642dSBill Krier  *
1325f1ef25cSAram Hăvărneanu  *	- traversal of child mounts (handled by smb_pathname_reduce)
133fe1c642dSBill Krier  *	- unmangling                (handled in smb_pathname)
134fe1c642dSBill Krier  *	- "chroot" behavior of share root (handled by lookuppnvp)
135fe1c642dSBill Krier  *
136fe1c642dSBill Krier  * In addition, it needs to replace backslashes with forward slashes.  It also
137fe1c642dSBill Krier  * ensures that link processing is done correctly, and that directory
138fe1c642dSBill Krier  * information requested by the caller is correctly returned (i.e. for paths
139fe1c642dSBill Krier  * with a link in the last component, the directory information of the
140fe1c642dSBill Krier  * link and not the target needs to be returned).
141fe1c642dSBill Krier  */
142fe1c642dSBill Krier 
143fe1c642dSBill Krier int
144fe1c642dSBill Krier smb_pathname_reduce(
145fe1c642dSBill Krier     smb_request_t	*sr,
146fe1c642dSBill Krier     cred_t		*cred,
147fe1c642dSBill Krier     const char		*path,
148fe1c642dSBill Krier     smb_node_t		*share_root_node,
149fe1c642dSBill Krier     smb_node_t		*cur_node,
150fe1c642dSBill Krier     smb_node_t		**dir_node,
151fe1c642dSBill Krier     char		*last_component)
152fe1c642dSBill Krier {
153fe1c642dSBill Krier 	smb_node_t	*root_node;
154fe1c642dSBill Krier 	pathname_t	ppn;
155fe1c642dSBill Krier 	char		*usepath;
156fe1c642dSBill Krier 	int		lookup_flags = FOLLOW;
157fe1c642dSBill Krier 	int 		trailing_slash = 0;
158fe1c642dSBill Krier 	int		err = 0;
159fe1c642dSBill Krier 	int		len;
160fe1c642dSBill Krier 	smb_node_t	*vss_cur_node;
161fe1c642dSBill Krier 	smb_node_t	*vss_root_node;
162fe1c642dSBill Krier 	smb_node_t	*local_cur_node;
163fe1c642dSBill Krier 	smb_node_t	*local_root_node;
164fe1c642dSBill Krier 
165fe1c642dSBill Krier 	ASSERT(dir_node);
166fe1c642dSBill Krier 	ASSERT(last_component);
167fe1c642dSBill Krier 
168fe1c642dSBill Krier 	*dir_node = NULL;
169fe1c642dSBill Krier 	*last_component = '\0';
170fe1c642dSBill Krier 	vss_cur_node = NULL;
171fe1c642dSBill Krier 	vss_root_node = NULL;
172fe1c642dSBill Krier 
173fe1c642dSBill Krier 	if (sr && sr->tid_tree) {
174f96bd5c8SAlan Wright 		if (STYPE_ISIPC(sr->tid_tree->t_res_type))
175fe1c642dSBill Krier 			return (EACCES);
176fe1c642dSBill Krier 	}
177fe1c642dSBill Krier 
178fe1c642dSBill Krier 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
179fe1c642dSBill Krier 		lookup_flags |= FIGNORECASE;
180fe1c642dSBill Krier 
181fe1c642dSBill Krier 	if (path == NULL)
182fe1c642dSBill Krier 		return (EINVAL);
183fe1c642dSBill Krier 
184fe1c642dSBill Krier 	if (*path == '\0')
185fe1c642dSBill Krier 		return (ENOENT);
186fe1c642dSBill Krier 
187b24e356bSPeer Dampmann 	usepath = kmem_alloc(SMB_MAXPATHLEN, KM_SLEEP);
188fe1c642dSBill Krier 
189b24e356bSPeer Dampmann 	len = strlcpy(usepath, path, SMB_MAXPATHLEN);
190b24e356bSPeer Dampmann 	if (len >= SMB_MAXPATHLEN) {
191b24e356bSPeer Dampmann 		kmem_free(usepath, SMB_MAXPATHLEN);
192fe1c642dSBill Krier 		return (ENAMETOOLONG);
193fe1c642dSBill Krier 	}
194fe1c642dSBill Krier 
195fe1c642dSBill Krier 	(void) strsubst(usepath, '\\', '/');
196fe1c642dSBill Krier 
197fe1c642dSBill Krier 	if (share_root_node)
198fe1c642dSBill Krier 		root_node = share_root_node;
199fe1c642dSBill Krier 	else
200fe1c642dSBill Krier 		root_node = sr->sr_server->si_root_smb_node;
201fe1c642dSBill Krier 
202fe1c642dSBill Krier 	if (cur_node == NULL)
203fe1c642dSBill Krier 		cur_node = root_node;
204fe1c642dSBill Krier 
205fe1c642dSBill Krier 	local_cur_node = cur_node;
206fe1c642dSBill Krier 	local_root_node = root_node;
207fe1c642dSBill Krier 
208*a90cf9f2SGordon Ross 	if (SMB_TREE_IS_DFSROOT(sr)) {
209*a90cf9f2SGordon Ross 		int is_dfs;
210*a90cf9f2SGordon Ross 		if (sr->session->dialect >= SMB_VERS_2_BASE)
211*a90cf9f2SGordon Ross 			is_dfs = sr->smb2_hdr_flags &
212*a90cf9f2SGordon Ross 			    SMB2_FLAGS_DFS_OPERATIONS;
213*a90cf9f2SGordon Ross 		else
214*a90cf9f2SGordon Ross 			is_dfs = sr->smb_flg2 & SMB_FLAGS2_DFS;
215*a90cf9f2SGordon Ross 		if (is_dfs != 0) {
216*a90cf9f2SGordon Ross 			err = smb_pathname_dfs_preprocess(sr, usepath,
217*a90cf9f2SGordon Ross 			    SMB_MAXPATHLEN);
2189fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			if (err != 0) {
219b24e356bSPeer Dampmann 				kmem_free(usepath, SMB_MAXPATHLEN);
2209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 				return (err);
2219fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			}
2229fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			len = strlen(usepath);
2239fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		}
224*a90cf9f2SGordon Ross 	}
2259fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
226*a90cf9f2SGordon Ross 	if (sr != NULL) {
227*a90cf9f2SGordon Ross 		boolean_t chk_vss;
228*a90cf9f2SGordon Ross 		if (sr->session->dialect >= SMB_VERS_2_BASE)
229*a90cf9f2SGordon Ross 			chk_vss = sr->arg.open.create_timewarp;
230*a90cf9f2SGordon Ross 		else
231*a90cf9f2SGordon Ross 			chk_vss = (sr->smb_flg2 &
232*a90cf9f2SGordon Ross 			    SMB_FLAGS2_REPARSE_PATH) != 0;
233*a90cf9f2SGordon Ross 		if (chk_vss) {
234fe1c642dSBill Krier 			err = smb_vss_lookup_nodes(sr, root_node, cur_node,
235fe1c642dSBill Krier 			    usepath, &vss_cur_node, &vss_root_node);
236fe1c642dSBill Krier 			if (err != 0) {
237*a90cf9f2SGordon Ross 				kmem_free(usepath, SMB_MAXPATHLEN);
238fe1c642dSBill Krier 				return (err);
239fe1c642dSBill Krier 			}
240fe1c642dSBill Krier 
241fe1c642dSBill Krier 			len = strlen(usepath);
242fe1c642dSBill Krier 			local_cur_node = vss_cur_node;
243fe1c642dSBill Krier 			local_root_node = vss_root_node;
244fe1c642dSBill Krier 		}
245*a90cf9f2SGordon Ross 	}
246fe1c642dSBill Krier 
247fe1c642dSBill Krier 	if (usepath[len - 1] == '/')
248fe1c642dSBill Krier 		trailing_slash = 1;
249fe1c642dSBill Krier 
250fe1c642dSBill Krier 	(void) strcanon(usepath, "/");
251fe1c642dSBill Krier 
252b24e356bSPeer Dampmann 	(void) pn_alloc_sz(&ppn, SMB_MAXPATHLEN);
253fe1c642dSBill Krier 
254fe1c642dSBill Krier 	if ((err = pn_set(&ppn, usepath)) != 0) {
255fe1c642dSBill Krier 		(void) pn_free(&ppn);
256b24e356bSPeer Dampmann 		kmem_free(usepath, SMB_MAXPATHLEN);
257fe1c642dSBill Krier 		if (vss_cur_node != NULL)
258fe1c642dSBill Krier 			(void) smb_node_release(vss_cur_node);
259fe1c642dSBill Krier 		if (vss_root_node != NULL)
260fe1c642dSBill Krier 			(void) smb_node_release(vss_root_node);
261fe1c642dSBill Krier 		return (err);
262fe1c642dSBill Krier 	}
263fe1c642dSBill Krier 
264fe1c642dSBill Krier 	/*
265fe1c642dSBill Krier 	 * If a path does not have a trailing slash, strip off the
266fe1c642dSBill Krier 	 * last component.  (We only need to return an smb_node for
267fe1c642dSBill Krier 	 * the second to last component; a name is returned for the
268fe1c642dSBill Krier 	 * last component.)
269fe1c642dSBill Krier 	 */
270fe1c642dSBill Krier 
271fe1c642dSBill Krier 	if (trailing_slash) {
272fe1c642dSBill Krier 		(void) strlcpy(last_component, ".", MAXNAMELEN);
273fe1c642dSBill Krier 	} else {
274fe1c642dSBill Krier 		(void) pn_setlast(&ppn);
275fe1c642dSBill Krier 		(void) strlcpy(last_component, ppn.pn_path, MAXNAMELEN);
276fe1c642dSBill Krier 		ppn.pn_path[0] = '\0';
277fe1c642dSBill Krier 	}
278fe1c642dSBill Krier 
279fe1c642dSBill Krier 	if ((strcmp(ppn.pn_buf, "/") == 0) || (ppn.pn_buf[0] == '\0')) {
280fe1c642dSBill Krier 		smb_node_ref(local_cur_node);
281fe1c642dSBill Krier 		*dir_node = local_cur_node;
282fe1c642dSBill Krier 	} else {
283fe1c642dSBill Krier 		err = smb_pathname(sr, ppn.pn_buf, lookup_flags,
284fe1c642dSBill Krier 		    local_root_node, local_cur_node, NULL, dir_node, cred);
285fe1c642dSBill Krier 	}
286fe1c642dSBill Krier 
287fe1c642dSBill Krier 	(void) pn_free(&ppn);
288b24e356bSPeer Dampmann 	kmem_free(usepath, SMB_MAXPATHLEN);
289fe1c642dSBill Krier 
290fe1c642dSBill Krier 	/*
2915f1ef25cSAram Hăvărneanu 	 * Prevent traversal to another file system if mount point
2925f1ef25cSAram Hăvărneanu 	 * traversal is disabled.
293fe1c642dSBill Krier 	 *
294fe1c642dSBill Krier 	 * Note that we disregard whether the traversal of the path went
295fe1c642dSBill Krier 	 * outside of the file system and then came back (say via a link).
2965f1ef25cSAram Hăvărneanu 	 * This means that only symlinks that are expressed relatively to
2975f1ef25cSAram Hăvărneanu 	 * the share root work.
2985f1ef25cSAram Hăvărneanu 	 *
2995f1ef25cSAram Hăvărneanu 	 * share_root_node is NULL when mapping a share, so we disregard
3005f1ef25cSAram Hăvărneanu 	 * that case.
301fe1c642dSBill Krier 	 */
302fe1c642dSBill Krier 
303fe1c642dSBill Krier 	if ((err == 0) && share_root_node) {
3045f1ef25cSAram Hăvărneanu 		if (share_root_node->vp->v_vfsp != (*dir_node)->vp->v_vfsp) {
305fe1c642dSBill Krier 			err = EACCES;
3065f1ef25cSAram Hăvărneanu 			if ((sr) && (sr)->tid_tree &&
3075f1ef25cSAram Hăvărneanu 			    smb_tree_has_feature((sr)->tid_tree,
3085f1ef25cSAram Hăvărneanu 			    SMB_TREE_TRAVERSE_MOUNTS))
3095f1ef25cSAram Hăvărneanu 				err = 0;
3105f1ef25cSAram Hăvărneanu 		}
311fe1c642dSBill Krier 	}
312fe1c642dSBill Krier 
313fe1c642dSBill Krier 	if (err) {
314fe1c642dSBill Krier 		if (*dir_node) {
315fe1c642dSBill Krier 			(void) smb_node_release(*dir_node);
316fe1c642dSBill Krier 			*dir_node = NULL;
317fe1c642dSBill Krier 		}
318fe1c642dSBill Krier 		*last_component = 0;
319fe1c642dSBill Krier 	}
320fe1c642dSBill Krier 
321fe1c642dSBill Krier 	if (vss_cur_node != NULL)
322fe1c642dSBill Krier 		(void) smb_node_release(vss_cur_node);
323fe1c642dSBill Krier 	if (vss_root_node != NULL)
324fe1c642dSBill Krier 		(void) smb_node_release(vss_root_node);
325fe1c642dSBill Krier 
326fe1c642dSBill Krier 	return (err);
327fe1c642dSBill Krier }
328fe1c642dSBill Krier 
329fe1c642dSBill Krier /*
330fe1c642dSBill Krier  * smb_pathname()
331fe1c642dSBill Krier  * wrapper to lookuppnvp().  Handles name unmangling.
332fe1c642dSBill Krier  *
333fe1c642dSBill Krier  * *dir_node is the true directory of the target *node.
334fe1c642dSBill Krier  *
335fe1c642dSBill Krier  * If any component but the last in the path is not found, ENOTDIR instead of
336fe1c642dSBill Krier  * ENOENT will be returned.
337fe1c642dSBill Krier  *
338fe1c642dSBill Krier  * Path components are processed one at a time so that smb_nodes can be
339fe1c642dSBill Krier  * created for each component.  This allows the n_dnode field in the
340fe1c642dSBill Krier  * smb_node to be properly populated.
341fe1c642dSBill Krier  *
342fe1c642dSBill Krier  * Because of the above, links are also processed in this routine
343fe1c642dSBill Krier  * (i.e., we do not pass the FOLLOW flag to lookuppnvp()).  This
344fe1c642dSBill Krier  * will allow smb_nodes to be created for each component of a link.
345fe1c642dSBill Krier  *
346fe1c642dSBill Krier  * Mangle checking is per component. If a name is mangled, when the
347fe1c642dSBill Krier  * unmangled name is passed to smb_pathname_lookup() do not pass
348fe1c642dSBill Krier  * FIGNORECASE, since the unmangled name is the real on-disk name.
349fe1c642dSBill Krier  * Otherwise pass FIGNORECASE if it's set in flags. This will cause the
350fe1c642dSBill Krier  * file system to return "first match" in the event of a case collision.
351fe1c642dSBill Krier  *
352fe1c642dSBill Krier  * If CATIA character translation is enabled it is applied to each
353fe1c642dSBill Krier  * component before passing the component to smb_pathname_lookup().
354fe1c642dSBill Krier  * After smb_pathname_lookup() the reverse translation is applied.
355fe1c642dSBill Krier  */
356fe1c642dSBill Krier 
357fe1c642dSBill Krier int
358fe1c642dSBill Krier smb_pathname(smb_request_t *sr, char *path, int flags,
359fe1c642dSBill Krier     smb_node_t *root_node, smb_node_t *cur_node, smb_node_t **dir_node,
360fe1c642dSBill Krier     smb_node_t **ret_node, cred_t *cred)
361fe1c642dSBill Krier {
362fe1c642dSBill Krier 	char		*component, *real_name, *namep;
363fe1c642dSBill Krier 	pathname_t	pn, rpn, upn, link_pn;
364fe1c642dSBill Krier 	smb_node_t	*dnode, *fnode;
3659fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_attr_t	attr;
366fe1c642dSBill Krier 	vnode_t		*rootvp, *vp;
367fe1c642dSBill Krier 	size_t		pathleft;
368fe1c642dSBill Krier 	int		err = 0;
369fe1c642dSBill Krier 	int		nlink = 0;
370fe1c642dSBill Krier 	int		local_flags;
371fe1c642dSBill Krier 	uint32_t	abe_flag = 0;
372fe1c642dSBill Krier 	char		namebuf[MAXNAMELEN];
373fe1c642dSBill Krier 
374fe1c642dSBill Krier 	if (path == NULL)
375fe1c642dSBill Krier 		return (EINVAL);
376fe1c642dSBill Krier 
377fe1c642dSBill Krier 	ASSERT(root_node);
378fe1c642dSBill Krier 	ASSERT(cur_node);
379fe1c642dSBill Krier 	ASSERT(ret_node);
380fe1c642dSBill Krier 
381fe1c642dSBill Krier 	*ret_node = NULL;
382fe1c642dSBill Krier 
383fe1c642dSBill Krier 	if (dir_node)
384fe1c642dSBill Krier 		*dir_node = NULL;
385fe1c642dSBill Krier 
386b24e356bSPeer Dampmann 	(void) pn_alloc_sz(&upn, SMB_MAXPATHLEN);
387fe1c642dSBill Krier 
388fe1c642dSBill Krier 	if ((err = pn_set(&upn, path)) != 0) {
389fe1c642dSBill Krier 		(void) pn_free(&upn);
390fe1c642dSBill Krier 		return (err);
391fe1c642dSBill Krier 	}
392fe1c642dSBill Krier 
393fe1c642dSBill Krier 	if (SMB_TREE_SUPPORTS_ABE(sr))
394fe1c642dSBill Krier 		abe_flag = SMB_ABE;
395fe1c642dSBill Krier 
396fe1c642dSBill Krier 	(void) pn_alloc(&pn);
397fe1c642dSBill Krier 	(void) pn_alloc(&rpn);
398fe1c642dSBill Krier 
399fe1c642dSBill Krier 	component = kmem_alloc(MAXNAMELEN, KM_SLEEP);
400fe1c642dSBill Krier 	real_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
401fe1c642dSBill Krier 
402fe1c642dSBill Krier 	fnode = NULL;
403fe1c642dSBill Krier 	dnode = cur_node;
404fe1c642dSBill Krier 	smb_node_ref(dnode);
405fe1c642dSBill Krier 	rootvp = root_node->vp;
406fe1c642dSBill Krier 
407fe1c642dSBill Krier 	while ((pathleft = pn_pathleft(&upn)) != 0) {
408fe1c642dSBill Krier 		if (fnode) {
409fe1c642dSBill Krier 			smb_node_release(dnode);
410fe1c642dSBill Krier 			dnode = fnode;
411fe1c642dSBill Krier 			fnode = NULL;
412fe1c642dSBill Krier 		}
413fe1c642dSBill Krier 
414fe1c642dSBill Krier 		if ((err = pn_getcomponent(&upn, component)) != 0)
415fe1c642dSBill Krier 			break;
416fe1c642dSBill Krier 
417fe1c642dSBill Krier 		if ((namep = smb_pathname_catia_v5tov4(sr, component,
418fe1c642dSBill Krier 		    namebuf, sizeof (namebuf))) == NULL) {
419fe1c642dSBill Krier 			err = EILSEQ;
420fe1c642dSBill Krier 			break;
421fe1c642dSBill Krier 		}
422fe1c642dSBill Krier 
423fe1c642dSBill Krier 		if ((err = pn_set(&pn, namep)) != 0)
424fe1c642dSBill Krier 			break;
425fe1c642dSBill Krier 
426fe1c642dSBill Krier 		local_flags = flags & FIGNORECASE;
427fe1c642dSBill Krier 		err = smb_pathname_lookup(&pn, &rpn, local_flags,
4289fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		    &vp, rootvp, dnode->vp, &attr, cred);
429fe1c642dSBill Krier 
430fe1c642dSBill Krier 		if (err) {
431cb174861Sjoyce mcintosh 			if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) ||
432cb174861Sjoyce mcintosh 			    !smb_maybe_mangled(component))
433fe1c642dSBill Krier 				break;
434fe1c642dSBill Krier 
435148c5f43SAlan Wright 			if ((err = smb_unmangle(dnode, component,
436fe1c642dSBill Krier 			    real_name, MAXNAMELEN, abe_flag)) != 0)
437fe1c642dSBill Krier 				break;
438fe1c642dSBill Krier 
439fe1c642dSBill Krier 			if ((namep = smb_pathname_catia_v5tov4(sr, real_name,
440fe1c642dSBill Krier 			    namebuf, sizeof (namebuf))) == NULL) {
441fe1c642dSBill Krier 				err = EILSEQ;
442fe1c642dSBill Krier 				break;
443fe1c642dSBill Krier 			}
444fe1c642dSBill Krier 
445fe1c642dSBill Krier 			if ((err = pn_set(&pn, namep)) != 0)
446fe1c642dSBill Krier 				break;
447fe1c642dSBill Krier 
448fe1c642dSBill Krier 			local_flags = 0;
449fe1c642dSBill Krier 			err = smb_pathname_lookup(&pn, &rpn, local_flags,
4509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			    &vp, rootvp, dnode->vp, &attr, cred);
451fe1c642dSBill Krier 			if (err)
452fe1c642dSBill Krier 				break;
453fe1c642dSBill Krier 		}
454fe1c642dSBill Krier 
4559fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		/*
4569fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		 * This check MUST be done before symlink check
4579fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		 * since a reparse point is of type VLNK but should
4589fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		 * not be handled like a regular symlink.
4599fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		 */
4609fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		if (attr.sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) {
4619fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			err = EREMOTE;
4629fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			VN_RELE(vp);
4639fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			break;
4649fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		}
4659fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
466fe1c642dSBill Krier 		if ((vp->v_type == VLNK) &&
467fe1c642dSBill Krier 		    ((flags & FOLLOW) || pn_pathleft(&upn))) {
468fe1c642dSBill Krier 
469fe1c642dSBill Krier 			if (++nlink > MAXSYMLINKS) {
470fe1c642dSBill Krier 				err = ELOOP;
471fe1c642dSBill Krier 				VN_RELE(vp);
472fe1c642dSBill Krier 				break;
473fe1c642dSBill Krier 			}
474fe1c642dSBill Krier 
475fe1c642dSBill Krier 			(void) pn_alloc(&link_pn);
476fe1c642dSBill Krier 			err = pn_getsymlink(vp, &link_pn, cred);
477fe1c642dSBill Krier 			VN_RELE(vp);
478fe1c642dSBill Krier 
479fe1c642dSBill Krier 			if (err == 0) {
480fe1c642dSBill Krier 				if (pn_pathleft(&link_pn) == 0)
481fe1c642dSBill Krier 					(void) pn_set(&link_pn, ".");
482fe1c642dSBill Krier 				err = pn_insert(&upn, &link_pn,
483fe1c642dSBill Krier 				    strlen(component));
484fe1c642dSBill Krier 			}
485fe1c642dSBill Krier 			pn_free(&link_pn);
486fe1c642dSBill Krier 
487fe1c642dSBill Krier 			if (err)
488fe1c642dSBill Krier 				break;
489fe1c642dSBill Krier 
490fe1c642dSBill Krier 			if (upn.pn_pathlen == 0) {
491fe1c642dSBill Krier 				err = ENOENT;
492fe1c642dSBill Krier 				break;
493fe1c642dSBill Krier 			}
494fe1c642dSBill Krier 
495fe1c642dSBill Krier 			if (upn.pn_path[0] == '/') {
496fe1c642dSBill Krier 				fnode = root_node;
497fe1c642dSBill Krier 				smb_node_ref(fnode);
498fe1c642dSBill Krier 			}
499fe1c642dSBill Krier 
500fe1c642dSBill Krier 			if (pn_fixslash(&upn))
501fe1c642dSBill Krier 				flags |= FOLLOW;
502fe1c642dSBill Krier 
503fe1c642dSBill Krier 		} else {
504fe1c642dSBill Krier 			if (flags & FIGNORECASE) {
505fe1c642dSBill Krier 				if (strcmp(rpn.pn_path, "/") != 0)
506fe1c642dSBill Krier 					pn_setlast(&rpn);
507fe1c642dSBill Krier 				namep = rpn.pn_path;
508fe1c642dSBill Krier 			} else {
509fe1c642dSBill Krier 				namep = pn.pn_path;
510fe1c642dSBill Krier 			}
511fe1c642dSBill Krier 
512fe1c642dSBill Krier 			namep = smb_pathname_catia_v4tov5(sr, namep,
513fe1c642dSBill Krier 			    namebuf, sizeof (namebuf));
514fe1c642dSBill Krier 
515fe1c642dSBill Krier 			fnode = smb_node_lookup(sr, NULL, cred, vp, namep,
516fe1c642dSBill Krier 			    dnode, NULL);
517fe1c642dSBill Krier 			VN_RELE(vp);
518fe1c642dSBill Krier 
519fe1c642dSBill Krier 			if (fnode == NULL) {
520fe1c642dSBill Krier 				err = ENOMEM;
521fe1c642dSBill Krier 				break;
522fe1c642dSBill Krier 			}
523fe1c642dSBill Krier 		}
524fe1c642dSBill Krier 
525fe1c642dSBill Krier 		while (upn.pn_path[0] == '/') {
526fe1c642dSBill Krier 			upn.pn_path++;
527fe1c642dSBill Krier 			upn.pn_pathlen--;
528fe1c642dSBill Krier 		}
529fe1c642dSBill Krier 
530fe1c642dSBill Krier 	}
531fe1c642dSBill Krier 
532fe1c642dSBill Krier 	if ((pathleft) && (err == ENOENT))
533fe1c642dSBill Krier 		err = ENOTDIR;
534fe1c642dSBill Krier 
535fe1c642dSBill Krier 	if (err) {
536fe1c642dSBill Krier 		if (fnode)
537fe1c642dSBill Krier 			smb_node_release(fnode);
538fe1c642dSBill Krier 		if (dnode)
539fe1c642dSBill Krier 			smb_node_release(dnode);
540fe1c642dSBill Krier 	} else {
541fe1c642dSBill Krier 		*ret_node = fnode;
542fe1c642dSBill Krier 
543fe1c642dSBill Krier 		if (dir_node)
544fe1c642dSBill Krier 			*dir_node = dnode;
545fe1c642dSBill Krier 		else
546fe1c642dSBill Krier 			smb_node_release(dnode);
547fe1c642dSBill Krier 	}
548fe1c642dSBill Krier 
549fe1c642dSBill Krier 	kmem_free(component, MAXNAMELEN);
550fe1c642dSBill Krier 	kmem_free(real_name, MAXNAMELEN);
551fe1c642dSBill Krier 	(void) pn_free(&pn);
552fe1c642dSBill Krier 	(void) pn_free(&rpn);
553fe1c642dSBill Krier 	(void) pn_free(&upn);
554fe1c642dSBill Krier 
555fe1c642dSBill Krier 	return (err);
556fe1c642dSBill Krier }
557fe1c642dSBill Krier 
558fe1c642dSBill Krier /*
559fe1c642dSBill Krier  * Holds on dvp and rootvp (if not rootdir) are required by lookuppnvp()
560fe1c642dSBill Krier  * and will be released within lookuppnvp().
561fe1c642dSBill Krier  */
562fe1c642dSBill Krier static int
563fe1c642dSBill Krier smb_pathname_lookup(pathname_t *pn, pathname_t *rpn, int flags,
5649fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States     vnode_t **vp, vnode_t *rootvp, vnode_t *dvp, smb_attr_t *attr, cred_t *cred)
565fe1c642dSBill Krier {
566fe1c642dSBill Krier 	int err;
567fe1c642dSBill Krier 
568fe1c642dSBill Krier 	*vp = NULL;
569fe1c642dSBill Krier 	VN_HOLD(dvp);
570fe1c642dSBill Krier 	if (rootvp != rootdir)
571fe1c642dSBill Krier 		VN_HOLD(rootvp);
572fe1c642dSBill Krier 
573fe1c642dSBill Krier 	err = lookuppnvp(pn, rpn, flags, NULL, vp, rootvp, dvp, cred);
5749fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if ((err == 0) && (attr != NULL))
5758622ec45SGordon Ross 		(void) smb_vop_getattr(*vp, NULL, attr, 0, zone_kcred());
5769fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
577fe1c642dSBill Krier 	return (err);
578fe1c642dSBill Krier }
579fe1c642dSBill Krier 
580fe1c642dSBill Krier /*
581fe1c642dSBill Krier  * CATIA Translation of a pathname component prior to passing it to lookuppnvp
582fe1c642dSBill Krier  *
583fe1c642dSBill Krier  * If the translated component name contains a '/' NULL is returned.
584fe1c642dSBill Krier  * The caller should treat this as error EILSEQ. It is not valid to
585fe1c642dSBill Krier  * have a directory name with a '/'.
586fe1c642dSBill Krier  */
587fe1c642dSBill Krier static char *
588fe1c642dSBill Krier smb_pathname_catia_v5tov4(smb_request_t *sr, char *name,
589fe1c642dSBill Krier     char *namebuf, int buflen)
590fe1c642dSBill Krier {
591fe1c642dSBill Krier 	char *namep;
592fe1c642dSBill Krier 
593fe1c642dSBill Krier 	if (SMB_TREE_SUPPORTS_CATIA(sr)) {
594fe1c642dSBill Krier 		namep = smb_vop_catia_v5tov4(name, namebuf, buflen);
595fe1c642dSBill Krier 		if (strchr(namep, '/') != NULL)
596fe1c642dSBill Krier 			return (NULL);
597fe1c642dSBill Krier 		return (namep);
598fe1c642dSBill Krier 	}
599fe1c642dSBill Krier 
600fe1c642dSBill Krier 	return (name);
601fe1c642dSBill Krier }
602fe1c642dSBill Krier 
603fe1c642dSBill Krier /*
604fe1c642dSBill Krier  * CATIA translation of a pathname component after returning from lookuppnvp
605fe1c642dSBill Krier  */
606fe1c642dSBill Krier static char *
607fe1c642dSBill Krier smb_pathname_catia_v4tov5(smb_request_t *sr, char *name,
608fe1c642dSBill Krier     char *namebuf, int buflen)
609fe1c642dSBill Krier {
610fe1c642dSBill Krier 	if (SMB_TREE_SUPPORTS_CATIA(sr)) {
611fe1c642dSBill Krier 		smb_vop_catia_v4tov5(name, namebuf, buflen);
612fe1c642dSBill Krier 		return (namebuf);
613fe1c642dSBill Krier 	}
614fe1c642dSBill Krier 
615fe1c642dSBill Krier 	return (name);
616fe1c642dSBill Krier }
617fe1c642dSBill Krier 
618fe1c642dSBill Krier /*
619fe1c642dSBill Krier  * sr - needed to check for case sense
620fe1c642dSBill Krier  * path - non mangled path needed to be looked up from the startvp
621fe1c642dSBill Krier  * startvp - the vnode to start the lookup from
622fe1c642dSBill Krier  * rootvp - the vnode of the root of the filesystem
623fe1c642dSBill Krier  * returns the vnode found when starting at startvp and using the path
624fe1c642dSBill Krier  *
625fe1c642dSBill Krier  * Finds a vnode starting at startvp and parsing the non mangled path
626fe1c642dSBill Krier  */
627fe1c642dSBill Krier 
628fe1c642dSBill Krier vnode_t *
629fe1c642dSBill Krier smb_lookuppathvptovp(smb_request_t *sr, char *path, vnode_t *startvp,
630fe1c642dSBill Krier     vnode_t *rootvp)
631fe1c642dSBill Krier {
632fe1c642dSBill Krier 	pathname_t pn;
633fe1c642dSBill Krier 	vnode_t *vp = NULL;
634fe1c642dSBill Krier 	int lookup_flags = FOLLOW;
635fe1c642dSBill Krier 
636fe1c642dSBill Krier 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
637fe1c642dSBill Krier 		lookup_flags |= FIGNORECASE;
638fe1c642dSBill Krier 
639fe1c642dSBill Krier 	(void) pn_alloc(&pn);
640fe1c642dSBill Krier 
641fe1c642dSBill Krier 	if (pn_set(&pn, path) == 0) {
642fe1c642dSBill Krier 		VN_HOLD(startvp);
643fe1c642dSBill Krier 		if (rootvp != rootdir)
644fe1c642dSBill Krier 			VN_HOLD(rootvp);
645fe1c642dSBill Krier 
646fe1c642dSBill Krier 		/* lookuppnvp should release the holds */
647fe1c642dSBill Krier 		if (lookuppnvp(&pn, NULL, lookup_flags, NULL, &vp,
6488622ec45SGordon Ross 		    rootvp, startvp, zone_kcred()) != 0) {
649fe1c642dSBill Krier 			pn_free(&pn);
650fe1c642dSBill Krier 			return (NULL);
651fe1c642dSBill Krier 		}
652fe1c642dSBill Krier 	}
653fe1c642dSBill Krier 
654fe1c642dSBill Krier 	pn_free(&pn);
655fe1c642dSBill Krier 	return (vp);
656fe1c642dSBill Krier }
657fe1c642dSBill Krier 
658fe1c642dSBill Krier /*
659fe1c642dSBill Krier  * smb_pathname_init
660fe1c642dSBill Krier  * Parse path: pname\\fname:sname:stype
661fe1c642dSBill Krier  *
662fe1c642dSBill Krier  * Elements of the smb_pathname_t structure are allocated using request
663fe1c642dSBill Krier  * specific storage and will be free'd when the sr is destroyed.
664fe1c642dSBill Krier  *
665fe1c642dSBill Krier  * Populate pn structure elements with the individual elements
666fe1c642dSBill Krier  * of pn->pn_path. pn->pn_sname will contain the whole stream name
667fe1c642dSBill Krier  * including the stream type and preceding colon: :sname:%DATA
668fe1c642dSBill Krier  * pn_stype will point to the stream type within pn_sname.
669fe1c642dSBill Krier  *
6709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * If the pname element is missing pn_pname will be set to NULL.
671fe1c642dSBill Krier  * If any other element is missing the pointer in pn will be NULL.
672fe1c642dSBill Krier  */
673fe1c642dSBill Krier void
674fe1c642dSBill Krier smb_pathname_init(smb_request_t *sr, smb_pathname_t *pn, char *path)
675fe1c642dSBill Krier {
676fe1c642dSBill Krier 	char *pname, *fname, *sname;
677fe1c642dSBill Krier 	int len;
678fe1c642dSBill Krier 
679fe1c642dSBill Krier 	bzero(pn, sizeof (smb_pathname_t));
680fe1c642dSBill Krier 	pn->pn_path = smb_pathname_strdup(sr, path);
681fe1c642dSBill Krier 
682fe1c642dSBill Krier 	smb_pathname_preprocess(sr, pn);
683fe1c642dSBill Krier 
684fe1c642dSBill Krier 	/* parse pn->pn_path into its constituent parts */
685fe1c642dSBill Krier 	pname = pn->pn_path;
686fe1c642dSBill Krier 	fname = strrchr(pn->pn_path, '\\');
687fe1c642dSBill Krier 
688fe1c642dSBill Krier 	if (fname) {
689fe1c642dSBill Krier 		if (fname == pname) {
6909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			pn->pn_pname = NULL;
691fe1c642dSBill Krier 		} else {
692fe1c642dSBill Krier 			*fname = '\0';
693fe1c642dSBill Krier 			pn->pn_pname =
694fe1c642dSBill Krier 			    smb_pathname_strdup(sr, pname);
695fe1c642dSBill Krier 			*fname = '\\';
696fe1c642dSBill Krier 		}
697fe1c642dSBill Krier 		++fname;
698fe1c642dSBill Krier 	} else {
699fe1c642dSBill Krier 		fname = pname;
7009fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		pn->pn_pname = NULL;
701fe1c642dSBill Krier 	}
702fe1c642dSBill Krier 
703fe1c642dSBill Krier 	if (fname[0] == '\0') {
704fe1c642dSBill Krier 		pn->pn_fname = NULL;
705fe1c642dSBill Krier 		return;
706fe1c642dSBill Krier 	}
707fe1c642dSBill Krier 
708fe1c642dSBill Krier 	if (!smb_is_stream_name(fname)) {
709fe1c642dSBill Krier 		pn->pn_fname = smb_pathname_strdup(sr, fname);
710fe1c642dSBill Krier 		return;
711fe1c642dSBill Krier 	}
712fe1c642dSBill Krier 
713fe1c642dSBill Krier 	/*
714fe1c642dSBill Krier 	 * find sname and stype in fname.
715fe1c642dSBill Krier 	 * sname can't be NULL smb_is_stream_name checks this
716fe1c642dSBill Krier 	 */
717fe1c642dSBill Krier 	sname = strchr(fname, ':');
718fe1c642dSBill Krier 	if (sname == fname)
719fe1c642dSBill Krier 		fname = NULL;
720fe1c642dSBill Krier 	else {
721fe1c642dSBill Krier 		*sname = '\0';
722fe1c642dSBill Krier 		pn->pn_fname =
723fe1c642dSBill Krier 		    smb_pathname_strdup(sr, fname);
724fe1c642dSBill Krier 		*sname = ':';
725fe1c642dSBill Krier 	}
726fe1c642dSBill Krier 
727fe1c642dSBill Krier 	pn->pn_sname = smb_pathname_strdup(sr, sname);
728fe1c642dSBill Krier 	pn->pn_stype = strchr(pn->pn_sname + 1, ':');
729fe1c642dSBill Krier 	if (pn->pn_stype) {
730fe1c642dSBill Krier 		(void) smb_strupr(pn->pn_stype);
731fe1c642dSBill Krier 	} else {
732fe1c642dSBill Krier 		len = strlen(pn->pn_sname);
733fe1c642dSBill Krier 		pn->pn_sname = smb_pathname_strcat(sr, pn->pn_sname, ":$DATA");
734fe1c642dSBill Krier 		pn->pn_stype = pn->pn_sname + len;
735fe1c642dSBill Krier 	}
736fe1c642dSBill Krier 	++pn->pn_stype;
737fe1c642dSBill Krier }
738fe1c642dSBill Krier 
739fe1c642dSBill Krier /*
740fe1c642dSBill Krier  * smb_pathname_preprocess
741fe1c642dSBill Krier  *
742fe1c642dSBill Krier  * Perform common pre-processing of pn->pn_path:
743fe1c642dSBill Krier  * - if the pn_path is blank, set it to '\\'
744fe1c642dSBill Krier  * - perform unicode wildcard converstion.
745fe1c642dSBill Krier  * - convert any '/' to '\\'
746fe1c642dSBill Krier  * - eliminate duplicate slashes
747fe1c642dSBill Krier  * - remove trailing slashes
7489fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * - quota directory specific pre-processing
749fe1c642dSBill Krier  */
750fe1c642dSBill Krier static void
751fe1c642dSBill Krier smb_pathname_preprocess(smb_request_t *sr, smb_pathname_t *pn)
752fe1c642dSBill Krier {
753fe1c642dSBill Krier 	char *p;
754fe1c642dSBill Krier 
755fe1c642dSBill Krier 	/* treat empty path as "\\" */
756fe1c642dSBill Krier 	if (strlen(pn->pn_path) == 0) {
757fe1c642dSBill Krier 		pn->pn_path = smb_pathname_strdup(sr, "\\");
758fe1c642dSBill Krier 		return;
759fe1c642dSBill Krier 	}
760fe1c642dSBill Krier 
761c13be35aSGordon Ross 	if (sr->session->dialect < NT_LM_0_12)
762fe1c642dSBill Krier 		smb_convert_wildcards(pn->pn_path);
763fe1c642dSBill Krier 
764fe1c642dSBill Krier 	/* treat '/' as '\\' */
765fe1c642dSBill Krier 	(void) strsubst(pn->pn_path, '/', '\\');
766fe1c642dSBill Krier 
767fe1c642dSBill Krier 	(void) strcanon(pn->pn_path, "\\");
768fe1c642dSBill Krier 
769fe1c642dSBill Krier 	/* remove trailing '\\' */
770fe1c642dSBill Krier 	p = pn->pn_path + strlen(pn->pn_path) - 1;
771fe1c642dSBill Krier 	if ((p != pn->pn_path) && (*p == '\\'))
772fe1c642dSBill Krier 		*p = '\0';
7739fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
7749fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_pathname_preprocess_quota(sr, pn);
7759fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_pathname_preprocess_adminshare(sr, pn);
7769fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
7779fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
7789fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /*
7799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * smb_pathname_preprocess_quota
7809fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  *
7819fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * There is a special file required by windows so that the quota
7829fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * tab will be displayed by windows clients. This is created in
7839fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * a special directory, $EXTEND, at the root of the shared file
7849fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * system. To hide this directory prepend a '.' (dot).
7859fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  */
7869fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void
7879fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_pathname_preprocess_quota(smb_request_t *sr, smb_pathname_t *pn)
7889fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
7899fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	char *name = "$EXTEND";
7909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	char *new_name = ".$EXTEND";
7919fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	char *p, *slash;
7929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	int len;
7939fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
7949fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (!smb_node_is_vfsroot(sr->tid_tree->t_snode))
7959fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		return;
7969fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
7979fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	p = pn->pn_path;
7989fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
7999fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	/* ignore any initial "\\" */
8009fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	p += strspn(p, "\\");
8019fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_strcasecmp(p, name, strlen(name)) != 0)
8029fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		return;
8039fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
8049fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	p += strlen(name);
8059fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if ((*p != ':') && (*p != '\\') && (*p != '\0'))
8069fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		return;
8079fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
8089fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	slash = (pn->pn_path[0] == '\\') ? "\\" : "";
8099fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	len = strlen(pn->pn_path) + 2;
8109fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	pn->pn_path = smb_srm_alloc(sr, len);
8119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	(void) snprintf(pn->pn_path, len, "%s%s%s", slash, new_name, p);
8129fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	(void) smb_strupr(pn->pn_path);
8139fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
8149fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
8159fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /*
8169fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * smb_pathname_preprocess_adminshare
8179fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  *
8189fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Convert any path with share name "C$" or "c$" (Admin share) in to lower case.
8199fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  */
8209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void
8219fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_pathname_preprocess_adminshare(smb_request_t *sr, smb_pathname_t *pn)
8229fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
8239fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (strcasecmp(sr->tid_tree->t_sharename, "c$") == 0)
8249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		(void) smb_strlwr(pn->pn_path);
825fe1c642dSBill Krier }
826fe1c642dSBill Krier 
827fe1c642dSBill Krier /*
828fe1c642dSBill Krier  * smb_pathname_strdup
829fe1c642dSBill Krier  *
830fe1c642dSBill Krier  * Duplicate NULL terminated string s.
831fe1c642dSBill Krier  *
832fe1c642dSBill Krier  * The new string is allocated using request specific storage and will
833fe1c642dSBill Krier  * be free'd when the sr is destroyed.
834fe1c642dSBill Krier  */
835fe1c642dSBill Krier static char *
836fe1c642dSBill Krier smb_pathname_strdup(smb_request_t *sr, const char *s)
837fe1c642dSBill Krier {
838fe1c642dSBill Krier 	char *s2;
839fe1c642dSBill Krier 	size_t n;
840fe1c642dSBill Krier 
841fe1c642dSBill Krier 	n = strlen(s) + 1;
8429fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	s2 = smb_srm_zalloc(sr, n);
843fe1c642dSBill Krier 	(void) strlcpy(s2, s, n);
844fe1c642dSBill Krier 	return (s2);
845fe1c642dSBill Krier }
846fe1c642dSBill Krier 
847fe1c642dSBill Krier /*
848fe1c642dSBill Krier  * smb_pathname_strcat
849fe1c642dSBill Krier  *
850fe1c642dSBill Krier  * Reallocate NULL terminated string s1 to accommodate
851fe1c642dSBill Krier  * concatenating  NULL terminated string s2.
852fe1c642dSBill Krier  * Append s2 and return resulting NULL terminated string.
853fe1c642dSBill Krier  *
854fe1c642dSBill Krier  * The string buffer is reallocated using request specific
855fe1c642dSBill Krier  * storage and will be free'd when the sr is destroyed.
856fe1c642dSBill Krier  */
857fe1c642dSBill Krier static char *
858fe1c642dSBill Krier smb_pathname_strcat(smb_request_t *sr, char *s1, const char *s2)
859fe1c642dSBill Krier {
860fe1c642dSBill Krier 	size_t n;
861fe1c642dSBill Krier 
862fe1c642dSBill Krier 	n = strlen(s1) + strlen(s2) + 1;
8639fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	s1 = smb_srm_rezalloc(sr, s1, n);
864fe1c642dSBill Krier 	(void) strlcat(s1, s2, n);
865fe1c642dSBill Krier 	return (s1);
866fe1c642dSBill Krier }
867fe1c642dSBill Krier 
868fe1c642dSBill Krier /*
869fe1c642dSBill Krier  * smb_pathname_validate
870fe1c642dSBill Krier  *
871fe1c642dSBill Krier  * Perform basic validation of pn:
872fe1c642dSBill Krier  * - If first component of pn->path is ".." -> PATH_SYNTAX_BAD
873fe1c642dSBill Krier  * - If there are wildcards in pn->pn_pname -> OBJECT_NAME_INVALID
874fe1c642dSBill Krier  * - If fname is "." -> INVALID_OBJECT_NAME
875fe1c642dSBill Krier  *
876fe1c642dSBill Krier  * On unix .. at the root of a file system links to the root. Thus
877fe1c642dSBill Krier  * an attempt to lookup "/../../.." will be the same as looking up "/"
878fe1c642dSBill Krier  * CIFs clients expect the above to result in
879fe1c642dSBill Krier  * NT_STATUS_OBJECT_PATH_SYNTAX_BAD. It is currently not possible
880fe1c642dSBill Krier  * (and questionable if it's desirable) to deal with all cases
881fe1c642dSBill Krier  * but paths beginning with \\.. are handled.
882fe1c642dSBill Krier  *
883fe1c642dSBill Krier  * Returns: B_TRUE if pn is valid,
884fe1c642dSBill Krier  *          otherwise returns B_FALSE and sets error status in sr.
885*a90cf9f2SGordon Ross  *
886*a90cf9f2SGordon Ross  * XXX: Get rid of smbsr_error calls for SMB2
887fe1c642dSBill Krier  */
888fe1c642dSBill Krier boolean_t
889fe1c642dSBill Krier smb_pathname_validate(smb_request_t *sr, smb_pathname_t *pn)
890fe1c642dSBill Krier {
891fe1c642dSBill Krier 	char *path = pn->pn_path;
892fe1c642dSBill Krier 
893fe1c642dSBill Krier 	/* ignore any initial "\\" */
894fe1c642dSBill Krier 	path += strspn(path, "\\");
895fe1c642dSBill Krier 
896fe1c642dSBill Krier 	/* If first component of path is ".." -> PATH_SYNTAX_BAD */
897fe1c642dSBill Krier 	if ((strcmp(path, "..") == 0) || (strncmp(path, "..\\", 3) == 0)) {
898fe1c642dSBill Krier 		smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
899fe1c642dSBill Krier 		    ERRDOS, ERROR_BAD_PATHNAME);
900fe1c642dSBill Krier 		return (B_FALSE);
901fe1c642dSBill Krier 	}
902fe1c642dSBill Krier 
903fe1c642dSBill Krier 	/* If there are wildcards in pn->pn_pname -> OBJECT_NAME_INVALID */
904fe1c642dSBill Krier 	if (pn->pn_pname && smb_contains_wildcards(pn->pn_pname)) {
905fe1c642dSBill Krier 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
906fe1c642dSBill Krier 		    ERRDOS, ERROR_INVALID_NAME);
907fe1c642dSBill Krier 		return (B_FALSE);
908fe1c642dSBill Krier 	}
909fe1c642dSBill Krier 
910fe1c642dSBill Krier 	/* If fname is "." -> INVALID_OBJECT_NAME */
911fe1c642dSBill Krier 	if (pn->pn_fname && (strcmp(pn->pn_fname, ".") == 0)) {
912fe1c642dSBill Krier 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
913fe1c642dSBill Krier 		    ERRDOS, ERROR_PATH_NOT_FOUND);
914fe1c642dSBill Krier 		return (B_FALSE);
915fe1c642dSBill Krier 	}
916fe1c642dSBill Krier 
917fe1c642dSBill Krier 	return (B_TRUE);
918fe1c642dSBill Krier }
919fe1c642dSBill Krier 
920fe1c642dSBill Krier /*
921fe1c642dSBill Krier  * smb_validate_dirname
922fe1c642dSBill Krier  *
923fe1c642dSBill Krier  * smb_pathname_validate() should have already been performed on pn.
924fe1c642dSBill Krier  *
925fe1c642dSBill Krier  * Very basic directory name validation:  checks for colons in a path.
926fe1c642dSBill Krier  * Need to skip the drive prefix since it contains a colon.
927fe1c642dSBill Krier  *
928fe1c642dSBill Krier  * Returns: B_TRUE if the name is valid,
929fe1c642dSBill Krier  *          otherwise returns B_FALSE and sets error status in sr.
930fe1c642dSBill Krier  */
931fe1c642dSBill Krier boolean_t
932fe1c642dSBill Krier smb_validate_dirname(smb_request_t *sr, smb_pathname_t *pn)
933fe1c642dSBill Krier {
934fe1c642dSBill Krier 	char *name;
935fe1c642dSBill Krier 	char *path = pn->pn_path;
936fe1c642dSBill Krier 
937fe1c642dSBill Krier 	if ((name = path) != 0) {
938fe1c642dSBill Krier 		name += strspn(name, "\\");
939fe1c642dSBill Krier 
940fe1c642dSBill Krier 		if (strchr(name, ':') != 0) {
941fe1c642dSBill Krier 			smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
942fe1c642dSBill Krier 			    ERRDOS, ERROR_INVALID_NAME);
943fe1c642dSBill Krier 			return (B_FALSE);
944fe1c642dSBill Krier 		}
945fe1c642dSBill Krier 	}
946fe1c642dSBill Krier 
947fe1c642dSBill Krier 	return (B_TRUE);
948fe1c642dSBill Krier }
949fe1c642dSBill Krier 
950fe1c642dSBill Krier /*
951fe1c642dSBill Krier  * smb_validate_object_name
952fe1c642dSBill Krier  *
953fe1c642dSBill Krier  * smb_pathname_validate() should have already been pertformed on pn.
954fe1c642dSBill Krier  *
955fe1c642dSBill Krier  * Very basic file name validation.
956fe1c642dSBill Krier  * For filenames, we check for names of the form "AAAn:". Names that
957fe1c642dSBill Krier  * contain three characters, a single digit and a colon (:) are reserved
958fe1c642dSBill Krier  * as DOS device names, i.e. "COM1:".
959fe1c642dSBill Krier  * Stream name validation is handed off to smb_validate_stream_name
960fe1c642dSBill Krier  *
961fe1c642dSBill Krier  * Returns: B_TRUE if pn->pn_fname is valid,
962fe1c642dSBill Krier  *          otherwise returns B_FALSE and sets error status in sr.
963fe1c642dSBill Krier  */
964fe1c642dSBill Krier boolean_t
965fe1c642dSBill Krier smb_validate_object_name(smb_request_t *sr, smb_pathname_t *pn)
966fe1c642dSBill Krier {
967fe1c642dSBill Krier 	if (pn->pn_fname &&
968fe1c642dSBill Krier 	    strlen(pn->pn_fname) == 5 &&
969fe1c642dSBill Krier 	    smb_isdigit(pn->pn_fname[3]) &&
970fe1c642dSBill Krier 	    pn->pn_fname[4] == ':') {
971fe1c642dSBill Krier 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
972fe1c642dSBill Krier 		    ERRDOS, ERROR_INVALID_NAME);
973fe1c642dSBill Krier 		return (B_FALSE);
974fe1c642dSBill Krier 	}
975fe1c642dSBill Krier 
976fe1c642dSBill Krier 	if (pn->pn_sname)
977fe1c642dSBill Krier 		return (smb_validate_stream_name(sr, pn));
978fe1c642dSBill Krier 
979fe1c642dSBill Krier 	return (B_TRUE);
980fe1c642dSBill Krier }
981fe1c642dSBill Krier 
982fe1c642dSBill Krier /*
983fe1c642dSBill Krier  * smb_stream_parse_name
984fe1c642dSBill Krier  *
985fe1c642dSBill Krier  * smb_stream_parse_name should only be called for a path that
986fe1c642dSBill Krier  * contains a valid named stream.  Path validation should have
987fe1c642dSBill Krier  * been performed before this function is called.
988fe1c642dSBill Krier  *
989fe1c642dSBill Krier  * Find the last component of path and split it into filename
990fe1c642dSBill Krier  * and stream name.
991fe1c642dSBill Krier  *
992fe1c642dSBill Krier  * On return the named stream type will be present.  The stream
993fe1c642dSBill Krier  * type defaults to ":$DATA", if it has not been defined
994fe1c642dSBill Krier  * For exmaple, 'stream' contains :<sname>:$DATA
995fe1c642dSBill Krier  */
996fe1c642dSBill Krier void
997fe1c642dSBill Krier smb_stream_parse_name(char *path, char *filename, char *stream)
998fe1c642dSBill Krier {
999fe1c642dSBill Krier 	char *fname, *sname, *stype;
1000fe1c642dSBill Krier 
1001fe1c642dSBill Krier 	ASSERT(path);
1002fe1c642dSBill Krier 	ASSERT(filename);
1003fe1c642dSBill Krier 	ASSERT(stream);
1004fe1c642dSBill Krier 
1005fe1c642dSBill Krier 	fname = strrchr(path, '\\');
1006fe1c642dSBill Krier 	fname = (fname == NULL) ? path : fname + 1;
1007fe1c642dSBill Krier 	(void) strlcpy(filename, fname, MAXNAMELEN);
1008fe1c642dSBill Krier 
1009fe1c642dSBill Krier 	sname = strchr(filename, ':');
1010fe1c642dSBill Krier 	(void) strlcpy(stream, sname, MAXNAMELEN);
1011fe1c642dSBill Krier 	*sname = '\0';
1012fe1c642dSBill Krier 
1013fe1c642dSBill Krier 	stype = strchr(stream + 1, ':');
1014fe1c642dSBill Krier 	if (stype == NULL)
1015fe1c642dSBill Krier 		(void) strlcat(stream, ":$DATA", MAXNAMELEN);
1016fe1c642dSBill Krier 	else
1017fe1c642dSBill Krier 		(void) smb_strupr(stype);
1018fe1c642dSBill Krier }
1019fe1c642dSBill Krier 
1020fe1c642dSBill Krier /*
1021fe1c642dSBill Krier  * smb_is_stream_name
1022fe1c642dSBill Krier  *
1023fe1c642dSBill Krier  * Determines if 'path' specifies a named stream.
1024fe1c642dSBill Krier  *
1025fe1c642dSBill Krier  * path is a NULL terminated string which could be a stream path.
1026fe1c642dSBill Krier  * [pathname/]fname[:stream_name[:stream_type]]
1027fe1c642dSBill Krier  *
1028fe1c642dSBill Krier  * - If there is no colon in the path or it's the last char
1029fe1c642dSBill Krier  *   then it's not a stream name
1030fe1c642dSBill Krier  *
1031fe1c642dSBill Krier  * - '::' is a non-stream and is commonly used by Windows to designate
1032fe1c642dSBill Krier  *   the unamed stream in the form "::$DATA"
1033fe1c642dSBill Krier  */
1034fe1c642dSBill Krier boolean_t
1035fe1c642dSBill Krier smb_is_stream_name(char *path)
1036fe1c642dSBill Krier {
1037fe1c642dSBill Krier 	char *colonp;
1038fe1c642dSBill Krier 
1039fe1c642dSBill Krier 	if (path == NULL)
1040fe1c642dSBill Krier 		return (B_FALSE);
1041fe1c642dSBill Krier 
1042fe1c642dSBill Krier 	colonp = strchr(path, ':');
1043fe1c642dSBill Krier 	if ((colonp == NULL) || (*(colonp+1) == '\0'))
1044fe1c642dSBill Krier 		return (B_FALSE);
1045fe1c642dSBill Krier 
1046fe1c642dSBill Krier 	if (strstr(path, "::"))
1047fe1c642dSBill Krier 		return (B_FALSE);
1048fe1c642dSBill Krier 
1049fe1c642dSBill Krier 	return (B_TRUE);
1050fe1c642dSBill Krier }
1051fe1c642dSBill Krier 
1052fe1c642dSBill Krier /*
1053fe1c642dSBill Krier  * smb_validate_stream_name
1054fe1c642dSBill Krier  *
1055fe1c642dSBill Krier  * B_FALSE will be returned, and the error status ser in the sr, if:
1056fe1c642dSBill Krier  * - the path is not a stream name
1057fe1c642dSBill Krier  * - a path is specified but the fname is ommitted.
1058fe1c642dSBill Krier  * - the stream_type is specified but not valid.
1059fe1c642dSBill Krier  *
1060fe1c642dSBill Krier  * Note: the stream type is case-insensitive.
1061fe1c642dSBill Krier  */
1062fe1c642dSBill Krier boolean_t
1063fe1c642dSBill Krier smb_validate_stream_name(smb_request_t *sr, smb_pathname_t *pn)
1064fe1c642dSBill Krier {
1065fe1c642dSBill Krier 	static char *strmtype[] = {
1066fe1c642dSBill Krier 		"$DATA",
1067fe1c642dSBill Krier 		"$INDEX_ALLOCATION"
1068fe1c642dSBill Krier 	};
1069fe1c642dSBill Krier 	int i;
1070fe1c642dSBill Krier 
1071fe1c642dSBill Krier 	ASSERT(pn);
1072fe1c642dSBill Krier 	ASSERT(pn->pn_sname);
1073fe1c642dSBill Krier 
1074fe1c642dSBill Krier 	if ((!(pn->pn_sname)) ||
1075fe1c642dSBill Krier 	    ((pn->pn_pname) && !(pn->pn_fname))) {
1076fe1c642dSBill Krier 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
1077fe1c642dSBill Krier 		    ERRDOS, ERROR_INVALID_NAME);
1078fe1c642dSBill Krier 		return (B_FALSE);
1079fe1c642dSBill Krier 	}
1080fe1c642dSBill Krier 
1081fe1c642dSBill Krier 
1082fe1c642dSBill Krier 	if (pn->pn_stype != NULL) {
1083fe1c642dSBill Krier 		for (i = 0; i < sizeof (strmtype) / sizeof (strmtype[0]); ++i) {
1084fe1c642dSBill Krier 			if (strcasecmp(pn->pn_stype, strmtype[i]) == 0)
1085fe1c642dSBill Krier 				return (B_TRUE);
1086fe1c642dSBill Krier 		}
1087fe1c642dSBill Krier 
1088fe1c642dSBill Krier 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
1089fe1c642dSBill Krier 		    ERRDOS, ERROR_INVALID_NAME);
1090fe1c642dSBill Krier 		return (B_FALSE);
1091fe1c642dSBill Krier 	}
1092fe1c642dSBill Krier 
1093fe1c642dSBill Krier 	return (B_TRUE);
1094fe1c642dSBill Krier }
10959fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
10969fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /*
10979fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * valid DFS I/O path:
10989fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  *
10999fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * \server-or-domain\share
11009fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * \server-or-domain\share\path
11019fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  *
11029fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * All the returned errors by this function needs to be
11039fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * checked against Windows.
11049fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  */
11059fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static int
11069fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_pathname_dfs_preprocess(smb_request_t *sr, char *path, size_t pathsz)
11079fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
11089fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_unc_t unc;
11099fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	char *linkpath;
11109fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	int rc;
11119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
11129fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (sr->tid_tree == NULL)
11139fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		return (0);
11149fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
11159fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if ((rc = smb_unc_init(path, &unc)) != 0)
11169fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		return (rc);
11179fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
11189fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_strcasecmp(unc.unc_share, sr->tid_tree->t_sharename, 0)) {
11199fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		smb_unc_free(&unc);
11209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		return (EINVAL);
11219fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	}
11229fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
11239fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	linkpath = unc.unc_path;
11249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	(void) snprintf(path, pathsz, "/%s", (linkpath) ? linkpath : "");
11259fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
11269fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_unc_free(&unc);
11279fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	return (0);
11289fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
1129