xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_pathname.c (revision 11337:1f8fe42c7b83)
1*11337SWilliam.Krier@Sun.COM /*
2*11337SWilliam.Krier@Sun.COM  * CDDL HEADER START
3*11337SWilliam.Krier@Sun.COM  *
4*11337SWilliam.Krier@Sun.COM  * The contents of this file are subject to the terms of the
5*11337SWilliam.Krier@Sun.COM  * Common Development and Distribution License (the "License").
6*11337SWilliam.Krier@Sun.COM  * You may not use this file except in compliance with the License.
7*11337SWilliam.Krier@Sun.COM  *
8*11337SWilliam.Krier@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*11337SWilliam.Krier@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*11337SWilliam.Krier@Sun.COM  * See the License for the specific language governing permissions
11*11337SWilliam.Krier@Sun.COM  * and limitations under the License.
12*11337SWilliam.Krier@Sun.COM  *
13*11337SWilliam.Krier@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*11337SWilliam.Krier@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*11337SWilliam.Krier@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*11337SWilliam.Krier@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*11337SWilliam.Krier@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*11337SWilliam.Krier@Sun.COM  *
19*11337SWilliam.Krier@Sun.COM  * CDDL HEADER END
20*11337SWilliam.Krier@Sun.COM  */
21*11337SWilliam.Krier@Sun.COM /*
22*11337SWilliam.Krier@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23*11337SWilliam.Krier@Sun.COM  * Use is subject to license terms.
24*11337SWilliam.Krier@Sun.COM  */
25*11337SWilliam.Krier@Sun.COM 
26*11337SWilliam.Krier@Sun.COM #include <smbsrv/smb_kproto.h>
27*11337SWilliam.Krier@Sun.COM #include <smbsrv/smb_fsops.h>
28*11337SWilliam.Krier@Sun.COM #include <sys/pathname.h>
29*11337SWilliam.Krier@Sun.COM #include <sys/sdt.h>
30*11337SWilliam.Krier@Sun.COM 
31*11337SWilliam.Krier@Sun.COM static char *smb_pathname_catia_v5tov4(smb_request_t *, char *, char *, int);
32*11337SWilliam.Krier@Sun.COM static char *smb_pathname_catia_v4tov5(smb_request_t *, char *, char *, int);
33*11337SWilliam.Krier@Sun.COM static int smb_pathname_lookup(pathname_t *, pathname_t *, int,
34*11337SWilliam.Krier@Sun.COM     vnode_t **, vnode_t *, vnode_t *, cred_t *);
35*11337SWilliam.Krier@Sun.COM static char *smb_pathname_strdup(smb_request_t *, const char *);
36*11337SWilliam.Krier@Sun.COM static char *smb_pathname_strcat(smb_request_t *, char *, const char *);
37*11337SWilliam.Krier@Sun.COM static void smb_pathname_preprocess(smb_request_t *, smb_pathname_t *);
38*11337SWilliam.Krier@Sun.COM 
39*11337SWilliam.Krier@Sun.COM uint32_t
40*11337SWilliam.Krier@Sun.COM smb_is_executable(char *path)
41*11337SWilliam.Krier@Sun.COM {
42*11337SWilliam.Krier@Sun.COM 	char	extension[5];
43*11337SWilliam.Krier@Sun.COM 	int	len = strlen(path);
44*11337SWilliam.Krier@Sun.COM 
45*11337SWilliam.Krier@Sun.COM 	if ((len >= 4) && (path[len - 4] == '.')) {
46*11337SWilliam.Krier@Sun.COM 		(void) strcpy(extension, &path[len - 3]);
47*11337SWilliam.Krier@Sun.COM 		(void) smb_strupr(extension);
48*11337SWilliam.Krier@Sun.COM 
49*11337SWilliam.Krier@Sun.COM 		if (strcmp(extension, "EXE") == 0)
50*11337SWilliam.Krier@Sun.COM 			return (NODE_FLAGS_EXECUTABLE);
51*11337SWilliam.Krier@Sun.COM 
52*11337SWilliam.Krier@Sun.COM 		if (strcmp(extension, "COM") == 0)
53*11337SWilliam.Krier@Sun.COM 			return (NODE_FLAGS_EXECUTABLE);
54*11337SWilliam.Krier@Sun.COM 
55*11337SWilliam.Krier@Sun.COM 		if (strcmp(extension, "DLL") == 0)
56*11337SWilliam.Krier@Sun.COM 			return (NODE_FLAGS_EXECUTABLE);
57*11337SWilliam.Krier@Sun.COM 
58*11337SWilliam.Krier@Sun.COM 		if (strcmp(extension, "SYM") == 0)
59*11337SWilliam.Krier@Sun.COM 			return (NODE_FLAGS_EXECUTABLE);
60*11337SWilliam.Krier@Sun.COM 	}
61*11337SWilliam.Krier@Sun.COM 
62*11337SWilliam.Krier@Sun.COM 	return (0);
63*11337SWilliam.Krier@Sun.COM }
64*11337SWilliam.Krier@Sun.COM 
65*11337SWilliam.Krier@Sun.COM /*
66*11337SWilliam.Krier@Sun.COM  * smb_pathname_reduce
67*11337SWilliam.Krier@Sun.COM  *
68*11337SWilliam.Krier@Sun.COM  * smb_pathname_reduce() takes a path and returns the smb_node for the
69*11337SWilliam.Krier@Sun.COM  * second-to-last component of the path.  It also returns the name of the last
70*11337SWilliam.Krier@Sun.COM  * component.  Pointers for both of these fields must be supplied by the caller.
71*11337SWilliam.Krier@Sun.COM  *
72*11337SWilliam.Krier@Sun.COM  * Upon success, 0 is returned.
73*11337SWilliam.Krier@Sun.COM  *
74*11337SWilliam.Krier@Sun.COM  * Upon error, *dir_node will be set to 0.
75*11337SWilliam.Krier@Sun.COM  *
76*11337SWilliam.Krier@Sun.COM  * *sr (in)
77*11337SWilliam.Krier@Sun.COM  * ---
78*11337SWilliam.Krier@Sun.COM  * smb_request structure pointer
79*11337SWilliam.Krier@Sun.COM  *
80*11337SWilliam.Krier@Sun.COM  * *cred (in)
81*11337SWilliam.Krier@Sun.COM  * -----
82*11337SWilliam.Krier@Sun.COM  * credential
83*11337SWilliam.Krier@Sun.COM  *
84*11337SWilliam.Krier@Sun.COM  * *path (in)
85*11337SWilliam.Krier@Sun.COM  * -----
86*11337SWilliam.Krier@Sun.COM  * pathname to be looked up
87*11337SWilliam.Krier@Sun.COM  *
88*11337SWilliam.Krier@Sun.COM  * *share_root_node (in)
89*11337SWilliam.Krier@Sun.COM  * ----------------
90*11337SWilliam.Krier@Sun.COM  * File operations which are share-relative should pass sr->tid_tree->t_snode.
91*11337SWilliam.Krier@Sun.COM  * If the call is not for a share-relative operation, this parameter must be 0
92*11337SWilliam.Krier@Sun.COM  * (e.g. the call from smbsr_setup_share()).  (Such callers will have path
93*11337SWilliam.Krier@Sun.COM  * operations done using root_smb_node.)  This parameter is used to determine
94*11337SWilliam.Krier@Sun.COM  * whether mount points can be crossed.
95*11337SWilliam.Krier@Sun.COM  *
96*11337SWilliam.Krier@Sun.COM  * share_root_node should have at least one reference on it.  This reference
97*11337SWilliam.Krier@Sun.COM  * will stay intact throughout this routine.
98*11337SWilliam.Krier@Sun.COM  *
99*11337SWilliam.Krier@Sun.COM  * *cur_node (in)
100*11337SWilliam.Krier@Sun.COM  * ---------
101*11337SWilliam.Krier@Sun.COM  * The smb_node for the current directory (for relative paths).
102*11337SWilliam.Krier@Sun.COM  * cur_node should have at least one reference on it.
103*11337SWilliam.Krier@Sun.COM  * This reference will stay intact throughout this routine.
104*11337SWilliam.Krier@Sun.COM  *
105*11337SWilliam.Krier@Sun.COM  * **dir_node (out)
106*11337SWilliam.Krier@Sun.COM  * ----------
107*11337SWilliam.Krier@Sun.COM  * Directory for the penultimate component of the original path.
108*11337SWilliam.Krier@Sun.COM  * (Note that this is not the same as the parent directory of the ultimate
109*11337SWilliam.Krier@Sun.COM  * target in the case of a link.)
110*11337SWilliam.Krier@Sun.COM  *
111*11337SWilliam.Krier@Sun.COM  * The directory smb_node is returned held.  The caller will need to release
112*11337SWilliam.Krier@Sun.COM  * the hold or otherwise make sure it will get released (e.g. in a destroy
113*11337SWilliam.Krier@Sun.COM  * routine if made part of a global structure).
114*11337SWilliam.Krier@Sun.COM  *
115*11337SWilliam.Krier@Sun.COM  * last_component (out)
116*11337SWilliam.Krier@Sun.COM  * --------------
117*11337SWilliam.Krier@Sun.COM  * The last component of the path.  (This may be different from the name of any
118*11337SWilliam.Krier@Sun.COM  * link target to which the last component may resolve.)
119*11337SWilliam.Krier@Sun.COM  *
120*11337SWilliam.Krier@Sun.COM  *
121*11337SWilliam.Krier@Sun.COM  * ____________________________
122*11337SWilliam.Krier@Sun.COM  *
123*11337SWilliam.Krier@Sun.COM  * The CIFS server lookup path needs to have logic equivalent to that of
124*11337SWilliam.Krier@Sun.COM  * smb_fsop_lookup(), smb_vop_lookup() and other smb_vop_*() routines in the
125*11337SWilliam.Krier@Sun.COM  * following areas:
126*11337SWilliam.Krier@Sun.COM  *
127*11337SWilliam.Krier@Sun.COM  *	- non-traversal of child mounts		(handled by smb_pathname_reduce)
128*11337SWilliam.Krier@Sun.COM  *	- unmangling 				(handled in smb_pathname)
129*11337SWilliam.Krier@Sun.COM  *	- "chroot" behavior of share root 	(handled by lookuppnvp)
130*11337SWilliam.Krier@Sun.COM  *
131*11337SWilliam.Krier@Sun.COM  * In addition, it needs to replace backslashes with forward slashes.  It also
132*11337SWilliam.Krier@Sun.COM  * ensures that link processing is done correctly, and that directory
133*11337SWilliam.Krier@Sun.COM  * information requested by the caller is correctly returned (i.e. for paths
134*11337SWilliam.Krier@Sun.COM  * with a link in the last component, the directory information of the
135*11337SWilliam.Krier@Sun.COM  * link and not the target needs to be returned).
136*11337SWilliam.Krier@Sun.COM  */
137*11337SWilliam.Krier@Sun.COM 
138*11337SWilliam.Krier@Sun.COM int
139*11337SWilliam.Krier@Sun.COM smb_pathname_reduce(
140*11337SWilliam.Krier@Sun.COM     smb_request_t	*sr,
141*11337SWilliam.Krier@Sun.COM     cred_t		*cred,
142*11337SWilliam.Krier@Sun.COM     const char		*path,
143*11337SWilliam.Krier@Sun.COM     smb_node_t		*share_root_node,
144*11337SWilliam.Krier@Sun.COM     smb_node_t		*cur_node,
145*11337SWilliam.Krier@Sun.COM     smb_node_t		**dir_node,
146*11337SWilliam.Krier@Sun.COM     char		*last_component)
147*11337SWilliam.Krier@Sun.COM {
148*11337SWilliam.Krier@Sun.COM 	smb_node_t	*root_node;
149*11337SWilliam.Krier@Sun.COM 	pathname_t	ppn;
150*11337SWilliam.Krier@Sun.COM 	char		*usepath;
151*11337SWilliam.Krier@Sun.COM 	int		lookup_flags = FOLLOW;
152*11337SWilliam.Krier@Sun.COM 	int 		trailing_slash = 0;
153*11337SWilliam.Krier@Sun.COM 	int		err = 0;
154*11337SWilliam.Krier@Sun.COM 	int		len;
155*11337SWilliam.Krier@Sun.COM 	smb_node_t	*vss_cur_node;
156*11337SWilliam.Krier@Sun.COM 	smb_node_t	*vss_root_node;
157*11337SWilliam.Krier@Sun.COM 	smb_node_t	*local_cur_node;
158*11337SWilliam.Krier@Sun.COM 	smb_node_t	*local_root_node;
159*11337SWilliam.Krier@Sun.COM 
160*11337SWilliam.Krier@Sun.COM 	ASSERT(dir_node);
161*11337SWilliam.Krier@Sun.COM 	ASSERT(last_component);
162*11337SWilliam.Krier@Sun.COM 
163*11337SWilliam.Krier@Sun.COM 	*dir_node = NULL;
164*11337SWilliam.Krier@Sun.COM 	*last_component = '\0';
165*11337SWilliam.Krier@Sun.COM 	vss_cur_node = NULL;
166*11337SWilliam.Krier@Sun.COM 	vss_root_node = NULL;
167*11337SWilliam.Krier@Sun.COM 
168*11337SWilliam.Krier@Sun.COM 	if (sr && sr->tid_tree) {
169*11337SWilliam.Krier@Sun.COM 		if (!STYPE_ISDSK(sr->tid_tree->t_res_type))
170*11337SWilliam.Krier@Sun.COM 			return (EACCES);
171*11337SWilliam.Krier@Sun.COM 	}
172*11337SWilliam.Krier@Sun.COM 
173*11337SWilliam.Krier@Sun.COM 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
174*11337SWilliam.Krier@Sun.COM 		lookup_flags |= FIGNORECASE;
175*11337SWilliam.Krier@Sun.COM 
176*11337SWilliam.Krier@Sun.COM 	if (path == NULL)
177*11337SWilliam.Krier@Sun.COM 		return (EINVAL);
178*11337SWilliam.Krier@Sun.COM 
179*11337SWilliam.Krier@Sun.COM 	if (*path == '\0')
180*11337SWilliam.Krier@Sun.COM 		return (ENOENT);
181*11337SWilliam.Krier@Sun.COM 
182*11337SWilliam.Krier@Sun.COM 	usepath = kmem_alloc(MAXPATHLEN, KM_SLEEP);
183*11337SWilliam.Krier@Sun.COM 
184*11337SWilliam.Krier@Sun.COM 	if ((len = strlcpy(usepath, path, MAXPATHLEN)) >= MAXPATHLEN) {
185*11337SWilliam.Krier@Sun.COM 		kmem_free(usepath, MAXPATHLEN);
186*11337SWilliam.Krier@Sun.COM 		return (ENAMETOOLONG);
187*11337SWilliam.Krier@Sun.COM 	}
188*11337SWilliam.Krier@Sun.COM 
189*11337SWilliam.Krier@Sun.COM 	(void) strsubst(usepath, '\\', '/');
190*11337SWilliam.Krier@Sun.COM 
191*11337SWilliam.Krier@Sun.COM 	if (share_root_node)
192*11337SWilliam.Krier@Sun.COM 		root_node = share_root_node;
193*11337SWilliam.Krier@Sun.COM 	else
194*11337SWilliam.Krier@Sun.COM 		root_node = sr->sr_server->si_root_smb_node;
195*11337SWilliam.Krier@Sun.COM 
196*11337SWilliam.Krier@Sun.COM 	if (cur_node == NULL)
197*11337SWilliam.Krier@Sun.COM 		cur_node = root_node;
198*11337SWilliam.Krier@Sun.COM 
199*11337SWilliam.Krier@Sun.COM 	local_cur_node = cur_node;
200*11337SWilliam.Krier@Sun.COM 	local_root_node = root_node;
201*11337SWilliam.Krier@Sun.COM 
202*11337SWilliam.Krier@Sun.COM 	if (sr && (sr->smb_flg2 & SMB_FLAGS2_REPARSE_PATH)) {
203*11337SWilliam.Krier@Sun.COM 		err = smb_vss_lookup_nodes(sr, root_node, cur_node,
204*11337SWilliam.Krier@Sun.COM 		    usepath, &vss_cur_node, &vss_root_node);
205*11337SWilliam.Krier@Sun.COM 
206*11337SWilliam.Krier@Sun.COM 		if (err != 0) {
207*11337SWilliam.Krier@Sun.COM 			kmem_free(usepath, MAXPATHLEN);
208*11337SWilliam.Krier@Sun.COM 			return (err);
209*11337SWilliam.Krier@Sun.COM 		}
210*11337SWilliam.Krier@Sun.COM 
211*11337SWilliam.Krier@Sun.COM 		len = strlen(usepath);
212*11337SWilliam.Krier@Sun.COM 		local_cur_node = vss_cur_node;
213*11337SWilliam.Krier@Sun.COM 		local_root_node = vss_root_node;
214*11337SWilliam.Krier@Sun.COM 	}
215*11337SWilliam.Krier@Sun.COM 
216*11337SWilliam.Krier@Sun.COM 	if (usepath[len - 1] == '/')
217*11337SWilliam.Krier@Sun.COM 		trailing_slash = 1;
218*11337SWilliam.Krier@Sun.COM 
219*11337SWilliam.Krier@Sun.COM 	(void) strcanon(usepath, "/");
220*11337SWilliam.Krier@Sun.COM 
221*11337SWilliam.Krier@Sun.COM 	(void) pn_alloc(&ppn);
222*11337SWilliam.Krier@Sun.COM 
223*11337SWilliam.Krier@Sun.COM 	if ((err = pn_set(&ppn, usepath)) != 0) {
224*11337SWilliam.Krier@Sun.COM 		(void) pn_free(&ppn);
225*11337SWilliam.Krier@Sun.COM 		kmem_free(usepath, MAXPATHLEN);
226*11337SWilliam.Krier@Sun.COM 		if (vss_cur_node != NULL)
227*11337SWilliam.Krier@Sun.COM 			(void) smb_node_release(vss_cur_node);
228*11337SWilliam.Krier@Sun.COM 		if (vss_root_node != NULL)
229*11337SWilliam.Krier@Sun.COM 			(void) smb_node_release(vss_root_node);
230*11337SWilliam.Krier@Sun.COM 		return (err);
231*11337SWilliam.Krier@Sun.COM 	}
232*11337SWilliam.Krier@Sun.COM 
233*11337SWilliam.Krier@Sun.COM 	/*
234*11337SWilliam.Krier@Sun.COM 	 * If a path does not have a trailing slash, strip off the
235*11337SWilliam.Krier@Sun.COM 	 * last component.  (We only need to return an smb_node for
236*11337SWilliam.Krier@Sun.COM 	 * the second to last component; a name is returned for the
237*11337SWilliam.Krier@Sun.COM 	 * last component.)
238*11337SWilliam.Krier@Sun.COM 	 */
239*11337SWilliam.Krier@Sun.COM 
240*11337SWilliam.Krier@Sun.COM 	if (trailing_slash) {
241*11337SWilliam.Krier@Sun.COM 		(void) strlcpy(last_component, ".", MAXNAMELEN);
242*11337SWilliam.Krier@Sun.COM 	} else {
243*11337SWilliam.Krier@Sun.COM 		(void) pn_setlast(&ppn);
244*11337SWilliam.Krier@Sun.COM 		(void) strlcpy(last_component, ppn.pn_path, MAXNAMELEN);
245*11337SWilliam.Krier@Sun.COM 		ppn.pn_path[0] = '\0';
246*11337SWilliam.Krier@Sun.COM 	}
247*11337SWilliam.Krier@Sun.COM 
248*11337SWilliam.Krier@Sun.COM 	if ((strcmp(ppn.pn_buf, "/") == 0) || (ppn.pn_buf[0] == '\0')) {
249*11337SWilliam.Krier@Sun.COM 		smb_node_ref(local_cur_node);
250*11337SWilliam.Krier@Sun.COM 		*dir_node = local_cur_node;
251*11337SWilliam.Krier@Sun.COM 	} else {
252*11337SWilliam.Krier@Sun.COM 		err = smb_pathname(sr, ppn.pn_buf, lookup_flags,
253*11337SWilliam.Krier@Sun.COM 		    local_root_node, local_cur_node, NULL, dir_node, cred);
254*11337SWilliam.Krier@Sun.COM 	}
255*11337SWilliam.Krier@Sun.COM 
256*11337SWilliam.Krier@Sun.COM 	(void) pn_free(&ppn);
257*11337SWilliam.Krier@Sun.COM 	kmem_free(usepath, MAXPATHLEN);
258*11337SWilliam.Krier@Sun.COM 
259*11337SWilliam.Krier@Sun.COM 	/*
260*11337SWilliam.Krier@Sun.COM 	 * Prevent access to anything outside of the share root, except
261*11337SWilliam.Krier@Sun.COM 	 * when mapping a share because that may require traversal from
262*11337SWilliam.Krier@Sun.COM 	 * / to a mounted file system.  share_root_node is NULL when
263*11337SWilliam.Krier@Sun.COM 	 * mapping a share.
264*11337SWilliam.Krier@Sun.COM 	 *
265*11337SWilliam.Krier@Sun.COM 	 * Note that we disregard whether the traversal of the path went
266*11337SWilliam.Krier@Sun.COM 	 * outside of the file system and then came back (say via a link).
267*11337SWilliam.Krier@Sun.COM 	 */
268*11337SWilliam.Krier@Sun.COM 
269*11337SWilliam.Krier@Sun.COM 	if ((err == 0) && share_root_node) {
270*11337SWilliam.Krier@Sun.COM 		if (share_root_node->vp->v_vfsp != (*dir_node)->vp->v_vfsp)
271*11337SWilliam.Krier@Sun.COM 			err = EACCES;
272*11337SWilliam.Krier@Sun.COM 	}
273*11337SWilliam.Krier@Sun.COM 
274*11337SWilliam.Krier@Sun.COM 	if (err) {
275*11337SWilliam.Krier@Sun.COM 		if (*dir_node) {
276*11337SWilliam.Krier@Sun.COM 			(void) smb_node_release(*dir_node);
277*11337SWilliam.Krier@Sun.COM 			*dir_node = NULL;
278*11337SWilliam.Krier@Sun.COM 		}
279*11337SWilliam.Krier@Sun.COM 		*last_component = 0;
280*11337SWilliam.Krier@Sun.COM 	}
281*11337SWilliam.Krier@Sun.COM 
282*11337SWilliam.Krier@Sun.COM 	if (vss_cur_node != NULL)
283*11337SWilliam.Krier@Sun.COM 		(void) smb_node_release(vss_cur_node);
284*11337SWilliam.Krier@Sun.COM 	if (vss_root_node != NULL)
285*11337SWilliam.Krier@Sun.COM 		(void) smb_node_release(vss_root_node);
286*11337SWilliam.Krier@Sun.COM 
287*11337SWilliam.Krier@Sun.COM 	return (err);
288*11337SWilliam.Krier@Sun.COM }
289*11337SWilliam.Krier@Sun.COM 
290*11337SWilliam.Krier@Sun.COM /*
291*11337SWilliam.Krier@Sun.COM  * smb_pathname()
292*11337SWilliam.Krier@Sun.COM  * wrapper to lookuppnvp().  Handles name unmangling.
293*11337SWilliam.Krier@Sun.COM  *
294*11337SWilliam.Krier@Sun.COM  * *dir_node is the true directory of the target *node.
295*11337SWilliam.Krier@Sun.COM  *
296*11337SWilliam.Krier@Sun.COM  * If any component but the last in the path is not found, ENOTDIR instead of
297*11337SWilliam.Krier@Sun.COM  * ENOENT will be returned.
298*11337SWilliam.Krier@Sun.COM  *
299*11337SWilliam.Krier@Sun.COM  * Path components are processed one at a time so that smb_nodes can be
300*11337SWilliam.Krier@Sun.COM  * created for each component.  This allows the n_dnode field in the
301*11337SWilliam.Krier@Sun.COM  * smb_node to be properly populated.
302*11337SWilliam.Krier@Sun.COM  *
303*11337SWilliam.Krier@Sun.COM  * Because of the above, links are also processed in this routine
304*11337SWilliam.Krier@Sun.COM  * (i.e., we do not pass the FOLLOW flag to lookuppnvp()).  This
305*11337SWilliam.Krier@Sun.COM  * will allow smb_nodes to be created for each component of a link.
306*11337SWilliam.Krier@Sun.COM  *
307*11337SWilliam.Krier@Sun.COM  * Mangle checking is per component. If a name is mangled, when the
308*11337SWilliam.Krier@Sun.COM  * unmangled name is passed to smb_pathname_lookup() do not pass
309*11337SWilliam.Krier@Sun.COM  * FIGNORECASE, since the unmangled name is the real on-disk name.
310*11337SWilliam.Krier@Sun.COM  * Otherwise pass FIGNORECASE if it's set in flags. This will cause the
311*11337SWilliam.Krier@Sun.COM  * file system to return "first match" in the event of a case collision.
312*11337SWilliam.Krier@Sun.COM  *
313*11337SWilliam.Krier@Sun.COM  * If CATIA character translation is enabled it is applied to each
314*11337SWilliam.Krier@Sun.COM  * component before passing the component to smb_pathname_lookup().
315*11337SWilliam.Krier@Sun.COM  * After smb_pathname_lookup() the reverse translation is applied.
316*11337SWilliam.Krier@Sun.COM  */
317*11337SWilliam.Krier@Sun.COM 
318*11337SWilliam.Krier@Sun.COM int
319*11337SWilliam.Krier@Sun.COM smb_pathname(smb_request_t *sr, char *path, int flags,
320*11337SWilliam.Krier@Sun.COM     smb_node_t *root_node, smb_node_t *cur_node, smb_node_t **dir_node,
321*11337SWilliam.Krier@Sun.COM     smb_node_t **ret_node, cred_t *cred)
322*11337SWilliam.Krier@Sun.COM {
323*11337SWilliam.Krier@Sun.COM 	char		*component, *real_name, *namep;
324*11337SWilliam.Krier@Sun.COM 	pathname_t	pn, rpn, upn, link_pn;
325*11337SWilliam.Krier@Sun.COM 	smb_node_t	*dnode, *fnode;
326*11337SWilliam.Krier@Sun.COM 	vnode_t		*rootvp, *vp;
327*11337SWilliam.Krier@Sun.COM 	size_t		pathleft;
328*11337SWilliam.Krier@Sun.COM 	int		err = 0;
329*11337SWilliam.Krier@Sun.COM 	int		nlink = 0;
330*11337SWilliam.Krier@Sun.COM 	int		local_flags;
331*11337SWilliam.Krier@Sun.COM 	uint32_t	abe_flag = 0;
332*11337SWilliam.Krier@Sun.COM 	char		namebuf[MAXNAMELEN];
333*11337SWilliam.Krier@Sun.COM 
334*11337SWilliam.Krier@Sun.COM 	if (path == NULL)
335*11337SWilliam.Krier@Sun.COM 		return (EINVAL);
336*11337SWilliam.Krier@Sun.COM 
337*11337SWilliam.Krier@Sun.COM 	ASSERT(root_node);
338*11337SWilliam.Krier@Sun.COM 	ASSERT(cur_node);
339*11337SWilliam.Krier@Sun.COM 	ASSERT(ret_node);
340*11337SWilliam.Krier@Sun.COM 
341*11337SWilliam.Krier@Sun.COM 	*ret_node = NULL;
342*11337SWilliam.Krier@Sun.COM 
343*11337SWilliam.Krier@Sun.COM 	if (dir_node)
344*11337SWilliam.Krier@Sun.COM 		*dir_node = NULL;
345*11337SWilliam.Krier@Sun.COM 
346*11337SWilliam.Krier@Sun.COM 	(void) pn_alloc(&upn);
347*11337SWilliam.Krier@Sun.COM 
348*11337SWilliam.Krier@Sun.COM 	if ((err = pn_set(&upn, path)) != 0) {
349*11337SWilliam.Krier@Sun.COM 		(void) pn_free(&upn);
350*11337SWilliam.Krier@Sun.COM 		return (err);
351*11337SWilliam.Krier@Sun.COM 	}
352*11337SWilliam.Krier@Sun.COM 
353*11337SWilliam.Krier@Sun.COM 	if (SMB_TREE_SUPPORTS_ABE(sr))
354*11337SWilliam.Krier@Sun.COM 		abe_flag = SMB_ABE;
355*11337SWilliam.Krier@Sun.COM 
356*11337SWilliam.Krier@Sun.COM 	(void) pn_alloc(&pn);
357*11337SWilliam.Krier@Sun.COM 	(void) pn_alloc(&rpn);
358*11337SWilliam.Krier@Sun.COM 
359*11337SWilliam.Krier@Sun.COM 	component = kmem_alloc(MAXNAMELEN, KM_SLEEP);
360*11337SWilliam.Krier@Sun.COM 	real_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
361*11337SWilliam.Krier@Sun.COM 
362*11337SWilliam.Krier@Sun.COM 	fnode = NULL;
363*11337SWilliam.Krier@Sun.COM 	dnode = cur_node;
364*11337SWilliam.Krier@Sun.COM 	smb_node_ref(dnode);
365*11337SWilliam.Krier@Sun.COM 	rootvp = root_node->vp;
366*11337SWilliam.Krier@Sun.COM 
367*11337SWilliam.Krier@Sun.COM 	while ((pathleft = pn_pathleft(&upn)) != 0) {
368*11337SWilliam.Krier@Sun.COM 		if (fnode) {
369*11337SWilliam.Krier@Sun.COM 			smb_node_release(dnode);
370*11337SWilliam.Krier@Sun.COM 			dnode = fnode;
371*11337SWilliam.Krier@Sun.COM 			fnode = NULL;
372*11337SWilliam.Krier@Sun.COM 		}
373*11337SWilliam.Krier@Sun.COM 
374*11337SWilliam.Krier@Sun.COM 		if ((err = pn_getcomponent(&upn, component)) != 0)
375*11337SWilliam.Krier@Sun.COM 			break;
376*11337SWilliam.Krier@Sun.COM 
377*11337SWilliam.Krier@Sun.COM 		if ((namep = smb_pathname_catia_v5tov4(sr, component,
378*11337SWilliam.Krier@Sun.COM 		    namebuf, sizeof (namebuf))) == NULL) {
379*11337SWilliam.Krier@Sun.COM 			err = EILSEQ;
380*11337SWilliam.Krier@Sun.COM 			break;
381*11337SWilliam.Krier@Sun.COM 		}
382*11337SWilliam.Krier@Sun.COM 
383*11337SWilliam.Krier@Sun.COM 		if ((err = pn_set(&pn, namep)) != 0)
384*11337SWilliam.Krier@Sun.COM 			break;
385*11337SWilliam.Krier@Sun.COM 
386*11337SWilliam.Krier@Sun.COM 		local_flags = flags & FIGNORECASE;
387*11337SWilliam.Krier@Sun.COM 		err = smb_pathname_lookup(&pn, &rpn, local_flags,
388*11337SWilliam.Krier@Sun.COM 		    &vp, rootvp, dnode->vp, cred);
389*11337SWilliam.Krier@Sun.COM 
390*11337SWilliam.Krier@Sun.COM 		if (err) {
391*11337SWilliam.Krier@Sun.COM 			if (smb_maybe_mangled_name(component) == 0)
392*11337SWilliam.Krier@Sun.COM 				break;
393*11337SWilliam.Krier@Sun.COM 
394*11337SWilliam.Krier@Sun.COM 			if ((err = smb_unmangle_name(dnode, component,
395*11337SWilliam.Krier@Sun.COM 			    real_name, MAXNAMELEN, abe_flag)) != 0)
396*11337SWilliam.Krier@Sun.COM 				break;
397*11337SWilliam.Krier@Sun.COM 
398*11337SWilliam.Krier@Sun.COM 			if ((namep = smb_pathname_catia_v5tov4(sr, real_name,
399*11337SWilliam.Krier@Sun.COM 			    namebuf, sizeof (namebuf))) == NULL) {
400*11337SWilliam.Krier@Sun.COM 				err = EILSEQ;
401*11337SWilliam.Krier@Sun.COM 				break;
402*11337SWilliam.Krier@Sun.COM 			}
403*11337SWilliam.Krier@Sun.COM 
404*11337SWilliam.Krier@Sun.COM 			if ((err = pn_set(&pn, namep)) != 0)
405*11337SWilliam.Krier@Sun.COM 				break;
406*11337SWilliam.Krier@Sun.COM 
407*11337SWilliam.Krier@Sun.COM 			local_flags = 0;
408*11337SWilliam.Krier@Sun.COM 			err = smb_pathname_lookup(&pn, &rpn, local_flags,
409*11337SWilliam.Krier@Sun.COM 			    &vp, rootvp, dnode->vp, cred);
410*11337SWilliam.Krier@Sun.COM 			if (err)
411*11337SWilliam.Krier@Sun.COM 				break;
412*11337SWilliam.Krier@Sun.COM 		}
413*11337SWilliam.Krier@Sun.COM 
414*11337SWilliam.Krier@Sun.COM 		if ((vp->v_type == VLNK) &&
415*11337SWilliam.Krier@Sun.COM 		    ((flags & FOLLOW) || pn_pathleft(&upn))) {
416*11337SWilliam.Krier@Sun.COM 
417*11337SWilliam.Krier@Sun.COM 			if (++nlink > MAXSYMLINKS) {
418*11337SWilliam.Krier@Sun.COM 				err = ELOOP;
419*11337SWilliam.Krier@Sun.COM 				VN_RELE(vp);
420*11337SWilliam.Krier@Sun.COM 				break;
421*11337SWilliam.Krier@Sun.COM 			}
422*11337SWilliam.Krier@Sun.COM 
423*11337SWilliam.Krier@Sun.COM 			(void) pn_alloc(&link_pn);
424*11337SWilliam.Krier@Sun.COM 			err = pn_getsymlink(vp, &link_pn, cred);
425*11337SWilliam.Krier@Sun.COM 			VN_RELE(vp);
426*11337SWilliam.Krier@Sun.COM 
427*11337SWilliam.Krier@Sun.COM 			if (err == 0) {
428*11337SWilliam.Krier@Sun.COM 				if (pn_pathleft(&link_pn) == 0)
429*11337SWilliam.Krier@Sun.COM 					(void) pn_set(&link_pn, ".");
430*11337SWilliam.Krier@Sun.COM 				err = pn_insert(&upn, &link_pn,
431*11337SWilliam.Krier@Sun.COM 				    strlen(component));
432*11337SWilliam.Krier@Sun.COM 			}
433*11337SWilliam.Krier@Sun.COM 			pn_free(&link_pn);
434*11337SWilliam.Krier@Sun.COM 
435*11337SWilliam.Krier@Sun.COM 			if (err)
436*11337SWilliam.Krier@Sun.COM 				break;
437*11337SWilliam.Krier@Sun.COM 
438*11337SWilliam.Krier@Sun.COM 			if (upn.pn_pathlen == 0) {
439*11337SWilliam.Krier@Sun.COM 				err = ENOENT;
440*11337SWilliam.Krier@Sun.COM 				break;
441*11337SWilliam.Krier@Sun.COM 			}
442*11337SWilliam.Krier@Sun.COM 
443*11337SWilliam.Krier@Sun.COM 			if (upn.pn_path[0] == '/') {
444*11337SWilliam.Krier@Sun.COM 				fnode = root_node;
445*11337SWilliam.Krier@Sun.COM 				smb_node_ref(fnode);
446*11337SWilliam.Krier@Sun.COM 			}
447*11337SWilliam.Krier@Sun.COM 
448*11337SWilliam.Krier@Sun.COM 			if (pn_fixslash(&upn))
449*11337SWilliam.Krier@Sun.COM 				flags |= FOLLOW;
450*11337SWilliam.Krier@Sun.COM 
451*11337SWilliam.Krier@Sun.COM 		} else {
452*11337SWilliam.Krier@Sun.COM 			if (flags & FIGNORECASE) {
453*11337SWilliam.Krier@Sun.COM 				if (strcmp(rpn.pn_path, "/") != 0)
454*11337SWilliam.Krier@Sun.COM 					pn_setlast(&rpn);
455*11337SWilliam.Krier@Sun.COM 				namep = rpn.pn_path;
456*11337SWilliam.Krier@Sun.COM 			} else {
457*11337SWilliam.Krier@Sun.COM 				namep = pn.pn_path;
458*11337SWilliam.Krier@Sun.COM 			}
459*11337SWilliam.Krier@Sun.COM 
460*11337SWilliam.Krier@Sun.COM 			namep = smb_pathname_catia_v4tov5(sr, namep,
461*11337SWilliam.Krier@Sun.COM 			    namebuf, sizeof (namebuf));
462*11337SWilliam.Krier@Sun.COM 
463*11337SWilliam.Krier@Sun.COM 			fnode = smb_node_lookup(sr, NULL, cred, vp, namep,
464*11337SWilliam.Krier@Sun.COM 			    dnode, NULL);
465*11337SWilliam.Krier@Sun.COM 			VN_RELE(vp);
466*11337SWilliam.Krier@Sun.COM 
467*11337SWilliam.Krier@Sun.COM 			if (fnode == NULL) {
468*11337SWilliam.Krier@Sun.COM 				err = ENOMEM;
469*11337SWilliam.Krier@Sun.COM 				break;
470*11337SWilliam.Krier@Sun.COM 			}
471*11337SWilliam.Krier@Sun.COM 		}
472*11337SWilliam.Krier@Sun.COM 
473*11337SWilliam.Krier@Sun.COM 		while (upn.pn_path[0] == '/') {
474*11337SWilliam.Krier@Sun.COM 			upn.pn_path++;
475*11337SWilliam.Krier@Sun.COM 			upn.pn_pathlen--;
476*11337SWilliam.Krier@Sun.COM 		}
477*11337SWilliam.Krier@Sun.COM 
478*11337SWilliam.Krier@Sun.COM 	}
479*11337SWilliam.Krier@Sun.COM 
480*11337SWilliam.Krier@Sun.COM 	if ((pathleft) && (err == ENOENT))
481*11337SWilliam.Krier@Sun.COM 		err = ENOTDIR;
482*11337SWilliam.Krier@Sun.COM 
483*11337SWilliam.Krier@Sun.COM 	if (err) {
484*11337SWilliam.Krier@Sun.COM 		if (fnode)
485*11337SWilliam.Krier@Sun.COM 			smb_node_release(fnode);
486*11337SWilliam.Krier@Sun.COM 		if (dnode)
487*11337SWilliam.Krier@Sun.COM 			smb_node_release(dnode);
488*11337SWilliam.Krier@Sun.COM 	} else {
489*11337SWilliam.Krier@Sun.COM 		*ret_node = fnode;
490*11337SWilliam.Krier@Sun.COM 
491*11337SWilliam.Krier@Sun.COM 		if (dir_node)
492*11337SWilliam.Krier@Sun.COM 			*dir_node = dnode;
493*11337SWilliam.Krier@Sun.COM 		else
494*11337SWilliam.Krier@Sun.COM 			smb_node_release(dnode);
495*11337SWilliam.Krier@Sun.COM 	}
496*11337SWilliam.Krier@Sun.COM 
497*11337SWilliam.Krier@Sun.COM 	kmem_free(component, MAXNAMELEN);
498*11337SWilliam.Krier@Sun.COM 	kmem_free(real_name, MAXNAMELEN);
499*11337SWilliam.Krier@Sun.COM 	(void) pn_free(&pn);
500*11337SWilliam.Krier@Sun.COM 	(void) pn_free(&rpn);
501*11337SWilliam.Krier@Sun.COM 	(void) pn_free(&upn);
502*11337SWilliam.Krier@Sun.COM 
503*11337SWilliam.Krier@Sun.COM 	return (err);
504*11337SWilliam.Krier@Sun.COM }
505*11337SWilliam.Krier@Sun.COM 
506*11337SWilliam.Krier@Sun.COM /*
507*11337SWilliam.Krier@Sun.COM  * Holds on dvp and rootvp (if not rootdir) are required by lookuppnvp()
508*11337SWilliam.Krier@Sun.COM  * and will be released within lookuppnvp().
509*11337SWilliam.Krier@Sun.COM  */
510*11337SWilliam.Krier@Sun.COM static int
511*11337SWilliam.Krier@Sun.COM smb_pathname_lookup(pathname_t *pn, pathname_t *rpn, int flags,
512*11337SWilliam.Krier@Sun.COM     vnode_t **vp, vnode_t *rootvp, vnode_t *dvp, cred_t *cred)
513*11337SWilliam.Krier@Sun.COM {
514*11337SWilliam.Krier@Sun.COM 	int err;
515*11337SWilliam.Krier@Sun.COM 
516*11337SWilliam.Krier@Sun.COM 	*vp = NULL;
517*11337SWilliam.Krier@Sun.COM 	VN_HOLD(dvp);
518*11337SWilliam.Krier@Sun.COM 	if (rootvp != rootdir)
519*11337SWilliam.Krier@Sun.COM 		VN_HOLD(rootvp);
520*11337SWilliam.Krier@Sun.COM 
521*11337SWilliam.Krier@Sun.COM 	err = lookuppnvp(pn, rpn, flags, NULL, vp, rootvp, dvp, cred);
522*11337SWilliam.Krier@Sun.COM 	return (err);
523*11337SWilliam.Krier@Sun.COM }
524*11337SWilliam.Krier@Sun.COM 
525*11337SWilliam.Krier@Sun.COM /*
526*11337SWilliam.Krier@Sun.COM  * CATIA Translation of a pathname component prior to passing it to lookuppnvp
527*11337SWilliam.Krier@Sun.COM  *
528*11337SWilliam.Krier@Sun.COM  * If the translated component name contains a '/' NULL is returned.
529*11337SWilliam.Krier@Sun.COM  * The caller should treat this as error EILSEQ. It is not valid to
530*11337SWilliam.Krier@Sun.COM  * have a directory name with a '/'.
531*11337SWilliam.Krier@Sun.COM  */
532*11337SWilliam.Krier@Sun.COM static char *
533*11337SWilliam.Krier@Sun.COM smb_pathname_catia_v5tov4(smb_request_t *sr, char *name,
534*11337SWilliam.Krier@Sun.COM     char *namebuf, int buflen)
535*11337SWilliam.Krier@Sun.COM {
536*11337SWilliam.Krier@Sun.COM 	char *namep;
537*11337SWilliam.Krier@Sun.COM 
538*11337SWilliam.Krier@Sun.COM 	if (SMB_TREE_SUPPORTS_CATIA(sr)) {
539*11337SWilliam.Krier@Sun.COM 		namep = smb_vop_catia_v5tov4(name, namebuf, buflen);
540*11337SWilliam.Krier@Sun.COM 		if (strchr(namep, '/') != NULL)
541*11337SWilliam.Krier@Sun.COM 			return (NULL);
542*11337SWilliam.Krier@Sun.COM 		return (namep);
543*11337SWilliam.Krier@Sun.COM 	}
544*11337SWilliam.Krier@Sun.COM 
545*11337SWilliam.Krier@Sun.COM 	return (name);
546*11337SWilliam.Krier@Sun.COM }
547*11337SWilliam.Krier@Sun.COM 
548*11337SWilliam.Krier@Sun.COM /*
549*11337SWilliam.Krier@Sun.COM  * CATIA translation of a pathname component after returning from lookuppnvp
550*11337SWilliam.Krier@Sun.COM  */
551*11337SWilliam.Krier@Sun.COM static char *
552*11337SWilliam.Krier@Sun.COM smb_pathname_catia_v4tov5(smb_request_t *sr, char *name,
553*11337SWilliam.Krier@Sun.COM     char *namebuf, int buflen)
554*11337SWilliam.Krier@Sun.COM {
555*11337SWilliam.Krier@Sun.COM 	if (SMB_TREE_SUPPORTS_CATIA(sr)) {
556*11337SWilliam.Krier@Sun.COM 		smb_vop_catia_v4tov5(name, namebuf, buflen);
557*11337SWilliam.Krier@Sun.COM 		return (namebuf);
558*11337SWilliam.Krier@Sun.COM 	}
559*11337SWilliam.Krier@Sun.COM 
560*11337SWilliam.Krier@Sun.COM 	return (name);
561*11337SWilliam.Krier@Sun.COM }
562*11337SWilliam.Krier@Sun.COM 
563*11337SWilliam.Krier@Sun.COM /*
564*11337SWilliam.Krier@Sun.COM  * sr - needed to check for case sense
565*11337SWilliam.Krier@Sun.COM  * path - non mangled path needed to be looked up from the startvp
566*11337SWilliam.Krier@Sun.COM  * startvp - the vnode to start the lookup from
567*11337SWilliam.Krier@Sun.COM  * rootvp - the vnode of the root of the filesystem
568*11337SWilliam.Krier@Sun.COM  * returns the vnode found when starting at startvp and using the path
569*11337SWilliam.Krier@Sun.COM  *
570*11337SWilliam.Krier@Sun.COM  * Finds a vnode starting at startvp and parsing the non mangled path
571*11337SWilliam.Krier@Sun.COM  */
572*11337SWilliam.Krier@Sun.COM 
573*11337SWilliam.Krier@Sun.COM vnode_t *
574*11337SWilliam.Krier@Sun.COM smb_lookuppathvptovp(smb_request_t *sr, char *path, vnode_t *startvp,
575*11337SWilliam.Krier@Sun.COM     vnode_t *rootvp)
576*11337SWilliam.Krier@Sun.COM {
577*11337SWilliam.Krier@Sun.COM 	pathname_t pn;
578*11337SWilliam.Krier@Sun.COM 	vnode_t *vp = NULL;
579*11337SWilliam.Krier@Sun.COM 	int lookup_flags = FOLLOW;
580*11337SWilliam.Krier@Sun.COM 
581*11337SWilliam.Krier@Sun.COM 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
582*11337SWilliam.Krier@Sun.COM 		lookup_flags |= FIGNORECASE;
583*11337SWilliam.Krier@Sun.COM 
584*11337SWilliam.Krier@Sun.COM 	(void) pn_alloc(&pn);
585*11337SWilliam.Krier@Sun.COM 
586*11337SWilliam.Krier@Sun.COM 	if (pn_set(&pn, path) == 0) {
587*11337SWilliam.Krier@Sun.COM 		VN_HOLD(startvp);
588*11337SWilliam.Krier@Sun.COM 		if (rootvp != rootdir)
589*11337SWilliam.Krier@Sun.COM 			VN_HOLD(rootvp);
590*11337SWilliam.Krier@Sun.COM 
591*11337SWilliam.Krier@Sun.COM 		/* lookuppnvp should release the holds */
592*11337SWilliam.Krier@Sun.COM 		if (lookuppnvp(&pn, NULL, lookup_flags, NULL, &vp,
593*11337SWilliam.Krier@Sun.COM 		    rootvp, startvp, kcred) != 0) {
594*11337SWilliam.Krier@Sun.COM 			pn_free(&pn);
595*11337SWilliam.Krier@Sun.COM 			return (NULL);
596*11337SWilliam.Krier@Sun.COM 		}
597*11337SWilliam.Krier@Sun.COM 	}
598*11337SWilliam.Krier@Sun.COM 
599*11337SWilliam.Krier@Sun.COM 	pn_free(&pn);
600*11337SWilliam.Krier@Sun.COM 	return (vp);
601*11337SWilliam.Krier@Sun.COM }
602*11337SWilliam.Krier@Sun.COM 
603*11337SWilliam.Krier@Sun.COM /*
604*11337SWilliam.Krier@Sun.COM  * smb_pathname_init
605*11337SWilliam.Krier@Sun.COM  * Parse path: pname\\fname:sname:stype
606*11337SWilliam.Krier@Sun.COM  *
607*11337SWilliam.Krier@Sun.COM  * Elements of the smb_pathname_t structure are allocated using request
608*11337SWilliam.Krier@Sun.COM  * specific storage and will be free'd when the sr is destroyed.
609*11337SWilliam.Krier@Sun.COM  *
610*11337SWilliam.Krier@Sun.COM  * Populate pn structure elements with the individual elements
611*11337SWilliam.Krier@Sun.COM  * of pn->pn_path. pn->pn_sname will contain the whole stream name
612*11337SWilliam.Krier@Sun.COM  * including the stream type and preceding colon: :sname:%DATA
613*11337SWilliam.Krier@Sun.COM  * pn_stype will point to the stream type within pn_sname.
614*11337SWilliam.Krier@Sun.COM  *
615*11337SWilliam.Krier@Sun.COM  * If the pname element is missing pn_pname will be set to "\\".
616*11337SWilliam.Krier@Sun.COM  * If any other element is missing the pointer in pn will be NULL.
617*11337SWilliam.Krier@Sun.COM  */
618*11337SWilliam.Krier@Sun.COM void
619*11337SWilliam.Krier@Sun.COM smb_pathname_init(smb_request_t *sr, smb_pathname_t *pn, char *path)
620*11337SWilliam.Krier@Sun.COM {
621*11337SWilliam.Krier@Sun.COM 	char *pname, *fname, *sname;
622*11337SWilliam.Krier@Sun.COM 	int len;
623*11337SWilliam.Krier@Sun.COM 
624*11337SWilliam.Krier@Sun.COM 	bzero(pn, sizeof (smb_pathname_t));
625*11337SWilliam.Krier@Sun.COM 	pn->pn_path = smb_pathname_strdup(sr, path);
626*11337SWilliam.Krier@Sun.COM 
627*11337SWilliam.Krier@Sun.COM 	smb_pathname_preprocess(sr, pn);
628*11337SWilliam.Krier@Sun.COM 
629*11337SWilliam.Krier@Sun.COM 	/* parse pn->pn_path into its constituent parts */
630*11337SWilliam.Krier@Sun.COM 	pname = pn->pn_path;
631*11337SWilliam.Krier@Sun.COM 	fname = strrchr(pn->pn_path, '\\');
632*11337SWilliam.Krier@Sun.COM 
633*11337SWilliam.Krier@Sun.COM 	if (fname) {
634*11337SWilliam.Krier@Sun.COM 		if (fname == pname) {
635*11337SWilliam.Krier@Sun.COM 			pn->pn_pname = smb_pathname_strdup(sr, "\\");
636*11337SWilliam.Krier@Sun.COM 		} else {
637*11337SWilliam.Krier@Sun.COM 			*fname = '\0';
638*11337SWilliam.Krier@Sun.COM 			pn->pn_pname =
639*11337SWilliam.Krier@Sun.COM 			    smb_pathname_strdup(sr, pname);
640*11337SWilliam.Krier@Sun.COM 			*fname = '\\';
641*11337SWilliam.Krier@Sun.COM 		}
642*11337SWilliam.Krier@Sun.COM 		++fname;
643*11337SWilliam.Krier@Sun.COM 	} else {
644*11337SWilliam.Krier@Sun.COM 		fname = pname;
645*11337SWilliam.Krier@Sun.COM 		pn->pn_pname = smb_pathname_strdup(sr, "\\");
646*11337SWilliam.Krier@Sun.COM 	}
647*11337SWilliam.Krier@Sun.COM 
648*11337SWilliam.Krier@Sun.COM 	if (fname[0] == '\0') {
649*11337SWilliam.Krier@Sun.COM 		pn->pn_fname = NULL;
650*11337SWilliam.Krier@Sun.COM 		return;
651*11337SWilliam.Krier@Sun.COM 	}
652*11337SWilliam.Krier@Sun.COM 
653*11337SWilliam.Krier@Sun.COM 	if (!smb_is_stream_name(fname)) {
654*11337SWilliam.Krier@Sun.COM 		pn->pn_fname = smb_pathname_strdup(sr, fname);
655*11337SWilliam.Krier@Sun.COM 		return;
656*11337SWilliam.Krier@Sun.COM 	}
657*11337SWilliam.Krier@Sun.COM 
658*11337SWilliam.Krier@Sun.COM 	/*
659*11337SWilliam.Krier@Sun.COM 	 * find sname and stype in fname.
660*11337SWilliam.Krier@Sun.COM 	 * sname can't be NULL smb_is_stream_name checks this
661*11337SWilliam.Krier@Sun.COM 	 */
662*11337SWilliam.Krier@Sun.COM 	sname = strchr(fname, ':');
663*11337SWilliam.Krier@Sun.COM 	if (sname == fname)
664*11337SWilliam.Krier@Sun.COM 		fname = NULL;
665*11337SWilliam.Krier@Sun.COM 	else {
666*11337SWilliam.Krier@Sun.COM 		*sname = '\0';
667*11337SWilliam.Krier@Sun.COM 		pn->pn_fname =
668*11337SWilliam.Krier@Sun.COM 		    smb_pathname_strdup(sr, fname);
669*11337SWilliam.Krier@Sun.COM 		*sname = ':';
670*11337SWilliam.Krier@Sun.COM 	}
671*11337SWilliam.Krier@Sun.COM 
672*11337SWilliam.Krier@Sun.COM 	pn->pn_sname = smb_pathname_strdup(sr, sname);
673*11337SWilliam.Krier@Sun.COM 	pn->pn_stype = strchr(pn->pn_sname + 1, ':');
674*11337SWilliam.Krier@Sun.COM 	if (pn->pn_stype) {
675*11337SWilliam.Krier@Sun.COM 		(void) smb_strupr(pn->pn_stype);
676*11337SWilliam.Krier@Sun.COM 	} else {
677*11337SWilliam.Krier@Sun.COM 		len = strlen(pn->pn_sname);
678*11337SWilliam.Krier@Sun.COM 		pn->pn_sname = smb_pathname_strcat(sr, pn->pn_sname, ":$DATA");
679*11337SWilliam.Krier@Sun.COM 		pn->pn_stype = pn->pn_sname + len;
680*11337SWilliam.Krier@Sun.COM 	}
681*11337SWilliam.Krier@Sun.COM 	++pn->pn_stype;
682*11337SWilliam.Krier@Sun.COM }
683*11337SWilliam.Krier@Sun.COM 
684*11337SWilliam.Krier@Sun.COM /*
685*11337SWilliam.Krier@Sun.COM  * smb_pathname_preprocess
686*11337SWilliam.Krier@Sun.COM  *
687*11337SWilliam.Krier@Sun.COM  * Perform common pre-processing of pn->pn_path:
688*11337SWilliam.Krier@Sun.COM  * - if the pn_path is blank, set it to '\\'
689*11337SWilliam.Krier@Sun.COM  * - perform unicode wildcard converstion.
690*11337SWilliam.Krier@Sun.COM  * - convert any '/' to '\\'
691*11337SWilliam.Krier@Sun.COM  * - eliminate duplicate slashes
692*11337SWilliam.Krier@Sun.COM  * - remove trailing slashes
693*11337SWilliam.Krier@Sun.COM  */
694*11337SWilliam.Krier@Sun.COM static void
695*11337SWilliam.Krier@Sun.COM smb_pathname_preprocess(smb_request_t *sr, smb_pathname_t *pn)
696*11337SWilliam.Krier@Sun.COM {
697*11337SWilliam.Krier@Sun.COM 	char *p;
698*11337SWilliam.Krier@Sun.COM 
699*11337SWilliam.Krier@Sun.COM 	/* treat empty path as "\\" */
700*11337SWilliam.Krier@Sun.COM 	if (strlen(pn->pn_path) == 0) {
701*11337SWilliam.Krier@Sun.COM 		pn->pn_path = smb_pathname_strdup(sr, "\\");
702*11337SWilliam.Krier@Sun.COM 		return;
703*11337SWilliam.Krier@Sun.COM 	}
704*11337SWilliam.Krier@Sun.COM 
705*11337SWilliam.Krier@Sun.COM 	/* perform unicode wildcard conversion */
706*11337SWilliam.Krier@Sun.COM 	smb_convert_wildcards(pn->pn_path);
707*11337SWilliam.Krier@Sun.COM 
708*11337SWilliam.Krier@Sun.COM 	/* treat '/' as '\\' */
709*11337SWilliam.Krier@Sun.COM 	(void) strsubst(pn->pn_path, '/', '\\');
710*11337SWilliam.Krier@Sun.COM 
711*11337SWilliam.Krier@Sun.COM 	(void) strcanon(pn->pn_path, "\\");
712*11337SWilliam.Krier@Sun.COM 
713*11337SWilliam.Krier@Sun.COM 	/* remove trailing '\\' */
714*11337SWilliam.Krier@Sun.COM 	p = pn->pn_path + strlen(pn->pn_path) - 1;
715*11337SWilliam.Krier@Sun.COM 	if ((p != pn->pn_path) && (*p == '\\'))
716*11337SWilliam.Krier@Sun.COM 		*p = '\0';
717*11337SWilliam.Krier@Sun.COM }
718*11337SWilliam.Krier@Sun.COM 
719*11337SWilliam.Krier@Sun.COM /*
720*11337SWilliam.Krier@Sun.COM  * smb_pathname_strdup
721*11337SWilliam.Krier@Sun.COM  *
722*11337SWilliam.Krier@Sun.COM  * Duplicate NULL terminated string s.
723*11337SWilliam.Krier@Sun.COM  *
724*11337SWilliam.Krier@Sun.COM  * The new string is allocated using request specific storage and will
725*11337SWilliam.Krier@Sun.COM  * be free'd when the sr is destroyed.
726*11337SWilliam.Krier@Sun.COM  */
727*11337SWilliam.Krier@Sun.COM static char *
728*11337SWilliam.Krier@Sun.COM smb_pathname_strdup(smb_request_t *sr, const char *s)
729*11337SWilliam.Krier@Sun.COM {
730*11337SWilliam.Krier@Sun.COM 	char *s2;
731*11337SWilliam.Krier@Sun.COM 	size_t n;
732*11337SWilliam.Krier@Sun.COM 
733*11337SWilliam.Krier@Sun.COM 	n = strlen(s) + 1;
734*11337SWilliam.Krier@Sun.COM 	s2 = smb_srm_alloc(sr, n);
735*11337SWilliam.Krier@Sun.COM 	(void) strlcpy(s2, s, n);
736*11337SWilliam.Krier@Sun.COM 	return (s2);
737*11337SWilliam.Krier@Sun.COM }
738*11337SWilliam.Krier@Sun.COM 
739*11337SWilliam.Krier@Sun.COM /*
740*11337SWilliam.Krier@Sun.COM  * smb_pathname_strcat
741*11337SWilliam.Krier@Sun.COM  *
742*11337SWilliam.Krier@Sun.COM  * Reallocate NULL terminated string s1 to accommodate
743*11337SWilliam.Krier@Sun.COM  * concatenating  NULL terminated string s2.
744*11337SWilliam.Krier@Sun.COM  * Append s2 and return resulting NULL terminated string.
745*11337SWilliam.Krier@Sun.COM  *
746*11337SWilliam.Krier@Sun.COM  * The string buffer is reallocated using request specific
747*11337SWilliam.Krier@Sun.COM  * storage and will be free'd when the sr is destroyed.
748*11337SWilliam.Krier@Sun.COM  */
749*11337SWilliam.Krier@Sun.COM static char *
750*11337SWilliam.Krier@Sun.COM smb_pathname_strcat(smb_request_t *sr, char *s1, const char *s2)
751*11337SWilliam.Krier@Sun.COM {
752*11337SWilliam.Krier@Sun.COM 	size_t n;
753*11337SWilliam.Krier@Sun.COM 
754*11337SWilliam.Krier@Sun.COM 	n = strlen(s1) + strlen(s2) + 1;
755*11337SWilliam.Krier@Sun.COM 	s1 = smb_srm_realloc(sr, s1, n);
756*11337SWilliam.Krier@Sun.COM 	(void) strlcat(s1, s2, n);
757*11337SWilliam.Krier@Sun.COM 	return (s1);
758*11337SWilliam.Krier@Sun.COM }
759*11337SWilliam.Krier@Sun.COM 
760*11337SWilliam.Krier@Sun.COM /*
761*11337SWilliam.Krier@Sun.COM  * smb_pathname_validate
762*11337SWilliam.Krier@Sun.COM  *
763*11337SWilliam.Krier@Sun.COM  * Perform basic validation of pn:
764*11337SWilliam.Krier@Sun.COM  * - If first component of pn->path is ".." -> PATH_SYNTAX_BAD
765*11337SWilliam.Krier@Sun.COM  * - If there are wildcards in pn->pn_pname -> OBJECT_NAME_INVALID
766*11337SWilliam.Krier@Sun.COM  * - If fname is "." -> INVALID_OBJECT_NAME
767*11337SWilliam.Krier@Sun.COM  *
768*11337SWilliam.Krier@Sun.COM  * On unix .. at the root of a file system links to the root. Thus
769*11337SWilliam.Krier@Sun.COM  * an attempt to lookup "/../../.." will be the same as looking up "/"
770*11337SWilliam.Krier@Sun.COM  * CIFs clients expect the above to result in
771*11337SWilliam.Krier@Sun.COM  * NT_STATUS_OBJECT_PATH_SYNTAX_BAD. It is currently not possible
772*11337SWilliam.Krier@Sun.COM  * (and questionable if it's desirable) to deal with all cases
773*11337SWilliam.Krier@Sun.COM  * but paths beginning with \\.. are handled.
774*11337SWilliam.Krier@Sun.COM  *
775*11337SWilliam.Krier@Sun.COM  * Returns: B_TRUE if pn is valid,
776*11337SWilliam.Krier@Sun.COM  *          otherwise returns B_FALSE and sets error status in sr.
777*11337SWilliam.Krier@Sun.COM  */
778*11337SWilliam.Krier@Sun.COM boolean_t
779*11337SWilliam.Krier@Sun.COM smb_pathname_validate(smb_request_t *sr, smb_pathname_t *pn)
780*11337SWilliam.Krier@Sun.COM {
781*11337SWilliam.Krier@Sun.COM 	char *path = pn->pn_path;
782*11337SWilliam.Krier@Sun.COM 
783*11337SWilliam.Krier@Sun.COM 	/* ignore any initial "\\" */
784*11337SWilliam.Krier@Sun.COM 	path += strspn(path, "\\");
785*11337SWilliam.Krier@Sun.COM 
786*11337SWilliam.Krier@Sun.COM 	/* If first component of path is ".." -> PATH_SYNTAX_BAD */
787*11337SWilliam.Krier@Sun.COM 	if ((strcmp(path, "..") == 0) || (strncmp(path, "..\\", 3) == 0)) {
788*11337SWilliam.Krier@Sun.COM 		smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
789*11337SWilliam.Krier@Sun.COM 		    ERRDOS, ERROR_BAD_PATHNAME);
790*11337SWilliam.Krier@Sun.COM 		return (B_FALSE);
791*11337SWilliam.Krier@Sun.COM 	}
792*11337SWilliam.Krier@Sun.COM 
793*11337SWilliam.Krier@Sun.COM 	/* If there are wildcards in pn->pn_pname -> OBJECT_NAME_INVALID */
794*11337SWilliam.Krier@Sun.COM 	if (pn->pn_pname && smb_contains_wildcards(pn->pn_pname)) {
795*11337SWilliam.Krier@Sun.COM 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
796*11337SWilliam.Krier@Sun.COM 		    ERRDOS, ERROR_INVALID_NAME);
797*11337SWilliam.Krier@Sun.COM 		return (B_FALSE);
798*11337SWilliam.Krier@Sun.COM 	}
799*11337SWilliam.Krier@Sun.COM 
800*11337SWilliam.Krier@Sun.COM 	/* If fname is "." -> INVALID_OBJECT_NAME */
801*11337SWilliam.Krier@Sun.COM 	if (pn->pn_fname && (strcmp(pn->pn_fname, ".") == 0)) {
802*11337SWilliam.Krier@Sun.COM 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
803*11337SWilliam.Krier@Sun.COM 		    ERRDOS, ERROR_PATH_NOT_FOUND);
804*11337SWilliam.Krier@Sun.COM 		return (B_FALSE);
805*11337SWilliam.Krier@Sun.COM 	}
806*11337SWilliam.Krier@Sun.COM 
807*11337SWilliam.Krier@Sun.COM 	return (B_TRUE);
808*11337SWilliam.Krier@Sun.COM }
809*11337SWilliam.Krier@Sun.COM 
810*11337SWilliam.Krier@Sun.COM /*
811*11337SWilliam.Krier@Sun.COM  * smb_validate_dirname
812*11337SWilliam.Krier@Sun.COM  *
813*11337SWilliam.Krier@Sun.COM  * smb_pathname_validate() should have already been performed on pn.
814*11337SWilliam.Krier@Sun.COM  *
815*11337SWilliam.Krier@Sun.COM  * Very basic directory name validation:  checks for colons in a path.
816*11337SWilliam.Krier@Sun.COM  * Need to skip the drive prefix since it contains a colon.
817*11337SWilliam.Krier@Sun.COM  *
818*11337SWilliam.Krier@Sun.COM  * Returns: B_TRUE if the name is valid,
819*11337SWilliam.Krier@Sun.COM  *          otherwise returns B_FALSE and sets error status in sr.
820*11337SWilliam.Krier@Sun.COM  */
821*11337SWilliam.Krier@Sun.COM boolean_t
822*11337SWilliam.Krier@Sun.COM smb_validate_dirname(smb_request_t *sr, smb_pathname_t *pn)
823*11337SWilliam.Krier@Sun.COM {
824*11337SWilliam.Krier@Sun.COM 	char *name;
825*11337SWilliam.Krier@Sun.COM 	char *path = pn->pn_path;
826*11337SWilliam.Krier@Sun.COM 
827*11337SWilliam.Krier@Sun.COM 	if ((name = path) != 0) {
828*11337SWilliam.Krier@Sun.COM 		name += strspn(name, "\\");
829*11337SWilliam.Krier@Sun.COM 
830*11337SWilliam.Krier@Sun.COM 		if (strchr(name, ':') != 0) {
831*11337SWilliam.Krier@Sun.COM 			smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
832*11337SWilliam.Krier@Sun.COM 			    ERRDOS, ERROR_INVALID_NAME);
833*11337SWilliam.Krier@Sun.COM 			return (B_FALSE);
834*11337SWilliam.Krier@Sun.COM 		}
835*11337SWilliam.Krier@Sun.COM 	}
836*11337SWilliam.Krier@Sun.COM 
837*11337SWilliam.Krier@Sun.COM 	return (B_TRUE);
838*11337SWilliam.Krier@Sun.COM }
839*11337SWilliam.Krier@Sun.COM 
840*11337SWilliam.Krier@Sun.COM /*
841*11337SWilliam.Krier@Sun.COM  * smb_validate_object_name
842*11337SWilliam.Krier@Sun.COM  *
843*11337SWilliam.Krier@Sun.COM  * smb_pathname_validate() should have already been pertformed on pn.
844*11337SWilliam.Krier@Sun.COM  *
845*11337SWilliam.Krier@Sun.COM  * Very basic file name validation.
846*11337SWilliam.Krier@Sun.COM  * For filenames, we check for names of the form "AAAn:". Names that
847*11337SWilliam.Krier@Sun.COM  * contain three characters, a single digit and a colon (:) are reserved
848*11337SWilliam.Krier@Sun.COM  * as DOS device names, i.e. "COM1:".
849*11337SWilliam.Krier@Sun.COM  * Stream name validation is handed off to smb_validate_stream_name
850*11337SWilliam.Krier@Sun.COM  *
851*11337SWilliam.Krier@Sun.COM  * Returns: B_TRUE if pn->pn_fname is valid,
852*11337SWilliam.Krier@Sun.COM  *          otherwise returns B_FALSE and sets error status in sr.
853*11337SWilliam.Krier@Sun.COM  */
854*11337SWilliam.Krier@Sun.COM boolean_t
855*11337SWilliam.Krier@Sun.COM smb_validate_object_name(smb_request_t *sr, smb_pathname_t *pn)
856*11337SWilliam.Krier@Sun.COM {
857*11337SWilliam.Krier@Sun.COM 	if (pn->pn_fname &&
858*11337SWilliam.Krier@Sun.COM 	    strlen(pn->pn_fname) == 5 &&
859*11337SWilliam.Krier@Sun.COM 	    smb_isdigit(pn->pn_fname[3]) &&
860*11337SWilliam.Krier@Sun.COM 	    pn->pn_fname[4] == ':') {
861*11337SWilliam.Krier@Sun.COM 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
862*11337SWilliam.Krier@Sun.COM 		    ERRDOS, ERROR_INVALID_NAME);
863*11337SWilliam.Krier@Sun.COM 		return (B_FALSE);
864*11337SWilliam.Krier@Sun.COM 	}
865*11337SWilliam.Krier@Sun.COM 
866*11337SWilliam.Krier@Sun.COM 	if (pn->pn_sname)
867*11337SWilliam.Krier@Sun.COM 		return (smb_validate_stream_name(sr, pn));
868*11337SWilliam.Krier@Sun.COM 
869*11337SWilliam.Krier@Sun.COM 	return (B_TRUE);
870*11337SWilliam.Krier@Sun.COM }
871*11337SWilliam.Krier@Sun.COM 
872*11337SWilliam.Krier@Sun.COM /*
873*11337SWilliam.Krier@Sun.COM  * smb_stream_parse_name
874*11337SWilliam.Krier@Sun.COM  *
875*11337SWilliam.Krier@Sun.COM  * smb_stream_parse_name should only be called for a path that
876*11337SWilliam.Krier@Sun.COM  * contains a valid named stream.  Path validation should have
877*11337SWilliam.Krier@Sun.COM  * been performed before this function is called.
878*11337SWilliam.Krier@Sun.COM  *
879*11337SWilliam.Krier@Sun.COM  * Find the last component of path and split it into filename
880*11337SWilliam.Krier@Sun.COM  * and stream name.
881*11337SWilliam.Krier@Sun.COM  *
882*11337SWilliam.Krier@Sun.COM  * On return the named stream type will be present.  The stream
883*11337SWilliam.Krier@Sun.COM  * type defaults to ":$DATA", if it has not been defined
884*11337SWilliam.Krier@Sun.COM  * For exmaple, 'stream' contains :<sname>:$DATA
885*11337SWilliam.Krier@Sun.COM  */
886*11337SWilliam.Krier@Sun.COM void
887*11337SWilliam.Krier@Sun.COM smb_stream_parse_name(char *path, char *filename, char *stream)
888*11337SWilliam.Krier@Sun.COM {
889*11337SWilliam.Krier@Sun.COM 	char *fname, *sname, *stype;
890*11337SWilliam.Krier@Sun.COM 
891*11337SWilliam.Krier@Sun.COM 	ASSERT(path);
892*11337SWilliam.Krier@Sun.COM 	ASSERT(filename);
893*11337SWilliam.Krier@Sun.COM 	ASSERT(stream);
894*11337SWilliam.Krier@Sun.COM 
895*11337SWilliam.Krier@Sun.COM 	fname = strrchr(path, '\\');
896*11337SWilliam.Krier@Sun.COM 	fname = (fname == NULL) ? path : fname + 1;
897*11337SWilliam.Krier@Sun.COM 	(void) strlcpy(filename, fname, MAXNAMELEN);
898*11337SWilliam.Krier@Sun.COM 
899*11337SWilliam.Krier@Sun.COM 	sname = strchr(filename, ':');
900*11337SWilliam.Krier@Sun.COM 	(void) strlcpy(stream, sname, MAXNAMELEN);
901*11337SWilliam.Krier@Sun.COM 	*sname = '\0';
902*11337SWilliam.Krier@Sun.COM 
903*11337SWilliam.Krier@Sun.COM 	stype = strchr(stream + 1, ':');
904*11337SWilliam.Krier@Sun.COM 	if (stype == NULL)
905*11337SWilliam.Krier@Sun.COM 		(void) strlcat(stream, ":$DATA", MAXNAMELEN);
906*11337SWilliam.Krier@Sun.COM 	else
907*11337SWilliam.Krier@Sun.COM 		(void) smb_strupr(stype);
908*11337SWilliam.Krier@Sun.COM }
909*11337SWilliam.Krier@Sun.COM 
910*11337SWilliam.Krier@Sun.COM /*
911*11337SWilliam.Krier@Sun.COM  * smb_is_stream_name
912*11337SWilliam.Krier@Sun.COM  *
913*11337SWilliam.Krier@Sun.COM  * Determines if 'path' specifies a named stream.
914*11337SWilliam.Krier@Sun.COM  *
915*11337SWilliam.Krier@Sun.COM  * path is a NULL terminated string which could be a stream path.
916*11337SWilliam.Krier@Sun.COM  * [pathname/]fname[:stream_name[:stream_type]]
917*11337SWilliam.Krier@Sun.COM  *
918*11337SWilliam.Krier@Sun.COM  * - If there is no colon in the path or it's the last char
919*11337SWilliam.Krier@Sun.COM  *   then it's not a stream name
920*11337SWilliam.Krier@Sun.COM  *
921*11337SWilliam.Krier@Sun.COM  * - '::' is a non-stream and is commonly used by Windows to designate
922*11337SWilliam.Krier@Sun.COM  *   the unamed stream in the form "::$DATA"
923*11337SWilliam.Krier@Sun.COM  */
924*11337SWilliam.Krier@Sun.COM boolean_t
925*11337SWilliam.Krier@Sun.COM smb_is_stream_name(char *path)
926*11337SWilliam.Krier@Sun.COM {
927*11337SWilliam.Krier@Sun.COM 	char *colonp;
928*11337SWilliam.Krier@Sun.COM 
929*11337SWilliam.Krier@Sun.COM 	if (path == NULL)
930*11337SWilliam.Krier@Sun.COM 		return (B_FALSE);
931*11337SWilliam.Krier@Sun.COM 
932*11337SWilliam.Krier@Sun.COM 	colonp = strchr(path, ':');
933*11337SWilliam.Krier@Sun.COM 	if ((colonp == NULL) || (*(colonp+1) == '\0'))
934*11337SWilliam.Krier@Sun.COM 		return (B_FALSE);
935*11337SWilliam.Krier@Sun.COM 
936*11337SWilliam.Krier@Sun.COM 	if (strstr(path, "::"))
937*11337SWilliam.Krier@Sun.COM 		return (B_FALSE);
938*11337SWilliam.Krier@Sun.COM 
939*11337SWilliam.Krier@Sun.COM 	return (B_TRUE);
940*11337SWilliam.Krier@Sun.COM }
941*11337SWilliam.Krier@Sun.COM 
942*11337SWilliam.Krier@Sun.COM /*
943*11337SWilliam.Krier@Sun.COM  * smb_validate_stream_name
944*11337SWilliam.Krier@Sun.COM  *
945*11337SWilliam.Krier@Sun.COM  * B_FALSE will be returned, and the error status ser in the sr, if:
946*11337SWilliam.Krier@Sun.COM  * - the path is not a stream name
947*11337SWilliam.Krier@Sun.COM  * - a path is specified but the fname is ommitted.
948*11337SWilliam.Krier@Sun.COM  * - the stream_type is specified but not valid.
949*11337SWilliam.Krier@Sun.COM  *
950*11337SWilliam.Krier@Sun.COM  * Note: the stream type is case-insensitive.
951*11337SWilliam.Krier@Sun.COM  */
952*11337SWilliam.Krier@Sun.COM boolean_t
953*11337SWilliam.Krier@Sun.COM smb_validate_stream_name(smb_request_t *sr, smb_pathname_t *pn)
954*11337SWilliam.Krier@Sun.COM {
955*11337SWilliam.Krier@Sun.COM 	static char *strmtype[] = {
956*11337SWilliam.Krier@Sun.COM 		"$DATA",
957*11337SWilliam.Krier@Sun.COM 		"$INDEX_ALLOCATION"
958*11337SWilliam.Krier@Sun.COM 	};
959*11337SWilliam.Krier@Sun.COM 	int i;
960*11337SWilliam.Krier@Sun.COM 
961*11337SWilliam.Krier@Sun.COM 	ASSERT(pn);
962*11337SWilliam.Krier@Sun.COM 	ASSERT(pn->pn_sname);
963*11337SWilliam.Krier@Sun.COM 
964*11337SWilliam.Krier@Sun.COM 	if ((!(pn->pn_sname)) ||
965*11337SWilliam.Krier@Sun.COM 	    ((pn->pn_pname) && !(pn->pn_fname))) {
966*11337SWilliam.Krier@Sun.COM 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
967*11337SWilliam.Krier@Sun.COM 		    ERRDOS, ERROR_INVALID_NAME);
968*11337SWilliam.Krier@Sun.COM 		return (B_FALSE);
969*11337SWilliam.Krier@Sun.COM 	}
970*11337SWilliam.Krier@Sun.COM 
971*11337SWilliam.Krier@Sun.COM 
972*11337SWilliam.Krier@Sun.COM 	if (pn->pn_stype != NULL) {
973*11337SWilliam.Krier@Sun.COM 		for (i = 0; i < sizeof (strmtype) / sizeof (strmtype[0]); ++i) {
974*11337SWilliam.Krier@Sun.COM 			if (strcasecmp(pn->pn_stype, strmtype[i]) == 0)
975*11337SWilliam.Krier@Sun.COM 				return (B_TRUE);
976*11337SWilliam.Krier@Sun.COM 		}
977*11337SWilliam.Krier@Sun.COM 
978*11337SWilliam.Krier@Sun.COM 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
979*11337SWilliam.Krier@Sun.COM 		    ERRDOS, ERROR_INVALID_NAME);
980*11337SWilliam.Krier@Sun.COM 		return (B_FALSE);
981*11337SWilliam.Krier@Sun.COM 	}
982*11337SWilliam.Krier@Sun.COM 
983*11337SWilliam.Krier@Sun.COM 	return (B_TRUE);
984*11337SWilliam.Krier@Sun.COM }
985