curl_path.c (6433B)
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_path.h" 30 #include <curl/curl.h> 31 #include "../curl_memory.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 */ 38 CURLcode 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 curlx_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(curlx_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(curlx_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 = curlx_dyn_len(&npath); 77 p = curlx_dyn_ptr(&npath); 78 if(len && (p[len-1] != '/')) 79 copyfrom = 2; 80 81 if(curlx_dyn_addn(&npath, &working_path[copyfrom], 82 working_path_len - copyfrom)) { 83 free(working_path); 84 return CURLE_OUT_OF_MEMORY; 85 } 86 } 87 else { 88 if(curlx_dyn_add(&npath, "/")) { 89 free(working_path); 90 return CURLE_OUT_OF_MEMORY; 91 } 92 } 93 } 94 95 if(curlx_dyn_len(&npath)) { 96 free(working_path); 97 98 /* store the pointer for the caller to receive */ 99 *path = curlx_dyn_ptr(&npath); 100 } 101 else 102 *path = working_path; 103 104 return CURLE_OK; 105 } 106 107 /* The original get_pathname() function came from OpenSSH sftp.c version 108 4.6p1. */ 109 /* 110 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> 111 * 112 * Permission to use, copy, modify, and distribute this software for any 113 * purpose with or without fee is hereby granted, provided that the above 114 * copyright notice and this permission notice appear in all copies. 115 * 116 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 117 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 118 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 119 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 120 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 121 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 122 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 123 */ 124 125 #define MAX_PATHLENGTH 65535 /* arbitrary long */ 126 127 CURLcode Curl_get_pathname(const char **cpp, char **path, const char *homedir) 128 { 129 const char *cp = *cpp, *end; 130 char quot; 131 unsigned int i; 132 static const char WHITESPACE[] = " \t\r\n"; 133 struct dynbuf out; 134 CURLcode result; 135 136 DEBUGASSERT(homedir); 137 *path = NULL; 138 *cpp = NULL; 139 if(!*cp || !homedir) 140 return CURLE_QUOTE_ERROR; 141 142 curlx_dyn_init(&out, MAX_PATHLENGTH); 143 144 /* Ignore leading whitespace */ 145 cp += strspn(cp, WHITESPACE); 146 147 /* Check for quoted filenames */ 148 if(*cp == '\"' || *cp == '\'') { 149 quot = *cp++; 150 151 /* Search for terminating quote, unescape some chars */ 152 for(i = 0; i <= strlen(cp); i++) { 153 if(cp[i] == quot) { /* Found quote */ 154 i++; 155 break; 156 } 157 if(cp[i] == '\0') { /* End of string */ 158 goto fail; 159 } 160 if(cp[i] == '\\') { /* Escaped characters */ 161 i++; 162 if(cp[i] != '\'' && cp[i] != '\"' && 163 cp[i] != '\\') { 164 goto fail; 165 } 166 } 167 result = curlx_dyn_addn(&out, &cp[i], 1); 168 if(result) 169 return result; 170 } 171 172 if(!curlx_dyn_len(&out)) 173 goto fail; 174 175 /* return pointer to second parameter if it exists */ 176 *cpp = &cp[i] + strspn(&cp[i], WHITESPACE); 177 } 178 else { 179 /* Read to end of filename - either to whitespace or terminator */ 180 end = strpbrk(cp, WHITESPACE); 181 if(!end) 182 end = strchr(cp, '\0'); 183 184 /* return pointer to second parameter if it exists */ 185 *cpp = end + strspn(end, WHITESPACE); 186 187 /* Handling for relative path - prepend home directory */ 188 if(cp[0] == '/' && cp[1] == '~' && cp[2] == '/') { 189 result = curlx_dyn_add(&out, homedir); 190 if(!result) 191 result = curlx_dyn_addn(&out, "/", 1); 192 if(result) 193 return result; 194 cp += 3; 195 } 196 /* Copy path name up until first "whitespace" */ 197 result = curlx_dyn_addn(&out, cp, (end - cp)); 198 if(result) 199 return result; 200 } 201 *path = curlx_dyn_ptr(&out); 202 return CURLE_OK; 203 204 fail: 205 curlx_dyn_free(&out); 206 return CURLE_QUOTE_ERROR; 207 } 208 209 #endif /* if SSH is used */