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) Red Hat, Inc.
9*6236dae4SAndroid Build Coastguard Worker *
10*6236dae4SAndroid Build Coastguard Worker * Authors: Nikos Mavrogiannopoulos, Tomas Mraz, Stanislav Zidek,
11*6236dae4SAndroid Build Coastguard Worker * Robert Kolcun, Andreas Schneider
12*6236dae4SAndroid Build Coastguard Worker *
13*6236dae4SAndroid Build Coastguard Worker * This software is licensed as described in the file COPYING, which
14*6236dae4SAndroid Build Coastguard Worker * you should have received as part of this distribution. The terms
15*6236dae4SAndroid Build Coastguard Worker * are also available at https://curl.se/docs/copyright.html.
16*6236dae4SAndroid Build Coastguard Worker *
17*6236dae4SAndroid Build Coastguard Worker * You may opt to use, copy, modify, merge, publish, distribute and/or sell
18*6236dae4SAndroid Build Coastguard Worker * copies of the Software, and permit persons to whom the Software is
19*6236dae4SAndroid Build Coastguard Worker * furnished to do so, under the terms of the COPYING file.
20*6236dae4SAndroid Build Coastguard Worker *
21*6236dae4SAndroid Build Coastguard Worker * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
22*6236dae4SAndroid Build Coastguard Worker * KIND, either express or implied.
23*6236dae4SAndroid Build Coastguard Worker *
24*6236dae4SAndroid Build Coastguard Worker * SPDX-License-Identifier: curl
25*6236dae4SAndroid Build Coastguard Worker *
26*6236dae4SAndroid Build Coastguard Worker ***************************************************************************/
27*6236dae4SAndroid Build Coastguard Worker
28*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
29*6236dae4SAndroid Build Coastguard Worker
30*6236dae4SAndroid Build Coastguard Worker #ifdef USE_LIBSSH
31*6236dae4SAndroid Build Coastguard Worker
32*6236dae4SAndroid Build Coastguard Worker #include <limits.h>
33*6236dae4SAndroid Build Coastguard Worker
34*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_NETINET_IN_H
35*6236dae4SAndroid Build Coastguard Worker #include <netinet/in.h>
36*6236dae4SAndroid Build Coastguard Worker #endif
37*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_ARPA_INET_H
38*6236dae4SAndroid Build Coastguard Worker #include <arpa/inet.h>
39*6236dae4SAndroid Build Coastguard Worker #endif
40*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_NETDB_H
41*6236dae4SAndroid Build Coastguard Worker #include <netdb.h>
42*6236dae4SAndroid Build Coastguard Worker #endif
43*6236dae4SAndroid Build Coastguard Worker #ifdef __VMS
44*6236dae4SAndroid Build Coastguard Worker #include <in.h>
45*6236dae4SAndroid Build Coastguard Worker #include <inet.h>
46*6236dae4SAndroid Build Coastguard Worker #endif
47*6236dae4SAndroid Build Coastguard Worker
48*6236dae4SAndroid Build Coastguard Worker #include <curl/curl.h>
49*6236dae4SAndroid Build Coastguard Worker #include "urldata.h"
50*6236dae4SAndroid Build Coastguard Worker #include "sendf.h"
51*6236dae4SAndroid Build Coastguard Worker #include "hostip.h"
52*6236dae4SAndroid Build Coastguard Worker #include "progress.h"
53*6236dae4SAndroid Build Coastguard Worker #include "transfer.h"
54*6236dae4SAndroid Build Coastguard Worker #include "escape.h"
55*6236dae4SAndroid Build Coastguard Worker #include "http.h" /* for HTTP proxy tunnel stuff */
56*6236dae4SAndroid Build Coastguard Worker #include "ssh.h"
57*6236dae4SAndroid Build Coastguard Worker #include "url.h"
58*6236dae4SAndroid Build Coastguard Worker #include "speedcheck.h"
59*6236dae4SAndroid Build Coastguard Worker #include "getinfo.h"
60*6236dae4SAndroid Build Coastguard Worker #include "strdup.h"
61*6236dae4SAndroid Build Coastguard Worker #include "strcase.h"
62*6236dae4SAndroid Build Coastguard Worker #include "vtls/vtls.h"
63*6236dae4SAndroid Build Coastguard Worker #include "cfilters.h"
64*6236dae4SAndroid Build Coastguard Worker #include "connect.h"
65*6236dae4SAndroid Build Coastguard Worker #include "inet_ntop.h"
66*6236dae4SAndroid Build Coastguard Worker #include "parsedate.h" /* for the week day and month names */
67*6236dae4SAndroid Build Coastguard Worker #include "sockaddr.h" /* required for Curl_sockaddr_storage */
68*6236dae4SAndroid Build Coastguard Worker #include "strtoofft.h"
69*6236dae4SAndroid Build Coastguard Worker #include "multiif.h"
70*6236dae4SAndroid Build Coastguard Worker #include "select.h"
71*6236dae4SAndroid Build Coastguard Worker #include "warnless.h"
72*6236dae4SAndroid Build Coastguard Worker #include "curl_path.h"
73*6236dae4SAndroid Build Coastguard Worker
74*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_SYS_STAT_H
75*6236dae4SAndroid Build Coastguard Worker #include <sys/stat.h>
76*6236dae4SAndroid Build Coastguard Worker #endif
77*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_UNISTD_H
78*6236dae4SAndroid Build Coastguard Worker #include <unistd.h>
79*6236dae4SAndroid Build Coastguard Worker #endif
80*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_FCNTL_H
81*6236dae4SAndroid Build Coastguard Worker #include <fcntl.h>
82*6236dae4SAndroid Build Coastguard Worker #endif
83*6236dae4SAndroid Build Coastguard Worker
84*6236dae4SAndroid Build Coastguard Worker /* The last 3 #include files should be in this order */
85*6236dae4SAndroid Build Coastguard Worker #include "curl_printf.h"
86*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
87*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
88*6236dae4SAndroid Build Coastguard Worker
89*6236dae4SAndroid Build Coastguard Worker /* A recent macro provided by libssh. Or make our own. */
90*6236dae4SAndroid Build Coastguard Worker #ifndef SSH_STRING_FREE_CHAR
91*6236dae4SAndroid Build Coastguard Worker #define SSH_STRING_FREE_CHAR(x) \
92*6236dae4SAndroid Build Coastguard Worker do { \
93*6236dae4SAndroid Build Coastguard Worker if(x) { \
94*6236dae4SAndroid Build Coastguard Worker ssh_string_free_char(x); \
95*6236dae4SAndroid Build Coastguard Worker x = NULL; \
96*6236dae4SAndroid Build Coastguard Worker } \
97*6236dae4SAndroid Build Coastguard Worker } while(0)
98*6236dae4SAndroid Build Coastguard Worker #endif
99*6236dae4SAndroid Build Coastguard Worker
100*6236dae4SAndroid Build Coastguard Worker /* These stat values may not be the same as the user's S_IFMT / S_IFLNK */
101*6236dae4SAndroid Build Coastguard Worker #ifndef SSH_S_IFMT
102*6236dae4SAndroid Build Coastguard Worker #define SSH_S_IFMT 00170000
103*6236dae4SAndroid Build Coastguard Worker #endif
104*6236dae4SAndroid Build Coastguard Worker #ifndef SSH_S_IFLNK
105*6236dae4SAndroid Build Coastguard Worker #define SSH_S_IFLNK 0120000
106*6236dae4SAndroid Build Coastguard Worker #endif
107*6236dae4SAndroid Build Coastguard Worker
108*6236dae4SAndroid Build Coastguard Worker /* Local functions: */
109*6236dae4SAndroid Build Coastguard Worker static CURLcode myssh_connect(struct Curl_easy *data, bool *done);
110*6236dae4SAndroid Build Coastguard Worker static CURLcode myssh_multi_statemach(struct Curl_easy *data,
111*6236dae4SAndroid Build Coastguard Worker bool *done);
112*6236dae4SAndroid Build Coastguard Worker static CURLcode myssh_do_it(struct Curl_easy *data, bool *done);
113*6236dae4SAndroid Build Coastguard Worker
114*6236dae4SAndroid Build Coastguard Worker static CURLcode scp_done(struct Curl_easy *data,
115*6236dae4SAndroid Build Coastguard Worker CURLcode, bool premature);
116*6236dae4SAndroid Build Coastguard Worker static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done);
117*6236dae4SAndroid Build Coastguard Worker static CURLcode scp_disconnect(struct Curl_easy *data,
118*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn,
119*6236dae4SAndroid Build Coastguard Worker bool dead_connection);
120*6236dae4SAndroid Build Coastguard Worker
121*6236dae4SAndroid Build Coastguard Worker static CURLcode sftp_done(struct Curl_easy *data,
122*6236dae4SAndroid Build Coastguard Worker CURLcode, bool premature);
123*6236dae4SAndroid Build Coastguard Worker static CURLcode sftp_doing(struct Curl_easy *data,
124*6236dae4SAndroid Build Coastguard Worker bool *dophase_done);
125*6236dae4SAndroid Build Coastguard Worker static CURLcode sftp_disconnect(struct Curl_easy *data,
126*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn,
127*6236dae4SAndroid Build Coastguard Worker bool dead);
128*6236dae4SAndroid Build Coastguard Worker static
129*6236dae4SAndroid Build Coastguard Worker CURLcode sftp_perform(struct Curl_easy *data,
130*6236dae4SAndroid Build Coastguard Worker bool *connected,
131*6236dae4SAndroid Build Coastguard Worker bool *dophase_done);
132*6236dae4SAndroid Build Coastguard Worker
133*6236dae4SAndroid Build Coastguard Worker static void sftp_quote(struct Curl_easy *data);
134*6236dae4SAndroid Build Coastguard Worker static void sftp_quote_stat(struct Curl_easy *data);
135*6236dae4SAndroid Build Coastguard Worker static int myssh_getsock(struct Curl_easy *data,
136*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn, curl_socket_t *sock);
137*6236dae4SAndroid Build Coastguard Worker static void myssh_block2waitfor(struct connectdata *conn, bool block);
138*6236dae4SAndroid Build Coastguard Worker
139*6236dae4SAndroid Build Coastguard Worker static CURLcode myssh_setup_connection(struct Curl_easy *data,
140*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn);
141*6236dae4SAndroid Build Coastguard Worker
142*6236dae4SAndroid Build Coastguard Worker /*
143*6236dae4SAndroid Build Coastguard Worker * SCP protocol handler.
144*6236dae4SAndroid Build Coastguard Worker */
145*6236dae4SAndroid Build Coastguard Worker
146*6236dae4SAndroid Build Coastguard Worker const struct Curl_handler Curl_handler_scp = {
147*6236dae4SAndroid Build Coastguard Worker "SCP", /* scheme */
148*6236dae4SAndroid Build Coastguard Worker myssh_setup_connection, /* setup_connection */
149*6236dae4SAndroid Build Coastguard Worker myssh_do_it, /* do_it */
150*6236dae4SAndroid Build Coastguard Worker scp_done, /* done */
151*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* do_more */
152*6236dae4SAndroid Build Coastguard Worker myssh_connect, /* connect_it */
153*6236dae4SAndroid Build Coastguard Worker myssh_multi_statemach, /* connecting */
154*6236dae4SAndroid Build Coastguard Worker scp_doing, /* doing */
155*6236dae4SAndroid Build Coastguard Worker myssh_getsock, /* proto_getsock */
156*6236dae4SAndroid Build Coastguard Worker myssh_getsock, /* doing_getsock */
157*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* domore_getsock */
158*6236dae4SAndroid Build Coastguard Worker myssh_getsock, /* perform_getsock */
159*6236dae4SAndroid Build Coastguard Worker scp_disconnect, /* disconnect */
160*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* write_resp */
161*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* write_resp_hd */
162*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* connection_check */
163*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* attach connection */
164*6236dae4SAndroid Build Coastguard Worker PORT_SSH, /* defport */
165*6236dae4SAndroid Build Coastguard Worker CURLPROTO_SCP, /* protocol */
166*6236dae4SAndroid Build Coastguard Worker CURLPROTO_SCP, /* family */
167*6236dae4SAndroid Build Coastguard Worker PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */
168*6236dae4SAndroid Build Coastguard Worker };
169*6236dae4SAndroid Build Coastguard Worker
170*6236dae4SAndroid Build Coastguard Worker /*
171*6236dae4SAndroid Build Coastguard Worker * SFTP protocol handler.
172*6236dae4SAndroid Build Coastguard Worker */
173*6236dae4SAndroid Build Coastguard Worker
174*6236dae4SAndroid Build Coastguard Worker const struct Curl_handler Curl_handler_sftp = {
175*6236dae4SAndroid Build Coastguard Worker "SFTP", /* scheme */
176*6236dae4SAndroid Build Coastguard Worker myssh_setup_connection, /* setup_connection */
177*6236dae4SAndroid Build Coastguard Worker myssh_do_it, /* do_it */
178*6236dae4SAndroid Build Coastguard Worker sftp_done, /* done */
179*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* do_more */
180*6236dae4SAndroid Build Coastguard Worker myssh_connect, /* connect_it */
181*6236dae4SAndroid Build Coastguard Worker myssh_multi_statemach, /* connecting */
182*6236dae4SAndroid Build Coastguard Worker sftp_doing, /* doing */
183*6236dae4SAndroid Build Coastguard Worker myssh_getsock, /* proto_getsock */
184*6236dae4SAndroid Build Coastguard Worker myssh_getsock, /* doing_getsock */
185*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* domore_getsock */
186*6236dae4SAndroid Build Coastguard Worker myssh_getsock, /* perform_getsock */
187*6236dae4SAndroid Build Coastguard Worker sftp_disconnect, /* disconnect */
188*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* write_resp */
189*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* write_resp_hd */
190*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* connection_check */
191*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* attach connection */
192*6236dae4SAndroid Build Coastguard Worker PORT_SSH, /* defport */
193*6236dae4SAndroid Build Coastguard Worker CURLPROTO_SFTP, /* protocol */
194*6236dae4SAndroid Build Coastguard Worker CURLPROTO_SFTP, /* family */
195*6236dae4SAndroid Build Coastguard Worker PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
196*6236dae4SAndroid Build Coastguard Worker | PROTOPT_NOURLQUERY /* flags */
197*6236dae4SAndroid Build Coastguard Worker };
198*6236dae4SAndroid Build Coastguard Worker
sftp_error_to_CURLE(int err)199*6236dae4SAndroid Build Coastguard Worker static CURLcode sftp_error_to_CURLE(int err)
200*6236dae4SAndroid Build Coastguard Worker {
201*6236dae4SAndroid Build Coastguard Worker switch(err) {
202*6236dae4SAndroid Build Coastguard Worker case SSH_FX_OK:
203*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
204*6236dae4SAndroid Build Coastguard Worker
205*6236dae4SAndroid Build Coastguard Worker case SSH_FX_NO_SUCH_FILE:
206*6236dae4SAndroid Build Coastguard Worker case SSH_FX_NO_SUCH_PATH:
207*6236dae4SAndroid Build Coastguard Worker return CURLE_REMOTE_FILE_NOT_FOUND;
208*6236dae4SAndroid Build Coastguard Worker
209*6236dae4SAndroid Build Coastguard Worker case SSH_FX_PERMISSION_DENIED:
210*6236dae4SAndroid Build Coastguard Worker case SSH_FX_WRITE_PROTECT:
211*6236dae4SAndroid Build Coastguard Worker return CURLE_REMOTE_ACCESS_DENIED;
212*6236dae4SAndroid Build Coastguard Worker
213*6236dae4SAndroid Build Coastguard Worker case SSH_FX_FILE_ALREADY_EXISTS:
214*6236dae4SAndroid Build Coastguard Worker return CURLE_REMOTE_FILE_EXISTS;
215*6236dae4SAndroid Build Coastguard Worker
216*6236dae4SAndroid Build Coastguard Worker default:
217*6236dae4SAndroid Build Coastguard Worker break;
218*6236dae4SAndroid Build Coastguard Worker }
219*6236dae4SAndroid Build Coastguard Worker
220*6236dae4SAndroid Build Coastguard Worker return CURLE_SSH;
221*6236dae4SAndroid Build Coastguard Worker }
222*6236dae4SAndroid Build Coastguard Worker
223*6236dae4SAndroid Build Coastguard Worker #ifndef DEBUGBUILD
224*6236dae4SAndroid Build Coastguard Worker #define state(x,y) mystate(x,y)
225*6236dae4SAndroid Build Coastguard Worker #else
226*6236dae4SAndroid Build Coastguard Worker #define state(x,y) mystate(x,y, __LINE__)
227*6236dae4SAndroid Build Coastguard Worker #endif
228*6236dae4SAndroid Build Coastguard Worker
229*6236dae4SAndroid Build Coastguard Worker /*
230*6236dae4SAndroid Build Coastguard Worker * SSH State machine related code
231*6236dae4SAndroid Build Coastguard Worker */
232*6236dae4SAndroid Build Coastguard Worker /* This is the ONLY way to change SSH state! */
mystate(struct Curl_easy * data,sshstate nowstate,int lineno)233*6236dae4SAndroid Build Coastguard Worker static void mystate(struct Curl_easy *data, sshstate nowstate
234*6236dae4SAndroid Build Coastguard Worker #ifdef DEBUGBUILD
235*6236dae4SAndroid Build Coastguard Worker , int lineno
236*6236dae4SAndroid Build Coastguard Worker #endif
237*6236dae4SAndroid Build Coastguard Worker )
238*6236dae4SAndroid Build Coastguard Worker {
239*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
240*6236dae4SAndroid Build Coastguard Worker struct ssh_conn *sshc = &conn->proto.sshc;
241*6236dae4SAndroid Build Coastguard Worker #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
242*6236dae4SAndroid Build Coastguard Worker /* for debug purposes */
243*6236dae4SAndroid Build Coastguard Worker static const char *const names[] = {
244*6236dae4SAndroid Build Coastguard Worker "SSH_STOP",
245*6236dae4SAndroid Build Coastguard Worker "SSH_INIT",
246*6236dae4SAndroid Build Coastguard Worker "SSH_S_STARTUP",
247*6236dae4SAndroid Build Coastguard Worker "SSH_HOSTKEY",
248*6236dae4SAndroid Build Coastguard Worker "SSH_AUTHLIST",
249*6236dae4SAndroid Build Coastguard Worker "SSH_AUTH_PKEY_INIT",
250*6236dae4SAndroid Build Coastguard Worker "SSH_AUTH_PKEY",
251*6236dae4SAndroid Build Coastguard Worker "SSH_AUTH_PASS_INIT",
252*6236dae4SAndroid Build Coastguard Worker "SSH_AUTH_PASS",
253*6236dae4SAndroid Build Coastguard Worker "SSH_AUTH_AGENT_INIT",
254*6236dae4SAndroid Build Coastguard Worker "SSH_AUTH_AGENT_LIST",
255*6236dae4SAndroid Build Coastguard Worker "SSH_AUTH_AGENT",
256*6236dae4SAndroid Build Coastguard Worker "SSH_AUTH_HOST_INIT",
257*6236dae4SAndroid Build Coastguard Worker "SSH_AUTH_HOST",
258*6236dae4SAndroid Build Coastguard Worker "SSH_AUTH_KEY_INIT",
259*6236dae4SAndroid Build Coastguard Worker "SSH_AUTH_KEY",
260*6236dae4SAndroid Build Coastguard Worker "SSH_AUTH_GSSAPI",
261*6236dae4SAndroid Build Coastguard Worker "SSH_AUTH_DONE",
262*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_INIT",
263*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_REALPATH",
264*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_QUOTE_INIT",
265*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_POSTQUOTE_INIT",
266*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_QUOTE",
267*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_NEXT_QUOTE",
268*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_QUOTE_STAT",
269*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_QUOTE_SETSTAT",
270*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_QUOTE_SYMLINK",
271*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_QUOTE_MKDIR",
272*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_QUOTE_RENAME",
273*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_QUOTE_RMDIR",
274*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_QUOTE_UNLINK",
275*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_QUOTE_STATVFS",
276*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_GETINFO",
277*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_FILETIME",
278*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_TRANS_INIT",
279*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_UPLOAD_INIT",
280*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_CREATE_DIRS_INIT",
281*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_CREATE_DIRS",
282*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_CREATE_DIRS_MKDIR",
283*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_READDIR_INIT",
284*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_READDIR",
285*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_READDIR_LINK",
286*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_READDIR_BOTTOM",
287*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_READDIR_DONE",
288*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_DOWNLOAD_INIT",
289*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_DOWNLOAD_STAT",
290*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_CLOSE",
291*6236dae4SAndroid Build Coastguard Worker "SSH_SFTP_SHUTDOWN",
292*6236dae4SAndroid Build Coastguard Worker "SSH_SCP_TRANS_INIT",
293*6236dae4SAndroid Build Coastguard Worker "SSH_SCP_UPLOAD_INIT",
294*6236dae4SAndroid Build Coastguard Worker "SSH_SCP_DOWNLOAD_INIT",
295*6236dae4SAndroid Build Coastguard Worker "SSH_SCP_DOWNLOAD",
296*6236dae4SAndroid Build Coastguard Worker "SSH_SCP_DONE",
297*6236dae4SAndroid Build Coastguard Worker "SSH_SCP_SEND_EOF",
298*6236dae4SAndroid Build Coastguard Worker "SSH_SCP_WAIT_EOF",
299*6236dae4SAndroid Build Coastguard Worker "SSH_SCP_WAIT_CLOSE",
300*6236dae4SAndroid Build Coastguard Worker "SSH_SCP_CHANNEL_FREE",
301*6236dae4SAndroid Build Coastguard Worker "SSH_SESSION_DISCONNECT",
302*6236dae4SAndroid Build Coastguard Worker "SSH_SESSION_FREE",
303*6236dae4SAndroid Build Coastguard Worker "QUIT"
304*6236dae4SAndroid Build Coastguard Worker };
305*6236dae4SAndroid Build Coastguard Worker
306*6236dae4SAndroid Build Coastguard Worker
307*6236dae4SAndroid Build Coastguard Worker if(sshc->state != nowstate) {
308*6236dae4SAndroid Build Coastguard Worker infof(data, "SSH %p state change from %s to %s (line %d)",
309*6236dae4SAndroid Build Coastguard Worker (void *) sshc, names[sshc->state], names[nowstate],
310*6236dae4SAndroid Build Coastguard Worker lineno);
311*6236dae4SAndroid Build Coastguard Worker }
312*6236dae4SAndroid Build Coastguard Worker #endif
313*6236dae4SAndroid Build Coastguard Worker
314*6236dae4SAndroid Build Coastguard Worker sshc->state = nowstate;
315*6236dae4SAndroid Build Coastguard Worker }
316*6236dae4SAndroid Build Coastguard Worker
317*6236dae4SAndroid Build Coastguard Worker /* Multiple options:
318*6236dae4SAndroid Build Coastguard Worker * 1. data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] is set with an MD5
319*6236dae4SAndroid Build Coastguard Worker * hash (90s style auth, not sure we should have it here)
320*6236dae4SAndroid Build Coastguard Worker * 2. data->set.ssh_keyfunc callback is set. Then we do trust on first
321*6236dae4SAndroid Build Coastguard Worker * use. We even save on knownhosts if CURLKHSTAT_FINE_ADD_TO_FILE
322*6236dae4SAndroid Build Coastguard Worker * is returned by it.
323*6236dae4SAndroid Build Coastguard Worker * 3. none of the above. We only accept if it is present on known hosts.
324*6236dae4SAndroid Build Coastguard Worker *
325*6236dae4SAndroid Build Coastguard Worker * Returns SSH_OK or SSH_ERROR.
326*6236dae4SAndroid Build Coastguard Worker */
myssh_is_known(struct Curl_easy * data)327*6236dae4SAndroid Build Coastguard Worker static int myssh_is_known(struct Curl_easy *data)
328*6236dae4SAndroid Build Coastguard Worker {
329*6236dae4SAndroid Build Coastguard Worker int rc;
330*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
331*6236dae4SAndroid Build Coastguard Worker struct ssh_conn *sshc = &conn->proto.sshc;
332*6236dae4SAndroid Build Coastguard Worker ssh_key pubkey;
333*6236dae4SAndroid Build Coastguard Worker size_t hlen;
334*6236dae4SAndroid Build Coastguard Worker unsigned char *hash = NULL;
335*6236dae4SAndroid Build Coastguard Worker char *found_base64 = NULL;
336*6236dae4SAndroid Build Coastguard Worker char *known_base64 = NULL;
337*6236dae4SAndroid Build Coastguard Worker int vstate;
338*6236dae4SAndroid Build Coastguard Worker enum curl_khmatch keymatch;
339*6236dae4SAndroid Build Coastguard Worker struct curl_khkey foundkey;
340*6236dae4SAndroid Build Coastguard Worker struct curl_khkey *knownkeyp = NULL;
341*6236dae4SAndroid Build Coastguard Worker curl_sshkeycallback func =
342*6236dae4SAndroid Build Coastguard Worker data->set.ssh_keyfunc;
343*6236dae4SAndroid Build Coastguard Worker
344*6236dae4SAndroid Build Coastguard Worker #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
345*6236dae4SAndroid Build Coastguard Worker struct ssh_knownhosts_entry *knownhostsentry = NULL;
346*6236dae4SAndroid Build Coastguard Worker struct curl_khkey knownkey;
347*6236dae4SAndroid Build Coastguard Worker #endif
348*6236dae4SAndroid Build Coastguard Worker
349*6236dae4SAndroid Build Coastguard Worker #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0)
350*6236dae4SAndroid Build Coastguard Worker rc = ssh_get_server_publickey(sshc->ssh_session, &pubkey);
351*6236dae4SAndroid Build Coastguard Worker #else
352*6236dae4SAndroid Build Coastguard Worker rc = ssh_get_publickey(sshc->ssh_session, &pubkey);
353*6236dae4SAndroid Build Coastguard Worker #endif
354*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_OK)
355*6236dae4SAndroid Build Coastguard Worker return rc;
356*6236dae4SAndroid Build Coastguard Worker
357*6236dae4SAndroid Build Coastguard Worker if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) {
358*6236dae4SAndroid Build Coastguard Worker int i;
359*6236dae4SAndroid Build Coastguard Worker char md5buffer[33];
360*6236dae4SAndroid Build Coastguard Worker const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
361*6236dae4SAndroid Build Coastguard Worker
362*6236dae4SAndroid Build Coastguard Worker rc = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_MD5,
363*6236dae4SAndroid Build Coastguard Worker &hash, &hlen);
364*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_OK || hlen != 16) {
365*6236dae4SAndroid Build Coastguard Worker failf(data,
366*6236dae4SAndroid Build Coastguard Worker "Denied establishing ssh session: md5 fingerprint not available");
367*6236dae4SAndroid Build Coastguard Worker goto cleanup;
368*6236dae4SAndroid Build Coastguard Worker }
369*6236dae4SAndroid Build Coastguard Worker
370*6236dae4SAndroid Build Coastguard Worker for(i = 0; i < 16; i++)
371*6236dae4SAndroid Build Coastguard Worker msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char)hash[i]);
372*6236dae4SAndroid Build Coastguard Worker
373*6236dae4SAndroid Build Coastguard Worker infof(data, "SSH MD5 fingerprint: %s", md5buffer);
374*6236dae4SAndroid Build Coastguard Worker
375*6236dae4SAndroid Build Coastguard Worker if(!strcasecompare(md5buffer, pubkey_md5)) {
376*6236dae4SAndroid Build Coastguard Worker failf(data,
377*6236dae4SAndroid Build Coastguard Worker "Denied establishing ssh session: mismatch md5 fingerprint. "
378*6236dae4SAndroid Build Coastguard Worker "Remote %s is not equal to %s", md5buffer, pubkey_md5);
379*6236dae4SAndroid Build Coastguard Worker rc = SSH_ERROR;
380*6236dae4SAndroid Build Coastguard Worker goto cleanup;
381*6236dae4SAndroid Build Coastguard Worker }
382*6236dae4SAndroid Build Coastguard Worker
383*6236dae4SAndroid Build Coastguard Worker rc = SSH_OK;
384*6236dae4SAndroid Build Coastguard Worker goto cleanup;
385*6236dae4SAndroid Build Coastguard Worker }
386*6236dae4SAndroid Build Coastguard Worker
387*6236dae4SAndroid Build Coastguard Worker if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
388*6236dae4SAndroid Build Coastguard Worker
389*6236dae4SAndroid Build Coastguard Worker #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
390*6236dae4SAndroid Build Coastguard Worker /* Get the known_key from the known hosts file */
391*6236dae4SAndroid Build Coastguard Worker vstate = ssh_session_get_known_hosts_entry(sshc->ssh_session,
392*6236dae4SAndroid Build Coastguard Worker &knownhostsentry);
393*6236dae4SAndroid Build Coastguard Worker
394*6236dae4SAndroid Build Coastguard Worker /* Case an entry was found in a known hosts file */
395*6236dae4SAndroid Build Coastguard Worker if(knownhostsentry) {
396*6236dae4SAndroid Build Coastguard Worker if(knownhostsentry->publickey) {
397*6236dae4SAndroid Build Coastguard Worker rc = ssh_pki_export_pubkey_base64(knownhostsentry->publickey,
398*6236dae4SAndroid Build Coastguard Worker &known_base64);
399*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_OK) {
400*6236dae4SAndroid Build Coastguard Worker goto cleanup;
401*6236dae4SAndroid Build Coastguard Worker }
402*6236dae4SAndroid Build Coastguard Worker knownkey.key = known_base64;
403*6236dae4SAndroid Build Coastguard Worker knownkey.len = strlen(known_base64);
404*6236dae4SAndroid Build Coastguard Worker
405*6236dae4SAndroid Build Coastguard Worker switch(ssh_key_type(knownhostsentry->publickey)) {
406*6236dae4SAndroid Build Coastguard Worker case SSH_KEYTYPE_RSA:
407*6236dae4SAndroid Build Coastguard Worker knownkey.keytype = CURLKHTYPE_RSA;
408*6236dae4SAndroid Build Coastguard Worker break;
409*6236dae4SAndroid Build Coastguard Worker case SSH_KEYTYPE_RSA1:
410*6236dae4SAndroid Build Coastguard Worker knownkey.keytype = CURLKHTYPE_RSA1;
411*6236dae4SAndroid Build Coastguard Worker break;
412*6236dae4SAndroid Build Coastguard Worker case SSH_KEYTYPE_ECDSA:
413*6236dae4SAndroid Build Coastguard Worker case SSH_KEYTYPE_ECDSA_P256:
414*6236dae4SAndroid Build Coastguard Worker case SSH_KEYTYPE_ECDSA_P384:
415*6236dae4SAndroid Build Coastguard Worker case SSH_KEYTYPE_ECDSA_P521:
416*6236dae4SAndroid Build Coastguard Worker knownkey.keytype = CURLKHTYPE_ECDSA;
417*6236dae4SAndroid Build Coastguard Worker break;
418*6236dae4SAndroid Build Coastguard Worker case SSH_KEYTYPE_ED25519:
419*6236dae4SAndroid Build Coastguard Worker knownkey.keytype = CURLKHTYPE_ED25519;
420*6236dae4SAndroid Build Coastguard Worker break;
421*6236dae4SAndroid Build Coastguard Worker case SSH_KEYTYPE_DSS:
422*6236dae4SAndroid Build Coastguard Worker knownkey.keytype = CURLKHTYPE_DSS;
423*6236dae4SAndroid Build Coastguard Worker break;
424*6236dae4SAndroid Build Coastguard Worker default:
425*6236dae4SAndroid Build Coastguard Worker rc = SSH_ERROR;
426*6236dae4SAndroid Build Coastguard Worker goto cleanup;
427*6236dae4SAndroid Build Coastguard Worker }
428*6236dae4SAndroid Build Coastguard Worker knownkeyp = &knownkey;
429*6236dae4SAndroid Build Coastguard Worker }
430*6236dae4SAndroid Build Coastguard Worker }
431*6236dae4SAndroid Build Coastguard Worker
432*6236dae4SAndroid Build Coastguard Worker switch(vstate) {
433*6236dae4SAndroid Build Coastguard Worker case SSH_KNOWN_HOSTS_OK:
434*6236dae4SAndroid Build Coastguard Worker keymatch = CURLKHMATCH_OK;
435*6236dae4SAndroid Build Coastguard Worker break;
436*6236dae4SAndroid Build Coastguard Worker case SSH_KNOWN_HOSTS_OTHER:
437*6236dae4SAndroid Build Coastguard Worker case SSH_KNOWN_HOSTS_NOT_FOUND:
438*6236dae4SAndroid Build Coastguard Worker case SSH_KNOWN_HOSTS_UNKNOWN:
439*6236dae4SAndroid Build Coastguard Worker case SSH_KNOWN_HOSTS_ERROR:
440*6236dae4SAndroid Build Coastguard Worker keymatch = CURLKHMATCH_MISSING;
441*6236dae4SAndroid Build Coastguard Worker break;
442*6236dae4SAndroid Build Coastguard Worker default:
443*6236dae4SAndroid Build Coastguard Worker keymatch = CURLKHMATCH_MISMATCH;
444*6236dae4SAndroid Build Coastguard Worker break;
445*6236dae4SAndroid Build Coastguard Worker }
446*6236dae4SAndroid Build Coastguard Worker
447*6236dae4SAndroid Build Coastguard Worker #else
448*6236dae4SAndroid Build Coastguard Worker vstate = ssh_is_server_known(sshc->ssh_session);
449*6236dae4SAndroid Build Coastguard Worker switch(vstate) {
450*6236dae4SAndroid Build Coastguard Worker case SSH_SERVER_KNOWN_OK:
451*6236dae4SAndroid Build Coastguard Worker keymatch = CURLKHMATCH_OK;
452*6236dae4SAndroid Build Coastguard Worker break;
453*6236dae4SAndroid Build Coastguard Worker case SSH_SERVER_FILE_NOT_FOUND:
454*6236dae4SAndroid Build Coastguard Worker case SSH_SERVER_NOT_KNOWN:
455*6236dae4SAndroid Build Coastguard Worker keymatch = CURLKHMATCH_MISSING;
456*6236dae4SAndroid Build Coastguard Worker break;
457*6236dae4SAndroid Build Coastguard Worker default:
458*6236dae4SAndroid Build Coastguard Worker keymatch = CURLKHMATCH_MISMATCH;
459*6236dae4SAndroid Build Coastguard Worker break;
460*6236dae4SAndroid Build Coastguard Worker }
461*6236dae4SAndroid Build Coastguard Worker #endif
462*6236dae4SAndroid Build Coastguard Worker
463*6236dae4SAndroid Build Coastguard Worker if(func) { /* use callback to determine action */
464*6236dae4SAndroid Build Coastguard Worker rc = ssh_pki_export_pubkey_base64(pubkey, &found_base64);
465*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_OK)
466*6236dae4SAndroid Build Coastguard Worker goto cleanup;
467*6236dae4SAndroid Build Coastguard Worker
468*6236dae4SAndroid Build Coastguard Worker foundkey.key = found_base64;
469*6236dae4SAndroid Build Coastguard Worker foundkey.len = strlen(found_base64);
470*6236dae4SAndroid Build Coastguard Worker
471*6236dae4SAndroid Build Coastguard Worker switch(ssh_key_type(pubkey)) {
472*6236dae4SAndroid Build Coastguard Worker case SSH_KEYTYPE_RSA:
473*6236dae4SAndroid Build Coastguard Worker foundkey.keytype = CURLKHTYPE_RSA;
474*6236dae4SAndroid Build Coastguard Worker break;
475*6236dae4SAndroid Build Coastguard Worker case SSH_KEYTYPE_RSA1:
476*6236dae4SAndroid Build Coastguard Worker foundkey.keytype = CURLKHTYPE_RSA1;
477*6236dae4SAndroid Build Coastguard Worker break;
478*6236dae4SAndroid Build Coastguard Worker case SSH_KEYTYPE_ECDSA:
479*6236dae4SAndroid Build Coastguard Worker #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
480*6236dae4SAndroid Build Coastguard Worker case SSH_KEYTYPE_ECDSA_P256:
481*6236dae4SAndroid Build Coastguard Worker case SSH_KEYTYPE_ECDSA_P384:
482*6236dae4SAndroid Build Coastguard Worker case SSH_KEYTYPE_ECDSA_P521:
483*6236dae4SAndroid Build Coastguard Worker #endif
484*6236dae4SAndroid Build Coastguard Worker foundkey.keytype = CURLKHTYPE_ECDSA;
485*6236dae4SAndroid Build Coastguard Worker break;
486*6236dae4SAndroid Build Coastguard Worker #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,7,0)
487*6236dae4SAndroid Build Coastguard Worker case SSH_KEYTYPE_ED25519:
488*6236dae4SAndroid Build Coastguard Worker foundkey.keytype = CURLKHTYPE_ED25519;
489*6236dae4SAndroid Build Coastguard Worker break;
490*6236dae4SAndroid Build Coastguard Worker #endif
491*6236dae4SAndroid Build Coastguard Worker case SSH_KEYTYPE_DSS:
492*6236dae4SAndroid Build Coastguard Worker foundkey.keytype = CURLKHTYPE_DSS;
493*6236dae4SAndroid Build Coastguard Worker break;
494*6236dae4SAndroid Build Coastguard Worker default:
495*6236dae4SAndroid Build Coastguard Worker rc = SSH_ERROR;
496*6236dae4SAndroid Build Coastguard Worker goto cleanup;
497*6236dae4SAndroid Build Coastguard Worker }
498*6236dae4SAndroid Build Coastguard Worker
499*6236dae4SAndroid Build Coastguard Worker Curl_set_in_callback(data, TRUE);
500*6236dae4SAndroid Build Coastguard Worker rc = func(data, knownkeyp, /* from the knownhosts file */
501*6236dae4SAndroid Build Coastguard Worker &foundkey, /* from the remote host */
502*6236dae4SAndroid Build Coastguard Worker keymatch, data->set.ssh_keyfunc_userp);
503*6236dae4SAndroid Build Coastguard Worker Curl_set_in_callback(data, FALSE);
504*6236dae4SAndroid Build Coastguard Worker
505*6236dae4SAndroid Build Coastguard Worker switch(rc) {
506*6236dae4SAndroid Build Coastguard Worker case CURLKHSTAT_FINE_ADD_TO_FILE:
507*6236dae4SAndroid Build Coastguard Worker #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0)
508*6236dae4SAndroid Build Coastguard Worker rc = ssh_session_update_known_hosts(sshc->ssh_session);
509*6236dae4SAndroid Build Coastguard Worker #else
510*6236dae4SAndroid Build Coastguard Worker rc = ssh_write_knownhost(sshc->ssh_session);
511*6236dae4SAndroid Build Coastguard Worker #endif
512*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_OK) {
513*6236dae4SAndroid Build Coastguard Worker goto cleanup;
514*6236dae4SAndroid Build Coastguard Worker }
515*6236dae4SAndroid Build Coastguard Worker break;
516*6236dae4SAndroid Build Coastguard Worker case CURLKHSTAT_FINE:
517*6236dae4SAndroid Build Coastguard Worker break;
518*6236dae4SAndroid Build Coastguard Worker default: /* REJECT/DEFER */
519*6236dae4SAndroid Build Coastguard Worker rc = SSH_ERROR;
520*6236dae4SAndroid Build Coastguard Worker goto cleanup;
521*6236dae4SAndroid Build Coastguard Worker }
522*6236dae4SAndroid Build Coastguard Worker }
523*6236dae4SAndroid Build Coastguard Worker else {
524*6236dae4SAndroid Build Coastguard Worker if(keymatch != CURLKHMATCH_OK) {
525*6236dae4SAndroid Build Coastguard Worker rc = SSH_ERROR;
526*6236dae4SAndroid Build Coastguard Worker goto cleanup;
527*6236dae4SAndroid Build Coastguard Worker }
528*6236dae4SAndroid Build Coastguard Worker }
529*6236dae4SAndroid Build Coastguard Worker }
530*6236dae4SAndroid Build Coastguard Worker rc = SSH_OK;
531*6236dae4SAndroid Build Coastguard Worker
532*6236dae4SAndroid Build Coastguard Worker cleanup:
533*6236dae4SAndroid Build Coastguard Worker if(found_base64) {
534*6236dae4SAndroid Build Coastguard Worker (free)(found_base64);
535*6236dae4SAndroid Build Coastguard Worker }
536*6236dae4SAndroid Build Coastguard Worker if(known_base64) {
537*6236dae4SAndroid Build Coastguard Worker (free)(known_base64);
538*6236dae4SAndroid Build Coastguard Worker }
539*6236dae4SAndroid Build Coastguard Worker if(hash)
540*6236dae4SAndroid Build Coastguard Worker ssh_clean_pubkey_hash(&hash);
541*6236dae4SAndroid Build Coastguard Worker ssh_key_free(pubkey);
542*6236dae4SAndroid Build Coastguard Worker #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
543*6236dae4SAndroid Build Coastguard Worker if(knownhostsentry) {
544*6236dae4SAndroid Build Coastguard Worker ssh_knownhosts_entry_free(knownhostsentry);
545*6236dae4SAndroid Build Coastguard Worker }
546*6236dae4SAndroid Build Coastguard Worker #endif
547*6236dae4SAndroid Build Coastguard Worker return rc;
548*6236dae4SAndroid Build Coastguard Worker }
549*6236dae4SAndroid Build Coastguard Worker
550*6236dae4SAndroid Build Coastguard Worker #define MOVE_TO_ERROR_STATE(_r) do { \
551*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SESSION_DISCONNECT); \
552*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = _r; \
553*6236dae4SAndroid Build Coastguard Worker rc = SSH_ERROR; \
554*6236dae4SAndroid Build Coastguard Worker } while(0)
555*6236dae4SAndroid Build Coastguard Worker
556*6236dae4SAndroid Build Coastguard Worker #define MOVE_TO_SFTP_CLOSE_STATE() do { \
557*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE); \
558*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = \
559*6236dae4SAndroid Build Coastguard Worker sftp_error_to_CURLE(sftp_get_error(sshc->sftp_session)); \
560*6236dae4SAndroid Build Coastguard Worker rc = SSH_ERROR; \
561*6236dae4SAndroid Build Coastguard Worker } while(0)
562*6236dae4SAndroid Build Coastguard Worker
563*6236dae4SAndroid Build Coastguard Worker #define MOVE_TO_PASSWD_AUTH do { \
564*6236dae4SAndroid Build Coastguard Worker if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) { \
565*6236dae4SAndroid Build Coastguard Worker rc = SSH_OK; \
566*6236dae4SAndroid Build Coastguard Worker state(data, SSH_AUTH_PASS_INIT); \
567*6236dae4SAndroid Build Coastguard Worker } \
568*6236dae4SAndroid Build Coastguard Worker else { \
569*6236dae4SAndroid Build Coastguard Worker MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); \
570*6236dae4SAndroid Build Coastguard Worker } \
571*6236dae4SAndroid Build Coastguard Worker } while(0)
572*6236dae4SAndroid Build Coastguard Worker
573*6236dae4SAndroid Build Coastguard Worker #define MOVE_TO_KEY_AUTH do { \
574*6236dae4SAndroid Build Coastguard Worker if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) { \
575*6236dae4SAndroid Build Coastguard Worker rc = SSH_OK; \
576*6236dae4SAndroid Build Coastguard Worker state(data, SSH_AUTH_KEY_INIT); \
577*6236dae4SAndroid Build Coastguard Worker } \
578*6236dae4SAndroid Build Coastguard Worker else { \
579*6236dae4SAndroid Build Coastguard Worker MOVE_TO_PASSWD_AUTH; \
580*6236dae4SAndroid Build Coastguard Worker } \
581*6236dae4SAndroid Build Coastguard Worker } while(0)
582*6236dae4SAndroid Build Coastguard Worker
583*6236dae4SAndroid Build Coastguard Worker #define MOVE_TO_GSSAPI_AUTH do { \
584*6236dae4SAndroid Build Coastguard Worker if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) { \
585*6236dae4SAndroid Build Coastguard Worker rc = SSH_OK; \
586*6236dae4SAndroid Build Coastguard Worker state(data, SSH_AUTH_GSSAPI); \
587*6236dae4SAndroid Build Coastguard Worker } \
588*6236dae4SAndroid Build Coastguard Worker else { \
589*6236dae4SAndroid Build Coastguard Worker MOVE_TO_KEY_AUTH; \
590*6236dae4SAndroid Build Coastguard Worker } \
591*6236dae4SAndroid Build Coastguard Worker } while(0)
592*6236dae4SAndroid Build Coastguard Worker
593*6236dae4SAndroid Build Coastguard Worker static
myssh_auth_interactive(struct connectdata * conn)594*6236dae4SAndroid Build Coastguard Worker int myssh_auth_interactive(struct connectdata *conn)
595*6236dae4SAndroid Build Coastguard Worker {
596*6236dae4SAndroid Build Coastguard Worker int rc;
597*6236dae4SAndroid Build Coastguard Worker struct ssh_conn *sshc = &conn->proto.sshc;
598*6236dae4SAndroid Build Coastguard Worker int nprompts;
599*6236dae4SAndroid Build Coastguard Worker
600*6236dae4SAndroid Build Coastguard Worker restart:
601*6236dae4SAndroid Build Coastguard Worker switch(sshc->kbd_state) {
602*6236dae4SAndroid Build Coastguard Worker case 0:
603*6236dae4SAndroid Build Coastguard Worker rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
604*6236dae4SAndroid Build Coastguard Worker if(rc == SSH_AUTH_AGAIN)
605*6236dae4SAndroid Build Coastguard Worker return SSH_AGAIN;
606*6236dae4SAndroid Build Coastguard Worker
607*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_AUTH_INFO)
608*6236dae4SAndroid Build Coastguard Worker return SSH_ERROR;
609*6236dae4SAndroid Build Coastguard Worker
610*6236dae4SAndroid Build Coastguard Worker nprompts = ssh_userauth_kbdint_getnprompts(sshc->ssh_session);
611*6236dae4SAndroid Build Coastguard Worker if(nprompts != 1)
612*6236dae4SAndroid Build Coastguard Worker return SSH_ERROR;
613*6236dae4SAndroid Build Coastguard Worker
614*6236dae4SAndroid Build Coastguard Worker rc = ssh_userauth_kbdint_setanswer(sshc->ssh_session, 0, conn->passwd);
615*6236dae4SAndroid Build Coastguard Worker if(rc < 0)
616*6236dae4SAndroid Build Coastguard Worker return SSH_ERROR;
617*6236dae4SAndroid Build Coastguard Worker
618*6236dae4SAndroid Build Coastguard Worker FALLTHROUGH();
619*6236dae4SAndroid Build Coastguard Worker case 1:
620*6236dae4SAndroid Build Coastguard Worker sshc->kbd_state = 1;
621*6236dae4SAndroid Build Coastguard Worker
622*6236dae4SAndroid Build Coastguard Worker rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
623*6236dae4SAndroid Build Coastguard Worker if(rc == SSH_AUTH_AGAIN)
624*6236dae4SAndroid Build Coastguard Worker return SSH_AGAIN;
625*6236dae4SAndroid Build Coastguard Worker else if(rc == SSH_AUTH_SUCCESS)
626*6236dae4SAndroid Build Coastguard Worker rc = SSH_OK;
627*6236dae4SAndroid Build Coastguard Worker else if(rc == SSH_AUTH_INFO) {
628*6236dae4SAndroid Build Coastguard Worker nprompts = ssh_userauth_kbdint_getnprompts(sshc->ssh_session);
629*6236dae4SAndroid Build Coastguard Worker if(nprompts)
630*6236dae4SAndroid Build Coastguard Worker return SSH_ERROR;
631*6236dae4SAndroid Build Coastguard Worker
632*6236dae4SAndroid Build Coastguard Worker sshc->kbd_state = 2;
633*6236dae4SAndroid Build Coastguard Worker goto restart;
634*6236dae4SAndroid Build Coastguard Worker }
635*6236dae4SAndroid Build Coastguard Worker else
636*6236dae4SAndroid Build Coastguard Worker rc = SSH_ERROR;
637*6236dae4SAndroid Build Coastguard Worker break;
638*6236dae4SAndroid Build Coastguard Worker case 2:
639*6236dae4SAndroid Build Coastguard Worker sshc->kbd_state = 2;
640*6236dae4SAndroid Build Coastguard Worker
641*6236dae4SAndroid Build Coastguard Worker rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
642*6236dae4SAndroid Build Coastguard Worker if(rc == SSH_AUTH_AGAIN)
643*6236dae4SAndroid Build Coastguard Worker return SSH_AGAIN;
644*6236dae4SAndroid Build Coastguard Worker else if(rc == SSH_AUTH_SUCCESS)
645*6236dae4SAndroid Build Coastguard Worker rc = SSH_OK;
646*6236dae4SAndroid Build Coastguard Worker else
647*6236dae4SAndroid Build Coastguard Worker rc = SSH_ERROR;
648*6236dae4SAndroid Build Coastguard Worker
649*6236dae4SAndroid Build Coastguard Worker break;
650*6236dae4SAndroid Build Coastguard Worker default:
651*6236dae4SAndroid Build Coastguard Worker return SSH_ERROR;
652*6236dae4SAndroid Build Coastguard Worker }
653*6236dae4SAndroid Build Coastguard Worker
654*6236dae4SAndroid Build Coastguard Worker sshc->kbd_state = 0;
655*6236dae4SAndroid Build Coastguard Worker return rc;
656*6236dae4SAndroid Build Coastguard Worker }
657*6236dae4SAndroid Build Coastguard Worker
658*6236dae4SAndroid Build Coastguard Worker /*
659*6236dae4SAndroid Build Coastguard Worker * ssh_statemach_act() runs the SSH state machine as far as it can without
660*6236dae4SAndroid Build Coastguard Worker * blocking and without reaching the end. The data the pointer 'block' points
661*6236dae4SAndroid Build Coastguard Worker * to will be set to TRUE if the libssh function returns SSH_AGAIN
662*6236dae4SAndroid Build Coastguard Worker * meaning it wants to be called again when the socket is ready
663*6236dae4SAndroid Build Coastguard Worker */
myssh_statemach_act(struct Curl_easy * data,bool * block)664*6236dae4SAndroid Build Coastguard Worker static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
665*6236dae4SAndroid Build Coastguard Worker {
666*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
667*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
668*6236dae4SAndroid Build Coastguard Worker struct SSHPROTO *protop = data->req.p.ssh;
669*6236dae4SAndroid Build Coastguard Worker struct ssh_conn *sshc = &conn->proto.sshc;
670*6236dae4SAndroid Build Coastguard Worker curl_socket_t sock = conn->sock[FIRSTSOCKET];
671*6236dae4SAndroid Build Coastguard Worker int rc = SSH_NO_ERROR, err;
672*6236dae4SAndroid Build Coastguard Worker int seekerr = CURL_SEEKFUNC_OK;
673*6236dae4SAndroid Build Coastguard Worker const char *err_msg;
674*6236dae4SAndroid Build Coastguard Worker *block = 0; /* we are not blocking by default */
675*6236dae4SAndroid Build Coastguard Worker
676*6236dae4SAndroid Build Coastguard Worker do {
677*6236dae4SAndroid Build Coastguard Worker
678*6236dae4SAndroid Build Coastguard Worker switch(sshc->state) {
679*6236dae4SAndroid Build Coastguard Worker case SSH_INIT:
680*6236dae4SAndroid Build Coastguard Worker sshc->secondCreateDirs = 0;
681*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
682*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = CURLE_OK;
683*6236dae4SAndroid Build Coastguard Worker
684*6236dae4SAndroid Build Coastguard Worker #if 0
685*6236dae4SAndroid Build Coastguard Worker ssh_set_log_level(SSH_LOG_PROTOCOL);
686*6236dae4SAndroid Build Coastguard Worker #endif
687*6236dae4SAndroid Build Coastguard Worker
688*6236dae4SAndroid Build Coastguard Worker /* Set libssh to non-blocking, since everything internally is
689*6236dae4SAndroid Build Coastguard Worker non-blocking */
690*6236dae4SAndroid Build Coastguard Worker ssh_set_blocking(sshc->ssh_session, 0);
691*6236dae4SAndroid Build Coastguard Worker
692*6236dae4SAndroid Build Coastguard Worker state(data, SSH_S_STARTUP);
693*6236dae4SAndroid Build Coastguard Worker FALLTHROUGH();
694*6236dae4SAndroid Build Coastguard Worker
695*6236dae4SAndroid Build Coastguard Worker case SSH_S_STARTUP:
696*6236dae4SAndroid Build Coastguard Worker rc = ssh_connect(sshc->ssh_session);
697*6236dae4SAndroid Build Coastguard Worker
698*6236dae4SAndroid Build Coastguard Worker myssh_block2waitfor(conn, (rc == SSH_AGAIN));
699*6236dae4SAndroid Build Coastguard Worker if(rc == SSH_AGAIN) {
700*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "ssh_connect -> EAGAIN"));
701*6236dae4SAndroid Build Coastguard Worker break;
702*6236dae4SAndroid Build Coastguard Worker }
703*6236dae4SAndroid Build Coastguard Worker
704*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_OK) {
705*6236dae4SAndroid Build Coastguard Worker failf(data, "Failure establishing ssh session");
706*6236dae4SAndroid Build Coastguard Worker MOVE_TO_ERROR_STATE(CURLE_FAILED_INIT);
707*6236dae4SAndroid Build Coastguard Worker break;
708*6236dae4SAndroid Build Coastguard Worker }
709*6236dae4SAndroid Build Coastguard Worker
710*6236dae4SAndroid Build Coastguard Worker state(data, SSH_HOSTKEY);
711*6236dae4SAndroid Build Coastguard Worker
712*6236dae4SAndroid Build Coastguard Worker FALLTHROUGH();
713*6236dae4SAndroid Build Coastguard Worker case SSH_HOSTKEY:
714*6236dae4SAndroid Build Coastguard Worker
715*6236dae4SAndroid Build Coastguard Worker rc = myssh_is_known(data);
716*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_OK) {
717*6236dae4SAndroid Build Coastguard Worker MOVE_TO_ERROR_STATE(CURLE_PEER_FAILED_VERIFICATION);
718*6236dae4SAndroid Build Coastguard Worker break;
719*6236dae4SAndroid Build Coastguard Worker }
720*6236dae4SAndroid Build Coastguard Worker
721*6236dae4SAndroid Build Coastguard Worker state(data, SSH_AUTHLIST);
722*6236dae4SAndroid Build Coastguard Worker FALLTHROUGH();
723*6236dae4SAndroid Build Coastguard Worker case SSH_AUTHLIST:{
724*6236dae4SAndroid Build Coastguard Worker sshc->authed = FALSE;
725*6236dae4SAndroid Build Coastguard Worker
726*6236dae4SAndroid Build Coastguard Worker rc = ssh_userauth_none(sshc->ssh_session, NULL);
727*6236dae4SAndroid Build Coastguard Worker if(rc == SSH_AUTH_AGAIN) {
728*6236dae4SAndroid Build Coastguard Worker rc = SSH_AGAIN;
729*6236dae4SAndroid Build Coastguard Worker break;
730*6236dae4SAndroid Build Coastguard Worker }
731*6236dae4SAndroid Build Coastguard Worker
732*6236dae4SAndroid Build Coastguard Worker if(rc == SSH_AUTH_SUCCESS) {
733*6236dae4SAndroid Build Coastguard Worker sshc->authed = TRUE;
734*6236dae4SAndroid Build Coastguard Worker infof(data, "Authenticated with none");
735*6236dae4SAndroid Build Coastguard Worker state(data, SSH_AUTH_DONE);
736*6236dae4SAndroid Build Coastguard Worker break;
737*6236dae4SAndroid Build Coastguard Worker }
738*6236dae4SAndroid Build Coastguard Worker else if(rc == SSH_AUTH_ERROR) {
739*6236dae4SAndroid Build Coastguard Worker MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
740*6236dae4SAndroid Build Coastguard Worker break;
741*6236dae4SAndroid Build Coastguard Worker }
742*6236dae4SAndroid Build Coastguard Worker
743*6236dae4SAndroid Build Coastguard Worker sshc->auth_methods =
744*6236dae4SAndroid Build Coastguard Worker (unsigned int)ssh_userauth_list(sshc->ssh_session, NULL);
745*6236dae4SAndroid Build Coastguard Worker if(sshc->auth_methods)
746*6236dae4SAndroid Build Coastguard Worker infof(data, "SSH authentication methods available: %s%s%s%s",
747*6236dae4SAndroid Build Coastguard Worker sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY ?
748*6236dae4SAndroid Build Coastguard Worker "public key, ": "",
749*6236dae4SAndroid Build Coastguard Worker sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC ?
750*6236dae4SAndroid Build Coastguard Worker "GSSAPI, " : "",
751*6236dae4SAndroid Build Coastguard Worker sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE ?
752*6236dae4SAndroid Build Coastguard Worker "keyboard-interactive, " : "",
753*6236dae4SAndroid Build Coastguard Worker sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD ?
754*6236dae4SAndroid Build Coastguard Worker "password": "");
755*6236dae4SAndroid Build Coastguard Worker if(sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) {
756*6236dae4SAndroid Build Coastguard Worker state(data, SSH_AUTH_PKEY_INIT);
757*6236dae4SAndroid Build Coastguard Worker infof(data, "Authentication using SSH public key file");
758*6236dae4SAndroid Build Coastguard Worker }
759*6236dae4SAndroid Build Coastguard Worker else if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) {
760*6236dae4SAndroid Build Coastguard Worker state(data, SSH_AUTH_GSSAPI);
761*6236dae4SAndroid Build Coastguard Worker }
762*6236dae4SAndroid Build Coastguard Worker else if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) {
763*6236dae4SAndroid Build Coastguard Worker state(data, SSH_AUTH_KEY_INIT);
764*6236dae4SAndroid Build Coastguard Worker }
765*6236dae4SAndroid Build Coastguard Worker else if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) {
766*6236dae4SAndroid Build Coastguard Worker state(data, SSH_AUTH_PASS_INIT);
767*6236dae4SAndroid Build Coastguard Worker }
768*6236dae4SAndroid Build Coastguard Worker else { /* unsupported authentication method */
769*6236dae4SAndroid Build Coastguard Worker MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
770*6236dae4SAndroid Build Coastguard Worker break;
771*6236dae4SAndroid Build Coastguard Worker }
772*6236dae4SAndroid Build Coastguard Worker
773*6236dae4SAndroid Build Coastguard Worker break;
774*6236dae4SAndroid Build Coastguard Worker }
775*6236dae4SAndroid Build Coastguard Worker case SSH_AUTH_PKEY_INIT:
776*6236dae4SAndroid Build Coastguard Worker if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY)) {
777*6236dae4SAndroid Build Coastguard Worker MOVE_TO_GSSAPI_AUTH;
778*6236dae4SAndroid Build Coastguard Worker break;
779*6236dae4SAndroid Build Coastguard Worker }
780*6236dae4SAndroid Build Coastguard Worker
781*6236dae4SAndroid Build Coastguard Worker /* Two choices, (1) private key was given on CMD,
782*6236dae4SAndroid Build Coastguard Worker * (2) use the "default" keys. */
783*6236dae4SAndroid Build Coastguard Worker if(data->set.str[STRING_SSH_PRIVATE_KEY]) {
784*6236dae4SAndroid Build Coastguard Worker if(sshc->pubkey && !data->set.ssl.key_passwd) {
785*6236dae4SAndroid Build Coastguard Worker rc = ssh_userauth_try_publickey(sshc->ssh_session, NULL,
786*6236dae4SAndroid Build Coastguard Worker sshc->pubkey);
787*6236dae4SAndroid Build Coastguard Worker if(rc == SSH_AUTH_AGAIN) {
788*6236dae4SAndroid Build Coastguard Worker rc = SSH_AGAIN;
789*6236dae4SAndroid Build Coastguard Worker break;
790*6236dae4SAndroid Build Coastguard Worker }
791*6236dae4SAndroid Build Coastguard Worker
792*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_OK) {
793*6236dae4SAndroid Build Coastguard Worker MOVE_TO_GSSAPI_AUTH;
794*6236dae4SAndroid Build Coastguard Worker break;
795*6236dae4SAndroid Build Coastguard Worker }
796*6236dae4SAndroid Build Coastguard Worker }
797*6236dae4SAndroid Build Coastguard Worker
798*6236dae4SAndroid Build Coastguard Worker rc = ssh_pki_import_privkey_file(data->
799*6236dae4SAndroid Build Coastguard Worker set.str[STRING_SSH_PRIVATE_KEY],
800*6236dae4SAndroid Build Coastguard Worker data->set.ssl.key_passwd, NULL,
801*6236dae4SAndroid Build Coastguard Worker NULL, &sshc->privkey);
802*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_OK) {
803*6236dae4SAndroid Build Coastguard Worker failf(data, "Could not load private key file %s",
804*6236dae4SAndroid Build Coastguard Worker data->set.str[STRING_SSH_PRIVATE_KEY]);
805*6236dae4SAndroid Build Coastguard Worker MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
806*6236dae4SAndroid Build Coastguard Worker break;
807*6236dae4SAndroid Build Coastguard Worker }
808*6236dae4SAndroid Build Coastguard Worker
809*6236dae4SAndroid Build Coastguard Worker state(data, SSH_AUTH_PKEY);
810*6236dae4SAndroid Build Coastguard Worker break;
811*6236dae4SAndroid Build Coastguard Worker
812*6236dae4SAndroid Build Coastguard Worker }
813*6236dae4SAndroid Build Coastguard Worker else {
814*6236dae4SAndroid Build Coastguard Worker rc = ssh_userauth_publickey_auto(sshc->ssh_session, NULL,
815*6236dae4SAndroid Build Coastguard Worker data->set.ssl.key_passwd);
816*6236dae4SAndroid Build Coastguard Worker if(rc == SSH_AUTH_AGAIN) {
817*6236dae4SAndroid Build Coastguard Worker rc = SSH_AGAIN;
818*6236dae4SAndroid Build Coastguard Worker break;
819*6236dae4SAndroid Build Coastguard Worker }
820*6236dae4SAndroid Build Coastguard Worker if(rc == SSH_AUTH_SUCCESS) {
821*6236dae4SAndroid Build Coastguard Worker rc = SSH_OK;
822*6236dae4SAndroid Build Coastguard Worker sshc->authed = TRUE;
823*6236dae4SAndroid Build Coastguard Worker infof(data, "Completed public key authentication");
824*6236dae4SAndroid Build Coastguard Worker state(data, SSH_AUTH_DONE);
825*6236dae4SAndroid Build Coastguard Worker break;
826*6236dae4SAndroid Build Coastguard Worker }
827*6236dae4SAndroid Build Coastguard Worker
828*6236dae4SAndroid Build Coastguard Worker MOVE_TO_GSSAPI_AUTH;
829*6236dae4SAndroid Build Coastguard Worker }
830*6236dae4SAndroid Build Coastguard Worker break;
831*6236dae4SAndroid Build Coastguard Worker case SSH_AUTH_PKEY:
832*6236dae4SAndroid Build Coastguard Worker rc = ssh_userauth_publickey(sshc->ssh_session, NULL, sshc->privkey);
833*6236dae4SAndroid Build Coastguard Worker if(rc == SSH_AUTH_AGAIN) {
834*6236dae4SAndroid Build Coastguard Worker rc = SSH_AGAIN;
835*6236dae4SAndroid Build Coastguard Worker break;
836*6236dae4SAndroid Build Coastguard Worker }
837*6236dae4SAndroid Build Coastguard Worker
838*6236dae4SAndroid Build Coastguard Worker if(rc == SSH_AUTH_SUCCESS) {
839*6236dae4SAndroid Build Coastguard Worker sshc->authed = TRUE;
840*6236dae4SAndroid Build Coastguard Worker infof(data, "Completed public key authentication");
841*6236dae4SAndroid Build Coastguard Worker state(data, SSH_AUTH_DONE);
842*6236dae4SAndroid Build Coastguard Worker break;
843*6236dae4SAndroid Build Coastguard Worker }
844*6236dae4SAndroid Build Coastguard Worker else {
845*6236dae4SAndroid Build Coastguard Worker infof(data, "Failed public key authentication (rc: %d)", rc);
846*6236dae4SAndroid Build Coastguard Worker MOVE_TO_GSSAPI_AUTH;
847*6236dae4SAndroid Build Coastguard Worker }
848*6236dae4SAndroid Build Coastguard Worker break;
849*6236dae4SAndroid Build Coastguard Worker
850*6236dae4SAndroid Build Coastguard Worker case SSH_AUTH_GSSAPI:
851*6236dae4SAndroid Build Coastguard Worker if(!(data->set.ssh_auth_types & CURLSSH_AUTH_GSSAPI)) {
852*6236dae4SAndroid Build Coastguard Worker MOVE_TO_KEY_AUTH;
853*6236dae4SAndroid Build Coastguard Worker break;
854*6236dae4SAndroid Build Coastguard Worker }
855*6236dae4SAndroid Build Coastguard Worker
856*6236dae4SAndroid Build Coastguard Worker rc = ssh_userauth_gssapi(sshc->ssh_session);
857*6236dae4SAndroid Build Coastguard Worker if(rc == SSH_AUTH_AGAIN) {
858*6236dae4SAndroid Build Coastguard Worker rc = SSH_AGAIN;
859*6236dae4SAndroid Build Coastguard Worker break;
860*6236dae4SAndroid Build Coastguard Worker }
861*6236dae4SAndroid Build Coastguard Worker
862*6236dae4SAndroid Build Coastguard Worker if(rc == SSH_AUTH_SUCCESS) {
863*6236dae4SAndroid Build Coastguard Worker rc = SSH_OK;
864*6236dae4SAndroid Build Coastguard Worker sshc->authed = TRUE;
865*6236dae4SAndroid Build Coastguard Worker infof(data, "Completed gssapi authentication");
866*6236dae4SAndroid Build Coastguard Worker state(data, SSH_AUTH_DONE);
867*6236dae4SAndroid Build Coastguard Worker break;
868*6236dae4SAndroid Build Coastguard Worker }
869*6236dae4SAndroid Build Coastguard Worker
870*6236dae4SAndroid Build Coastguard Worker MOVE_TO_KEY_AUTH;
871*6236dae4SAndroid Build Coastguard Worker break;
872*6236dae4SAndroid Build Coastguard Worker
873*6236dae4SAndroid Build Coastguard Worker case SSH_AUTH_KEY_INIT:
874*6236dae4SAndroid Build Coastguard Worker if(data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) {
875*6236dae4SAndroid Build Coastguard Worker state(data, SSH_AUTH_KEY);
876*6236dae4SAndroid Build Coastguard Worker }
877*6236dae4SAndroid Build Coastguard Worker else {
878*6236dae4SAndroid Build Coastguard Worker MOVE_TO_PASSWD_AUTH;
879*6236dae4SAndroid Build Coastguard Worker }
880*6236dae4SAndroid Build Coastguard Worker break;
881*6236dae4SAndroid Build Coastguard Worker
882*6236dae4SAndroid Build Coastguard Worker case SSH_AUTH_KEY:
883*6236dae4SAndroid Build Coastguard Worker /* keyboard-interactive authentication */
884*6236dae4SAndroid Build Coastguard Worker rc = myssh_auth_interactive(conn);
885*6236dae4SAndroid Build Coastguard Worker if(rc == SSH_AGAIN) {
886*6236dae4SAndroid Build Coastguard Worker break;
887*6236dae4SAndroid Build Coastguard Worker }
888*6236dae4SAndroid Build Coastguard Worker if(rc == SSH_OK) {
889*6236dae4SAndroid Build Coastguard Worker sshc->authed = TRUE;
890*6236dae4SAndroid Build Coastguard Worker infof(data, "completed keyboard interactive authentication");
891*6236dae4SAndroid Build Coastguard Worker state(data, SSH_AUTH_DONE);
892*6236dae4SAndroid Build Coastguard Worker }
893*6236dae4SAndroid Build Coastguard Worker else {
894*6236dae4SAndroid Build Coastguard Worker MOVE_TO_PASSWD_AUTH;
895*6236dae4SAndroid Build Coastguard Worker }
896*6236dae4SAndroid Build Coastguard Worker break;
897*6236dae4SAndroid Build Coastguard Worker
898*6236dae4SAndroid Build Coastguard Worker case SSH_AUTH_PASS_INIT:
899*6236dae4SAndroid Build Coastguard Worker if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD)) {
900*6236dae4SAndroid Build Coastguard Worker MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
901*6236dae4SAndroid Build Coastguard Worker break;
902*6236dae4SAndroid Build Coastguard Worker }
903*6236dae4SAndroid Build Coastguard Worker state(data, SSH_AUTH_PASS);
904*6236dae4SAndroid Build Coastguard Worker FALLTHROUGH();
905*6236dae4SAndroid Build Coastguard Worker
906*6236dae4SAndroid Build Coastguard Worker case SSH_AUTH_PASS:
907*6236dae4SAndroid Build Coastguard Worker rc = ssh_userauth_password(sshc->ssh_session, NULL, conn->passwd);
908*6236dae4SAndroid Build Coastguard Worker if(rc == SSH_AUTH_AGAIN) {
909*6236dae4SAndroid Build Coastguard Worker rc = SSH_AGAIN;
910*6236dae4SAndroid Build Coastguard Worker break;
911*6236dae4SAndroid Build Coastguard Worker }
912*6236dae4SAndroid Build Coastguard Worker
913*6236dae4SAndroid Build Coastguard Worker if(rc == SSH_AUTH_SUCCESS) {
914*6236dae4SAndroid Build Coastguard Worker sshc->authed = TRUE;
915*6236dae4SAndroid Build Coastguard Worker infof(data, "Completed password authentication");
916*6236dae4SAndroid Build Coastguard Worker state(data, SSH_AUTH_DONE);
917*6236dae4SAndroid Build Coastguard Worker }
918*6236dae4SAndroid Build Coastguard Worker else {
919*6236dae4SAndroid Build Coastguard Worker MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
920*6236dae4SAndroid Build Coastguard Worker }
921*6236dae4SAndroid Build Coastguard Worker break;
922*6236dae4SAndroid Build Coastguard Worker
923*6236dae4SAndroid Build Coastguard Worker case SSH_AUTH_DONE:
924*6236dae4SAndroid Build Coastguard Worker if(!sshc->authed) {
925*6236dae4SAndroid Build Coastguard Worker failf(data, "Authentication failure");
926*6236dae4SAndroid Build Coastguard Worker MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
927*6236dae4SAndroid Build Coastguard Worker break;
928*6236dae4SAndroid Build Coastguard Worker }
929*6236dae4SAndroid Build Coastguard Worker
930*6236dae4SAndroid Build Coastguard Worker /*
931*6236dae4SAndroid Build Coastguard Worker * At this point we have an authenticated ssh session.
932*6236dae4SAndroid Build Coastguard Worker */
933*6236dae4SAndroid Build Coastguard Worker infof(data, "Authentication complete");
934*6236dae4SAndroid Build Coastguard Worker
935*6236dae4SAndroid Build Coastguard Worker Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSH is connected */
936*6236dae4SAndroid Build Coastguard Worker
937*6236dae4SAndroid Build Coastguard Worker conn->sockfd = sock;
938*6236dae4SAndroid Build Coastguard Worker conn->writesockfd = CURL_SOCKET_BAD;
939*6236dae4SAndroid Build Coastguard Worker
940*6236dae4SAndroid Build Coastguard Worker if(conn->handler->protocol == CURLPROTO_SFTP) {
941*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_INIT);
942*6236dae4SAndroid Build Coastguard Worker break;
943*6236dae4SAndroid Build Coastguard Worker }
944*6236dae4SAndroid Build Coastguard Worker infof(data, "SSH CONNECT phase done");
945*6236dae4SAndroid Build Coastguard Worker state(data, SSH_STOP);
946*6236dae4SAndroid Build Coastguard Worker break;
947*6236dae4SAndroid Build Coastguard Worker
948*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_INIT:
949*6236dae4SAndroid Build Coastguard Worker ssh_set_blocking(sshc->ssh_session, 1);
950*6236dae4SAndroid Build Coastguard Worker
951*6236dae4SAndroid Build Coastguard Worker sshc->sftp_session = sftp_new(sshc->ssh_session);
952*6236dae4SAndroid Build Coastguard Worker if(!sshc->sftp_session) {
953*6236dae4SAndroid Build Coastguard Worker failf(data, "Failure initializing sftp session: %s",
954*6236dae4SAndroid Build Coastguard Worker ssh_get_error(sshc->ssh_session));
955*6236dae4SAndroid Build Coastguard Worker MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
956*6236dae4SAndroid Build Coastguard Worker break;
957*6236dae4SAndroid Build Coastguard Worker }
958*6236dae4SAndroid Build Coastguard Worker
959*6236dae4SAndroid Build Coastguard Worker rc = sftp_init(sshc->sftp_session);
960*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_OK) {
961*6236dae4SAndroid Build Coastguard Worker failf(data, "Failure initializing sftp session: %s",
962*6236dae4SAndroid Build Coastguard Worker ssh_get_error(sshc->ssh_session));
963*6236dae4SAndroid Build Coastguard Worker MOVE_TO_ERROR_STATE(sftp_error_to_CURLE(SSH_FX_FAILURE));
964*6236dae4SAndroid Build Coastguard Worker break;
965*6236dae4SAndroid Build Coastguard Worker }
966*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_REALPATH);
967*6236dae4SAndroid Build Coastguard Worker FALLTHROUGH();
968*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_REALPATH:
969*6236dae4SAndroid Build Coastguard Worker /*
970*6236dae4SAndroid Build Coastguard Worker * Get the "home" directory
971*6236dae4SAndroid Build Coastguard Worker */
972*6236dae4SAndroid Build Coastguard Worker sshc->homedir = sftp_canonicalize_path(sshc->sftp_session, ".");
973*6236dae4SAndroid Build Coastguard Worker if(!sshc->homedir) {
974*6236dae4SAndroid Build Coastguard Worker MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
975*6236dae4SAndroid Build Coastguard Worker break;
976*6236dae4SAndroid Build Coastguard Worker }
977*6236dae4SAndroid Build Coastguard Worker data->state.most_recent_ftp_entrypath = sshc->homedir;
978*6236dae4SAndroid Build Coastguard Worker
979*6236dae4SAndroid Build Coastguard Worker /* This is the last step in the SFTP connect phase. Do note that while
980*6236dae4SAndroid Build Coastguard Worker we get the homedir here, we get the "workingpath" in the DO action
981*6236dae4SAndroid Build Coastguard Worker since the homedir will remain the same between request but the
982*6236dae4SAndroid Build Coastguard Worker working path will not. */
983*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "SSH CONNECT phase done"));
984*6236dae4SAndroid Build Coastguard Worker state(data, SSH_STOP);
985*6236dae4SAndroid Build Coastguard Worker break;
986*6236dae4SAndroid Build Coastguard Worker
987*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_QUOTE_INIT:
988*6236dae4SAndroid Build Coastguard Worker result = Curl_getworkingpath(data, sshc->homedir, &protop->path);
989*6236dae4SAndroid Build Coastguard Worker if(result) {
990*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = result;
991*6236dae4SAndroid Build Coastguard Worker state(data, SSH_STOP);
992*6236dae4SAndroid Build Coastguard Worker break;
993*6236dae4SAndroid Build Coastguard Worker }
994*6236dae4SAndroid Build Coastguard Worker
995*6236dae4SAndroid Build Coastguard Worker if(data->set.quote) {
996*6236dae4SAndroid Build Coastguard Worker infof(data, "Sending quote commands");
997*6236dae4SAndroid Build Coastguard Worker sshc->quote_item = data->set.quote;
998*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_QUOTE);
999*6236dae4SAndroid Build Coastguard Worker }
1000*6236dae4SAndroid Build Coastguard Worker else {
1001*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_GETINFO);
1002*6236dae4SAndroid Build Coastguard Worker }
1003*6236dae4SAndroid Build Coastguard Worker break;
1004*6236dae4SAndroid Build Coastguard Worker
1005*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_POSTQUOTE_INIT:
1006*6236dae4SAndroid Build Coastguard Worker if(data->set.postquote) {
1007*6236dae4SAndroid Build Coastguard Worker infof(data, "Sending quote commands");
1008*6236dae4SAndroid Build Coastguard Worker sshc->quote_item = data->set.postquote;
1009*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_QUOTE);
1010*6236dae4SAndroid Build Coastguard Worker }
1011*6236dae4SAndroid Build Coastguard Worker else {
1012*6236dae4SAndroid Build Coastguard Worker state(data, SSH_STOP);
1013*6236dae4SAndroid Build Coastguard Worker }
1014*6236dae4SAndroid Build Coastguard Worker break;
1015*6236dae4SAndroid Build Coastguard Worker
1016*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_QUOTE:
1017*6236dae4SAndroid Build Coastguard Worker /* Send any quote commands */
1018*6236dae4SAndroid Build Coastguard Worker sftp_quote(data);
1019*6236dae4SAndroid Build Coastguard Worker break;
1020*6236dae4SAndroid Build Coastguard Worker
1021*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_NEXT_QUOTE:
1022*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path1);
1023*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path2);
1024*6236dae4SAndroid Build Coastguard Worker
1025*6236dae4SAndroid Build Coastguard Worker sshc->quote_item = sshc->quote_item->next;
1026*6236dae4SAndroid Build Coastguard Worker
1027*6236dae4SAndroid Build Coastguard Worker if(sshc->quote_item) {
1028*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_QUOTE);
1029*6236dae4SAndroid Build Coastguard Worker }
1030*6236dae4SAndroid Build Coastguard Worker else {
1031*6236dae4SAndroid Build Coastguard Worker if(sshc->nextstate != SSH_NO_STATE) {
1032*6236dae4SAndroid Build Coastguard Worker state(data, sshc->nextstate);
1033*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
1034*6236dae4SAndroid Build Coastguard Worker }
1035*6236dae4SAndroid Build Coastguard Worker else {
1036*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_GETINFO);
1037*6236dae4SAndroid Build Coastguard Worker }
1038*6236dae4SAndroid Build Coastguard Worker }
1039*6236dae4SAndroid Build Coastguard Worker break;
1040*6236dae4SAndroid Build Coastguard Worker
1041*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_QUOTE_STAT:
1042*6236dae4SAndroid Build Coastguard Worker sftp_quote_stat(data);
1043*6236dae4SAndroid Build Coastguard Worker break;
1044*6236dae4SAndroid Build Coastguard Worker
1045*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_QUOTE_SETSTAT:
1046*6236dae4SAndroid Build Coastguard Worker rc = sftp_setstat(sshc->sftp_session, sshc->quote_path2,
1047*6236dae4SAndroid Build Coastguard Worker sshc->quote_attrs);
1048*6236dae4SAndroid Build Coastguard Worker if(rc && !sshc->acceptfail) {
1049*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path1);
1050*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path2);
1051*6236dae4SAndroid Build Coastguard Worker failf(data, "Attempt to set SFTP stats failed: %s",
1052*6236dae4SAndroid Build Coastguard Worker ssh_get_error(sshc->ssh_session));
1053*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
1054*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
1055*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = CURLE_QUOTE_ERROR;
1056*6236dae4SAndroid Build Coastguard Worker /* sshc->actualcode = sftp_error_to_CURLE(err);
1057*6236dae4SAndroid Build Coastguard Worker * we do not send the actual error; we return
1058*6236dae4SAndroid Build Coastguard Worker * the error the libssh2 backend is returning */
1059*6236dae4SAndroid Build Coastguard Worker break;
1060*6236dae4SAndroid Build Coastguard Worker }
1061*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_NEXT_QUOTE);
1062*6236dae4SAndroid Build Coastguard Worker break;
1063*6236dae4SAndroid Build Coastguard Worker
1064*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_QUOTE_SYMLINK:
1065*6236dae4SAndroid Build Coastguard Worker rc = sftp_symlink(sshc->sftp_session, sshc->quote_path2,
1066*6236dae4SAndroid Build Coastguard Worker sshc->quote_path1);
1067*6236dae4SAndroid Build Coastguard Worker if(rc && !sshc->acceptfail) {
1068*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path1);
1069*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path2);
1070*6236dae4SAndroid Build Coastguard Worker failf(data, "symlink command failed: %s",
1071*6236dae4SAndroid Build Coastguard Worker ssh_get_error(sshc->ssh_session));
1072*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
1073*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
1074*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = CURLE_QUOTE_ERROR;
1075*6236dae4SAndroid Build Coastguard Worker break;
1076*6236dae4SAndroid Build Coastguard Worker }
1077*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_NEXT_QUOTE);
1078*6236dae4SAndroid Build Coastguard Worker break;
1079*6236dae4SAndroid Build Coastguard Worker
1080*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_QUOTE_MKDIR:
1081*6236dae4SAndroid Build Coastguard Worker rc = sftp_mkdir(sshc->sftp_session, sshc->quote_path1,
1082*6236dae4SAndroid Build Coastguard Worker (mode_t)data->set.new_directory_perms);
1083*6236dae4SAndroid Build Coastguard Worker if(rc && !sshc->acceptfail) {
1084*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path1);
1085*6236dae4SAndroid Build Coastguard Worker failf(data, "mkdir command failed: %s",
1086*6236dae4SAndroid Build Coastguard Worker ssh_get_error(sshc->ssh_session));
1087*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
1088*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
1089*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = CURLE_QUOTE_ERROR;
1090*6236dae4SAndroid Build Coastguard Worker break;
1091*6236dae4SAndroid Build Coastguard Worker }
1092*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_NEXT_QUOTE);
1093*6236dae4SAndroid Build Coastguard Worker break;
1094*6236dae4SAndroid Build Coastguard Worker
1095*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_QUOTE_RENAME:
1096*6236dae4SAndroid Build Coastguard Worker rc = sftp_rename(sshc->sftp_session, sshc->quote_path1,
1097*6236dae4SAndroid Build Coastguard Worker sshc->quote_path2);
1098*6236dae4SAndroid Build Coastguard Worker if(rc && !sshc->acceptfail) {
1099*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path1);
1100*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path2);
1101*6236dae4SAndroid Build Coastguard Worker failf(data, "rename command failed: %s",
1102*6236dae4SAndroid Build Coastguard Worker ssh_get_error(sshc->ssh_session));
1103*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
1104*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
1105*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = CURLE_QUOTE_ERROR;
1106*6236dae4SAndroid Build Coastguard Worker break;
1107*6236dae4SAndroid Build Coastguard Worker }
1108*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_NEXT_QUOTE);
1109*6236dae4SAndroid Build Coastguard Worker break;
1110*6236dae4SAndroid Build Coastguard Worker
1111*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_QUOTE_RMDIR:
1112*6236dae4SAndroid Build Coastguard Worker rc = sftp_rmdir(sshc->sftp_session, sshc->quote_path1);
1113*6236dae4SAndroid Build Coastguard Worker if(rc && !sshc->acceptfail) {
1114*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path1);
1115*6236dae4SAndroid Build Coastguard Worker failf(data, "rmdir command failed: %s",
1116*6236dae4SAndroid Build Coastguard Worker ssh_get_error(sshc->ssh_session));
1117*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
1118*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
1119*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = CURLE_QUOTE_ERROR;
1120*6236dae4SAndroid Build Coastguard Worker break;
1121*6236dae4SAndroid Build Coastguard Worker }
1122*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_NEXT_QUOTE);
1123*6236dae4SAndroid Build Coastguard Worker break;
1124*6236dae4SAndroid Build Coastguard Worker
1125*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_QUOTE_UNLINK:
1126*6236dae4SAndroid Build Coastguard Worker rc = sftp_unlink(sshc->sftp_session, sshc->quote_path1);
1127*6236dae4SAndroid Build Coastguard Worker if(rc && !sshc->acceptfail) {
1128*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path1);
1129*6236dae4SAndroid Build Coastguard Worker failf(data, "rm command failed: %s",
1130*6236dae4SAndroid Build Coastguard Worker ssh_get_error(sshc->ssh_session));
1131*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
1132*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
1133*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = CURLE_QUOTE_ERROR;
1134*6236dae4SAndroid Build Coastguard Worker break;
1135*6236dae4SAndroid Build Coastguard Worker }
1136*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_NEXT_QUOTE);
1137*6236dae4SAndroid Build Coastguard Worker break;
1138*6236dae4SAndroid Build Coastguard Worker
1139*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_QUOTE_STATVFS:
1140*6236dae4SAndroid Build Coastguard Worker {
1141*6236dae4SAndroid Build Coastguard Worker sftp_statvfs_t statvfs;
1142*6236dae4SAndroid Build Coastguard Worker
1143*6236dae4SAndroid Build Coastguard Worker statvfs = sftp_statvfs(sshc->sftp_session, sshc->quote_path1);
1144*6236dae4SAndroid Build Coastguard Worker if(!statvfs && !sshc->acceptfail) {
1145*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path1);
1146*6236dae4SAndroid Build Coastguard Worker failf(data, "statvfs command failed: %s",
1147*6236dae4SAndroid Build Coastguard Worker ssh_get_error(sshc->ssh_session));
1148*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
1149*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
1150*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = CURLE_QUOTE_ERROR;
1151*6236dae4SAndroid Build Coastguard Worker break;
1152*6236dae4SAndroid Build Coastguard Worker }
1153*6236dae4SAndroid Build Coastguard Worker else if(statvfs) {
1154*6236dae4SAndroid Build Coastguard Worker #ifdef _MSC_VER
1155*6236dae4SAndroid Build Coastguard Worker #define CURL_LIBSSH_VFS_SIZE_MASK "I64u"
1156*6236dae4SAndroid Build Coastguard Worker #else
1157*6236dae4SAndroid Build Coastguard Worker #define CURL_LIBSSH_VFS_SIZE_MASK PRIu64
1158*6236dae4SAndroid Build Coastguard Worker #endif
1159*6236dae4SAndroid Build Coastguard Worker char *tmp = aprintf("statvfs:\n"
1160*6236dae4SAndroid Build Coastguard Worker "f_bsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1161*6236dae4SAndroid Build Coastguard Worker "f_frsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1162*6236dae4SAndroid Build Coastguard Worker "f_blocks: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1163*6236dae4SAndroid Build Coastguard Worker "f_bfree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1164*6236dae4SAndroid Build Coastguard Worker "f_bavail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1165*6236dae4SAndroid Build Coastguard Worker "f_files: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1166*6236dae4SAndroid Build Coastguard Worker "f_ffree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1167*6236dae4SAndroid Build Coastguard Worker "f_favail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1168*6236dae4SAndroid Build Coastguard Worker "f_fsid: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1169*6236dae4SAndroid Build Coastguard Worker "f_flag: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
1170*6236dae4SAndroid Build Coastguard Worker "f_namemax: %" CURL_LIBSSH_VFS_SIZE_MASK "\n",
1171*6236dae4SAndroid Build Coastguard Worker statvfs->f_bsize, statvfs->f_frsize,
1172*6236dae4SAndroid Build Coastguard Worker statvfs->f_blocks, statvfs->f_bfree,
1173*6236dae4SAndroid Build Coastguard Worker statvfs->f_bavail, statvfs->f_files,
1174*6236dae4SAndroid Build Coastguard Worker statvfs->f_ffree, statvfs->f_favail,
1175*6236dae4SAndroid Build Coastguard Worker statvfs->f_fsid, statvfs->f_flag,
1176*6236dae4SAndroid Build Coastguard Worker statvfs->f_namemax);
1177*6236dae4SAndroid Build Coastguard Worker sftp_statvfs_free(statvfs);
1178*6236dae4SAndroid Build Coastguard Worker
1179*6236dae4SAndroid Build Coastguard Worker if(!tmp) {
1180*6236dae4SAndroid Build Coastguard Worker result = CURLE_OUT_OF_MEMORY;
1181*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
1182*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
1183*6236dae4SAndroid Build Coastguard Worker break;
1184*6236dae4SAndroid Build Coastguard Worker }
1185*6236dae4SAndroid Build Coastguard Worker
1186*6236dae4SAndroid Build Coastguard Worker result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
1187*6236dae4SAndroid Build Coastguard Worker free(tmp);
1188*6236dae4SAndroid Build Coastguard Worker if(result) {
1189*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
1190*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
1191*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = result;
1192*6236dae4SAndroid Build Coastguard Worker }
1193*6236dae4SAndroid Build Coastguard Worker }
1194*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_NEXT_QUOTE);
1195*6236dae4SAndroid Build Coastguard Worker break;
1196*6236dae4SAndroid Build Coastguard Worker }
1197*6236dae4SAndroid Build Coastguard Worker
1198*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_GETINFO:
1199*6236dae4SAndroid Build Coastguard Worker if(data->set.get_filetime) {
1200*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_FILETIME);
1201*6236dae4SAndroid Build Coastguard Worker }
1202*6236dae4SAndroid Build Coastguard Worker else {
1203*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_TRANS_INIT);
1204*6236dae4SAndroid Build Coastguard Worker }
1205*6236dae4SAndroid Build Coastguard Worker break;
1206*6236dae4SAndroid Build Coastguard Worker
1207*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_FILETIME:
1208*6236dae4SAndroid Build Coastguard Worker {
1209*6236dae4SAndroid Build Coastguard Worker sftp_attributes attrs;
1210*6236dae4SAndroid Build Coastguard Worker
1211*6236dae4SAndroid Build Coastguard Worker attrs = sftp_stat(sshc->sftp_session, protop->path);
1212*6236dae4SAndroid Build Coastguard Worker if(attrs) {
1213*6236dae4SAndroid Build Coastguard Worker data->info.filetime = attrs->mtime;
1214*6236dae4SAndroid Build Coastguard Worker sftp_attributes_free(attrs);
1215*6236dae4SAndroid Build Coastguard Worker }
1216*6236dae4SAndroid Build Coastguard Worker
1217*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_TRANS_INIT);
1218*6236dae4SAndroid Build Coastguard Worker break;
1219*6236dae4SAndroid Build Coastguard Worker }
1220*6236dae4SAndroid Build Coastguard Worker
1221*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_TRANS_INIT:
1222*6236dae4SAndroid Build Coastguard Worker if(data->state.upload)
1223*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_UPLOAD_INIT);
1224*6236dae4SAndroid Build Coastguard Worker else {
1225*6236dae4SAndroid Build Coastguard Worker if(protop->path[strlen(protop->path)-1] == '/')
1226*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_READDIR_INIT);
1227*6236dae4SAndroid Build Coastguard Worker else
1228*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_DOWNLOAD_INIT);
1229*6236dae4SAndroid Build Coastguard Worker }
1230*6236dae4SAndroid Build Coastguard Worker break;
1231*6236dae4SAndroid Build Coastguard Worker
1232*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_UPLOAD_INIT:
1233*6236dae4SAndroid Build Coastguard Worker {
1234*6236dae4SAndroid Build Coastguard Worker int flags;
1235*6236dae4SAndroid Build Coastguard Worker
1236*6236dae4SAndroid Build Coastguard Worker if(data->state.resume_from) {
1237*6236dae4SAndroid Build Coastguard Worker sftp_attributes attrs;
1238*6236dae4SAndroid Build Coastguard Worker
1239*6236dae4SAndroid Build Coastguard Worker if(data->state.resume_from < 0) {
1240*6236dae4SAndroid Build Coastguard Worker attrs = sftp_stat(sshc->sftp_session, protop->path);
1241*6236dae4SAndroid Build Coastguard Worker if(attrs) {
1242*6236dae4SAndroid Build Coastguard Worker curl_off_t size = attrs->size;
1243*6236dae4SAndroid Build Coastguard Worker if(size < 0) {
1244*6236dae4SAndroid Build Coastguard Worker failf(data, "Bad file size (%" FMT_OFF_T ")", size);
1245*6236dae4SAndroid Build Coastguard Worker MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME);
1246*6236dae4SAndroid Build Coastguard Worker break;
1247*6236dae4SAndroid Build Coastguard Worker }
1248*6236dae4SAndroid Build Coastguard Worker data->state.resume_from = attrs->size;
1249*6236dae4SAndroid Build Coastguard Worker
1250*6236dae4SAndroid Build Coastguard Worker sftp_attributes_free(attrs);
1251*6236dae4SAndroid Build Coastguard Worker }
1252*6236dae4SAndroid Build Coastguard Worker else {
1253*6236dae4SAndroid Build Coastguard Worker data->state.resume_from = 0;
1254*6236dae4SAndroid Build Coastguard Worker }
1255*6236dae4SAndroid Build Coastguard Worker }
1256*6236dae4SAndroid Build Coastguard Worker }
1257*6236dae4SAndroid Build Coastguard Worker
1258*6236dae4SAndroid Build Coastguard Worker if(data->set.remote_append)
1259*6236dae4SAndroid Build Coastguard Worker /* Try to open for append, but create if nonexisting */
1260*6236dae4SAndroid Build Coastguard Worker flags = O_WRONLY|O_CREAT|O_APPEND;
1261*6236dae4SAndroid Build Coastguard Worker else if(data->state.resume_from > 0)
1262*6236dae4SAndroid Build Coastguard Worker /* If we have restart position then open for append */
1263*6236dae4SAndroid Build Coastguard Worker flags = O_WRONLY|O_APPEND;
1264*6236dae4SAndroid Build Coastguard Worker else
1265*6236dae4SAndroid Build Coastguard Worker /* Clear file before writing (normal behavior) */
1266*6236dae4SAndroid Build Coastguard Worker flags = O_WRONLY|O_CREAT|O_TRUNC;
1267*6236dae4SAndroid Build Coastguard Worker
1268*6236dae4SAndroid Build Coastguard Worker if(sshc->sftp_file)
1269*6236dae4SAndroid Build Coastguard Worker sftp_close(sshc->sftp_file);
1270*6236dae4SAndroid Build Coastguard Worker sshc->sftp_file =
1271*6236dae4SAndroid Build Coastguard Worker sftp_open(sshc->sftp_session, protop->path,
1272*6236dae4SAndroid Build Coastguard Worker flags, (mode_t)data->set.new_file_perms);
1273*6236dae4SAndroid Build Coastguard Worker if(!sshc->sftp_file) {
1274*6236dae4SAndroid Build Coastguard Worker err = sftp_get_error(sshc->sftp_session);
1275*6236dae4SAndroid Build Coastguard Worker
1276*6236dae4SAndroid Build Coastguard Worker if(((err == SSH_FX_NO_SUCH_FILE || err == SSH_FX_FAILURE ||
1277*6236dae4SAndroid Build Coastguard Worker err == SSH_FX_NO_SUCH_PATH)) &&
1278*6236dae4SAndroid Build Coastguard Worker (data->set.ftp_create_missing_dirs &&
1279*6236dae4SAndroid Build Coastguard Worker (strlen(protop->path) > 1))) {
1280*6236dae4SAndroid Build Coastguard Worker /* try to create the path remotely */
1281*6236dae4SAndroid Build Coastguard Worker rc = 0;
1282*6236dae4SAndroid Build Coastguard Worker sshc->secondCreateDirs = 1;
1283*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CREATE_DIRS_INIT);
1284*6236dae4SAndroid Build Coastguard Worker break;
1285*6236dae4SAndroid Build Coastguard Worker }
1286*6236dae4SAndroid Build Coastguard Worker else {
1287*6236dae4SAndroid Build Coastguard Worker MOVE_TO_SFTP_CLOSE_STATE();
1288*6236dae4SAndroid Build Coastguard Worker break;
1289*6236dae4SAndroid Build Coastguard Worker }
1290*6236dae4SAndroid Build Coastguard Worker }
1291*6236dae4SAndroid Build Coastguard Worker
1292*6236dae4SAndroid Build Coastguard Worker /* If we have a restart point then we need to seek to the correct
1293*6236dae4SAndroid Build Coastguard Worker position. */
1294*6236dae4SAndroid Build Coastguard Worker if(data->state.resume_from > 0) {
1295*6236dae4SAndroid Build Coastguard Worker /* Let's read off the proper amount of bytes from the input. */
1296*6236dae4SAndroid Build Coastguard Worker if(data->set.seek_func) {
1297*6236dae4SAndroid Build Coastguard Worker Curl_set_in_callback(data, TRUE);
1298*6236dae4SAndroid Build Coastguard Worker seekerr = data->set.seek_func(data->set.seek_client,
1299*6236dae4SAndroid Build Coastguard Worker data->state.resume_from, SEEK_SET);
1300*6236dae4SAndroid Build Coastguard Worker Curl_set_in_callback(data, FALSE);
1301*6236dae4SAndroid Build Coastguard Worker }
1302*6236dae4SAndroid Build Coastguard Worker
1303*6236dae4SAndroid Build Coastguard Worker if(seekerr != CURL_SEEKFUNC_OK) {
1304*6236dae4SAndroid Build Coastguard Worker curl_off_t passed = 0;
1305*6236dae4SAndroid Build Coastguard Worker
1306*6236dae4SAndroid Build Coastguard Worker if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1307*6236dae4SAndroid Build Coastguard Worker failf(data, "Could not seek stream");
1308*6236dae4SAndroid Build Coastguard Worker return CURLE_FTP_COULDNT_USE_REST;
1309*6236dae4SAndroid Build Coastguard Worker }
1310*6236dae4SAndroid Build Coastguard Worker /* seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */
1311*6236dae4SAndroid Build Coastguard Worker do {
1312*6236dae4SAndroid Build Coastguard Worker char scratch[4*1024];
1313*6236dae4SAndroid Build Coastguard Worker size_t readthisamountnow =
1314*6236dae4SAndroid Build Coastguard Worker (data->state.resume_from - passed >
1315*6236dae4SAndroid Build Coastguard Worker (curl_off_t)sizeof(scratch)) ?
1316*6236dae4SAndroid Build Coastguard Worker sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed);
1317*6236dae4SAndroid Build Coastguard Worker
1318*6236dae4SAndroid Build Coastguard Worker size_t actuallyread =
1319*6236dae4SAndroid Build Coastguard Worker data->state.fread_func(scratch, 1,
1320*6236dae4SAndroid Build Coastguard Worker readthisamountnow, data->state.in);
1321*6236dae4SAndroid Build Coastguard Worker
1322*6236dae4SAndroid Build Coastguard Worker passed += actuallyread;
1323*6236dae4SAndroid Build Coastguard Worker if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1324*6236dae4SAndroid Build Coastguard Worker /* this checks for greater-than only to make sure that the
1325*6236dae4SAndroid Build Coastguard Worker CURL_READFUNC_ABORT return code still aborts */
1326*6236dae4SAndroid Build Coastguard Worker failf(data, "Failed to read data");
1327*6236dae4SAndroid Build Coastguard Worker MOVE_TO_ERROR_STATE(CURLE_FTP_COULDNT_USE_REST);
1328*6236dae4SAndroid Build Coastguard Worker break;
1329*6236dae4SAndroid Build Coastguard Worker }
1330*6236dae4SAndroid Build Coastguard Worker } while(passed < data->state.resume_from);
1331*6236dae4SAndroid Build Coastguard Worker if(rc)
1332*6236dae4SAndroid Build Coastguard Worker break;
1333*6236dae4SAndroid Build Coastguard Worker }
1334*6236dae4SAndroid Build Coastguard Worker
1335*6236dae4SAndroid Build Coastguard Worker /* now, decrease the size of the read */
1336*6236dae4SAndroid Build Coastguard Worker if(data->state.infilesize > 0) {
1337*6236dae4SAndroid Build Coastguard Worker data->state.infilesize -= data->state.resume_from;
1338*6236dae4SAndroid Build Coastguard Worker data->req.size = data->state.infilesize;
1339*6236dae4SAndroid Build Coastguard Worker Curl_pgrsSetUploadSize(data, data->state.infilesize);
1340*6236dae4SAndroid Build Coastguard Worker }
1341*6236dae4SAndroid Build Coastguard Worker
1342*6236dae4SAndroid Build Coastguard Worker rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
1343*6236dae4SAndroid Build Coastguard Worker if(rc) {
1344*6236dae4SAndroid Build Coastguard Worker MOVE_TO_SFTP_CLOSE_STATE();
1345*6236dae4SAndroid Build Coastguard Worker break;
1346*6236dae4SAndroid Build Coastguard Worker }
1347*6236dae4SAndroid Build Coastguard Worker }
1348*6236dae4SAndroid Build Coastguard Worker if(data->state.infilesize > 0) {
1349*6236dae4SAndroid Build Coastguard Worker data->req.size = data->state.infilesize;
1350*6236dae4SAndroid Build Coastguard Worker Curl_pgrsSetUploadSize(data, data->state.infilesize);
1351*6236dae4SAndroid Build Coastguard Worker }
1352*6236dae4SAndroid Build Coastguard Worker /* upload data */
1353*6236dae4SAndroid Build Coastguard Worker Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
1354*6236dae4SAndroid Build Coastguard Worker
1355*6236dae4SAndroid Build Coastguard Worker /* not set by Curl_xfer_setup to preserve keepon bits */
1356*6236dae4SAndroid Build Coastguard Worker conn->sockfd = conn->writesockfd;
1357*6236dae4SAndroid Build Coastguard Worker
1358*6236dae4SAndroid Build Coastguard Worker /* store this original bitmask setup to use later on if we cannot
1359*6236dae4SAndroid Build Coastguard Worker figure out a "real" bitmask */
1360*6236dae4SAndroid Build Coastguard Worker sshc->orig_waitfor = data->req.keepon;
1361*6236dae4SAndroid Build Coastguard Worker
1362*6236dae4SAndroid Build Coastguard Worker /* we want to use the _sending_ function even when the socket turns
1363*6236dae4SAndroid Build Coastguard Worker out readable as the underlying libssh sftp send function will deal
1364*6236dae4SAndroid Build Coastguard Worker with both accordingly */
1365*6236dae4SAndroid Build Coastguard Worker data->state.select_bits = CURL_CSELECT_OUT;
1366*6236dae4SAndroid Build Coastguard Worker
1367*6236dae4SAndroid Build Coastguard Worker /* since we do not really wait for anything at this point, we want the
1368*6236dae4SAndroid Build Coastguard Worker state machine to move on as soon as possible so we set a very short
1369*6236dae4SAndroid Build Coastguard Worker timeout here */
1370*6236dae4SAndroid Build Coastguard Worker Curl_expire(data, 0, EXPIRE_RUN_NOW);
1371*6236dae4SAndroid Build Coastguard Worker
1372*6236dae4SAndroid Build Coastguard Worker state(data, SSH_STOP);
1373*6236dae4SAndroid Build Coastguard Worker break;
1374*6236dae4SAndroid Build Coastguard Worker }
1375*6236dae4SAndroid Build Coastguard Worker
1376*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_CREATE_DIRS_INIT:
1377*6236dae4SAndroid Build Coastguard Worker if(strlen(protop->path) > 1) {
1378*6236dae4SAndroid Build Coastguard Worker sshc->slash_pos = protop->path + 1; /* ignore the leading '/' */
1379*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CREATE_DIRS);
1380*6236dae4SAndroid Build Coastguard Worker }
1381*6236dae4SAndroid Build Coastguard Worker else {
1382*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_UPLOAD_INIT);
1383*6236dae4SAndroid Build Coastguard Worker }
1384*6236dae4SAndroid Build Coastguard Worker break;
1385*6236dae4SAndroid Build Coastguard Worker
1386*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_CREATE_DIRS:
1387*6236dae4SAndroid Build Coastguard Worker sshc->slash_pos = strchr(sshc->slash_pos, '/');
1388*6236dae4SAndroid Build Coastguard Worker if(sshc->slash_pos) {
1389*6236dae4SAndroid Build Coastguard Worker *sshc->slash_pos = 0;
1390*6236dae4SAndroid Build Coastguard Worker
1391*6236dae4SAndroid Build Coastguard Worker infof(data, "Creating directory '%s'", protop->path);
1392*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CREATE_DIRS_MKDIR);
1393*6236dae4SAndroid Build Coastguard Worker break;
1394*6236dae4SAndroid Build Coastguard Worker }
1395*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_UPLOAD_INIT);
1396*6236dae4SAndroid Build Coastguard Worker break;
1397*6236dae4SAndroid Build Coastguard Worker
1398*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_CREATE_DIRS_MKDIR:
1399*6236dae4SAndroid Build Coastguard Worker /* 'mode' - parameter is preliminary - default to 0644 */
1400*6236dae4SAndroid Build Coastguard Worker rc = sftp_mkdir(sshc->sftp_session, protop->path,
1401*6236dae4SAndroid Build Coastguard Worker (mode_t)data->set.new_directory_perms);
1402*6236dae4SAndroid Build Coastguard Worker *sshc->slash_pos = '/';
1403*6236dae4SAndroid Build Coastguard Worker ++sshc->slash_pos;
1404*6236dae4SAndroid Build Coastguard Worker if(rc < 0) {
1405*6236dae4SAndroid Build Coastguard Worker /*
1406*6236dae4SAndroid Build Coastguard Worker * Abort if failure was not that the dir already exists or the
1407*6236dae4SAndroid Build Coastguard Worker * permission was denied (creation might succeed further down the
1408*6236dae4SAndroid Build Coastguard Worker * path) - retry on unspecific FAILURE also
1409*6236dae4SAndroid Build Coastguard Worker */
1410*6236dae4SAndroid Build Coastguard Worker err = sftp_get_error(sshc->sftp_session);
1411*6236dae4SAndroid Build Coastguard Worker if((err != SSH_FX_FILE_ALREADY_EXISTS) &&
1412*6236dae4SAndroid Build Coastguard Worker (err != SSH_FX_FAILURE) &&
1413*6236dae4SAndroid Build Coastguard Worker (err != SSH_FX_PERMISSION_DENIED)) {
1414*6236dae4SAndroid Build Coastguard Worker MOVE_TO_SFTP_CLOSE_STATE();
1415*6236dae4SAndroid Build Coastguard Worker break;
1416*6236dae4SAndroid Build Coastguard Worker }
1417*6236dae4SAndroid Build Coastguard Worker rc = 0; /* clear rc and continue */
1418*6236dae4SAndroid Build Coastguard Worker }
1419*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CREATE_DIRS);
1420*6236dae4SAndroid Build Coastguard Worker break;
1421*6236dae4SAndroid Build Coastguard Worker
1422*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_READDIR_INIT:
1423*6236dae4SAndroid Build Coastguard Worker Curl_pgrsSetDownloadSize(data, -1);
1424*6236dae4SAndroid Build Coastguard Worker if(data->req.no_body) {
1425*6236dae4SAndroid Build Coastguard Worker state(data, SSH_STOP);
1426*6236dae4SAndroid Build Coastguard Worker break;
1427*6236dae4SAndroid Build Coastguard Worker }
1428*6236dae4SAndroid Build Coastguard Worker
1429*6236dae4SAndroid Build Coastguard Worker /*
1430*6236dae4SAndroid Build Coastguard Worker * This is a directory that we are trying to get, so produce a directory
1431*6236dae4SAndroid Build Coastguard Worker * listing
1432*6236dae4SAndroid Build Coastguard Worker */
1433*6236dae4SAndroid Build Coastguard Worker sshc->sftp_dir = sftp_opendir(sshc->sftp_session,
1434*6236dae4SAndroid Build Coastguard Worker protop->path);
1435*6236dae4SAndroid Build Coastguard Worker if(!sshc->sftp_dir) {
1436*6236dae4SAndroid Build Coastguard Worker failf(data, "Could not open directory for reading: %s",
1437*6236dae4SAndroid Build Coastguard Worker ssh_get_error(sshc->ssh_session));
1438*6236dae4SAndroid Build Coastguard Worker MOVE_TO_SFTP_CLOSE_STATE();
1439*6236dae4SAndroid Build Coastguard Worker break;
1440*6236dae4SAndroid Build Coastguard Worker }
1441*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_READDIR);
1442*6236dae4SAndroid Build Coastguard Worker break;
1443*6236dae4SAndroid Build Coastguard Worker
1444*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_READDIR:
1445*6236dae4SAndroid Build Coastguard Worker Curl_dyn_reset(&sshc->readdir_buf);
1446*6236dae4SAndroid Build Coastguard Worker if(sshc->readdir_attrs)
1447*6236dae4SAndroid Build Coastguard Worker sftp_attributes_free(sshc->readdir_attrs);
1448*6236dae4SAndroid Build Coastguard Worker
1449*6236dae4SAndroid Build Coastguard Worker sshc->readdir_attrs = sftp_readdir(sshc->sftp_session, sshc->sftp_dir);
1450*6236dae4SAndroid Build Coastguard Worker if(sshc->readdir_attrs) {
1451*6236dae4SAndroid Build Coastguard Worker sshc->readdir_filename = sshc->readdir_attrs->name;
1452*6236dae4SAndroid Build Coastguard Worker sshc->readdir_longentry = sshc->readdir_attrs->longname;
1453*6236dae4SAndroid Build Coastguard Worker sshc->readdir_len = strlen(sshc->readdir_filename);
1454*6236dae4SAndroid Build Coastguard Worker
1455*6236dae4SAndroid Build Coastguard Worker if(data->set.list_only) {
1456*6236dae4SAndroid Build Coastguard Worker char *tmpLine;
1457*6236dae4SAndroid Build Coastguard Worker
1458*6236dae4SAndroid Build Coastguard Worker tmpLine = aprintf("%s\n", sshc->readdir_filename);
1459*6236dae4SAndroid Build Coastguard Worker if(!tmpLine) {
1460*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
1461*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = CURLE_OUT_OF_MEMORY;
1462*6236dae4SAndroid Build Coastguard Worker break;
1463*6236dae4SAndroid Build Coastguard Worker }
1464*6236dae4SAndroid Build Coastguard Worker result = Curl_client_write(data, CLIENTWRITE_BODY,
1465*6236dae4SAndroid Build Coastguard Worker tmpLine, sshc->readdir_len + 1);
1466*6236dae4SAndroid Build Coastguard Worker free(tmpLine);
1467*6236dae4SAndroid Build Coastguard Worker
1468*6236dae4SAndroid Build Coastguard Worker if(result) {
1469*6236dae4SAndroid Build Coastguard Worker state(data, SSH_STOP);
1470*6236dae4SAndroid Build Coastguard Worker break;
1471*6236dae4SAndroid Build Coastguard Worker }
1472*6236dae4SAndroid Build Coastguard Worker
1473*6236dae4SAndroid Build Coastguard Worker }
1474*6236dae4SAndroid Build Coastguard Worker else {
1475*6236dae4SAndroid Build Coastguard Worker if(Curl_dyn_add(&sshc->readdir_buf, sshc->readdir_longentry)) {
1476*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = CURLE_OUT_OF_MEMORY;
1477*6236dae4SAndroid Build Coastguard Worker state(data, SSH_STOP);
1478*6236dae4SAndroid Build Coastguard Worker break;
1479*6236dae4SAndroid Build Coastguard Worker }
1480*6236dae4SAndroid Build Coastguard Worker
1481*6236dae4SAndroid Build Coastguard Worker if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
1482*6236dae4SAndroid Build Coastguard Worker ((sshc->readdir_attrs->permissions & SSH_S_IFMT) ==
1483*6236dae4SAndroid Build Coastguard Worker SSH_S_IFLNK)) {
1484*6236dae4SAndroid Build Coastguard Worker sshc->readdir_linkPath = aprintf("%s%s", protop->path,
1485*6236dae4SAndroid Build Coastguard Worker sshc->readdir_filename);
1486*6236dae4SAndroid Build Coastguard Worker
1487*6236dae4SAndroid Build Coastguard Worker if(!sshc->readdir_linkPath) {
1488*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
1489*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = CURLE_OUT_OF_MEMORY;
1490*6236dae4SAndroid Build Coastguard Worker break;
1491*6236dae4SAndroid Build Coastguard Worker }
1492*6236dae4SAndroid Build Coastguard Worker
1493*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_READDIR_LINK);
1494*6236dae4SAndroid Build Coastguard Worker break;
1495*6236dae4SAndroid Build Coastguard Worker }
1496*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_READDIR_BOTTOM);
1497*6236dae4SAndroid Build Coastguard Worker break;
1498*6236dae4SAndroid Build Coastguard Worker }
1499*6236dae4SAndroid Build Coastguard Worker }
1500*6236dae4SAndroid Build Coastguard Worker else if(sftp_dir_eof(sshc->sftp_dir)) {
1501*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_READDIR_DONE);
1502*6236dae4SAndroid Build Coastguard Worker break;
1503*6236dae4SAndroid Build Coastguard Worker }
1504*6236dae4SAndroid Build Coastguard Worker else {
1505*6236dae4SAndroid Build Coastguard Worker failf(data, "Could not open remote file for reading: %s",
1506*6236dae4SAndroid Build Coastguard Worker ssh_get_error(sshc->ssh_session));
1507*6236dae4SAndroid Build Coastguard Worker MOVE_TO_SFTP_CLOSE_STATE();
1508*6236dae4SAndroid Build Coastguard Worker break;
1509*6236dae4SAndroid Build Coastguard Worker }
1510*6236dae4SAndroid Build Coastguard Worker break;
1511*6236dae4SAndroid Build Coastguard Worker
1512*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_READDIR_LINK:
1513*6236dae4SAndroid Build Coastguard Worker if(sshc->readdir_link_attrs)
1514*6236dae4SAndroid Build Coastguard Worker sftp_attributes_free(sshc->readdir_link_attrs);
1515*6236dae4SAndroid Build Coastguard Worker
1516*6236dae4SAndroid Build Coastguard Worker sshc->readdir_link_attrs = sftp_lstat(sshc->sftp_session,
1517*6236dae4SAndroid Build Coastguard Worker sshc->readdir_linkPath);
1518*6236dae4SAndroid Build Coastguard Worker if(sshc->readdir_link_attrs == 0) {
1519*6236dae4SAndroid Build Coastguard Worker failf(data, "Could not read symlink for reading: %s",
1520*6236dae4SAndroid Build Coastguard Worker ssh_get_error(sshc->ssh_session));
1521*6236dae4SAndroid Build Coastguard Worker MOVE_TO_SFTP_CLOSE_STATE();
1522*6236dae4SAndroid Build Coastguard Worker break;
1523*6236dae4SAndroid Build Coastguard Worker }
1524*6236dae4SAndroid Build Coastguard Worker
1525*6236dae4SAndroid Build Coastguard Worker if(!sshc->readdir_link_attrs->name) {
1526*6236dae4SAndroid Build Coastguard Worker sshc->readdir_tmp = sftp_readlink(sshc->sftp_session,
1527*6236dae4SAndroid Build Coastguard Worker sshc->readdir_linkPath);
1528*6236dae4SAndroid Build Coastguard Worker if(!sshc->readdir_filename)
1529*6236dae4SAndroid Build Coastguard Worker sshc->readdir_len = 0;
1530*6236dae4SAndroid Build Coastguard Worker else
1531*6236dae4SAndroid Build Coastguard Worker sshc->readdir_len = strlen(sshc->readdir_tmp);
1532*6236dae4SAndroid Build Coastguard Worker sshc->readdir_longentry = NULL;
1533*6236dae4SAndroid Build Coastguard Worker sshc->readdir_filename = sshc->readdir_tmp;
1534*6236dae4SAndroid Build Coastguard Worker }
1535*6236dae4SAndroid Build Coastguard Worker else {
1536*6236dae4SAndroid Build Coastguard Worker sshc->readdir_len = strlen(sshc->readdir_link_attrs->name);
1537*6236dae4SAndroid Build Coastguard Worker sshc->readdir_filename = sshc->readdir_link_attrs->name;
1538*6236dae4SAndroid Build Coastguard Worker sshc->readdir_longentry = sshc->readdir_link_attrs->longname;
1539*6236dae4SAndroid Build Coastguard Worker }
1540*6236dae4SAndroid Build Coastguard Worker
1541*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->readdir_linkPath);
1542*6236dae4SAndroid Build Coastguard Worker
1543*6236dae4SAndroid Build Coastguard Worker if(Curl_dyn_addf(&sshc->readdir_buf, " -> %s",
1544*6236dae4SAndroid Build Coastguard Worker sshc->readdir_filename)) {
1545*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = CURLE_OUT_OF_MEMORY;
1546*6236dae4SAndroid Build Coastguard Worker break;
1547*6236dae4SAndroid Build Coastguard Worker }
1548*6236dae4SAndroid Build Coastguard Worker
1549*6236dae4SAndroid Build Coastguard Worker sftp_attributes_free(sshc->readdir_link_attrs);
1550*6236dae4SAndroid Build Coastguard Worker sshc->readdir_link_attrs = NULL;
1551*6236dae4SAndroid Build Coastguard Worker sshc->readdir_filename = NULL;
1552*6236dae4SAndroid Build Coastguard Worker sshc->readdir_longentry = NULL;
1553*6236dae4SAndroid Build Coastguard Worker
1554*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_READDIR_BOTTOM);
1555*6236dae4SAndroid Build Coastguard Worker FALLTHROUGH();
1556*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_READDIR_BOTTOM:
1557*6236dae4SAndroid Build Coastguard Worker if(Curl_dyn_addn(&sshc->readdir_buf, "\n", 1))
1558*6236dae4SAndroid Build Coastguard Worker result = CURLE_OUT_OF_MEMORY;
1559*6236dae4SAndroid Build Coastguard Worker else
1560*6236dae4SAndroid Build Coastguard Worker result = Curl_client_write(data, CLIENTWRITE_BODY,
1561*6236dae4SAndroid Build Coastguard Worker Curl_dyn_ptr(&sshc->readdir_buf),
1562*6236dae4SAndroid Build Coastguard Worker Curl_dyn_len(&sshc->readdir_buf));
1563*6236dae4SAndroid Build Coastguard Worker
1564*6236dae4SAndroid Build Coastguard Worker ssh_string_free_char(sshc->readdir_tmp);
1565*6236dae4SAndroid Build Coastguard Worker sshc->readdir_tmp = NULL;
1566*6236dae4SAndroid Build Coastguard Worker
1567*6236dae4SAndroid Build Coastguard Worker if(result) {
1568*6236dae4SAndroid Build Coastguard Worker state(data, SSH_STOP);
1569*6236dae4SAndroid Build Coastguard Worker }
1570*6236dae4SAndroid Build Coastguard Worker else
1571*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_READDIR);
1572*6236dae4SAndroid Build Coastguard Worker break;
1573*6236dae4SAndroid Build Coastguard Worker
1574*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_READDIR_DONE:
1575*6236dae4SAndroid Build Coastguard Worker sftp_closedir(sshc->sftp_dir);
1576*6236dae4SAndroid Build Coastguard Worker sshc->sftp_dir = NULL;
1577*6236dae4SAndroid Build Coastguard Worker
1578*6236dae4SAndroid Build Coastguard Worker /* no data to transfer */
1579*6236dae4SAndroid Build Coastguard Worker Curl_xfer_setup_nop(data);
1580*6236dae4SAndroid Build Coastguard Worker state(data, SSH_STOP);
1581*6236dae4SAndroid Build Coastguard Worker break;
1582*6236dae4SAndroid Build Coastguard Worker
1583*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_DOWNLOAD_INIT:
1584*6236dae4SAndroid Build Coastguard Worker /*
1585*6236dae4SAndroid Build Coastguard Worker * Work on getting the specified file
1586*6236dae4SAndroid Build Coastguard Worker */
1587*6236dae4SAndroid Build Coastguard Worker if(sshc->sftp_file)
1588*6236dae4SAndroid Build Coastguard Worker sftp_close(sshc->sftp_file);
1589*6236dae4SAndroid Build Coastguard Worker
1590*6236dae4SAndroid Build Coastguard Worker sshc->sftp_file = sftp_open(sshc->sftp_session, protop->path,
1591*6236dae4SAndroid Build Coastguard Worker O_RDONLY, (mode_t)data->set.new_file_perms);
1592*6236dae4SAndroid Build Coastguard Worker if(!sshc->sftp_file) {
1593*6236dae4SAndroid Build Coastguard Worker failf(data, "Could not open remote file for reading: %s",
1594*6236dae4SAndroid Build Coastguard Worker ssh_get_error(sshc->ssh_session));
1595*6236dae4SAndroid Build Coastguard Worker
1596*6236dae4SAndroid Build Coastguard Worker MOVE_TO_SFTP_CLOSE_STATE();
1597*6236dae4SAndroid Build Coastguard Worker break;
1598*6236dae4SAndroid Build Coastguard Worker }
1599*6236dae4SAndroid Build Coastguard Worker sftp_file_set_nonblocking(sshc->sftp_file);
1600*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_DOWNLOAD_STAT);
1601*6236dae4SAndroid Build Coastguard Worker break;
1602*6236dae4SAndroid Build Coastguard Worker
1603*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_DOWNLOAD_STAT:
1604*6236dae4SAndroid Build Coastguard Worker {
1605*6236dae4SAndroid Build Coastguard Worker sftp_attributes attrs;
1606*6236dae4SAndroid Build Coastguard Worker curl_off_t size;
1607*6236dae4SAndroid Build Coastguard Worker
1608*6236dae4SAndroid Build Coastguard Worker attrs = sftp_fstat(sshc->sftp_file);
1609*6236dae4SAndroid Build Coastguard Worker if(!attrs ||
1610*6236dae4SAndroid Build Coastguard Worker !(attrs->flags & SSH_FILEXFER_ATTR_SIZE) ||
1611*6236dae4SAndroid Build Coastguard Worker (attrs->size == 0)) {
1612*6236dae4SAndroid Build Coastguard Worker /*
1613*6236dae4SAndroid Build Coastguard Worker * sftp_fstat did not return an error, so maybe the server
1614*6236dae4SAndroid Build Coastguard Worker * just does not support stat()
1615*6236dae4SAndroid Build Coastguard Worker * OR the server does not return a file size with a stat()
1616*6236dae4SAndroid Build Coastguard Worker * OR file size is 0
1617*6236dae4SAndroid Build Coastguard Worker */
1618*6236dae4SAndroid Build Coastguard Worker data->req.size = -1;
1619*6236dae4SAndroid Build Coastguard Worker data->req.maxdownload = -1;
1620*6236dae4SAndroid Build Coastguard Worker Curl_pgrsSetDownloadSize(data, -1);
1621*6236dae4SAndroid Build Coastguard Worker size = 0;
1622*6236dae4SAndroid Build Coastguard Worker }
1623*6236dae4SAndroid Build Coastguard Worker else {
1624*6236dae4SAndroid Build Coastguard Worker size = attrs->size;
1625*6236dae4SAndroid Build Coastguard Worker
1626*6236dae4SAndroid Build Coastguard Worker sftp_attributes_free(attrs);
1627*6236dae4SAndroid Build Coastguard Worker
1628*6236dae4SAndroid Build Coastguard Worker if(size < 0) {
1629*6236dae4SAndroid Build Coastguard Worker failf(data, "Bad file size (%" FMT_OFF_T ")", size);
1630*6236dae4SAndroid Build Coastguard Worker return CURLE_BAD_DOWNLOAD_RESUME;
1631*6236dae4SAndroid Build Coastguard Worker }
1632*6236dae4SAndroid Build Coastguard Worker if(data->state.use_range) {
1633*6236dae4SAndroid Build Coastguard Worker curl_off_t from, to;
1634*6236dae4SAndroid Build Coastguard Worker char *ptr;
1635*6236dae4SAndroid Build Coastguard Worker char *ptr2;
1636*6236dae4SAndroid Build Coastguard Worker CURLofft to_t;
1637*6236dae4SAndroid Build Coastguard Worker CURLofft from_t;
1638*6236dae4SAndroid Build Coastguard Worker
1639*6236dae4SAndroid Build Coastguard Worker from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from);
1640*6236dae4SAndroid Build Coastguard Worker if(from_t == CURL_OFFT_FLOW) {
1641*6236dae4SAndroid Build Coastguard Worker return CURLE_RANGE_ERROR;
1642*6236dae4SAndroid Build Coastguard Worker }
1643*6236dae4SAndroid Build Coastguard Worker while(*ptr && (ISBLANK(*ptr) || (*ptr == '-')))
1644*6236dae4SAndroid Build Coastguard Worker ptr++;
1645*6236dae4SAndroid Build Coastguard Worker to_t = curlx_strtoofft(ptr, &ptr2, 10, &to);
1646*6236dae4SAndroid Build Coastguard Worker if(to_t == CURL_OFFT_FLOW) {
1647*6236dae4SAndroid Build Coastguard Worker return CURLE_RANGE_ERROR;
1648*6236dae4SAndroid Build Coastguard Worker }
1649*6236dae4SAndroid Build Coastguard Worker if((to_t == CURL_OFFT_INVAL) /* no "to" value given */
1650*6236dae4SAndroid Build Coastguard Worker || (to >= size)) {
1651*6236dae4SAndroid Build Coastguard Worker to = size - 1;
1652*6236dae4SAndroid Build Coastguard Worker }
1653*6236dae4SAndroid Build Coastguard Worker if(from_t) {
1654*6236dae4SAndroid Build Coastguard Worker /* from is relative to end of file */
1655*6236dae4SAndroid Build Coastguard Worker from = size - to;
1656*6236dae4SAndroid Build Coastguard Worker to = size - 1;
1657*6236dae4SAndroid Build Coastguard Worker }
1658*6236dae4SAndroid Build Coastguard Worker if(from > size) {
1659*6236dae4SAndroid Build Coastguard Worker failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
1660*6236dae4SAndroid Build Coastguard Worker FMT_OFF_T ")", from, size);
1661*6236dae4SAndroid Build Coastguard Worker return CURLE_BAD_DOWNLOAD_RESUME;
1662*6236dae4SAndroid Build Coastguard Worker }
1663*6236dae4SAndroid Build Coastguard Worker if(from > to) {
1664*6236dae4SAndroid Build Coastguard Worker from = to;
1665*6236dae4SAndroid Build Coastguard Worker size = 0;
1666*6236dae4SAndroid Build Coastguard Worker }
1667*6236dae4SAndroid Build Coastguard Worker else {
1668*6236dae4SAndroid Build Coastguard Worker if((to - from) == CURL_OFF_T_MAX)
1669*6236dae4SAndroid Build Coastguard Worker return CURLE_RANGE_ERROR;
1670*6236dae4SAndroid Build Coastguard Worker size = to - from + 1;
1671*6236dae4SAndroid Build Coastguard Worker }
1672*6236dae4SAndroid Build Coastguard Worker
1673*6236dae4SAndroid Build Coastguard Worker rc = sftp_seek64(sshc->sftp_file, from);
1674*6236dae4SAndroid Build Coastguard Worker if(rc) {
1675*6236dae4SAndroid Build Coastguard Worker MOVE_TO_SFTP_CLOSE_STATE();
1676*6236dae4SAndroid Build Coastguard Worker break;
1677*6236dae4SAndroid Build Coastguard Worker }
1678*6236dae4SAndroid Build Coastguard Worker }
1679*6236dae4SAndroid Build Coastguard Worker data->req.size = size;
1680*6236dae4SAndroid Build Coastguard Worker data->req.maxdownload = size;
1681*6236dae4SAndroid Build Coastguard Worker Curl_pgrsSetDownloadSize(data, size);
1682*6236dae4SAndroid Build Coastguard Worker }
1683*6236dae4SAndroid Build Coastguard Worker
1684*6236dae4SAndroid Build Coastguard Worker /* We can resume if we can seek to the resume position */
1685*6236dae4SAndroid Build Coastguard Worker if(data->state.resume_from) {
1686*6236dae4SAndroid Build Coastguard Worker if(data->state.resume_from < 0) {
1687*6236dae4SAndroid Build Coastguard Worker /* We are supposed to download the last abs(from) bytes */
1688*6236dae4SAndroid Build Coastguard Worker if((curl_off_t)size < -data->state.resume_from) {
1689*6236dae4SAndroid Build Coastguard Worker failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
1690*6236dae4SAndroid Build Coastguard Worker FMT_OFF_T ")", data->state.resume_from, size);
1691*6236dae4SAndroid Build Coastguard Worker return CURLE_BAD_DOWNLOAD_RESUME;
1692*6236dae4SAndroid Build Coastguard Worker }
1693*6236dae4SAndroid Build Coastguard Worker /* download from where? */
1694*6236dae4SAndroid Build Coastguard Worker data->state.resume_from += size;
1695*6236dae4SAndroid Build Coastguard Worker }
1696*6236dae4SAndroid Build Coastguard Worker else {
1697*6236dae4SAndroid Build Coastguard Worker if((curl_off_t)size < data->state.resume_from) {
1698*6236dae4SAndroid Build Coastguard Worker failf(data, "Offset (%" FMT_OFF_T
1699*6236dae4SAndroid Build Coastguard Worker ") was beyond file size (%" FMT_OFF_T ")",
1700*6236dae4SAndroid Build Coastguard Worker data->state.resume_from, size);
1701*6236dae4SAndroid Build Coastguard Worker return CURLE_BAD_DOWNLOAD_RESUME;
1702*6236dae4SAndroid Build Coastguard Worker }
1703*6236dae4SAndroid Build Coastguard Worker }
1704*6236dae4SAndroid Build Coastguard Worker /* Now store the number of bytes we are expected to download */
1705*6236dae4SAndroid Build Coastguard Worker data->req.size = size - data->state.resume_from;
1706*6236dae4SAndroid Build Coastguard Worker data->req.maxdownload = size - data->state.resume_from;
1707*6236dae4SAndroid Build Coastguard Worker Curl_pgrsSetDownloadSize(data,
1708*6236dae4SAndroid Build Coastguard Worker size - data->state.resume_from);
1709*6236dae4SAndroid Build Coastguard Worker
1710*6236dae4SAndroid Build Coastguard Worker rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
1711*6236dae4SAndroid Build Coastguard Worker if(rc) {
1712*6236dae4SAndroid Build Coastguard Worker MOVE_TO_SFTP_CLOSE_STATE();
1713*6236dae4SAndroid Build Coastguard Worker break;
1714*6236dae4SAndroid Build Coastguard Worker }
1715*6236dae4SAndroid Build Coastguard Worker }
1716*6236dae4SAndroid Build Coastguard Worker }
1717*6236dae4SAndroid Build Coastguard Worker
1718*6236dae4SAndroid Build Coastguard Worker /* Setup the actual download */
1719*6236dae4SAndroid Build Coastguard Worker if(data->req.size == 0) {
1720*6236dae4SAndroid Build Coastguard Worker /* no data to transfer */
1721*6236dae4SAndroid Build Coastguard Worker Curl_xfer_setup_nop(data);
1722*6236dae4SAndroid Build Coastguard Worker infof(data, "File already completely downloaded");
1723*6236dae4SAndroid Build Coastguard Worker state(data, SSH_STOP);
1724*6236dae4SAndroid Build Coastguard Worker break;
1725*6236dae4SAndroid Build Coastguard Worker }
1726*6236dae4SAndroid Build Coastguard Worker Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE);
1727*6236dae4SAndroid Build Coastguard Worker
1728*6236dae4SAndroid Build Coastguard Worker /* not set by Curl_xfer_setup to preserve keepon bits */
1729*6236dae4SAndroid Build Coastguard Worker conn->writesockfd = conn->sockfd;
1730*6236dae4SAndroid Build Coastguard Worker
1731*6236dae4SAndroid Build Coastguard Worker /* we want to use the _receiving_ function even when the socket turns
1732*6236dae4SAndroid Build Coastguard Worker out writableable as the underlying libssh recv function will deal
1733*6236dae4SAndroid Build Coastguard Worker with both accordingly */
1734*6236dae4SAndroid Build Coastguard Worker data->state.select_bits = CURL_CSELECT_IN;
1735*6236dae4SAndroid Build Coastguard Worker
1736*6236dae4SAndroid Build Coastguard Worker if(result) {
1737*6236dae4SAndroid Build Coastguard Worker /* this should never occur; the close state should be entered
1738*6236dae4SAndroid Build Coastguard Worker at the time the error occurs */
1739*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
1740*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = result;
1741*6236dae4SAndroid Build Coastguard Worker }
1742*6236dae4SAndroid Build Coastguard Worker else {
1743*6236dae4SAndroid Build Coastguard Worker sshc->sftp_recv_state = 0;
1744*6236dae4SAndroid Build Coastguard Worker state(data, SSH_STOP);
1745*6236dae4SAndroid Build Coastguard Worker }
1746*6236dae4SAndroid Build Coastguard Worker break;
1747*6236dae4SAndroid Build Coastguard Worker
1748*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_CLOSE:
1749*6236dae4SAndroid Build Coastguard Worker if(sshc->sftp_file) {
1750*6236dae4SAndroid Build Coastguard Worker sftp_close(sshc->sftp_file);
1751*6236dae4SAndroid Build Coastguard Worker sshc->sftp_file = NULL;
1752*6236dae4SAndroid Build Coastguard Worker }
1753*6236dae4SAndroid Build Coastguard Worker Curl_safefree(protop->path);
1754*6236dae4SAndroid Build Coastguard Worker
1755*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "SFTP DONE done"));
1756*6236dae4SAndroid Build Coastguard Worker
1757*6236dae4SAndroid Build Coastguard Worker /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT
1758*6236dae4SAndroid Build Coastguard Worker After nextstate is executed, the control should come back to
1759*6236dae4SAndroid Build Coastguard Worker SSH_SFTP_CLOSE to pass the correct result back */
1760*6236dae4SAndroid Build Coastguard Worker if(sshc->nextstate != SSH_NO_STATE &&
1761*6236dae4SAndroid Build Coastguard Worker sshc->nextstate != SSH_SFTP_CLOSE) {
1762*6236dae4SAndroid Build Coastguard Worker state(data, sshc->nextstate);
1763*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_SFTP_CLOSE;
1764*6236dae4SAndroid Build Coastguard Worker }
1765*6236dae4SAndroid Build Coastguard Worker else {
1766*6236dae4SAndroid Build Coastguard Worker state(data, SSH_STOP);
1767*6236dae4SAndroid Build Coastguard Worker result = sshc->actualcode;
1768*6236dae4SAndroid Build Coastguard Worker }
1769*6236dae4SAndroid Build Coastguard Worker break;
1770*6236dae4SAndroid Build Coastguard Worker
1771*6236dae4SAndroid Build Coastguard Worker case SSH_SFTP_SHUTDOWN:
1772*6236dae4SAndroid Build Coastguard Worker /* during times we get here due to a broken transfer and then the
1773*6236dae4SAndroid Build Coastguard Worker sftp_handle might not have been taken down so make sure that is done
1774*6236dae4SAndroid Build Coastguard Worker before we proceed */
1775*6236dae4SAndroid Build Coastguard Worker
1776*6236dae4SAndroid Build Coastguard Worker if(sshc->sftp_file) {
1777*6236dae4SAndroid Build Coastguard Worker sftp_close(sshc->sftp_file);
1778*6236dae4SAndroid Build Coastguard Worker sshc->sftp_file = NULL;
1779*6236dae4SAndroid Build Coastguard Worker }
1780*6236dae4SAndroid Build Coastguard Worker
1781*6236dae4SAndroid Build Coastguard Worker if(sshc->sftp_session) {
1782*6236dae4SAndroid Build Coastguard Worker sftp_free(sshc->sftp_session);
1783*6236dae4SAndroid Build Coastguard Worker sshc->sftp_session = NULL;
1784*6236dae4SAndroid Build Coastguard Worker }
1785*6236dae4SAndroid Build Coastguard Worker
1786*6236dae4SAndroid Build Coastguard Worker SSH_STRING_FREE_CHAR(sshc->homedir);
1787*6236dae4SAndroid Build Coastguard Worker data->state.most_recent_ftp_entrypath = NULL;
1788*6236dae4SAndroid Build Coastguard Worker
1789*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SESSION_DISCONNECT);
1790*6236dae4SAndroid Build Coastguard Worker break;
1791*6236dae4SAndroid Build Coastguard Worker
1792*6236dae4SAndroid Build Coastguard Worker case SSH_SCP_TRANS_INIT:
1793*6236dae4SAndroid Build Coastguard Worker result = Curl_getworkingpath(data, sshc->homedir, &protop->path);
1794*6236dae4SAndroid Build Coastguard Worker if(result) {
1795*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = result;
1796*6236dae4SAndroid Build Coastguard Worker state(data, SSH_STOP);
1797*6236dae4SAndroid Build Coastguard Worker break;
1798*6236dae4SAndroid Build Coastguard Worker }
1799*6236dae4SAndroid Build Coastguard Worker
1800*6236dae4SAndroid Build Coastguard Worker /* Functions from the SCP subsystem cannot handle/return SSH_AGAIN */
1801*6236dae4SAndroid Build Coastguard Worker ssh_set_blocking(sshc->ssh_session, 1);
1802*6236dae4SAndroid Build Coastguard Worker
1803*6236dae4SAndroid Build Coastguard Worker if(data->state.upload) {
1804*6236dae4SAndroid Build Coastguard Worker if(data->state.infilesize < 0) {
1805*6236dae4SAndroid Build Coastguard Worker failf(data, "SCP requires a known file size for upload");
1806*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = CURLE_UPLOAD_FAILED;
1807*6236dae4SAndroid Build Coastguard Worker MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1808*6236dae4SAndroid Build Coastguard Worker break;
1809*6236dae4SAndroid Build Coastguard Worker }
1810*6236dae4SAndroid Build Coastguard Worker
1811*6236dae4SAndroid Build Coastguard Worker sshc->scp_session =
1812*6236dae4SAndroid Build Coastguard Worker ssh_scp_new(sshc->ssh_session, SSH_SCP_WRITE, protop->path);
1813*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SCP_UPLOAD_INIT);
1814*6236dae4SAndroid Build Coastguard Worker }
1815*6236dae4SAndroid Build Coastguard Worker else {
1816*6236dae4SAndroid Build Coastguard Worker sshc->scp_session =
1817*6236dae4SAndroid Build Coastguard Worker ssh_scp_new(sshc->ssh_session, SSH_SCP_READ, protop->path);
1818*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SCP_DOWNLOAD_INIT);
1819*6236dae4SAndroid Build Coastguard Worker }
1820*6236dae4SAndroid Build Coastguard Worker
1821*6236dae4SAndroid Build Coastguard Worker if(!sshc->scp_session) {
1822*6236dae4SAndroid Build Coastguard Worker err_msg = ssh_get_error(sshc->ssh_session);
1823*6236dae4SAndroid Build Coastguard Worker failf(data, "%s", err_msg);
1824*6236dae4SAndroid Build Coastguard Worker MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1825*6236dae4SAndroid Build Coastguard Worker }
1826*6236dae4SAndroid Build Coastguard Worker
1827*6236dae4SAndroid Build Coastguard Worker break;
1828*6236dae4SAndroid Build Coastguard Worker
1829*6236dae4SAndroid Build Coastguard Worker case SSH_SCP_UPLOAD_INIT:
1830*6236dae4SAndroid Build Coastguard Worker
1831*6236dae4SAndroid Build Coastguard Worker rc = ssh_scp_init(sshc->scp_session);
1832*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_OK) {
1833*6236dae4SAndroid Build Coastguard Worker err_msg = ssh_get_error(sshc->ssh_session);
1834*6236dae4SAndroid Build Coastguard Worker failf(data, "%s", err_msg);
1835*6236dae4SAndroid Build Coastguard Worker MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1836*6236dae4SAndroid Build Coastguard Worker break;
1837*6236dae4SAndroid Build Coastguard Worker }
1838*6236dae4SAndroid Build Coastguard Worker
1839*6236dae4SAndroid Build Coastguard Worker rc = ssh_scp_push_file(sshc->scp_session, protop->path,
1840*6236dae4SAndroid Build Coastguard Worker data->state.infilesize,
1841*6236dae4SAndroid Build Coastguard Worker (int)data->set.new_file_perms);
1842*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_OK) {
1843*6236dae4SAndroid Build Coastguard Worker err_msg = ssh_get_error(sshc->ssh_session);
1844*6236dae4SAndroid Build Coastguard Worker failf(data, "%s", err_msg);
1845*6236dae4SAndroid Build Coastguard Worker MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1846*6236dae4SAndroid Build Coastguard Worker break;
1847*6236dae4SAndroid Build Coastguard Worker }
1848*6236dae4SAndroid Build Coastguard Worker
1849*6236dae4SAndroid Build Coastguard Worker /* upload data */
1850*6236dae4SAndroid Build Coastguard Worker Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
1851*6236dae4SAndroid Build Coastguard Worker
1852*6236dae4SAndroid Build Coastguard Worker /* not set by Curl_xfer_setup to preserve keepon bits */
1853*6236dae4SAndroid Build Coastguard Worker conn->sockfd = conn->writesockfd;
1854*6236dae4SAndroid Build Coastguard Worker
1855*6236dae4SAndroid Build Coastguard Worker /* store this original bitmask setup to use later on if we cannot
1856*6236dae4SAndroid Build Coastguard Worker figure out a "real" bitmask */
1857*6236dae4SAndroid Build Coastguard Worker sshc->orig_waitfor = data->req.keepon;
1858*6236dae4SAndroid Build Coastguard Worker
1859*6236dae4SAndroid Build Coastguard Worker /* we want to use the _sending_ function even when the socket turns
1860*6236dae4SAndroid Build Coastguard Worker out readable as the underlying libssh scp send function will deal
1861*6236dae4SAndroid Build Coastguard Worker with both accordingly */
1862*6236dae4SAndroid Build Coastguard Worker data->state.select_bits = CURL_CSELECT_OUT;
1863*6236dae4SAndroid Build Coastguard Worker
1864*6236dae4SAndroid Build Coastguard Worker state(data, SSH_STOP);
1865*6236dae4SAndroid Build Coastguard Worker
1866*6236dae4SAndroid Build Coastguard Worker break;
1867*6236dae4SAndroid Build Coastguard Worker
1868*6236dae4SAndroid Build Coastguard Worker case SSH_SCP_DOWNLOAD_INIT:
1869*6236dae4SAndroid Build Coastguard Worker
1870*6236dae4SAndroid Build Coastguard Worker rc = ssh_scp_init(sshc->scp_session);
1871*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_OK) {
1872*6236dae4SAndroid Build Coastguard Worker err_msg = ssh_get_error(sshc->ssh_session);
1873*6236dae4SAndroid Build Coastguard Worker failf(data, "%s", err_msg);
1874*6236dae4SAndroid Build Coastguard Worker MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
1875*6236dae4SAndroid Build Coastguard Worker break;
1876*6236dae4SAndroid Build Coastguard Worker }
1877*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SCP_DOWNLOAD);
1878*6236dae4SAndroid Build Coastguard Worker FALLTHROUGH();
1879*6236dae4SAndroid Build Coastguard Worker
1880*6236dae4SAndroid Build Coastguard Worker case SSH_SCP_DOWNLOAD:{
1881*6236dae4SAndroid Build Coastguard Worker curl_off_t bytecount;
1882*6236dae4SAndroid Build Coastguard Worker
1883*6236dae4SAndroid Build Coastguard Worker rc = ssh_scp_pull_request(sshc->scp_session);
1884*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_SCP_REQUEST_NEWFILE) {
1885*6236dae4SAndroid Build Coastguard Worker err_msg = ssh_get_error(sshc->ssh_session);
1886*6236dae4SAndroid Build Coastguard Worker failf(data, "%s", err_msg);
1887*6236dae4SAndroid Build Coastguard Worker MOVE_TO_ERROR_STATE(CURLE_REMOTE_FILE_NOT_FOUND);
1888*6236dae4SAndroid Build Coastguard Worker break;
1889*6236dae4SAndroid Build Coastguard Worker }
1890*6236dae4SAndroid Build Coastguard Worker
1891*6236dae4SAndroid Build Coastguard Worker /* download data */
1892*6236dae4SAndroid Build Coastguard Worker bytecount = ssh_scp_request_get_size(sshc->scp_session);
1893*6236dae4SAndroid Build Coastguard Worker data->req.maxdownload = (curl_off_t) bytecount;
1894*6236dae4SAndroid Build Coastguard Worker Curl_xfer_setup1(data, CURL_XFER_RECV, bytecount, FALSE);
1895*6236dae4SAndroid Build Coastguard Worker
1896*6236dae4SAndroid Build Coastguard Worker /* not set by Curl_xfer_setup to preserve keepon bits */
1897*6236dae4SAndroid Build Coastguard Worker conn->writesockfd = conn->sockfd;
1898*6236dae4SAndroid Build Coastguard Worker
1899*6236dae4SAndroid Build Coastguard Worker /* we want to use the _receiving_ function even when the socket turns
1900*6236dae4SAndroid Build Coastguard Worker out writableable as the underlying libssh recv function will deal
1901*6236dae4SAndroid Build Coastguard Worker with both accordingly */
1902*6236dae4SAndroid Build Coastguard Worker data->state.select_bits = CURL_CSELECT_IN;
1903*6236dae4SAndroid Build Coastguard Worker
1904*6236dae4SAndroid Build Coastguard Worker state(data, SSH_STOP);
1905*6236dae4SAndroid Build Coastguard Worker break;
1906*6236dae4SAndroid Build Coastguard Worker }
1907*6236dae4SAndroid Build Coastguard Worker case SSH_SCP_DONE:
1908*6236dae4SAndroid Build Coastguard Worker if(data->state.upload)
1909*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SCP_SEND_EOF);
1910*6236dae4SAndroid Build Coastguard Worker else
1911*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SCP_CHANNEL_FREE);
1912*6236dae4SAndroid Build Coastguard Worker break;
1913*6236dae4SAndroid Build Coastguard Worker
1914*6236dae4SAndroid Build Coastguard Worker case SSH_SCP_SEND_EOF:
1915*6236dae4SAndroid Build Coastguard Worker if(sshc->scp_session) {
1916*6236dae4SAndroid Build Coastguard Worker rc = ssh_scp_close(sshc->scp_session);
1917*6236dae4SAndroid Build Coastguard Worker if(rc == SSH_AGAIN) {
1918*6236dae4SAndroid Build Coastguard Worker /* Currently the ssh_scp_close handles waiting for EOF in
1919*6236dae4SAndroid Build Coastguard Worker * blocking way.
1920*6236dae4SAndroid Build Coastguard Worker */
1921*6236dae4SAndroid Build Coastguard Worker break;
1922*6236dae4SAndroid Build Coastguard Worker }
1923*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_OK) {
1924*6236dae4SAndroid Build Coastguard Worker infof(data, "Failed to close libssh scp channel: %s",
1925*6236dae4SAndroid Build Coastguard Worker ssh_get_error(sshc->ssh_session));
1926*6236dae4SAndroid Build Coastguard Worker }
1927*6236dae4SAndroid Build Coastguard Worker }
1928*6236dae4SAndroid Build Coastguard Worker
1929*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SCP_CHANNEL_FREE);
1930*6236dae4SAndroid Build Coastguard Worker break;
1931*6236dae4SAndroid Build Coastguard Worker
1932*6236dae4SAndroid Build Coastguard Worker case SSH_SCP_CHANNEL_FREE:
1933*6236dae4SAndroid Build Coastguard Worker if(sshc->scp_session) {
1934*6236dae4SAndroid Build Coastguard Worker ssh_scp_free(sshc->scp_session);
1935*6236dae4SAndroid Build Coastguard Worker sshc->scp_session = NULL;
1936*6236dae4SAndroid Build Coastguard Worker }
1937*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "SCP DONE phase complete"));
1938*6236dae4SAndroid Build Coastguard Worker
1939*6236dae4SAndroid Build Coastguard Worker ssh_set_blocking(sshc->ssh_session, 0);
1940*6236dae4SAndroid Build Coastguard Worker
1941*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SESSION_DISCONNECT);
1942*6236dae4SAndroid Build Coastguard Worker FALLTHROUGH();
1943*6236dae4SAndroid Build Coastguard Worker
1944*6236dae4SAndroid Build Coastguard Worker case SSH_SESSION_DISCONNECT:
1945*6236dae4SAndroid Build Coastguard Worker /* during weird times when we have been prematurely aborted, the channel
1946*6236dae4SAndroid Build Coastguard Worker is still alive when we reach this state and we MUST kill the channel
1947*6236dae4SAndroid Build Coastguard Worker properly first */
1948*6236dae4SAndroid Build Coastguard Worker if(sshc->scp_session) {
1949*6236dae4SAndroid Build Coastguard Worker ssh_scp_free(sshc->scp_session);
1950*6236dae4SAndroid Build Coastguard Worker sshc->scp_session = NULL;
1951*6236dae4SAndroid Build Coastguard Worker }
1952*6236dae4SAndroid Build Coastguard Worker
1953*6236dae4SAndroid Build Coastguard Worker ssh_disconnect(sshc->ssh_session);
1954*6236dae4SAndroid Build Coastguard Worker if(!ssh_version(SSH_VERSION_INT(0, 10, 0))) {
1955*6236dae4SAndroid Build Coastguard Worker /* conn->sock[FIRSTSOCKET] is closed by ssh_disconnect behind our back,
1956*6236dae4SAndroid Build Coastguard Worker tell the connection to forget about it. This libssh
1957*6236dae4SAndroid Build Coastguard Worker bug is fixed in 0.10.0. */
1958*6236dae4SAndroid Build Coastguard Worker Curl_conn_forget_socket(data, FIRSTSOCKET);
1959*6236dae4SAndroid Build Coastguard Worker }
1960*6236dae4SAndroid Build Coastguard Worker
1961*6236dae4SAndroid Build Coastguard Worker SSH_STRING_FREE_CHAR(sshc->homedir);
1962*6236dae4SAndroid Build Coastguard Worker data->state.most_recent_ftp_entrypath = NULL;
1963*6236dae4SAndroid Build Coastguard Worker
1964*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SESSION_FREE);
1965*6236dae4SAndroid Build Coastguard Worker FALLTHROUGH();
1966*6236dae4SAndroid Build Coastguard Worker case SSH_SESSION_FREE:
1967*6236dae4SAndroid Build Coastguard Worker if(sshc->ssh_session) {
1968*6236dae4SAndroid Build Coastguard Worker ssh_free(sshc->ssh_session);
1969*6236dae4SAndroid Build Coastguard Worker sshc->ssh_session = NULL;
1970*6236dae4SAndroid Build Coastguard Worker }
1971*6236dae4SAndroid Build Coastguard Worker
1972*6236dae4SAndroid Build Coastguard Worker /* worst-case scenario cleanup */
1973*6236dae4SAndroid Build Coastguard Worker
1974*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(sshc->ssh_session == NULL);
1975*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(sshc->scp_session == NULL);
1976*6236dae4SAndroid Build Coastguard Worker
1977*6236dae4SAndroid Build Coastguard Worker if(sshc->readdir_tmp) {
1978*6236dae4SAndroid Build Coastguard Worker ssh_string_free_char(sshc->readdir_tmp);
1979*6236dae4SAndroid Build Coastguard Worker sshc->readdir_tmp = NULL;
1980*6236dae4SAndroid Build Coastguard Worker }
1981*6236dae4SAndroid Build Coastguard Worker
1982*6236dae4SAndroid Build Coastguard Worker if(sshc->quote_attrs)
1983*6236dae4SAndroid Build Coastguard Worker sftp_attributes_free(sshc->quote_attrs);
1984*6236dae4SAndroid Build Coastguard Worker
1985*6236dae4SAndroid Build Coastguard Worker if(sshc->readdir_attrs)
1986*6236dae4SAndroid Build Coastguard Worker sftp_attributes_free(sshc->readdir_attrs);
1987*6236dae4SAndroid Build Coastguard Worker
1988*6236dae4SAndroid Build Coastguard Worker if(sshc->readdir_link_attrs)
1989*6236dae4SAndroid Build Coastguard Worker sftp_attributes_free(sshc->readdir_link_attrs);
1990*6236dae4SAndroid Build Coastguard Worker
1991*6236dae4SAndroid Build Coastguard Worker if(sshc->privkey)
1992*6236dae4SAndroid Build Coastguard Worker ssh_key_free(sshc->privkey);
1993*6236dae4SAndroid Build Coastguard Worker if(sshc->pubkey)
1994*6236dae4SAndroid Build Coastguard Worker ssh_key_free(sshc->pubkey);
1995*6236dae4SAndroid Build Coastguard Worker
1996*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->rsa_pub);
1997*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->rsa);
1998*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path1);
1999*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path2);
2000*6236dae4SAndroid Build Coastguard Worker Curl_dyn_free(&sshc->readdir_buf);
2001*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->readdir_linkPath);
2002*6236dae4SAndroid Build Coastguard Worker SSH_STRING_FREE_CHAR(sshc->homedir);
2003*6236dae4SAndroid Build Coastguard Worker
2004*6236dae4SAndroid Build Coastguard Worker /* the code we are about to return */
2005*6236dae4SAndroid Build Coastguard Worker result = sshc->actualcode;
2006*6236dae4SAndroid Build Coastguard Worker
2007*6236dae4SAndroid Build Coastguard Worker memset(sshc, 0, sizeof(struct ssh_conn));
2008*6236dae4SAndroid Build Coastguard Worker
2009*6236dae4SAndroid Build Coastguard Worker connclose(conn, "SSH session free");
2010*6236dae4SAndroid Build Coastguard Worker sshc->state = SSH_SESSION_FREE; /* current */
2011*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
2012*6236dae4SAndroid Build Coastguard Worker state(data, SSH_STOP);
2013*6236dae4SAndroid Build Coastguard Worker break;
2014*6236dae4SAndroid Build Coastguard Worker
2015*6236dae4SAndroid Build Coastguard Worker case SSH_QUIT:
2016*6236dae4SAndroid Build Coastguard Worker default:
2017*6236dae4SAndroid Build Coastguard Worker /* internal error */
2018*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
2019*6236dae4SAndroid Build Coastguard Worker state(data, SSH_STOP);
2020*6236dae4SAndroid Build Coastguard Worker break;
2021*6236dae4SAndroid Build Coastguard Worker
2022*6236dae4SAndroid Build Coastguard Worker }
2023*6236dae4SAndroid Build Coastguard Worker } while(!rc && (sshc->state != SSH_STOP));
2024*6236dae4SAndroid Build Coastguard Worker
2025*6236dae4SAndroid Build Coastguard Worker
2026*6236dae4SAndroid Build Coastguard Worker if(rc == SSH_AGAIN) {
2027*6236dae4SAndroid Build Coastguard Worker /* we would block, we need to wait for the socket to be ready (in the
2028*6236dae4SAndroid Build Coastguard Worker right direction too)! */
2029*6236dae4SAndroid Build Coastguard Worker *block = TRUE;
2030*6236dae4SAndroid Build Coastguard Worker }
2031*6236dae4SAndroid Build Coastguard Worker
2032*6236dae4SAndroid Build Coastguard Worker return result;
2033*6236dae4SAndroid Build Coastguard Worker }
2034*6236dae4SAndroid Build Coastguard Worker
2035*6236dae4SAndroid Build Coastguard Worker
2036*6236dae4SAndroid Build Coastguard Worker /* called by the multi interface to figure out what socket(s) to wait for and
2037*6236dae4SAndroid Build Coastguard Worker for what actions in the DO_DONE, PERFORM and WAITPERFORM states */
myssh_getsock(struct Curl_easy * data,struct connectdata * conn,curl_socket_t * sock)2038*6236dae4SAndroid Build Coastguard Worker static int myssh_getsock(struct Curl_easy *data,
2039*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn,
2040*6236dae4SAndroid Build Coastguard Worker curl_socket_t *sock)
2041*6236dae4SAndroid Build Coastguard Worker {
2042*6236dae4SAndroid Build Coastguard Worker int bitmap = GETSOCK_BLANK;
2043*6236dae4SAndroid Build Coastguard Worker (void)data;
2044*6236dae4SAndroid Build Coastguard Worker sock[0] = conn->sock[FIRSTSOCKET];
2045*6236dae4SAndroid Build Coastguard Worker
2046*6236dae4SAndroid Build Coastguard Worker if(conn->waitfor & KEEP_RECV)
2047*6236dae4SAndroid Build Coastguard Worker bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
2048*6236dae4SAndroid Build Coastguard Worker
2049*6236dae4SAndroid Build Coastguard Worker if(conn->waitfor & KEEP_SEND)
2050*6236dae4SAndroid Build Coastguard Worker bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
2051*6236dae4SAndroid Build Coastguard Worker
2052*6236dae4SAndroid Build Coastguard Worker if(!conn->waitfor)
2053*6236dae4SAndroid Build Coastguard Worker bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
2054*6236dae4SAndroid Build Coastguard Worker
2055*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "ssh_getsock -> %x", bitmap));
2056*6236dae4SAndroid Build Coastguard Worker return bitmap;
2057*6236dae4SAndroid Build Coastguard Worker }
2058*6236dae4SAndroid Build Coastguard Worker
myssh_block2waitfor(struct connectdata * conn,bool block)2059*6236dae4SAndroid Build Coastguard Worker static void myssh_block2waitfor(struct connectdata *conn, bool block)
2060*6236dae4SAndroid Build Coastguard Worker {
2061*6236dae4SAndroid Build Coastguard Worker struct ssh_conn *sshc = &conn->proto.sshc;
2062*6236dae4SAndroid Build Coastguard Worker
2063*6236dae4SAndroid Build Coastguard Worker /* If it did not block, or nothing was returned by ssh_get_poll_flags
2064*6236dae4SAndroid Build Coastguard Worker * have the original set */
2065*6236dae4SAndroid Build Coastguard Worker conn->waitfor = sshc->orig_waitfor;
2066*6236dae4SAndroid Build Coastguard Worker
2067*6236dae4SAndroid Build Coastguard Worker if(block) {
2068*6236dae4SAndroid Build Coastguard Worker int dir = ssh_get_poll_flags(sshc->ssh_session);
2069*6236dae4SAndroid Build Coastguard Worker conn->waitfor = 0;
2070*6236dae4SAndroid Build Coastguard Worker /* translate the libssh define bits into our own bit defines */
2071*6236dae4SAndroid Build Coastguard Worker if(dir & SSH_READ_PENDING)
2072*6236dae4SAndroid Build Coastguard Worker conn->waitfor |= KEEP_RECV;
2073*6236dae4SAndroid Build Coastguard Worker if(dir & SSH_WRITE_PENDING)
2074*6236dae4SAndroid Build Coastguard Worker conn->waitfor |= KEEP_SEND;
2075*6236dae4SAndroid Build Coastguard Worker }
2076*6236dae4SAndroid Build Coastguard Worker }
2077*6236dae4SAndroid Build Coastguard Worker
2078*6236dae4SAndroid Build Coastguard Worker /* called repeatedly until done from multi.c */
myssh_multi_statemach(struct Curl_easy * data,bool * done)2079*6236dae4SAndroid Build Coastguard Worker static CURLcode myssh_multi_statemach(struct Curl_easy *data,
2080*6236dae4SAndroid Build Coastguard Worker bool *done)
2081*6236dae4SAndroid Build Coastguard Worker {
2082*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
2083*6236dae4SAndroid Build Coastguard Worker struct ssh_conn *sshc = &conn->proto.sshc;
2084*6236dae4SAndroid Build Coastguard Worker bool block; /* we store the status and use that to provide a ssh_getsock()
2085*6236dae4SAndroid Build Coastguard Worker implementation */
2086*6236dae4SAndroid Build Coastguard Worker CURLcode result = myssh_statemach_act(data, &block);
2087*6236dae4SAndroid Build Coastguard Worker
2088*6236dae4SAndroid Build Coastguard Worker *done = (sshc->state == SSH_STOP);
2089*6236dae4SAndroid Build Coastguard Worker myssh_block2waitfor(conn, block);
2090*6236dae4SAndroid Build Coastguard Worker
2091*6236dae4SAndroid Build Coastguard Worker return result;
2092*6236dae4SAndroid Build Coastguard Worker }
2093*6236dae4SAndroid Build Coastguard Worker
myssh_block_statemach(struct Curl_easy * data,bool disconnect)2094*6236dae4SAndroid Build Coastguard Worker static CURLcode myssh_block_statemach(struct Curl_easy *data,
2095*6236dae4SAndroid Build Coastguard Worker bool disconnect)
2096*6236dae4SAndroid Build Coastguard Worker {
2097*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
2098*6236dae4SAndroid Build Coastguard Worker struct ssh_conn *sshc = &conn->proto.sshc;
2099*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
2100*6236dae4SAndroid Build Coastguard Worker
2101*6236dae4SAndroid Build Coastguard Worker while((sshc->state != SSH_STOP) && !result) {
2102*6236dae4SAndroid Build Coastguard Worker bool block;
2103*6236dae4SAndroid Build Coastguard Worker timediff_t left = 1000;
2104*6236dae4SAndroid Build Coastguard Worker struct curltime now = Curl_now();
2105*6236dae4SAndroid Build Coastguard Worker
2106*6236dae4SAndroid Build Coastguard Worker result = myssh_statemach_act(data, &block);
2107*6236dae4SAndroid Build Coastguard Worker if(result)
2108*6236dae4SAndroid Build Coastguard Worker break;
2109*6236dae4SAndroid Build Coastguard Worker
2110*6236dae4SAndroid Build Coastguard Worker if(!disconnect) {
2111*6236dae4SAndroid Build Coastguard Worker if(Curl_pgrsUpdate(data))
2112*6236dae4SAndroid Build Coastguard Worker return CURLE_ABORTED_BY_CALLBACK;
2113*6236dae4SAndroid Build Coastguard Worker
2114*6236dae4SAndroid Build Coastguard Worker result = Curl_speedcheck(data, now);
2115*6236dae4SAndroid Build Coastguard Worker if(result)
2116*6236dae4SAndroid Build Coastguard Worker break;
2117*6236dae4SAndroid Build Coastguard Worker
2118*6236dae4SAndroid Build Coastguard Worker left = Curl_timeleft(data, NULL, FALSE);
2119*6236dae4SAndroid Build Coastguard Worker if(left < 0) {
2120*6236dae4SAndroid Build Coastguard Worker failf(data, "Operation timed out");
2121*6236dae4SAndroid Build Coastguard Worker return CURLE_OPERATION_TIMEDOUT;
2122*6236dae4SAndroid Build Coastguard Worker }
2123*6236dae4SAndroid Build Coastguard Worker }
2124*6236dae4SAndroid Build Coastguard Worker
2125*6236dae4SAndroid Build Coastguard Worker if(block) {
2126*6236dae4SAndroid Build Coastguard Worker curl_socket_t fd_read = conn->sock[FIRSTSOCKET];
2127*6236dae4SAndroid Build Coastguard Worker /* wait for the socket to become ready */
2128*6236dae4SAndroid Build Coastguard Worker (void) Curl_socket_check(fd_read, CURL_SOCKET_BAD,
2129*6236dae4SAndroid Build Coastguard Worker CURL_SOCKET_BAD, left > 1000 ? 1000 : left);
2130*6236dae4SAndroid Build Coastguard Worker }
2131*6236dae4SAndroid Build Coastguard Worker
2132*6236dae4SAndroid Build Coastguard Worker }
2133*6236dae4SAndroid Build Coastguard Worker
2134*6236dae4SAndroid Build Coastguard Worker return result;
2135*6236dae4SAndroid Build Coastguard Worker }
2136*6236dae4SAndroid Build Coastguard Worker
2137*6236dae4SAndroid Build Coastguard Worker /*
2138*6236dae4SAndroid Build Coastguard Worker * SSH setup connection
2139*6236dae4SAndroid Build Coastguard Worker */
myssh_setup_connection(struct Curl_easy * data,struct connectdata * conn)2140*6236dae4SAndroid Build Coastguard Worker static CURLcode myssh_setup_connection(struct Curl_easy *data,
2141*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn)
2142*6236dae4SAndroid Build Coastguard Worker {
2143*6236dae4SAndroid Build Coastguard Worker struct SSHPROTO *ssh;
2144*6236dae4SAndroid Build Coastguard Worker struct ssh_conn *sshc = &conn->proto.sshc;
2145*6236dae4SAndroid Build Coastguard Worker
2146*6236dae4SAndroid Build Coastguard Worker data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
2147*6236dae4SAndroid Build Coastguard Worker if(!ssh)
2148*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
2149*6236dae4SAndroid Build Coastguard Worker Curl_dyn_init(&sshc->readdir_buf, CURL_PATH_MAX * 2);
2150*6236dae4SAndroid Build Coastguard Worker
2151*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
2152*6236dae4SAndroid Build Coastguard Worker }
2153*6236dae4SAndroid Build Coastguard Worker
2154*6236dae4SAndroid Build Coastguard Worker static Curl_recv scp_recv, sftp_recv;
2155*6236dae4SAndroid Build Coastguard Worker static Curl_send scp_send, sftp_send;
2156*6236dae4SAndroid Build Coastguard Worker
2157*6236dae4SAndroid Build Coastguard Worker /*
2158*6236dae4SAndroid Build Coastguard Worker * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to
2159*6236dae4SAndroid Build Coastguard Worker * do protocol-specific actions at connect-time.
2160*6236dae4SAndroid Build Coastguard Worker */
myssh_connect(struct Curl_easy * data,bool * done)2161*6236dae4SAndroid Build Coastguard Worker static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
2162*6236dae4SAndroid Build Coastguard Worker {
2163*6236dae4SAndroid Build Coastguard Worker struct ssh_conn *ssh;
2164*6236dae4SAndroid Build Coastguard Worker CURLcode result;
2165*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
2166*6236dae4SAndroid Build Coastguard Worker curl_socket_t sock = conn->sock[FIRSTSOCKET];
2167*6236dae4SAndroid Build Coastguard Worker int rc;
2168*6236dae4SAndroid Build Coastguard Worker
2169*6236dae4SAndroid Build Coastguard Worker /* initialize per-handle data if not already */
2170*6236dae4SAndroid Build Coastguard Worker if(!data->req.p.ssh)
2171*6236dae4SAndroid Build Coastguard Worker myssh_setup_connection(data, conn);
2172*6236dae4SAndroid Build Coastguard Worker
2173*6236dae4SAndroid Build Coastguard Worker /* We default to persistent connections. We set this already in this connect
2174*6236dae4SAndroid Build Coastguard Worker function to make the reuse checks properly be able to check this bit. */
2175*6236dae4SAndroid Build Coastguard Worker connkeep(conn, "SSH default");
2176*6236dae4SAndroid Build Coastguard Worker
2177*6236dae4SAndroid Build Coastguard Worker if(conn->handler->protocol & CURLPROTO_SCP) {
2178*6236dae4SAndroid Build Coastguard Worker conn->recv[FIRSTSOCKET] = scp_recv;
2179*6236dae4SAndroid Build Coastguard Worker conn->send[FIRSTSOCKET] = scp_send;
2180*6236dae4SAndroid Build Coastguard Worker }
2181*6236dae4SAndroid Build Coastguard Worker else {
2182*6236dae4SAndroid Build Coastguard Worker conn->recv[FIRSTSOCKET] = sftp_recv;
2183*6236dae4SAndroid Build Coastguard Worker conn->send[FIRSTSOCKET] = sftp_send;
2184*6236dae4SAndroid Build Coastguard Worker }
2185*6236dae4SAndroid Build Coastguard Worker
2186*6236dae4SAndroid Build Coastguard Worker ssh = &conn->proto.sshc;
2187*6236dae4SAndroid Build Coastguard Worker
2188*6236dae4SAndroid Build Coastguard Worker ssh->ssh_session = ssh_new();
2189*6236dae4SAndroid Build Coastguard Worker if(!ssh->ssh_session) {
2190*6236dae4SAndroid Build Coastguard Worker failf(data, "Failure initialising ssh session");
2191*6236dae4SAndroid Build Coastguard Worker return CURLE_FAILED_INIT;
2192*6236dae4SAndroid Build Coastguard Worker }
2193*6236dae4SAndroid Build Coastguard Worker
2194*6236dae4SAndroid Build Coastguard Worker rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, conn->host.name);
2195*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_OK) {
2196*6236dae4SAndroid Build Coastguard Worker failf(data, "Could not set remote host");
2197*6236dae4SAndroid Build Coastguard Worker return CURLE_FAILED_INIT;
2198*6236dae4SAndroid Build Coastguard Worker }
2199*6236dae4SAndroid Build Coastguard Worker
2200*6236dae4SAndroid Build Coastguard Worker rc = ssh_options_parse_config(ssh->ssh_session, NULL);
2201*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_OK) {
2202*6236dae4SAndroid Build Coastguard Worker infof(data, "Could not parse SSH configuration files");
2203*6236dae4SAndroid Build Coastguard Worker /* ignore */
2204*6236dae4SAndroid Build Coastguard Worker }
2205*6236dae4SAndroid Build Coastguard Worker
2206*6236dae4SAndroid Build Coastguard Worker rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_FD, &sock);
2207*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_OK) {
2208*6236dae4SAndroid Build Coastguard Worker failf(data, "Could not set socket");
2209*6236dae4SAndroid Build Coastguard Worker return CURLE_FAILED_INIT;
2210*6236dae4SAndroid Build Coastguard Worker }
2211*6236dae4SAndroid Build Coastguard Worker
2212*6236dae4SAndroid Build Coastguard Worker if(conn->user && conn->user[0] != '\0') {
2213*6236dae4SAndroid Build Coastguard Worker infof(data, "User: %s", conn->user);
2214*6236dae4SAndroid Build Coastguard Worker rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user);
2215*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_OK) {
2216*6236dae4SAndroid Build Coastguard Worker failf(data, "Could not set user");
2217*6236dae4SAndroid Build Coastguard Worker return CURLE_FAILED_INIT;
2218*6236dae4SAndroid Build Coastguard Worker }
2219*6236dae4SAndroid Build Coastguard Worker }
2220*6236dae4SAndroid Build Coastguard Worker
2221*6236dae4SAndroid Build Coastguard Worker if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
2222*6236dae4SAndroid Build Coastguard Worker infof(data, "Known hosts: %s", data->set.str[STRING_SSH_KNOWNHOSTS]);
2223*6236dae4SAndroid Build Coastguard Worker rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS,
2224*6236dae4SAndroid Build Coastguard Worker data->set.str[STRING_SSH_KNOWNHOSTS]);
2225*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_OK) {
2226*6236dae4SAndroid Build Coastguard Worker failf(data, "Could not set known hosts file path");
2227*6236dae4SAndroid Build Coastguard Worker return CURLE_FAILED_INIT;
2228*6236dae4SAndroid Build Coastguard Worker }
2229*6236dae4SAndroid Build Coastguard Worker }
2230*6236dae4SAndroid Build Coastguard Worker
2231*6236dae4SAndroid Build Coastguard Worker if(conn->remote_port) {
2232*6236dae4SAndroid Build Coastguard Worker rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_PORT,
2233*6236dae4SAndroid Build Coastguard Worker &conn->remote_port);
2234*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_OK) {
2235*6236dae4SAndroid Build Coastguard Worker failf(data, "Could not set remote port");
2236*6236dae4SAndroid Build Coastguard Worker return CURLE_FAILED_INIT;
2237*6236dae4SAndroid Build Coastguard Worker }
2238*6236dae4SAndroid Build Coastguard Worker }
2239*6236dae4SAndroid Build Coastguard Worker
2240*6236dae4SAndroid Build Coastguard Worker if(data->set.ssh_compression) {
2241*6236dae4SAndroid Build Coastguard Worker rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_COMPRESSION,
2242*6236dae4SAndroid Build Coastguard Worker "zlib,[email protected],none");
2243*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_OK) {
2244*6236dae4SAndroid Build Coastguard Worker failf(data, "Could not set compression");
2245*6236dae4SAndroid Build Coastguard Worker return CURLE_FAILED_INIT;
2246*6236dae4SAndroid Build Coastguard Worker }
2247*6236dae4SAndroid Build Coastguard Worker }
2248*6236dae4SAndroid Build Coastguard Worker
2249*6236dae4SAndroid Build Coastguard Worker ssh->privkey = NULL;
2250*6236dae4SAndroid Build Coastguard Worker ssh->pubkey = NULL;
2251*6236dae4SAndroid Build Coastguard Worker
2252*6236dae4SAndroid Build Coastguard Worker if(data->set.str[STRING_SSH_PUBLIC_KEY]) {
2253*6236dae4SAndroid Build Coastguard Worker rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY],
2254*6236dae4SAndroid Build Coastguard Worker &ssh->pubkey);
2255*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_OK) {
2256*6236dae4SAndroid Build Coastguard Worker failf(data, "Could not load public key file");
2257*6236dae4SAndroid Build Coastguard Worker return CURLE_FAILED_INIT;
2258*6236dae4SAndroid Build Coastguard Worker }
2259*6236dae4SAndroid Build Coastguard Worker }
2260*6236dae4SAndroid Build Coastguard Worker
2261*6236dae4SAndroid Build Coastguard Worker /* we do not verify here, we do it at the state machine,
2262*6236dae4SAndroid Build Coastguard Worker * after connection */
2263*6236dae4SAndroid Build Coastguard Worker
2264*6236dae4SAndroid Build Coastguard Worker state(data, SSH_INIT);
2265*6236dae4SAndroid Build Coastguard Worker
2266*6236dae4SAndroid Build Coastguard Worker result = myssh_multi_statemach(data, done);
2267*6236dae4SAndroid Build Coastguard Worker
2268*6236dae4SAndroid Build Coastguard Worker return result;
2269*6236dae4SAndroid Build Coastguard Worker }
2270*6236dae4SAndroid Build Coastguard Worker
2271*6236dae4SAndroid Build Coastguard Worker /* called from multi.c while DOing */
scp_doing(struct Curl_easy * data,bool * dophase_done)2272*6236dae4SAndroid Build Coastguard Worker static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done)
2273*6236dae4SAndroid Build Coastguard Worker {
2274*6236dae4SAndroid Build Coastguard Worker CURLcode result;
2275*6236dae4SAndroid Build Coastguard Worker
2276*6236dae4SAndroid Build Coastguard Worker result = myssh_multi_statemach(data, dophase_done);
2277*6236dae4SAndroid Build Coastguard Worker
2278*6236dae4SAndroid Build Coastguard Worker if(*dophase_done) {
2279*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "DO phase is complete"));
2280*6236dae4SAndroid Build Coastguard Worker }
2281*6236dae4SAndroid Build Coastguard Worker return result;
2282*6236dae4SAndroid Build Coastguard Worker }
2283*6236dae4SAndroid Build Coastguard Worker
2284*6236dae4SAndroid Build Coastguard Worker /*
2285*6236dae4SAndroid Build Coastguard Worker ***********************************************************************
2286*6236dae4SAndroid Build Coastguard Worker *
2287*6236dae4SAndroid Build Coastguard Worker * scp_perform()
2288*6236dae4SAndroid Build Coastguard Worker *
2289*6236dae4SAndroid Build Coastguard Worker * This is the actual DO function for SCP. Get a file according to
2290*6236dae4SAndroid Build Coastguard Worker * the options previously setup.
2291*6236dae4SAndroid Build Coastguard Worker */
2292*6236dae4SAndroid Build Coastguard Worker
2293*6236dae4SAndroid Build Coastguard Worker static
scp_perform(struct Curl_easy * data,bool * connected,bool * dophase_done)2294*6236dae4SAndroid Build Coastguard Worker CURLcode scp_perform(struct Curl_easy *data,
2295*6236dae4SAndroid Build Coastguard Worker bool *connected, bool *dophase_done)
2296*6236dae4SAndroid Build Coastguard Worker {
2297*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
2298*6236dae4SAndroid Build Coastguard Worker
2299*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "DO phase starts"));
2300*6236dae4SAndroid Build Coastguard Worker
2301*6236dae4SAndroid Build Coastguard Worker *dophase_done = FALSE; /* not done yet */
2302*6236dae4SAndroid Build Coastguard Worker
2303*6236dae4SAndroid Build Coastguard Worker /* start the first command in the DO phase */
2304*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SCP_TRANS_INIT);
2305*6236dae4SAndroid Build Coastguard Worker
2306*6236dae4SAndroid Build Coastguard Worker result = myssh_multi_statemach(data, dophase_done);
2307*6236dae4SAndroid Build Coastguard Worker
2308*6236dae4SAndroid Build Coastguard Worker *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
2309*6236dae4SAndroid Build Coastguard Worker
2310*6236dae4SAndroid Build Coastguard Worker if(*dophase_done) {
2311*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "DO phase is complete"));
2312*6236dae4SAndroid Build Coastguard Worker }
2313*6236dae4SAndroid Build Coastguard Worker
2314*6236dae4SAndroid Build Coastguard Worker return result;
2315*6236dae4SAndroid Build Coastguard Worker }
2316*6236dae4SAndroid Build Coastguard Worker
myssh_do_it(struct Curl_easy * data,bool * done)2317*6236dae4SAndroid Build Coastguard Worker static CURLcode myssh_do_it(struct Curl_easy *data, bool *done)
2318*6236dae4SAndroid Build Coastguard Worker {
2319*6236dae4SAndroid Build Coastguard Worker CURLcode result;
2320*6236dae4SAndroid Build Coastguard Worker bool connected = FALSE;
2321*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
2322*6236dae4SAndroid Build Coastguard Worker struct ssh_conn *sshc = &conn->proto.sshc;
2323*6236dae4SAndroid Build Coastguard Worker
2324*6236dae4SAndroid Build Coastguard Worker *done = FALSE; /* default to false */
2325*6236dae4SAndroid Build Coastguard Worker
2326*6236dae4SAndroid Build Coastguard Worker data->req.size = -1; /* make sure this is unknown at this point */
2327*6236dae4SAndroid Build Coastguard Worker
2328*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = CURLE_OK; /* reset error code */
2329*6236dae4SAndroid Build Coastguard Worker sshc->secondCreateDirs = 0; /* reset the create dir attempt state
2330*6236dae4SAndroid Build Coastguard Worker variable */
2331*6236dae4SAndroid Build Coastguard Worker
2332*6236dae4SAndroid Build Coastguard Worker Curl_pgrsSetUploadCounter(data, 0);
2333*6236dae4SAndroid Build Coastguard Worker Curl_pgrsSetDownloadCounter(data, 0);
2334*6236dae4SAndroid Build Coastguard Worker Curl_pgrsSetUploadSize(data, -1);
2335*6236dae4SAndroid Build Coastguard Worker Curl_pgrsSetDownloadSize(data, -1);
2336*6236dae4SAndroid Build Coastguard Worker
2337*6236dae4SAndroid Build Coastguard Worker if(conn->handler->protocol & CURLPROTO_SCP)
2338*6236dae4SAndroid Build Coastguard Worker result = scp_perform(data, &connected, done);
2339*6236dae4SAndroid Build Coastguard Worker else
2340*6236dae4SAndroid Build Coastguard Worker result = sftp_perform(data, &connected, done);
2341*6236dae4SAndroid Build Coastguard Worker
2342*6236dae4SAndroid Build Coastguard Worker return result;
2343*6236dae4SAndroid Build Coastguard Worker }
2344*6236dae4SAndroid Build Coastguard Worker
2345*6236dae4SAndroid Build Coastguard Worker /* BLOCKING, but the function is using the state machine so the only reason
2346*6236dae4SAndroid Build Coastguard Worker this is still blocking is that the multi interface code has no support for
2347*6236dae4SAndroid Build Coastguard Worker disconnecting operations that takes a while */
scp_disconnect(struct Curl_easy * data,struct connectdata * conn,bool dead_connection)2348*6236dae4SAndroid Build Coastguard Worker static CURLcode scp_disconnect(struct Curl_easy *data,
2349*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn,
2350*6236dae4SAndroid Build Coastguard Worker bool dead_connection)
2351*6236dae4SAndroid Build Coastguard Worker {
2352*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
2353*6236dae4SAndroid Build Coastguard Worker struct ssh_conn *ssh = &conn->proto.sshc;
2354*6236dae4SAndroid Build Coastguard Worker (void) dead_connection;
2355*6236dae4SAndroid Build Coastguard Worker
2356*6236dae4SAndroid Build Coastguard Worker if(ssh->ssh_session) {
2357*6236dae4SAndroid Build Coastguard Worker /* only if there is a session still around to use! */
2358*6236dae4SAndroid Build Coastguard Worker
2359*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SESSION_DISCONNECT);
2360*6236dae4SAndroid Build Coastguard Worker
2361*6236dae4SAndroid Build Coastguard Worker result = myssh_block_statemach(data, TRUE);
2362*6236dae4SAndroid Build Coastguard Worker }
2363*6236dae4SAndroid Build Coastguard Worker
2364*6236dae4SAndroid Build Coastguard Worker return result;
2365*6236dae4SAndroid Build Coastguard Worker }
2366*6236dae4SAndroid Build Coastguard Worker
2367*6236dae4SAndroid Build Coastguard Worker /* generic done function for both SCP and SFTP called from their specific
2368*6236dae4SAndroid Build Coastguard Worker done functions */
myssh_done(struct Curl_easy * data,CURLcode status)2369*6236dae4SAndroid Build Coastguard Worker static CURLcode myssh_done(struct Curl_easy *data, CURLcode status)
2370*6236dae4SAndroid Build Coastguard Worker {
2371*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
2372*6236dae4SAndroid Build Coastguard Worker struct SSHPROTO *protop = data->req.p.ssh;
2373*6236dae4SAndroid Build Coastguard Worker
2374*6236dae4SAndroid Build Coastguard Worker if(!status) {
2375*6236dae4SAndroid Build Coastguard Worker /* run the state-machine */
2376*6236dae4SAndroid Build Coastguard Worker result = myssh_block_statemach(data, FALSE);
2377*6236dae4SAndroid Build Coastguard Worker }
2378*6236dae4SAndroid Build Coastguard Worker else
2379*6236dae4SAndroid Build Coastguard Worker result = status;
2380*6236dae4SAndroid Build Coastguard Worker
2381*6236dae4SAndroid Build Coastguard Worker if(protop)
2382*6236dae4SAndroid Build Coastguard Worker Curl_safefree(protop->path);
2383*6236dae4SAndroid Build Coastguard Worker if(Curl_pgrsDone(data))
2384*6236dae4SAndroid Build Coastguard Worker return CURLE_ABORTED_BY_CALLBACK;
2385*6236dae4SAndroid Build Coastguard Worker
2386*6236dae4SAndroid Build Coastguard Worker data->req.keepon = 0; /* clear all bits */
2387*6236dae4SAndroid Build Coastguard Worker return result;
2388*6236dae4SAndroid Build Coastguard Worker }
2389*6236dae4SAndroid Build Coastguard Worker
2390*6236dae4SAndroid Build Coastguard Worker
scp_done(struct Curl_easy * data,CURLcode status,bool premature)2391*6236dae4SAndroid Build Coastguard Worker static CURLcode scp_done(struct Curl_easy *data, CURLcode status,
2392*6236dae4SAndroid Build Coastguard Worker bool premature)
2393*6236dae4SAndroid Build Coastguard Worker {
2394*6236dae4SAndroid Build Coastguard Worker (void) premature; /* not used */
2395*6236dae4SAndroid Build Coastguard Worker
2396*6236dae4SAndroid Build Coastguard Worker if(!status)
2397*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SCP_DONE);
2398*6236dae4SAndroid Build Coastguard Worker
2399*6236dae4SAndroid Build Coastguard Worker return myssh_done(data, status);
2400*6236dae4SAndroid Build Coastguard Worker
2401*6236dae4SAndroid Build Coastguard Worker }
2402*6236dae4SAndroid Build Coastguard Worker
scp_send(struct Curl_easy * data,int sockindex,const void * mem,size_t len,bool eos,CURLcode * err)2403*6236dae4SAndroid Build Coastguard Worker static ssize_t scp_send(struct Curl_easy *data, int sockindex,
2404*6236dae4SAndroid Build Coastguard Worker const void *mem, size_t len, bool eos, CURLcode *err)
2405*6236dae4SAndroid Build Coastguard Worker {
2406*6236dae4SAndroid Build Coastguard Worker int rc;
2407*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
2408*6236dae4SAndroid Build Coastguard Worker (void) sockindex; /* we only support SCP on the fixed known primary socket */
2409*6236dae4SAndroid Build Coastguard Worker (void) err;
2410*6236dae4SAndroid Build Coastguard Worker (void)eos;
2411*6236dae4SAndroid Build Coastguard Worker
2412*6236dae4SAndroid Build Coastguard Worker rc = ssh_scp_write(conn->proto.sshc.scp_session, mem, len);
2413*6236dae4SAndroid Build Coastguard Worker
2414*6236dae4SAndroid Build Coastguard Worker #if 0
2415*6236dae4SAndroid Build Coastguard Worker /* The following code is misleading, mostly added as wishful thinking
2416*6236dae4SAndroid Build Coastguard Worker * that libssh at some point will implement non-blocking ssh_scp_write/read.
2417*6236dae4SAndroid Build Coastguard Worker * Currently rc can only be number of bytes read or SSH_ERROR. */
2418*6236dae4SAndroid Build Coastguard Worker myssh_block2waitfor(conn, (rc == SSH_AGAIN));
2419*6236dae4SAndroid Build Coastguard Worker
2420*6236dae4SAndroid Build Coastguard Worker if(rc == SSH_AGAIN) {
2421*6236dae4SAndroid Build Coastguard Worker *err = CURLE_AGAIN;
2422*6236dae4SAndroid Build Coastguard Worker return 0;
2423*6236dae4SAndroid Build Coastguard Worker }
2424*6236dae4SAndroid Build Coastguard Worker else
2425*6236dae4SAndroid Build Coastguard Worker #endif
2426*6236dae4SAndroid Build Coastguard Worker if(rc != SSH_OK) {
2427*6236dae4SAndroid Build Coastguard Worker *err = CURLE_SSH;
2428*6236dae4SAndroid Build Coastguard Worker return -1;
2429*6236dae4SAndroid Build Coastguard Worker }
2430*6236dae4SAndroid Build Coastguard Worker
2431*6236dae4SAndroid Build Coastguard Worker return len;
2432*6236dae4SAndroid Build Coastguard Worker }
2433*6236dae4SAndroid Build Coastguard Worker
scp_recv(struct Curl_easy * data,int sockindex,char * mem,size_t len,CURLcode * err)2434*6236dae4SAndroid Build Coastguard Worker static ssize_t scp_recv(struct Curl_easy *data, int sockindex,
2435*6236dae4SAndroid Build Coastguard Worker char *mem, size_t len, CURLcode *err)
2436*6236dae4SAndroid Build Coastguard Worker {
2437*6236dae4SAndroid Build Coastguard Worker ssize_t nread;
2438*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
2439*6236dae4SAndroid Build Coastguard Worker (void) err;
2440*6236dae4SAndroid Build Coastguard Worker (void) sockindex; /* we only support SCP on the fixed known primary socket */
2441*6236dae4SAndroid Build Coastguard Worker
2442*6236dae4SAndroid Build Coastguard Worker /* libssh returns int */
2443*6236dae4SAndroid Build Coastguard Worker nread = ssh_scp_read(conn->proto.sshc.scp_session, mem, len);
2444*6236dae4SAndroid Build Coastguard Worker
2445*6236dae4SAndroid Build Coastguard Worker #if 0
2446*6236dae4SAndroid Build Coastguard Worker /* The following code is misleading, mostly added as wishful thinking
2447*6236dae4SAndroid Build Coastguard Worker * that libssh at some point will implement non-blocking ssh_scp_write/read.
2448*6236dae4SAndroid Build Coastguard Worker * Currently rc can only be SSH_OK or SSH_ERROR. */
2449*6236dae4SAndroid Build Coastguard Worker
2450*6236dae4SAndroid Build Coastguard Worker myssh_block2waitfor(conn, (nread == SSH_AGAIN));
2451*6236dae4SAndroid Build Coastguard Worker if(nread == SSH_AGAIN) {
2452*6236dae4SAndroid Build Coastguard Worker *err = CURLE_AGAIN;
2453*6236dae4SAndroid Build Coastguard Worker nread = -1;
2454*6236dae4SAndroid Build Coastguard Worker }
2455*6236dae4SAndroid Build Coastguard Worker #endif
2456*6236dae4SAndroid Build Coastguard Worker
2457*6236dae4SAndroid Build Coastguard Worker return nread;
2458*6236dae4SAndroid Build Coastguard Worker }
2459*6236dae4SAndroid Build Coastguard Worker
2460*6236dae4SAndroid Build Coastguard Worker /*
2461*6236dae4SAndroid Build Coastguard Worker * =============== SFTP ===============
2462*6236dae4SAndroid Build Coastguard Worker */
2463*6236dae4SAndroid Build Coastguard Worker
2464*6236dae4SAndroid Build Coastguard Worker /*
2465*6236dae4SAndroid Build Coastguard Worker ***********************************************************************
2466*6236dae4SAndroid Build Coastguard Worker *
2467*6236dae4SAndroid Build Coastguard Worker * sftp_perform()
2468*6236dae4SAndroid Build Coastguard Worker *
2469*6236dae4SAndroid Build Coastguard Worker * This is the actual DO function for SFTP. Get a file/directory according to
2470*6236dae4SAndroid Build Coastguard Worker * the options previously setup.
2471*6236dae4SAndroid Build Coastguard Worker */
2472*6236dae4SAndroid Build Coastguard Worker
2473*6236dae4SAndroid Build Coastguard Worker static
sftp_perform(struct Curl_easy * data,bool * connected,bool * dophase_done)2474*6236dae4SAndroid Build Coastguard Worker CURLcode sftp_perform(struct Curl_easy *data,
2475*6236dae4SAndroid Build Coastguard Worker bool *connected,
2476*6236dae4SAndroid Build Coastguard Worker bool *dophase_done)
2477*6236dae4SAndroid Build Coastguard Worker {
2478*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
2479*6236dae4SAndroid Build Coastguard Worker
2480*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "DO phase starts"));
2481*6236dae4SAndroid Build Coastguard Worker
2482*6236dae4SAndroid Build Coastguard Worker *dophase_done = FALSE; /* not done yet */
2483*6236dae4SAndroid Build Coastguard Worker
2484*6236dae4SAndroid Build Coastguard Worker /* start the first command in the DO phase */
2485*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_QUOTE_INIT);
2486*6236dae4SAndroid Build Coastguard Worker
2487*6236dae4SAndroid Build Coastguard Worker /* run the state-machine */
2488*6236dae4SAndroid Build Coastguard Worker result = myssh_multi_statemach(data, dophase_done);
2489*6236dae4SAndroid Build Coastguard Worker
2490*6236dae4SAndroid Build Coastguard Worker *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
2491*6236dae4SAndroid Build Coastguard Worker
2492*6236dae4SAndroid Build Coastguard Worker if(*dophase_done) {
2493*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "DO phase is complete"));
2494*6236dae4SAndroid Build Coastguard Worker }
2495*6236dae4SAndroid Build Coastguard Worker
2496*6236dae4SAndroid Build Coastguard Worker return result;
2497*6236dae4SAndroid Build Coastguard Worker }
2498*6236dae4SAndroid Build Coastguard Worker
2499*6236dae4SAndroid Build Coastguard Worker /* called from multi.c while DOing */
sftp_doing(struct Curl_easy * data,bool * dophase_done)2500*6236dae4SAndroid Build Coastguard Worker static CURLcode sftp_doing(struct Curl_easy *data,
2501*6236dae4SAndroid Build Coastguard Worker bool *dophase_done)
2502*6236dae4SAndroid Build Coastguard Worker {
2503*6236dae4SAndroid Build Coastguard Worker CURLcode result = myssh_multi_statemach(data, dophase_done);
2504*6236dae4SAndroid Build Coastguard Worker if(*dophase_done) {
2505*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "DO phase is complete"));
2506*6236dae4SAndroid Build Coastguard Worker }
2507*6236dae4SAndroid Build Coastguard Worker return result;
2508*6236dae4SAndroid Build Coastguard Worker }
2509*6236dae4SAndroid Build Coastguard Worker
2510*6236dae4SAndroid Build Coastguard Worker /* BLOCKING, but the function is using the state machine so the only reason
2511*6236dae4SAndroid Build Coastguard Worker this is still blocking is that the multi interface code has no support for
2512*6236dae4SAndroid Build Coastguard Worker disconnecting operations that takes a while */
sftp_disconnect(struct Curl_easy * data,struct connectdata * conn,bool dead_connection)2513*6236dae4SAndroid Build Coastguard Worker static CURLcode sftp_disconnect(struct Curl_easy *data,
2514*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn,
2515*6236dae4SAndroid Build Coastguard Worker bool dead_connection)
2516*6236dae4SAndroid Build Coastguard Worker {
2517*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
2518*6236dae4SAndroid Build Coastguard Worker (void) dead_connection;
2519*6236dae4SAndroid Build Coastguard Worker
2520*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "SSH DISCONNECT starts now"));
2521*6236dae4SAndroid Build Coastguard Worker
2522*6236dae4SAndroid Build Coastguard Worker if(conn->proto.sshc.ssh_session) {
2523*6236dae4SAndroid Build Coastguard Worker /* only if there is a session still around to use! */
2524*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_SHUTDOWN);
2525*6236dae4SAndroid Build Coastguard Worker result = myssh_block_statemach(data, TRUE);
2526*6236dae4SAndroid Build Coastguard Worker }
2527*6236dae4SAndroid Build Coastguard Worker
2528*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "SSH DISCONNECT is done"));
2529*6236dae4SAndroid Build Coastguard Worker
2530*6236dae4SAndroid Build Coastguard Worker return result;
2531*6236dae4SAndroid Build Coastguard Worker
2532*6236dae4SAndroid Build Coastguard Worker }
2533*6236dae4SAndroid Build Coastguard Worker
sftp_done(struct Curl_easy * data,CURLcode status,bool premature)2534*6236dae4SAndroid Build Coastguard Worker static CURLcode sftp_done(struct Curl_easy *data, CURLcode status,
2535*6236dae4SAndroid Build Coastguard Worker bool premature)
2536*6236dae4SAndroid Build Coastguard Worker {
2537*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
2538*6236dae4SAndroid Build Coastguard Worker struct ssh_conn *sshc = &conn->proto.sshc;
2539*6236dae4SAndroid Build Coastguard Worker
2540*6236dae4SAndroid Build Coastguard Worker if(!status) {
2541*6236dae4SAndroid Build Coastguard Worker /* Post quote commands are executed after the SFTP_CLOSE state to avoid
2542*6236dae4SAndroid Build Coastguard Worker errors that could happen due to open file handles during POSTQUOTE
2543*6236dae4SAndroid Build Coastguard Worker operation */
2544*6236dae4SAndroid Build Coastguard Worker if(!premature && data->set.postquote && !conn->bits.retry)
2545*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
2546*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
2547*6236dae4SAndroid Build Coastguard Worker }
2548*6236dae4SAndroid Build Coastguard Worker return myssh_done(data, status);
2549*6236dae4SAndroid Build Coastguard Worker }
2550*6236dae4SAndroid Build Coastguard Worker
2551*6236dae4SAndroid Build Coastguard Worker /* return number of sent bytes */
sftp_send(struct Curl_easy * data,int sockindex,const void * mem,size_t len,bool eos,CURLcode * err)2552*6236dae4SAndroid Build Coastguard Worker static ssize_t sftp_send(struct Curl_easy *data, int sockindex,
2553*6236dae4SAndroid Build Coastguard Worker const void *mem, size_t len, bool eos,
2554*6236dae4SAndroid Build Coastguard Worker CURLcode *err)
2555*6236dae4SAndroid Build Coastguard Worker {
2556*6236dae4SAndroid Build Coastguard Worker ssize_t nwrite;
2557*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
2558*6236dae4SAndroid Build Coastguard Worker (void)sockindex;
2559*6236dae4SAndroid Build Coastguard Worker (void)eos;
2560*6236dae4SAndroid Build Coastguard Worker
2561*6236dae4SAndroid Build Coastguard Worker /* limit the writes to the maximum specified in Section 3 of
2562*6236dae4SAndroid Build Coastguard Worker * https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02
2563*6236dae4SAndroid Build Coastguard Worker */
2564*6236dae4SAndroid Build Coastguard Worker if(len > 32768)
2565*6236dae4SAndroid Build Coastguard Worker len = 32768;
2566*6236dae4SAndroid Build Coastguard Worker
2567*6236dae4SAndroid Build Coastguard Worker nwrite = sftp_write(conn->proto.sshc.sftp_file, mem, len);
2568*6236dae4SAndroid Build Coastguard Worker
2569*6236dae4SAndroid Build Coastguard Worker myssh_block2waitfor(conn, FALSE);
2570*6236dae4SAndroid Build Coastguard Worker
2571*6236dae4SAndroid Build Coastguard Worker #if 0 /* not returned by libssh on write */
2572*6236dae4SAndroid Build Coastguard Worker if(nwrite == SSH_AGAIN) {
2573*6236dae4SAndroid Build Coastguard Worker *err = CURLE_AGAIN;
2574*6236dae4SAndroid Build Coastguard Worker nwrite = 0;
2575*6236dae4SAndroid Build Coastguard Worker }
2576*6236dae4SAndroid Build Coastguard Worker else
2577*6236dae4SAndroid Build Coastguard Worker #endif
2578*6236dae4SAndroid Build Coastguard Worker if(nwrite < 0) {
2579*6236dae4SAndroid Build Coastguard Worker *err = CURLE_SSH;
2580*6236dae4SAndroid Build Coastguard Worker nwrite = -1;
2581*6236dae4SAndroid Build Coastguard Worker }
2582*6236dae4SAndroid Build Coastguard Worker
2583*6236dae4SAndroid Build Coastguard Worker return nwrite;
2584*6236dae4SAndroid Build Coastguard Worker }
2585*6236dae4SAndroid Build Coastguard Worker
2586*6236dae4SAndroid Build Coastguard Worker /*
2587*6236dae4SAndroid Build Coastguard Worker * Return number of received (decrypted) bytes
2588*6236dae4SAndroid Build Coastguard Worker * or <0 on error
2589*6236dae4SAndroid Build Coastguard Worker */
sftp_recv(struct Curl_easy * data,int sockindex,char * mem,size_t len,CURLcode * err)2590*6236dae4SAndroid Build Coastguard Worker static ssize_t sftp_recv(struct Curl_easy *data, int sockindex,
2591*6236dae4SAndroid Build Coastguard Worker char *mem, size_t len, CURLcode *err)
2592*6236dae4SAndroid Build Coastguard Worker {
2593*6236dae4SAndroid Build Coastguard Worker ssize_t nread;
2594*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
2595*6236dae4SAndroid Build Coastguard Worker (void)sockindex;
2596*6236dae4SAndroid Build Coastguard Worker
2597*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(len < CURL_MAX_READ_SIZE);
2598*6236dae4SAndroid Build Coastguard Worker
2599*6236dae4SAndroid Build Coastguard Worker switch(conn->proto.sshc.sftp_recv_state) {
2600*6236dae4SAndroid Build Coastguard Worker case 0:
2601*6236dae4SAndroid Build Coastguard Worker conn->proto.sshc.sftp_file_index =
2602*6236dae4SAndroid Build Coastguard Worker sftp_async_read_begin(conn->proto.sshc.sftp_file,
2603*6236dae4SAndroid Build Coastguard Worker (uint32_t)len);
2604*6236dae4SAndroid Build Coastguard Worker if(conn->proto.sshc.sftp_file_index < 0) {
2605*6236dae4SAndroid Build Coastguard Worker *err = CURLE_RECV_ERROR;
2606*6236dae4SAndroid Build Coastguard Worker return -1;
2607*6236dae4SAndroid Build Coastguard Worker }
2608*6236dae4SAndroid Build Coastguard Worker
2609*6236dae4SAndroid Build Coastguard Worker FALLTHROUGH();
2610*6236dae4SAndroid Build Coastguard Worker case 1:
2611*6236dae4SAndroid Build Coastguard Worker conn->proto.sshc.sftp_recv_state = 1;
2612*6236dae4SAndroid Build Coastguard Worker
2613*6236dae4SAndroid Build Coastguard Worker nread = sftp_async_read(conn->proto.sshc.sftp_file,
2614*6236dae4SAndroid Build Coastguard Worker mem, (uint32_t)len,
2615*6236dae4SAndroid Build Coastguard Worker (uint32_t)conn->proto.sshc.sftp_file_index);
2616*6236dae4SAndroid Build Coastguard Worker
2617*6236dae4SAndroid Build Coastguard Worker myssh_block2waitfor(conn, (nread == SSH_AGAIN));
2618*6236dae4SAndroid Build Coastguard Worker
2619*6236dae4SAndroid Build Coastguard Worker if(nread == SSH_AGAIN) {
2620*6236dae4SAndroid Build Coastguard Worker *err = CURLE_AGAIN;
2621*6236dae4SAndroid Build Coastguard Worker return -1;
2622*6236dae4SAndroid Build Coastguard Worker }
2623*6236dae4SAndroid Build Coastguard Worker else if(nread < 0) {
2624*6236dae4SAndroid Build Coastguard Worker *err = CURLE_RECV_ERROR;
2625*6236dae4SAndroid Build Coastguard Worker return -1;
2626*6236dae4SAndroid Build Coastguard Worker }
2627*6236dae4SAndroid Build Coastguard Worker
2628*6236dae4SAndroid Build Coastguard Worker conn->proto.sshc.sftp_recv_state = 0;
2629*6236dae4SAndroid Build Coastguard Worker return nread;
2630*6236dae4SAndroid Build Coastguard Worker
2631*6236dae4SAndroid Build Coastguard Worker default:
2632*6236dae4SAndroid Build Coastguard Worker /* we never reach here */
2633*6236dae4SAndroid Build Coastguard Worker return -1;
2634*6236dae4SAndroid Build Coastguard Worker }
2635*6236dae4SAndroid Build Coastguard Worker }
2636*6236dae4SAndroid Build Coastguard Worker
sftp_quote(struct Curl_easy * data)2637*6236dae4SAndroid Build Coastguard Worker static void sftp_quote(struct Curl_easy *data)
2638*6236dae4SAndroid Build Coastguard Worker {
2639*6236dae4SAndroid Build Coastguard Worker const char *cp;
2640*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
2641*6236dae4SAndroid Build Coastguard Worker struct SSHPROTO *protop = data->req.p.ssh;
2642*6236dae4SAndroid Build Coastguard Worker struct ssh_conn *sshc = &conn->proto.sshc;
2643*6236dae4SAndroid Build Coastguard Worker CURLcode result;
2644*6236dae4SAndroid Build Coastguard Worker
2645*6236dae4SAndroid Build Coastguard Worker /*
2646*6236dae4SAndroid Build Coastguard Worker * Support some of the "FTP" commands
2647*6236dae4SAndroid Build Coastguard Worker */
2648*6236dae4SAndroid Build Coastguard Worker char *cmd = sshc->quote_item->data;
2649*6236dae4SAndroid Build Coastguard Worker sshc->acceptfail = FALSE;
2650*6236dae4SAndroid Build Coastguard Worker
2651*6236dae4SAndroid Build Coastguard Worker /* if a command starts with an asterisk, which a legal SFTP command never
2652*6236dae4SAndroid Build Coastguard Worker can, the command will be allowed to fail without it causing any
2653*6236dae4SAndroid Build Coastguard Worker aborts or cancels etc. It will cause libcurl to act as if the command
2654*6236dae4SAndroid Build Coastguard Worker is successful, whatever the server responds. */
2655*6236dae4SAndroid Build Coastguard Worker
2656*6236dae4SAndroid Build Coastguard Worker if(cmd[0] == '*') {
2657*6236dae4SAndroid Build Coastguard Worker cmd++;
2658*6236dae4SAndroid Build Coastguard Worker sshc->acceptfail = TRUE;
2659*6236dae4SAndroid Build Coastguard Worker }
2660*6236dae4SAndroid Build Coastguard Worker
2661*6236dae4SAndroid Build Coastguard Worker if(strcasecompare("pwd", cmd)) {
2662*6236dae4SAndroid Build Coastguard Worker /* output debug output if that is requested */
2663*6236dae4SAndroid Build Coastguard Worker char *tmp = aprintf("257 \"%s\" is current directory.\n",
2664*6236dae4SAndroid Build Coastguard Worker protop->path);
2665*6236dae4SAndroid Build Coastguard Worker if(!tmp) {
2666*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = CURLE_OUT_OF_MEMORY;
2667*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
2668*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
2669*6236dae4SAndroid Build Coastguard Worker return;
2670*6236dae4SAndroid Build Coastguard Worker }
2671*6236dae4SAndroid Build Coastguard Worker Curl_debug(data, CURLINFO_HEADER_OUT, (char *) "PWD\n", 4);
2672*6236dae4SAndroid Build Coastguard Worker Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
2673*6236dae4SAndroid Build Coastguard Worker
2674*6236dae4SAndroid Build Coastguard Worker /* this sends an FTP-like "header" to the header callback so that the
2675*6236dae4SAndroid Build Coastguard Worker current directory can be read very similar to how it is read when
2676*6236dae4SAndroid Build Coastguard Worker using ordinary FTP. */
2677*6236dae4SAndroid Build Coastguard Worker result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
2678*6236dae4SAndroid Build Coastguard Worker free(tmp);
2679*6236dae4SAndroid Build Coastguard Worker if(result) {
2680*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
2681*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
2682*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = result;
2683*6236dae4SAndroid Build Coastguard Worker }
2684*6236dae4SAndroid Build Coastguard Worker else
2685*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_NEXT_QUOTE);
2686*6236dae4SAndroid Build Coastguard Worker return;
2687*6236dae4SAndroid Build Coastguard Worker }
2688*6236dae4SAndroid Build Coastguard Worker
2689*6236dae4SAndroid Build Coastguard Worker /*
2690*6236dae4SAndroid Build Coastguard Worker * the arguments following the command must be separated from the
2691*6236dae4SAndroid Build Coastguard Worker * command with a space so we can check for it unconditionally
2692*6236dae4SAndroid Build Coastguard Worker */
2693*6236dae4SAndroid Build Coastguard Worker cp = strchr(cmd, ' ');
2694*6236dae4SAndroid Build Coastguard Worker if(!cp) {
2695*6236dae4SAndroid Build Coastguard Worker failf(data, "Syntax error in SFTP command. Supply parameter(s)");
2696*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
2697*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
2698*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = CURLE_QUOTE_ERROR;
2699*6236dae4SAndroid Build Coastguard Worker return;
2700*6236dae4SAndroid Build Coastguard Worker }
2701*6236dae4SAndroid Build Coastguard Worker
2702*6236dae4SAndroid Build Coastguard Worker /*
2703*6236dae4SAndroid Build Coastguard Worker * also, every command takes at least one argument so we get that
2704*6236dae4SAndroid Build Coastguard Worker * first argument right now
2705*6236dae4SAndroid Build Coastguard Worker */
2706*6236dae4SAndroid Build Coastguard Worker result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir);
2707*6236dae4SAndroid Build Coastguard Worker if(result) {
2708*6236dae4SAndroid Build Coastguard Worker if(result == CURLE_OUT_OF_MEMORY)
2709*6236dae4SAndroid Build Coastguard Worker failf(data, "Out of memory");
2710*6236dae4SAndroid Build Coastguard Worker else
2711*6236dae4SAndroid Build Coastguard Worker failf(data, "Syntax error: Bad first parameter");
2712*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
2713*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
2714*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = result;
2715*6236dae4SAndroid Build Coastguard Worker return;
2716*6236dae4SAndroid Build Coastguard Worker }
2717*6236dae4SAndroid Build Coastguard Worker
2718*6236dae4SAndroid Build Coastguard Worker /*
2719*6236dae4SAndroid Build Coastguard Worker * SFTP is a binary protocol, so we do not send text commands
2720*6236dae4SAndroid Build Coastguard Worker * to the server. Instead, we scan for commands used by
2721*6236dae4SAndroid Build Coastguard Worker * OpenSSH's sftp program and call the appropriate libssh
2722*6236dae4SAndroid Build Coastguard Worker * functions.
2723*6236dae4SAndroid Build Coastguard Worker */
2724*6236dae4SAndroid Build Coastguard Worker if(strncasecompare(cmd, "chgrp ", 6) ||
2725*6236dae4SAndroid Build Coastguard Worker strncasecompare(cmd, "chmod ", 6) ||
2726*6236dae4SAndroid Build Coastguard Worker strncasecompare(cmd, "chown ", 6) ||
2727*6236dae4SAndroid Build Coastguard Worker strncasecompare(cmd, "atime ", 6) ||
2728*6236dae4SAndroid Build Coastguard Worker strncasecompare(cmd, "mtime ", 6)) {
2729*6236dae4SAndroid Build Coastguard Worker /* attribute change */
2730*6236dae4SAndroid Build Coastguard Worker
2731*6236dae4SAndroid Build Coastguard Worker /* sshc->quote_path1 contains the mode to set */
2732*6236dae4SAndroid Build Coastguard Worker /* get the destination */
2733*6236dae4SAndroid Build Coastguard Worker result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2734*6236dae4SAndroid Build Coastguard Worker if(result) {
2735*6236dae4SAndroid Build Coastguard Worker if(result == CURLE_OUT_OF_MEMORY)
2736*6236dae4SAndroid Build Coastguard Worker failf(data, "Out of memory");
2737*6236dae4SAndroid Build Coastguard Worker else
2738*6236dae4SAndroid Build Coastguard Worker failf(data, "Syntax error in chgrp/chmod/chown/atime/mtime: "
2739*6236dae4SAndroid Build Coastguard Worker "Bad second parameter");
2740*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path1);
2741*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
2742*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
2743*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = result;
2744*6236dae4SAndroid Build Coastguard Worker return;
2745*6236dae4SAndroid Build Coastguard Worker }
2746*6236dae4SAndroid Build Coastguard Worker sshc->quote_attrs = NULL;
2747*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_QUOTE_STAT);
2748*6236dae4SAndroid Build Coastguard Worker return;
2749*6236dae4SAndroid Build Coastguard Worker }
2750*6236dae4SAndroid Build Coastguard Worker if(strncasecompare(cmd, "ln ", 3) ||
2751*6236dae4SAndroid Build Coastguard Worker strncasecompare(cmd, "symlink ", 8)) {
2752*6236dae4SAndroid Build Coastguard Worker /* symbolic linking */
2753*6236dae4SAndroid Build Coastguard Worker /* sshc->quote_path1 is the source */
2754*6236dae4SAndroid Build Coastguard Worker /* get the destination */
2755*6236dae4SAndroid Build Coastguard Worker result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2756*6236dae4SAndroid Build Coastguard Worker if(result) {
2757*6236dae4SAndroid Build Coastguard Worker if(result == CURLE_OUT_OF_MEMORY)
2758*6236dae4SAndroid Build Coastguard Worker failf(data, "Out of memory");
2759*6236dae4SAndroid Build Coastguard Worker else
2760*6236dae4SAndroid Build Coastguard Worker failf(data, "Syntax error in ln/symlink: Bad second parameter");
2761*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path1);
2762*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
2763*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
2764*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = result;
2765*6236dae4SAndroid Build Coastguard Worker return;
2766*6236dae4SAndroid Build Coastguard Worker }
2767*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_QUOTE_SYMLINK);
2768*6236dae4SAndroid Build Coastguard Worker return;
2769*6236dae4SAndroid Build Coastguard Worker }
2770*6236dae4SAndroid Build Coastguard Worker else if(strncasecompare(cmd, "mkdir ", 6)) {
2771*6236dae4SAndroid Build Coastguard Worker /* create dir */
2772*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_QUOTE_MKDIR);
2773*6236dae4SAndroid Build Coastguard Worker return;
2774*6236dae4SAndroid Build Coastguard Worker }
2775*6236dae4SAndroid Build Coastguard Worker else if(strncasecompare(cmd, "rename ", 7)) {
2776*6236dae4SAndroid Build Coastguard Worker /* rename file */
2777*6236dae4SAndroid Build Coastguard Worker /* first param is the source path */
2778*6236dae4SAndroid Build Coastguard Worker /* second param is the dest. path */
2779*6236dae4SAndroid Build Coastguard Worker result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2780*6236dae4SAndroid Build Coastguard Worker if(result) {
2781*6236dae4SAndroid Build Coastguard Worker if(result == CURLE_OUT_OF_MEMORY)
2782*6236dae4SAndroid Build Coastguard Worker failf(data, "Out of memory");
2783*6236dae4SAndroid Build Coastguard Worker else
2784*6236dae4SAndroid Build Coastguard Worker failf(data, "Syntax error in rename: Bad second parameter");
2785*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path1);
2786*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
2787*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
2788*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = result;
2789*6236dae4SAndroid Build Coastguard Worker return;
2790*6236dae4SAndroid Build Coastguard Worker }
2791*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_QUOTE_RENAME);
2792*6236dae4SAndroid Build Coastguard Worker return;
2793*6236dae4SAndroid Build Coastguard Worker }
2794*6236dae4SAndroid Build Coastguard Worker else if(strncasecompare(cmd, "rmdir ", 6)) {
2795*6236dae4SAndroid Build Coastguard Worker /* delete dir */
2796*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_QUOTE_RMDIR);
2797*6236dae4SAndroid Build Coastguard Worker return;
2798*6236dae4SAndroid Build Coastguard Worker }
2799*6236dae4SAndroid Build Coastguard Worker else if(strncasecompare(cmd, "rm ", 3)) {
2800*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_QUOTE_UNLINK);
2801*6236dae4SAndroid Build Coastguard Worker return;
2802*6236dae4SAndroid Build Coastguard Worker }
2803*6236dae4SAndroid Build Coastguard Worker #ifdef HAS_STATVFS_SUPPORT
2804*6236dae4SAndroid Build Coastguard Worker else if(strncasecompare(cmd, "statvfs ", 8)) {
2805*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_QUOTE_STATVFS);
2806*6236dae4SAndroid Build Coastguard Worker return;
2807*6236dae4SAndroid Build Coastguard Worker }
2808*6236dae4SAndroid Build Coastguard Worker #endif
2809*6236dae4SAndroid Build Coastguard Worker
2810*6236dae4SAndroid Build Coastguard Worker failf(data, "Unknown SFTP command");
2811*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path1);
2812*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path2);
2813*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
2814*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
2815*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = CURLE_QUOTE_ERROR;
2816*6236dae4SAndroid Build Coastguard Worker }
2817*6236dae4SAndroid Build Coastguard Worker
sftp_quote_stat(struct Curl_easy * data)2818*6236dae4SAndroid Build Coastguard Worker static void sftp_quote_stat(struct Curl_easy *data)
2819*6236dae4SAndroid Build Coastguard Worker {
2820*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
2821*6236dae4SAndroid Build Coastguard Worker struct ssh_conn *sshc = &conn->proto.sshc;
2822*6236dae4SAndroid Build Coastguard Worker char *cmd = sshc->quote_item->data;
2823*6236dae4SAndroid Build Coastguard Worker sshc->acceptfail = FALSE;
2824*6236dae4SAndroid Build Coastguard Worker
2825*6236dae4SAndroid Build Coastguard Worker /* if a command starts with an asterisk, which a legal SFTP command never
2826*6236dae4SAndroid Build Coastguard Worker can, the command will be allowed to fail without it causing any
2827*6236dae4SAndroid Build Coastguard Worker aborts or cancels etc. It will cause libcurl to act as if the command
2828*6236dae4SAndroid Build Coastguard Worker is successful, whatever the server responds. */
2829*6236dae4SAndroid Build Coastguard Worker
2830*6236dae4SAndroid Build Coastguard Worker if(cmd[0] == '*') {
2831*6236dae4SAndroid Build Coastguard Worker cmd++;
2832*6236dae4SAndroid Build Coastguard Worker sshc->acceptfail = TRUE;
2833*6236dae4SAndroid Build Coastguard Worker }
2834*6236dae4SAndroid Build Coastguard Worker
2835*6236dae4SAndroid Build Coastguard Worker /* We read the file attributes, store them in sshc->quote_attrs
2836*6236dae4SAndroid Build Coastguard Worker * and modify them accordingly to command. Then we switch to
2837*6236dae4SAndroid Build Coastguard Worker * QUOTE_SETSTAT state to write new ones.
2838*6236dae4SAndroid Build Coastguard Worker */
2839*6236dae4SAndroid Build Coastguard Worker
2840*6236dae4SAndroid Build Coastguard Worker if(sshc->quote_attrs)
2841*6236dae4SAndroid Build Coastguard Worker sftp_attributes_free(sshc->quote_attrs);
2842*6236dae4SAndroid Build Coastguard Worker sshc->quote_attrs = sftp_stat(sshc->sftp_session, sshc->quote_path2);
2843*6236dae4SAndroid Build Coastguard Worker if(!sshc->quote_attrs) {
2844*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path1);
2845*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path2);
2846*6236dae4SAndroid Build Coastguard Worker failf(data, "Attempt to get SFTP stats failed: %d",
2847*6236dae4SAndroid Build Coastguard Worker sftp_get_error(sshc->sftp_session));
2848*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
2849*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
2850*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = CURLE_QUOTE_ERROR;
2851*6236dae4SAndroid Build Coastguard Worker return;
2852*6236dae4SAndroid Build Coastguard Worker }
2853*6236dae4SAndroid Build Coastguard Worker
2854*6236dae4SAndroid Build Coastguard Worker /* Now set the new attributes... */
2855*6236dae4SAndroid Build Coastguard Worker if(strncasecompare(cmd, "chgrp", 5)) {
2856*6236dae4SAndroid Build Coastguard Worker sshc->quote_attrs->gid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2857*6236dae4SAndroid Build Coastguard Worker if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
2858*6236dae4SAndroid Build Coastguard Worker !sshc->acceptfail) {
2859*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path1);
2860*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path2);
2861*6236dae4SAndroid Build Coastguard Worker failf(data, "Syntax error: chgrp gid not a number");
2862*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
2863*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
2864*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = CURLE_QUOTE_ERROR;
2865*6236dae4SAndroid Build Coastguard Worker return;
2866*6236dae4SAndroid Build Coastguard Worker }
2867*6236dae4SAndroid Build Coastguard Worker sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2868*6236dae4SAndroid Build Coastguard Worker }
2869*6236dae4SAndroid Build Coastguard Worker else if(strncasecompare(cmd, "chmod", 5)) {
2870*6236dae4SAndroid Build Coastguard Worker mode_t perms;
2871*6236dae4SAndroid Build Coastguard Worker perms = (mode_t)strtoul(sshc->quote_path1, NULL, 8);
2872*6236dae4SAndroid Build Coastguard Worker /* permissions are octal */
2873*6236dae4SAndroid Build Coastguard Worker if(perms == 0 && !ISDIGIT(sshc->quote_path1[0])) {
2874*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path1);
2875*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path2);
2876*6236dae4SAndroid Build Coastguard Worker failf(data, "Syntax error: chmod permissions not a number");
2877*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
2878*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
2879*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = CURLE_QUOTE_ERROR;
2880*6236dae4SAndroid Build Coastguard Worker return;
2881*6236dae4SAndroid Build Coastguard Worker }
2882*6236dae4SAndroid Build Coastguard Worker sshc->quote_attrs->permissions = perms;
2883*6236dae4SAndroid Build Coastguard Worker sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_PERMISSIONS;
2884*6236dae4SAndroid Build Coastguard Worker }
2885*6236dae4SAndroid Build Coastguard Worker else if(strncasecompare(cmd, "chown", 5)) {
2886*6236dae4SAndroid Build Coastguard Worker sshc->quote_attrs->uid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2887*6236dae4SAndroid Build Coastguard Worker if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
2888*6236dae4SAndroid Build Coastguard Worker !sshc->acceptfail) {
2889*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path1);
2890*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path2);
2891*6236dae4SAndroid Build Coastguard Worker failf(data, "Syntax error: chown uid not a number");
2892*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
2893*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
2894*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = CURLE_QUOTE_ERROR;
2895*6236dae4SAndroid Build Coastguard Worker return;
2896*6236dae4SAndroid Build Coastguard Worker }
2897*6236dae4SAndroid Build Coastguard Worker sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2898*6236dae4SAndroid Build Coastguard Worker }
2899*6236dae4SAndroid Build Coastguard Worker else if(strncasecompare(cmd, "atime", 5) ||
2900*6236dae4SAndroid Build Coastguard Worker strncasecompare(cmd, "mtime", 5)) {
2901*6236dae4SAndroid Build Coastguard Worker time_t date = Curl_getdate_capped(sshc->quote_path1);
2902*6236dae4SAndroid Build Coastguard Worker bool fail = FALSE;
2903*6236dae4SAndroid Build Coastguard Worker if(date == -1) {
2904*6236dae4SAndroid Build Coastguard Worker failf(data, "incorrect date format for %.*s", 5, cmd);
2905*6236dae4SAndroid Build Coastguard Worker fail = TRUE;
2906*6236dae4SAndroid Build Coastguard Worker }
2907*6236dae4SAndroid Build Coastguard Worker #if SIZEOF_TIME_T > 4
2908*6236dae4SAndroid Build Coastguard Worker else if(date > 0xffffffff) {
2909*6236dae4SAndroid Build Coastguard Worker failf(data, "date overflow");
2910*6236dae4SAndroid Build Coastguard Worker fail = TRUE; /* avoid setting a capped time */
2911*6236dae4SAndroid Build Coastguard Worker }
2912*6236dae4SAndroid Build Coastguard Worker #endif
2913*6236dae4SAndroid Build Coastguard Worker if(fail) {
2914*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path1);
2915*6236dae4SAndroid Build Coastguard Worker Curl_safefree(sshc->quote_path2);
2916*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_CLOSE);
2917*6236dae4SAndroid Build Coastguard Worker sshc->nextstate = SSH_NO_STATE;
2918*6236dae4SAndroid Build Coastguard Worker sshc->actualcode = CURLE_QUOTE_ERROR;
2919*6236dae4SAndroid Build Coastguard Worker return;
2920*6236dae4SAndroid Build Coastguard Worker }
2921*6236dae4SAndroid Build Coastguard Worker if(strncasecompare(cmd, "atime", 5))
2922*6236dae4SAndroid Build Coastguard Worker sshc->quote_attrs->atime = (uint32_t)date;
2923*6236dae4SAndroid Build Coastguard Worker else /* mtime */
2924*6236dae4SAndroid Build Coastguard Worker sshc->quote_attrs->mtime = (uint32_t)date;
2925*6236dae4SAndroid Build Coastguard Worker
2926*6236dae4SAndroid Build Coastguard Worker sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_ACMODTIME;
2927*6236dae4SAndroid Build Coastguard Worker }
2928*6236dae4SAndroid Build Coastguard Worker
2929*6236dae4SAndroid Build Coastguard Worker /* Now send the completed structure... */
2930*6236dae4SAndroid Build Coastguard Worker state(data, SSH_SFTP_QUOTE_SETSTAT);
2931*6236dae4SAndroid Build Coastguard Worker return;
2932*6236dae4SAndroid Build Coastguard Worker }
2933*6236dae4SAndroid Build Coastguard Worker
Curl_ssh_init(void)2934*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_ssh_init(void)
2935*6236dae4SAndroid Build Coastguard Worker {
2936*6236dae4SAndroid Build Coastguard Worker if(ssh_init()) {
2937*6236dae4SAndroid Build Coastguard Worker DEBUGF(fprintf(stderr, "Error: libssh_init failed\n"));
2938*6236dae4SAndroid Build Coastguard Worker return CURLE_FAILED_INIT;
2939*6236dae4SAndroid Build Coastguard Worker }
2940*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
2941*6236dae4SAndroid Build Coastguard Worker }
2942*6236dae4SAndroid Build Coastguard Worker
Curl_ssh_cleanup(void)2943*6236dae4SAndroid Build Coastguard Worker void Curl_ssh_cleanup(void)
2944*6236dae4SAndroid Build Coastguard Worker {
2945*6236dae4SAndroid Build Coastguard Worker (void)ssh_finalize();
2946*6236dae4SAndroid Build Coastguard Worker }
2947*6236dae4SAndroid Build Coastguard Worker
Curl_ssh_version(char * buffer,size_t buflen)2948*6236dae4SAndroid Build Coastguard Worker void Curl_ssh_version(char *buffer, size_t buflen)
2949*6236dae4SAndroid Build Coastguard Worker {
2950*6236dae4SAndroid Build Coastguard Worker (void)msnprintf(buffer, buflen, "libssh/%s", ssh_version(0));
2951*6236dae4SAndroid Build Coastguard Worker }
2952*6236dae4SAndroid Build Coastguard Worker
2953*6236dae4SAndroid Build Coastguard Worker #endif /* USE_LIBSSH */
2954