111337SWilliam.Krier@Sun.COM /*
211337SWilliam.Krier@Sun.COM * CDDL HEADER START
311337SWilliam.Krier@Sun.COM *
411337SWilliam.Krier@Sun.COM * The contents of this file are subject to the terms of the
511337SWilliam.Krier@Sun.COM * Common Development and Distribution License (the "License").
611337SWilliam.Krier@Sun.COM * You may not use this file except in compliance with the License.
711337SWilliam.Krier@Sun.COM *
811337SWilliam.Krier@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911337SWilliam.Krier@Sun.COM * or http://www.opensolaris.org/os/licensing.
1011337SWilliam.Krier@Sun.COM * See the License for the specific language governing permissions
1111337SWilliam.Krier@Sun.COM * and limitations under the License.
1211337SWilliam.Krier@Sun.COM *
1311337SWilliam.Krier@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1411337SWilliam.Krier@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511337SWilliam.Krier@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1611337SWilliam.Krier@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1711337SWilliam.Krier@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1811337SWilliam.Krier@Sun.COM *
1911337SWilliam.Krier@Sun.COM * CDDL HEADER END
2011337SWilliam.Krier@Sun.COM */
2111337SWilliam.Krier@Sun.COM /*
2212508Samw@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
2311337SWilliam.Krier@Sun.COM */
2411337SWilliam.Krier@Sun.COM
2511337SWilliam.Krier@Sun.COM #include <smbsrv/smb_kproto.h>
2611337SWilliam.Krier@Sun.COM #include <smbsrv/smb_fsops.h>
2711337SWilliam.Krier@Sun.COM #include <sys/pathname.h>
2811337SWilliam.Krier@Sun.COM #include <sys/sdt.h>
2911337SWilliam.Krier@Sun.COM
3011337SWilliam.Krier@Sun.COM static char *smb_pathname_catia_v5tov4(smb_request_t *, char *, char *, int);
3111337SWilliam.Krier@Sun.COM static char *smb_pathname_catia_v4tov5(smb_request_t *, char *, char *, int);
3211337SWilliam.Krier@Sun.COM static int smb_pathname_lookup(pathname_t *, pathname_t *, int,
3311963SAfshin.Ardakani@Sun.COM vnode_t **, vnode_t *, vnode_t *, smb_attr_t *attr, cred_t *);
3411337SWilliam.Krier@Sun.COM static char *smb_pathname_strdup(smb_request_t *, const char *);
3511337SWilliam.Krier@Sun.COM static char *smb_pathname_strcat(smb_request_t *, char *, const char *);
3611337SWilliam.Krier@Sun.COM static void smb_pathname_preprocess(smb_request_t *, smb_pathname_t *);
3711963SAfshin.Ardakani@Sun.COM static void smb_pathname_preprocess_quota(smb_request_t *, smb_pathname_t *);
3811963SAfshin.Ardakani@Sun.COM static int smb_pathname_dfs_preprocess(smb_request_t *, char *, size_t);
3911963SAfshin.Ardakani@Sun.COM static void smb_pathname_preprocess_adminshare(smb_request_t *,
4011963SAfshin.Ardakani@Sun.COM smb_pathname_t *);
4111963SAfshin.Ardakani@Sun.COM
4211337SWilliam.Krier@Sun.COM
4311337SWilliam.Krier@Sun.COM uint32_t
smb_is_executable(char * path)4411337SWilliam.Krier@Sun.COM smb_is_executable(char *path)
4511337SWilliam.Krier@Sun.COM {
4611337SWilliam.Krier@Sun.COM char extension[5];
4711337SWilliam.Krier@Sun.COM int len = strlen(path);
4811337SWilliam.Krier@Sun.COM
4911337SWilliam.Krier@Sun.COM if ((len >= 4) && (path[len - 4] == '.')) {
5011337SWilliam.Krier@Sun.COM (void) strcpy(extension, &path[len - 3]);
5111337SWilliam.Krier@Sun.COM (void) smb_strupr(extension);
5211337SWilliam.Krier@Sun.COM
5311337SWilliam.Krier@Sun.COM if (strcmp(extension, "EXE") == 0)
5411337SWilliam.Krier@Sun.COM return (NODE_FLAGS_EXECUTABLE);
5511337SWilliam.Krier@Sun.COM
5611337SWilliam.Krier@Sun.COM if (strcmp(extension, "COM") == 0)
5711337SWilliam.Krier@Sun.COM return (NODE_FLAGS_EXECUTABLE);
5811337SWilliam.Krier@Sun.COM
5911337SWilliam.Krier@Sun.COM if (strcmp(extension, "DLL") == 0)
6011337SWilliam.Krier@Sun.COM return (NODE_FLAGS_EXECUTABLE);
6111337SWilliam.Krier@Sun.COM
6211337SWilliam.Krier@Sun.COM if (strcmp(extension, "SYM") == 0)
6311337SWilliam.Krier@Sun.COM return (NODE_FLAGS_EXECUTABLE);
6411337SWilliam.Krier@Sun.COM }
6511337SWilliam.Krier@Sun.COM
6611337SWilliam.Krier@Sun.COM return (0);
6711337SWilliam.Krier@Sun.COM }
6811337SWilliam.Krier@Sun.COM
6911337SWilliam.Krier@Sun.COM /*
7011337SWilliam.Krier@Sun.COM * smb_pathname_reduce
7111337SWilliam.Krier@Sun.COM *
7211337SWilliam.Krier@Sun.COM * smb_pathname_reduce() takes a path and returns the smb_node for the
7311337SWilliam.Krier@Sun.COM * second-to-last component of the path. It also returns the name of the last
7411337SWilliam.Krier@Sun.COM * component. Pointers for both of these fields must be supplied by the caller.
7511337SWilliam.Krier@Sun.COM *
7611337SWilliam.Krier@Sun.COM * Upon success, 0 is returned.
7711337SWilliam.Krier@Sun.COM *
7811337SWilliam.Krier@Sun.COM * Upon error, *dir_node will be set to 0.
7911337SWilliam.Krier@Sun.COM *
8011337SWilliam.Krier@Sun.COM * *sr (in)
8111337SWilliam.Krier@Sun.COM * ---
8211337SWilliam.Krier@Sun.COM * smb_request structure pointer
8311337SWilliam.Krier@Sun.COM *
8411337SWilliam.Krier@Sun.COM * *cred (in)
8511337SWilliam.Krier@Sun.COM * -----
8611337SWilliam.Krier@Sun.COM * credential
8711337SWilliam.Krier@Sun.COM *
8811337SWilliam.Krier@Sun.COM * *path (in)
8911337SWilliam.Krier@Sun.COM * -----
9011337SWilliam.Krier@Sun.COM * pathname to be looked up
9111337SWilliam.Krier@Sun.COM *
9211337SWilliam.Krier@Sun.COM * *share_root_node (in)
9311337SWilliam.Krier@Sun.COM * ----------------
9411337SWilliam.Krier@Sun.COM * File operations which are share-relative should pass sr->tid_tree->t_snode.
9511337SWilliam.Krier@Sun.COM * If the call is not for a share-relative operation, this parameter must be 0
9611337SWilliam.Krier@Sun.COM * (e.g. the call from smbsr_setup_share()). (Such callers will have path
9711337SWilliam.Krier@Sun.COM * operations done using root_smb_node.) This parameter is used to determine
9811337SWilliam.Krier@Sun.COM * whether mount points can be crossed.
9911337SWilliam.Krier@Sun.COM *
10011337SWilliam.Krier@Sun.COM * share_root_node should have at least one reference on it. This reference
10111337SWilliam.Krier@Sun.COM * will stay intact throughout this routine.
10211337SWilliam.Krier@Sun.COM *
10311337SWilliam.Krier@Sun.COM * *cur_node (in)
10411337SWilliam.Krier@Sun.COM * ---------
10511337SWilliam.Krier@Sun.COM * The smb_node for the current directory (for relative paths).
10611337SWilliam.Krier@Sun.COM * cur_node should have at least one reference on it.
10711337SWilliam.Krier@Sun.COM * This reference will stay intact throughout this routine.
10811337SWilliam.Krier@Sun.COM *
10911337SWilliam.Krier@Sun.COM * **dir_node (out)
11011337SWilliam.Krier@Sun.COM * ----------
11111337SWilliam.Krier@Sun.COM * Directory for the penultimate component of the original path.
11211337SWilliam.Krier@Sun.COM * (Note that this is not the same as the parent directory of the ultimate
11311337SWilliam.Krier@Sun.COM * target in the case of a link.)
11411337SWilliam.Krier@Sun.COM *
11511337SWilliam.Krier@Sun.COM * The directory smb_node is returned held. The caller will need to release
11611337SWilliam.Krier@Sun.COM * the hold or otherwise make sure it will get released (e.g. in a destroy
11711337SWilliam.Krier@Sun.COM * routine if made part of a global structure).
11811337SWilliam.Krier@Sun.COM *
11911337SWilliam.Krier@Sun.COM * last_component (out)
12011337SWilliam.Krier@Sun.COM * --------------
12111337SWilliam.Krier@Sun.COM * The last component of the path. (This may be different from the name of any
12211337SWilliam.Krier@Sun.COM * link target to which the last component may resolve.)
12311337SWilliam.Krier@Sun.COM *
12411337SWilliam.Krier@Sun.COM *
12511337SWilliam.Krier@Sun.COM * ____________________________
12611337SWilliam.Krier@Sun.COM *
12711337SWilliam.Krier@Sun.COM * The CIFS server lookup path needs to have logic equivalent to that of
12811337SWilliam.Krier@Sun.COM * smb_fsop_lookup(), smb_vop_lookup() and other smb_vop_*() routines in the
12911337SWilliam.Krier@Sun.COM * following areas:
13011337SWilliam.Krier@Sun.COM *
13111337SWilliam.Krier@Sun.COM * - non-traversal of child mounts (handled by smb_pathname_reduce)
13211337SWilliam.Krier@Sun.COM * - unmangling (handled in smb_pathname)
13311337SWilliam.Krier@Sun.COM * - "chroot" behavior of share root (handled by lookuppnvp)
13411337SWilliam.Krier@Sun.COM *
13511337SWilliam.Krier@Sun.COM * In addition, it needs to replace backslashes with forward slashes. It also
13611337SWilliam.Krier@Sun.COM * ensures that link processing is done correctly, and that directory
13711337SWilliam.Krier@Sun.COM * information requested by the caller is correctly returned (i.e. for paths
13811337SWilliam.Krier@Sun.COM * with a link in the last component, the directory information of the
13911337SWilliam.Krier@Sun.COM * link and not the target needs to be returned).
14011337SWilliam.Krier@Sun.COM */
14111337SWilliam.Krier@Sun.COM
14211337SWilliam.Krier@Sun.COM int
smb_pathname_reduce(smb_request_t * sr,cred_t * cred,const char * path,smb_node_t * share_root_node,smb_node_t * cur_node,smb_node_t ** dir_node,char * last_component)14311337SWilliam.Krier@Sun.COM smb_pathname_reduce(
14411337SWilliam.Krier@Sun.COM smb_request_t *sr,
14511337SWilliam.Krier@Sun.COM cred_t *cred,
14611337SWilliam.Krier@Sun.COM const char *path,
14711337SWilliam.Krier@Sun.COM smb_node_t *share_root_node,
14811337SWilliam.Krier@Sun.COM smb_node_t *cur_node,
14911337SWilliam.Krier@Sun.COM smb_node_t **dir_node,
15011337SWilliam.Krier@Sun.COM char *last_component)
15111337SWilliam.Krier@Sun.COM {
15211337SWilliam.Krier@Sun.COM smb_node_t *root_node;
15311337SWilliam.Krier@Sun.COM pathname_t ppn;
15411337SWilliam.Krier@Sun.COM char *usepath;
15511337SWilliam.Krier@Sun.COM int lookup_flags = FOLLOW;
15611337SWilliam.Krier@Sun.COM int trailing_slash = 0;
15711337SWilliam.Krier@Sun.COM int err = 0;
15811337SWilliam.Krier@Sun.COM int len;
15911337SWilliam.Krier@Sun.COM smb_node_t *vss_cur_node;
16011337SWilliam.Krier@Sun.COM smb_node_t *vss_root_node;
16111337SWilliam.Krier@Sun.COM smb_node_t *local_cur_node;
16211337SWilliam.Krier@Sun.COM smb_node_t *local_root_node;
16311337SWilliam.Krier@Sun.COM
16411337SWilliam.Krier@Sun.COM ASSERT(dir_node);
16511337SWilliam.Krier@Sun.COM ASSERT(last_component);
16611337SWilliam.Krier@Sun.COM
16711337SWilliam.Krier@Sun.COM *dir_node = NULL;
16811337SWilliam.Krier@Sun.COM *last_component = '\0';
16911337SWilliam.Krier@Sun.COM vss_cur_node = NULL;
17011337SWilliam.Krier@Sun.COM vss_root_node = NULL;
17111337SWilliam.Krier@Sun.COM
17211337SWilliam.Krier@Sun.COM if (sr && sr->tid_tree) {
17311447Samw@Sun.COM if (STYPE_ISIPC(sr->tid_tree->t_res_type))
17411337SWilliam.Krier@Sun.COM return (EACCES);
17511337SWilliam.Krier@Sun.COM }
17611337SWilliam.Krier@Sun.COM
17711337SWilliam.Krier@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr))
17811337SWilliam.Krier@Sun.COM lookup_flags |= FIGNORECASE;
17911337SWilliam.Krier@Sun.COM
18011337SWilliam.Krier@Sun.COM if (path == NULL)
18111337SWilliam.Krier@Sun.COM return (EINVAL);
18211337SWilliam.Krier@Sun.COM
18311337SWilliam.Krier@Sun.COM if (*path == '\0')
18411337SWilliam.Krier@Sun.COM return (ENOENT);
18511337SWilliam.Krier@Sun.COM
18611337SWilliam.Krier@Sun.COM usepath = kmem_alloc(MAXPATHLEN, KM_SLEEP);
18711337SWilliam.Krier@Sun.COM
18811337SWilliam.Krier@Sun.COM if ((len = strlcpy(usepath, path, MAXPATHLEN)) >= MAXPATHLEN) {
18911337SWilliam.Krier@Sun.COM kmem_free(usepath, MAXPATHLEN);
19011337SWilliam.Krier@Sun.COM return (ENAMETOOLONG);
19111337SWilliam.Krier@Sun.COM }
19211337SWilliam.Krier@Sun.COM
19311337SWilliam.Krier@Sun.COM (void) strsubst(usepath, '\\', '/');
19411337SWilliam.Krier@Sun.COM
19511337SWilliam.Krier@Sun.COM if (share_root_node)
19611337SWilliam.Krier@Sun.COM root_node = share_root_node;
19711337SWilliam.Krier@Sun.COM else
19811337SWilliam.Krier@Sun.COM root_node = sr->sr_server->si_root_smb_node;
19911337SWilliam.Krier@Sun.COM
20011337SWilliam.Krier@Sun.COM if (cur_node == NULL)
20111337SWilliam.Krier@Sun.COM cur_node = root_node;
20211337SWilliam.Krier@Sun.COM
20311337SWilliam.Krier@Sun.COM local_cur_node = cur_node;
20411337SWilliam.Krier@Sun.COM local_root_node = root_node;
20511337SWilliam.Krier@Sun.COM
20612508Samw@Sun.COM if (SMB_TREE_IS_DFSROOT(sr) && (sr->smb_flg2 & SMB_FLAGS2_DFS)) {
20711963SAfshin.Ardakani@Sun.COM err = smb_pathname_dfs_preprocess(sr, usepath, MAXPATHLEN);
20811963SAfshin.Ardakani@Sun.COM if (err != 0) {
20911963SAfshin.Ardakani@Sun.COM kmem_free(usepath, MAXPATHLEN);
21011963SAfshin.Ardakani@Sun.COM return (err);
21111963SAfshin.Ardakani@Sun.COM }
21211963SAfshin.Ardakani@Sun.COM len = strlen(usepath);
21311963SAfshin.Ardakani@Sun.COM }
21411963SAfshin.Ardakani@Sun.COM
21511337SWilliam.Krier@Sun.COM if (sr && (sr->smb_flg2 & SMB_FLAGS2_REPARSE_PATH)) {
21611337SWilliam.Krier@Sun.COM err = smb_vss_lookup_nodes(sr, root_node, cur_node,
21711337SWilliam.Krier@Sun.COM usepath, &vss_cur_node, &vss_root_node);
21811337SWilliam.Krier@Sun.COM
21911337SWilliam.Krier@Sun.COM if (err != 0) {
22011337SWilliam.Krier@Sun.COM kmem_free(usepath, MAXPATHLEN);
22111337SWilliam.Krier@Sun.COM return (err);
22211337SWilliam.Krier@Sun.COM }
22311337SWilliam.Krier@Sun.COM
22411337SWilliam.Krier@Sun.COM len = strlen(usepath);
22511337SWilliam.Krier@Sun.COM local_cur_node = vss_cur_node;
22611337SWilliam.Krier@Sun.COM local_root_node = vss_root_node;
22711337SWilliam.Krier@Sun.COM }
22811337SWilliam.Krier@Sun.COM
22911337SWilliam.Krier@Sun.COM if (usepath[len - 1] == '/')
23011337SWilliam.Krier@Sun.COM trailing_slash = 1;
23111337SWilliam.Krier@Sun.COM
23211337SWilliam.Krier@Sun.COM (void) strcanon(usepath, "/");
23311337SWilliam.Krier@Sun.COM
23411337SWilliam.Krier@Sun.COM (void) pn_alloc(&ppn);
23511337SWilliam.Krier@Sun.COM
23611337SWilliam.Krier@Sun.COM if ((err = pn_set(&ppn, usepath)) != 0) {
23711337SWilliam.Krier@Sun.COM (void) pn_free(&ppn);
23811337SWilliam.Krier@Sun.COM kmem_free(usepath, MAXPATHLEN);
23911337SWilliam.Krier@Sun.COM if (vss_cur_node != NULL)
24011337SWilliam.Krier@Sun.COM (void) smb_node_release(vss_cur_node);
24111337SWilliam.Krier@Sun.COM if (vss_root_node != NULL)
24211337SWilliam.Krier@Sun.COM (void) smb_node_release(vss_root_node);
24311337SWilliam.Krier@Sun.COM return (err);
24411337SWilliam.Krier@Sun.COM }
24511337SWilliam.Krier@Sun.COM
24611337SWilliam.Krier@Sun.COM /*
24711337SWilliam.Krier@Sun.COM * If a path does not have a trailing slash, strip off the
24811337SWilliam.Krier@Sun.COM * last component. (We only need to return an smb_node for
24911337SWilliam.Krier@Sun.COM * the second to last component; a name is returned for the
25011337SWilliam.Krier@Sun.COM * last component.)
25111337SWilliam.Krier@Sun.COM */
25211337SWilliam.Krier@Sun.COM
25311337SWilliam.Krier@Sun.COM if (trailing_slash) {
25411337SWilliam.Krier@Sun.COM (void) strlcpy(last_component, ".", MAXNAMELEN);
25511337SWilliam.Krier@Sun.COM } else {
25611337SWilliam.Krier@Sun.COM (void) pn_setlast(&ppn);
25711337SWilliam.Krier@Sun.COM (void) strlcpy(last_component, ppn.pn_path, MAXNAMELEN);
25811337SWilliam.Krier@Sun.COM ppn.pn_path[0] = '\0';
25911337SWilliam.Krier@Sun.COM }
26011337SWilliam.Krier@Sun.COM
26111337SWilliam.Krier@Sun.COM if ((strcmp(ppn.pn_buf, "/") == 0) || (ppn.pn_buf[0] == '\0')) {
26211337SWilliam.Krier@Sun.COM smb_node_ref(local_cur_node);
26311337SWilliam.Krier@Sun.COM *dir_node = local_cur_node;
26411337SWilliam.Krier@Sun.COM } else {
26511337SWilliam.Krier@Sun.COM err = smb_pathname(sr, ppn.pn_buf, lookup_flags,
26611337SWilliam.Krier@Sun.COM local_root_node, local_cur_node, NULL, dir_node, cred);
26711337SWilliam.Krier@Sun.COM }
26811337SWilliam.Krier@Sun.COM
26911337SWilliam.Krier@Sun.COM (void) pn_free(&ppn);
27011337SWilliam.Krier@Sun.COM kmem_free(usepath, MAXPATHLEN);
27111337SWilliam.Krier@Sun.COM
27211337SWilliam.Krier@Sun.COM /*
27311337SWilliam.Krier@Sun.COM * Prevent access to anything outside of the share root, except
27411337SWilliam.Krier@Sun.COM * when mapping a share because that may require traversal from
27511337SWilliam.Krier@Sun.COM * / to a mounted file system. share_root_node is NULL when
27611337SWilliam.Krier@Sun.COM * mapping a share.
27711337SWilliam.Krier@Sun.COM *
27811337SWilliam.Krier@Sun.COM * Note that we disregard whether the traversal of the path went
27911337SWilliam.Krier@Sun.COM * outside of the file system and then came back (say via a link).
28011337SWilliam.Krier@Sun.COM */
28111337SWilliam.Krier@Sun.COM
28211337SWilliam.Krier@Sun.COM if ((err == 0) && share_root_node) {
28311337SWilliam.Krier@Sun.COM if (share_root_node->vp->v_vfsp != (*dir_node)->vp->v_vfsp)
28411337SWilliam.Krier@Sun.COM err = EACCES;
28511337SWilliam.Krier@Sun.COM }
28611337SWilliam.Krier@Sun.COM
28711337SWilliam.Krier@Sun.COM if (err) {
28811337SWilliam.Krier@Sun.COM if (*dir_node) {
28911337SWilliam.Krier@Sun.COM (void) smb_node_release(*dir_node);
29011337SWilliam.Krier@Sun.COM *dir_node = NULL;
29111337SWilliam.Krier@Sun.COM }
29211337SWilliam.Krier@Sun.COM *last_component = 0;
29311337SWilliam.Krier@Sun.COM }
29411337SWilliam.Krier@Sun.COM
29511337SWilliam.Krier@Sun.COM if (vss_cur_node != NULL)
29611337SWilliam.Krier@Sun.COM (void) smb_node_release(vss_cur_node);
29711337SWilliam.Krier@Sun.COM if (vss_root_node != NULL)
29811337SWilliam.Krier@Sun.COM (void) smb_node_release(vss_root_node);
29911337SWilliam.Krier@Sun.COM
30011337SWilliam.Krier@Sun.COM return (err);
30111337SWilliam.Krier@Sun.COM }
30211337SWilliam.Krier@Sun.COM
30311337SWilliam.Krier@Sun.COM /*
30411337SWilliam.Krier@Sun.COM * smb_pathname()
30511337SWilliam.Krier@Sun.COM * wrapper to lookuppnvp(). Handles name unmangling.
30611337SWilliam.Krier@Sun.COM *
30711337SWilliam.Krier@Sun.COM * *dir_node is the true directory of the target *node.
30811337SWilliam.Krier@Sun.COM *
30911337SWilliam.Krier@Sun.COM * If any component but the last in the path is not found, ENOTDIR instead of
31011337SWilliam.Krier@Sun.COM * ENOENT will be returned.
31111337SWilliam.Krier@Sun.COM *
31211337SWilliam.Krier@Sun.COM * Path components are processed one at a time so that smb_nodes can be
31311337SWilliam.Krier@Sun.COM * created for each component. This allows the n_dnode field in the
31411337SWilliam.Krier@Sun.COM * smb_node to be properly populated.
31511337SWilliam.Krier@Sun.COM *
31611337SWilliam.Krier@Sun.COM * Because of the above, links are also processed in this routine
31711337SWilliam.Krier@Sun.COM * (i.e., we do not pass the FOLLOW flag to lookuppnvp()). This
31811337SWilliam.Krier@Sun.COM * will allow smb_nodes to be created for each component of a link.
31911337SWilliam.Krier@Sun.COM *
32011337SWilliam.Krier@Sun.COM * Mangle checking is per component. If a name is mangled, when the
32111337SWilliam.Krier@Sun.COM * unmangled name is passed to smb_pathname_lookup() do not pass
32211337SWilliam.Krier@Sun.COM * FIGNORECASE, since the unmangled name is the real on-disk name.
32311337SWilliam.Krier@Sun.COM * Otherwise pass FIGNORECASE if it's set in flags. This will cause the
32411337SWilliam.Krier@Sun.COM * file system to return "first match" in the event of a case collision.
32511337SWilliam.Krier@Sun.COM *
32611337SWilliam.Krier@Sun.COM * If CATIA character translation is enabled it is applied to each
32711337SWilliam.Krier@Sun.COM * component before passing the component to smb_pathname_lookup().
32811337SWilliam.Krier@Sun.COM * After smb_pathname_lookup() the reverse translation is applied.
32911337SWilliam.Krier@Sun.COM */
33011337SWilliam.Krier@Sun.COM
33111337SWilliam.Krier@Sun.COM int
smb_pathname(smb_request_t * sr,char * path,int flags,smb_node_t * root_node,smb_node_t * cur_node,smb_node_t ** dir_node,smb_node_t ** ret_node,cred_t * cred)33211337SWilliam.Krier@Sun.COM smb_pathname(smb_request_t *sr, char *path, int flags,
33311337SWilliam.Krier@Sun.COM smb_node_t *root_node, smb_node_t *cur_node, smb_node_t **dir_node,
33411337SWilliam.Krier@Sun.COM smb_node_t **ret_node, cred_t *cred)
33511337SWilliam.Krier@Sun.COM {
33611337SWilliam.Krier@Sun.COM char *component, *real_name, *namep;
33711337SWilliam.Krier@Sun.COM pathname_t pn, rpn, upn, link_pn;
33811337SWilliam.Krier@Sun.COM smb_node_t *dnode, *fnode;
33911963SAfshin.Ardakani@Sun.COM smb_attr_t attr;
34011337SWilliam.Krier@Sun.COM vnode_t *rootvp, *vp;
34111337SWilliam.Krier@Sun.COM size_t pathleft;
34211337SWilliam.Krier@Sun.COM int err = 0;
34311337SWilliam.Krier@Sun.COM int nlink = 0;
34411337SWilliam.Krier@Sun.COM int local_flags;
34511337SWilliam.Krier@Sun.COM uint32_t abe_flag = 0;
34611337SWilliam.Krier@Sun.COM char namebuf[MAXNAMELEN];
34711337SWilliam.Krier@Sun.COM
34811337SWilliam.Krier@Sun.COM if (path == NULL)
34911337SWilliam.Krier@Sun.COM return (EINVAL);
35011337SWilliam.Krier@Sun.COM
35111337SWilliam.Krier@Sun.COM ASSERT(root_node);
35211337SWilliam.Krier@Sun.COM ASSERT(cur_node);
35311337SWilliam.Krier@Sun.COM ASSERT(ret_node);
35411337SWilliam.Krier@Sun.COM
35511337SWilliam.Krier@Sun.COM *ret_node = NULL;
35611337SWilliam.Krier@Sun.COM
35711337SWilliam.Krier@Sun.COM if (dir_node)
35811337SWilliam.Krier@Sun.COM *dir_node = NULL;
35911337SWilliam.Krier@Sun.COM
36011337SWilliam.Krier@Sun.COM (void) pn_alloc(&upn);
36111337SWilliam.Krier@Sun.COM
36211337SWilliam.Krier@Sun.COM if ((err = pn_set(&upn, path)) != 0) {
36311337SWilliam.Krier@Sun.COM (void) pn_free(&upn);
36411337SWilliam.Krier@Sun.COM return (err);
36511337SWilliam.Krier@Sun.COM }
36611337SWilliam.Krier@Sun.COM
36711337SWilliam.Krier@Sun.COM if (SMB_TREE_SUPPORTS_ABE(sr))
36811337SWilliam.Krier@Sun.COM abe_flag = SMB_ABE;
36911337SWilliam.Krier@Sun.COM
37011337SWilliam.Krier@Sun.COM (void) pn_alloc(&pn);
37111337SWilliam.Krier@Sun.COM (void) pn_alloc(&rpn);
37211337SWilliam.Krier@Sun.COM
37311337SWilliam.Krier@Sun.COM component = kmem_alloc(MAXNAMELEN, KM_SLEEP);
37411337SWilliam.Krier@Sun.COM real_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
37511337SWilliam.Krier@Sun.COM
37611337SWilliam.Krier@Sun.COM fnode = NULL;
37711337SWilliam.Krier@Sun.COM dnode = cur_node;
37811337SWilliam.Krier@Sun.COM smb_node_ref(dnode);
37911337SWilliam.Krier@Sun.COM rootvp = root_node->vp;
38011337SWilliam.Krier@Sun.COM
38111337SWilliam.Krier@Sun.COM while ((pathleft = pn_pathleft(&upn)) != 0) {
38211337SWilliam.Krier@Sun.COM if (fnode) {
38311337SWilliam.Krier@Sun.COM smb_node_release(dnode);
38411337SWilliam.Krier@Sun.COM dnode = fnode;
38511337SWilliam.Krier@Sun.COM fnode = NULL;
38611337SWilliam.Krier@Sun.COM }
38711337SWilliam.Krier@Sun.COM
38811337SWilliam.Krier@Sun.COM if ((err = pn_getcomponent(&upn, component)) != 0)
38911337SWilliam.Krier@Sun.COM break;
39011337SWilliam.Krier@Sun.COM
39111337SWilliam.Krier@Sun.COM if ((namep = smb_pathname_catia_v5tov4(sr, component,
39211337SWilliam.Krier@Sun.COM namebuf, sizeof (namebuf))) == NULL) {
39311337SWilliam.Krier@Sun.COM err = EILSEQ;
39411337SWilliam.Krier@Sun.COM break;
39511337SWilliam.Krier@Sun.COM }
39611337SWilliam.Krier@Sun.COM
39711337SWilliam.Krier@Sun.COM if ((err = pn_set(&pn, namep)) != 0)
39811337SWilliam.Krier@Sun.COM break;
39911337SWilliam.Krier@Sun.COM
40011337SWilliam.Krier@Sun.COM local_flags = flags & FIGNORECASE;
40111337SWilliam.Krier@Sun.COM err = smb_pathname_lookup(&pn, &rpn, local_flags,
40211963SAfshin.Ardakani@Sun.COM &vp, rootvp, dnode->vp, &attr, cred);
40311337SWilliam.Krier@Sun.COM
40411337SWilliam.Krier@Sun.COM if (err) {
405*12890SJoyce.McIntosh@Sun.COM if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) ||
406*12890SJoyce.McIntosh@Sun.COM !smb_maybe_mangled(component))
40711337SWilliam.Krier@Sun.COM break;
40811337SWilliam.Krier@Sun.COM
40912508Samw@Sun.COM if ((err = smb_unmangle(dnode, component,
41011337SWilliam.Krier@Sun.COM real_name, MAXNAMELEN, abe_flag)) != 0)
41111337SWilliam.Krier@Sun.COM break;
41211337SWilliam.Krier@Sun.COM
41311337SWilliam.Krier@Sun.COM if ((namep = smb_pathname_catia_v5tov4(sr, real_name,
41411337SWilliam.Krier@Sun.COM namebuf, sizeof (namebuf))) == NULL) {
41511337SWilliam.Krier@Sun.COM err = EILSEQ;
41611337SWilliam.Krier@Sun.COM break;
41711337SWilliam.Krier@Sun.COM }
41811337SWilliam.Krier@Sun.COM
41911337SWilliam.Krier@Sun.COM if ((err = pn_set(&pn, namep)) != 0)
42011337SWilliam.Krier@Sun.COM break;
42111337SWilliam.Krier@Sun.COM
42211337SWilliam.Krier@Sun.COM local_flags = 0;
42311337SWilliam.Krier@Sun.COM err = smb_pathname_lookup(&pn, &rpn, local_flags,
42411963SAfshin.Ardakani@Sun.COM &vp, rootvp, dnode->vp, &attr, cred);
42511337SWilliam.Krier@Sun.COM if (err)
42611337SWilliam.Krier@Sun.COM break;
42711337SWilliam.Krier@Sun.COM }
42811337SWilliam.Krier@Sun.COM
42911963SAfshin.Ardakani@Sun.COM /*
43011963SAfshin.Ardakani@Sun.COM * This check MUST be done before symlink check
43111963SAfshin.Ardakani@Sun.COM * since a reparse point is of type VLNK but should
43211963SAfshin.Ardakani@Sun.COM * not be handled like a regular symlink.
43311963SAfshin.Ardakani@Sun.COM */
43411963SAfshin.Ardakani@Sun.COM if (attr.sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) {
43511963SAfshin.Ardakani@Sun.COM err = EREMOTE;
43611963SAfshin.Ardakani@Sun.COM VN_RELE(vp);
43711963SAfshin.Ardakani@Sun.COM break;
43811963SAfshin.Ardakani@Sun.COM }
43911963SAfshin.Ardakani@Sun.COM
44011337SWilliam.Krier@Sun.COM if ((vp->v_type == VLNK) &&
44111337SWilliam.Krier@Sun.COM ((flags & FOLLOW) || pn_pathleft(&upn))) {
44211337SWilliam.Krier@Sun.COM
44311337SWilliam.Krier@Sun.COM if (++nlink > MAXSYMLINKS) {
44411337SWilliam.Krier@Sun.COM err = ELOOP;
44511337SWilliam.Krier@Sun.COM VN_RELE(vp);
44611337SWilliam.Krier@Sun.COM break;
44711337SWilliam.Krier@Sun.COM }
44811337SWilliam.Krier@Sun.COM
44911337SWilliam.Krier@Sun.COM (void) pn_alloc(&link_pn);
45011337SWilliam.Krier@Sun.COM err = pn_getsymlink(vp, &link_pn, cred);
45111337SWilliam.Krier@Sun.COM VN_RELE(vp);
45211337SWilliam.Krier@Sun.COM
45311337SWilliam.Krier@Sun.COM if (err == 0) {
45411337SWilliam.Krier@Sun.COM if (pn_pathleft(&link_pn) == 0)
45511337SWilliam.Krier@Sun.COM (void) pn_set(&link_pn, ".");
45611337SWilliam.Krier@Sun.COM err = pn_insert(&upn, &link_pn,
45711337SWilliam.Krier@Sun.COM strlen(component));
45811337SWilliam.Krier@Sun.COM }
45911337SWilliam.Krier@Sun.COM pn_free(&link_pn);
46011337SWilliam.Krier@Sun.COM
46111337SWilliam.Krier@Sun.COM if (err)
46211337SWilliam.Krier@Sun.COM break;
46311337SWilliam.Krier@Sun.COM
46411337SWilliam.Krier@Sun.COM if (upn.pn_pathlen == 0) {
46511337SWilliam.Krier@Sun.COM err = ENOENT;
46611337SWilliam.Krier@Sun.COM break;
46711337SWilliam.Krier@Sun.COM }
46811337SWilliam.Krier@Sun.COM
46911337SWilliam.Krier@Sun.COM if (upn.pn_path[0] == '/') {
47011337SWilliam.Krier@Sun.COM fnode = root_node;
47111337SWilliam.Krier@Sun.COM smb_node_ref(fnode);
47211337SWilliam.Krier@Sun.COM }
47311337SWilliam.Krier@Sun.COM
47411337SWilliam.Krier@Sun.COM if (pn_fixslash(&upn))
47511337SWilliam.Krier@Sun.COM flags |= FOLLOW;
47611337SWilliam.Krier@Sun.COM
47711337SWilliam.Krier@Sun.COM } else {
47811337SWilliam.Krier@Sun.COM if (flags & FIGNORECASE) {
47911337SWilliam.Krier@Sun.COM if (strcmp(rpn.pn_path, "/") != 0)
48011337SWilliam.Krier@Sun.COM pn_setlast(&rpn);
48111337SWilliam.Krier@Sun.COM namep = rpn.pn_path;
48211337SWilliam.Krier@Sun.COM } else {
48311337SWilliam.Krier@Sun.COM namep = pn.pn_path;
48411337SWilliam.Krier@Sun.COM }
48511337SWilliam.Krier@Sun.COM
48611337SWilliam.Krier@Sun.COM namep = smb_pathname_catia_v4tov5(sr, namep,
48711337SWilliam.Krier@Sun.COM namebuf, sizeof (namebuf));
48811337SWilliam.Krier@Sun.COM
48911337SWilliam.Krier@Sun.COM fnode = smb_node_lookup(sr, NULL, cred, vp, namep,
49011337SWilliam.Krier@Sun.COM dnode, NULL);
49111337SWilliam.Krier@Sun.COM VN_RELE(vp);
49211337SWilliam.Krier@Sun.COM
49311337SWilliam.Krier@Sun.COM if (fnode == NULL) {
49411337SWilliam.Krier@Sun.COM err = ENOMEM;
49511337SWilliam.Krier@Sun.COM break;
49611337SWilliam.Krier@Sun.COM }
49711337SWilliam.Krier@Sun.COM }
49811337SWilliam.Krier@Sun.COM
49911337SWilliam.Krier@Sun.COM while (upn.pn_path[0] == '/') {
50011337SWilliam.Krier@Sun.COM upn.pn_path++;
50111337SWilliam.Krier@Sun.COM upn.pn_pathlen--;
50211337SWilliam.Krier@Sun.COM }
50311337SWilliam.Krier@Sun.COM
50411337SWilliam.Krier@Sun.COM }
50511337SWilliam.Krier@Sun.COM
50611337SWilliam.Krier@Sun.COM if ((pathleft) && (err == ENOENT))
50711337SWilliam.Krier@Sun.COM err = ENOTDIR;
50811337SWilliam.Krier@Sun.COM
50911337SWilliam.Krier@Sun.COM if (err) {
51011337SWilliam.Krier@Sun.COM if (fnode)
51111337SWilliam.Krier@Sun.COM smb_node_release(fnode);
51211337SWilliam.Krier@Sun.COM if (dnode)
51311337SWilliam.Krier@Sun.COM smb_node_release(dnode);
51411337SWilliam.Krier@Sun.COM } else {
51511337SWilliam.Krier@Sun.COM *ret_node = fnode;
51611337SWilliam.Krier@Sun.COM
51711337SWilliam.Krier@Sun.COM if (dir_node)
51811337SWilliam.Krier@Sun.COM *dir_node = dnode;
51911337SWilliam.Krier@Sun.COM else
52011337SWilliam.Krier@Sun.COM smb_node_release(dnode);
52111337SWilliam.Krier@Sun.COM }
52211337SWilliam.Krier@Sun.COM
52311337SWilliam.Krier@Sun.COM kmem_free(component, MAXNAMELEN);
52411337SWilliam.Krier@Sun.COM kmem_free(real_name, MAXNAMELEN);
52511337SWilliam.Krier@Sun.COM (void) pn_free(&pn);
52611337SWilliam.Krier@Sun.COM (void) pn_free(&rpn);
52711337SWilliam.Krier@Sun.COM (void) pn_free(&upn);
52811337SWilliam.Krier@Sun.COM
52911337SWilliam.Krier@Sun.COM return (err);
53011337SWilliam.Krier@Sun.COM }
53111337SWilliam.Krier@Sun.COM
53211337SWilliam.Krier@Sun.COM /*
53311337SWilliam.Krier@Sun.COM * Holds on dvp and rootvp (if not rootdir) are required by lookuppnvp()
53411337SWilliam.Krier@Sun.COM * and will be released within lookuppnvp().
53511337SWilliam.Krier@Sun.COM */
53611337SWilliam.Krier@Sun.COM static int
smb_pathname_lookup(pathname_t * pn,pathname_t * rpn,int flags,vnode_t ** vp,vnode_t * rootvp,vnode_t * dvp,smb_attr_t * attr,cred_t * cred)53711337SWilliam.Krier@Sun.COM smb_pathname_lookup(pathname_t *pn, pathname_t *rpn, int flags,
53811963SAfshin.Ardakani@Sun.COM vnode_t **vp, vnode_t *rootvp, vnode_t *dvp, smb_attr_t *attr, cred_t *cred)
53911337SWilliam.Krier@Sun.COM {
54011337SWilliam.Krier@Sun.COM int err;
54111337SWilliam.Krier@Sun.COM
54211337SWilliam.Krier@Sun.COM *vp = NULL;
54311337SWilliam.Krier@Sun.COM VN_HOLD(dvp);
54411337SWilliam.Krier@Sun.COM if (rootvp != rootdir)
54511337SWilliam.Krier@Sun.COM VN_HOLD(rootvp);
54611337SWilliam.Krier@Sun.COM
54711337SWilliam.Krier@Sun.COM err = lookuppnvp(pn, rpn, flags, NULL, vp, rootvp, dvp, cred);
54811963SAfshin.Ardakani@Sun.COM if ((err == 0) && (attr != NULL))
54911963SAfshin.Ardakani@Sun.COM (void) smb_vop_getattr(*vp, NULL, attr, 0, kcred);
55011963SAfshin.Ardakani@Sun.COM
55111337SWilliam.Krier@Sun.COM return (err);
55211337SWilliam.Krier@Sun.COM }
55311337SWilliam.Krier@Sun.COM
55411337SWilliam.Krier@Sun.COM /*
55511337SWilliam.Krier@Sun.COM * CATIA Translation of a pathname component prior to passing it to lookuppnvp
55611337SWilliam.Krier@Sun.COM *
55711337SWilliam.Krier@Sun.COM * If the translated component name contains a '/' NULL is returned.
55811337SWilliam.Krier@Sun.COM * The caller should treat this as error EILSEQ. It is not valid to
55911337SWilliam.Krier@Sun.COM * have a directory name with a '/'.
56011337SWilliam.Krier@Sun.COM */
56111337SWilliam.Krier@Sun.COM static char *
smb_pathname_catia_v5tov4(smb_request_t * sr,char * name,char * namebuf,int buflen)56211337SWilliam.Krier@Sun.COM smb_pathname_catia_v5tov4(smb_request_t *sr, char *name,
56311337SWilliam.Krier@Sun.COM char *namebuf, int buflen)
56411337SWilliam.Krier@Sun.COM {
56511337SWilliam.Krier@Sun.COM char *namep;
56611337SWilliam.Krier@Sun.COM
56711337SWilliam.Krier@Sun.COM if (SMB_TREE_SUPPORTS_CATIA(sr)) {
56811337SWilliam.Krier@Sun.COM namep = smb_vop_catia_v5tov4(name, namebuf, buflen);
56911337SWilliam.Krier@Sun.COM if (strchr(namep, '/') != NULL)
57011337SWilliam.Krier@Sun.COM return (NULL);
57111337SWilliam.Krier@Sun.COM return (namep);
57211337SWilliam.Krier@Sun.COM }
57311337SWilliam.Krier@Sun.COM
57411337SWilliam.Krier@Sun.COM return (name);
57511337SWilliam.Krier@Sun.COM }
57611337SWilliam.Krier@Sun.COM
57711337SWilliam.Krier@Sun.COM /*
57811337SWilliam.Krier@Sun.COM * CATIA translation of a pathname component after returning from lookuppnvp
57911337SWilliam.Krier@Sun.COM */
58011337SWilliam.Krier@Sun.COM static char *
smb_pathname_catia_v4tov5(smb_request_t * sr,char * name,char * namebuf,int buflen)58111337SWilliam.Krier@Sun.COM smb_pathname_catia_v4tov5(smb_request_t *sr, char *name,
58211337SWilliam.Krier@Sun.COM char *namebuf, int buflen)
58311337SWilliam.Krier@Sun.COM {
58411337SWilliam.Krier@Sun.COM if (SMB_TREE_SUPPORTS_CATIA(sr)) {
58511337SWilliam.Krier@Sun.COM smb_vop_catia_v4tov5(name, namebuf, buflen);
58611337SWilliam.Krier@Sun.COM return (namebuf);
58711337SWilliam.Krier@Sun.COM }
58811337SWilliam.Krier@Sun.COM
58911337SWilliam.Krier@Sun.COM return (name);
59011337SWilliam.Krier@Sun.COM }
59111337SWilliam.Krier@Sun.COM
59211337SWilliam.Krier@Sun.COM /*
59311337SWilliam.Krier@Sun.COM * sr - needed to check for case sense
59411337SWilliam.Krier@Sun.COM * path - non mangled path needed to be looked up from the startvp
59511337SWilliam.Krier@Sun.COM * startvp - the vnode to start the lookup from
59611337SWilliam.Krier@Sun.COM * rootvp - the vnode of the root of the filesystem
59711337SWilliam.Krier@Sun.COM * returns the vnode found when starting at startvp and using the path
59811337SWilliam.Krier@Sun.COM *
59911337SWilliam.Krier@Sun.COM * Finds a vnode starting at startvp and parsing the non mangled path
60011337SWilliam.Krier@Sun.COM */
60111337SWilliam.Krier@Sun.COM
60211337SWilliam.Krier@Sun.COM vnode_t *
smb_lookuppathvptovp(smb_request_t * sr,char * path,vnode_t * startvp,vnode_t * rootvp)60311337SWilliam.Krier@Sun.COM smb_lookuppathvptovp(smb_request_t *sr, char *path, vnode_t *startvp,
60411337SWilliam.Krier@Sun.COM vnode_t *rootvp)
60511337SWilliam.Krier@Sun.COM {
60611337SWilliam.Krier@Sun.COM pathname_t pn;
60711337SWilliam.Krier@Sun.COM vnode_t *vp = NULL;
60811337SWilliam.Krier@Sun.COM int lookup_flags = FOLLOW;
60911337SWilliam.Krier@Sun.COM
61011337SWilliam.Krier@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr))
61111337SWilliam.Krier@Sun.COM lookup_flags |= FIGNORECASE;
61211337SWilliam.Krier@Sun.COM
61311337SWilliam.Krier@Sun.COM (void) pn_alloc(&pn);
61411337SWilliam.Krier@Sun.COM
61511337SWilliam.Krier@Sun.COM if (pn_set(&pn, path) == 0) {
61611337SWilliam.Krier@Sun.COM VN_HOLD(startvp);
61711337SWilliam.Krier@Sun.COM if (rootvp != rootdir)
61811337SWilliam.Krier@Sun.COM VN_HOLD(rootvp);
61911337SWilliam.Krier@Sun.COM
62011337SWilliam.Krier@Sun.COM /* lookuppnvp should release the holds */
62111337SWilliam.Krier@Sun.COM if (lookuppnvp(&pn, NULL, lookup_flags, NULL, &vp,
62211337SWilliam.Krier@Sun.COM rootvp, startvp, kcred) != 0) {
62311337SWilliam.Krier@Sun.COM pn_free(&pn);
62411337SWilliam.Krier@Sun.COM return (NULL);
62511337SWilliam.Krier@Sun.COM }
62611337SWilliam.Krier@Sun.COM }
62711337SWilliam.Krier@Sun.COM
62811337SWilliam.Krier@Sun.COM pn_free(&pn);
62911337SWilliam.Krier@Sun.COM return (vp);
63011337SWilliam.Krier@Sun.COM }
63111337SWilliam.Krier@Sun.COM
63211337SWilliam.Krier@Sun.COM /*
63311337SWilliam.Krier@Sun.COM * smb_pathname_init
63411337SWilliam.Krier@Sun.COM * Parse path: pname\\fname:sname:stype
63511337SWilliam.Krier@Sun.COM *
63611337SWilliam.Krier@Sun.COM * Elements of the smb_pathname_t structure are allocated using request
63711337SWilliam.Krier@Sun.COM * specific storage and will be free'd when the sr is destroyed.
63811337SWilliam.Krier@Sun.COM *
63911337SWilliam.Krier@Sun.COM * Populate pn structure elements with the individual elements
64011337SWilliam.Krier@Sun.COM * of pn->pn_path. pn->pn_sname will contain the whole stream name
64111337SWilliam.Krier@Sun.COM * including the stream type and preceding colon: :sname:%DATA
64211337SWilliam.Krier@Sun.COM * pn_stype will point to the stream type within pn_sname.
64311337SWilliam.Krier@Sun.COM *
64411963SAfshin.Ardakani@Sun.COM * If the pname element is missing pn_pname will be set to NULL.
64511337SWilliam.Krier@Sun.COM * If any other element is missing the pointer in pn will be NULL.
64611337SWilliam.Krier@Sun.COM */
64711337SWilliam.Krier@Sun.COM void
smb_pathname_init(smb_request_t * sr,smb_pathname_t * pn,char * path)64811337SWilliam.Krier@Sun.COM smb_pathname_init(smb_request_t *sr, smb_pathname_t *pn, char *path)
64911337SWilliam.Krier@Sun.COM {
65011337SWilliam.Krier@Sun.COM char *pname, *fname, *sname;
65111337SWilliam.Krier@Sun.COM int len;
65211337SWilliam.Krier@Sun.COM
65311337SWilliam.Krier@Sun.COM bzero(pn, sizeof (smb_pathname_t));
65411337SWilliam.Krier@Sun.COM pn->pn_path = smb_pathname_strdup(sr, path);
65511337SWilliam.Krier@Sun.COM
65611337SWilliam.Krier@Sun.COM smb_pathname_preprocess(sr, pn);
65711337SWilliam.Krier@Sun.COM
65811337SWilliam.Krier@Sun.COM /* parse pn->pn_path into its constituent parts */
65911337SWilliam.Krier@Sun.COM pname = pn->pn_path;
66011337SWilliam.Krier@Sun.COM fname = strrchr(pn->pn_path, '\\');
66111337SWilliam.Krier@Sun.COM
66211337SWilliam.Krier@Sun.COM if (fname) {
66311337SWilliam.Krier@Sun.COM if (fname == pname) {
66411963SAfshin.Ardakani@Sun.COM pn->pn_pname = NULL;
66511337SWilliam.Krier@Sun.COM } else {
66611337SWilliam.Krier@Sun.COM *fname = '\0';
66711337SWilliam.Krier@Sun.COM pn->pn_pname =
66811337SWilliam.Krier@Sun.COM smb_pathname_strdup(sr, pname);
66911337SWilliam.Krier@Sun.COM *fname = '\\';
67011337SWilliam.Krier@Sun.COM }
67111337SWilliam.Krier@Sun.COM ++fname;
67211337SWilliam.Krier@Sun.COM } else {
67311337SWilliam.Krier@Sun.COM fname = pname;
67411963SAfshin.Ardakani@Sun.COM pn->pn_pname = NULL;
67511337SWilliam.Krier@Sun.COM }
67611337SWilliam.Krier@Sun.COM
67711337SWilliam.Krier@Sun.COM if (fname[0] == '\0') {
67811337SWilliam.Krier@Sun.COM pn->pn_fname = NULL;
67911337SWilliam.Krier@Sun.COM return;
68011337SWilliam.Krier@Sun.COM }
68111337SWilliam.Krier@Sun.COM
68211337SWilliam.Krier@Sun.COM if (!smb_is_stream_name(fname)) {
68311337SWilliam.Krier@Sun.COM pn->pn_fname = smb_pathname_strdup(sr, fname);
68411337SWilliam.Krier@Sun.COM return;
68511337SWilliam.Krier@Sun.COM }
68611337SWilliam.Krier@Sun.COM
68711337SWilliam.Krier@Sun.COM /*
68811337SWilliam.Krier@Sun.COM * find sname and stype in fname.
68911337SWilliam.Krier@Sun.COM * sname can't be NULL smb_is_stream_name checks this
69011337SWilliam.Krier@Sun.COM */
69111337SWilliam.Krier@Sun.COM sname = strchr(fname, ':');
69211337SWilliam.Krier@Sun.COM if (sname == fname)
69311337SWilliam.Krier@Sun.COM fname = NULL;
69411337SWilliam.Krier@Sun.COM else {
69511337SWilliam.Krier@Sun.COM *sname = '\0';
69611337SWilliam.Krier@Sun.COM pn->pn_fname =
69711337SWilliam.Krier@Sun.COM smb_pathname_strdup(sr, fname);
69811337SWilliam.Krier@Sun.COM *sname = ':';
69911337SWilliam.Krier@Sun.COM }
70011337SWilliam.Krier@Sun.COM
70111337SWilliam.Krier@Sun.COM pn->pn_sname = smb_pathname_strdup(sr, sname);
70211337SWilliam.Krier@Sun.COM pn->pn_stype = strchr(pn->pn_sname + 1, ':');
70311337SWilliam.Krier@Sun.COM if (pn->pn_stype) {
70411337SWilliam.Krier@Sun.COM (void) smb_strupr(pn->pn_stype);
70511337SWilliam.Krier@Sun.COM } else {
70611337SWilliam.Krier@Sun.COM len = strlen(pn->pn_sname);
70711337SWilliam.Krier@Sun.COM pn->pn_sname = smb_pathname_strcat(sr, pn->pn_sname, ":$DATA");
70811337SWilliam.Krier@Sun.COM pn->pn_stype = pn->pn_sname + len;
70911337SWilliam.Krier@Sun.COM }
71011337SWilliam.Krier@Sun.COM ++pn->pn_stype;
71111337SWilliam.Krier@Sun.COM }
71211337SWilliam.Krier@Sun.COM
71311337SWilliam.Krier@Sun.COM /*
71411337SWilliam.Krier@Sun.COM * smb_pathname_preprocess
71511337SWilliam.Krier@Sun.COM *
71611337SWilliam.Krier@Sun.COM * Perform common pre-processing of pn->pn_path:
71711337SWilliam.Krier@Sun.COM * - if the pn_path is blank, set it to '\\'
71811337SWilliam.Krier@Sun.COM * - perform unicode wildcard converstion.
71911337SWilliam.Krier@Sun.COM * - convert any '/' to '\\'
72011337SWilliam.Krier@Sun.COM * - eliminate duplicate slashes
72111337SWilliam.Krier@Sun.COM * - remove trailing slashes
72211963SAfshin.Ardakani@Sun.COM * - quota directory specific pre-processing
72311337SWilliam.Krier@Sun.COM */
72411337SWilliam.Krier@Sun.COM static void
smb_pathname_preprocess(smb_request_t * sr,smb_pathname_t * pn)72511337SWilliam.Krier@Sun.COM smb_pathname_preprocess(smb_request_t *sr, smb_pathname_t *pn)
72611337SWilliam.Krier@Sun.COM {
72711337SWilliam.Krier@Sun.COM char *p;
72811337SWilliam.Krier@Sun.COM
72911337SWilliam.Krier@Sun.COM /* treat empty path as "\\" */
73011337SWilliam.Krier@Sun.COM if (strlen(pn->pn_path) == 0) {
73111337SWilliam.Krier@Sun.COM pn->pn_path = smb_pathname_strdup(sr, "\\");
73211337SWilliam.Krier@Sun.COM return;
73311337SWilliam.Krier@Sun.COM }
73411337SWilliam.Krier@Sun.COM
73511337SWilliam.Krier@Sun.COM /* perform unicode wildcard conversion */
73611337SWilliam.Krier@Sun.COM smb_convert_wildcards(pn->pn_path);
73711337SWilliam.Krier@Sun.COM
73811337SWilliam.Krier@Sun.COM /* treat '/' as '\\' */
73911337SWilliam.Krier@Sun.COM (void) strsubst(pn->pn_path, '/', '\\');
74011337SWilliam.Krier@Sun.COM
74111337SWilliam.Krier@Sun.COM (void) strcanon(pn->pn_path, "\\");
74211337SWilliam.Krier@Sun.COM
74311337SWilliam.Krier@Sun.COM /* remove trailing '\\' */
74411337SWilliam.Krier@Sun.COM p = pn->pn_path + strlen(pn->pn_path) - 1;
74511337SWilliam.Krier@Sun.COM if ((p != pn->pn_path) && (*p == '\\'))
74611337SWilliam.Krier@Sun.COM *p = '\0';
74711963SAfshin.Ardakani@Sun.COM
74811963SAfshin.Ardakani@Sun.COM smb_pathname_preprocess_quota(sr, pn);
74911963SAfshin.Ardakani@Sun.COM smb_pathname_preprocess_adminshare(sr, pn);
75011963SAfshin.Ardakani@Sun.COM }
75111963SAfshin.Ardakani@Sun.COM
75211963SAfshin.Ardakani@Sun.COM /*
75311963SAfshin.Ardakani@Sun.COM * smb_pathname_preprocess_quota
75411963SAfshin.Ardakani@Sun.COM *
75511963SAfshin.Ardakani@Sun.COM * There is a special file required by windows so that the quota
75611963SAfshin.Ardakani@Sun.COM * tab will be displayed by windows clients. This is created in
75711963SAfshin.Ardakani@Sun.COM * a special directory, $EXTEND, at the root of the shared file
75811963SAfshin.Ardakani@Sun.COM * system. To hide this directory prepend a '.' (dot).
75911963SAfshin.Ardakani@Sun.COM */
76011963SAfshin.Ardakani@Sun.COM static void
smb_pathname_preprocess_quota(smb_request_t * sr,smb_pathname_t * pn)76111963SAfshin.Ardakani@Sun.COM smb_pathname_preprocess_quota(smb_request_t *sr, smb_pathname_t *pn)
76211963SAfshin.Ardakani@Sun.COM {
76311963SAfshin.Ardakani@Sun.COM char *name = "$EXTEND";
76411963SAfshin.Ardakani@Sun.COM char *new_name = ".$EXTEND";
76511963SAfshin.Ardakani@Sun.COM char *p, *slash;
76611963SAfshin.Ardakani@Sun.COM int len;
76711963SAfshin.Ardakani@Sun.COM
76811963SAfshin.Ardakani@Sun.COM if (!smb_node_is_vfsroot(sr->tid_tree->t_snode))
76911963SAfshin.Ardakani@Sun.COM return;
77011963SAfshin.Ardakani@Sun.COM
77111963SAfshin.Ardakani@Sun.COM p = pn->pn_path;
77211963SAfshin.Ardakani@Sun.COM
77311963SAfshin.Ardakani@Sun.COM /* ignore any initial "\\" */
77411963SAfshin.Ardakani@Sun.COM p += strspn(p, "\\");
77511963SAfshin.Ardakani@Sun.COM if (smb_strcasecmp(p, name, strlen(name)) != 0)
77611963SAfshin.Ardakani@Sun.COM return;
77711963SAfshin.Ardakani@Sun.COM
77811963SAfshin.Ardakani@Sun.COM p += strlen(name);
77911963SAfshin.Ardakani@Sun.COM if ((*p != ':') && (*p != '\\') && (*p != '\0'))
78011963SAfshin.Ardakani@Sun.COM return;
78111963SAfshin.Ardakani@Sun.COM
78211963SAfshin.Ardakani@Sun.COM slash = (pn->pn_path[0] == '\\') ? "\\" : "";
78311963SAfshin.Ardakani@Sun.COM len = strlen(pn->pn_path) + 2;
78411963SAfshin.Ardakani@Sun.COM pn->pn_path = smb_srm_alloc(sr, len);
78511963SAfshin.Ardakani@Sun.COM (void) snprintf(pn->pn_path, len, "%s%s%s", slash, new_name, p);
78611963SAfshin.Ardakani@Sun.COM (void) smb_strupr(pn->pn_path);
78711963SAfshin.Ardakani@Sun.COM }
78811963SAfshin.Ardakani@Sun.COM
78911963SAfshin.Ardakani@Sun.COM /*
79011963SAfshin.Ardakani@Sun.COM * smb_pathname_preprocess_adminshare
79111963SAfshin.Ardakani@Sun.COM *
79211963SAfshin.Ardakani@Sun.COM * Convert any path with share name "C$" or "c$" (Admin share) in to lower case.
79311963SAfshin.Ardakani@Sun.COM */
79411963SAfshin.Ardakani@Sun.COM static void
smb_pathname_preprocess_adminshare(smb_request_t * sr,smb_pathname_t * pn)79511963SAfshin.Ardakani@Sun.COM smb_pathname_preprocess_adminshare(smb_request_t *sr, smb_pathname_t *pn)
79611963SAfshin.Ardakani@Sun.COM {
79711963SAfshin.Ardakani@Sun.COM if (strcasecmp(sr->tid_tree->t_sharename, "c$") == 0)
79811963SAfshin.Ardakani@Sun.COM (void) smb_strlwr(pn->pn_path);
79911337SWilliam.Krier@Sun.COM }
80011337SWilliam.Krier@Sun.COM
80111337SWilliam.Krier@Sun.COM /*
80211337SWilliam.Krier@Sun.COM * smb_pathname_strdup
80311337SWilliam.Krier@Sun.COM *
80411337SWilliam.Krier@Sun.COM * Duplicate NULL terminated string s.
80511337SWilliam.Krier@Sun.COM *
80611337SWilliam.Krier@Sun.COM * The new string is allocated using request specific storage and will
80711337SWilliam.Krier@Sun.COM * be free'd when the sr is destroyed.
80811337SWilliam.Krier@Sun.COM */
80911337SWilliam.Krier@Sun.COM static char *
smb_pathname_strdup(smb_request_t * sr,const char * s)81011337SWilliam.Krier@Sun.COM smb_pathname_strdup(smb_request_t *sr, const char *s)
81111337SWilliam.Krier@Sun.COM {
81211337SWilliam.Krier@Sun.COM char *s2;
81311337SWilliam.Krier@Sun.COM size_t n;
81411337SWilliam.Krier@Sun.COM
81511337SWilliam.Krier@Sun.COM n = strlen(s) + 1;
81611963SAfshin.Ardakani@Sun.COM s2 = smb_srm_zalloc(sr, n);
81711337SWilliam.Krier@Sun.COM (void) strlcpy(s2, s, n);
81811337SWilliam.Krier@Sun.COM return (s2);
81911337SWilliam.Krier@Sun.COM }
82011337SWilliam.Krier@Sun.COM
82111337SWilliam.Krier@Sun.COM /*
82211337SWilliam.Krier@Sun.COM * smb_pathname_strcat
82311337SWilliam.Krier@Sun.COM *
82411337SWilliam.Krier@Sun.COM * Reallocate NULL terminated string s1 to accommodate
82511337SWilliam.Krier@Sun.COM * concatenating NULL terminated string s2.
82611337SWilliam.Krier@Sun.COM * Append s2 and return resulting NULL terminated string.
82711337SWilliam.Krier@Sun.COM *
82811337SWilliam.Krier@Sun.COM * The string buffer is reallocated using request specific
82911337SWilliam.Krier@Sun.COM * storage and will be free'd when the sr is destroyed.
83011337SWilliam.Krier@Sun.COM */
83111337SWilliam.Krier@Sun.COM static char *
smb_pathname_strcat(smb_request_t * sr,char * s1,const char * s2)83211337SWilliam.Krier@Sun.COM smb_pathname_strcat(smb_request_t *sr, char *s1, const char *s2)
83311337SWilliam.Krier@Sun.COM {
83411337SWilliam.Krier@Sun.COM size_t n;
83511337SWilliam.Krier@Sun.COM
83611337SWilliam.Krier@Sun.COM n = strlen(s1) + strlen(s2) + 1;
83711963SAfshin.Ardakani@Sun.COM s1 = smb_srm_rezalloc(sr, s1, n);
83811337SWilliam.Krier@Sun.COM (void) strlcat(s1, s2, n);
83911337SWilliam.Krier@Sun.COM return (s1);
84011337SWilliam.Krier@Sun.COM }
84111337SWilliam.Krier@Sun.COM
84211337SWilliam.Krier@Sun.COM /*
84311337SWilliam.Krier@Sun.COM * smb_pathname_validate
84411337SWilliam.Krier@Sun.COM *
84511337SWilliam.Krier@Sun.COM * Perform basic validation of pn:
84611337SWilliam.Krier@Sun.COM * - If first component of pn->path is ".." -> PATH_SYNTAX_BAD
84711337SWilliam.Krier@Sun.COM * - If there are wildcards in pn->pn_pname -> OBJECT_NAME_INVALID
84811337SWilliam.Krier@Sun.COM * - If fname is "." -> INVALID_OBJECT_NAME
84911337SWilliam.Krier@Sun.COM *
85011337SWilliam.Krier@Sun.COM * On unix .. at the root of a file system links to the root. Thus
85111337SWilliam.Krier@Sun.COM * an attempt to lookup "/../../.." will be the same as looking up "/"
85211337SWilliam.Krier@Sun.COM * CIFs clients expect the above to result in
85311337SWilliam.Krier@Sun.COM * NT_STATUS_OBJECT_PATH_SYNTAX_BAD. It is currently not possible
85411337SWilliam.Krier@Sun.COM * (and questionable if it's desirable) to deal with all cases
85511337SWilliam.Krier@Sun.COM * but paths beginning with \\.. are handled.
85611337SWilliam.Krier@Sun.COM *
85711337SWilliam.Krier@Sun.COM * Returns: B_TRUE if pn is valid,
85811337SWilliam.Krier@Sun.COM * otherwise returns B_FALSE and sets error status in sr.
85911337SWilliam.Krier@Sun.COM */
86011337SWilliam.Krier@Sun.COM boolean_t
smb_pathname_validate(smb_request_t * sr,smb_pathname_t * pn)86111337SWilliam.Krier@Sun.COM smb_pathname_validate(smb_request_t *sr, smb_pathname_t *pn)
86211337SWilliam.Krier@Sun.COM {
86311337SWilliam.Krier@Sun.COM char *path = pn->pn_path;
86411337SWilliam.Krier@Sun.COM
86511337SWilliam.Krier@Sun.COM /* ignore any initial "\\" */
86611337SWilliam.Krier@Sun.COM path += strspn(path, "\\");
86711337SWilliam.Krier@Sun.COM
86811337SWilliam.Krier@Sun.COM /* If first component of path is ".." -> PATH_SYNTAX_BAD */
86911337SWilliam.Krier@Sun.COM if ((strcmp(path, "..") == 0) || (strncmp(path, "..\\", 3) == 0)) {
87011337SWilliam.Krier@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
87111337SWilliam.Krier@Sun.COM ERRDOS, ERROR_BAD_PATHNAME);
87211337SWilliam.Krier@Sun.COM return (B_FALSE);
87311337SWilliam.Krier@Sun.COM }
87411337SWilliam.Krier@Sun.COM
87511337SWilliam.Krier@Sun.COM /* If there are wildcards in pn->pn_pname -> OBJECT_NAME_INVALID */
87611337SWilliam.Krier@Sun.COM if (pn->pn_pname && smb_contains_wildcards(pn->pn_pname)) {
87711337SWilliam.Krier@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
87811337SWilliam.Krier@Sun.COM ERRDOS, ERROR_INVALID_NAME);
87911337SWilliam.Krier@Sun.COM return (B_FALSE);
88011337SWilliam.Krier@Sun.COM }
88111337SWilliam.Krier@Sun.COM
88211337SWilliam.Krier@Sun.COM /* If fname is "." -> INVALID_OBJECT_NAME */
88311337SWilliam.Krier@Sun.COM if (pn->pn_fname && (strcmp(pn->pn_fname, ".") == 0)) {
88411337SWilliam.Krier@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
88511337SWilliam.Krier@Sun.COM ERRDOS, ERROR_PATH_NOT_FOUND);
88611337SWilliam.Krier@Sun.COM return (B_FALSE);
88711337SWilliam.Krier@Sun.COM }
88811337SWilliam.Krier@Sun.COM
88911337SWilliam.Krier@Sun.COM return (B_TRUE);
89011337SWilliam.Krier@Sun.COM }
89111337SWilliam.Krier@Sun.COM
89211337SWilliam.Krier@Sun.COM /*
89311337SWilliam.Krier@Sun.COM * smb_validate_dirname
89411337SWilliam.Krier@Sun.COM *
89511337SWilliam.Krier@Sun.COM * smb_pathname_validate() should have already been performed on pn.
89611337SWilliam.Krier@Sun.COM *
89711337SWilliam.Krier@Sun.COM * Very basic directory name validation: checks for colons in a path.
89811337SWilliam.Krier@Sun.COM * Need to skip the drive prefix since it contains a colon.
89911337SWilliam.Krier@Sun.COM *
90011337SWilliam.Krier@Sun.COM * Returns: B_TRUE if the name is valid,
90111337SWilliam.Krier@Sun.COM * otherwise returns B_FALSE and sets error status in sr.
90211337SWilliam.Krier@Sun.COM */
90311337SWilliam.Krier@Sun.COM boolean_t
smb_validate_dirname(smb_request_t * sr,smb_pathname_t * pn)90411337SWilliam.Krier@Sun.COM smb_validate_dirname(smb_request_t *sr, smb_pathname_t *pn)
90511337SWilliam.Krier@Sun.COM {
90611337SWilliam.Krier@Sun.COM char *name;
90711337SWilliam.Krier@Sun.COM char *path = pn->pn_path;
90811337SWilliam.Krier@Sun.COM
90911337SWilliam.Krier@Sun.COM if ((name = path) != 0) {
91011337SWilliam.Krier@Sun.COM name += strspn(name, "\\");
91111337SWilliam.Krier@Sun.COM
91211337SWilliam.Krier@Sun.COM if (strchr(name, ':') != 0) {
91311337SWilliam.Krier@Sun.COM smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
91411337SWilliam.Krier@Sun.COM ERRDOS, ERROR_INVALID_NAME);
91511337SWilliam.Krier@Sun.COM return (B_FALSE);
91611337SWilliam.Krier@Sun.COM }
91711337SWilliam.Krier@Sun.COM }
91811337SWilliam.Krier@Sun.COM
91911337SWilliam.Krier@Sun.COM return (B_TRUE);
92011337SWilliam.Krier@Sun.COM }
92111337SWilliam.Krier@Sun.COM
92211337SWilliam.Krier@Sun.COM /*
92311337SWilliam.Krier@Sun.COM * smb_validate_object_name
92411337SWilliam.Krier@Sun.COM *
92511337SWilliam.Krier@Sun.COM * smb_pathname_validate() should have already been pertformed on pn.
92611337SWilliam.Krier@Sun.COM *
92711337SWilliam.Krier@Sun.COM * Very basic file name validation.
92811337SWilliam.Krier@Sun.COM * For filenames, we check for names of the form "AAAn:". Names that
92911337SWilliam.Krier@Sun.COM * contain three characters, a single digit and a colon (:) are reserved
93011337SWilliam.Krier@Sun.COM * as DOS device names, i.e. "COM1:".
93111337SWilliam.Krier@Sun.COM * Stream name validation is handed off to smb_validate_stream_name
93211337SWilliam.Krier@Sun.COM *
93311337SWilliam.Krier@Sun.COM * Returns: B_TRUE if pn->pn_fname is valid,
93411337SWilliam.Krier@Sun.COM * otherwise returns B_FALSE and sets error status in sr.
93511337SWilliam.Krier@Sun.COM */
93611337SWilliam.Krier@Sun.COM boolean_t
smb_validate_object_name(smb_request_t * sr,smb_pathname_t * pn)93711337SWilliam.Krier@Sun.COM smb_validate_object_name(smb_request_t *sr, smb_pathname_t *pn)
93811337SWilliam.Krier@Sun.COM {
93911337SWilliam.Krier@Sun.COM if (pn->pn_fname &&
94011337SWilliam.Krier@Sun.COM strlen(pn->pn_fname) == 5 &&
94111337SWilliam.Krier@Sun.COM smb_isdigit(pn->pn_fname[3]) &&
94211337SWilliam.Krier@Sun.COM pn->pn_fname[4] == ':') {
94311337SWilliam.Krier@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
94411337SWilliam.Krier@Sun.COM ERRDOS, ERROR_INVALID_NAME);
94511337SWilliam.Krier@Sun.COM return (B_FALSE);
94611337SWilliam.Krier@Sun.COM }
94711337SWilliam.Krier@Sun.COM
94811337SWilliam.Krier@Sun.COM if (pn->pn_sname)
94911337SWilliam.Krier@Sun.COM return (smb_validate_stream_name(sr, pn));
95011337SWilliam.Krier@Sun.COM
95111337SWilliam.Krier@Sun.COM return (B_TRUE);
95211337SWilliam.Krier@Sun.COM }
95311337SWilliam.Krier@Sun.COM
95411337SWilliam.Krier@Sun.COM /*
95511337SWilliam.Krier@Sun.COM * smb_stream_parse_name
95611337SWilliam.Krier@Sun.COM *
95711337SWilliam.Krier@Sun.COM * smb_stream_parse_name should only be called for a path that
95811337SWilliam.Krier@Sun.COM * contains a valid named stream. Path validation should have
95911337SWilliam.Krier@Sun.COM * been performed before this function is called.
96011337SWilliam.Krier@Sun.COM *
96111337SWilliam.Krier@Sun.COM * Find the last component of path and split it into filename
96211337SWilliam.Krier@Sun.COM * and stream name.
96311337SWilliam.Krier@Sun.COM *
96411337SWilliam.Krier@Sun.COM * On return the named stream type will be present. The stream
96511337SWilliam.Krier@Sun.COM * type defaults to ":$DATA", if it has not been defined
96611337SWilliam.Krier@Sun.COM * For exmaple, 'stream' contains :<sname>:$DATA
96711337SWilliam.Krier@Sun.COM */
96811337SWilliam.Krier@Sun.COM void
smb_stream_parse_name(char * path,char * filename,char * stream)96911337SWilliam.Krier@Sun.COM smb_stream_parse_name(char *path, char *filename, char *stream)
97011337SWilliam.Krier@Sun.COM {
97111337SWilliam.Krier@Sun.COM char *fname, *sname, *stype;
97211337SWilliam.Krier@Sun.COM
97311337SWilliam.Krier@Sun.COM ASSERT(path);
97411337SWilliam.Krier@Sun.COM ASSERT(filename);
97511337SWilliam.Krier@Sun.COM ASSERT(stream);
97611337SWilliam.Krier@Sun.COM
97711337SWilliam.Krier@Sun.COM fname = strrchr(path, '\\');
97811337SWilliam.Krier@Sun.COM fname = (fname == NULL) ? path : fname + 1;
97911337SWilliam.Krier@Sun.COM (void) strlcpy(filename, fname, MAXNAMELEN);
98011337SWilliam.Krier@Sun.COM
98111337SWilliam.Krier@Sun.COM sname = strchr(filename, ':');
98211337SWilliam.Krier@Sun.COM (void) strlcpy(stream, sname, MAXNAMELEN);
98311337SWilliam.Krier@Sun.COM *sname = '\0';
98411337SWilliam.Krier@Sun.COM
98511337SWilliam.Krier@Sun.COM stype = strchr(stream + 1, ':');
98611337SWilliam.Krier@Sun.COM if (stype == NULL)
98711337SWilliam.Krier@Sun.COM (void) strlcat(stream, ":$DATA", MAXNAMELEN);
98811337SWilliam.Krier@Sun.COM else
98911337SWilliam.Krier@Sun.COM (void) smb_strupr(stype);
99011337SWilliam.Krier@Sun.COM }
99111337SWilliam.Krier@Sun.COM
99211337SWilliam.Krier@Sun.COM /*
99311337SWilliam.Krier@Sun.COM * smb_is_stream_name
99411337SWilliam.Krier@Sun.COM *
99511337SWilliam.Krier@Sun.COM * Determines if 'path' specifies a named stream.
99611337SWilliam.Krier@Sun.COM *
99711337SWilliam.Krier@Sun.COM * path is a NULL terminated string which could be a stream path.
99811337SWilliam.Krier@Sun.COM * [pathname/]fname[:stream_name[:stream_type]]
99911337SWilliam.Krier@Sun.COM *
100011337SWilliam.Krier@Sun.COM * - If there is no colon in the path or it's the last char
100111337SWilliam.Krier@Sun.COM * then it's not a stream name
100211337SWilliam.Krier@Sun.COM *
100311337SWilliam.Krier@Sun.COM * - '::' is a non-stream and is commonly used by Windows to designate
100411337SWilliam.Krier@Sun.COM * the unamed stream in the form "::$DATA"
100511337SWilliam.Krier@Sun.COM */
100611337SWilliam.Krier@Sun.COM boolean_t
smb_is_stream_name(char * path)100711337SWilliam.Krier@Sun.COM smb_is_stream_name(char *path)
100811337SWilliam.Krier@Sun.COM {
100911337SWilliam.Krier@Sun.COM char *colonp;
101011337SWilliam.Krier@Sun.COM
101111337SWilliam.Krier@Sun.COM if (path == NULL)
101211337SWilliam.Krier@Sun.COM return (B_FALSE);
101311337SWilliam.Krier@Sun.COM
101411337SWilliam.Krier@Sun.COM colonp = strchr(path, ':');
101511337SWilliam.Krier@Sun.COM if ((colonp == NULL) || (*(colonp+1) == '\0'))
101611337SWilliam.Krier@Sun.COM return (B_FALSE);
101711337SWilliam.Krier@Sun.COM
101811337SWilliam.Krier@Sun.COM if (strstr(path, "::"))
101911337SWilliam.Krier@Sun.COM return (B_FALSE);
102011337SWilliam.Krier@Sun.COM
102111337SWilliam.Krier@Sun.COM return (B_TRUE);
102211337SWilliam.Krier@Sun.COM }
102311337SWilliam.Krier@Sun.COM
102411337SWilliam.Krier@Sun.COM /*
102511337SWilliam.Krier@Sun.COM * smb_validate_stream_name
102611337SWilliam.Krier@Sun.COM *
102711337SWilliam.Krier@Sun.COM * B_FALSE will be returned, and the error status ser in the sr, if:
102811337SWilliam.Krier@Sun.COM * - the path is not a stream name
102911337SWilliam.Krier@Sun.COM * - a path is specified but the fname is ommitted.
103011337SWilliam.Krier@Sun.COM * - the stream_type is specified but not valid.
103111337SWilliam.Krier@Sun.COM *
103211337SWilliam.Krier@Sun.COM * Note: the stream type is case-insensitive.
103311337SWilliam.Krier@Sun.COM */
103411337SWilliam.Krier@Sun.COM boolean_t
smb_validate_stream_name(smb_request_t * sr,smb_pathname_t * pn)103511337SWilliam.Krier@Sun.COM smb_validate_stream_name(smb_request_t *sr, smb_pathname_t *pn)
103611337SWilliam.Krier@Sun.COM {
103711337SWilliam.Krier@Sun.COM static char *strmtype[] = {
103811337SWilliam.Krier@Sun.COM "$DATA",
103911337SWilliam.Krier@Sun.COM "$INDEX_ALLOCATION"
104011337SWilliam.Krier@Sun.COM };
104111337SWilliam.Krier@Sun.COM int i;
104211337SWilliam.Krier@Sun.COM
104311337SWilliam.Krier@Sun.COM ASSERT(pn);
104411337SWilliam.Krier@Sun.COM ASSERT(pn->pn_sname);
104511337SWilliam.Krier@Sun.COM
104611337SWilliam.Krier@Sun.COM if ((!(pn->pn_sname)) ||
104711337SWilliam.Krier@Sun.COM ((pn->pn_pname) && !(pn->pn_fname))) {
104811337SWilliam.Krier@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
104911337SWilliam.Krier@Sun.COM ERRDOS, ERROR_INVALID_NAME);
105011337SWilliam.Krier@Sun.COM return (B_FALSE);
105111337SWilliam.Krier@Sun.COM }
105211337SWilliam.Krier@Sun.COM
105311337SWilliam.Krier@Sun.COM
105411337SWilliam.Krier@Sun.COM if (pn->pn_stype != NULL) {
105511337SWilliam.Krier@Sun.COM for (i = 0; i < sizeof (strmtype) / sizeof (strmtype[0]); ++i) {
105611337SWilliam.Krier@Sun.COM if (strcasecmp(pn->pn_stype, strmtype[i]) == 0)
105711337SWilliam.Krier@Sun.COM return (B_TRUE);
105811337SWilliam.Krier@Sun.COM }
105911337SWilliam.Krier@Sun.COM
106011337SWilliam.Krier@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
106111337SWilliam.Krier@Sun.COM ERRDOS, ERROR_INVALID_NAME);
106211337SWilliam.Krier@Sun.COM return (B_FALSE);
106311337SWilliam.Krier@Sun.COM }
106411337SWilliam.Krier@Sun.COM
106511337SWilliam.Krier@Sun.COM return (B_TRUE);
106611337SWilliam.Krier@Sun.COM }
106711963SAfshin.Ardakani@Sun.COM
106811963SAfshin.Ardakani@Sun.COM /*
106911963SAfshin.Ardakani@Sun.COM * valid DFS I/O path:
107011963SAfshin.Ardakani@Sun.COM *
107111963SAfshin.Ardakani@Sun.COM * \server-or-domain\share
107211963SAfshin.Ardakani@Sun.COM * \server-or-domain\share\path
107311963SAfshin.Ardakani@Sun.COM *
107411963SAfshin.Ardakani@Sun.COM * All the returned errors by this function needs to be
107511963SAfshin.Ardakani@Sun.COM * checked against Windows.
107611963SAfshin.Ardakani@Sun.COM */
107711963SAfshin.Ardakani@Sun.COM static int
smb_pathname_dfs_preprocess(smb_request_t * sr,char * path,size_t pathsz)107811963SAfshin.Ardakani@Sun.COM smb_pathname_dfs_preprocess(smb_request_t *sr, char *path, size_t pathsz)
107911963SAfshin.Ardakani@Sun.COM {
108011963SAfshin.Ardakani@Sun.COM smb_unc_t unc;
108111963SAfshin.Ardakani@Sun.COM char *linkpath;
108211963SAfshin.Ardakani@Sun.COM int rc;
108311963SAfshin.Ardakani@Sun.COM
108411963SAfshin.Ardakani@Sun.COM if (sr->tid_tree == NULL)
108511963SAfshin.Ardakani@Sun.COM return (0);
108611963SAfshin.Ardakani@Sun.COM
108711963SAfshin.Ardakani@Sun.COM if ((rc = smb_unc_init(path, &unc)) != 0)
108811963SAfshin.Ardakani@Sun.COM return (rc);
108911963SAfshin.Ardakani@Sun.COM
109011963SAfshin.Ardakani@Sun.COM if (smb_strcasecmp(unc.unc_share, sr->tid_tree->t_sharename, 0)) {
109111963SAfshin.Ardakani@Sun.COM smb_unc_free(&unc);
109211963SAfshin.Ardakani@Sun.COM return (EINVAL);
109311963SAfshin.Ardakani@Sun.COM }
109411963SAfshin.Ardakani@Sun.COM
109511963SAfshin.Ardakani@Sun.COM linkpath = unc.unc_path;
109611963SAfshin.Ardakani@Sun.COM (void) snprintf(path, pathsz, "/%s", (linkpath) ? linkpath : "");
109711963SAfshin.Ardakani@Sun.COM
109811963SAfshin.Ardakani@Sun.COM smb_unc_free(&unc);
109911963SAfshin.Ardakani@Sun.COM return (0);
110011963SAfshin.Ardakani@Sun.COM }
1101