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