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