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*12508Samw@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 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 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 206*12508Samw@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 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*12508Samw@Sun.COM if (!smb_maybe_mangled(component)) 40611337SWilliam.Krier@Sun.COM break; 40711337SWilliam.Krier@Sun.COM 408*12508Samw@Sun.COM if ((err = smb_unmangle(dnode, component, 40911337SWilliam.Krier@Sun.COM real_name, MAXNAMELEN, abe_flag)) != 0) 41011337SWilliam.Krier@Sun.COM break; 41111337SWilliam.Krier@Sun.COM 41211337SWilliam.Krier@Sun.COM if ((namep = smb_pathname_catia_v5tov4(sr, real_name, 41311337SWilliam.Krier@Sun.COM namebuf, sizeof (namebuf))) == NULL) { 41411337SWilliam.Krier@Sun.COM err = EILSEQ; 41511337SWilliam.Krier@Sun.COM break; 41611337SWilliam.Krier@Sun.COM } 41711337SWilliam.Krier@Sun.COM 41811337SWilliam.Krier@Sun.COM if ((err = pn_set(&pn, namep)) != 0) 41911337SWilliam.Krier@Sun.COM break; 42011337SWilliam.Krier@Sun.COM 42111337SWilliam.Krier@Sun.COM local_flags = 0; 42211337SWilliam.Krier@Sun.COM err = smb_pathname_lookup(&pn, &rpn, local_flags, 42311963SAfshin.Ardakani@Sun.COM &vp, rootvp, dnode->vp, &attr, cred); 42411337SWilliam.Krier@Sun.COM if (err) 42511337SWilliam.Krier@Sun.COM break; 42611337SWilliam.Krier@Sun.COM } 42711337SWilliam.Krier@Sun.COM 42811963SAfshin.Ardakani@Sun.COM /* 42911963SAfshin.Ardakani@Sun.COM * This check MUST be done before symlink check 43011963SAfshin.Ardakani@Sun.COM * since a reparse point is of type VLNK but should 43111963SAfshin.Ardakani@Sun.COM * not be handled like a regular symlink. 43211963SAfshin.Ardakani@Sun.COM */ 43311963SAfshin.Ardakani@Sun.COM if (attr.sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) { 43411963SAfshin.Ardakani@Sun.COM err = EREMOTE; 43511963SAfshin.Ardakani@Sun.COM VN_RELE(vp); 43611963SAfshin.Ardakani@Sun.COM break; 43711963SAfshin.Ardakani@Sun.COM } 43811963SAfshin.Ardakani@Sun.COM 43911337SWilliam.Krier@Sun.COM if ((vp->v_type == VLNK) && 44011337SWilliam.Krier@Sun.COM ((flags & FOLLOW) || pn_pathleft(&upn))) { 44111337SWilliam.Krier@Sun.COM 44211337SWilliam.Krier@Sun.COM if (++nlink > MAXSYMLINKS) { 44311337SWilliam.Krier@Sun.COM err = ELOOP; 44411337SWilliam.Krier@Sun.COM VN_RELE(vp); 44511337SWilliam.Krier@Sun.COM break; 44611337SWilliam.Krier@Sun.COM } 44711337SWilliam.Krier@Sun.COM 44811337SWilliam.Krier@Sun.COM (void) pn_alloc(&link_pn); 44911337SWilliam.Krier@Sun.COM err = pn_getsymlink(vp, &link_pn, cred); 45011337SWilliam.Krier@Sun.COM VN_RELE(vp); 45111337SWilliam.Krier@Sun.COM 45211337SWilliam.Krier@Sun.COM if (err == 0) { 45311337SWilliam.Krier@Sun.COM if (pn_pathleft(&link_pn) == 0) 45411337SWilliam.Krier@Sun.COM (void) pn_set(&link_pn, "."); 45511337SWilliam.Krier@Sun.COM err = pn_insert(&upn, &link_pn, 45611337SWilliam.Krier@Sun.COM strlen(component)); 45711337SWilliam.Krier@Sun.COM } 45811337SWilliam.Krier@Sun.COM pn_free(&link_pn); 45911337SWilliam.Krier@Sun.COM 46011337SWilliam.Krier@Sun.COM if (err) 46111337SWilliam.Krier@Sun.COM break; 46211337SWilliam.Krier@Sun.COM 46311337SWilliam.Krier@Sun.COM if (upn.pn_pathlen == 0) { 46411337SWilliam.Krier@Sun.COM err = ENOENT; 46511337SWilliam.Krier@Sun.COM break; 46611337SWilliam.Krier@Sun.COM } 46711337SWilliam.Krier@Sun.COM 46811337SWilliam.Krier@Sun.COM if (upn.pn_path[0] == '/') { 46911337SWilliam.Krier@Sun.COM fnode = root_node; 47011337SWilliam.Krier@Sun.COM smb_node_ref(fnode); 47111337SWilliam.Krier@Sun.COM } 47211337SWilliam.Krier@Sun.COM 47311337SWilliam.Krier@Sun.COM if (pn_fixslash(&upn)) 47411337SWilliam.Krier@Sun.COM flags |= FOLLOW; 47511337SWilliam.Krier@Sun.COM 47611337SWilliam.Krier@Sun.COM } else { 47711337SWilliam.Krier@Sun.COM if (flags & FIGNORECASE) { 47811337SWilliam.Krier@Sun.COM if (strcmp(rpn.pn_path, "/") != 0) 47911337SWilliam.Krier@Sun.COM pn_setlast(&rpn); 48011337SWilliam.Krier@Sun.COM namep = rpn.pn_path; 48111337SWilliam.Krier@Sun.COM } else { 48211337SWilliam.Krier@Sun.COM namep = pn.pn_path; 48311337SWilliam.Krier@Sun.COM } 48411337SWilliam.Krier@Sun.COM 48511337SWilliam.Krier@Sun.COM namep = smb_pathname_catia_v4tov5(sr, namep, 48611337SWilliam.Krier@Sun.COM namebuf, sizeof (namebuf)); 48711337SWilliam.Krier@Sun.COM 48811337SWilliam.Krier@Sun.COM fnode = smb_node_lookup(sr, NULL, cred, vp, namep, 48911337SWilliam.Krier@Sun.COM dnode, NULL); 49011337SWilliam.Krier@Sun.COM VN_RELE(vp); 49111337SWilliam.Krier@Sun.COM 49211337SWilliam.Krier@Sun.COM if (fnode == NULL) { 49311337SWilliam.Krier@Sun.COM err = ENOMEM; 49411337SWilliam.Krier@Sun.COM break; 49511337SWilliam.Krier@Sun.COM } 49611337SWilliam.Krier@Sun.COM } 49711337SWilliam.Krier@Sun.COM 49811337SWilliam.Krier@Sun.COM while (upn.pn_path[0] == '/') { 49911337SWilliam.Krier@Sun.COM upn.pn_path++; 50011337SWilliam.Krier@Sun.COM upn.pn_pathlen--; 50111337SWilliam.Krier@Sun.COM } 50211337SWilliam.Krier@Sun.COM 50311337SWilliam.Krier@Sun.COM } 50411337SWilliam.Krier@Sun.COM 50511337SWilliam.Krier@Sun.COM if ((pathleft) && (err == ENOENT)) 50611337SWilliam.Krier@Sun.COM err = ENOTDIR; 50711337SWilliam.Krier@Sun.COM 50811337SWilliam.Krier@Sun.COM if (err) { 50911337SWilliam.Krier@Sun.COM if (fnode) 51011337SWilliam.Krier@Sun.COM smb_node_release(fnode); 51111337SWilliam.Krier@Sun.COM if (dnode) 51211337SWilliam.Krier@Sun.COM smb_node_release(dnode); 51311337SWilliam.Krier@Sun.COM } else { 51411337SWilliam.Krier@Sun.COM *ret_node = fnode; 51511337SWilliam.Krier@Sun.COM 51611337SWilliam.Krier@Sun.COM if (dir_node) 51711337SWilliam.Krier@Sun.COM *dir_node = dnode; 51811337SWilliam.Krier@Sun.COM else 51911337SWilliam.Krier@Sun.COM smb_node_release(dnode); 52011337SWilliam.Krier@Sun.COM } 52111337SWilliam.Krier@Sun.COM 52211337SWilliam.Krier@Sun.COM kmem_free(component, MAXNAMELEN); 52311337SWilliam.Krier@Sun.COM kmem_free(real_name, MAXNAMELEN); 52411337SWilliam.Krier@Sun.COM (void) pn_free(&pn); 52511337SWilliam.Krier@Sun.COM (void) pn_free(&rpn); 52611337SWilliam.Krier@Sun.COM (void) pn_free(&upn); 52711337SWilliam.Krier@Sun.COM 52811337SWilliam.Krier@Sun.COM return (err); 52911337SWilliam.Krier@Sun.COM } 53011337SWilliam.Krier@Sun.COM 53111337SWilliam.Krier@Sun.COM /* 53211337SWilliam.Krier@Sun.COM * Holds on dvp and rootvp (if not rootdir) are required by lookuppnvp() 53311337SWilliam.Krier@Sun.COM * and will be released within lookuppnvp(). 53411337SWilliam.Krier@Sun.COM */ 53511337SWilliam.Krier@Sun.COM static int 53611337SWilliam.Krier@Sun.COM smb_pathname_lookup(pathname_t *pn, pathname_t *rpn, int flags, 53711963SAfshin.Ardakani@Sun.COM vnode_t **vp, vnode_t *rootvp, vnode_t *dvp, smb_attr_t *attr, cred_t *cred) 53811337SWilliam.Krier@Sun.COM { 53911337SWilliam.Krier@Sun.COM int err; 54011337SWilliam.Krier@Sun.COM 54111337SWilliam.Krier@Sun.COM *vp = NULL; 54211337SWilliam.Krier@Sun.COM VN_HOLD(dvp); 54311337SWilliam.Krier@Sun.COM if (rootvp != rootdir) 54411337SWilliam.Krier@Sun.COM VN_HOLD(rootvp); 54511337SWilliam.Krier@Sun.COM 54611337SWilliam.Krier@Sun.COM err = lookuppnvp(pn, rpn, flags, NULL, vp, rootvp, dvp, cred); 54711963SAfshin.Ardakani@Sun.COM if ((err == 0) && (attr != NULL)) 54811963SAfshin.Ardakani@Sun.COM (void) smb_vop_getattr(*vp, NULL, attr, 0, kcred); 54911963SAfshin.Ardakani@Sun.COM 55011337SWilliam.Krier@Sun.COM return (err); 55111337SWilliam.Krier@Sun.COM } 55211337SWilliam.Krier@Sun.COM 55311337SWilliam.Krier@Sun.COM /* 55411337SWilliam.Krier@Sun.COM * CATIA Translation of a pathname component prior to passing it to lookuppnvp 55511337SWilliam.Krier@Sun.COM * 55611337SWilliam.Krier@Sun.COM * If the translated component name contains a '/' NULL is returned. 55711337SWilliam.Krier@Sun.COM * The caller should treat this as error EILSEQ. It is not valid to 55811337SWilliam.Krier@Sun.COM * have a directory name with a '/'. 55911337SWilliam.Krier@Sun.COM */ 56011337SWilliam.Krier@Sun.COM static char * 56111337SWilliam.Krier@Sun.COM smb_pathname_catia_v5tov4(smb_request_t *sr, char *name, 56211337SWilliam.Krier@Sun.COM char *namebuf, int buflen) 56311337SWilliam.Krier@Sun.COM { 56411337SWilliam.Krier@Sun.COM char *namep; 56511337SWilliam.Krier@Sun.COM 56611337SWilliam.Krier@Sun.COM if (SMB_TREE_SUPPORTS_CATIA(sr)) { 56711337SWilliam.Krier@Sun.COM namep = smb_vop_catia_v5tov4(name, namebuf, buflen); 56811337SWilliam.Krier@Sun.COM if (strchr(namep, '/') != NULL) 56911337SWilliam.Krier@Sun.COM return (NULL); 57011337SWilliam.Krier@Sun.COM return (namep); 57111337SWilliam.Krier@Sun.COM } 57211337SWilliam.Krier@Sun.COM 57311337SWilliam.Krier@Sun.COM return (name); 57411337SWilliam.Krier@Sun.COM } 57511337SWilliam.Krier@Sun.COM 57611337SWilliam.Krier@Sun.COM /* 57711337SWilliam.Krier@Sun.COM * CATIA translation of a pathname component after returning from lookuppnvp 57811337SWilliam.Krier@Sun.COM */ 57911337SWilliam.Krier@Sun.COM static char * 58011337SWilliam.Krier@Sun.COM smb_pathname_catia_v4tov5(smb_request_t *sr, char *name, 58111337SWilliam.Krier@Sun.COM char *namebuf, int buflen) 58211337SWilliam.Krier@Sun.COM { 58311337SWilliam.Krier@Sun.COM if (SMB_TREE_SUPPORTS_CATIA(sr)) { 58411337SWilliam.Krier@Sun.COM smb_vop_catia_v4tov5(name, namebuf, buflen); 58511337SWilliam.Krier@Sun.COM return (namebuf); 58611337SWilliam.Krier@Sun.COM } 58711337SWilliam.Krier@Sun.COM 58811337SWilliam.Krier@Sun.COM return (name); 58911337SWilliam.Krier@Sun.COM } 59011337SWilliam.Krier@Sun.COM 59111337SWilliam.Krier@Sun.COM /* 59211337SWilliam.Krier@Sun.COM * sr - needed to check for case sense 59311337SWilliam.Krier@Sun.COM * path - non mangled path needed to be looked up from the startvp 59411337SWilliam.Krier@Sun.COM * startvp - the vnode to start the lookup from 59511337SWilliam.Krier@Sun.COM * rootvp - the vnode of the root of the filesystem 59611337SWilliam.Krier@Sun.COM * returns the vnode found when starting at startvp and using the path 59711337SWilliam.Krier@Sun.COM * 59811337SWilliam.Krier@Sun.COM * Finds a vnode starting at startvp and parsing the non mangled path 59911337SWilliam.Krier@Sun.COM */ 60011337SWilliam.Krier@Sun.COM 60111337SWilliam.Krier@Sun.COM vnode_t * 60211337SWilliam.Krier@Sun.COM smb_lookuppathvptovp(smb_request_t *sr, char *path, vnode_t *startvp, 60311337SWilliam.Krier@Sun.COM vnode_t *rootvp) 60411337SWilliam.Krier@Sun.COM { 60511337SWilliam.Krier@Sun.COM pathname_t pn; 60611337SWilliam.Krier@Sun.COM vnode_t *vp = NULL; 60711337SWilliam.Krier@Sun.COM int lookup_flags = FOLLOW; 60811337SWilliam.Krier@Sun.COM 60911337SWilliam.Krier@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 61011337SWilliam.Krier@Sun.COM lookup_flags |= FIGNORECASE; 61111337SWilliam.Krier@Sun.COM 61211337SWilliam.Krier@Sun.COM (void) pn_alloc(&pn); 61311337SWilliam.Krier@Sun.COM 61411337SWilliam.Krier@Sun.COM if (pn_set(&pn, path) == 0) { 61511337SWilliam.Krier@Sun.COM VN_HOLD(startvp); 61611337SWilliam.Krier@Sun.COM if (rootvp != rootdir) 61711337SWilliam.Krier@Sun.COM VN_HOLD(rootvp); 61811337SWilliam.Krier@Sun.COM 61911337SWilliam.Krier@Sun.COM /* lookuppnvp should release the holds */ 62011337SWilliam.Krier@Sun.COM if (lookuppnvp(&pn, NULL, lookup_flags, NULL, &vp, 62111337SWilliam.Krier@Sun.COM rootvp, startvp, kcred) != 0) { 62211337SWilliam.Krier@Sun.COM pn_free(&pn); 62311337SWilliam.Krier@Sun.COM return (NULL); 62411337SWilliam.Krier@Sun.COM } 62511337SWilliam.Krier@Sun.COM } 62611337SWilliam.Krier@Sun.COM 62711337SWilliam.Krier@Sun.COM pn_free(&pn); 62811337SWilliam.Krier@Sun.COM return (vp); 62911337SWilliam.Krier@Sun.COM } 63011337SWilliam.Krier@Sun.COM 63111337SWilliam.Krier@Sun.COM /* 63211337SWilliam.Krier@Sun.COM * smb_pathname_init 63311337SWilliam.Krier@Sun.COM * Parse path: pname\\fname:sname:stype 63411337SWilliam.Krier@Sun.COM * 63511337SWilliam.Krier@Sun.COM * Elements of the smb_pathname_t structure are allocated using request 63611337SWilliam.Krier@Sun.COM * specific storage and will be free'd when the sr is destroyed. 63711337SWilliam.Krier@Sun.COM * 63811337SWilliam.Krier@Sun.COM * Populate pn structure elements with the individual elements 63911337SWilliam.Krier@Sun.COM * of pn->pn_path. pn->pn_sname will contain the whole stream name 64011337SWilliam.Krier@Sun.COM * including the stream type and preceding colon: :sname:%DATA 64111337SWilliam.Krier@Sun.COM * pn_stype will point to the stream type within pn_sname. 64211337SWilliam.Krier@Sun.COM * 64311963SAfshin.Ardakani@Sun.COM * If the pname element is missing pn_pname will be set to NULL. 64411337SWilliam.Krier@Sun.COM * If any other element is missing the pointer in pn will be NULL. 64511337SWilliam.Krier@Sun.COM */ 64611337SWilliam.Krier@Sun.COM void 64711337SWilliam.Krier@Sun.COM smb_pathname_init(smb_request_t *sr, smb_pathname_t *pn, char *path) 64811337SWilliam.Krier@Sun.COM { 64911337SWilliam.Krier@Sun.COM char *pname, *fname, *sname; 65011337SWilliam.Krier@Sun.COM int len; 65111337SWilliam.Krier@Sun.COM 65211337SWilliam.Krier@Sun.COM bzero(pn, sizeof (smb_pathname_t)); 65311337SWilliam.Krier@Sun.COM pn->pn_path = smb_pathname_strdup(sr, path); 65411337SWilliam.Krier@Sun.COM 65511337SWilliam.Krier@Sun.COM smb_pathname_preprocess(sr, pn); 65611337SWilliam.Krier@Sun.COM 65711337SWilliam.Krier@Sun.COM /* parse pn->pn_path into its constituent parts */ 65811337SWilliam.Krier@Sun.COM pname = pn->pn_path; 65911337SWilliam.Krier@Sun.COM fname = strrchr(pn->pn_path, '\\'); 66011337SWilliam.Krier@Sun.COM 66111337SWilliam.Krier@Sun.COM if (fname) { 66211337SWilliam.Krier@Sun.COM if (fname == pname) { 66311963SAfshin.Ardakani@Sun.COM pn->pn_pname = NULL; 66411337SWilliam.Krier@Sun.COM } else { 66511337SWilliam.Krier@Sun.COM *fname = '\0'; 66611337SWilliam.Krier@Sun.COM pn->pn_pname = 66711337SWilliam.Krier@Sun.COM smb_pathname_strdup(sr, pname); 66811337SWilliam.Krier@Sun.COM *fname = '\\'; 66911337SWilliam.Krier@Sun.COM } 67011337SWilliam.Krier@Sun.COM ++fname; 67111337SWilliam.Krier@Sun.COM } else { 67211337SWilliam.Krier@Sun.COM fname = pname; 67311963SAfshin.Ardakani@Sun.COM pn->pn_pname = NULL; 67411337SWilliam.Krier@Sun.COM } 67511337SWilliam.Krier@Sun.COM 67611337SWilliam.Krier@Sun.COM if (fname[0] == '\0') { 67711337SWilliam.Krier@Sun.COM pn->pn_fname = NULL; 67811337SWilliam.Krier@Sun.COM return; 67911337SWilliam.Krier@Sun.COM } 68011337SWilliam.Krier@Sun.COM 68111337SWilliam.Krier@Sun.COM if (!smb_is_stream_name(fname)) { 68211337SWilliam.Krier@Sun.COM pn->pn_fname = smb_pathname_strdup(sr, fname); 68311337SWilliam.Krier@Sun.COM return; 68411337SWilliam.Krier@Sun.COM } 68511337SWilliam.Krier@Sun.COM 68611337SWilliam.Krier@Sun.COM /* 68711337SWilliam.Krier@Sun.COM * find sname and stype in fname. 68811337SWilliam.Krier@Sun.COM * sname can't be NULL smb_is_stream_name checks this 68911337SWilliam.Krier@Sun.COM */ 69011337SWilliam.Krier@Sun.COM sname = strchr(fname, ':'); 69111337SWilliam.Krier@Sun.COM if (sname == fname) 69211337SWilliam.Krier@Sun.COM fname = NULL; 69311337SWilliam.Krier@Sun.COM else { 69411337SWilliam.Krier@Sun.COM *sname = '\0'; 69511337SWilliam.Krier@Sun.COM pn->pn_fname = 69611337SWilliam.Krier@Sun.COM smb_pathname_strdup(sr, fname); 69711337SWilliam.Krier@Sun.COM *sname = ':'; 69811337SWilliam.Krier@Sun.COM } 69911337SWilliam.Krier@Sun.COM 70011337SWilliam.Krier@Sun.COM pn->pn_sname = smb_pathname_strdup(sr, sname); 70111337SWilliam.Krier@Sun.COM pn->pn_stype = strchr(pn->pn_sname + 1, ':'); 70211337SWilliam.Krier@Sun.COM if (pn->pn_stype) { 70311337SWilliam.Krier@Sun.COM (void) smb_strupr(pn->pn_stype); 70411337SWilliam.Krier@Sun.COM } else { 70511337SWilliam.Krier@Sun.COM len = strlen(pn->pn_sname); 70611337SWilliam.Krier@Sun.COM pn->pn_sname = smb_pathname_strcat(sr, pn->pn_sname, ":$DATA"); 70711337SWilliam.Krier@Sun.COM pn->pn_stype = pn->pn_sname + len; 70811337SWilliam.Krier@Sun.COM } 70911337SWilliam.Krier@Sun.COM ++pn->pn_stype; 71011337SWilliam.Krier@Sun.COM } 71111337SWilliam.Krier@Sun.COM 71211337SWilliam.Krier@Sun.COM /* 71311337SWilliam.Krier@Sun.COM * smb_pathname_preprocess 71411337SWilliam.Krier@Sun.COM * 71511337SWilliam.Krier@Sun.COM * Perform common pre-processing of pn->pn_path: 71611337SWilliam.Krier@Sun.COM * - if the pn_path is blank, set it to '\\' 71711337SWilliam.Krier@Sun.COM * - perform unicode wildcard converstion. 71811337SWilliam.Krier@Sun.COM * - convert any '/' to '\\' 71911337SWilliam.Krier@Sun.COM * - eliminate duplicate slashes 72011337SWilliam.Krier@Sun.COM * - remove trailing slashes 72111963SAfshin.Ardakani@Sun.COM * - quota directory specific pre-processing 72211337SWilliam.Krier@Sun.COM */ 72311337SWilliam.Krier@Sun.COM static void 72411337SWilliam.Krier@Sun.COM smb_pathname_preprocess(smb_request_t *sr, smb_pathname_t *pn) 72511337SWilliam.Krier@Sun.COM { 72611337SWilliam.Krier@Sun.COM char *p; 72711337SWilliam.Krier@Sun.COM 72811337SWilliam.Krier@Sun.COM /* treat empty path as "\\" */ 72911337SWilliam.Krier@Sun.COM if (strlen(pn->pn_path) == 0) { 73011337SWilliam.Krier@Sun.COM pn->pn_path = smb_pathname_strdup(sr, "\\"); 73111337SWilliam.Krier@Sun.COM return; 73211337SWilliam.Krier@Sun.COM } 73311337SWilliam.Krier@Sun.COM 73411337SWilliam.Krier@Sun.COM /* perform unicode wildcard conversion */ 73511337SWilliam.Krier@Sun.COM smb_convert_wildcards(pn->pn_path); 73611337SWilliam.Krier@Sun.COM 73711337SWilliam.Krier@Sun.COM /* treat '/' as '\\' */ 73811337SWilliam.Krier@Sun.COM (void) strsubst(pn->pn_path, '/', '\\'); 73911337SWilliam.Krier@Sun.COM 74011337SWilliam.Krier@Sun.COM (void) strcanon(pn->pn_path, "\\"); 74111337SWilliam.Krier@Sun.COM 74211337SWilliam.Krier@Sun.COM /* remove trailing '\\' */ 74311337SWilliam.Krier@Sun.COM p = pn->pn_path + strlen(pn->pn_path) - 1; 74411337SWilliam.Krier@Sun.COM if ((p != pn->pn_path) && (*p == '\\')) 74511337SWilliam.Krier@Sun.COM *p = '\0'; 74611963SAfshin.Ardakani@Sun.COM 74711963SAfshin.Ardakani@Sun.COM smb_pathname_preprocess_quota(sr, pn); 74811963SAfshin.Ardakani@Sun.COM smb_pathname_preprocess_adminshare(sr, pn); 74911963SAfshin.Ardakani@Sun.COM } 75011963SAfshin.Ardakani@Sun.COM 75111963SAfshin.Ardakani@Sun.COM /* 75211963SAfshin.Ardakani@Sun.COM * smb_pathname_preprocess_quota 75311963SAfshin.Ardakani@Sun.COM * 75411963SAfshin.Ardakani@Sun.COM * There is a special file required by windows so that the quota 75511963SAfshin.Ardakani@Sun.COM * tab will be displayed by windows clients. This is created in 75611963SAfshin.Ardakani@Sun.COM * a special directory, $EXTEND, at the root of the shared file 75711963SAfshin.Ardakani@Sun.COM * system. To hide this directory prepend a '.' (dot). 75811963SAfshin.Ardakani@Sun.COM */ 75911963SAfshin.Ardakani@Sun.COM static void 76011963SAfshin.Ardakani@Sun.COM smb_pathname_preprocess_quota(smb_request_t *sr, smb_pathname_t *pn) 76111963SAfshin.Ardakani@Sun.COM { 76211963SAfshin.Ardakani@Sun.COM char *name = "$EXTEND"; 76311963SAfshin.Ardakani@Sun.COM char *new_name = ".$EXTEND"; 76411963SAfshin.Ardakani@Sun.COM char *p, *slash; 76511963SAfshin.Ardakani@Sun.COM int len; 76611963SAfshin.Ardakani@Sun.COM 76711963SAfshin.Ardakani@Sun.COM if (!smb_node_is_vfsroot(sr->tid_tree->t_snode)) 76811963SAfshin.Ardakani@Sun.COM return; 76911963SAfshin.Ardakani@Sun.COM 77011963SAfshin.Ardakani@Sun.COM p = pn->pn_path; 77111963SAfshin.Ardakani@Sun.COM 77211963SAfshin.Ardakani@Sun.COM /* ignore any initial "\\" */ 77311963SAfshin.Ardakani@Sun.COM p += strspn(p, "\\"); 77411963SAfshin.Ardakani@Sun.COM if (smb_strcasecmp(p, name, strlen(name)) != 0) 77511963SAfshin.Ardakani@Sun.COM return; 77611963SAfshin.Ardakani@Sun.COM 77711963SAfshin.Ardakani@Sun.COM p += strlen(name); 77811963SAfshin.Ardakani@Sun.COM if ((*p != ':') && (*p != '\\') && (*p != '\0')) 77911963SAfshin.Ardakani@Sun.COM return; 78011963SAfshin.Ardakani@Sun.COM 78111963SAfshin.Ardakani@Sun.COM slash = (pn->pn_path[0] == '\\') ? "\\" : ""; 78211963SAfshin.Ardakani@Sun.COM len = strlen(pn->pn_path) + 2; 78311963SAfshin.Ardakani@Sun.COM pn->pn_path = smb_srm_alloc(sr, len); 78411963SAfshin.Ardakani@Sun.COM (void) snprintf(pn->pn_path, len, "%s%s%s", slash, new_name, p); 78511963SAfshin.Ardakani@Sun.COM (void) smb_strupr(pn->pn_path); 78611963SAfshin.Ardakani@Sun.COM } 78711963SAfshin.Ardakani@Sun.COM 78811963SAfshin.Ardakani@Sun.COM /* 78911963SAfshin.Ardakani@Sun.COM * smb_pathname_preprocess_adminshare 79011963SAfshin.Ardakani@Sun.COM * 79111963SAfshin.Ardakani@Sun.COM * Convert any path with share name "C$" or "c$" (Admin share) in to lower case. 79211963SAfshin.Ardakani@Sun.COM */ 79311963SAfshin.Ardakani@Sun.COM static void 79411963SAfshin.Ardakani@Sun.COM smb_pathname_preprocess_adminshare(smb_request_t *sr, smb_pathname_t *pn) 79511963SAfshin.Ardakani@Sun.COM { 79611963SAfshin.Ardakani@Sun.COM if (strcasecmp(sr->tid_tree->t_sharename, "c$") == 0) 79711963SAfshin.Ardakani@Sun.COM (void) smb_strlwr(pn->pn_path); 79811337SWilliam.Krier@Sun.COM } 79911337SWilliam.Krier@Sun.COM 80011337SWilliam.Krier@Sun.COM /* 80111337SWilliam.Krier@Sun.COM * smb_pathname_strdup 80211337SWilliam.Krier@Sun.COM * 80311337SWilliam.Krier@Sun.COM * Duplicate NULL terminated string s. 80411337SWilliam.Krier@Sun.COM * 80511337SWilliam.Krier@Sun.COM * The new string is allocated using request specific storage and will 80611337SWilliam.Krier@Sun.COM * be free'd when the sr is destroyed. 80711337SWilliam.Krier@Sun.COM */ 80811337SWilliam.Krier@Sun.COM static char * 80911337SWilliam.Krier@Sun.COM smb_pathname_strdup(smb_request_t *sr, const char *s) 81011337SWilliam.Krier@Sun.COM { 81111337SWilliam.Krier@Sun.COM char *s2; 81211337SWilliam.Krier@Sun.COM size_t n; 81311337SWilliam.Krier@Sun.COM 81411337SWilliam.Krier@Sun.COM n = strlen(s) + 1; 81511963SAfshin.Ardakani@Sun.COM s2 = smb_srm_zalloc(sr, n); 81611337SWilliam.Krier@Sun.COM (void) strlcpy(s2, s, n); 81711337SWilliam.Krier@Sun.COM return (s2); 81811337SWilliam.Krier@Sun.COM } 81911337SWilliam.Krier@Sun.COM 82011337SWilliam.Krier@Sun.COM /* 82111337SWilliam.Krier@Sun.COM * smb_pathname_strcat 82211337SWilliam.Krier@Sun.COM * 82311337SWilliam.Krier@Sun.COM * Reallocate NULL terminated string s1 to accommodate 82411337SWilliam.Krier@Sun.COM * concatenating NULL terminated string s2. 82511337SWilliam.Krier@Sun.COM * Append s2 and return resulting NULL terminated string. 82611337SWilliam.Krier@Sun.COM * 82711337SWilliam.Krier@Sun.COM * The string buffer is reallocated using request specific 82811337SWilliam.Krier@Sun.COM * storage and will be free'd when the sr is destroyed. 82911337SWilliam.Krier@Sun.COM */ 83011337SWilliam.Krier@Sun.COM static char * 83111337SWilliam.Krier@Sun.COM smb_pathname_strcat(smb_request_t *sr, char *s1, const char *s2) 83211337SWilliam.Krier@Sun.COM { 83311337SWilliam.Krier@Sun.COM size_t n; 83411337SWilliam.Krier@Sun.COM 83511337SWilliam.Krier@Sun.COM n = strlen(s1) + strlen(s2) + 1; 83611963SAfshin.Ardakani@Sun.COM s1 = smb_srm_rezalloc(sr, s1, n); 83711337SWilliam.Krier@Sun.COM (void) strlcat(s1, s2, n); 83811337SWilliam.Krier@Sun.COM return (s1); 83911337SWilliam.Krier@Sun.COM } 84011337SWilliam.Krier@Sun.COM 84111337SWilliam.Krier@Sun.COM /* 84211337SWilliam.Krier@Sun.COM * smb_pathname_validate 84311337SWilliam.Krier@Sun.COM * 84411337SWilliam.Krier@Sun.COM * Perform basic validation of pn: 84511337SWilliam.Krier@Sun.COM * - If first component of pn->path is ".." -> PATH_SYNTAX_BAD 84611337SWilliam.Krier@Sun.COM * - If there are wildcards in pn->pn_pname -> OBJECT_NAME_INVALID 84711337SWilliam.Krier@Sun.COM * - If fname is "." -> INVALID_OBJECT_NAME 84811337SWilliam.Krier@Sun.COM * 84911337SWilliam.Krier@Sun.COM * On unix .. at the root of a file system links to the root. Thus 85011337SWilliam.Krier@Sun.COM * an attempt to lookup "/../../.." will be the same as looking up "/" 85111337SWilliam.Krier@Sun.COM * CIFs clients expect the above to result in 85211337SWilliam.Krier@Sun.COM * NT_STATUS_OBJECT_PATH_SYNTAX_BAD. It is currently not possible 85311337SWilliam.Krier@Sun.COM * (and questionable if it's desirable) to deal with all cases 85411337SWilliam.Krier@Sun.COM * but paths beginning with \\.. are handled. 85511337SWilliam.Krier@Sun.COM * 85611337SWilliam.Krier@Sun.COM * Returns: B_TRUE if pn is valid, 85711337SWilliam.Krier@Sun.COM * otherwise returns B_FALSE and sets error status in sr. 85811337SWilliam.Krier@Sun.COM */ 85911337SWilliam.Krier@Sun.COM boolean_t 86011337SWilliam.Krier@Sun.COM smb_pathname_validate(smb_request_t *sr, smb_pathname_t *pn) 86111337SWilliam.Krier@Sun.COM { 86211337SWilliam.Krier@Sun.COM char *path = pn->pn_path; 86311337SWilliam.Krier@Sun.COM 86411337SWilliam.Krier@Sun.COM /* ignore any initial "\\" */ 86511337SWilliam.Krier@Sun.COM path += strspn(path, "\\"); 86611337SWilliam.Krier@Sun.COM 86711337SWilliam.Krier@Sun.COM /* If first component of path is ".." -> PATH_SYNTAX_BAD */ 86811337SWilliam.Krier@Sun.COM if ((strcmp(path, "..") == 0) || (strncmp(path, "..\\", 3) == 0)) { 86911337SWilliam.Krier@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD, 87011337SWilliam.Krier@Sun.COM ERRDOS, ERROR_BAD_PATHNAME); 87111337SWilliam.Krier@Sun.COM return (B_FALSE); 87211337SWilliam.Krier@Sun.COM } 87311337SWilliam.Krier@Sun.COM 87411337SWilliam.Krier@Sun.COM /* If there are wildcards in pn->pn_pname -> OBJECT_NAME_INVALID */ 87511337SWilliam.Krier@Sun.COM if (pn->pn_pname && smb_contains_wildcards(pn->pn_pname)) { 87611337SWilliam.Krier@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, 87711337SWilliam.Krier@Sun.COM ERRDOS, ERROR_INVALID_NAME); 87811337SWilliam.Krier@Sun.COM return (B_FALSE); 87911337SWilliam.Krier@Sun.COM } 88011337SWilliam.Krier@Sun.COM 88111337SWilliam.Krier@Sun.COM /* If fname is "." -> INVALID_OBJECT_NAME */ 88211337SWilliam.Krier@Sun.COM if (pn->pn_fname && (strcmp(pn->pn_fname, ".") == 0)) { 88311337SWilliam.Krier@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, 88411337SWilliam.Krier@Sun.COM ERRDOS, ERROR_PATH_NOT_FOUND); 88511337SWilliam.Krier@Sun.COM return (B_FALSE); 88611337SWilliam.Krier@Sun.COM } 88711337SWilliam.Krier@Sun.COM 88811337SWilliam.Krier@Sun.COM return (B_TRUE); 88911337SWilliam.Krier@Sun.COM } 89011337SWilliam.Krier@Sun.COM 89111337SWilliam.Krier@Sun.COM /* 89211337SWilliam.Krier@Sun.COM * smb_validate_dirname 89311337SWilliam.Krier@Sun.COM * 89411337SWilliam.Krier@Sun.COM * smb_pathname_validate() should have already been performed on pn. 89511337SWilliam.Krier@Sun.COM * 89611337SWilliam.Krier@Sun.COM * Very basic directory name validation: checks for colons in a path. 89711337SWilliam.Krier@Sun.COM * Need to skip the drive prefix since it contains a colon. 89811337SWilliam.Krier@Sun.COM * 89911337SWilliam.Krier@Sun.COM * Returns: B_TRUE if the name is valid, 90011337SWilliam.Krier@Sun.COM * otherwise returns B_FALSE and sets error status in sr. 90111337SWilliam.Krier@Sun.COM */ 90211337SWilliam.Krier@Sun.COM boolean_t 90311337SWilliam.Krier@Sun.COM smb_validate_dirname(smb_request_t *sr, smb_pathname_t *pn) 90411337SWilliam.Krier@Sun.COM { 90511337SWilliam.Krier@Sun.COM char *name; 90611337SWilliam.Krier@Sun.COM char *path = pn->pn_path; 90711337SWilliam.Krier@Sun.COM 90811337SWilliam.Krier@Sun.COM if ((name = path) != 0) { 90911337SWilliam.Krier@Sun.COM name += strspn(name, "\\"); 91011337SWilliam.Krier@Sun.COM 91111337SWilliam.Krier@Sun.COM if (strchr(name, ':') != 0) { 91211337SWilliam.Krier@Sun.COM smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY, 91311337SWilliam.Krier@Sun.COM ERRDOS, ERROR_INVALID_NAME); 91411337SWilliam.Krier@Sun.COM return (B_FALSE); 91511337SWilliam.Krier@Sun.COM } 91611337SWilliam.Krier@Sun.COM } 91711337SWilliam.Krier@Sun.COM 91811337SWilliam.Krier@Sun.COM return (B_TRUE); 91911337SWilliam.Krier@Sun.COM } 92011337SWilliam.Krier@Sun.COM 92111337SWilliam.Krier@Sun.COM /* 92211337SWilliam.Krier@Sun.COM * smb_validate_object_name 92311337SWilliam.Krier@Sun.COM * 92411337SWilliam.Krier@Sun.COM * smb_pathname_validate() should have already been pertformed on pn. 92511337SWilliam.Krier@Sun.COM * 92611337SWilliam.Krier@Sun.COM * Very basic file name validation. 92711337SWilliam.Krier@Sun.COM * For filenames, we check for names of the form "AAAn:". Names that 92811337SWilliam.Krier@Sun.COM * contain three characters, a single digit and a colon (:) are reserved 92911337SWilliam.Krier@Sun.COM * as DOS device names, i.e. "COM1:". 93011337SWilliam.Krier@Sun.COM * Stream name validation is handed off to smb_validate_stream_name 93111337SWilliam.Krier@Sun.COM * 93211337SWilliam.Krier@Sun.COM * Returns: B_TRUE if pn->pn_fname is valid, 93311337SWilliam.Krier@Sun.COM * otherwise returns B_FALSE and sets error status in sr. 93411337SWilliam.Krier@Sun.COM */ 93511337SWilliam.Krier@Sun.COM boolean_t 93611337SWilliam.Krier@Sun.COM smb_validate_object_name(smb_request_t *sr, smb_pathname_t *pn) 93711337SWilliam.Krier@Sun.COM { 93811337SWilliam.Krier@Sun.COM if (pn->pn_fname && 93911337SWilliam.Krier@Sun.COM strlen(pn->pn_fname) == 5 && 94011337SWilliam.Krier@Sun.COM smb_isdigit(pn->pn_fname[3]) && 94111337SWilliam.Krier@Sun.COM pn->pn_fname[4] == ':') { 94211337SWilliam.Krier@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, 94311337SWilliam.Krier@Sun.COM ERRDOS, ERROR_INVALID_NAME); 94411337SWilliam.Krier@Sun.COM return (B_FALSE); 94511337SWilliam.Krier@Sun.COM } 94611337SWilliam.Krier@Sun.COM 94711337SWilliam.Krier@Sun.COM if (pn->pn_sname) 94811337SWilliam.Krier@Sun.COM return (smb_validate_stream_name(sr, pn)); 94911337SWilliam.Krier@Sun.COM 95011337SWilliam.Krier@Sun.COM return (B_TRUE); 95111337SWilliam.Krier@Sun.COM } 95211337SWilliam.Krier@Sun.COM 95311337SWilliam.Krier@Sun.COM /* 95411337SWilliam.Krier@Sun.COM * smb_stream_parse_name 95511337SWilliam.Krier@Sun.COM * 95611337SWilliam.Krier@Sun.COM * smb_stream_parse_name should only be called for a path that 95711337SWilliam.Krier@Sun.COM * contains a valid named stream. Path validation should have 95811337SWilliam.Krier@Sun.COM * been performed before this function is called. 95911337SWilliam.Krier@Sun.COM * 96011337SWilliam.Krier@Sun.COM * Find the last component of path and split it into filename 96111337SWilliam.Krier@Sun.COM * and stream name. 96211337SWilliam.Krier@Sun.COM * 96311337SWilliam.Krier@Sun.COM * On return the named stream type will be present. The stream 96411337SWilliam.Krier@Sun.COM * type defaults to ":$DATA", if it has not been defined 96511337SWilliam.Krier@Sun.COM * For exmaple, 'stream' contains :<sname>:$DATA 96611337SWilliam.Krier@Sun.COM */ 96711337SWilliam.Krier@Sun.COM void 96811337SWilliam.Krier@Sun.COM smb_stream_parse_name(char *path, char *filename, char *stream) 96911337SWilliam.Krier@Sun.COM { 97011337SWilliam.Krier@Sun.COM char *fname, *sname, *stype; 97111337SWilliam.Krier@Sun.COM 97211337SWilliam.Krier@Sun.COM ASSERT(path); 97311337SWilliam.Krier@Sun.COM ASSERT(filename); 97411337SWilliam.Krier@Sun.COM ASSERT(stream); 97511337SWilliam.Krier@Sun.COM 97611337SWilliam.Krier@Sun.COM fname = strrchr(path, '\\'); 97711337SWilliam.Krier@Sun.COM fname = (fname == NULL) ? path : fname + 1; 97811337SWilliam.Krier@Sun.COM (void) strlcpy(filename, fname, MAXNAMELEN); 97911337SWilliam.Krier@Sun.COM 98011337SWilliam.Krier@Sun.COM sname = strchr(filename, ':'); 98111337SWilliam.Krier@Sun.COM (void) strlcpy(stream, sname, MAXNAMELEN); 98211337SWilliam.Krier@Sun.COM *sname = '\0'; 98311337SWilliam.Krier@Sun.COM 98411337SWilliam.Krier@Sun.COM stype = strchr(stream + 1, ':'); 98511337SWilliam.Krier@Sun.COM if (stype == NULL) 98611337SWilliam.Krier@Sun.COM (void) strlcat(stream, ":$DATA", MAXNAMELEN); 98711337SWilliam.Krier@Sun.COM else 98811337SWilliam.Krier@Sun.COM (void) smb_strupr(stype); 98911337SWilliam.Krier@Sun.COM } 99011337SWilliam.Krier@Sun.COM 99111337SWilliam.Krier@Sun.COM /* 99211337SWilliam.Krier@Sun.COM * smb_is_stream_name 99311337SWilliam.Krier@Sun.COM * 99411337SWilliam.Krier@Sun.COM * Determines if 'path' specifies a named stream. 99511337SWilliam.Krier@Sun.COM * 99611337SWilliam.Krier@Sun.COM * path is a NULL terminated string which could be a stream path. 99711337SWilliam.Krier@Sun.COM * [pathname/]fname[:stream_name[:stream_type]] 99811337SWilliam.Krier@Sun.COM * 99911337SWilliam.Krier@Sun.COM * - If there is no colon in the path or it's the last char 100011337SWilliam.Krier@Sun.COM * then it's not a stream name 100111337SWilliam.Krier@Sun.COM * 100211337SWilliam.Krier@Sun.COM * - '::' is a non-stream and is commonly used by Windows to designate 100311337SWilliam.Krier@Sun.COM * the unamed stream in the form "::$DATA" 100411337SWilliam.Krier@Sun.COM */ 100511337SWilliam.Krier@Sun.COM boolean_t 100611337SWilliam.Krier@Sun.COM smb_is_stream_name(char *path) 100711337SWilliam.Krier@Sun.COM { 100811337SWilliam.Krier@Sun.COM char *colonp; 100911337SWilliam.Krier@Sun.COM 101011337SWilliam.Krier@Sun.COM if (path == NULL) 101111337SWilliam.Krier@Sun.COM return (B_FALSE); 101211337SWilliam.Krier@Sun.COM 101311337SWilliam.Krier@Sun.COM colonp = strchr(path, ':'); 101411337SWilliam.Krier@Sun.COM if ((colonp == NULL) || (*(colonp+1) == '\0')) 101511337SWilliam.Krier@Sun.COM return (B_FALSE); 101611337SWilliam.Krier@Sun.COM 101711337SWilliam.Krier@Sun.COM if (strstr(path, "::")) 101811337SWilliam.Krier@Sun.COM return (B_FALSE); 101911337SWilliam.Krier@Sun.COM 102011337SWilliam.Krier@Sun.COM return (B_TRUE); 102111337SWilliam.Krier@Sun.COM } 102211337SWilliam.Krier@Sun.COM 102311337SWilliam.Krier@Sun.COM /* 102411337SWilliam.Krier@Sun.COM * smb_validate_stream_name 102511337SWilliam.Krier@Sun.COM * 102611337SWilliam.Krier@Sun.COM * B_FALSE will be returned, and the error status ser in the sr, if: 102711337SWilliam.Krier@Sun.COM * - the path is not a stream name 102811337SWilliam.Krier@Sun.COM * - a path is specified but the fname is ommitted. 102911337SWilliam.Krier@Sun.COM * - the stream_type is specified but not valid. 103011337SWilliam.Krier@Sun.COM * 103111337SWilliam.Krier@Sun.COM * Note: the stream type is case-insensitive. 103211337SWilliam.Krier@Sun.COM */ 103311337SWilliam.Krier@Sun.COM boolean_t 103411337SWilliam.Krier@Sun.COM smb_validate_stream_name(smb_request_t *sr, smb_pathname_t *pn) 103511337SWilliam.Krier@Sun.COM { 103611337SWilliam.Krier@Sun.COM static char *strmtype[] = { 103711337SWilliam.Krier@Sun.COM "$DATA", 103811337SWilliam.Krier@Sun.COM "$INDEX_ALLOCATION" 103911337SWilliam.Krier@Sun.COM }; 104011337SWilliam.Krier@Sun.COM int i; 104111337SWilliam.Krier@Sun.COM 104211337SWilliam.Krier@Sun.COM ASSERT(pn); 104311337SWilliam.Krier@Sun.COM ASSERT(pn->pn_sname); 104411337SWilliam.Krier@Sun.COM 104511337SWilliam.Krier@Sun.COM if ((!(pn->pn_sname)) || 104611337SWilliam.Krier@Sun.COM ((pn->pn_pname) && !(pn->pn_fname))) { 104711337SWilliam.Krier@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, 104811337SWilliam.Krier@Sun.COM ERRDOS, ERROR_INVALID_NAME); 104911337SWilliam.Krier@Sun.COM return (B_FALSE); 105011337SWilliam.Krier@Sun.COM } 105111337SWilliam.Krier@Sun.COM 105211337SWilliam.Krier@Sun.COM 105311337SWilliam.Krier@Sun.COM if (pn->pn_stype != NULL) { 105411337SWilliam.Krier@Sun.COM for (i = 0; i < sizeof (strmtype) / sizeof (strmtype[0]); ++i) { 105511337SWilliam.Krier@Sun.COM if (strcasecmp(pn->pn_stype, strmtype[i]) == 0) 105611337SWilliam.Krier@Sun.COM return (B_TRUE); 105711337SWilliam.Krier@Sun.COM } 105811337SWilliam.Krier@Sun.COM 105911337SWilliam.Krier@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, 106011337SWilliam.Krier@Sun.COM ERRDOS, ERROR_INVALID_NAME); 106111337SWilliam.Krier@Sun.COM return (B_FALSE); 106211337SWilliam.Krier@Sun.COM } 106311337SWilliam.Krier@Sun.COM 106411337SWilliam.Krier@Sun.COM return (B_TRUE); 106511337SWilliam.Krier@Sun.COM } 106611963SAfshin.Ardakani@Sun.COM 106711963SAfshin.Ardakani@Sun.COM /* 106811963SAfshin.Ardakani@Sun.COM * valid DFS I/O path: 106911963SAfshin.Ardakani@Sun.COM * 107011963SAfshin.Ardakani@Sun.COM * \server-or-domain\share 107111963SAfshin.Ardakani@Sun.COM * \server-or-domain\share\path 107211963SAfshin.Ardakani@Sun.COM * 107311963SAfshin.Ardakani@Sun.COM * All the returned errors by this function needs to be 107411963SAfshin.Ardakani@Sun.COM * checked against Windows. 107511963SAfshin.Ardakani@Sun.COM */ 107611963SAfshin.Ardakani@Sun.COM static int 107711963SAfshin.Ardakani@Sun.COM smb_pathname_dfs_preprocess(smb_request_t *sr, char *path, size_t pathsz) 107811963SAfshin.Ardakani@Sun.COM { 107911963SAfshin.Ardakani@Sun.COM smb_unc_t unc; 108011963SAfshin.Ardakani@Sun.COM char *linkpath; 108111963SAfshin.Ardakani@Sun.COM int rc; 108211963SAfshin.Ardakani@Sun.COM 108311963SAfshin.Ardakani@Sun.COM if (sr->tid_tree == NULL) 108411963SAfshin.Ardakani@Sun.COM return (0); 108511963SAfshin.Ardakani@Sun.COM 108611963SAfshin.Ardakani@Sun.COM if ((rc = smb_unc_init(path, &unc)) != 0) 108711963SAfshin.Ardakani@Sun.COM return (rc); 108811963SAfshin.Ardakani@Sun.COM 108911963SAfshin.Ardakani@Sun.COM if (smb_strcasecmp(unc.unc_share, sr->tid_tree->t_sharename, 0)) { 109011963SAfshin.Ardakani@Sun.COM smb_unc_free(&unc); 109111963SAfshin.Ardakani@Sun.COM return (EINVAL); 109211963SAfshin.Ardakani@Sun.COM } 109311963SAfshin.Ardakani@Sun.COM 109411963SAfshin.Ardakani@Sun.COM linkpath = unc.unc_path; 109511963SAfshin.Ardakani@Sun.COM (void) snprintf(path, pathsz, "/%s", (linkpath) ? linkpath : ""); 109611963SAfshin.Ardakani@Sun.COM 109711963SAfshin.Ardakani@Sun.COM smb_unc_free(&unc); 109811963SAfshin.Ardakani@Sun.COM return (0); 109911963SAfshin.Ardakani@Sun.COM } 1100