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