113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl AND ISC 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci 2513498266Sopenharmony_ci#include "curl_setup.h" 2613498266Sopenharmony_ci 2713498266Sopenharmony_ci#if defined(USE_SSH) 2813498266Sopenharmony_ci 2913498266Sopenharmony_ci#include <curl/curl.h> 3013498266Sopenharmony_ci#include "curl_memory.h" 3113498266Sopenharmony_ci#include "curl_path.h" 3213498266Sopenharmony_ci#include "escape.h" 3313498266Sopenharmony_ci#include "memdebug.h" 3413498266Sopenharmony_ci 3513498266Sopenharmony_ci#define MAX_SSHPATH_LEN 100000 /* arbitrary */ 3613498266Sopenharmony_ci 3713498266Sopenharmony_ci/* figure out the path to work with in this particular request */ 3813498266Sopenharmony_ciCURLcode Curl_getworkingpath(struct Curl_easy *data, 3913498266Sopenharmony_ci char *homedir, /* when SFTP is used */ 4013498266Sopenharmony_ci char **path) /* returns the allocated 4113498266Sopenharmony_ci real path to work with */ 4213498266Sopenharmony_ci{ 4313498266Sopenharmony_ci char *working_path; 4413498266Sopenharmony_ci size_t working_path_len; 4513498266Sopenharmony_ci struct dynbuf npath; 4613498266Sopenharmony_ci CURLcode result = 4713498266Sopenharmony_ci Curl_urldecode(data->state.up.path, 0, &working_path, 4813498266Sopenharmony_ci &working_path_len, REJECT_ZERO); 4913498266Sopenharmony_ci if(result) 5013498266Sopenharmony_ci return result; 5113498266Sopenharmony_ci 5213498266Sopenharmony_ci /* new path to switch to in case we need to */ 5313498266Sopenharmony_ci Curl_dyn_init(&npath, MAX_SSHPATH_LEN); 5413498266Sopenharmony_ci 5513498266Sopenharmony_ci /* Check for /~/, indicating relative to the user's home directory */ 5613498266Sopenharmony_ci if((data->conn->handler->protocol & CURLPROTO_SCP) && 5713498266Sopenharmony_ci (working_path_len > 3) && (!memcmp(working_path, "/~/", 3))) { 5813498266Sopenharmony_ci /* It is referenced to the home directory, so strip the leading '/~/' */ 5913498266Sopenharmony_ci if(Curl_dyn_addn(&npath, &working_path[3], working_path_len - 3)) { 6013498266Sopenharmony_ci free(working_path); 6113498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 6213498266Sopenharmony_ci } 6313498266Sopenharmony_ci } 6413498266Sopenharmony_ci else if((data->conn->handler->protocol & CURLPROTO_SFTP) && 6513498266Sopenharmony_ci (!strcmp("/~", working_path) || 6613498266Sopenharmony_ci ((working_path_len > 2) && !memcmp(working_path, "/~/", 3)))) { 6713498266Sopenharmony_ci if(Curl_dyn_add(&npath, homedir)) { 6813498266Sopenharmony_ci free(working_path); 6913498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 7013498266Sopenharmony_ci } 7113498266Sopenharmony_ci if(working_path_len > 2) { 7213498266Sopenharmony_ci size_t len; 7313498266Sopenharmony_ci const char *p; 7413498266Sopenharmony_ci int copyfrom = 3; 7513498266Sopenharmony_ci /* Copy a separating '/' if homedir does not end with one */ 7613498266Sopenharmony_ci len = Curl_dyn_len(&npath); 7713498266Sopenharmony_ci p = Curl_dyn_ptr(&npath); 7813498266Sopenharmony_ci if(len && (p[len-1] != '/')) 7913498266Sopenharmony_ci copyfrom = 2; 8013498266Sopenharmony_ci 8113498266Sopenharmony_ci if(Curl_dyn_addn(&npath, 8213498266Sopenharmony_ci &working_path[copyfrom], working_path_len - copyfrom)) { 8313498266Sopenharmony_ci free(working_path); 8413498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 8513498266Sopenharmony_ci } 8613498266Sopenharmony_ci } 8713498266Sopenharmony_ci } 8813498266Sopenharmony_ci 8913498266Sopenharmony_ci if(Curl_dyn_len(&npath)) { 9013498266Sopenharmony_ci free(working_path); 9113498266Sopenharmony_ci 9213498266Sopenharmony_ci /* store the pointer for the caller to receive */ 9313498266Sopenharmony_ci *path = Curl_dyn_ptr(&npath); 9413498266Sopenharmony_ci } 9513498266Sopenharmony_ci else 9613498266Sopenharmony_ci *path = working_path; 9713498266Sopenharmony_ci 9813498266Sopenharmony_ci return CURLE_OK; 9913498266Sopenharmony_ci} 10013498266Sopenharmony_ci 10113498266Sopenharmony_ci/* The get_pathname() function is being borrowed from OpenSSH sftp.c 10213498266Sopenharmony_ci version 4.6p1. */ 10313498266Sopenharmony_ci/* 10413498266Sopenharmony_ci * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> 10513498266Sopenharmony_ci * 10613498266Sopenharmony_ci * Permission to use, copy, modify, and distribute this software for any 10713498266Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 10813498266Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 10913498266Sopenharmony_ci * 11013498266Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11113498266Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11213498266Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11313498266Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11413498266Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 11513498266Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 11613498266Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 11713498266Sopenharmony_ci */ 11813498266Sopenharmony_ciCURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir) 11913498266Sopenharmony_ci{ 12013498266Sopenharmony_ci const char *cp = *cpp, *end; 12113498266Sopenharmony_ci char quot; 12213498266Sopenharmony_ci unsigned int i, j; 12313498266Sopenharmony_ci size_t fullPathLength, pathLength; 12413498266Sopenharmony_ci bool relativePath = false; 12513498266Sopenharmony_ci static const char WHITESPACE[] = " \t\r\n"; 12613498266Sopenharmony_ci 12713498266Sopenharmony_ci DEBUGASSERT(homedir); 12813498266Sopenharmony_ci if(!*cp || !homedir) { 12913498266Sopenharmony_ci *cpp = NULL; 13013498266Sopenharmony_ci *path = NULL; 13113498266Sopenharmony_ci return CURLE_QUOTE_ERROR; 13213498266Sopenharmony_ci } 13313498266Sopenharmony_ci /* Ignore leading whitespace */ 13413498266Sopenharmony_ci cp += strspn(cp, WHITESPACE); 13513498266Sopenharmony_ci /* Allocate enough space for home directory and filename + separator */ 13613498266Sopenharmony_ci fullPathLength = strlen(cp) + strlen(homedir) + 2; 13713498266Sopenharmony_ci *path = malloc(fullPathLength); 13813498266Sopenharmony_ci if(!*path) 13913498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 14013498266Sopenharmony_ci 14113498266Sopenharmony_ci /* Check for quoted filenames */ 14213498266Sopenharmony_ci if(*cp == '\"' || *cp == '\'') { 14313498266Sopenharmony_ci quot = *cp++; 14413498266Sopenharmony_ci 14513498266Sopenharmony_ci /* Search for terminating quote, unescape some chars */ 14613498266Sopenharmony_ci for(i = j = 0; i <= strlen(cp); i++) { 14713498266Sopenharmony_ci if(cp[i] == quot) { /* Found quote */ 14813498266Sopenharmony_ci i++; 14913498266Sopenharmony_ci (*path)[j] = '\0'; 15013498266Sopenharmony_ci break; 15113498266Sopenharmony_ci } 15213498266Sopenharmony_ci if(cp[i] == '\0') { /* End of string */ 15313498266Sopenharmony_ci goto fail; 15413498266Sopenharmony_ci } 15513498266Sopenharmony_ci if(cp[i] == '\\') { /* Escaped characters */ 15613498266Sopenharmony_ci i++; 15713498266Sopenharmony_ci if(cp[i] != '\'' && cp[i] != '\"' && 15813498266Sopenharmony_ci cp[i] != '\\') { 15913498266Sopenharmony_ci goto fail; 16013498266Sopenharmony_ci } 16113498266Sopenharmony_ci } 16213498266Sopenharmony_ci (*path)[j++] = cp[i]; 16313498266Sopenharmony_ci } 16413498266Sopenharmony_ci 16513498266Sopenharmony_ci if(j == 0) { 16613498266Sopenharmony_ci goto fail; 16713498266Sopenharmony_ci } 16813498266Sopenharmony_ci *cpp = cp + i + strspn(cp + i, WHITESPACE); 16913498266Sopenharmony_ci } 17013498266Sopenharmony_ci else { 17113498266Sopenharmony_ci /* Read to end of filename - either to whitespace or terminator */ 17213498266Sopenharmony_ci end = strpbrk(cp, WHITESPACE); 17313498266Sopenharmony_ci if(!end) 17413498266Sopenharmony_ci end = strchr(cp, '\0'); 17513498266Sopenharmony_ci /* return pointer to second parameter if it exists */ 17613498266Sopenharmony_ci *cpp = end + strspn(end, WHITESPACE); 17713498266Sopenharmony_ci pathLength = 0; 17813498266Sopenharmony_ci relativePath = (cp[0] == '/' && cp[1] == '~' && cp[2] == '/'); 17913498266Sopenharmony_ci /* Handling for relative path - prepend home directory */ 18013498266Sopenharmony_ci if(relativePath) { 18113498266Sopenharmony_ci strcpy(*path, homedir); 18213498266Sopenharmony_ci pathLength = strlen(homedir); 18313498266Sopenharmony_ci (*path)[pathLength++] = '/'; 18413498266Sopenharmony_ci (*path)[pathLength] = '\0'; 18513498266Sopenharmony_ci cp += 3; 18613498266Sopenharmony_ci } 18713498266Sopenharmony_ci /* Copy path name up until first "whitespace" */ 18813498266Sopenharmony_ci memcpy(&(*path)[pathLength], cp, (int)(end - cp)); 18913498266Sopenharmony_ci pathLength += (int)(end - cp); 19013498266Sopenharmony_ci (*path)[pathLength] = '\0'; 19113498266Sopenharmony_ci } 19213498266Sopenharmony_ci return CURLE_OK; 19313498266Sopenharmony_ci 19413498266Sopenharmony_cifail: 19513498266Sopenharmony_ci Curl_safefree(*path); 19613498266Sopenharmony_ci return CURLE_QUOTE_ERROR; 19713498266Sopenharmony_ci} 19813498266Sopenharmony_ci 19913498266Sopenharmony_ci#endif /* if SSH is used */ 200