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