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, /* connection_check */
166 ZERO_NULL, /* attach connection */
167 PORT_SSH, /* defport */
168 CURLPROTO_SCP, /* protocol */
169 CURLPROTO_SCP, /* family */
170 PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */
171 };
172
173 /*
174 * SFTP protocol handler.
175 */
176
177 const struct Curl_handler Curl_handler_sftp = {
178 "SFTP", /* scheme */
179 myssh_setup_connection, /* setup_connection */
180 myssh_do_it, /* do_it */
181 sftp_done, /* done */
182 ZERO_NULL, /* do_more */
183 myssh_connect, /* connect_it */
184 myssh_multi_statemach, /* connecting */
185 sftp_doing, /* doing */
186 myssh_getsock, /* proto_getsock */
187 myssh_getsock, /* doing_getsock */
188 ZERO_NULL, /* domore_getsock */
189 myssh_getsock, /* perform_getsock */
190 sftp_disconnect, /* disconnect */
191 ZERO_NULL, /* write_resp */
192 ZERO_NULL, /* connection_check */
193 ZERO_NULL, /* attach connection */
194 PORT_SSH, /* defport */
195 CURLPROTO_SFTP, /* protocol */
196 CURLPROTO_SFTP, /* family */
197 PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
198 | PROTOPT_NOURLQUERY /* flags */
199 };
200
sftp_error_to_CURLE(int err)201 static CURLcode sftp_error_to_CURLE(int err)
202 {
203 switch(err) {
204 case SSH_FX_OK:
205 return CURLE_OK;
206
207 case SSH_FX_NO_SUCH_FILE:
208 case SSH_FX_NO_SUCH_PATH:
209 return CURLE_REMOTE_FILE_NOT_FOUND;
210
211 case SSH_FX_PERMISSION_DENIED:
212 case SSH_FX_WRITE_PROTECT:
213 return CURLE_REMOTE_ACCESS_DENIED;
214
215 case SSH_FX_FILE_ALREADY_EXISTS:
216 return CURLE_REMOTE_FILE_EXISTS;
217
218 default:
219 break;
220 }
221
222 return CURLE_SSH;
223 }
224
225 #ifndef DEBUGBUILD
226 #define state(x,y) mystate(x,y)
227 #else
228 #define state(x,y) mystate(x,y, __LINE__)
229 #endif
230
231 /*
232 * SSH State machine related code
233 */
234 /* This is the ONLY way to change SSH state! */
mystate(struct Curl_easy *data, sshstate nowstate , int lineno )235 static void mystate(struct Curl_easy *data, sshstate nowstate
236 #ifdef DEBUGBUILD
237 , int lineno
238 #endif
239 )
240 {
241 struct connectdata *conn = data->conn;
242 struct ssh_conn *sshc = &conn->proto.sshc;
243 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
244 /* for debug purposes */
245 static const char *const names[] = {
246 "SSH_STOP",
247 "SSH_INIT",
248 "SSH_S_STARTUP",
249 "SSH_HOSTKEY",
250 "SSH_AUTHLIST",
251 "SSH_AUTH_PKEY_INIT",
252 "SSH_AUTH_PKEY",
253 "SSH_AUTH_PASS_INIT",
254 "SSH_AUTH_PASS",
255 "SSH_AUTH_AGENT_INIT",
256 "SSH_AUTH_AGENT_LIST",
257 "SSH_AUTH_AGENT",
258 "SSH_AUTH_HOST_INIT",
259 "SSH_AUTH_HOST",
260 "SSH_AUTH_KEY_INIT",
261 "SSH_AUTH_KEY",
262 "SSH_AUTH_GSSAPI",
263 "SSH_AUTH_DONE",
264 "SSH_SFTP_INIT",
265 "SSH_SFTP_REALPATH",
266 "SSH_SFTP_QUOTE_INIT",
267 "SSH_SFTP_POSTQUOTE_INIT",
268 "SSH_SFTP_QUOTE",
269 "SSH_SFTP_NEXT_QUOTE",
270 "SSH_SFTP_QUOTE_STAT",
271 "SSH_SFTP_QUOTE_SETSTAT",
272 "SSH_SFTP_QUOTE_SYMLINK",
273 "SSH_SFTP_QUOTE_MKDIR",
274 "SSH_SFTP_QUOTE_RENAME",
275 "SSH_SFTP_QUOTE_RMDIR",
276 "SSH_SFTP_QUOTE_UNLINK",
277 "SSH_SFTP_QUOTE_STATVFS",
278 "SSH_SFTP_GETINFO",
279 "SSH_SFTP_FILETIME",
280 "SSH_SFTP_TRANS_INIT",
281 "SSH_SFTP_UPLOAD_INIT",
282 "SSH_SFTP_CREATE_DIRS_INIT",
283 "SSH_SFTP_CREATE_DIRS",
284 "SSH_SFTP_CREATE_DIRS_MKDIR",
285 "SSH_SFTP_READDIR_INIT",
286 "SSH_SFTP_READDIR",
287 "SSH_SFTP_READDIR_LINK",
288 "SSH_SFTP_READDIR_BOTTOM",
289 "SSH_SFTP_READDIR_DONE",
290 "SSH_SFTP_DOWNLOAD_INIT",
291 "SSH_SFTP_DOWNLOAD_STAT",
292 "SSH_SFTP_CLOSE",
293 "SSH_SFTP_SHUTDOWN",
294 "SSH_SCP_TRANS_INIT",
295 "SSH_SCP_UPLOAD_INIT",
296 "SSH_SCP_DOWNLOAD_INIT",
297 "SSH_SCP_DOWNLOAD",
298 "SSH_SCP_DONE",
299 "SSH_SCP_SEND_EOF",
300 "SSH_SCP_WAIT_EOF",
301 "SSH_SCP_WAIT_CLOSE",
302 "SSH_SCP_CHANNEL_FREE",
303 "SSH_SESSION_DISCONNECT",
304 "SSH_SESSION_FREE",
305 "QUIT"
306 };
307
308
309 if(sshc->state != nowstate) {
310 infof(data, "SSH %p state change from %s to %s (line %d)",
311 (void *) sshc, names[sshc->state], names[nowstate],
312 lineno);
313 }
314 #endif
315
316 sshc->state = nowstate;
317 }
318
319 /* Multiple options:
320 * 1. data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] is set with an MD5
321 * hash (90s style auth, not sure we should have it here)
322 * 2. data->set.ssh_keyfunc callback is set. Then we do trust on first
323 * use. We even save on knownhosts if CURLKHSTAT_FINE_ADD_TO_FILE
324 * is returned by it.
325 * 3. none of the above. We only accept if it is present on known hosts.
326 *
327 * Returns SSH_OK or SSH_ERROR.
328 */
myssh_is_known(struct Curl_easy *data)329 static int myssh_is_known(struct Curl_easy *data)
330 {
331 int rc;
332 struct connectdata *conn = data->conn;
333 struct ssh_conn *sshc = &conn->proto.sshc;
334 ssh_key pubkey;
335 size_t hlen;
336 unsigned char *hash = NULL;
337 char *found_base64 = NULL;
338 char *known_base64 = NULL;
339 int vstate;
340 enum curl_khmatch keymatch;
341 struct curl_khkey foundkey;
342 struct curl_khkey *knownkeyp = NULL;
343 curl_sshkeycallback func =
344 data->set.ssh_keyfunc;
345
346 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
347 struct ssh_knownhosts_entry *knownhostsentry = NULL;
348 struct curl_khkey knownkey;
349 #endif
350
351 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0)
352 rc = ssh_get_server_publickey(sshc->ssh_session, &pubkey);
353 #else
354 rc = ssh_get_publickey(sshc->ssh_session, &pubkey);
355 #endif
356 if(rc != SSH_OK)
357 return rc;
358
359 if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) {
360 int i;
361 char md5buffer[33];
362 const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
363
364 rc = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_MD5,
365 &hash, &hlen);
366 if(rc != SSH_OK || hlen != 16) {
367 failf(data,
368 "Denied establishing ssh session: md5 fingerprint not available");
369 goto cleanup;
370 }
371
372 for(i = 0; i < 16; i++)
373 msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char)hash[i]);
374
375 infof(data, "SSH MD5 fingerprint: %s", md5buffer);
376
377 if(!strcasecompare(md5buffer, pubkey_md5)) {
378 failf(data,
379 "Denied establishing ssh session: mismatch md5 fingerprint. "
380 "Remote %s is not equal to %s", md5buffer, pubkey_md5);
381 rc = SSH_ERROR;
382 goto cleanup;
383 }
384
385 rc = SSH_OK;
386 goto cleanup;
387 }
388
389 if(data->set.ssl.primary.verifyhost != TRUE) {
390 rc = SSH_OK;
391 goto cleanup;
392 }
393
394 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
395 /* Get the known_key from the known hosts file */
396 vstate = ssh_session_get_known_hosts_entry(sshc->ssh_session,
397 &knownhostsentry);
398
399 /* Case an entry was found in a known hosts file */
400 if(knownhostsentry) {
401 if(knownhostsentry->publickey) {
402 rc = ssh_pki_export_pubkey_base64(knownhostsentry->publickey,
403 &known_base64);
404 if(rc != SSH_OK) {
405 goto cleanup;
406 }
407 knownkey.key = known_base64;
408 knownkey.len = strlen(known_base64);
409
410 switch(ssh_key_type(knownhostsentry->publickey)) {
411 case SSH_KEYTYPE_RSA:
412 knownkey.keytype = CURLKHTYPE_RSA;
413 break;
414 case SSH_KEYTYPE_RSA1:
415 knownkey.keytype = CURLKHTYPE_RSA1;
416 break;
417 case SSH_KEYTYPE_ECDSA:
418 case SSH_KEYTYPE_ECDSA_P256:
419 case SSH_KEYTYPE_ECDSA_P384:
420 case SSH_KEYTYPE_ECDSA_P521:
421 knownkey.keytype = CURLKHTYPE_ECDSA;
422 break;
423 case SSH_KEYTYPE_ED25519:
424 knownkey.keytype = CURLKHTYPE_ED25519;
425 break;
426 case SSH_KEYTYPE_DSS:
427 knownkey.keytype = CURLKHTYPE_DSS;
428 break;
429 default:
430 rc = SSH_ERROR;
431 goto cleanup;
432 }
433 knownkeyp = &knownkey;
434 }
435 }
436
437 switch(vstate) {
438 case SSH_KNOWN_HOSTS_OK:
439 keymatch = CURLKHMATCH_OK;
440 break;
441 case SSH_KNOWN_HOSTS_OTHER:
442 case SSH_KNOWN_HOSTS_NOT_FOUND:
443 case SSH_KNOWN_HOSTS_UNKNOWN:
444 case SSH_KNOWN_HOSTS_ERROR:
445 keymatch = CURLKHMATCH_MISSING;
446 break;
447 default:
448 keymatch = CURLKHMATCH_MISMATCH;
449 break;
450 }
451
452 #else
453 vstate = ssh_is_server_known(sshc->ssh_session);
454 switch(vstate) {
455 case SSH_SERVER_KNOWN_OK:
456 keymatch = CURLKHMATCH_OK;
457 break;
458 case SSH_SERVER_FILE_NOT_FOUND:
459 case SSH_SERVER_NOT_KNOWN:
460 keymatch = CURLKHMATCH_MISSING;
461 break;
462 default:
463 keymatch = CURLKHMATCH_MISMATCH;
464 break;
465 }
466 #endif
467
468 if(func) { /* use callback to determine action */
469 rc = ssh_pki_export_pubkey_base64(pubkey, &found_base64);
470 if(rc != SSH_OK)
471 goto cleanup;
472
473 foundkey.key = found_base64;
474 foundkey.len = strlen(found_base64);
475
476 switch(ssh_key_type(pubkey)) {
477 case SSH_KEYTYPE_RSA:
478 foundkey.keytype = CURLKHTYPE_RSA;
479 break;
480 case SSH_KEYTYPE_RSA1:
481 foundkey.keytype = CURLKHTYPE_RSA1;
482 break;
483 case SSH_KEYTYPE_ECDSA:
484 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
485 case SSH_KEYTYPE_ECDSA_P256:
486 case SSH_KEYTYPE_ECDSA_P384:
487 case SSH_KEYTYPE_ECDSA_P521:
488 #endif
489 foundkey.keytype = CURLKHTYPE_ECDSA;
490 break;
491 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,7,0)
492 case SSH_KEYTYPE_ED25519:
493 foundkey.keytype = CURLKHTYPE_ED25519;
494 break;
495 #endif
496 case SSH_KEYTYPE_DSS:
497 foundkey.keytype = CURLKHTYPE_DSS;
498 break;
499 default:
500 rc = SSH_ERROR;
501 goto cleanup;
502 }
503
504 Curl_set_in_callback(data, true);
505 rc = func(data, knownkeyp, /* from the knownhosts file */
506 &foundkey, /* from the remote host */
507 keymatch, data->set.ssh_keyfunc_userp);
508 Curl_set_in_callback(data, false);
509
510 switch(rc) {
511 case CURLKHSTAT_FINE_ADD_TO_FILE:
512 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0)
513 rc = ssh_session_update_known_hosts(sshc->ssh_session);
514 #else
515 rc = ssh_write_knownhost(sshc->ssh_session);
516 #endif
517 if(rc != SSH_OK) {
518 goto cleanup;
519 }
520 break;
521 case CURLKHSTAT_FINE:
522 break;
523 default: /* REJECT/DEFER */
524 rc = SSH_ERROR;
525 goto cleanup;
526 }
527 }
528 else {
529 if(keymatch != CURLKHMATCH_OK) {
530 rc = SSH_ERROR;
531 goto cleanup;
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(conn->seek_func) {
1296 Curl_set_in_callback(data, true);
1297 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1298 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_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
1353
1354 /* not set by Curl_setup_transfer 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_setup_transfer(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 size = to - from + 1;
1669 }
1670
1671 rc = sftp_seek64(sshc->sftp_file, from);
1672 if(rc) {
1673 MOVE_TO_SFTP_CLOSE_STATE();
1674 break;
1675 }
1676 }
1677 data->req.size = size;
1678 data->req.maxdownload = size;
1679 Curl_pgrsSetDownloadSize(data, size);
1680 }
1681
1682 /* We can resume if we can seek to the resume position */
1683 if(data->state.resume_from) {
1684 if(data->state.resume_from < 0) {
1685 /* We're supposed to download the last abs(from) bytes */
1686 if((curl_off_t)size < -data->state.resume_from) {
1687 failf(data, "Offset (%"
1688 CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
1689 CURL_FORMAT_CURL_OFF_T ")",
1690 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 (%" CURL_FORMAT_CURL_OFF_T
1699 ") was beyond file size (%" CURL_FORMAT_CURL_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_setup_transfer(data, -1, -1, FALSE, -1);
1722 infof(data, "File already completely downloaded");
1723 state(data, SSH_STOP);
1724 break;
1725 }
1726 Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1);
1727
1728 /* not set by Curl_setup_transfer 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_setup_transfer(data, -1, data->req.size, FALSE, FIRSTSOCKET);
1851
1852 /* not set by Curl_setup_transfer to preserve keepon bits */
1853 conn->sockfd = conn->writesockfd;
1854
1855 /* store this original bitmask setup to use later on if we can't
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_setup_transfer(data, FIRSTSOCKET, bytecount, FALSE, -1);
1895
1896 /* not set by Curl_setup_transfer 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've 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 return bitmap;
2056 }
2057
myssh_block2waitfor(struct connectdata *conn, bool block)2058 static void myssh_block2waitfor(struct connectdata *conn, bool block)
2059 {
2060 struct ssh_conn *sshc = &conn->proto.sshc;
2061
2062 /* If it didn't block, or nothing was returned by ssh_get_poll_flags
2063 * have the original set */
2064 conn->waitfor = sshc->orig_waitfor;
2065
2066 if(block) {
2067 int dir = ssh_get_poll_flags(sshc->ssh_session);
2068 if(dir & SSH_READ_PENDING) {
2069 /* translate the libssh define bits into our own bit defines */
2070 conn->waitfor = KEEP_RECV;
2071 }
2072 else if(dir & SSH_WRITE_PENDING) {
2073 conn->waitfor = KEEP_SEND;
2074 }
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) ? TRUE : FALSE;
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, 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 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, conn->host.name);
2195 if(rc != SSH_OK) {
2196 failf(data, "Could not set remote host");
2197 return CURLE_FAILED_INIT;
2198 }
2199
2200 rc = ssh_options_parse_config(ssh->ssh_session, NULL);
2201 if(rc != SSH_OK) {
2202 infof(data, "Could not parse SSH configuration files");
2203 /* ignore */
2204 }
2205
2206 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_FD, &sock);
2207 if(rc != SSH_OK) {
2208 failf(data, "Could not set socket");
2209 return CURLE_FAILED_INIT;
2210 }
2211
2212 if(conn->user && conn->user[0] != '\0') {
2213 infof(data, "User: %s", conn->user);
2214 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user);
2215 if(rc != SSH_OK) {
2216 failf(data, "Could not set user");
2217 return CURLE_FAILED_INIT;
2218 }
2219 }
2220
2221 if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
2222 infof(data, "Known hosts: %s", data->set.str[STRING_SSH_KNOWNHOSTS]);
2223 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS,
2224 data->set.str[STRING_SSH_KNOWNHOSTS]);
2225 if(rc != SSH_OK) {
2226 failf(data, "Could not set known hosts file path");
2227 return CURLE_FAILED_INIT;
2228 }
2229 }
2230
2231 if(conn->remote_port) {
2232 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_PORT,
2233 &conn->remote_port);
2234 if(rc != SSH_OK) {
2235 failf(data, "Could not set remote port");
2236 return CURLE_FAILED_INIT;
2237 }
2238 }
2239
2240 if(data->set.ssh_compression) {
2241 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_COMPRESSION,
2242 "zlib,zlib@openssh.com,none");
2243 if(rc != SSH_OK) {
2244 failf(data, "Could not set compression");
2245 return CURLE_FAILED_INIT;
2246 }
2247 }
2248
2249 ssh->privkey = NULL;
2250 ssh->pubkey = NULL;
2251
2252 if(data->set.str[STRING_SSH_PUBLIC_KEY]) {
2253 rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY],
2254 &ssh->pubkey);
2255 if(rc != SSH_OK) {
2256 failf(data, "Could not load public key file");
2257 return CURLE_FAILED_INIT;
2258 }
2259 }
2260
2261 /* we do not verify here, we do it at the state machine,
2262 * after connection */
2263
2264 state(data, SSH_INIT);
2265
2266 result = myssh_multi_statemach(data, done);
2267
2268 return result;
2269 }
2270
2271 /* called from multi.c while DOing */
scp_doing(struct Curl_easy *data, bool *dophase_done)2272 static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done)
2273 {
2274 CURLcode result;
2275
2276 result = myssh_multi_statemach(data, dophase_done);
2277
2278 if(*dophase_done) {
2279 DEBUGF(infof(data, "DO phase is complete"));
2280 }
2281 return result;
2282 }
2283
2284 /*
2285 ***********************************************************************
2286 *
2287 * scp_perform()
2288 *
2289 * This is the actual DO function for SCP. Get a file according to
2290 * the options previously setup.
2291 */
2292
2293 static
scp_perform(struct Curl_easy *data, bool *connected, bool *dophase_done)2294 CURLcode scp_perform(struct Curl_easy *data,
2295 bool *connected, bool *dophase_done)
2296 {
2297 CURLcode result = CURLE_OK;
2298
2299 DEBUGF(infof(data, "DO phase starts"));
2300
2301 *dophase_done = FALSE; /* not done yet */
2302
2303 /* start the first command in the DO phase */
2304 state(data, SSH_SCP_TRANS_INIT);
2305
2306 result = myssh_multi_statemach(data, dophase_done);
2307
2308 *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
2309
2310 if(*dophase_done) {
2311 DEBUGF(infof(data, "DO phase is complete"));
2312 }
2313
2314 return result;
2315 }
2316
myssh_do_it(struct Curl_easy *data, bool *done)2317 static CURLcode myssh_do_it(struct Curl_easy *data, bool *done)
2318 {
2319 CURLcode result;
2320 bool connected = 0;
2321 struct connectdata *conn = data->conn;
2322 struct ssh_conn *sshc = &conn->proto.sshc;
2323
2324 *done = FALSE; /* default to false */
2325
2326 data->req.size = -1; /* make sure this is unknown at this point */
2327
2328 sshc->actualcode = CURLE_OK; /* reset error code */
2329 sshc->secondCreateDirs = 0; /* reset the create dir attempt state
2330 variable */
2331
2332 Curl_pgrsSetUploadCounter(data, 0);
2333 Curl_pgrsSetDownloadCounter(data, 0);
2334 Curl_pgrsSetUploadSize(data, -1);
2335 Curl_pgrsSetDownloadSize(data, -1);
2336
2337 if(conn->handler->protocol & CURLPROTO_SCP)
2338 result = scp_perform(data, &connected, done);
2339 else
2340 result = sftp_perform(data, &connected, done);
2341
2342 return result;
2343 }
2344
2345 /* BLOCKING, but the function is using the state machine so the only reason
2346 this is still blocking is that the multi interface code has no support for
2347 disconnecting operations that takes a while */
scp_disconnect(struct Curl_easy *data, struct connectdata *conn, bool dead_connection)2348 static CURLcode scp_disconnect(struct Curl_easy *data,
2349 struct connectdata *conn,
2350 bool dead_connection)
2351 {
2352 CURLcode result = CURLE_OK;
2353 struct ssh_conn *ssh = &conn->proto.sshc;
2354 (void) dead_connection;
2355
2356 if(ssh->ssh_session) {
2357 /* only if there's a session still around to use! */
2358
2359 state(data, SSH_SESSION_DISCONNECT);
2360
2361 result = myssh_block_statemach(data, TRUE);
2362 }
2363
2364 return result;
2365 }
2366
2367 /* generic done function for both SCP and SFTP called from their specific
2368 done functions */
myssh_done(struct Curl_easy *data, CURLcode status)2369 static CURLcode myssh_done(struct Curl_easy *data, CURLcode status)
2370 {
2371 CURLcode result = CURLE_OK;
2372 struct SSHPROTO *protop = data->req.p.ssh;
2373
2374 if(!status) {
2375 /* run the state-machine */
2376 result = myssh_block_statemach(data, FALSE);
2377 }
2378 else
2379 result = status;
2380
2381 if(protop)
2382 Curl_safefree(protop->path);
2383 if(Curl_pgrsDone(data))
2384 return CURLE_ABORTED_BY_CALLBACK;
2385
2386 data->req.keepon = 0; /* clear all bits */
2387 return result;
2388 }
2389
2390
scp_done(struct Curl_easy *data, CURLcode status, bool premature)2391 static CURLcode scp_done(struct Curl_easy *data, CURLcode status,
2392 bool premature)
2393 {
2394 (void) premature; /* not used */
2395
2396 if(!status)
2397 state(data, SSH_SCP_DONE);
2398
2399 return myssh_done(data, status);
2400
2401 }
2402
scp_send(struct Curl_easy *data, int sockindex, const void *mem, size_t len, CURLcode *err)2403 static ssize_t scp_send(struct Curl_easy *data, int sockindex,
2404 const void *mem, size_t len, CURLcode *err)
2405 {
2406 int rc;
2407 struct connectdata *conn = data->conn;
2408 (void) sockindex; /* we only support SCP on the fixed known primary socket */
2409 (void) err;
2410
2411 rc = ssh_scp_write(conn->proto.sshc.scp_session, mem, len);
2412
2413 #if 0
2414 /* The following code is misleading, mostly added as wishful thinking
2415 * that libssh at some point will implement non-blocking ssh_scp_write/read.
2416 * Currently rc can only be number of bytes read or SSH_ERROR. */
2417 myssh_block2waitfor(conn, (rc == SSH_AGAIN) ? TRUE : FALSE);
2418
2419 if(rc == SSH_AGAIN) {
2420 *err = CURLE_AGAIN;
2421 return 0;
2422 }
2423 else
2424 #endif
2425 if(rc != SSH_OK) {
2426 *err = CURLE_SSH;
2427 return -1;
2428 }
2429
2430 return len;
2431 }
2432
scp_recv(struct Curl_easy *data, int sockindex, char *mem, size_t len, CURLcode *err)2433 static ssize_t scp_recv(struct Curl_easy *data, int sockindex,
2434 char *mem, size_t len, CURLcode *err)
2435 {
2436 ssize_t nread;
2437 struct connectdata *conn = data->conn;
2438 (void) err;
2439 (void) sockindex; /* we only support SCP on the fixed known primary socket */
2440
2441 /* libssh returns int */
2442 nread = ssh_scp_read(conn->proto.sshc.scp_session, mem, len);
2443
2444 #if 0
2445 /* The following code is misleading, mostly added as wishful thinking
2446 * that libssh at some point will implement non-blocking ssh_scp_write/read.
2447 * Currently rc can only be SSH_OK or SSH_ERROR. */
2448
2449 myssh_block2waitfor(conn, (nread == SSH_AGAIN) ? TRUE : FALSE);
2450 if(nread == SSH_AGAIN) {
2451 *err = CURLE_AGAIN;
2452 nread = -1;
2453 }
2454 #endif
2455
2456 return nread;
2457 }
2458
2459 /*
2460 * =============== SFTP ===============
2461 */
2462
2463 /*
2464 ***********************************************************************
2465 *
2466 * sftp_perform()
2467 *
2468 * This is the actual DO function for SFTP. Get a file/directory according to
2469 * the options previously setup.
2470 */
2471
2472 static
sftp_perform(struct Curl_easy *data, bool *connected, bool *dophase_done)2473 CURLcode sftp_perform(struct Curl_easy *data,
2474 bool *connected,
2475 bool *dophase_done)
2476 {
2477 CURLcode result = CURLE_OK;
2478
2479 DEBUGF(infof(data, "DO phase starts"));
2480
2481 *dophase_done = FALSE; /* not done yet */
2482
2483 /* start the first command in the DO phase */
2484 state(data, SSH_SFTP_QUOTE_INIT);
2485
2486 /* run the state-machine */
2487 result = myssh_multi_statemach(data, dophase_done);
2488
2489 *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
2490
2491 if(*dophase_done) {
2492 DEBUGF(infof(data, "DO phase is complete"));
2493 }
2494
2495 return result;
2496 }
2497
2498 /* called from multi.c while DOing */
sftp_doing(struct Curl_easy *data, bool *dophase_done)2499 static CURLcode sftp_doing(struct Curl_easy *data,
2500 bool *dophase_done)
2501 {
2502 CURLcode result = myssh_multi_statemach(data, dophase_done);
2503 if(*dophase_done) {
2504 DEBUGF(infof(data, "DO phase is complete"));
2505 }
2506 return result;
2507 }
2508
2509 /* BLOCKING, but the function is using the state machine so the only reason
2510 this is still blocking is that the multi interface code has no support for
2511 disconnecting operations that takes a while */
sftp_disconnect(struct Curl_easy *data, struct connectdata *conn, bool dead_connection)2512 static CURLcode sftp_disconnect(struct Curl_easy *data,
2513 struct connectdata *conn,
2514 bool dead_connection)
2515 {
2516 CURLcode result = CURLE_OK;
2517 (void) dead_connection;
2518
2519 DEBUGF(infof(data, "SSH DISCONNECT starts now"));
2520
2521 if(conn->proto.sshc.ssh_session) {
2522 /* only if there's a session still around to use! */
2523 state(data, SSH_SFTP_SHUTDOWN);
2524 result = myssh_block_statemach(data, TRUE);
2525 }
2526
2527 DEBUGF(infof(data, "SSH DISCONNECT is done"));
2528
2529 return result;
2530
2531 }
2532
sftp_done(struct Curl_easy *data, CURLcode status, bool premature)2533 static CURLcode sftp_done(struct Curl_easy *data, CURLcode status,
2534 bool premature)
2535 {
2536 struct connectdata *conn = data->conn;
2537 struct ssh_conn *sshc = &conn->proto.sshc;
2538
2539 if(!status) {
2540 /* Post quote commands are executed after the SFTP_CLOSE state to avoid
2541 errors that could happen due to open file handles during POSTQUOTE
2542 operation */
2543 if(!premature && data->set.postquote && !conn->bits.retry)
2544 sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
2545 state(data, SSH_SFTP_CLOSE);
2546 }
2547 return myssh_done(data, status);
2548 }
2549
2550 /* return number of sent bytes */
sftp_send(struct Curl_easy *data, int sockindex, const void *mem, size_t len, CURLcode *err)2551 static ssize_t sftp_send(struct Curl_easy *data, int sockindex,
2552 const void *mem, size_t len, CURLcode *err)
2553 {
2554 ssize_t nwrite;
2555 struct connectdata *conn = data->conn;
2556 (void)sockindex;
2557
2558 /* limit the writes to the maximum specified in Section 3 of
2559 * https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02
2560 */
2561 if(len > 32768)
2562 len = 32768;
2563
2564 nwrite = sftp_write(conn->proto.sshc.sftp_file, mem, len);
2565
2566 myssh_block2waitfor(conn, FALSE);
2567
2568 #if 0 /* not returned by libssh on write */
2569 if(nwrite == SSH_AGAIN) {
2570 *err = CURLE_AGAIN;
2571 nwrite = 0;
2572 }
2573 else
2574 #endif
2575 if(nwrite < 0) {
2576 *err = CURLE_SSH;
2577 nwrite = -1;
2578 }
2579
2580 return nwrite;
2581 }
2582
2583 /*
2584 * Return number of received (decrypted) bytes
2585 * or <0 on error
2586 */
sftp_recv(struct Curl_easy *data, int sockindex, char *mem, size_t len, CURLcode *err)2587 static ssize_t sftp_recv(struct Curl_easy *data, int sockindex,
2588 char *mem, size_t len, CURLcode *err)
2589 {
2590 ssize_t nread;
2591 struct connectdata *conn = data->conn;
2592 (void)sockindex;
2593
2594 DEBUGASSERT(len < CURL_MAX_READ_SIZE);
2595
2596 switch(conn->proto.sshc.sftp_recv_state) {
2597 case 0:
2598 conn->proto.sshc.sftp_file_index =
2599 sftp_async_read_begin(conn->proto.sshc.sftp_file,
2600 (uint32_t)len);
2601 if(conn->proto.sshc.sftp_file_index < 0) {
2602 *err = CURLE_RECV_ERROR;
2603 return -1;
2604 }
2605
2606 FALLTHROUGH();
2607 case 1:
2608 conn->proto.sshc.sftp_recv_state = 1;
2609
2610 nread = sftp_async_read(conn->proto.sshc.sftp_file,
2611 mem, (uint32_t)len,
2612 conn->proto.sshc.sftp_file_index);
2613
2614 myssh_block2waitfor(conn, (nread == SSH_AGAIN)?TRUE:FALSE);
2615
2616 if(nread == SSH_AGAIN) {
2617 *err = CURLE_AGAIN;
2618 return -1;
2619 }
2620 else if(nread < 0) {
2621 *err = CURLE_RECV_ERROR;
2622 return -1;
2623 }
2624
2625 conn->proto.sshc.sftp_recv_state = 0;
2626 return nread;
2627
2628 default:
2629 /* we never reach here */
2630 return -1;
2631 }
2632 }
2633
sftp_quote(struct Curl_easy *data)2634 static void sftp_quote(struct Curl_easy *data)
2635 {
2636 const char *cp;
2637 struct connectdata *conn = data->conn;
2638 struct SSHPROTO *protop = data->req.p.ssh;
2639 struct ssh_conn *sshc = &conn->proto.sshc;
2640 CURLcode result;
2641
2642 /*
2643 * Support some of the "FTP" commands
2644 */
2645 char *cmd = sshc->quote_item->data;
2646 sshc->acceptfail = FALSE;
2647
2648 /* if a command starts with an asterisk, which a legal SFTP command never
2649 can, the command will be allowed to fail without it causing any
2650 aborts or cancels etc. It will cause libcurl to act as if the command
2651 is successful, whatever the server responds. */
2652
2653 if(cmd[0] == '*') {
2654 cmd++;
2655 sshc->acceptfail = TRUE;
2656 }
2657
2658 if(strcasecompare("pwd", cmd)) {
2659 /* output debug output if that is requested */
2660 char *tmp = aprintf("257 \"%s\" is current directory.\n",
2661 protop->path);
2662 if(!tmp) {
2663 sshc->actualcode = CURLE_OUT_OF_MEMORY;
2664 state(data, SSH_SFTP_CLOSE);
2665 sshc->nextstate = SSH_NO_STATE;
2666 return;
2667 }
2668 Curl_debug(data, CURLINFO_HEADER_OUT, (char *) "PWD\n", 4);
2669 Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
2670
2671 /* this sends an FTP-like "header" to the header callback so that the
2672 current directory can be read very similar to how it is read when
2673 using ordinary FTP. */
2674 result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
2675 free(tmp);
2676 if(result) {
2677 state(data, SSH_SFTP_CLOSE);
2678 sshc->nextstate = SSH_NO_STATE;
2679 sshc->actualcode = result;
2680 }
2681 else
2682 state(data, SSH_SFTP_NEXT_QUOTE);
2683 return;
2684 }
2685
2686 /*
2687 * the arguments following the command must be separated from the
2688 * command with a space so we can check for it unconditionally
2689 */
2690 cp = strchr(cmd, ' ');
2691 if(!cp) {
2692 failf(data, "Syntax error in SFTP command. Supply parameter(s)");
2693 state(data, SSH_SFTP_CLOSE);
2694 sshc->nextstate = SSH_NO_STATE;
2695 sshc->actualcode = CURLE_QUOTE_ERROR;
2696 return;
2697 }
2698
2699 /*
2700 * also, every command takes at least one argument so we get that
2701 * first argument right now
2702 */
2703 result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir);
2704 if(result) {
2705 if(result == CURLE_OUT_OF_MEMORY)
2706 failf(data, "Out of memory");
2707 else
2708 failf(data, "Syntax error: Bad first parameter");
2709 state(data, SSH_SFTP_CLOSE);
2710 sshc->nextstate = SSH_NO_STATE;
2711 sshc->actualcode = result;
2712 return;
2713 }
2714
2715 /*
2716 * SFTP is a binary protocol, so we don't send text commands
2717 * to the server. Instead, we scan for commands used by
2718 * OpenSSH's sftp program and call the appropriate libssh
2719 * functions.
2720 */
2721 if(strncasecompare(cmd, "chgrp ", 6) ||
2722 strncasecompare(cmd, "chmod ", 6) ||
2723 strncasecompare(cmd, "chown ", 6) ||
2724 strncasecompare(cmd, "atime ", 6) ||
2725 strncasecompare(cmd, "mtime ", 6)) {
2726 /* attribute change */
2727
2728 /* sshc->quote_path1 contains the mode to set */
2729 /* get the destination */
2730 result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2731 if(result) {
2732 if(result == CURLE_OUT_OF_MEMORY)
2733 failf(data, "Out of memory");
2734 else
2735 failf(data, "Syntax error in chgrp/chmod/chown/atime/mtime: "
2736 "Bad second parameter");
2737 Curl_safefree(sshc->quote_path1);
2738 state(data, SSH_SFTP_CLOSE);
2739 sshc->nextstate = SSH_NO_STATE;
2740 sshc->actualcode = result;
2741 return;
2742 }
2743 sshc->quote_attrs = NULL;
2744 state(data, SSH_SFTP_QUOTE_STAT);
2745 return;
2746 }
2747 if(strncasecompare(cmd, "ln ", 3) ||
2748 strncasecompare(cmd, "symlink ", 8)) {
2749 /* symbolic linking */
2750 /* sshc->quote_path1 is the source */
2751 /* get the destination */
2752 result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2753 if(result) {
2754 if(result == CURLE_OUT_OF_MEMORY)
2755 failf(data, "Out of memory");
2756 else
2757 failf(data, "Syntax error in ln/symlink: Bad second parameter");
2758 Curl_safefree(sshc->quote_path1);
2759 state(data, SSH_SFTP_CLOSE);
2760 sshc->nextstate = SSH_NO_STATE;
2761 sshc->actualcode = result;
2762 return;
2763 }
2764 state(data, SSH_SFTP_QUOTE_SYMLINK);
2765 return;
2766 }
2767 else if(strncasecompare(cmd, "mkdir ", 6)) {
2768 /* create dir */
2769 state(data, SSH_SFTP_QUOTE_MKDIR);
2770 return;
2771 }
2772 else if(strncasecompare(cmd, "rename ", 7)) {
2773 /* rename file */
2774 /* first param is the source path */
2775 /* second param is the dest. path */
2776 result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2777 if(result) {
2778 if(result == CURLE_OUT_OF_MEMORY)
2779 failf(data, "Out of memory");
2780 else
2781 failf(data, "Syntax error in rename: Bad second parameter");
2782 Curl_safefree(sshc->quote_path1);
2783 state(data, SSH_SFTP_CLOSE);
2784 sshc->nextstate = SSH_NO_STATE;
2785 sshc->actualcode = result;
2786 return;
2787 }
2788 state(data, SSH_SFTP_QUOTE_RENAME);
2789 return;
2790 }
2791 else if(strncasecompare(cmd, "rmdir ", 6)) {
2792 /* delete dir */
2793 state(data, SSH_SFTP_QUOTE_RMDIR);
2794 return;
2795 }
2796 else if(strncasecompare(cmd, "rm ", 3)) {
2797 state(data, SSH_SFTP_QUOTE_UNLINK);
2798 return;
2799 }
2800 #ifdef HAS_STATVFS_SUPPORT
2801 else if(strncasecompare(cmd, "statvfs ", 8)) {
2802 state(data, SSH_SFTP_QUOTE_STATVFS);
2803 return;
2804 }
2805 #endif
2806
2807 failf(data, "Unknown SFTP command");
2808 Curl_safefree(sshc->quote_path1);
2809 Curl_safefree(sshc->quote_path2);
2810 state(data, SSH_SFTP_CLOSE);
2811 sshc->nextstate = SSH_NO_STATE;
2812 sshc->actualcode = CURLE_QUOTE_ERROR;
2813 }
2814
sftp_quote_stat(struct Curl_easy *data)2815 static void sftp_quote_stat(struct Curl_easy *data)
2816 {
2817 struct connectdata *conn = data->conn;
2818 struct ssh_conn *sshc = &conn->proto.sshc;
2819 char *cmd = sshc->quote_item->data;
2820 sshc->acceptfail = FALSE;
2821
2822 /* if a command starts with an asterisk, which a legal SFTP command never
2823 can, the command will be allowed to fail without it causing any
2824 aborts or cancels etc. It will cause libcurl to act as if the command
2825 is successful, whatever the server responds. */
2826
2827 if(cmd[0] == '*') {
2828 cmd++;
2829 sshc->acceptfail = TRUE;
2830 }
2831
2832 /* We read the file attributes, store them in sshc->quote_attrs
2833 * and modify them accordingly to command. Then we switch to
2834 * QUOTE_SETSTAT state to write new ones.
2835 */
2836
2837 if(sshc->quote_attrs)
2838 sftp_attributes_free(sshc->quote_attrs);
2839 sshc->quote_attrs = sftp_stat(sshc->sftp_session, sshc->quote_path2);
2840 if(!sshc->quote_attrs) {
2841 Curl_safefree(sshc->quote_path1);
2842 Curl_safefree(sshc->quote_path2);
2843 failf(data, "Attempt to get SFTP stats failed: %d",
2844 sftp_get_error(sshc->sftp_session));
2845 state(data, SSH_SFTP_CLOSE);
2846 sshc->nextstate = SSH_NO_STATE;
2847 sshc->actualcode = CURLE_QUOTE_ERROR;
2848 return;
2849 }
2850
2851 /* Now set the new attributes... */
2852 if(strncasecompare(cmd, "chgrp", 5)) {
2853 sshc->quote_attrs->gid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2854 if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
2855 !sshc->acceptfail) {
2856 Curl_safefree(sshc->quote_path1);
2857 Curl_safefree(sshc->quote_path2);
2858 failf(data, "Syntax error: chgrp gid not a number");
2859 state(data, SSH_SFTP_CLOSE);
2860 sshc->nextstate = SSH_NO_STATE;
2861 sshc->actualcode = CURLE_QUOTE_ERROR;
2862 return;
2863 }
2864 sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2865 }
2866 else if(strncasecompare(cmd, "chmod", 5)) {
2867 mode_t perms;
2868 perms = (mode_t)strtoul(sshc->quote_path1, NULL, 8);
2869 /* permissions are octal */
2870 if(perms == 0 && !ISDIGIT(sshc->quote_path1[0])) {
2871 Curl_safefree(sshc->quote_path1);
2872 Curl_safefree(sshc->quote_path2);
2873 failf(data, "Syntax error: chmod permissions not a number");
2874 state(data, SSH_SFTP_CLOSE);
2875 sshc->nextstate = SSH_NO_STATE;
2876 sshc->actualcode = CURLE_QUOTE_ERROR;
2877 return;
2878 }
2879 sshc->quote_attrs->permissions = perms;
2880 sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_PERMISSIONS;
2881 }
2882 else if(strncasecompare(cmd, "chown", 5)) {
2883 sshc->quote_attrs->uid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2884 if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
2885 !sshc->acceptfail) {
2886 Curl_safefree(sshc->quote_path1);
2887 Curl_safefree(sshc->quote_path2);
2888 failf(data, "Syntax error: chown uid not a number");
2889 state(data, SSH_SFTP_CLOSE);
2890 sshc->nextstate = SSH_NO_STATE;
2891 sshc->actualcode = CURLE_QUOTE_ERROR;
2892 return;
2893 }
2894 sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2895 }
2896 else if(strncasecompare(cmd, "atime", 5) ||
2897 strncasecompare(cmd, "mtime", 5)) {
2898 time_t date = Curl_getdate_capped(sshc->quote_path1);
2899 bool fail = FALSE;
2900 if(date == -1) {
2901 failf(data, "incorrect date format for %.*s", 5, cmd);
2902 fail = TRUE;
2903 }
2904 #if SIZEOF_TIME_T > 4
2905 else if(date > 0xffffffff) {
2906 failf(data, "date overflow");
2907 fail = TRUE; /* avoid setting a capped time */
2908 }
2909 #endif
2910 if(fail) {
2911 Curl_safefree(sshc->quote_path1);
2912 Curl_safefree(sshc->quote_path2);
2913 state(data, SSH_SFTP_CLOSE);
2914 sshc->nextstate = SSH_NO_STATE;
2915 sshc->actualcode = CURLE_QUOTE_ERROR;
2916 return;
2917 }
2918 if(strncasecompare(cmd, "atime", 5))
2919 sshc->quote_attrs->atime = (uint32_t)date;
2920 else /* mtime */
2921 sshc->quote_attrs->mtime = (uint32_t)date;
2922
2923 sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_ACMODTIME;
2924 }
2925
2926 /* Now send the completed structure... */
2927 state(data, SSH_SFTP_QUOTE_SETSTAT);
2928 return;
2929 }
2930
Curl_ssh_init(void)2931 CURLcode Curl_ssh_init(void)
2932 {
2933 if(ssh_init()) {
2934 DEBUGF(fprintf(stderr, "Error: libssh_init failed\n"));
2935 return CURLE_FAILED_INIT;
2936 }
2937 return CURLE_OK;
2938 }
2939
Curl_ssh_cleanup(void)2940 void Curl_ssh_cleanup(void)
2941 {
2942 (void)ssh_finalize();
2943 }
2944
Curl_ssh_version(char *buffer, size_t buflen)2945 void Curl_ssh_version(char *buffer, size_t buflen)
2946 {
2947 (void)msnprintf(buffer, buflen, "libssh/%s", ssh_version(0));
2948 }
2949
2950 #endif /* USE_LIBSSH */
2951