1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 2017 - 2022 Red Hat, Inc.
10 * Authors: Nikos Mavrogiannopoulos, Tomas Mraz, Stanislav Zidek,
11 * Robert Kolcun, Andreas Schneider
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.
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.
21 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
22 * KIND, either express or implied.
24 * SPDX-License-Identifier: curl
26 ***************************************************************************/
28 #include "curl_setup.h"
34 #include <libssh/libssh.h>
35 #include <libssh/sftp.h>
37 #ifdef HAVE_NETINET_IN_H
38 #include <netinet/in.h>
40 #ifdef HAVE_ARPA_INET_H
41 #include <arpa/inet.h>
44 #include <sys/utsname.h>
54 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
56 #define in_addr_t unsigned long
59 #include <curl/curl.h>
66 #include "http.h" /* for HTTP proxy tunnel stuff */
69 #include "speedcheck.h"
73 #include "vtls/vtls.h"
75 #include "inet_ntop.h"
76 #include "parsedate.h" /* for the week day and month names */
77 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
78 #include "strtoofft.h"
82 #include "curl_path.h"
84 #ifdef HAVE_SYS_STAT_H
94 /* The last 3 #include files should be in this order */
95 #include "curl_printf.h"
96 #include "curl_memory.h"
99 /* in 0.10.0 or later, ignore deprecated warnings */
100 #if defined(__GNUC__) && \
101 (LIBSSH_VERSION_MINOR >= 10) || \
102 (LIBSSH_VERSION_MAJOR > 0)
103 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
106 /* A recent macro provided by libssh. Or make our own. */
107 #ifndef SSH_STRING_FREE_CHAR
108 #define SSH_STRING_FREE_CHAR(x) \
111 ssh_string_free_char(x); \
117 /* These stat values may not be the same as the user's S_IFMT / S_IFLNK */
119 #define SSH_S_IFMT 00170000
122 #define SSH_S_IFLNK 0120000
125 /* Local functions: */
126 static CURLcode myssh_connect(struct Curl_easy *data, bool *done);
127 static CURLcode myssh_multi_statemach(struct Curl_easy *data,
129 static CURLcode myssh_do_it(struct Curl_easy *data, bool *done);
131 static CURLcode scp_done(struct Curl_easy *data,
132 CURLcode, bool premature);
133 static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done);
134 static CURLcode scp_disconnect(struct Curl_easy *data,
135 struct connectdata *conn,
136 bool dead_connection);
138 static CURLcode sftp_done(struct Curl_easy *data,
139 CURLcode, bool premature);
140 static CURLcode sftp_doing(struct Curl_easy *data,
142 static CURLcode sftp_disconnect(struct Curl_easy *data,
143 struct connectdata *conn,
146 CURLcode sftp_perform(struct Curl_easy *data,
150 static void sftp_quote(struct Curl_easy *data);
151 static void sftp_quote_stat(struct Curl_easy *data);
152 static int myssh_getsock(struct Curl_easy *data,
153 struct connectdata *conn, curl_socket_t *sock);
155 static CURLcode myssh_setup_connection(struct Curl_easy *data,
156 struct connectdata *conn);
159 * SCP protocol handler.
162 const struct Curl_handler Curl_handler_scp = {
164 myssh_setup_connection, /* setup_connection */
165 myssh_do_it, /* do_it */
167 ZERO_NULL, /* do_more */
168 myssh_connect, /* connect_it */
169 myssh_multi_statemach, /* connecting */
170 scp_doing, /* doing */
171 myssh_getsock, /* proto_getsock */
172 myssh_getsock, /* doing_getsock */
173 ZERO_NULL, /* domore_getsock */
174 myssh_getsock, /* perform_getsock */
175 scp_disconnect, /* disconnect */
176 ZERO_NULL, /* readwrite */
177 ZERO_NULL, /* connection_check */
178 ZERO_NULL, /* attach connection */
179 PORT_SSH, /* defport */
180 CURLPROTO_SCP, /* protocol */
181 CURLPROTO_SCP, /* family */
182 PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */
186 * SFTP protocol handler.
189 const struct Curl_handler Curl_handler_sftp = {
191 myssh_setup_connection, /* setup_connection */
192 myssh_do_it, /* do_it */
193 sftp_done, /* done */
194 ZERO_NULL, /* do_more */
195 myssh_connect, /* connect_it */
196 myssh_multi_statemach, /* connecting */
197 sftp_doing, /* doing */
198 myssh_getsock, /* proto_getsock */
199 myssh_getsock, /* doing_getsock */
200 ZERO_NULL, /* domore_getsock */
201 myssh_getsock, /* perform_getsock */
202 sftp_disconnect, /* disconnect */
203 ZERO_NULL, /* readwrite */
204 ZERO_NULL, /* connection_check */
205 ZERO_NULL, /* attach connection */
206 PORT_SSH, /* defport */
207 CURLPROTO_SFTP, /* protocol */
208 CURLPROTO_SFTP, /* family */
209 PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
210 | PROTOPT_NOURLQUERY /* flags */
213 static CURLcode sftp_error_to_CURLE(int err)
219 case SSH_FX_NO_SUCH_FILE:
220 case SSH_FX_NO_SUCH_PATH:
221 return CURLE_REMOTE_FILE_NOT_FOUND;
223 case SSH_FX_PERMISSION_DENIED:
224 case SSH_FX_WRITE_PROTECT:
225 return CURLE_REMOTE_ACCESS_DENIED;
227 case SSH_FX_FILE_ALREADY_EXISTS:
228 return CURLE_REMOTE_FILE_EXISTS;
238 #define state(x,y) mystate(x,y)
240 #define state(x,y) mystate(x,y, __LINE__)
244 * SSH State machine related code
246 /* This is the ONLY way to change SSH state! */
247 static void mystate(struct Curl_easy *data, sshstate nowstate
253 struct connectdata *conn = data->conn;
254 struct ssh_conn *sshc = &conn->proto.sshc;
255 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
256 /* for debug purposes */
257 static const char *const names[] = {
263 "SSH_AUTH_PKEY_INIT",
265 "SSH_AUTH_PASS_INIT",
267 "SSH_AUTH_AGENT_INIT",
268 "SSH_AUTH_AGENT_LIST",
270 "SSH_AUTH_HOST_INIT",
278 "SSH_SFTP_QUOTE_INIT",
279 "SSH_SFTP_POSTQUOTE_INIT",
281 "SSH_SFTP_NEXT_QUOTE",
282 "SSH_SFTP_QUOTE_STAT",
283 "SSH_SFTP_QUOTE_SETSTAT",
284 "SSH_SFTP_QUOTE_SYMLINK",
285 "SSH_SFTP_QUOTE_MKDIR",
286 "SSH_SFTP_QUOTE_RENAME",
287 "SSH_SFTP_QUOTE_RMDIR",
288 "SSH_SFTP_QUOTE_UNLINK",
289 "SSH_SFTP_QUOTE_STATVFS",
292 "SSH_SFTP_TRANS_INIT",
293 "SSH_SFTP_UPLOAD_INIT",
294 "SSH_SFTP_CREATE_DIRS_INIT",
295 "SSH_SFTP_CREATE_DIRS",
296 "SSH_SFTP_CREATE_DIRS_MKDIR",
297 "SSH_SFTP_READDIR_INIT",
299 "SSH_SFTP_READDIR_LINK",
300 "SSH_SFTP_READDIR_BOTTOM",
301 "SSH_SFTP_READDIR_DONE",
302 "SSH_SFTP_DOWNLOAD_INIT",
303 "SSH_SFTP_DOWNLOAD_STAT",
306 "SSH_SCP_TRANS_INIT",
307 "SSH_SCP_UPLOAD_INIT",
308 "SSH_SCP_DOWNLOAD_INIT",
313 "SSH_SCP_WAIT_CLOSE",
314 "SSH_SCP_CHANNEL_FREE",
315 "SSH_SESSION_DISCONNECT",
321 if(sshc->state != nowstate) {
322 infof(data, "SSH %p state change from %s to %s (line %d)",
323 (void *) sshc, names[sshc->state], names[nowstate],
328 sshc->state = nowstate;
332 * 1. data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] is set with an MD5
333 * hash (90s style auth, not sure we should have it here)
334 * 2. data->set.ssh_keyfunc callback is set. Then we do trust on first
335 * use. We even save on knownhosts if CURLKHSTAT_FINE_ADD_TO_FILE
337 * 3. none of the above. We only accept if it is present on known hosts.
339 * Returns SSH_OK or SSH_ERROR.
341 static int myssh_is_known(struct Curl_easy *data)
344 struct connectdata *conn = data->conn;
345 struct ssh_conn *sshc = &conn->proto.sshc;
348 unsigned char *hash = NULL;
349 char *found_base64 = NULL;
350 char *known_base64 = NULL;
352 enum curl_khmatch keymatch;
353 struct curl_khkey foundkey;
354 struct curl_khkey *knownkeyp = NULL;
355 curl_sshkeycallback func =
356 data->set.ssh_keyfunc;
358 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
359 struct ssh_knownhosts_entry *knownhostsentry = NULL;
360 struct curl_khkey knownkey;
363 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0)
364 rc = ssh_get_server_publickey(sshc->ssh_session, &pubkey);
366 rc = ssh_get_publickey(sshc->ssh_session, &pubkey);
371 if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) {
374 const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
376 rc = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_MD5,
378 if(rc != SSH_OK || hlen != 16) {
380 "Denied establishing ssh session: md5 fingerprint not available");
384 for(i = 0; i < 16; i++)
385 msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char)hash[i]);
387 infof(data, "SSH MD5 fingerprint: %s", md5buffer);
389 if(!strcasecompare(md5buffer, pubkey_md5)) {
391 "Denied establishing ssh session: mismatch md5 fingerprint. "
392 "Remote %s is not equal to %s", md5buffer, pubkey_md5);
401 if(data->set.ssl.primary.verifyhost != TRUE) {
406 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
407 /* Get the known_key from the known hosts file */
408 vstate = ssh_session_get_known_hosts_entry(sshc->ssh_session,
411 /* Case an entry was found in a known hosts file */
412 if(knownhostsentry) {
413 if(knownhostsentry->publickey) {
414 rc = ssh_pki_export_pubkey_base64(knownhostsentry->publickey,
419 knownkey.key = known_base64;
420 knownkey.len = strlen(known_base64);
422 switch(ssh_key_type(knownhostsentry->publickey)) {
423 case SSH_KEYTYPE_RSA:
424 knownkey.keytype = CURLKHTYPE_RSA;
426 case SSH_KEYTYPE_RSA1:
427 knownkey.keytype = CURLKHTYPE_RSA1;
429 case SSH_KEYTYPE_ECDSA:
430 case SSH_KEYTYPE_ECDSA_P256:
431 case SSH_KEYTYPE_ECDSA_P384:
432 case SSH_KEYTYPE_ECDSA_P521:
433 knownkey.keytype = CURLKHTYPE_ECDSA;
435 case SSH_KEYTYPE_ED25519:
436 knownkey.keytype = CURLKHTYPE_ED25519;
438 case SSH_KEYTYPE_DSS:
439 knownkey.keytype = CURLKHTYPE_DSS;
445 knownkeyp = &knownkey;
450 case SSH_KNOWN_HOSTS_OK:
451 keymatch = CURLKHMATCH_OK;
453 case SSH_KNOWN_HOSTS_OTHER:
455 case SSH_KNOWN_HOSTS_NOT_FOUND:
457 case SSH_KNOWN_HOSTS_UNKNOWN:
459 case SSH_KNOWN_HOSTS_ERROR:
460 keymatch = CURLKHMATCH_MISSING;
463 keymatch = CURLKHMATCH_MISMATCH;
468 vstate = ssh_is_server_known(sshc->ssh_session);
470 case SSH_SERVER_KNOWN_OK:
471 keymatch = CURLKHMATCH_OK;
473 case SSH_SERVER_FILE_NOT_FOUND:
475 case SSH_SERVER_NOT_KNOWN:
476 keymatch = CURLKHMATCH_MISSING;
479 keymatch = CURLKHMATCH_MISMATCH;
484 if(func) { /* use callback to determine action */
485 rc = ssh_pki_export_pubkey_base64(pubkey, &found_base64);
489 foundkey.key = found_base64;
490 foundkey.len = strlen(found_base64);
492 switch(ssh_key_type(pubkey)) {
493 case SSH_KEYTYPE_RSA:
494 foundkey.keytype = CURLKHTYPE_RSA;
496 case SSH_KEYTYPE_RSA1:
497 foundkey.keytype = CURLKHTYPE_RSA1;
499 case SSH_KEYTYPE_ECDSA:
500 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
501 case SSH_KEYTYPE_ECDSA_P256:
502 case SSH_KEYTYPE_ECDSA_P384:
503 case SSH_KEYTYPE_ECDSA_P521:
505 foundkey.keytype = CURLKHTYPE_ECDSA;
507 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,7,0)
508 case SSH_KEYTYPE_ED25519:
509 foundkey.keytype = CURLKHTYPE_ED25519;
512 case SSH_KEYTYPE_DSS:
513 foundkey.keytype = CURLKHTYPE_DSS;
520 Curl_set_in_callback(data, true);
521 rc = func(data, knownkeyp, /* from the knownhosts file */
522 &foundkey, /* from the remote host */
523 keymatch, data->set.ssh_keyfunc_userp);
524 Curl_set_in_callback(data, false);
527 case CURLKHSTAT_FINE_ADD_TO_FILE:
528 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0)
529 rc = ssh_session_update_known_hosts(sshc->ssh_session);
531 rc = ssh_write_knownhost(sshc->ssh_session);
537 case CURLKHSTAT_FINE:
539 default: /* REJECT/DEFER */
545 if(keymatch != CURLKHMATCH_OK) {
554 (free)(found_base64);
557 (free)(known_base64);
560 ssh_clean_pubkey_hash(&hash);
561 ssh_key_free(pubkey);
562 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
563 if(knownhostsentry) {
564 ssh_knownhosts_entry_free(knownhostsentry);
570 #define MOVE_TO_ERROR_STATE(_r) do { \
571 state(data, SSH_SESSION_DISCONNECT); \
572 sshc->actualcode = _r; \
576 #define MOVE_TO_SFTP_CLOSE_STATE() do { \
577 state(data, SSH_SFTP_CLOSE); \
579 sftp_error_to_CURLE(sftp_get_error(sshc->sftp_session)); \
583 #define MOVE_TO_LAST_AUTH do { \
584 if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) { \
586 state(data, SSH_AUTH_PASS_INIT); \
589 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); \
593 #define MOVE_TO_TERTIARY_AUTH do { \
594 if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) { \
596 state(data, SSH_AUTH_KEY_INIT); \
603 #define MOVE_TO_SECONDARY_AUTH do { \
604 if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) { \
606 state(data, SSH_AUTH_GSSAPI); \
609 MOVE_TO_TERTIARY_AUTH; \
614 int myssh_auth_interactive(struct connectdata *conn)
617 struct ssh_conn *sshc = &conn->proto.sshc;
621 switch(sshc->kbd_state) {
623 rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
624 if(rc == SSH_AUTH_AGAIN)
627 if(rc != SSH_AUTH_INFO)
630 nprompts = ssh_userauth_kbdint_getnprompts(sshc->ssh_session);
634 rc = ssh_userauth_kbdint_setanswer(sshc->ssh_session, 0, conn->passwd);
642 rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
643 if(rc == SSH_AUTH_AGAIN)
645 else if(rc == SSH_AUTH_SUCCESS)
647 else if(rc == SSH_AUTH_INFO) {
648 nprompts = ssh_userauth_kbdint_getnprompts(sshc->ssh_session);
661 rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
662 if(rc == SSH_AUTH_AGAIN)
664 else if(rc == SSH_AUTH_SUCCESS)
679 * ssh_statemach_act() runs the SSH state machine as far as it can without
680 * blocking and without reaching the end. The data the pointer 'block' points
681 * to will be set to TRUE if the libssh function returns SSH_AGAIN
682 * meaning it wants to be called again when the socket is ready
684 static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
686 CURLcode result = CURLE_OK;
687 struct connectdata *conn = data->conn;
688 struct SSHPROTO *protop = data->req.p.ssh;
689 struct ssh_conn *sshc = &conn->proto.sshc;
690 curl_socket_t sock = conn->sock[FIRSTSOCKET];
691 int rc = SSH_NO_ERROR, err;
692 char *new_readdir_line;
693 int seekerr = CURL_SEEKFUNC_OK;
695 *block = 0; /* we're not blocking by default */
699 switch(sshc->state) {
701 sshc->secondCreateDirs = 0;
702 sshc->nextstate = SSH_NO_STATE;
703 sshc->actualcode = CURLE_OK;
706 ssh_set_log_level(SSH_LOG_PROTOCOL);
709 /* Set libssh to non-blocking, since everything internally is
711 ssh_set_blocking(sshc->ssh_session, 0);
713 state(data, SSH_S_STARTUP);
717 rc = ssh_connect(sshc->ssh_session);
722 failf(data, "Failure establishing ssh session");
723 MOVE_TO_ERROR_STATE(CURLE_FAILED_INIT);
727 state(data, SSH_HOSTKEY);
732 rc = myssh_is_known(data);
734 MOVE_TO_ERROR_STATE(CURLE_PEER_FAILED_VERIFICATION);
738 state(data, SSH_AUTHLIST);
741 sshc->authed = FALSE;
743 rc = ssh_userauth_none(sshc->ssh_session, NULL);
744 if(rc == SSH_AUTH_AGAIN) {
749 if(rc == SSH_AUTH_SUCCESS) {
751 infof(data, "Authenticated with none");
752 state(data, SSH_AUTH_DONE);
755 else if(rc == SSH_AUTH_ERROR) {
756 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
760 sshc->auth_methods = ssh_userauth_list(sshc->ssh_session, NULL);
761 if(sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) {
762 state(data, SSH_AUTH_PKEY_INIT);
763 infof(data, "Authentication using SSH public key file");
765 else if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) {
766 state(data, SSH_AUTH_GSSAPI);
768 else if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) {
769 state(data, SSH_AUTH_KEY_INIT);
771 else if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) {
772 state(data, SSH_AUTH_PASS_INIT);
774 else { /* unsupported authentication method */
775 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
781 case SSH_AUTH_PKEY_INIT:
782 if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY)) {
783 MOVE_TO_SECONDARY_AUTH;
787 /* Two choices, (1) private key was given on CMD,
788 * (2) use the "default" keys. */
789 if(data->set.str[STRING_SSH_PRIVATE_KEY]) {
790 if(sshc->pubkey && !data->set.ssl.key_passwd) {
791 rc = ssh_userauth_try_publickey(sshc->ssh_session, NULL,
793 if(rc == SSH_AUTH_AGAIN) {
799 MOVE_TO_SECONDARY_AUTH;
804 rc = ssh_pki_import_privkey_file(data->
805 set.str[STRING_SSH_PRIVATE_KEY],
806 data->set.ssl.key_passwd, NULL,
807 NULL, &sshc->privkey);
809 failf(data, "Could not load private key file %s",
810 data->set.str[STRING_SSH_PRIVATE_KEY]);
811 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
815 state(data, SSH_AUTH_PKEY);
820 rc = ssh_userauth_publickey_auto(sshc->ssh_session, NULL,
821 data->set.ssl.key_passwd);
822 if(rc == SSH_AUTH_AGAIN) {
826 if(rc == SSH_AUTH_SUCCESS) {
829 infof(data, "Completed public key authentication");
830 state(data, SSH_AUTH_DONE);
834 MOVE_TO_SECONDARY_AUTH;
838 rc = ssh_userauth_publickey(sshc->ssh_session, NULL, sshc->privkey);
839 if(rc == SSH_AUTH_AGAIN) {
844 if(rc == SSH_AUTH_SUCCESS) {
846 infof(data, "Completed public key authentication");
847 state(data, SSH_AUTH_DONE);
851 infof(data, "Failed public key authentication (rc: %d)", rc);
852 MOVE_TO_SECONDARY_AUTH;
856 case SSH_AUTH_GSSAPI:
857 if(!(data->set.ssh_auth_types & CURLSSH_AUTH_GSSAPI)) {
858 MOVE_TO_TERTIARY_AUTH;
862 rc = ssh_userauth_gssapi(sshc->ssh_session);
863 if(rc == SSH_AUTH_AGAIN) {
868 if(rc == SSH_AUTH_SUCCESS) {
871 infof(data, "Completed gssapi authentication");
872 state(data, SSH_AUTH_DONE);
876 MOVE_TO_TERTIARY_AUTH;
879 case SSH_AUTH_KEY_INIT:
880 if(data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) {
881 state(data, SSH_AUTH_KEY);
890 /* Authentication failed. Continue with keyboard-interactive now. */
891 rc = myssh_auth_interactive(conn);
892 if(rc == SSH_AGAIN) {
897 infof(data, "completed keyboard interactive authentication");
899 state(data, SSH_AUTH_DONE);
902 case SSH_AUTH_PASS_INIT:
903 if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD)) {
904 /* Host key authentication is intentionally not implemented */
905 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
908 state(data, SSH_AUTH_PASS);
912 rc = ssh_userauth_password(sshc->ssh_session, NULL, conn->passwd);
913 if(rc == SSH_AUTH_AGAIN) {
918 if(rc == SSH_AUTH_SUCCESS) {
920 infof(data, "Completed password authentication");
921 state(data, SSH_AUTH_DONE);
924 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
930 failf(data, "Authentication failure");
931 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
936 * At this point we have an authenticated ssh session.
938 infof(data, "Authentication complete");
940 Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSH is connected */
943 conn->writesockfd = CURL_SOCKET_BAD;
945 if(conn->handler->protocol == CURLPROTO_SFTP) {
946 state(data, SSH_SFTP_INIT);
949 infof(data, "SSH CONNECT phase done");
950 state(data, SSH_STOP);
954 ssh_set_blocking(sshc->ssh_session, 1);
956 sshc->sftp_session = sftp_new(sshc->ssh_session);
957 if(!sshc->sftp_session) {
958 failf(data, "Failure initializing sftp session: %s",
959 ssh_get_error(sshc->ssh_session));
960 MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
964 rc = sftp_init(sshc->sftp_session);
966 failf(data, "Failure initializing sftp session: %s",
967 ssh_get_error(sshc->ssh_session));
968 MOVE_TO_ERROR_STATE(sftp_error_to_CURLE(SSH_FX_FAILURE));
971 state(data, SSH_SFTP_REALPATH);
973 case SSH_SFTP_REALPATH:
975 * Get the "home" directory
977 sshc->homedir = sftp_canonicalize_path(sshc->sftp_session, ".");
979 MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
982 data->state.most_recent_ftp_entrypath = sshc->homedir;
984 /* This is the last step in the SFTP connect phase. Do note that while
985 we get the homedir here, we get the "workingpath" in the DO action
986 since the homedir will remain the same between request but the
987 working path will not. */
988 DEBUGF(infof(data, "SSH CONNECT phase done"));
989 state(data, SSH_STOP);
992 case SSH_SFTP_QUOTE_INIT:
993 result = Curl_getworkingpath(data, sshc->homedir, &protop->path);
995 sshc->actualcode = result;
996 state(data, SSH_STOP);
1000 if(data->set.quote) {
1001 infof(data, "Sending quote commands");
1002 sshc->quote_item = data->set.quote;
1003 state(data, SSH_SFTP_QUOTE);
1006 state(data, SSH_SFTP_GETINFO);
1010 case SSH_SFTP_POSTQUOTE_INIT:
1011 if(data->set.postquote) {
1012 infof(data, "Sending quote commands");
1013 sshc->quote_item = data->set.postquote;
1014 state(data, SSH_SFTP_QUOTE);
1017 state(data, SSH_STOP);
1021 case SSH_SFTP_QUOTE:
1022 /* Send any quote commands */
1026 case SSH_SFTP_NEXT_QUOTE:
1027 Curl_safefree(sshc->quote_path1);
1028 Curl_safefree(sshc->quote_path2);
1030 sshc->quote_item = sshc->quote_item->next;
1032 if(sshc->quote_item) {
1033 state(data, SSH_SFTP_QUOTE);
1036 if(sshc->nextstate != SSH_NO_STATE) {
1037 state(data, sshc->nextstate);
1038 sshc->nextstate = SSH_NO_STATE;
1041 state(data, SSH_SFTP_GETINFO);
1046 case SSH_SFTP_QUOTE_STAT:
1047 sftp_quote_stat(data);
1050 case SSH_SFTP_QUOTE_SETSTAT:
1051 rc = sftp_setstat(sshc->sftp_session, sshc->quote_path2,
1053 if(rc && !sshc->acceptfail) {
1054 Curl_safefree(sshc->quote_path1);
1055 Curl_safefree(sshc->quote_path2);
1056 failf(data, "Attempt to set SFTP stats failed: %s",
1057 ssh_get_error(sshc->ssh_session));
1058 state(data, SSH_SFTP_CLOSE);
1059 sshc->nextstate = SSH_NO_STATE;
1060 sshc->actualcode = CURLE_QUOTE_ERROR;
1061 /* sshc->actualcode = sftp_error_to_CURLE(err);
1062 * we do not send the actual error; we return
1063 * the error the libssh2 backend is returning */
1066 state(data, SSH_SFTP_NEXT_QUOTE);
1069 case SSH_SFTP_QUOTE_SYMLINK:
1070 rc = sftp_symlink(sshc->sftp_session, sshc->quote_path2,
1072 if(rc && !sshc->acceptfail) {
1073 Curl_safefree(sshc->quote_path1);
1074 Curl_safefree(sshc->quote_path2);
1075 failf(data, "symlink command failed: %s",
1076 ssh_get_error(sshc->ssh_session));
1077 state(data, SSH_SFTP_CLOSE);
1078 sshc->nextstate = SSH_NO_STATE;
1079 sshc->actualcode = CURLE_QUOTE_ERROR;
1082 state(data, SSH_SFTP_NEXT_QUOTE);
1085 case SSH_SFTP_QUOTE_MKDIR:
1086 rc = sftp_mkdir(sshc->sftp_session, sshc->quote_path1,
1087 (mode_t)data->set.new_directory_perms);
1088 if(rc && !sshc->acceptfail) {
1089 Curl_safefree(sshc->quote_path1);
1090 failf(data, "mkdir command failed: %s",
1091 ssh_get_error(sshc->ssh_session));
1092 state(data, SSH_SFTP_CLOSE);
1093 sshc->nextstate = SSH_NO_STATE;
1094 sshc->actualcode = CURLE_QUOTE_ERROR;
1097 state(data, SSH_SFTP_NEXT_QUOTE);
1100 case SSH_SFTP_QUOTE_RENAME:
1101 rc = sftp_rename(sshc->sftp_session, sshc->quote_path1,
1103 if(rc && !sshc->acceptfail) {
1104 Curl_safefree(sshc->quote_path1);
1105 Curl_safefree(sshc->quote_path2);
1106 failf(data, "rename command failed: %s",
1107 ssh_get_error(sshc->ssh_session));
1108 state(data, SSH_SFTP_CLOSE);
1109 sshc->nextstate = SSH_NO_STATE;
1110 sshc->actualcode = CURLE_QUOTE_ERROR;
1113 state(data, SSH_SFTP_NEXT_QUOTE);
1116 case SSH_SFTP_QUOTE_RMDIR:
1117 rc = sftp_rmdir(sshc->sftp_session, sshc->quote_path1);
1118 if(rc && !sshc->acceptfail) {
1119 Curl_safefree(sshc->quote_path1);
1120 failf(data, "rmdir command failed: %s",
1121 ssh_get_error(sshc->ssh_session));
1122 state(data, SSH_SFTP_CLOSE);
1123 sshc->nextstate = SSH_NO_STATE;
1124 sshc->actualcode = CURLE_QUOTE_ERROR;
1127 state(data, SSH_SFTP_NEXT_QUOTE);
1130 case SSH_SFTP_QUOTE_UNLINK:
1131 rc = sftp_unlink(sshc->sftp_session, sshc->quote_path1);
1132 if(rc && !sshc->acceptfail) {
1133 Curl_safefree(sshc->quote_path1);
1134 failf(data, "rm command failed: %s",
1135 ssh_get_error(sshc->ssh_session));
1136 state(data, SSH_SFTP_CLOSE);
1137 sshc->nextstate = SSH_NO_STATE;
1138 sshc->actualcode = CURLE_QUOTE_ERROR;
1141 state(data, SSH_SFTP_NEXT_QUOTE);
1144 case SSH_SFTP_QUOTE_STATVFS:
1146 sftp_statvfs_t statvfs;
1148 statvfs = sftp_statvfs(sshc->sftp_session, sshc->quote_path1);
1149 if(!statvfs && !sshc->acceptfail) {
1150 Curl_safefree(sshc->quote_path1);
1151 failf(data, "statvfs command failed: %s",
1152 ssh_get_error(sshc->ssh_session));
1153 state(data, SSH_SFTP_CLOSE);
1154 sshc->nextstate = SSH_NO_STATE;
1155 sshc->actualcode = CURLE_QUOTE_ERROR;
1159 char *tmp = aprintf("statvfs:\n"
1160 "f_bsize: %llu\n" "f_frsize: %llu\n"
1161 "f_blocks: %llu\n" "f_bfree: %llu\n"
1162 "f_bavail: %llu\n" "f_files: %llu\n"
1163 "f_ffree: %llu\n" "f_favail: %llu\n"
1164 "f_fsid: %llu\n" "f_flag: %llu\n"
1165 "f_namemax: %llu\n",
1166 statvfs->f_bsize, statvfs->f_frsize,
1167 statvfs->f_blocks, statvfs->f_bfree,
1168 statvfs->f_bavail, statvfs->f_files,
1169 statvfs->f_ffree, statvfs->f_favail,
1170 statvfs->f_fsid, statvfs->f_flag,
1171 statvfs->f_namemax);
1172 sftp_statvfs_free(statvfs);
1175 result = CURLE_OUT_OF_MEMORY;
1176 state(data, SSH_SFTP_CLOSE);
1177 sshc->nextstate = SSH_NO_STATE;
1181 result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
1184 state(data, SSH_SFTP_CLOSE);
1185 sshc->nextstate = SSH_NO_STATE;
1186 sshc->actualcode = result;
1189 state(data, SSH_SFTP_NEXT_QUOTE);
1193 case SSH_SFTP_GETINFO:
1194 if(data->set.get_filetime) {
1195 state(data, SSH_SFTP_FILETIME);
1198 state(data, SSH_SFTP_TRANS_INIT);
1202 case SSH_SFTP_FILETIME:
1204 sftp_attributes attrs;
1206 attrs = sftp_stat(sshc->sftp_session, protop->path);
1208 data->info.filetime = attrs->mtime;
1209 sftp_attributes_free(attrs);
1212 state(data, SSH_SFTP_TRANS_INIT);
1216 case SSH_SFTP_TRANS_INIT:
1217 if(data->set.upload)
1218 state(data, SSH_SFTP_UPLOAD_INIT);
1220 if(protop->path[strlen(protop->path)-1] == '/')
1221 state(data, SSH_SFTP_READDIR_INIT);
1223 state(data, SSH_SFTP_DOWNLOAD_INIT);
1227 case SSH_SFTP_UPLOAD_INIT:
1231 if(data->state.resume_from) {
1232 sftp_attributes attrs;
1234 if(data->state.resume_from < 0) {
1235 attrs = sftp_stat(sshc->sftp_session, protop->path);
1237 curl_off_t size = attrs->size;
1239 failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
1240 MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME);
1243 data->state.resume_from = attrs->size;
1245 sftp_attributes_free(attrs);
1248 data->state.resume_from = 0;
1253 if(data->set.remote_append)
1254 /* Try to open for append, but create if nonexisting */
1255 flags = O_WRONLY|O_CREAT|O_APPEND;
1256 else if(data->state.resume_from > 0)
1257 /* If we have restart position then open for append */
1258 flags = O_WRONLY|O_APPEND;
1260 /* Clear file before writing (normal behavior) */
1261 flags = O_WRONLY|O_CREAT|O_TRUNC;
1264 sftp_close(sshc->sftp_file);
1266 sftp_open(sshc->sftp_session, protop->path,
1267 flags, (mode_t)data->set.new_file_perms);
1268 if(!sshc->sftp_file) {
1269 err = sftp_get_error(sshc->sftp_session);
1271 if(((err == SSH_FX_NO_SUCH_FILE || err == SSH_FX_FAILURE ||
1272 err == SSH_FX_NO_SUCH_PATH)) &&
1273 (data->set.ftp_create_missing_dirs &&
1274 (strlen(protop->path) > 1))) {
1275 /* try to create the path remotely */
1277 sshc->secondCreateDirs = 1;
1278 state(data, SSH_SFTP_CREATE_DIRS_INIT);
1282 MOVE_TO_SFTP_CLOSE_STATE();
1287 /* If we have a restart point then we need to seek to the correct
1289 if(data->state.resume_from > 0) {
1290 /* Let's read off the proper amount of bytes from the input. */
1291 if(conn->seek_func) {
1292 Curl_set_in_callback(data, true);
1293 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1295 Curl_set_in_callback(data, false);
1298 if(seekerr != CURL_SEEKFUNC_OK) {
1299 curl_off_t passed = 0;
1301 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1302 failf(data, "Could not seek stream");
1303 return CURLE_FTP_COULDNT_USE_REST;
1305 /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
1307 size_t readthisamountnow =
1308 (data->state.resume_from - passed > data->set.buffer_size) ?
1309 (size_t)data->set.buffer_size :
1310 curlx_sotouz(data->state.resume_from - passed);
1312 size_t actuallyread =
1313 data->state.fread_func(data->state.buffer, 1,
1314 readthisamountnow, data->state.in);
1316 passed += actuallyread;
1317 if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1318 /* this checks for greater-than only to make sure that the
1319 CURL_READFUNC_ABORT return code still aborts */
1320 failf(data, "Failed to read data");
1321 MOVE_TO_ERROR_STATE(CURLE_FTP_COULDNT_USE_REST);
1324 } while(passed < data->state.resume_from);
1329 /* now, decrease the size of the read */
1330 if(data->state.infilesize > 0) {
1331 data->state.infilesize -= data->state.resume_from;
1332 data->req.size = data->state.infilesize;
1333 Curl_pgrsSetUploadSize(data, data->state.infilesize);
1336 rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
1338 MOVE_TO_SFTP_CLOSE_STATE();
1342 if(data->state.infilesize > 0) {
1343 data->req.size = data->state.infilesize;
1344 Curl_pgrsSetUploadSize(data, data->state.infilesize);
1347 Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
1349 /* not set by Curl_setup_transfer to preserve keepon bits */
1350 conn->sockfd = conn->writesockfd;
1352 /* store this original bitmask setup to use later on if we can't
1353 figure out a "real" bitmask */
1354 sshc->orig_waitfor = data->req.keepon;
1356 /* we want to use the _sending_ function even when the socket turns
1357 out readable as the underlying libssh sftp send function will deal
1358 with both accordingly */
1359 conn->cselect_bits = CURL_CSELECT_OUT;
1361 /* since we don't really wait for anything at this point, we want the
1362 state machine to move on as soon as possible so we set a very short
1364 Curl_expire(data, 0, EXPIRE_RUN_NOW);
1366 state(data, SSH_STOP);
1370 case SSH_SFTP_CREATE_DIRS_INIT:
1371 if(strlen(protop->path) > 1) {
1372 sshc->slash_pos = protop->path + 1; /* ignore the leading '/' */
1373 state(data, SSH_SFTP_CREATE_DIRS);
1376 state(data, SSH_SFTP_UPLOAD_INIT);
1380 case SSH_SFTP_CREATE_DIRS:
1381 sshc->slash_pos = strchr(sshc->slash_pos, '/');
1382 if(sshc->slash_pos) {
1383 *sshc->slash_pos = 0;
1385 infof(data, "Creating directory '%s'", protop->path);
1386 state(data, SSH_SFTP_CREATE_DIRS_MKDIR);
1389 state(data, SSH_SFTP_UPLOAD_INIT);
1392 case SSH_SFTP_CREATE_DIRS_MKDIR:
1393 /* 'mode' - parameter is preliminary - default to 0644 */
1394 rc = sftp_mkdir(sshc->sftp_session, protop->path,
1395 (mode_t)data->set.new_directory_perms);
1396 *sshc->slash_pos = '/';
1400 * Abort if failure wasn't that the dir already exists or the
1401 * permission was denied (creation might succeed further down the
1402 * path) - retry on unspecific FAILURE also
1404 err = sftp_get_error(sshc->sftp_session);
1405 if((err != SSH_FX_FILE_ALREADY_EXISTS) &&
1406 (err != SSH_FX_FAILURE) &&
1407 (err != SSH_FX_PERMISSION_DENIED)) {
1408 MOVE_TO_SFTP_CLOSE_STATE();
1411 rc = 0; /* clear rc and continue */
1413 state(data, SSH_SFTP_CREATE_DIRS);
1416 case SSH_SFTP_READDIR_INIT:
1417 Curl_pgrsSetDownloadSize(data, -1);
1418 if(data->set.opt_no_body) {
1419 state(data, SSH_STOP);
1424 * This is a directory that we are trying to get, so produce a directory
1427 sshc->sftp_dir = sftp_opendir(sshc->sftp_session,
1429 if(!sshc->sftp_dir) {
1430 failf(data, "Could not open directory for reading: %s",
1431 ssh_get_error(sshc->ssh_session));
1432 MOVE_TO_SFTP_CLOSE_STATE();
1435 state(data, SSH_SFTP_READDIR);
1438 case SSH_SFTP_READDIR:
1440 if(sshc->readdir_attrs)
1441 sftp_attributes_free(sshc->readdir_attrs);
1443 sshc->readdir_attrs = sftp_readdir(sshc->sftp_session, sshc->sftp_dir);
1444 if(sshc->readdir_attrs) {
1445 sshc->readdir_filename = sshc->readdir_attrs->name;
1446 sshc->readdir_longentry = sshc->readdir_attrs->longname;
1447 sshc->readdir_len = strlen(sshc->readdir_filename);
1449 if(data->set.list_only) {
1452 tmpLine = aprintf("%s\n", sshc->readdir_filename);
1454 state(data, SSH_SFTP_CLOSE);
1455 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1458 result = Curl_client_write(data, CLIENTWRITE_BODY,
1459 tmpLine, sshc->readdir_len + 1);
1463 state(data, SSH_STOP);
1466 /* since this counts what we send to the client, we include the
1467 newline in this counter */
1468 data->req.bytecount += sshc->readdir_len + 1;
1470 /* output debug output if that is requested */
1471 Curl_debug(data, CURLINFO_DATA_OUT, (char *)sshc->readdir_filename,
1475 sshc->readdir_currLen = strlen(sshc->readdir_longentry);
1476 sshc->readdir_totalLen = 80 + sshc->readdir_currLen;
1477 sshc->readdir_line = calloc(sshc->readdir_totalLen, 1);
1478 if(!sshc->readdir_line) {
1479 state(data, SSH_SFTP_CLOSE);
1480 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1484 memcpy(sshc->readdir_line, sshc->readdir_longentry,
1485 sshc->readdir_currLen);
1486 if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
1487 ((sshc->readdir_attrs->permissions & SSH_S_IFMT) ==
1489 sshc->readdir_linkPath = aprintf("%s%s", protop->path,
1490 sshc->readdir_filename);
1492 if(!sshc->readdir_linkPath) {
1493 state(data, SSH_SFTP_CLOSE);
1494 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1498 state(data, SSH_SFTP_READDIR_LINK);
1501 state(data, SSH_SFTP_READDIR_BOTTOM);
1505 else if(sftp_dir_eof(sshc->sftp_dir)) {
1506 state(data, SSH_SFTP_READDIR_DONE);
1510 failf(data, "Could not open remote file for reading: %s",
1511 ssh_get_error(sshc->ssh_session));
1512 MOVE_TO_SFTP_CLOSE_STATE();
1517 case SSH_SFTP_READDIR_LINK:
1518 if(sshc->readdir_link_attrs)
1519 sftp_attributes_free(sshc->readdir_link_attrs);
1521 sshc->readdir_link_attrs = sftp_lstat(sshc->sftp_session,
1522 sshc->readdir_linkPath);
1523 if(sshc->readdir_link_attrs == 0) {
1524 failf(data, "Could not read symlink for reading: %s",
1525 ssh_get_error(sshc->ssh_session));
1526 MOVE_TO_SFTP_CLOSE_STATE();
1530 if(!sshc->readdir_link_attrs->name) {
1531 sshc->readdir_tmp = sftp_readlink(sshc->sftp_session,
1532 sshc->readdir_linkPath);
1533 if(!sshc->readdir_filename)
1534 sshc->readdir_len = 0;
1536 sshc->readdir_len = strlen(sshc->readdir_tmp);
1537 sshc->readdir_longentry = NULL;
1538 sshc->readdir_filename = sshc->readdir_tmp;
1541 sshc->readdir_len = strlen(sshc->readdir_link_attrs->name);
1542 sshc->readdir_filename = sshc->readdir_link_attrs->name;
1543 sshc->readdir_longentry = sshc->readdir_link_attrs->longname;
1546 Curl_safefree(sshc->readdir_linkPath);
1548 /* get room for the filename and extra output */
1549 sshc->readdir_totalLen += 4 + sshc->readdir_len;
1550 new_readdir_line = Curl_saferealloc(sshc->readdir_line,
1551 sshc->readdir_totalLen);
1552 if(!new_readdir_line) {
1553 sshc->readdir_line = NULL;
1554 state(data, SSH_SFTP_CLOSE);
1555 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1558 sshc->readdir_line = new_readdir_line;
1560 sshc->readdir_currLen += msnprintf(sshc->readdir_line +
1561 sshc->readdir_currLen,
1562 sshc->readdir_totalLen -
1563 sshc->readdir_currLen,
1565 sshc->readdir_filename);
1567 sftp_attributes_free(sshc->readdir_link_attrs);
1568 sshc->readdir_link_attrs = NULL;
1569 sshc->readdir_filename = NULL;
1570 sshc->readdir_longentry = NULL;
1572 state(data, SSH_SFTP_READDIR_BOTTOM);
1574 case SSH_SFTP_READDIR_BOTTOM:
1575 sshc->readdir_currLen += msnprintf(sshc->readdir_line +
1576 sshc->readdir_currLen,
1577 sshc->readdir_totalLen -
1578 sshc->readdir_currLen, "\n");
1579 result = Curl_client_write(data, CLIENTWRITE_BODY,
1581 sshc->readdir_currLen);
1584 /* output debug output if that is requested */
1585 Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_line,
1586 sshc->readdir_currLen);
1587 data->req.bytecount += sshc->readdir_currLen;
1589 Curl_safefree(sshc->readdir_line);
1590 ssh_string_free_char(sshc->readdir_tmp);
1591 sshc->readdir_tmp = NULL;
1594 state(data, SSH_STOP);
1597 state(data, SSH_SFTP_READDIR);
1600 case SSH_SFTP_READDIR_DONE:
1601 sftp_closedir(sshc->sftp_dir);
1602 sshc->sftp_dir = NULL;
1604 /* no data to transfer */
1605 Curl_setup_transfer(data, -1, -1, FALSE, -1);
1606 state(data, SSH_STOP);
1609 case SSH_SFTP_DOWNLOAD_INIT:
1611 * Work on getting the specified file
1614 sftp_close(sshc->sftp_file);
1616 sshc->sftp_file = sftp_open(sshc->sftp_session, protop->path,
1617 O_RDONLY, (mode_t)data->set.new_file_perms);
1618 if(!sshc->sftp_file) {
1619 failf(data, "Could not open remote file for reading: %s",
1620 ssh_get_error(sshc->ssh_session));
1622 MOVE_TO_SFTP_CLOSE_STATE();
1626 state(data, SSH_SFTP_DOWNLOAD_STAT);
1629 case SSH_SFTP_DOWNLOAD_STAT:
1631 sftp_attributes attrs;
1634 attrs = sftp_fstat(sshc->sftp_file);
1636 !(attrs->flags & SSH_FILEXFER_ATTR_SIZE) ||
1637 (attrs->size == 0)) {
1639 * sftp_fstat didn't return an error, so maybe the server
1640 * just doesn't support stat()
1641 * OR the server doesn't return a file size with a stat()
1644 data->req.size = -1;
1645 data->req.maxdownload = -1;
1646 Curl_pgrsSetDownloadSize(data, -1);
1652 sftp_attributes_free(attrs);
1655 failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
1656 return CURLE_BAD_DOWNLOAD_RESUME;
1658 if(data->state.use_range) {
1659 curl_off_t from, to;
1665 from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from);
1666 if(from_t == CURL_OFFT_FLOW) {
1667 return CURLE_RANGE_ERROR;
1669 while(*ptr && (ISBLANK(*ptr) || (*ptr == '-')))
1671 to_t = curlx_strtoofft(ptr, &ptr2, 0, &to);
1672 if(to_t == CURL_OFFT_FLOW) {
1673 return CURLE_RANGE_ERROR;
1675 if((to_t == CURL_OFFT_INVAL) /* no "to" value given */
1680 /* from is relative to end of file */
1685 failf(data, "Offset (%"
1686 CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
1687 CURL_FORMAT_CURL_OFF_T ")", from, size);
1688 return CURLE_BAD_DOWNLOAD_RESUME;
1695 size = to - from + 1;
1698 rc = sftp_seek64(sshc->sftp_file, from);
1700 MOVE_TO_SFTP_CLOSE_STATE();
1704 data->req.size = size;
1705 data->req.maxdownload = size;
1706 Curl_pgrsSetDownloadSize(data, size);
1709 /* We can resume if we can seek to the resume position */
1710 if(data->state.resume_from) {
1711 if(data->state.resume_from < 0) {
1712 /* We're supposed to download the last abs(from) bytes */
1713 if((curl_off_t)size < -data->state.resume_from) {
1714 failf(data, "Offset (%"
1715 CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
1716 CURL_FORMAT_CURL_OFF_T ")",
1717 data->state.resume_from, size);
1718 return CURLE_BAD_DOWNLOAD_RESUME;
1720 /* download from where? */
1721 data->state.resume_from += size;
1724 if((curl_off_t)size < data->state.resume_from) {
1725 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
1726 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
1727 data->state.resume_from, size);
1728 return CURLE_BAD_DOWNLOAD_RESUME;
1731 /* Now store the number of bytes we are expected to download */
1732 data->req.size = size - data->state.resume_from;
1733 data->req.maxdownload = size - data->state.resume_from;
1734 Curl_pgrsSetDownloadSize(data,
1735 size - data->state.resume_from);
1737 rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
1739 MOVE_TO_SFTP_CLOSE_STATE();
1745 /* Setup the actual download */
1746 if(data->req.size == 0) {
1747 /* no data to transfer */
1748 Curl_setup_transfer(data, -1, -1, FALSE, -1);
1749 infof(data, "File already completely downloaded");
1750 state(data, SSH_STOP);
1753 Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1);
1755 /* not set by Curl_setup_transfer to preserve keepon bits */
1756 conn->writesockfd = conn->sockfd;
1758 /* we want to use the _receiving_ function even when the socket turns
1759 out writableable as the underlying libssh recv function will deal
1760 with both accordingly */
1761 conn->cselect_bits = CURL_CSELECT_IN;
1764 /* this should never occur; the close state should be entered
1765 at the time the error occurs */
1766 state(data, SSH_SFTP_CLOSE);
1767 sshc->actualcode = result;
1770 sshc->sftp_recv_state = 0;
1771 state(data, SSH_STOP);
1775 case SSH_SFTP_CLOSE:
1776 if(sshc->sftp_file) {
1777 sftp_close(sshc->sftp_file);
1778 sshc->sftp_file = NULL;
1780 Curl_safefree(protop->path);
1782 DEBUGF(infof(data, "SFTP DONE done"));
1784 /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT
1785 After nextstate is executed, the control should come back to
1786 SSH_SFTP_CLOSE to pass the correct result back */
1787 if(sshc->nextstate != SSH_NO_STATE &&
1788 sshc->nextstate != SSH_SFTP_CLOSE) {
1789 state(data, sshc->nextstate);
1790 sshc->nextstate = SSH_SFTP_CLOSE;
1793 state(data, SSH_STOP);
1794 result = sshc->actualcode;
1798 case SSH_SFTP_SHUTDOWN:
1799 /* during times we get here due to a broken transfer and then the
1800 sftp_handle might not have been taken down so make sure that is done
1801 before we proceed */
1803 if(sshc->sftp_file) {
1804 sftp_close(sshc->sftp_file);
1805 sshc->sftp_file = NULL;
1808 if(sshc->sftp_session) {
1809 sftp_free(sshc->sftp_session);
1810 sshc->sftp_session = NULL;
1813 SSH_STRING_FREE_CHAR(sshc->homedir);
1814 data->state.most_recent_ftp_entrypath = NULL;
1816 state(data, SSH_SESSION_DISCONNECT);
1819 case SSH_SCP_TRANS_INIT:
1820 result = Curl_getworkingpath(data, sshc->homedir, &protop->path);
1822 sshc->actualcode = result;
1823 state(data, SSH_STOP);
1827 /* Functions from the SCP subsystem cannot handle/return SSH_AGAIN */
1828 ssh_set_blocking(sshc->ssh_session, 1);
1830 if(data->set.upload) {
1831 if(data->state.infilesize < 0) {
1832 failf(data, "SCP requires a known file size for upload");
1833 sshc->actualcode = CURLE_UPLOAD_FAILED;
1834 MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1839 ssh_scp_new(sshc->ssh_session, SSH_SCP_WRITE, protop->path);
1840 state(data, SSH_SCP_UPLOAD_INIT);
1844 ssh_scp_new(sshc->ssh_session, SSH_SCP_READ, protop->path);
1845 state(data, SSH_SCP_DOWNLOAD_INIT);
1848 if(!sshc->scp_session) {
1849 err_msg = ssh_get_error(sshc->ssh_session);
1850 failf(data, "%s", err_msg);
1851 MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1856 case SSH_SCP_UPLOAD_INIT:
1858 rc = ssh_scp_init(sshc->scp_session);
1860 err_msg = ssh_get_error(sshc->ssh_session);
1861 failf(data, "%s", err_msg);
1862 MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1866 rc = ssh_scp_push_file(sshc->scp_session, protop->path,
1867 data->state.infilesize,
1868 (int)data->set.new_file_perms);
1870 err_msg = ssh_get_error(sshc->ssh_session);
1871 failf(data, "%s", err_msg);
1872 MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1877 Curl_setup_transfer(data, -1, data->req.size, FALSE, FIRSTSOCKET);
1879 /* not set by Curl_setup_transfer to preserve keepon bits */
1880 conn->sockfd = conn->writesockfd;
1882 /* store this original bitmask setup to use later on if we can't
1883 figure out a "real" bitmask */
1884 sshc->orig_waitfor = data->req.keepon;
1886 /* we want to use the _sending_ function even when the socket turns
1887 out readable as the underlying libssh scp send function will deal
1888 with both accordingly */
1889 conn->cselect_bits = CURL_CSELECT_OUT;
1891 state(data, SSH_STOP);
1895 case SSH_SCP_DOWNLOAD_INIT:
1897 rc = ssh_scp_init(sshc->scp_session);
1899 err_msg = ssh_get_error(sshc->ssh_session);
1900 failf(data, "%s", err_msg);
1901 MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
1904 state(data, SSH_SCP_DOWNLOAD);
1907 case SSH_SCP_DOWNLOAD:{
1908 curl_off_t bytecount;
1910 rc = ssh_scp_pull_request(sshc->scp_session);
1911 if(rc != SSH_SCP_REQUEST_NEWFILE) {
1912 err_msg = ssh_get_error(sshc->ssh_session);
1913 failf(data, "%s", err_msg);
1914 MOVE_TO_ERROR_STATE(CURLE_REMOTE_FILE_NOT_FOUND);
1919 bytecount = ssh_scp_request_get_size(sshc->scp_session);
1920 data->req.maxdownload = (curl_off_t) bytecount;
1921 Curl_setup_transfer(data, FIRSTSOCKET, bytecount, FALSE, -1);
1923 /* not set by Curl_setup_transfer to preserve keepon bits */
1924 conn->writesockfd = conn->sockfd;
1926 /* we want to use the _receiving_ function even when the socket turns
1927 out writableable as the underlying libssh recv function will deal
1928 with both accordingly */
1929 conn->cselect_bits = CURL_CSELECT_IN;
1931 state(data, SSH_STOP);
1935 if(data->set.upload)
1936 state(data, SSH_SCP_SEND_EOF);
1938 state(data, SSH_SCP_CHANNEL_FREE);
1941 case SSH_SCP_SEND_EOF:
1942 if(sshc->scp_session) {
1943 rc = ssh_scp_close(sshc->scp_session);
1944 if(rc == SSH_AGAIN) {
1945 /* Currently the ssh_scp_close handles waiting for EOF in
1951 infof(data, "Failed to close libssh scp channel: %s",
1952 ssh_get_error(sshc->ssh_session));
1956 state(data, SSH_SCP_CHANNEL_FREE);
1959 case SSH_SCP_CHANNEL_FREE:
1960 if(sshc->scp_session) {
1961 ssh_scp_free(sshc->scp_session);
1962 sshc->scp_session = NULL;
1964 DEBUGF(infof(data, "SCP DONE phase complete"));
1966 ssh_set_blocking(sshc->ssh_session, 0);
1968 state(data, SSH_SESSION_DISCONNECT);
1971 case SSH_SESSION_DISCONNECT:
1972 /* during weird times when we've been prematurely aborted, the channel
1973 is still alive when we reach this state and we MUST kill the channel
1975 if(sshc->scp_session) {
1976 ssh_scp_free(sshc->scp_session);
1977 sshc->scp_session = NULL;
1980 ssh_disconnect(sshc->ssh_session);
1981 if(!ssh_version(SSH_VERSION_INT(0, 10, 0))) {
1982 /* conn->sock[FIRSTSOCKET] is closed by ssh_disconnect behind our back,
1983 explicitly mark it as closed with the memdebug macro. This libssh
1984 bug is fixed in 0.10.0. */
1985 fake_sclose(conn->sock[FIRSTSOCKET]);
1986 conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD;
1989 SSH_STRING_FREE_CHAR(sshc->homedir);
1990 data->state.most_recent_ftp_entrypath = NULL;
1992 state(data, SSH_SESSION_FREE);
1994 case SSH_SESSION_FREE:
1995 if(sshc->ssh_session) {
1996 ssh_free(sshc->ssh_session);
1997 sshc->ssh_session = NULL;
2000 /* worst-case scenario cleanup */
2002 DEBUGASSERT(sshc->ssh_session == NULL);
2003 DEBUGASSERT(sshc->scp_session == NULL);
2005 if(sshc->readdir_tmp) {
2006 ssh_string_free_char(sshc->readdir_tmp);
2007 sshc->readdir_tmp = NULL;
2010 if(sshc->quote_attrs)
2011 sftp_attributes_free(sshc->quote_attrs);
2013 if(sshc->readdir_attrs)
2014 sftp_attributes_free(sshc->readdir_attrs);
2016 if(sshc->readdir_link_attrs)
2017 sftp_attributes_free(sshc->readdir_link_attrs);
2020 ssh_key_free(sshc->privkey);
2022 ssh_key_free(sshc->pubkey);
2024 Curl_safefree(sshc->rsa_pub);
2025 Curl_safefree(sshc->rsa);
2026 Curl_safefree(sshc->quote_path1);
2027 Curl_safefree(sshc->quote_path2);
2028 Curl_safefree(sshc->readdir_line);
2029 Curl_safefree(sshc->readdir_linkPath);
2030 SSH_STRING_FREE_CHAR(sshc->homedir);
2032 /* the code we are about to return */
2033 result = sshc->actualcode;
2035 memset(sshc, 0, sizeof(struct ssh_conn));
2037 connclose(conn, "SSH session free");
2038 sshc->state = SSH_SESSION_FREE; /* current */
2039 sshc->nextstate = SSH_NO_STATE;
2040 state(data, SSH_STOP);
2044 /* fallthrough, just stop! */
2046 /* internal error */
2047 sshc->nextstate = SSH_NO_STATE;
2048 state(data, SSH_STOP);
2052 } while(!rc && (sshc->state != SSH_STOP));
2055 if(rc == SSH_AGAIN) {
2056 /* we would block, we need to wait for the socket to be ready (in the
2057 right direction too)! */
2065 /* called by the multi interface to figure out what socket(s) to wait for and
2066 for what actions in the DO_DONE, PERFORM and WAITPERFORM states */
2067 static int myssh_getsock(struct Curl_easy *data,
2068 struct connectdata *conn,
2069 curl_socket_t *sock)
2071 int bitmap = GETSOCK_BLANK;
2073 sock[0] = conn->sock[FIRSTSOCKET];
2075 if(conn->waitfor & KEEP_RECV)
2076 bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
2078 if(conn->waitfor & KEEP_SEND)
2079 bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
2082 bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
2087 static void myssh_block2waitfor(struct connectdata *conn, bool block)
2089 struct ssh_conn *sshc = &conn->proto.sshc;
2091 /* If it didn't block, or nothing was returned by ssh_get_poll_flags
2092 * have the original set */
2093 conn->waitfor = sshc->orig_waitfor;
2096 int dir = ssh_get_poll_flags(sshc->ssh_session);
2097 if(dir & SSH_READ_PENDING) {
2098 /* translate the libssh define bits into our own bit defines */
2099 conn->waitfor = KEEP_RECV;
2101 else if(dir & SSH_WRITE_PENDING) {
2102 conn->waitfor = KEEP_SEND;
2107 /* called repeatedly until done from multi.c */
2108 static CURLcode myssh_multi_statemach(struct Curl_easy *data,
2111 struct connectdata *conn = data->conn;
2112 struct ssh_conn *sshc = &conn->proto.sshc;
2113 bool block; /* we store the status and use that to provide a ssh_getsock()
2115 CURLcode result = myssh_statemach_act(data, &block);
2117 *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
2118 myssh_block2waitfor(conn, block);
2123 static CURLcode myssh_block_statemach(struct Curl_easy *data,
2126 struct connectdata *conn = data->conn;
2127 struct ssh_conn *sshc = &conn->proto.sshc;
2128 CURLcode result = CURLE_OK;
2130 while((sshc->state != SSH_STOP) && !result) {
2132 timediff_t left = 1000;
2133 struct curltime now = Curl_now();
2135 result = myssh_statemach_act(data, &block);
2140 if(Curl_pgrsUpdate(data))
2141 return CURLE_ABORTED_BY_CALLBACK;
2143 result = Curl_speedcheck(data, now);
2147 left = Curl_timeleft(data, NULL, FALSE);
2149 failf(data, "Operation timed out");
2150 return CURLE_OPERATION_TIMEDOUT;
2155 curl_socket_t fd_read = conn->sock[FIRSTSOCKET];
2156 /* wait for the socket to become ready */
2157 (void) Curl_socket_check(fd_read, CURL_SOCKET_BAD,
2158 CURL_SOCKET_BAD, left > 1000 ? 1000 : left);
2167 * SSH setup connection
2169 static CURLcode myssh_setup_connection(struct Curl_easy *data,
2170 struct connectdata *conn)
2172 struct SSHPROTO *ssh;
2175 data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
2177 return CURLE_OUT_OF_MEMORY;
2182 static Curl_recv scp_recv, sftp_recv;
2183 static Curl_send scp_send, sftp_send;
2186 * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to
2187 * do protocol-specific actions at connect-time.
2189 static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
2191 struct ssh_conn *ssh;
2193 struct connectdata *conn = data->conn;
2194 curl_socket_t sock = conn->sock[FIRSTSOCKET];
2197 /* initialize per-handle data if not already */
2198 if(!data->req.p.ssh)
2199 myssh_setup_connection(data, conn);
2201 /* We default to persistent connections. We set this already in this connect
2202 function to make the re-use checks properly be able to check this bit. */
2203 connkeep(conn, "SSH default");
2205 if(conn->handler->protocol & CURLPROTO_SCP) {
2206 conn->recv[FIRSTSOCKET] = scp_recv;
2207 conn->send[FIRSTSOCKET] = scp_send;
2210 conn->recv[FIRSTSOCKET] = sftp_recv;
2211 conn->send[FIRSTSOCKET] = sftp_send;
2214 ssh = &conn->proto.sshc;
2216 ssh->ssh_session = ssh_new();
2217 if(!ssh->ssh_session) {
2218 failf(data, "Failure initialising ssh session");
2219 return CURLE_FAILED_INIT;
2222 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, conn->host.name);
2224 failf(data, "Could not set remote host");
2225 return CURLE_FAILED_INIT;
2228 rc = ssh_options_parse_config(ssh->ssh_session, NULL);
2230 infof(data, "Could not parse SSH configuration files");
2234 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_FD, &sock);
2236 failf(data, "Could not set socket");
2237 return CURLE_FAILED_INIT;
2240 if(conn->user && conn->user[0] != '\0') {
2241 infof(data, "User: %s", conn->user);
2242 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user);
2244 failf(data, "Could not set user");
2245 return CURLE_FAILED_INIT;
2249 if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
2250 infof(data, "Known hosts: %s", data->set.str[STRING_SSH_KNOWNHOSTS]);
2251 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS,
2252 data->set.str[STRING_SSH_KNOWNHOSTS]);
2254 failf(data, "Could not set known hosts file path");
2255 return CURLE_FAILED_INIT;
2259 if(conn->remote_port) {
2260 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_PORT,
2261 &conn->remote_port);
2263 failf(data, "Could not set remote port");
2264 return CURLE_FAILED_INIT;
2268 if(data->set.ssh_compression) {
2269 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_COMPRESSION,
2270 "zlib,zlib@openssh.com,none");
2272 failf(data, "Could not set compression");
2273 return CURLE_FAILED_INIT;
2277 ssh->privkey = NULL;
2280 if(data->set.str[STRING_SSH_PUBLIC_KEY]) {
2281 rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY],
2284 failf(data, "Could not load public key file");
2285 return CURLE_FAILED_INIT;
2289 /* we do not verify here, we do it at the state machine,
2290 * after connection */
2292 state(data, SSH_INIT);
2294 result = myssh_multi_statemach(data, done);
2299 /* called from multi.c while DOing */
2300 static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done)
2304 result = myssh_multi_statemach(data, dophase_done);
2307 DEBUGF(infof(data, "DO phase is complete"));
2313 ***********************************************************************
2317 * This is the actual DO function for SCP. Get a file according to
2318 * the options previously setup.
2322 CURLcode scp_perform(struct Curl_easy *data,
2323 bool *connected, bool *dophase_done)
2325 CURLcode result = CURLE_OK;
2326 struct connectdata *conn = data->conn;
2328 DEBUGF(infof(data, "DO phase starts"));
2330 *dophase_done = FALSE; /* not done yet */
2332 /* start the first command in the DO phase */
2333 state(data, SSH_SCP_TRANS_INIT);
2335 result = myssh_multi_statemach(data, dophase_done);
2337 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
2340 DEBUGF(infof(data, "DO phase is complete"));
2346 static CURLcode myssh_do_it(struct Curl_easy *data, bool *done)
2350 struct connectdata *conn = data->conn;
2351 struct ssh_conn *sshc = &conn->proto.sshc;
2353 *done = FALSE; /* default to false */
2355 data->req.size = -1; /* make sure this is unknown at this point */
2357 sshc->actualcode = CURLE_OK; /* reset error code */
2358 sshc->secondCreateDirs = 0; /* reset the create dir attempt state
2361 Curl_pgrsSetUploadCounter(data, 0);
2362 Curl_pgrsSetDownloadCounter(data, 0);
2363 Curl_pgrsSetUploadSize(data, -1);
2364 Curl_pgrsSetDownloadSize(data, -1);
2366 if(conn->handler->protocol & CURLPROTO_SCP)
2367 result = scp_perform(data, &connected, done);
2369 result = sftp_perform(data, &connected, done);
2374 /* BLOCKING, but the function is using the state machine so the only reason
2375 this is still blocking is that the multi interface code has no support for
2376 disconnecting operations that takes a while */
2377 static CURLcode scp_disconnect(struct Curl_easy *data,
2378 struct connectdata *conn,
2379 bool dead_connection)
2381 CURLcode result = CURLE_OK;
2382 struct ssh_conn *ssh = &conn->proto.sshc;
2383 (void) dead_connection;
2385 if(ssh->ssh_session) {
2386 /* only if there's a session still around to use! */
2388 state(data, SSH_SESSION_DISCONNECT);
2390 result = myssh_block_statemach(data, TRUE);
2396 /* generic done function for both SCP and SFTP called from their specific
2398 static CURLcode myssh_done(struct Curl_easy *data, CURLcode status)
2400 CURLcode result = CURLE_OK;
2401 struct SSHPROTO *protop = data->req.p.ssh;
2404 /* run the state-machine */
2405 result = myssh_block_statemach(data, FALSE);
2411 Curl_safefree(protop->path);
2412 if(Curl_pgrsDone(data))
2413 return CURLE_ABORTED_BY_CALLBACK;
2415 data->req.keepon = 0; /* clear all bits */
2420 static CURLcode scp_done(struct Curl_easy *data, CURLcode status,
2423 (void) premature; /* not used */
2426 state(data, SSH_SCP_DONE);
2428 return myssh_done(data, status);
2432 static ssize_t scp_send(struct Curl_easy *data, int sockindex,
2433 const void *mem, size_t len, CURLcode *err)
2436 struct connectdata *conn = data->conn;
2437 (void) sockindex; /* we only support SCP on the fixed known primary socket */
2440 rc = ssh_scp_write(conn->proto.sshc.scp_session, mem, len);
2443 /* The following code is misleading, mostly added as wishful thinking
2444 * that libssh at some point will implement non-blocking ssh_scp_write/read.
2445 * Currently rc can only be number of bytes read or SSH_ERROR. */
2446 myssh_block2waitfor(conn, (rc == SSH_AGAIN) ? TRUE : FALSE);
2448 if(rc == SSH_AGAIN) {
2462 static ssize_t scp_recv(struct Curl_easy *data, int sockindex,
2463 char *mem, size_t len, CURLcode *err)
2466 struct connectdata *conn = data->conn;
2468 (void) sockindex; /* we only support SCP on the fixed known primary socket */
2470 /* libssh returns int */
2471 nread = ssh_scp_read(conn->proto.sshc.scp_session, mem, len);
2474 /* The following code is misleading, mostly added as wishful thinking
2475 * that libssh at some point will implement non-blocking ssh_scp_write/read.
2476 * Currently rc can only be SSH_OK or SSH_ERROR. */
2478 myssh_block2waitfor(conn, (nread == SSH_AGAIN) ? TRUE : FALSE);
2479 if(nread == SSH_AGAIN) {
2489 * =============== SFTP ===============
2493 ***********************************************************************
2497 * This is the actual DO function for SFTP. Get a file/directory according to
2498 * the options previously setup.
2502 CURLcode sftp_perform(struct Curl_easy *data,
2506 CURLcode result = CURLE_OK;
2507 struct connectdata *conn = data->conn;
2509 DEBUGF(infof(data, "DO phase starts"));
2511 *dophase_done = FALSE; /* not done yet */
2513 /* start the first command in the DO phase */
2514 state(data, SSH_SFTP_QUOTE_INIT);
2516 /* run the state-machine */
2517 result = myssh_multi_statemach(data, dophase_done);
2519 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
2522 DEBUGF(infof(data, "DO phase is complete"));
2528 /* called from multi.c while DOing */
2529 static CURLcode sftp_doing(struct Curl_easy *data,
2532 CURLcode result = myssh_multi_statemach(data, dophase_done);
2534 DEBUGF(infof(data, "DO phase is complete"));
2539 /* BLOCKING, but the function is using the state machine so the only reason
2540 this is still blocking is that the multi interface code has no support for
2541 disconnecting operations that takes a while */
2542 static CURLcode sftp_disconnect(struct Curl_easy *data,
2543 struct connectdata *conn,
2544 bool dead_connection)
2546 CURLcode result = CURLE_OK;
2547 (void) dead_connection;
2549 DEBUGF(infof(data, "SSH DISCONNECT starts now"));
2551 if(conn->proto.sshc.ssh_session) {
2552 /* only if there's a session still around to use! */
2553 state(data, SSH_SFTP_SHUTDOWN);
2554 result = myssh_block_statemach(data, TRUE);
2557 DEBUGF(infof(data, "SSH DISCONNECT is done"));
2563 static CURLcode sftp_done(struct Curl_easy *data, CURLcode status,
2566 struct connectdata *conn = data->conn;
2567 struct ssh_conn *sshc = &conn->proto.sshc;
2570 /* Post quote commands are executed after the SFTP_CLOSE state to avoid
2571 errors that could happen due to open file handles during POSTQUOTE
2573 if(!premature && data->set.postquote && !conn->bits.retry)
2574 sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
2575 state(data, SSH_SFTP_CLOSE);
2577 return myssh_done(data, status);
2580 /* return number of sent bytes */
2581 static ssize_t sftp_send(struct Curl_easy *data, int sockindex,
2582 const void *mem, size_t len, CURLcode *err)
2585 struct connectdata *conn = data->conn;
2588 nwrite = sftp_write(conn->proto.sshc.sftp_file, mem, len);
2590 myssh_block2waitfor(conn, FALSE);
2592 #if 0 /* not returned by libssh on write */
2593 if(nwrite == SSH_AGAIN) {
2608 * Return number of received (decrypted) bytes
2611 static ssize_t sftp_recv(struct Curl_easy *data, int sockindex,
2612 char *mem, size_t len, CURLcode *err)
2615 struct connectdata *conn = data->conn;
2618 DEBUGASSERT(len < CURL_MAX_READ_SIZE);
2620 switch(conn->proto.sshc.sftp_recv_state) {
2622 conn->proto.sshc.sftp_file_index =
2623 sftp_async_read_begin(conn->proto.sshc.sftp_file,
2625 if(conn->proto.sshc.sftp_file_index < 0) {
2626 *err = CURLE_RECV_ERROR;
2632 conn->proto.sshc.sftp_recv_state = 1;
2634 nread = sftp_async_read(conn->proto.sshc.sftp_file,
2636 conn->proto.sshc.sftp_file_index);
2638 myssh_block2waitfor(conn, (nread == SSH_AGAIN)?TRUE:FALSE);
2640 if(nread == SSH_AGAIN) {
2644 else if(nread < 0) {
2645 *err = CURLE_RECV_ERROR;
2649 conn->proto.sshc.sftp_recv_state = 0;
2653 /* we never reach here */
2658 static void sftp_quote(struct Curl_easy *data)
2661 struct connectdata *conn = data->conn;
2662 struct SSHPROTO *protop = data->req.p.ssh;
2663 struct ssh_conn *sshc = &conn->proto.sshc;
2667 * Support some of the "FTP" commands
2669 char *cmd = sshc->quote_item->data;
2670 sshc->acceptfail = FALSE;
2672 /* if a command starts with an asterisk, which a legal SFTP command never
2673 can, the command will be allowed to fail without it causing any
2674 aborts or cancels etc. It will cause libcurl to act as if the command
2675 is successful, whatever the server reponds. */
2679 sshc->acceptfail = TRUE;
2682 if(strcasecompare("pwd", cmd)) {
2683 /* output debug output if that is requested */
2684 char *tmp = aprintf("257 \"%s\" is current directory.\n",
2687 sshc->actualcode = CURLE_OUT_OF_MEMORY;
2688 state(data, SSH_SFTP_CLOSE);
2689 sshc->nextstate = SSH_NO_STATE;
2692 Curl_debug(data, CURLINFO_HEADER_OUT, (char *) "PWD\n", 4);
2693 Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
2695 /* this sends an FTP-like "header" to the header callback so that the
2696 current directory can be read very similar to how it is read when
2697 using ordinary FTP. */
2698 result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
2701 state(data, SSH_SFTP_CLOSE);
2702 sshc->nextstate = SSH_NO_STATE;
2703 sshc->actualcode = result;
2706 state(data, SSH_SFTP_NEXT_QUOTE);
2711 * the arguments following the command must be separated from the
2712 * command with a space so we can check for it unconditionally
2714 cp = strchr(cmd, ' ');
2716 failf(data, "Syntax error in SFTP command. Supply parameter(s)");
2717 state(data, SSH_SFTP_CLOSE);
2718 sshc->nextstate = SSH_NO_STATE;
2719 sshc->actualcode = CURLE_QUOTE_ERROR;
2724 * also, every command takes at least one argument so we get that
2725 * first argument right now
2727 result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir);
2729 if(result == CURLE_OUT_OF_MEMORY)
2730 failf(data, "Out of memory");
2732 failf(data, "Syntax error: Bad first parameter");
2733 state(data, SSH_SFTP_CLOSE);
2734 sshc->nextstate = SSH_NO_STATE;
2735 sshc->actualcode = result;
2740 * SFTP is a binary protocol, so we don't send text commands
2741 * to the server. Instead, we scan for commands used by
2742 * OpenSSH's sftp program and call the appropriate libssh
2745 if(strncasecompare(cmd, "chgrp ", 6) ||
2746 strncasecompare(cmd, "chmod ", 6) ||
2747 strncasecompare(cmd, "chown ", 6) ||
2748 strncasecompare(cmd, "atime ", 6) ||
2749 strncasecompare(cmd, "mtime ", 6)) {
2750 /* attribute change */
2752 /* sshc->quote_path1 contains the mode to set */
2753 /* get the destination */
2754 result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2756 if(result == CURLE_OUT_OF_MEMORY)
2757 failf(data, "Out of memory");
2759 failf(data, "Syntax error in chgrp/chmod/chown/atime/mtime: "
2760 "Bad second parameter");
2761 Curl_safefree(sshc->quote_path1);
2762 state(data, SSH_SFTP_CLOSE);
2763 sshc->nextstate = SSH_NO_STATE;
2764 sshc->actualcode = result;
2767 sshc->quote_attrs = NULL;
2768 state(data, SSH_SFTP_QUOTE_STAT);
2771 if(strncasecompare(cmd, "ln ", 3) ||
2772 strncasecompare(cmd, "symlink ", 8)) {
2773 /* symbolic linking */
2774 /* sshc->quote_path1 is the source */
2775 /* get the destination */
2776 result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2778 if(result == CURLE_OUT_OF_MEMORY)
2779 failf(data, "Out of memory");
2781 failf(data, "Syntax error in ln/symlink: Bad second parameter");
2782 Curl_safefree(sshc->quote_path1);
2783 state(data, SSH_SFTP_CLOSE);
2784 sshc->nextstate = SSH_NO_STATE;
2785 sshc->actualcode = result;
2788 state(data, SSH_SFTP_QUOTE_SYMLINK);
2791 else if(strncasecompare(cmd, "mkdir ", 6)) {
2793 state(data, SSH_SFTP_QUOTE_MKDIR);
2796 else if(strncasecompare(cmd, "rename ", 7)) {
2798 /* first param is the source path */
2799 /* second param is the dest. path */
2800 result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2802 if(result == CURLE_OUT_OF_MEMORY)
2803 failf(data, "Out of memory");
2805 failf(data, "Syntax error in rename: Bad second parameter");
2806 Curl_safefree(sshc->quote_path1);
2807 state(data, SSH_SFTP_CLOSE);
2808 sshc->nextstate = SSH_NO_STATE;
2809 sshc->actualcode = result;
2812 state(data, SSH_SFTP_QUOTE_RENAME);
2815 else if(strncasecompare(cmd, "rmdir ", 6)) {
2817 state(data, SSH_SFTP_QUOTE_RMDIR);
2820 else if(strncasecompare(cmd, "rm ", 3)) {
2821 state(data, SSH_SFTP_QUOTE_UNLINK);
2824 #ifdef HAS_STATVFS_SUPPORT
2825 else if(strncasecompare(cmd, "statvfs ", 8)) {
2826 state(data, SSH_SFTP_QUOTE_STATVFS);
2831 failf(data, "Unknown SFTP command");
2832 Curl_safefree(sshc->quote_path1);
2833 Curl_safefree(sshc->quote_path2);
2834 state(data, SSH_SFTP_CLOSE);
2835 sshc->nextstate = SSH_NO_STATE;
2836 sshc->actualcode = CURLE_QUOTE_ERROR;
2839 static void sftp_quote_stat(struct Curl_easy *data)
2841 struct connectdata *conn = data->conn;
2842 struct ssh_conn *sshc = &conn->proto.sshc;
2843 char *cmd = sshc->quote_item->data;
2844 sshc->acceptfail = FALSE;
2846 /* if a command starts with an asterisk, which a legal SFTP command never
2847 can, the command will be allowed to fail without it causing any
2848 aborts or cancels etc. It will cause libcurl to act as if the command
2849 is successful, whatever the server reponds. */
2853 sshc->acceptfail = TRUE;
2856 /* We read the file attributes, store them in sshc->quote_attrs
2857 * and modify them accordingly to command. Then we switch to
2858 * QUOTE_SETSTAT state to write new ones.
2861 if(sshc->quote_attrs)
2862 sftp_attributes_free(sshc->quote_attrs);
2863 sshc->quote_attrs = sftp_stat(sshc->sftp_session, sshc->quote_path2);
2864 if(!sshc->quote_attrs) {
2865 Curl_safefree(sshc->quote_path1);
2866 Curl_safefree(sshc->quote_path2);
2867 failf(data, "Attempt to get SFTP stats failed: %d",
2868 sftp_get_error(sshc->sftp_session));
2869 state(data, SSH_SFTP_CLOSE);
2870 sshc->nextstate = SSH_NO_STATE;
2871 sshc->actualcode = CURLE_QUOTE_ERROR;
2875 /* Now set the new attributes... */
2876 if(strncasecompare(cmd, "chgrp", 5)) {
2877 sshc->quote_attrs->gid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2878 if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
2879 !sshc->acceptfail) {
2880 Curl_safefree(sshc->quote_path1);
2881 Curl_safefree(sshc->quote_path2);
2882 failf(data, "Syntax error: chgrp gid not a number");
2883 state(data, SSH_SFTP_CLOSE);
2884 sshc->nextstate = SSH_NO_STATE;
2885 sshc->actualcode = CURLE_QUOTE_ERROR;
2888 sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2890 else if(strncasecompare(cmd, "chmod", 5)) {
2892 perms = (mode_t)strtoul(sshc->quote_path1, NULL, 8);
2893 /* permissions are octal */
2894 if(perms == 0 && !ISDIGIT(sshc->quote_path1[0])) {
2895 Curl_safefree(sshc->quote_path1);
2896 Curl_safefree(sshc->quote_path2);
2897 failf(data, "Syntax error: chmod permissions not a number");
2898 state(data, SSH_SFTP_CLOSE);
2899 sshc->nextstate = SSH_NO_STATE;
2900 sshc->actualcode = CURLE_QUOTE_ERROR;
2903 sshc->quote_attrs->permissions = perms;
2904 sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_PERMISSIONS;
2906 else if(strncasecompare(cmd, "chown", 5)) {
2907 sshc->quote_attrs->uid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2908 if(sshc->quote_attrs->uid == 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: chown uid not a number");
2913 state(data, SSH_SFTP_CLOSE);
2914 sshc->nextstate = SSH_NO_STATE;
2915 sshc->actualcode = CURLE_QUOTE_ERROR;
2918 sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2920 else if(strncasecompare(cmd, "atime", 5) ||
2921 strncasecompare(cmd, "mtime", 5)) {
2922 time_t date = Curl_getdate_capped(sshc->quote_path1);
2925 failf(data, "incorrect date format for %.*s", 5, cmd);
2928 #if SIZEOF_TIME_T > 4
2929 else if(date > 0xffffffff) {
2930 failf(data, "date overflow");
2931 fail = TRUE; /* avoid setting a capped time */
2935 Curl_safefree(sshc->quote_path1);
2936 Curl_safefree(sshc->quote_path2);
2937 state(data, SSH_SFTP_CLOSE);
2938 sshc->nextstate = SSH_NO_STATE;
2939 sshc->actualcode = CURLE_QUOTE_ERROR;
2942 if(strncasecompare(cmd, "atime", 5))
2943 sshc->quote_attrs->atime = (uint32_t)date;
2945 sshc->quote_attrs->mtime = (uint32_t)date;
2947 sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_ACMODTIME;
2950 /* Now send the completed structure... */
2951 state(data, SSH_SFTP_QUOTE_SETSTAT);
2955 CURLcode Curl_ssh_init(void)
2958 DEBUGF(fprintf(stderr, "Error: libssh_init failed\n"));
2959 return CURLE_FAILED_INIT;
2964 void Curl_ssh_cleanup(void)
2966 (void)ssh_finalize();
2969 void Curl_ssh_version(char *buffer, size_t buflen)
2971 (void)msnprintf(buffer, buflen, "libssh/%s", ssh_version(0));
2974 #endif /* USE_LIBSSH */