1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * SPDX-License-Identifier: curl AND ISC 22 * 23 ***************************************************************************/ 24 25#include "curl_setup.h" 26 27#if defined(USE_SSH) 28 29#include <curl/curl.h> 30#include "curl_memory.h" 31#include "curl_path.h" 32#include "escape.h" 33#include "memdebug.h" 34 35#define MAX_SSHPATH_LEN 100000 /* arbitrary */ 36 37/* figure out the path to work with in this particular request */ 38CURLcode Curl_getworkingpath(struct Curl_easy *data, 39 char *homedir, /* when SFTP is used */ 40 char **path) /* returns the allocated 41 real path to work with */ 42{ 43 char *working_path; 44 size_t working_path_len; 45 struct dynbuf npath; 46 CURLcode result = 47 Curl_urldecode(data->state.up.path, 0, &working_path, 48 &working_path_len, REJECT_ZERO); 49 if(result) 50 return result; 51 52 /* new path to switch to in case we need to */ 53 Curl_dyn_init(&npath, MAX_SSHPATH_LEN); 54 55 /* Check for /~/, indicating relative to the user's home directory */ 56 if((data->conn->handler->protocol & CURLPROTO_SCP) && 57 (working_path_len > 3) && (!memcmp(working_path, "/~/", 3))) { 58 /* It is referenced to the home directory, so strip the leading '/~/' */ 59 if(Curl_dyn_addn(&npath, &working_path[3], working_path_len - 3)) { 60 free(working_path); 61 return CURLE_OUT_OF_MEMORY; 62 } 63 } 64 else if((data->conn->handler->protocol & CURLPROTO_SFTP) && 65 (!strcmp("/~", working_path) || 66 ((working_path_len > 2) && !memcmp(working_path, "/~/", 3)))) { 67 if(Curl_dyn_add(&npath, homedir)) { 68 free(working_path); 69 return CURLE_OUT_OF_MEMORY; 70 } 71 if(working_path_len > 2) { 72 size_t len; 73 const char *p; 74 int copyfrom = 3; 75 /* Copy a separating '/' if homedir does not end with one */ 76 len = Curl_dyn_len(&npath); 77 p = Curl_dyn_ptr(&npath); 78 if(len && (p[len-1] != '/')) 79 copyfrom = 2; 80 81 if(Curl_dyn_addn(&npath, 82 &working_path[copyfrom], working_path_len - copyfrom)) { 83 free(working_path); 84 return CURLE_OUT_OF_MEMORY; 85 } 86 } 87 } 88 89 if(Curl_dyn_len(&npath)) { 90 free(working_path); 91 92 /* store the pointer for the caller to receive */ 93 *path = Curl_dyn_ptr(&npath); 94 } 95 else 96 *path = working_path; 97 98 return CURLE_OK; 99} 100 101/* The get_pathname() function is being borrowed from OpenSSH sftp.c 102 version 4.6p1. */ 103/* 104 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> 105 * 106 * Permission to use, copy, modify, and distribute this software for any 107 * purpose with or without fee is hereby granted, provided that the above 108 * copyright notice and this permission notice appear in all copies. 109 * 110 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 111 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 112 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 113 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 114 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 115 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 116 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 117 */ 118CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir) 119{ 120 const char *cp = *cpp, *end; 121 char quot; 122 unsigned int i, j; 123 size_t fullPathLength, pathLength; 124 bool relativePath = false; 125 static const char WHITESPACE[] = " \t\r\n"; 126 127 DEBUGASSERT(homedir); 128 if(!*cp || !homedir) { 129 *cpp = NULL; 130 *path = NULL; 131 return CURLE_QUOTE_ERROR; 132 } 133 /* Ignore leading whitespace */ 134 cp += strspn(cp, WHITESPACE); 135 /* Allocate enough space for home directory and filename + separator */ 136 fullPathLength = strlen(cp) + strlen(homedir) + 2; 137 *path = malloc(fullPathLength); 138 if(!*path) 139 return CURLE_OUT_OF_MEMORY; 140 141 /* Check for quoted filenames */ 142 if(*cp == '\"' || *cp == '\'') { 143 quot = *cp++; 144 145 /* Search for terminating quote, unescape some chars */ 146 for(i = j = 0; i <= strlen(cp); i++) { 147 if(cp[i] == quot) { /* Found quote */ 148 i++; 149 (*path)[j] = '\0'; 150 break; 151 } 152 if(cp[i] == '\0') { /* End of string */ 153 goto fail; 154 } 155 if(cp[i] == '\\') { /* Escaped characters */ 156 i++; 157 if(cp[i] != '\'' && cp[i] != '\"' && 158 cp[i] != '\\') { 159 goto fail; 160 } 161 } 162 (*path)[j++] = cp[i]; 163 } 164 165 if(j == 0) { 166 goto fail; 167 } 168 *cpp = cp + i + strspn(cp + i, WHITESPACE); 169 } 170 else { 171 /* Read to end of filename - either to whitespace or terminator */ 172 end = strpbrk(cp, WHITESPACE); 173 if(!end) 174 end = strchr(cp, '\0'); 175 /* return pointer to second parameter if it exists */ 176 *cpp = end + strspn(end, WHITESPACE); 177 pathLength = 0; 178 relativePath = (cp[0] == '/' && cp[1] == '~' && cp[2] == '/'); 179 /* Handling for relative path - prepend home directory */ 180 if(relativePath) { 181 strcpy(*path, homedir); 182 pathLength = strlen(homedir); 183 (*path)[pathLength++] = '/'; 184 (*path)[pathLength] = '\0'; 185 cp += 3; 186 } 187 /* Copy path name up until first "whitespace" */ 188 memcpy(&(*path)[pathLength], cp, (int)(end - cp)); 189 pathLength += (int)(end - cp); 190 (*path)[pathLength] = '\0'; 191 } 192 return CURLE_OK; 193 194fail: 195 Curl_safefree(*path); 196 return CURLE_QUOTE_ERROR; 197} 198 199#endif /* if SSH is used */ 200