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