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