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