1fe1c642dSBill Krier /* 2fe1c642dSBill Krier * CDDL HEADER START 3fe1c642dSBill Krier * 4fe1c642dSBill Krier * The contents of this file are subject to the terms of the 5fe1c642dSBill Krier * Common Development and Distribution License (the "License"). 6fe1c642dSBill Krier * You may not use this file except in compliance with the License. 7fe1c642dSBill Krier * 8fe1c642dSBill Krier * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fe1c642dSBill Krier * or http://www.opensolaris.org/os/licensing. 10fe1c642dSBill Krier * See the License for the specific language governing permissions 11fe1c642dSBill Krier * and limitations under the License. 12fe1c642dSBill Krier * 13fe1c642dSBill Krier * When distributing Covered Code, include this CDDL HEADER in each 14fe1c642dSBill Krier * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fe1c642dSBill Krier * If applicable, add the following below this CDDL HEADER, with the 16fe1c642dSBill Krier * fields enclosed by brackets "[]" replaced with your own identifying 17fe1c642dSBill Krier * information: Portions Copyright [yyyy] [name of copyright owner] 18fe1c642dSBill Krier * 19fe1c642dSBill Krier * CDDL HEADER END 20fe1c642dSBill Krier */ 21fe1c642dSBill Krier /* 22148c5f43SAlan Wright * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23*1bc6aeeeSMatt Barden * Copyright 2019 Nexenta by DDN, Inc. All rights reserved. 24fe1c642dSBill Krier */ 25fe1c642dSBill Krier 26fe1c642dSBill Krier #include <smbsrv/smb_kproto.h> 27fe1c642dSBill Krier #include <smbsrv/smb_fsops.h> 28fe1c642dSBill Krier #include <sys/pathname.h> 29fe1c642dSBill Krier #include <sys/sdt.h> 30fe1c642dSBill Krier 31fe1c642dSBill Krier static char *smb_pathname_catia_v5tov4(smb_request_t *, char *, char *, int); 32fe1c642dSBill Krier static char *smb_pathname_catia_v4tov5(smb_request_t *, char *, char *, int); 33fe1c642dSBill Krier static int smb_pathname_lookup(pathname_t *, pathname_t *, int, 349fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States vnode_t **, vnode_t *, vnode_t *, smb_attr_t *attr, cred_t *); 35fe1c642dSBill Krier static char *smb_pathname_strdup(smb_request_t *, const char *); 36fe1c642dSBill Krier static char *smb_pathname_strcat(smb_request_t *, char *, const char *); 37fe1c642dSBill Krier static void smb_pathname_preprocess(smb_request_t *, smb_pathname_t *); 389fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void smb_pathname_preprocess_quota(smb_request_t *, smb_pathname_t *); 399fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static int smb_pathname_dfs_preprocess(smb_request_t *, char *, size_t); 409fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void smb_pathname_preprocess_adminshare(smb_request_t *, 419fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_pathname_t *); 429fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 43fe1c642dSBill Krier 44fe1c642dSBill Krier uint32_t 45fe1c642dSBill Krier smb_is_executable(char *path) 46fe1c642dSBill Krier { 47fe1c642dSBill Krier char extension[5]; 48fe1c642dSBill Krier int len = strlen(path); 49fe1c642dSBill Krier 50fe1c642dSBill Krier if ((len >= 4) && (path[len - 4] == '.')) { 51fe1c642dSBill Krier (void) strcpy(extension, &path[len - 3]); 52fe1c642dSBill Krier (void) smb_strupr(extension); 53fe1c642dSBill Krier 54fe1c642dSBill Krier if (strcmp(extension, "EXE") == 0) 55fe1c642dSBill Krier return (NODE_FLAGS_EXECUTABLE); 56fe1c642dSBill Krier 57fe1c642dSBill Krier if (strcmp(extension, "COM") == 0) 58fe1c642dSBill Krier return (NODE_FLAGS_EXECUTABLE); 59fe1c642dSBill Krier 60fe1c642dSBill Krier if (strcmp(extension, "DLL") == 0) 61fe1c642dSBill Krier return (NODE_FLAGS_EXECUTABLE); 62fe1c642dSBill Krier 63fe1c642dSBill Krier if (strcmp(extension, "SYM") == 0) 64fe1c642dSBill Krier return (NODE_FLAGS_EXECUTABLE); 65fe1c642dSBill Krier } 66fe1c642dSBill Krier 67fe1c642dSBill Krier return (0); 68fe1c642dSBill Krier } 69fe1c642dSBill Krier 70fe1c642dSBill Krier /* 71fe1c642dSBill Krier * smb_pathname_reduce 72fe1c642dSBill Krier * 73fe1c642dSBill Krier * smb_pathname_reduce() takes a path and returns the smb_node for the 74fe1c642dSBill Krier * second-to-last component of the path. It also returns the name of the last 75fe1c642dSBill Krier * component. Pointers for both of these fields must be supplied by the caller. 76fe1c642dSBill Krier * 77fe1c642dSBill Krier * Upon success, 0 is returned. 78fe1c642dSBill Krier * 79fe1c642dSBill Krier * Upon error, *dir_node will be set to 0. 80fe1c642dSBill Krier * 81fe1c642dSBill Krier * *sr (in) 82fe1c642dSBill Krier * --- 83fe1c642dSBill Krier * smb_request structure pointer 84fe1c642dSBill Krier * 85fe1c642dSBill Krier * *cred (in) 86fe1c642dSBill Krier * ----- 87fe1c642dSBill Krier * credential 88fe1c642dSBill Krier * 89fe1c642dSBill Krier * *path (in) 90fe1c642dSBill Krier * ----- 91fe1c642dSBill Krier * pathname to be looked up 92fe1c642dSBill Krier * 93fe1c642dSBill Krier * *share_root_node (in) 94fe1c642dSBill Krier * ---------------- 95fe1c642dSBill Krier * File operations which are share-relative should pass sr->tid_tree->t_snode. 96fe1c642dSBill Krier * If the call is not for a share-relative operation, this parameter must be 0 97fe1c642dSBill Krier * (e.g. the call from smbsr_setup_share()). (Such callers will have path 98fe1c642dSBill Krier * operations done using root_smb_node.) This parameter is used to determine 99fe1c642dSBill Krier * whether mount points can be crossed. 100fe1c642dSBill Krier * 101fe1c642dSBill Krier * share_root_node should have at least one reference on it. This reference 102fe1c642dSBill Krier * will stay intact throughout this routine. 103fe1c642dSBill Krier * 104fe1c642dSBill Krier * *cur_node (in) 105fe1c642dSBill Krier * --------- 106fe1c642dSBill Krier * The smb_node for the current directory (for relative paths). 107fe1c642dSBill Krier * cur_node should have at least one reference on it. 108fe1c642dSBill Krier * This reference will stay intact throughout this routine. 109fe1c642dSBill Krier * 110fe1c642dSBill Krier * **dir_node (out) 111fe1c642dSBill Krier * ---------- 112fe1c642dSBill Krier * Directory for the penultimate component of the original path. 113fe1c642dSBill Krier * (Note that this is not the same as the parent directory of the ultimate 114fe1c642dSBill Krier * target in the case of a link.) 115fe1c642dSBill Krier * 116fe1c642dSBill Krier * The directory smb_node is returned held. The caller will need to release 117fe1c642dSBill Krier * the hold or otherwise make sure it will get released (e.g. in a destroy 118fe1c642dSBill Krier * routine if made part of a global structure). 119fe1c642dSBill Krier * 120fe1c642dSBill Krier * last_component (out) 121fe1c642dSBill Krier * -------------- 122fe1c642dSBill Krier * The last component of the path. (This may be different from the name of any 123fe1c642dSBill Krier * link target to which the last component may resolve.) 124fe1c642dSBill Krier * 125fe1c642dSBill Krier * 126fe1c642dSBill Krier * ____________________________ 127fe1c642dSBill Krier * 128fe1c642dSBill Krier * The CIFS server lookup path needs to have logic equivalent to that of 129fe1c642dSBill Krier * smb_fsop_lookup(), smb_vop_lookup() and other smb_vop_*() routines in the 130fe1c642dSBill Krier * following areas: 131fe1c642dSBill Krier * 1325f1ef25cSAram Hăvărneanu * - traversal of child mounts (handled by smb_pathname_reduce) 133fe1c642dSBill Krier * - unmangling (handled in smb_pathname) 134fe1c642dSBill Krier * - "chroot" behavior of share root (handled by lookuppnvp) 135fe1c642dSBill Krier * 136fe1c642dSBill Krier * In addition, it needs to replace backslashes with forward slashes. It also 137fe1c642dSBill Krier * ensures that link processing is done correctly, and that directory 138fe1c642dSBill Krier * information requested by the caller is correctly returned (i.e. for paths 139fe1c642dSBill Krier * with a link in the last component, the directory information of the 140fe1c642dSBill Krier * link and not the target needs to be returned). 141fe1c642dSBill Krier */ 142fe1c642dSBill Krier 143fe1c642dSBill Krier int 144fe1c642dSBill Krier smb_pathname_reduce( 145fe1c642dSBill Krier smb_request_t *sr, 146fe1c642dSBill Krier cred_t *cred, 147fe1c642dSBill Krier const char *path, 148fe1c642dSBill Krier smb_node_t *share_root_node, 149fe1c642dSBill Krier smb_node_t *cur_node, 150fe1c642dSBill Krier smb_node_t **dir_node, 151fe1c642dSBill Krier char *last_component) 152fe1c642dSBill Krier { 153fe1c642dSBill Krier smb_node_t *root_node; 154*1bc6aeeeSMatt Barden pathname_t ppn, mnt_pn; 155fe1c642dSBill Krier char *usepath; 156fe1c642dSBill Krier int lookup_flags = FOLLOW; 157fe1c642dSBill Krier int trailing_slash = 0; 158fe1c642dSBill Krier int err = 0; 159fe1c642dSBill Krier int len; 160*1bc6aeeeSMatt Barden smb_node_t *vss_node; 161fe1c642dSBill Krier smb_node_t *local_cur_node; 162fe1c642dSBill Krier smb_node_t *local_root_node; 163*1bc6aeeeSMatt Barden boolean_t chk_vss; 164*1bc6aeeeSMatt Barden char *gmttoken; 165fe1c642dSBill Krier 166fe1c642dSBill Krier ASSERT(dir_node); 167fe1c642dSBill Krier ASSERT(last_component); 168fe1c642dSBill Krier 169fe1c642dSBill Krier *dir_node = NULL; 170fe1c642dSBill Krier *last_component = '\0'; 171*1bc6aeeeSMatt Barden vss_node = NULL; 172*1bc6aeeeSMatt Barden gmttoken = NULL; 173*1bc6aeeeSMatt Barden chk_vss = B_FALSE; 174fe1c642dSBill Krier 175fe1c642dSBill Krier if (sr && sr->tid_tree) { 176f96bd5c8SAlan Wright if (STYPE_ISIPC(sr->tid_tree->t_res_type)) 177fe1c642dSBill Krier return (EACCES); 178fe1c642dSBill Krier } 179fe1c642dSBill Krier 180fe1c642dSBill Krier if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 181fe1c642dSBill Krier lookup_flags |= FIGNORECASE; 182fe1c642dSBill Krier 183fe1c642dSBill Krier if (path == NULL) 184fe1c642dSBill Krier return (EINVAL); 185fe1c642dSBill Krier 186fe1c642dSBill Krier if (*path == '\0') 187fe1c642dSBill Krier return (ENOENT); 188fe1c642dSBill Krier 189b24e356bSPeer Dampmann usepath = kmem_alloc(SMB_MAXPATHLEN, KM_SLEEP); 190fe1c642dSBill Krier 191b24e356bSPeer Dampmann len = strlcpy(usepath, path, SMB_MAXPATHLEN); 192b24e356bSPeer Dampmann if (len >= SMB_MAXPATHLEN) { 193b24e356bSPeer Dampmann kmem_free(usepath, SMB_MAXPATHLEN); 194fe1c642dSBill Krier return (ENAMETOOLONG); 195fe1c642dSBill Krier } 196fe1c642dSBill Krier 197fe1c642dSBill Krier (void) strsubst(usepath, '\\', '/'); 198fe1c642dSBill Krier 199fe1c642dSBill Krier if (share_root_node) 200fe1c642dSBill Krier root_node = share_root_node; 201fe1c642dSBill Krier else 202fe1c642dSBill Krier root_node = sr->sr_server->si_root_smb_node; 203fe1c642dSBill Krier 204fe1c642dSBill Krier if (cur_node == NULL) 205fe1c642dSBill Krier cur_node = root_node; 206fe1c642dSBill Krier 207fe1c642dSBill Krier local_cur_node = cur_node; 208fe1c642dSBill Krier local_root_node = root_node; 209fe1c642dSBill Krier 210a90cf9f2SGordon Ross if (SMB_TREE_IS_DFSROOT(sr)) { 211a90cf9f2SGordon Ross int is_dfs; 212a90cf9f2SGordon Ross if (sr->session->dialect >= SMB_VERS_2_BASE) 213a90cf9f2SGordon Ross is_dfs = sr->smb2_hdr_flags & 214a90cf9f2SGordon Ross SMB2_FLAGS_DFS_OPERATIONS; 215a90cf9f2SGordon Ross else 216a90cf9f2SGordon Ross is_dfs = sr->smb_flg2 & SMB_FLAGS2_DFS; 217a90cf9f2SGordon Ross if (is_dfs != 0) { 218a90cf9f2SGordon Ross err = smb_pathname_dfs_preprocess(sr, usepath, 219a90cf9f2SGordon Ross SMB_MAXPATHLEN); 2209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (err != 0) { 221b24e356bSPeer Dampmann kmem_free(usepath, SMB_MAXPATHLEN); 2229fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return (err); 2239fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 2249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States len = strlen(usepath); 2259fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 226a90cf9f2SGordon Ross } 2279fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 228a90cf9f2SGordon Ross if (sr != NULL) { 229*1bc6aeeeSMatt Barden if (sr->session->dialect >= SMB_VERS_2_BASE) { 230a90cf9f2SGordon Ross chk_vss = sr->arg.open.create_timewarp; 231*1bc6aeeeSMatt Barden } else { 232a90cf9f2SGordon Ross chk_vss = (sr->smb_flg2 & 233a90cf9f2SGordon Ross SMB_FLAGS2_REPARSE_PATH) != 0; 234*1bc6aeeeSMatt Barden 235a90cf9f2SGordon Ross if (chk_vss) { 236*1bc6aeeeSMatt Barden gmttoken = kmem_alloc(SMB_VSS_GMT_SIZE, 237*1bc6aeeeSMatt Barden KM_SLEEP); 238*1bc6aeeeSMatt Barden err = smb_vss_extract_gmttoken(usepath, 239*1bc6aeeeSMatt Barden gmttoken); 240fe1c642dSBill Krier if (err != 0) { 241a90cf9f2SGordon Ross kmem_free(usepath, SMB_MAXPATHLEN); 242*1bc6aeeeSMatt Barden kmem_free(gmttoken, SMB_VSS_GMT_SIZE); 243fe1c642dSBill Krier return (err); 244fe1c642dSBill Krier } 245fe1c642dSBill Krier len = strlen(usepath); 246fe1c642dSBill Krier } 247a90cf9f2SGordon Ross } 248*1bc6aeeeSMatt Barden if (chk_vss) 249*1bc6aeeeSMatt Barden (void) pn_alloc(&mnt_pn); 250*1bc6aeeeSMatt Barden } 251fe1c642dSBill Krier 252fe1c642dSBill Krier if (usepath[len - 1] == '/') 253fe1c642dSBill Krier trailing_slash = 1; 254fe1c642dSBill Krier 255fe1c642dSBill Krier (void) strcanon(usepath, "/"); 256fe1c642dSBill Krier 257b24e356bSPeer Dampmann (void) pn_alloc_sz(&ppn, SMB_MAXPATHLEN); 258fe1c642dSBill Krier 259fe1c642dSBill Krier if ((err = pn_set(&ppn, usepath)) != 0) { 260fe1c642dSBill Krier (void) pn_free(&ppn); 261b24e356bSPeer Dampmann kmem_free(usepath, SMB_MAXPATHLEN); 262*1bc6aeeeSMatt Barden if (chk_vss) 263*1bc6aeeeSMatt Barden (void) pn_free(&mnt_pn); 264*1bc6aeeeSMatt Barden if (gmttoken != NULL) 265*1bc6aeeeSMatt Barden kmem_free(gmttoken, SMB_VSS_GMT_SIZE); 266fe1c642dSBill Krier return (err); 267fe1c642dSBill Krier } 268fe1c642dSBill Krier 269fe1c642dSBill Krier /* 270fe1c642dSBill Krier * If a path does not have a trailing slash, strip off the 271fe1c642dSBill Krier * last component. (We only need to return an smb_node for 272fe1c642dSBill Krier * the second to last component; a name is returned for the 273fe1c642dSBill Krier * last component.) 274*1bc6aeeeSMatt Barden * 275*1bc6aeeeSMatt Barden * For VSS requests, the last component might be a filesystem of its 276*1bc6aeeeSMatt Barden * own, and we need to discover that before exiting this function, 277*1bc6aeeeSMatt Barden * so allow the lookup to happen on the last component. 278*1bc6aeeeSMatt Barden * We'll correct this later when we convert to the snapshot. 279fe1c642dSBill Krier */ 280fe1c642dSBill Krier 281*1bc6aeeeSMatt Barden if (!chk_vss) { 282fe1c642dSBill Krier if (trailing_slash) { 283fe1c642dSBill Krier (void) strlcpy(last_component, ".", MAXNAMELEN); 284fe1c642dSBill Krier } else { 285fe1c642dSBill Krier (void) pn_setlast(&ppn); 286fe1c642dSBill Krier (void) strlcpy(last_component, ppn.pn_path, MAXNAMELEN); 287fe1c642dSBill Krier ppn.pn_path[0] = '\0'; 288fe1c642dSBill Krier } 289*1bc6aeeeSMatt Barden } 290fe1c642dSBill Krier 291fe1c642dSBill Krier if ((strcmp(ppn.pn_buf, "/") == 0) || (ppn.pn_buf[0] == '\0')) { 292fe1c642dSBill Krier smb_node_ref(local_cur_node); 293fe1c642dSBill Krier *dir_node = local_cur_node; 294fe1c642dSBill Krier } else { 295fe1c642dSBill Krier err = smb_pathname(sr, ppn.pn_buf, lookup_flags, 296*1bc6aeeeSMatt Barden local_root_node, local_cur_node, NULL, dir_node, cred, 297*1bc6aeeeSMatt Barden chk_vss ? &mnt_pn : NULL); 298fe1c642dSBill Krier } 299fe1c642dSBill Krier 300fe1c642dSBill Krier (void) pn_free(&ppn); 301b24e356bSPeer Dampmann kmem_free(usepath, SMB_MAXPATHLEN); 302fe1c642dSBill Krier 303fe1c642dSBill Krier /* 304*1bc6aeeeSMatt Barden * We need to try and convert to snapshots, even on error. 305*1bc6aeeeSMatt Barden * This is to handle the following cases: 306*1bc6aeeeSMatt Barden * - We're on the lowest level filesystem, but a directory got renamed 307*1bc6aeeeSMatt Barden * on the live version. We'll get ENOENT, but can still find it in 308*1bc6aeeeSMatt Barden * the snapshot. 309*1bc6aeeeSMatt Barden * - The last component was actually a file. We need to leave the last 310*1bc6aeeeSMatt Barden * component in in case it is, itself, a mountpoint, but that means 311*1bc6aeeeSMatt Barden * we might get ENOTDIR if it's not actually a directory. 312*1bc6aeeeSMatt Barden * 313*1bc6aeeeSMatt Barden * Note that if you change the share-relative name of a mountpoint, 314*1bc6aeeeSMatt Barden * you won't be able to access previous versions of files under it. 315*1bc6aeeeSMatt Barden */ 316*1bc6aeeeSMatt Barden if (chk_vss && *dir_node != NULL) { 317*1bc6aeeeSMatt Barden if ((err = smb_vss_lookup_nodes(sr, *dir_node, &vss_node, 318*1bc6aeeeSMatt Barden gmttoken)) == 0) { 319*1bc6aeeeSMatt Barden char *p = mnt_pn.pn_path; 320*1bc6aeeeSMatt Barden size_t pathleft; 321*1bc6aeeeSMatt Barden 322*1bc6aeeeSMatt Barden smb_node_release(*dir_node); 323*1bc6aeeeSMatt Barden *dir_node = NULL; 324*1bc6aeeeSMatt Barden pathleft = pn_pathleft(&mnt_pn); 325*1bc6aeeeSMatt Barden 326*1bc6aeeeSMatt Barden if (pathleft == 0 || trailing_slash) { 327*1bc6aeeeSMatt Barden (void) strlcpy(last_component, ".", MAXNAMELEN); 328*1bc6aeeeSMatt Barden } else { 329*1bc6aeeeSMatt Barden (void) pn_setlast(&mnt_pn); 330*1bc6aeeeSMatt Barden (void) strlcpy(last_component, mnt_pn.pn_path, 331*1bc6aeeeSMatt Barden MAXNAMELEN); 332*1bc6aeeeSMatt Barden mnt_pn.pn_path[0] = '\0'; 333*1bc6aeeeSMatt Barden pathleft -= strlen(last_component); 334*1bc6aeeeSMatt Barden } 335*1bc6aeeeSMatt Barden 336*1bc6aeeeSMatt Barden if (pathleft != 0) { 337*1bc6aeeeSMatt Barden err = smb_pathname(sr, p, lookup_flags, 338*1bc6aeeeSMatt Barden vss_node, vss_node, NULL, dir_node, cred, 339*1bc6aeeeSMatt Barden NULL); 340*1bc6aeeeSMatt Barden } else { 341*1bc6aeeeSMatt Barden *dir_node = vss_node; 342*1bc6aeeeSMatt Barden vss_node = NULL; 343*1bc6aeeeSMatt Barden } 344*1bc6aeeeSMatt Barden } 345*1bc6aeeeSMatt Barden } 346*1bc6aeeeSMatt Barden 347*1bc6aeeeSMatt Barden if (chk_vss) 348*1bc6aeeeSMatt Barden (void) pn_free(&mnt_pn); 349*1bc6aeeeSMatt Barden if (gmttoken != NULL) 350*1bc6aeeeSMatt Barden kmem_free(gmttoken, SMB_VSS_GMT_SIZE); 351*1bc6aeeeSMatt Barden 352*1bc6aeeeSMatt Barden /* 3535f1ef25cSAram Hăvărneanu * Prevent traversal to another file system if mount point 3545f1ef25cSAram Hăvărneanu * traversal is disabled. 355fe1c642dSBill Krier * 356fe1c642dSBill Krier * Note that we disregard whether the traversal of the path went 357fe1c642dSBill Krier * outside of the file system and then came back (say via a link). 3585f1ef25cSAram Hăvărneanu * This means that only symlinks that are expressed relatively to 3595f1ef25cSAram Hăvărneanu * the share root work. 3605f1ef25cSAram Hăvărneanu * 3615f1ef25cSAram Hăvărneanu * share_root_node is NULL when mapping a share, so we disregard 3625f1ef25cSAram Hăvărneanu * that case. 363fe1c642dSBill Krier */ 364fe1c642dSBill Krier 365fe1c642dSBill Krier if ((err == 0) && share_root_node) { 3665f1ef25cSAram Hăvărneanu if (share_root_node->vp->v_vfsp != (*dir_node)->vp->v_vfsp) { 367fe1c642dSBill Krier err = EACCES; 3685f1ef25cSAram Hăvărneanu if ((sr) && (sr)->tid_tree && 3695f1ef25cSAram Hăvărneanu smb_tree_has_feature((sr)->tid_tree, 3705f1ef25cSAram Hăvărneanu SMB_TREE_TRAVERSE_MOUNTS)) 3715f1ef25cSAram Hăvărneanu err = 0; 3725f1ef25cSAram Hăvărneanu } 373fe1c642dSBill Krier } 374fe1c642dSBill Krier 375fe1c642dSBill Krier if (err) { 376fe1c642dSBill Krier if (*dir_node) { 377fe1c642dSBill Krier (void) smb_node_release(*dir_node); 378fe1c642dSBill Krier *dir_node = NULL; 379fe1c642dSBill Krier } 380fe1c642dSBill Krier *last_component = 0; 381fe1c642dSBill Krier } 382fe1c642dSBill Krier 383*1bc6aeeeSMatt Barden if (vss_node != NULL) 384*1bc6aeeeSMatt Barden (void) smb_node_release(vss_node); 385fe1c642dSBill Krier return (err); 386fe1c642dSBill Krier } 387fe1c642dSBill Krier 388fe1c642dSBill Krier /* 389fe1c642dSBill Krier * smb_pathname() 390fe1c642dSBill Krier * wrapper to lookuppnvp(). Handles name unmangling. 391fe1c642dSBill Krier * 392fe1c642dSBill Krier * *dir_node is the true directory of the target *node. 393fe1c642dSBill Krier * 394fe1c642dSBill Krier * If any component but the last in the path is not found, ENOTDIR instead of 395fe1c642dSBill Krier * ENOENT will be returned. 396fe1c642dSBill Krier * 397fe1c642dSBill Krier * Path components are processed one at a time so that smb_nodes can be 398fe1c642dSBill Krier * created for each component. This allows the n_dnode field in the 399fe1c642dSBill Krier * smb_node to be properly populated. 400fe1c642dSBill Krier * 401fe1c642dSBill Krier * Because of the above, links are also processed in this routine 402fe1c642dSBill Krier * (i.e., we do not pass the FOLLOW flag to lookuppnvp()). This 403fe1c642dSBill Krier * will allow smb_nodes to be created for each component of a link. 404fe1c642dSBill Krier * 405fe1c642dSBill Krier * Mangle checking is per component. If a name is mangled, when the 406fe1c642dSBill Krier * unmangled name is passed to smb_pathname_lookup() do not pass 407fe1c642dSBill Krier * FIGNORECASE, since the unmangled name is the real on-disk name. 408fe1c642dSBill Krier * Otherwise pass FIGNORECASE if it's set in flags. This will cause the 409fe1c642dSBill Krier * file system to return "first match" in the event of a case collision. 410fe1c642dSBill Krier * 411fe1c642dSBill Krier * If CATIA character translation is enabled it is applied to each 412fe1c642dSBill Krier * component before passing the component to smb_pathname_lookup(). 413fe1c642dSBill Krier * After smb_pathname_lookup() the reverse translation is applied. 414fe1c642dSBill Krier */ 415fe1c642dSBill Krier 416fe1c642dSBill Krier int 417fe1c642dSBill Krier smb_pathname(smb_request_t *sr, char *path, int flags, 418fe1c642dSBill Krier smb_node_t *root_node, smb_node_t *cur_node, smb_node_t **dir_node, 419*1bc6aeeeSMatt Barden smb_node_t **ret_node, cred_t *cred, pathname_t *mnt_pn) 420fe1c642dSBill Krier { 421fe1c642dSBill Krier char *component, *real_name, *namep; 422fe1c642dSBill Krier pathname_t pn, rpn, upn, link_pn; 423*1bc6aeeeSMatt Barden smb_node_t *dnode, *fnode, *mnt_node; 4249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_attr_t attr; 425fe1c642dSBill Krier vnode_t *rootvp, *vp; 426fe1c642dSBill Krier size_t pathleft; 427fe1c642dSBill Krier int err = 0; 428fe1c642dSBill Krier int nlink = 0; 429fe1c642dSBill Krier int local_flags; 430fe1c642dSBill Krier uint32_t abe_flag = 0; 431fe1c642dSBill Krier char namebuf[MAXNAMELEN]; 432*1bc6aeeeSMatt Barden vnode_t *fsrootvp = NULL; 433fe1c642dSBill Krier 434fe1c642dSBill Krier if (path == NULL) 435fe1c642dSBill Krier return (EINVAL); 436fe1c642dSBill Krier 437fe1c642dSBill Krier ASSERT(root_node); 438fe1c642dSBill Krier ASSERT(cur_node); 439fe1c642dSBill Krier ASSERT(ret_node); 440fe1c642dSBill Krier 441fe1c642dSBill Krier *ret_node = NULL; 442fe1c642dSBill Krier 443fe1c642dSBill Krier if (dir_node) 444fe1c642dSBill Krier *dir_node = NULL; 445fe1c642dSBill Krier 446b24e356bSPeer Dampmann (void) pn_alloc_sz(&upn, SMB_MAXPATHLEN); 447fe1c642dSBill Krier 448fe1c642dSBill Krier if ((err = pn_set(&upn, path)) != 0) { 449fe1c642dSBill Krier (void) pn_free(&upn); 450fe1c642dSBill Krier return (err); 451fe1c642dSBill Krier } 452fe1c642dSBill Krier 453*1bc6aeeeSMatt Barden if (mnt_pn != NULL && (err = pn_set(mnt_pn, path) != 0)) { 454*1bc6aeeeSMatt Barden (void) pn_free(&upn); 455*1bc6aeeeSMatt Barden return (err); 456*1bc6aeeeSMatt Barden } 457*1bc6aeeeSMatt Barden 458fe1c642dSBill Krier if (SMB_TREE_SUPPORTS_ABE(sr)) 459fe1c642dSBill Krier abe_flag = SMB_ABE; 460fe1c642dSBill Krier 461fe1c642dSBill Krier (void) pn_alloc(&pn); 462fe1c642dSBill Krier (void) pn_alloc(&rpn); 463fe1c642dSBill Krier 464fe1c642dSBill Krier component = kmem_alloc(MAXNAMELEN, KM_SLEEP); 465fe1c642dSBill Krier real_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 466fe1c642dSBill Krier 467*1bc6aeeeSMatt Barden if (mnt_pn != NULL) { 468*1bc6aeeeSMatt Barden mnt_node = cur_node; 469*1bc6aeeeSMatt Barden smb_node_ref(cur_node); 470*1bc6aeeeSMatt Barden } else 471*1bc6aeeeSMatt Barden mnt_node = NULL; 472fe1c642dSBill Krier fnode = NULL; 473fe1c642dSBill Krier dnode = cur_node; 474fe1c642dSBill Krier smb_node_ref(dnode); 475fe1c642dSBill Krier rootvp = root_node->vp; 476fe1c642dSBill Krier 477fe1c642dSBill Krier while ((pathleft = pn_pathleft(&upn)) != 0) { 478fe1c642dSBill Krier if (fnode) { 479fe1c642dSBill Krier smb_node_release(dnode); 480fe1c642dSBill Krier dnode = fnode; 481fe1c642dSBill Krier fnode = NULL; 482fe1c642dSBill Krier } 483fe1c642dSBill Krier 484fe1c642dSBill Krier if ((err = pn_getcomponent(&upn, component)) != 0) 485fe1c642dSBill Krier break; 486fe1c642dSBill Krier 487fe1c642dSBill Krier if ((namep = smb_pathname_catia_v5tov4(sr, component, 488fe1c642dSBill Krier namebuf, sizeof (namebuf))) == NULL) { 489fe1c642dSBill Krier err = EILSEQ; 490fe1c642dSBill Krier break; 491fe1c642dSBill Krier } 492fe1c642dSBill Krier 493fe1c642dSBill Krier if ((err = pn_set(&pn, namep)) != 0) 494fe1c642dSBill Krier break; 495fe1c642dSBill Krier 4968d94f651SGordon Ross /* We want the DOS attributes. */ 4978d94f651SGordon Ross bzero(&attr, sizeof (attr)); 4988d94f651SGordon Ross attr.sa_mask = SMB_AT_DOSATTR; 4998d94f651SGordon Ross 500fe1c642dSBill Krier local_flags = flags & FIGNORECASE; 501fe1c642dSBill Krier err = smb_pathname_lookup(&pn, &rpn, local_flags, 5029fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States &vp, rootvp, dnode->vp, &attr, cred); 503fe1c642dSBill Krier 504fe1c642dSBill Krier if (err) { 505cb174861Sjoyce mcintosh if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) || 506cb174861Sjoyce mcintosh !smb_maybe_mangled(component)) 507fe1c642dSBill Krier break; 508fe1c642dSBill Krier 509148c5f43SAlan Wright if ((err = smb_unmangle(dnode, component, 510fe1c642dSBill Krier real_name, MAXNAMELEN, abe_flag)) != 0) 511fe1c642dSBill Krier break; 512fe1c642dSBill Krier 513fe1c642dSBill Krier if ((namep = smb_pathname_catia_v5tov4(sr, real_name, 514fe1c642dSBill Krier namebuf, sizeof (namebuf))) == NULL) { 515fe1c642dSBill Krier err = EILSEQ; 516fe1c642dSBill Krier break; 517fe1c642dSBill Krier } 518fe1c642dSBill Krier 519fe1c642dSBill Krier if ((err = pn_set(&pn, namep)) != 0) 520fe1c642dSBill Krier break; 521fe1c642dSBill Krier 522fe1c642dSBill Krier local_flags = 0; 523fe1c642dSBill Krier err = smb_pathname_lookup(&pn, &rpn, local_flags, 5249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States &vp, rootvp, dnode->vp, &attr, cred); 525fe1c642dSBill Krier if (err) 526fe1c642dSBill Krier break; 527fe1c642dSBill Krier } 528fe1c642dSBill Krier 5299fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* 5309fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * This check MUST be done before symlink check 5319fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * since a reparse point is of type VLNK but should 5329fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * not be handled like a regular symlink. 5339fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States */ 5349fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (attr.sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) { 5359fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States err = EREMOTE; 5369fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States VN_RELE(vp); 5379fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States break; 5389fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 5399fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 540fe1c642dSBill Krier if ((vp->v_type == VLNK) && 541fe1c642dSBill Krier ((flags & FOLLOW) || pn_pathleft(&upn))) { 542fe1c642dSBill Krier 543fe1c642dSBill Krier if (++nlink > MAXSYMLINKS) { 544fe1c642dSBill Krier err = ELOOP; 545fe1c642dSBill Krier VN_RELE(vp); 546fe1c642dSBill Krier break; 547fe1c642dSBill Krier } 548fe1c642dSBill Krier 549fe1c642dSBill Krier (void) pn_alloc(&link_pn); 550fe1c642dSBill Krier err = pn_getsymlink(vp, &link_pn, cred); 551fe1c642dSBill Krier VN_RELE(vp); 552fe1c642dSBill Krier 553fe1c642dSBill Krier if (err == 0) { 554fe1c642dSBill Krier if (pn_pathleft(&link_pn) == 0) 555fe1c642dSBill Krier (void) pn_set(&link_pn, "."); 556fe1c642dSBill Krier err = pn_insert(&upn, &link_pn, 557fe1c642dSBill Krier strlen(component)); 558fe1c642dSBill Krier } 559fe1c642dSBill Krier pn_free(&link_pn); 560fe1c642dSBill Krier 561fe1c642dSBill Krier if (err) 562fe1c642dSBill Krier break; 563fe1c642dSBill Krier 564fe1c642dSBill Krier if (upn.pn_pathlen == 0) { 565fe1c642dSBill Krier err = ENOENT; 566fe1c642dSBill Krier break; 567fe1c642dSBill Krier } 568fe1c642dSBill Krier 569fe1c642dSBill Krier if (upn.pn_path[0] == '/') { 570fe1c642dSBill Krier fnode = root_node; 571fe1c642dSBill Krier smb_node_ref(fnode); 572fe1c642dSBill Krier } 573fe1c642dSBill Krier 574fe1c642dSBill Krier if (pn_fixslash(&upn)) 575fe1c642dSBill Krier flags |= FOLLOW; 576fe1c642dSBill Krier 577fe1c642dSBill Krier } else { 578fe1c642dSBill Krier if (flags & FIGNORECASE) { 579fe1c642dSBill Krier if (strcmp(rpn.pn_path, "/") != 0) 580fe1c642dSBill Krier pn_setlast(&rpn); 581fe1c642dSBill Krier namep = rpn.pn_path; 582fe1c642dSBill Krier } else { 583fe1c642dSBill Krier namep = pn.pn_path; 584fe1c642dSBill Krier } 585fe1c642dSBill Krier 586fe1c642dSBill Krier namep = smb_pathname_catia_v4tov5(sr, namep, 587fe1c642dSBill Krier namebuf, sizeof (namebuf)); 588fe1c642dSBill Krier 589fe1c642dSBill Krier fnode = smb_node_lookup(sr, NULL, cred, vp, namep, 590fe1c642dSBill Krier dnode, NULL); 591fe1c642dSBill Krier VN_RELE(vp); 592fe1c642dSBill Krier 593fe1c642dSBill Krier if (fnode == NULL) { 594fe1c642dSBill Krier err = ENOMEM; 595fe1c642dSBill Krier break; 596fe1c642dSBill Krier } 597fe1c642dSBill Krier } 598fe1c642dSBill Krier 599fe1c642dSBill Krier while (upn.pn_path[0] == '/') { 600fe1c642dSBill Krier upn.pn_path++; 601fe1c642dSBill Krier upn.pn_pathlen--; 602fe1c642dSBill Krier } 603fe1c642dSBill Krier 604*1bc6aeeeSMatt Barden /* 605*1bc6aeeeSMatt Barden * If the node we looked up is the root of a filesystem, 606*1bc6aeeeSMatt Barden * snapshot the lookup so we can replay this after discovering 607*1bc6aeeeSMatt Barden * the lowest mounted filesystem. 608*1bc6aeeeSMatt Barden */ 609*1bc6aeeeSMatt Barden if (mnt_pn != NULL && 610*1bc6aeeeSMatt Barden fnode != NULL && 611*1bc6aeeeSMatt Barden (err = VFS_ROOT(fnode->vp->v_vfsp, &fsrootvp)) == 0) { 612*1bc6aeeeSMatt Barden if (fsrootvp == fnode->vp) { 613*1bc6aeeeSMatt Barden mnt_pn->pn_pathlen = pn_pathleft(&upn); 614*1bc6aeeeSMatt Barden mnt_pn->pn_path = mnt_pn->pn_buf + 615*1bc6aeeeSMatt Barden ((ptrdiff_t)upn.pn_path - 616*1bc6aeeeSMatt Barden (ptrdiff_t)upn.pn_buf); 617*1bc6aeeeSMatt Barden 618*1bc6aeeeSMatt Barden smb_node_ref(fnode); 619*1bc6aeeeSMatt Barden if (mnt_node != NULL) 620*1bc6aeeeSMatt Barden smb_node_release(mnt_node); 621*1bc6aeeeSMatt Barden mnt_node = fnode; 622*1bc6aeeeSMatt Barden 623*1bc6aeeeSMatt Barden } 624*1bc6aeeeSMatt Barden VN_RELE(fsrootvp); 625*1bc6aeeeSMatt Barden } 626fe1c642dSBill Krier } 627fe1c642dSBill Krier 628fe1c642dSBill Krier if ((pathleft) && (err == ENOENT)) 629fe1c642dSBill Krier err = ENOTDIR; 630fe1c642dSBill Krier 631*1bc6aeeeSMatt Barden if (mnt_node == NULL) 632*1bc6aeeeSMatt Barden mnt_pn = NULL; 633*1bc6aeeeSMatt Barden 634*1bc6aeeeSMatt Barden /* 635*1bc6aeeeSMatt Barden * We always want to return a node when we're doing VSS 636*1bc6aeeeSMatt Barden * (mnt_pn != NULL) 637*1bc6aeeeSMatt Barden */ 638*1bc6aeeeSMatt Barden if (mnt_pn == NULL && err != 0) { 639fe1c642dSBill Krier if (fnode) 640fe1c642dSBill Krier smb_node_release(fnode); 641fe1c642dSBill Krier if (dnode) 642fe1c642dSBill Krier smb_node_release(dnode); 643fe1c642dSBill Krier } else { 644*1bc6aeeeSMatt Barden if (mnt_pn != NULL) { 645*1bc6aeeeSMatt Barden *ret_node = mnt_node; 646*1bc6aeeeSMatt Barden if (fnode != NULL) 647*1bc6aeeeSMatt Barden smb_node_release(fnode); 648*1bc6aeeeSMatt Barden } else { 649fe1c642dSBill Krier *ret_node = fnode; 650*1bc6aeeeSMatt Barden } 651fe1c642dSBill Krier 652fe1c642dSBill Krier if (dir_node) 653fe1c642dSBill Krier *dir_node = dnode; 654fe1c642dSBill Krier else 655fe1c642dSBill Krier smb_node_release(dnode); 656fe1c642dSBill Krier } 657fe1c642dSBill Krier 658fe1c642dSBill Krier kmem_free(component, MAXNAMELEN); 659fe1c642dSBill Krier kmem_free(real_name, MAXNAMELEN); 660fe1c642dSBill Krier (void) pn_free(&pn); 661fe1c642dSBill Krier (void) pn_free(&rpn); 662fe1c642dSBill Krier (void) pn_free(&upn); 663fe1c642dSBill Krier 664fe1c642dSBill Krier return (err); 665fe1c642dSBill Krier } 666fe1c642dSBill Krier 667fe1c642dSBill Krier /* 668fe1c642dSBill Krier * Holds on dvp and rootvp (if not rootdir) are required by lookuppnvp() 669fe1c642dSBill Krier * and will be released within lookuppnvp(). 670fe1c642dSBill Krier */ 671fe1c642dSBill Krier static int 672fe1c642dSBill Krier smb_pathname_lookup(pathname_t *pn, pathname_t *rpn, int flags, 6739fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States vnode_t **vp, vnode_t *rootvp, vnode_t *dvp, smb_attr_t *attr, cred_t *cred) 674fe1c642dSBill Krier { 675fe1c642dSBill Krier int err; 676fe1c642dSBill Krier 677fe1c642dSBill Krier *vp = NULL; 678fe1c642dSBill Krier VN_HOLD(dvp); 679fe1c642dSBill Krier if (rootvp != rootdir) 680fe1c642dSBill Krier VN_HOLD(rootvp); 681fe1c642dSBill Krier 682fe1c642dSBill Krier err = lookuppnvp(pn, rpn, flags, NULL, vp, rootvp, dvp, cred); 6839fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if ((err == 0) && (attr != NULL)) 6848622ec45SGordon Ross (void) smb_vop_getattr(*vp, NULL, attr, 0, zone_kcred()); 6859fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 686fe1c642dSBill Krier return (err); 687fe1c642dSBill Krier } 688fe1c642dSBill Krier 689fe1c642dSBill Krier /* 690fe1c642dSBill Krier * CATIA Translation of a pathname component prior to passing it to lookuppnvp 691fe1c642dSBill Krier * 692fe1c642dSBill Krier * If the translated component name contains a '/' NULL is returned. 693fe1c642dSBill Krier * The caller should treat this as error EILSEQ. It is not valid to 694fe1c642dSBill Krier * have a directory name with a '/'. 695fe1c642dSBill Krier */ 696fe1c642dSBill Krier static char * 697fe1c642dSBill Krier smb_pathname_catia_v5tov4(smb_request_t *sr, char *name, 698fe1c642dSBill Krier char *namebuf, int buflen) 699fe1c642dSBill Krier { 700fe1c642dSBill Krier char *namep; 701fe1c642dSBill Krier 702fe1c642dSBill Krier if (SMB_TREE_SUPPORTS_CATIA(sr)) { 703fe1c642dSBill Krier namep = smb_vop_catia_v5tov4(name, namebuf, buflen); 704fe1c642dSBill Krier if (strchr(namep, '/') != NULL) 705fe1c642dSBill Krier return (NULL); 706fe1c642dSBill Krier return (namep); 707fe1c642dSBill Krier } 708fe1c642dSBill Krier 709fe1c642dSBill Krier return (name); 710fe1c642dSBill Krier } 711fe1c642dSBill Krier 712fe1c642dSBill Krier /* 713fe1c642dSBill Krier * CATIA translation of a pathname component after returning from lookuppnvp 714fe1c642dSBill Krier */ 715fe1c642dSBill Krier static char * 716fe1c642dSBill Krier smb_pathname_catia_v4tov5(smb_request_t *sr, char *name, 717fe1c642dSBill Krier char *namebuf, int buflen) 718fe1c642dSBill Krier { 719fe1c642dSBill Krier if (SMB_TREE_SUPPORTS_CATIA(sr)) { 720fe1c642dSBill Krier smb_vop_catia_v4tov5(name, namebuf, buflen); 721fe1c642dSBill Krier return (namebuf); 722fe1c642dSBill Krier } 723fe1c642dSBill Krier 724fe1c642dSBill Krier return (name); 725fe1c642dSBill Krier } 726fe1c642dSBill Krier 727fe1c642dSBill Krier /* 728fe1c642dSBill Krier * sr - needed to check for case sense 729fe1c642dSBill Krier * path - non mangled path needed to be looked up from the startvp 730fe1c642dSBill Krier * startvp - the vnode to start the lookup from 731fe1c642dSBill Krier * rootvp - the vnode of the root of the filesystem 732fe1c642dSBill Krier * returns the vnode found when starting at startvp and using the path 733fe1c642dSBill Krier * 734fe1c642dSBill Krier * Finds a vnode starting at startvp and parsing the non mangled path 735fe1c642dSBill Krier */ 736fe1c642dSBill Krier 737fe1c642dSBill Krier vnode_t * 738fe1c642dSBill Krier smb_lookuppathvptovp(smb_request_t *sr, char *path, vnode_t *startvp, 739fe1c642dSBill Krier vnode_t *rootvp) 740fe1c642dSBill Krier { 741fe1c642dSBill Krier pathname_t pn; 742fe1c642dSBill Krier vnode_t *vp = NULL; 743fe1c642dSBill Krier int lookup_flags = FOLLOW; 744fe1c642dSBill Krier 745fe1c642dSBill Krier if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 746fe1c642dSBill Krier lookup_flags |= FIGNORECASE; 747fe1c642dSBill Krier 748fe1c642dSBill Krier (void) pn_alloc(&pn); 749fe1c642dSBill Krier 750fe1c642dSBill Krier if (pn_set(&pn, path) == 0) { 751fe1c642dSBill Krier VN_HOLD(startvp); 752fe1c642dSBill Krier if (rootvp != rootdir) 753fe1c642dSBill Krier VN_HOLD(rootvp); 754fe1c642dSBill Krier 755fe1c642dSBill Krier /* lookuppnvp should release the holds */ 756fe1c642dSBill Krier if (lookuppnvp(&pn, NULL, lookup_flags, NULL, &vp, 7578622ec45SGordon Ross rootvp, startvp, zone_kcred()) != 0) { 758fe1c642dSBill Krier pn_free(&pn); 759fe1c642dSBill Krier return (NULL); 760fe1c642dSBill Krier } 761fe1c642dSBill Krier } 762fe1c642dSBill Krier 763fe1c642dSBill Krier pn_free(&pn); 764fe1c642dSBill Krier return (vp); 765fe1c642dSBill Krier } 766fe1c642dSBill Krier 767fe1c642dSBill Krier /* 768fe1c642dSBill Krier * smb_pathname_init 769fe1c642dSBill Krier * Parse path: pname\\fname:sname:stype 770fe1c642dSBill Krier * 771fe1c642dSBill Krier * Elements of the smb_pathname_t structure are allocated using request 772fe1c642dSBill Krier * specific storage and will be free'd when the sr is destroyed. 773fe1c642dSBill Krier * 774fe1c642dSBill Krier * Populate pn structure elements with the individual elements 775fe1c642dSBill Krier * of pn->pn_path. pn->pn_sname will contain the whole stream name 776fe1c642dSBill Krier * including the stream type and preceding colon: :sname:%DATA 777fe1c642dSBill Krier * pn_stype will point to the stream type within pn_sname. 778fe1c642dSBill Krier * 7799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * If the pname element is missing pn_pname will be set to NULL. 780fe1c642dSBill Krier * If any other element is missing the pointer in pn will be NULL. 781fe1c642dSBill Krier */ 782fe1c642dSBill Krier void 783fe1c642dSBill Krier smb_pathname_init(smb_request_t *sr, smb_pathname_t *pn, char *path) 784fe1c642dSBill Krier { 785fe1c642dSBill Krier char *pname, *fname, *sname; 786fe1c642dSBill Krier int len; 787fe1c642dSBill Krier 788fe1c642dSBill Krier bzero(pn, sizeof (smb_pathname_t)); 789fe1c642dSBill Krier pn->pn_path = smb_pathname_strdup(sr, path); 790fe1c642dSBill Krier 791fe1c642dSBill Krier smb_pathname_preprocess(sr, pn); 792fe1c642dSBill Krier 793fe1c642dSBill Krier /* parse pn->pn_path into its constituent parts */ 794fe1c642dSBill Krier pname = pn->pn_path; 795fe1c642dSBill Krier fname = strrchr(pn->pn_path, '\\'); 796fe1c642dSBill Krier 797fe1c642dSBill Krier if (fname) { 798fe1c642dSBill Krier if (fname == pname) { 7999fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States pn->pn_pname = NULL; 800fe1c642dSBill Krier } else { 801fe1c642dSBill Krier *fname = '\0'; 802fe1c642dSBill Krier pn->pn_pname = 803fe1c642dSBill Krier smb_pathname_strdup(sr, pname); 804fe1c642dSBill Krier *fname = '\\'; 805fe1c642dSBill Krier } 806fe1c642dSBill Krier ++fname; 807fe1c642dSBill Krier } else { 808fe1c642dSBill Krier fname = pname; 8099fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States pn->pn_pname = NULL; 810fe1c642dSBill Krier } 811fe1c642dSBill Krier 812fe1c642dSBill Krier if (fname[0] == '\0') { 813fe1c642dSBill Krier pn->pn_fname = NULL; 814fe1c642dSBill Krier return; 815fe1c642dSBill Krier } 816fe1c642dSBill Krier 817fe1c642dSBill Krier if (!smb_is_stream_name(fname)) { 818fe1c642dSBill Krier pn->pn_fname = smb_pathname_strdup(sr, fname); 819fe1c642dSBill Krier return; 820fe1c642dSBill Krier } 821fe1c642dSBill Krier 822fe1c642dSBill Krier /* 823fe1c642dSBill Krier * find sname and stype in fname. 824fe1c642dSBill Krier * sname can't be NULL smb_is_stream_name checks this 825fe1c642dSBill Krier */ 826fe1c642dSBill Krier sname = strchr(fname, ':'); 827fe1c642dSBill Krier if (sname == fname) 828fe1c642dSBill Krier fname = NULL; 829fe1c642dSBill Krier else { 830fe1c642dSBill Krier *sname = '\0'; 831fe1c642dSBill Krier pn->pn_fname = 832fe1c642dSBill Krier smb_pathname_strdup(sr, fname); 833fe1c642dSBill Krier *sname = ':'; 834fe1c642dSBill Krier } 835fe1c642dSBill Krier 836fe1c642dSBill Krier pn->pn_sname = smb_pathname_strdup(sr, sname); 837fe1c642dSBill Krier pn->pn_stype = strchr(pn->pn_sname + 1, ':'); 838fe1c642dSBill Krier if (pn->pn_stype) { 839fe1c642dSBill Krier (void) smb_strupr(pn->pn_stype); 840fe1c642dSBill Krier } else { 841fe1c642dSBill Krier len = strlen(pn->pn_sname); 842fe1c642dSBill Krier pn->pn_sname = smb_pathname_strcat(sr, pn->pn_sname, ":$DATA"); 843fe1c642dSBill Krier pn->pn_stype = pn->pn_sname + len; 844fe1c642dSBill Krier } 845fe1c642dSBill Krier ++pn->pn_stype; 846fe1c642dSBill Krier } 847fe1c642dSBill Krier 848fe1c642dSBill Krier /* 849fe1c642dSBill Krier * smb_pathname_preprocess 850fe1c642dSBill Krier * 851fe1c642dSBill Krier * Perform common pre-processing of pn->pn_path: 852fe1c642dSBill Krier * - if the pn_path is blank, set it to '\\' 853fe1c642dSBill Krier * - perform unicode wildcard converstion. 854fe1c642dSBill Krier * - convert any '/' to '\\' 855fe1c642dSBill Krier * - eliminate duplicate slashes 856fe1c642dSBill Krier * - remove trailing slashes 8579fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * - quota directory specific pre-processing 858fe1c642dSBill Krier */ 859fe1c642dSBill Krier static void 860fe1c642dSBill Krier smb_pathname_preprocess(smb_request_t *sr, smb_pathname_t *pn) 861fe1c642dSBill Krier { 862fe1c642dSBill Krier char *p; 863fe1c642dSBill Krier 864fe1c642dSBill Krier /* treat empty path as "\\" */ 865fe1c642dSBill Krier if (strlen(pn->pn_path) == 0) { 866fe1c642dSBill Krier pn->pn_path = smb_pathname_strdup(sr, "\\"); 867fe1c642dSBill Krier return; 868fe1c642dSBill Krier } 869fe1c642dSBill Krier 870c13be35aSGordon Ross if (sr->session->dialect < NT_LM_0_12) 871fe1c642dSBill Krier smb_convert_wildcards(pn->pn_path); 872fe1c642dSBill Krier 873fe1c642dSBill Krier /* treat '/' as '\\' */ 874fe1c642dSBill Krier (void) strsubst(pn->pn_path, '/', '\\'); 875fe1c642dSBill Krier 876fe1c642dSBill Krier (void) strcanon(pn->pn_path, "\\"); 877fe1c642dSBill Krier 878fe1c642dSBill Krier /* remove trailing '\\' */ 879fe1c642dSBill Krier p = pn->pn_path + strlen(pn->pn_path) - 1; 880fe1c642dSBill Krier if ((p != pn->pn_path) && (*p == '\\')) 881fe1c642dSBill Krier *p = '\0'; 8829fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 8839fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_pathname_preprocess_quota(sr, pn); 8849fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_pathname_preprocess_adminshare(sr, pn); 8859fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 8869fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 8879fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* 8889fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * smb_pathname_preprocess_quota 8899fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * 8909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * There is a special file required by windows so that the quota 8919fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * tab will be displayed by windows clients. This is created in 8929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * a special directory, $EXTEND, at the root of the shared file 8939fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * system. To hide this directory prepend a '.' (dot). 8949fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States */ 8959fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void 8969fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_pathname_preprocess_quota(smb_request_t *sr, smb_pathname_t *pn) 8979fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 8989fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States char *name = "$EXTEND"; 8999fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States char *new_name = ".$EXTEND"; 9009fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States char *p, *slash; 9019fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States int len; 9029fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 9039fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (!smb_node_is_vfsroot(sr->tid_tree->t_snode)) 9049fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return; 9059fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 9069fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States p = pn->pn_path; 9079fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 9089fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* ignore any initial "\\" */ 9099fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States p += strspn(p, "\\"); 9109fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (smb_strcasecmp(p, name, strlen(name)) != 0) 9119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return; 9129fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 9139fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States p += strlen(name); 9149fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if ((*p != ':') && (*p != '\\') && (*p != '\0')) 9159fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return; 9169fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 9179fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States slash = (pn->pn_path[0] == '\\') ? "\\" : ""; 9189fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States len = strlen(pn->pn_path) + 2; 9199fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States pn->pn_path = smb_srm_alloc(sr, len); 9209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (void) snprintf(pn->pn_path, len, "%s%s%s", slash, new_name, p); 9219fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (void) smb_strupr(pn->pn_path); 9229fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 9239fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 9249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* 9259fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * smb_pathname_preprocess_adminshare 9269fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * 9279fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Convert any path with share name "C$" or "c$" (Admin share) in to lower case. 9289fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States */ 9299fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void 9309fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_pathname_preprocess_adminshare(smb_request_t *sr, smb_pathname_t *pn) 9319fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 9329fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (strcasecmp(sr->tid_tree->t_sharename, "c$") == 0) 9339fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (void) smb_strlwr(pn->pn_path); 934fe1c642dSBill Krier } 935fe1c642dSBill Krier 936fe1c642dSBill Krier /* 937fe1c642dSBill Krier * smb_pathname_strdup 938fe1c642dSBill Krier * 939fe1c642dSBill Krier * Duplicate NULL terminated string s. 940fe1c642dSBill Krier * 941fe1c642dSBill Krier * The new string is allocated using request specific storage and will 942fe1c642dSBill Krier * be free'd when the sr is destroyed. 943fe1c642dSBill Krier */ 944fe1c642dSBill Krier static char * 945fe1c642dSBill Krier smb_pathname_strdup(smb_request_t *sr, const char *s) 946fe1c642dSBill Krier { 947fe1c642dSBill Krier char *s2; 948fe1c642dSBill Krier size_t n; 949fe1c642dSBill Krier 950fe1c642dSBill Krier n = strlen(s) + 1; 9519fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States s2 = smb_srm_zalloc(sr, n); 952fe1c642dSBill Krier (void) strlcpy(s2, s, n); 953fe1c642dSBill Krier return (s2); 954fe1c642dSBill Krier } 955fe1c642dSBill Krier 956fe1c642dSBill Krier /* 957fe1c642dSBill Krier * smb_pathname_strcat 958fe1c642dSBill Krier * 959fe1c642dSBill Krier * Reallocate NULL terminated string s1 to accommodate 960fe1c642dSBill Krier * concatenating NULL terminated string s2. 961fe1c642dSBill Krier * Append s2 and return resulting NULL terminated string. 962fe1c642dSBill Krier * 963fe1c642dSBill Krier * The string buffer is reallocated using request specific 964fe1c642dSBill Krier * storage and will be free'd when the sr is destroyed. 965fe1c642dSBill Krier */ 966fe1c642dSBill Krier static char * 967fe1c642dSBill Krier smb_pathname_strcat(smb_request_t *sr, char *s1, const char *s2) 968fe1c642dSBill Krier { 969fe1c642dSBill Krier size_t n; 970fe1c642dSBill Krier 971fe1c642dSBill Krier n = strlen(s1) + strlen(s2) + 1; 9729fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States s1 = smb_srm_rezalloc(sr, s1, n); 973fe1c642dSBill Krier (void) strlcat(s1, s2, n); 974fe1c642dSBill Krier return (s1); 975fe1c642dSBill Krier } 976fe1c642dSBill Krier 977fe1c642dSBill Krier /* 978fe1c642dSBill Krier * smb_pathname_validate 979fe1c642dSBill Krier * 980fe1c642dSBill Krier * Perform basic validation of pn: 981fe1c642dSBill Krier * - If first component of pn->path is ".." -> PATH_SYNTAX_BAD 982fe1c642dSBill Krier * - If there are wildcards in pn->pn_pname -> OBJECT_NAME_INVALID 983fe1c642dSBill Krier * - If fname is "." -> INVALID_OBJECT_NAME 984fe1c642dSBill Krier * 985fe1c642dSBill Krier * On unix .. at the root of a file system links to the root. Thus 986fe1c642dSBill Krier * an attempt to lookup "/../../.." will be the same as looking up "/" 987fe1c642dSBill Krier * CIFs clients expect the above to result in 988fe1c642dSBill Krier * NT_STATUS_OBJECT_PATH_SYNTAX_BAD. It is currently not possible 989fe1c642dSBill Krier * (and questionable if it's desirable) to deal with all cases 990fe1c642dSBill Krier * but paths beginning with \\.. are handled. 991fe1c642dSBill Krier * 992fe1c642dSBill Krier * Returns: B_TRUE if pn is valid, 993fe1c642dSBill Krier * otherwise returns B_FALSE and sets error status in sr. 994a90cf9f2SGordon Ross * 995a90cf9f2SGordon Ross * XXX: Get rid of smbsr_error calls for SMB2 996fe1c642dSBill Krier */ 997fe1c642dSBill Krier boolean_t 998fe1c642dSBill Krier smb_pathname_validate(smb_request_t *sr, smb_pathname_t *pn) 999fe1c642dSBill Krier { 1000fe1c642dSBill Krier char *path = pn->pn_path; 1001fe1c642dSBill Krier 1002fe1c642dSBill Krier /* ignore any initial "\\" */ 1003fe1c642dSBill Krier path += strspn(path, "\\"); 1004fe1c642dSBill Krier 1005fe1c642dSBill Krier /* If first component of path is ".." -> PATH_SYNTAX_BAD */ 1006fe1c642dSBill Krier if ((strcmp(path, "..") == 0) || (strncmp(path, "..\\", 3) == 0)) { 1007fe1c642dSBill Krier smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD, 1008fe1c642dSBill Krier ERRDOS, ERROR_BAD_PATHNAME); 1009fe1c642dSBill Krier return (B_FALSE); 1010fe1c642dSBill Krier } 1011fe1c642dSBill Krier 1012fe1c642dSBill Krier /* If there are wildcards in pn->pn_pname -> OBJECT_NAME_INVALID */ 1013fe1c642dSBill Krier if (pn->pn_pname && smb_contains_wildcards(pn->pn_pname)) { 1014fe1c642dSBill Krier smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, 1015fe1c642dSBill Krier ERRDOS, ERROR_INVALID_NAME); 1016fe1c642dSBill Krier return (B_FALSE); 1017fe1c642dSBill Krier } 1018fe1c642dSBill Krier 1019c5f48fa5SGordon Ross /* If fname is "." -> OBJECT_NAME_INVALID */ 1020fe1c642dSBill Krier if (pn->pn_fname && (strcmp(pn->pn_fname, ".") == 0)) { 1021fe1c642dSBill Krier smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, 1022c5f48fa5SGordon Ross ERRDOS, ERROR_INVALID_NAME); 1023fe1c642dSBill Krier return (B_FALSE); 1024fe1c642dSBill Krier } 1025fe1c642dSBill Krier 1026fe1c642dSBill Krier return (B_TRUE); 1027fe1c642dSBill Krier } 1028fe1c642dSBill Krier 1029fe1c642dSBill Krier /* 1030fe1c642dSBill Krier * smb_validate_dirname 1031fe1c642dSBill Krier * 1032fe1c642dSBill Krier * smb_pathname_validate() should have already been performed on pn. 1033fe1c642dSBill Krier * 1034fe1c642dSBill Krier * Very basic directory name validation: checks for colons in a path. 1035fe1c642dSBill Krier * Need to skip the drive prefix since it contains a colon. 1036fe1c642dSBill Krier * 1037fe1c642dSBill Krier * Returns: B_TRUE if the name is valid, 1038fe1c642dSBill Krier * otherwise returns B_FALSE and sets error status in sr. 1039fe1c642dSBill Krier */ 1040fe1c642dSBill Krier boolean_t 1041fe1c642dSBill Krier smb_validate_dirname(smb_request_t *sr, smb_pathname_t *pn) 1042fe1c642dSBill Krier { 1043fe1c642dSBill Krier char *name; 1044fe1c642dSBill Krier char *path = pn->pn_path; 1045fe1c642dSBill Krier 1046fe1c642dSBill Krier if ((name = path) != 0) { 1047fe1c642dSBill Krier name += strspn(name, "\\"); 1048fe1c642dSBill Krier 1049fe1c642dSBill Krier if (strchr(name, ':') != 0) { 1050fe1c642dSBill Krier smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY, 1051fe1c642dSBill Krier ERRDOS, ERROR_INVALID_NAME); 1052fe1c642dSBill Krier return (B_FALSE); 1053fe1c642dSBill Krier } 1054fe1c642dSBill Krier } 1055fe1c642dSBill Krier 1056fe1c642dSBill Krier return (B_TRUE); 1057fe1c642dSBill Krier } 1058fe1c642dSBill Krier 1059fe1c642dSBill Krier /* 1060fe1c642dSBill Krier * smb_validate_object_name 1061fe1c642dSBill Krier * 1062fe1c642dSBill Krier * smb_pathname_validate() should have already been pertformed on pn. 1063fe1c642dSBill Krier * 1064fe1c642dSBill Krier * Very basic file name validation. 1065fe1c642dSBill Krier * For filenames, we check for names of the form "AAAn:". Names that 1066fe1c642dSBill Krier * contain three characters, a single digit and a colon (:) are reserved 1067fe1c642dSBill Krier * as DOS device names, i.e. "COM1:". 1068fe1c642dSBill Krier * Stream name validation is handed off to smb_validate_stream_name 1069fe1c642dSBill Krier * 1070fe1c642dSBill Krier * Returns: B_TRUE if pn->pn_fname is valid, 1071fe1c642dSBill Krier * otherwise returns B_FALSE and sets error status in sr. 1072fe1c642dSBill Krier */ 1073fe1c642dSBill Krier boolean_t 1074fe1c642dSBill Krier smb_validate_object_name(smb_request_t *sr, smb_pathname_t *pn) 1075fe1c642dSBill Krier { 1076fe1c642dSBill Krier if (pn->pn_fname && 1077fe1c642dSBill Krier strlen(pn->pn_fname) == 5 && 1078fe1c642dSBill Krier smb_isdigit(pn->pn_fname[3]) && 1079fe1c642dSBill Krier pn->pn_fname[4] == ':') { 1080fe1c642dSBill Krier smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, 1081fe1c642dSBill Krier ERRDOS, ERROR_INVALID_NAME); 1082fe1c642dSBill Krier return (B_FALSE); 1083fe1c642dSBill Krier } 1084fe1c642dSBill Krier 1085fe1c642dSBill Krier if (pn->pn_sname) 1086fe1c642dSBill Krier return (smb_validate_stream_name(sr, pn)); 1087fe1c642dSBill Krier 1088fe1c642dSBill Krier return (B_TRUE); 1089fe1c642dSBill Krier } 1090fe1c642dSBill Krier 1091fe1c642dSBill Krier /* 1092fe1c642dSBill Krier * smb_stream_parse_name 1093fe1c642dSBill Krier * 1094fe1c642dSBill Krier * smb_stream_parse_name should only be called for a path that 1095fe1c642dSBill Krier * contains a valid named stream. Path validation should have 1096d082c877SGordon Ross * been performed before this function is called, typically by 1097d082c877SGordon Ross * calling smb_is_stream_name() just before this. 1098fe1c642dSBill Krier * 1099fe1c642dSBill Krier * Find the last component of path and split it into filename 1100fe1c642dSBill Krier * and stream name. 1101fe1c642dSBill Krier * 1102fe1c642dSBill Krier * On return the named stream type will be present. The stream 1103fe1c642dSBill Krier * type defaults to ":$DATA", if it has not been defined 1104d082c877SGordon Ross * For example, 'stream' contains :<sname>:$DATA 1105d082c877SGordon Ross * 1106d082c877SGordon Ross * Output args: filename, stream both MAXNAMELEN 1107fe1c642dSBill Krier */ 1108fe1c642dSBill Krier void 1109fe1c642dSBill Krier smb_stream_parse_name(char *path, char *filename, char *stream) 1110fe1c642dSBill Krier { 1111fe1c642dSBill Krier char *fname, *sname, *stype; 1112d082c877SGordon Ross size_t flen, slen; 1113fe1c642dSBill Krier 1114fe1c642dSBill Krier ASSERT(path); 1115fe1c642dSBill Krier ASSERT(filename); 1116fe1c642dSBill Krier ASSERT(stream); 1117fe1c642dSBill Krier 1118fe1c642dSBill Krier fname = strrchr(path, '\\'); 1119fe1c642dSBill Krier fname = (fname == NULL) ? path : fname + 1; 1120d082c877SGordon Ross sname = strchr(fname, ':'); 1121d082c877SGordon Ross /* Caller makes sure there is a ':' in path. */ 1122d082c877SGordon Ross VERIFY(sname != NULL); 1123d082c877SGordon Ross /* LINTED: possible ptrdiff_t overflow */ 1124d082c877SGordon Ross flen = sname - fname; 1125d082c877SGordon Ross slen = strlen(sname); 1126fe1c642dSBill Krier 1127d082c877SGordon Ross if (flen > (MAXNAMELEN-1)) 1128d082c877SGordon Ross flen = (MAXNAMELEN-1); 1129d082c877SGordon Ross (void) strncpy(filename, fname, flen); 1130d082c877SGordon Ross filename[flen] = '\0'; 1131fe1c642dSBill Krier 1132d082c877SGordon Ross if (slen > (MAXNAMELEN-1)) 1133d082c877SGordon Ross slen = (MAXNAMELEN-1); 1134d082c877SGordon Ross (void) strncpy(stream, sname, slen); 1135d082c877SGordon Ross stream[slen] = '\0'; 1136d082c877SGordon Ross 1137d082c877SGordon Ross /* Add a "stream type" if there isn't one. */ 1138fe1c642dSBill Krier stype = strchr(stream + 1, ':'); 1139fe1c642dSBill Krier if (stype == NULL) 1140fe1c642dSBill Krier (void) strlcat(stream, ":$DATA", MAXNAMELEN); 1141fe1c642dSBill Krier else 1142fe1c642dSBill Krier (void) smb_strupr(stype); 1143fe1c642dSBill Krier } 1144fe1c642dSBill Krier 1145fe1c642dSBill Krier /* 1146fe1c642dSBill Krier * smb_is_stream_name 1147fe1c642dSBill Krier * 1148fe1c642dSBill Krier * Determines if 'path' specifies a named stream. 1149fe1c642dSBill Krier * 1150fe1c642dSBill Krier * path is a NULL terminated string which could be a stream path. 1151fe1c642dSBill Krier * [pathname/]fname[:stream_name[:stream_type]] 1152fe1c642dSBill Krier * 1153fe1c642dSBill Krier * - If there is no colon in the path or it's the last char 1154fe1c642dSBill Krier * then it's not a stream name 1155fe1c642dSBill Krier * 1156fe1c642dSBill Krier * - '::' is a non-stream and is commonly used by Windows to designate 1157fe1c642dSBill Krier * the unamed stream in the form "::$DATA" 1158fe1c642dSBill Krier */ 1159fe1c642dSBill Krier boolean_t 1160fe1c642dSBill Krier smb_is_stream_name(char *path) 1161fe1c642dSBill Krier { 1162fe1c642dSBill Krier char *colonp; 1163fe1c642dSBill Krier 1164fe1c642dSBill Krier if (path == NULL) 1165fe1c642dSBill Krier return (B_FALSE); 1166fe1c642dSBill Krier 1167fe1c642dSBill Krier colonp = strchr(path, ':'); 1168fe1c642dSBill Krier if ((colonp == NULL) || (*(colonp+1) == '\0')) 1169fe1c642dSBill Krier return (B_FALSE); 1170fe1c642dSBill Krier 1171fe1c642dSBill Krier if (strstr(path, "::")) 1172fe1c642dSBill Krier return (B_FALSE); 1173fe1c642dSBill Krier 1174fe1c642dSBill Krier return (B_TRUE); 1175fe1c642dSBill Krier } 1176fe1c642dSBill Krier 1177fe1c642dSBill Krier /* 11788d94f651SGordon Ross * Is this stream node a "restricted" type? 11798d94f651SGordon Ross */ 11808d94f651SGordon Ross boolean_t 11818d94f651SGordon Ross smb_strname_restricted(char *strname) 11828d94f651SGordon Ross { 11838d94f651SGordon Ross char *stype; 11848d94f651SGordon Ross 11858d94f651SGordon Ross stype = strrchr(strname, ':'); 11868d94f651SGordon Ross if (stype == NULL) 11878d94f651SGordon Ross return (B_FALSE); 11888d94f651SGordon Ross 11898d94f651SGordon Ross /* 11908d94f651SGordon Ross * Only ":$CA" is restricted (for now). 11918d94f651SGordon Ross */ 11928d94f651SGordon Ross if (strcmp(stype, ":$CA") == 0) 11938d94f651SGordon Ross return (B_TRUE); 11948d94f651SGordon Ross 11958d94f651SGordon Ross return (B_FALSE); 11968d94f651SGordon Ross } 11978d94f651SGordon Ross 11988d94f651SGordon Ross /* 1199fe1c642dSBill Krier * smb_validate_stream_name 1200fe1c642dSBill Krier * 1201fe1c642dSBill Krier * B_FALSE will be returned, and the error status ser in the sr, if: 1202fe1c642dSBill Krier * - the path is not a stream name 1203fe1c642dSBill Krier * - a path is specified but the fname is ommitted. 1204fe1c642dSBill Krier * - the stream_type is specified but not valid. 1205fe1c642dSBill Krier * 1206fe1c642dSBill Krier * Note: the stream type is case-insensitive. 1207fe1c642dSBill Krier */ 1208fe1c642dSBill Krier boolean_t 1209fe1c642dSBill Krier smb_validate_stream_name(smb_request_t *sr, smb_pathname_t *pn) 1210fe1c642dSBill Krier { 1211fe1c642dSBill Krier static char *strmtype[] = { 12128d94f651SGordon Ross "$CA", 1213fe1c642dSBill Krier "$DATA", 1214fe1c642dSBill Krier "$INDEX_ALLOCATION" 1215fe1c642dSBill Krier }; 1216fe1c642dSBill Krier int i; 1217fe1c642dSBill Krier 1218fe1c642dSBill Krier ASSERT(pn); 1219fe1c642dSBill Krier ASSERT(pn->pn_sname); 1220fe1c642dSBill Krier 1221fe1c642dSBill Krier if ((!(pn->pn_sname)) || 1222fe1c642dSBill Krier ((pn->pn_pname) && !(pn->pn_fname))) { 1223fe1c642dSBill Krier smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, 1224fe1c642dSBill Krier ERRDOS, ERROR_INVALID_NAME); 1225fe1c642dSBill Krier return (B_FALSE); 1226fe1c642dSBill Krier } 1227fe1c642dSBill Krier 1228fe1c642dSBill Krier 1229fe1c642dSBill Krier if (pn->pn_stype != NULL) { 1230fe1c642dSBill Krier for (i = 0; i < sizeof (strmtype) / sizeof (strmtype[0]); ++i) { 1231fe1c642dSBill Krier if (strcasecmp(pn->pn_stype, strmtype[i]) == 0) 1232fe1c642dSBill Krier return (B_TRUE); 1233fe1c642dSBill Krier } 1234fe1c642dSBill Krier 1235fe1c642dSBill Krier smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, 1236fe1c642dSBill Krier ERRDOS, ERROR_INVALID_NAME); 1237fe1c642dSBill Krier return (B_FALSE); 1238fe1c642dSBill Krier } 1239fe1c642dSBill Krier 1240fe1c642dSBill Krier return (B_TRUE); 1241fe1c642dSBill Krier } 12429fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 12439fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* 12449fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * valid DFS I/O path: 12459fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * 12469fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * \server-or-domain\share 12479fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * \server-or-domain\share\path 12489fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * 12499fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * All the returned errors by this function needs to be 12509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * checked against Windows. 12519fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States */ 12529fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static int 12539fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_pathname_dfs_preprocess(smb_request_t *sr, char *path, size_t pathsz) 12549fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 12559fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_unc_t unc; 12569fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States char *linkpath; 12579fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States int rc; 12589fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 12599fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (sr->tid_tree == NULL) 12609fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return (0); 12619fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 12629fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if ((rc = smb_unc_init(path, &unc)) != 0) 12639fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return (rc); 12649fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 12659fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (smb_strcasecmp(unc.unc_share, sr->tid_tree->t_sharename, 0)) { 12669fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_unc_free(&unc); 12679fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return (EINVAL); 12689fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 12699fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 12709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States linkpath = unc.unc_path; 12719fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (void) snprintf(path, pathsz, "/%s", (linkpath) ? linkpath : ""); 12729fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 12739fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_unc_free(&unc); 12749fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return (0); 12759fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 1276