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 ***************************************************************************/
26 #include "curl_setup.h"
32 #include <libssh/libssh.h>
33 #include <libssh/sftp.h>
35 #ifdef HAVE_NETINET_IN_H
36 #include <netinet/in.h>
38 #ifdef HAVE_ARPA_INET_H
39 #include <arpa/inet.h>
42 #include <sys/utsname.h>
52 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
54 #define in_addr_t unsigned long
57 #include <curl/curl.h>
64 #include "http.h" /* for HTTP proxy tunnel stuff */
67 #include "speedcheck.h"
71 #include "vtls/vtls.h"
73 #include "inet_ntop.h"
74 #include "parsedate.h" /* for the week day and month names */
75 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
76 #include "strtoofft.h"
80 #include "curl_path.h"
82 #ifdef HAVE_SYS_STAT_H
92 /* The last 3 #include files should be in this order */
93 #include "curl_printf.h"
94 #include "curl_memory.h"
97 /* A recent macro provided by libssh. Or make our own. */
98 #ifndef SSH_STRING_FREE_CHAR
99 #define SSH_STRING_FREE_CHAR(x) \
102 ssh_string_free_char(x); \
108 /* These stat values may not be the same as the user's S_IFMT / S_IFLNK */
110 #define SSH_S_IFMT 00170000
113 #define SSH_S_IFLNK 0120000
116 /* Local functions: */
117 static CURLcode myssh_connect(struct Curl_easy *data, bool *done);
118 static CURLcode myssh_multi_statemach(struct Curl_easy *data,
120 static CURLcode myssh_do_it(struct Curl_easy *data, bool *done);
122 static CURLcode scp_done(struct Curl_easy *data,
123 CURLcode, bool premature);
124 static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done);
125 static CURLcode scp_disconnect(struct Curl_easy *data,
126 struct connectdata *conn,
127 bool dead_connection);
129 static CURLcode sftp_done(struct Curl_easy *data,
130 CURLcode, bool premature);
131 static CURLcode sftp_doing(struct Curl_easy *data,
133 static CURLcode sftp_disconnect(struct Curl_easy *data,
134 struct connectdata *conn,
137 CURLcode sftp_perform(struct Curl_easy *data,
141 static void sftp_quote(struct Curl_easy *data);
142 static void sftp_quote_stat(struct Curl_easy *data);
143 static int myssh_getsock(struct Curl_easy *data,
144 struct connectdata *conn, curl_socket_t *sock);
146 static CURLcode myssh_setup_connection(struct Curl_easy *data,
147 struct connectdata *conn);
150 * SCP protocol handler.
153 const struct Curl_handler Curl_handler_scp = {
155 myssh_setup_connection, /* setup_connection */
156 myssh_do_it, /* do_it */
158 ZERO_NULL, /* do_more */
159 myssh_connect, /* connect_it */
160 myssh_multi_statemach, /* connecting */
161 scp_doing, /* doing */
162 myssh_getsock, /* proto_getsock */
163 myssh_getsock, /* doing_getsock */
164 ZERO_NULL, /* domore_getsock */
165 myssh_getsock, /* perform_getsock */
166 scp_disconnect, /* disconnect */
167 ZERO_NULL, /* readwrite */
168 ZERO_NULL, /* connection_check */
169 ZERO_NULL, /* attach connection */
170 PORT_SSH, /* defport */
171 CURLPROTO_SCP, /* protocol */
172 CURLPROTO_SCP, /* family */
173 PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */
177 * SFTP protocol handler.
180 const struct Curl_handler Curl_handler_sftp = {
182 myssh_setup_connection, /* setup_connection */
183 myssh_do_it, /* do_it */
184 sftp_done, /* done */
185 ZERO_NULL, /* do_more */
186 myssh_connect, /* connect_it */
187 myssh_multi_statemach, /* connecting */
188 sftp_doing, /* doing */
189 myssh_getsock, /* proto_getsock */
190 myssh_getsock, /* doing_getsock */
191 ZERO_NULL, /* domore_getsock */
192 myssh_getsock, /* perform_getsock */
193 sftp_disconnect, /* disconnect */
194 ZERO_NULL, /* readwrite */
195 ZERO_NULL, /* connection_check */
196 ZERO_NULL, /* attach connection */
197 PORT_SSH, /* defport */
198 CURLPROTO_SFTP, /* protocol */
199 CURLPROTO_SFTP, /* family */
200 PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
201 | PROTOPT_NOURLQUERY /* flags */
204 static CURLcode sftp_error_to_CURLE(int err)
210 case SSH_FX_NO_SUCH_FILE:
211 case SSH_FX_NO_SUCH_PATH:
212 return CURLE_REMOTE_FILE_NOT_FOUND;
214 case SSH_FX_PERMISSION_DENIED:
215 case SSH_FX_WRITE_PROTECT:
216 return CURLE_REMOTE_ACCESS_DENIED;
218 case SSH_FX_FILE_ALREADY_EXISTS:
219 return CURLE_REMOTE_FILE_EXISTS;
229 #define state(x,y) mystate(x,y)
231 #define state(x,y) mystate(x,y, __LINE__)
235 * SSH State machine related code
237 /* This is the ONLY way to change SSH state! */
238 static void mystate(struct Curl_easy *data, sshstate nowstate
244 struct connectdata *conn = data->conn;
245 struct ssh_conn *sshc = &conn->proto.sshc;
246 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
247 /* for debug purposes */
248 static const char *const names[] = {
254 "SSH_AUTH_PKEY_INIT",
256 "SSH_AUTH_PASS_INIT",
258 "SSH_AUTH_AGENT_INIT",
259 "SSH_AUTH_AGENT_LIST",
261 "SSH_AUTH_HOST_INIT",
269 "SSH_SFTP_QUOTE_INIT",
270 "SSH_SFTP_POSTQUOTE_INIT",
272 "SSH_SFTP_NEXT_QUOTE",
273 "SSH_SFTP_QUOTE_STAT",
274 "SSH_SFTP_QUOTE_SETSTAT",
275 "SSH_SFTP_QUOTE_SYMLINK",
276 "SSH_SFTP_QUOTE_MKDIR",
277 "SSH_SFTP_QUOTE_RENAME",
278 "SSH_SFTP_QUOTE_RMDIR",
279 "SSH_SFTP_QUOTE_UNLINK",
280 "SSH_SFTP_QUOTE_STATVFS",
283 "SSH_SFTP_TRANS_INIT",
284 "SSH_SFTP_UPLOAD_INIT",
285 "SSH_SFTP_CREATE_DIRS_INIT",
286 "SSH_SFTP_CREATE_DIRS",
287 "SSH_SFTP_CREATE_DIRS_MKDIR",
288 "SSH_SFTP_READDIR_INIT",
290 "SSH_SFTP_READDIR_LINK",
291 "SSH_SFTP_READDIR_BOTTOM",
292 "SSH_SFTP_READDIR_DONE",
293 "SSH_SFTP_DOWNLOAD_INIT",
294 "SSH_SFTP_DOWNLOAD_STAT",
297 "SSH_SCP_TRANS_INIT",
298 "SSH_SCP_UPLOAD_INIT",
299 "SSH_SCP_DOWNLOAD_INIT",
304 "SSH_SCP_WAIT_CLOSE",
305 "SSH_SCP_CHANNEL_FREE",
306 "SSH_SESSION_DISCONNECT",
312 if(sshc->state != nowstate) {
313 infof(data, "SSH %p state change from %s to %s (line %d)",
314 (void *) sshc, names[sshc->state], names[nowstate],
319 sshc->state = nowstate;
323 * 1. data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] is set with an MD5
324 * hash (90s style auth, not sure we should have it here)
325 * 2. data->set.ssh_keyfunc callback is set. Then we do trust on first
326 * use. We even save on knownhosts if CURLKHSTAT_FINE_ADD_TO_FILE
328 * 3. none of the above. We only accept if it is present on known hosts.
330 * Returns SSH_OK or SSH_ERROR.
332 static int myssh_is_known(struct Curl_easy *data)
335 struct connectdata *conn = data->conn;
336 struct ssh_conn *sshc = &conn->proto.sshc;
339 unsigned char *hash = NULL;
340 char *found_base64 = NULL;
341 char *known_base64 = NULL;
343 enum curl_khmatch keymatch;
344 struct curl_khkey foundkey;
345 struct curl_khkey *knownkeyp = NULL;
346 curl_sshkeycallback func =
347 data->set.ssh_keyfunc;
349 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
350 struct ssh_knownhosts_entry *knownhostsentry = NULL;
351 struct curl_khkey knownkey;
354 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0)
355 rc = ssh_get_server_publickey(sshc->ssh_session, &pubkey);
357 rc = ssh_get_publickey(sshc->ssh_session, &pubkey);
362 if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) {
365 const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
367 rc = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_MD5,
369 if(rc != SSH_OK || hlen != 16) {
371 "Denied establishing ssh session: md5 fingerprint not available");
375 for(i = 0; i < 16; i++)
376 msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char)hash[i]);
378 infof(data, "SSH MD5 fingerprint: %s", md5buffer);
380 if(!strcasecompare(md5buffer, pubkey_md5)) {
382 "Denied establishing ssh session: mismatch md5 fingerprint. "
383 "Remote %s is not equal to %s", md5buffer, pubkey_md5);
392 if(data->set.ssl.primary.verifyhost != TRUE) {
397 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
398 /* Get the known_key from the known hosts file */
399 vstate = ssh_session_get_known_hosts_entry(sshc->ssh_session,
402 /* Case an entry was found in a known hosts file */
403 if(knownhostsentry) {
404 if(knownhostsentry->publickey) {
405 rc = ssh_pki_export_pubkey_base64(knownhostsentry->publickey,
410 knownkey.key = known_base64;
411 knownkey.len = strlen(known_base64);
413 switch(ssh_key_type(knownhostsentry->publickey)) {
414 case SSH_KEYTYPE_RSA:
415 knownkey.keytype = CURLKHTYPE_RSA;
417 case SSH_KEYTYPE_RSA1:
418 knownkey.keytype = CURLKHTYPE_RSA1;
420 case SSH_KEYTYPE_ECDSA:
421 case SSH_KEYTYPE_ECDSA_P256:
422 case SSH_KEYTYPE_ECDSA_P384:
423 case SSH_KEYTYPE_ECDSA_P521:
424 knownkey.keytype = CURLKHTYPE_ECDSA;
426 case SSH_KEYTYPE_ED25519:
427 knownkey.keytype = CURLKHTYPE_ED25519;
429 case SSH_KEYTYPE_DSS:
430 knownkey.keytype = CURLKHTYPE_DSS;
436 knownkeyp = &knownkey;
441 case SSH_KNOWN_HOSTS_OK:
442 keymatch = CURLKHMATCH_OK;
444 case SSH_KNOWN_HOSTS_OTHER:
446 case SSH_KNOWN_HOSTS_NOT_FOUND:
448 case SSH_KNOWN_HOSTS_UNKNOWN:
450 case SSH_KNOWN_HOSTS_ERROR:
451 keymatch = CURLKHMATCH_MISSING;
454 keymatch = CURLKHMATCH_MISMATCH;
459 vstate = ssh_is_server_known(sshc->ssh_session);
461 case SSH_SERVER_KNOWN_OK:
462 keymatch = CURLKHMATCH_OK;
464 case SSH_SERVER_FILE_NOT_FOUND:
466 case SSH_SERVER_NOT_KNOWN:
467 keymatch = CURLKHMATCH_MISSING;
470 keymatch = CURLKHMATCH_MISMATCH;
475 if(func) { /* use callback to determine action */
476 rc = ssh_pki_export_pubkey_base64(pubkey, &found_base64);
480 foundkey.key = found_base64;
481 foundkey.len = strlen(found_base64);
483 switch(ssh_key_type(pubkey)) {
484 case SSH_KEYTYPE_RSA:
485 foundkey.keytype = CURLKHTYPE_RSA;
487 case SSH_KEYTYPE_RSA1:
488 foundkey.keytype = CURLKHTYPE_RSA1;
490 case SSH_KEYTYPE_ECDSA:
491 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
492 case SSH_KEYTYPE_ECDSA_P256:
493 case SSH_KEYTYPE_ECDSA_P384:
494 case SSH_KEYTYPE_ECDSA_P521:
496 foundkey.keytype = CURLKHTYPE_ECDSA;
498 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,7,0)
499 case SSH_KEYTYPE_ED25519:
500 foundkey.keytype = CURLKHTYPE_ED25519;
503 case SSH_KEYTYPE_DSS:
504 foundkey.keytype = CURLKHTYPE_DSS;
511 Curl_set_in_callback(data, true);
512 rc = func(data, knownkeyp, /* from the knownhosts file */
513 &foundkey, /* from the remote host */
514 keymatch, data->set.ssh_keyfunc_userp);
515 Curl_set_in_callback(data, false);
518 case CURLKHSTAT_FINE_ADD_TO_FILE:
519 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0)
520 rc = ssh_session_update_known_hosts(sshc->ssh_session);
522 rc = ssh_write_knownhost(sshc->ssh_session);
528 case CURLKHSTAT_FINE:
530 default: /* REJECT/DEFER */
536 if(keymatch != CURLKHMATCH_OK) {
545 (free)(found_base64);
548 (free)(known_base64);
551 ssh_clean_pubkey_hash(&hash);
552 ssh_key_free(pubkey);
553 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
554 if(knownhostsentry) {
555 ssh_knownhosts_entry_free(knownhostsentry);
561 #define MOVE_TO_ERROR_STATE(_r) do { \
562 state(data, SSH_SESSION_DISCONNECT); \
563 sshc->actualcode = _r; \
567 #define MOVE_TO_SFTP_CLOSE_STATE() do { \
568 state(data, SSH_SFTP_CLOSE); \
570 sftp_error_to_CURLE(sftp_get_error(sshc->sftp_session)); \
574 #define MOVE_TO_LAST_AUTH do { \
575 if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) { \
577 state(data, SSH_AUTH_PASS_INIT); \
580 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); \
584 #define MOVE_TO_TERTIARY_AUTH do { \
585 if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) { \
587 state(data, SSH_AUTH_KEY_INIT); \
594 #define MOVE_TO_SECONDARY_AUTH do { \
595 if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) { \
597 state(data, SSH_AUTH_GSSAPI); \
600 MOVE_TO_TERTIARY_AUTH; \
605 int myssh_auth_interactive(struct connectdata *conn)
608 struct ssh_conn *sshc = &conn->proto.sshc;
612 switch(sshc->kbd_state) {
614 rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
615 if(rc == SSH_AUTH_AGAIN)
618 if(rc != SSH_AUTH_INFO)
621 nprompts = ssh_userauth_kbdint_getnprompts(sshc->ssh_session);
625 rc = ssh_userauth_kbdint_setanswer(sshc->ssh_session, 0, conn->passwd);
633 rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
634 if(rc == SSH_AUTH_AGAIN)
636 else if(rc == SSH_AUTH_SUCCESS)
638 else if(rc == SSH_AUTH_INFO) {
639 nprompts = ssh_userauth_kbdint_getnprompts(sshc->ssh_session);
652 rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
653 if(rc == SSH_AUTH_AGAIN)
655 else if(rc == SSH_AUTH_SUCCESS)
670 * ssh_statemach_act() runs the SSH state machine as far as it can without
671 * blocking and without reaching the end. The data the pointer 'block' points
672 * to will be set to TRUE if the libssh function returns SSH_AGAIN
673 * meaning it wants to be called again when the socket is ready
675 static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
677 CURLcode result = CURLE_OK;
678 struct connectdata *conn = data->conn;
679 struct SSHPROTO *protop = data->req.p.ssh;
680 struct ssh_conn *sshc = &conn->proto.sshc;
681 curl_socket_t sock = conn->sock[FIRSTSOCKET];
682 int rc = SSH_NO_ERROR, err;
683 char *new_readdir_line;
684 int seekerr = CURL_SEEKFUNC_OK;
686 *block = 0; /* we're not blocking by default */
690 switch(sshc->state) {
692 sshc->secondCreateDirs = 0;
693 sshc->nextstate = SSH_NO_STATE;
694 sshc->actualcode = CURLE_OK;
697 ssh_set_log_level(SSH_LOG_PROTOCOL);
700 /* Set libssh to non-blocking, since everything internally is
702 ssh_set_blocking(sshc->ssh_session, 0);
704 state(data, SSH_S_STARTUP);
708 rc = ssh_connect(sshc->ssh_session);
713 failf(data, "Failure establishing ssh session");
714 MOVE_TO_ERROR_STATE(CURLE_FAILED_INIT);
718 state(data, SSH_HOSTKEY);
723 rc = myssh_is_known(data);
725 MOVE_TO_ERROR_STATE(CURLE_PEER_FAILED_VERIFICATION);
729 state(data, SSH_AUTHLIST);
732 sshc->authed = FALSE;
734 rc = ssh_userauth_none(sshc->ssh_session, NULL);
735 if(rc == SSH_AUTH_AGAIN) {
740 if(rc == SSH_AUTH_SUCCESS) {
742 infof(data, "Authenticated with none");
743 state(data, SSH_AUTH_DONE);
746 else if(rc == SSH_AUTH_ERROR) {
747 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
751 sshc->auth_methods = ssh_userauth_list(sshc->ssh_session, NULL);
752 if(sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) {
753 state(data, SSH_AUTH_PKEY_INIT);
754 infof(data, "Authentication using SSH public key file");
756 else if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) {
757 state(data, SSH_AUTH_GSSAPI);
759 else if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) {
760 state(data, SSH_AUTH_KEY_INIT);
762 else if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) {
763 state(data, SSH_AUTH_PASS_INIT);
765 else { /* unsupported authentication method */
766 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
772 case SSH_AUTH_PKEY_INIT:
773 if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY)) {
774 MOVE_TO_SECONDARY_AUTH;
778 /* Two choices, (1) private key was given on CMD,
779 * (2) use the "default" keys. */
780 if(data->set.str[STRING_SSH_PRIVATE_KEY]) {
781 if(sshc->pubkey && !data->set.ssl.key_passwd) {
782 rc = ssh_userauth_try_publickey(sshc->ssh_session, NULL,
784 if(rc == SSH_AUTH_AGAIN) {
790 MOVE_TO_SECONDARY_AUTH;
795 rc = ssh_pki_import_privkey_file(data->
796 set.str[STRING_SSH_PRIVATE_KEY],
797 data->set.ssl.key_passwd, NULL,
798 NULL, &sshc->privkey);
800 failf(data, "Could not load private key file %s",
801 data->set.str[STRING_SSH_PRIVATE_KEY]);
802 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
806 state(data, SSH_AUTH_PKEY);
811 rc = ssh_userauth_publickey_auto(sshc->ssh_session, NULL,
812 data->set.ssl.key_passwd);
813 if(rc == SSH_AUTH_AGAIN) {
817 if(rc == SSH_AUTH_SUCCESS) {
820 infof(data, "Completed public key authentication");
821 state(data, SSH_AUTH_DONE);
825 MOVE_TO_SECONDARY_AUTH;
829 rc = ssh_userauth_publickey(sshc->ssh_session, NULL, sshc->privkey);
830 if(rc == SSH_AUTH_AGAIN) {
835 if(rc == SSH_AUTH_SUCCESS) {
837 infof(data, "Completed public key authentication");
838 state(data, SSH_AUTH_DONE);
842 infof(data, "Failed public key authentication (rc: %d)", rc);
843 MOVE_TO_SECONDARY_AUTH;
847 case SSH_AUTH_GSSAPI:
848 if(!(data->set.ssh_auth_types & CURLSSH_AUTH_GSSAPI)) {
849 MOVE_TO_TERTIARY_AUTH;
853 rc = ssh_userauth_gssapi(sshc->ssh_session);
854 if(rc == SSH_AUTH_AGAIN) {
859 if(rc == SSH_AUTH_SUCCESS) {
862 infof(data, "Completed gssapi authentication");
863 state(data, SSH_AUTH_DONE);
867 MOVE_TO_TERTIARY_AUTH;
870 case SSH_AUTH_KEY_INIT:
871 if(data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) {
872 state(data, SSH_AUTH_KEY);
881 /* Authentication failed. Continue with keyboard-interactive now. */
882 rc = myssh_auth_interactive(conn);
883 if(rc == SSH_AGAIN) {
888 infof(data, "completed keyboard interactive authentication");
890 state(data, SSH_AUTH_DONE);
893 case SSH_AUTH_PASS_INIT:
894 if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD)) {
895 /* Host key authentication is intentionally not implemented */
896 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
899 state(data, SSH_AUTH_PASS);
903 rc = ssh_userauth_password(sshc->ssh_session, NULL, conn->passwd);
904 if(rc == SSH_AUTH_AGAIN) {
909 if(rc == SSH_AUTH_SUCCESS) {
911 infof(data, "Completed password authentication");
912 state(data, SSH_AUTH_DONE);
915 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
921 failf(data, "Authentication failure");
922 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
927 * At this point we have an authenticated ssh session.
929 infof(data, "Authentication complete");
931 Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSH is connected */
934 conn->writesockfd = CURL_SOCKET_BAD;
936 if(conn->handler->protocol == CURLPROTO_SFTP) {
937 state(data, SSH_SFTP_INIT);
940 infof(data, "SSH CONNECT phase done");
941 state(data, SSH_STOP);
945 ssh_set_blocking(sshc->ssh_session, 1);
947 sshc->sftp_session = sftp_new(sshc->ssh_session);
948 if(!sshc->sftp_session) {
949 failf(data, "Failure initializing sftp session: %s",
950 ssh_get_error(sshc->ssh_session));
951 MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
955 rc = sftp_init(sshc->sftp_session);
957 rc = sftp_get_error(sshc->sftp_session);
958 failf(data, "Failure initializing sftp session: %s",
959 ssh_get_error(sshc->ssh_session));
960 MOVE_TO_ERROR_STATE(sftp_error_to_CURLE(rc));
963 state(data, SSH_SFTP_REALPATH);
965 case SSH_SFTP_REALPATH:
967 * Get the "home" directory
969 sshc->homedir = sftp_canonicalize_path(sshc->sftp_session, ".");
971 MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
974 data->state.most_recent_ftp_entrypath = sshc->homedir;
976 /* This is the last step in the SFTP connect phase. Do note that while
977 we get the homedir here, we get the "workingpath" in the DO action
978 since the homedir will remain the same between request but the
979 working path will not. */
980 DEBUGF(infof(data, "SSH CONNECT phase done"));
981 state(data, SSH_STOP);
984 case SSH_SFTP_QUOTE_INIT:
985 result = Curl_getworkingpath(data, sshc->homedir, &protop->path);
987 sshc->actualcode = result;
988 state(data, SSH_STOP);
992 if(data->set.quote) {
993 infof(data, "Sending quote commands");
994 sshc->quote_item = data->set.quote;
995 state(data, SSH_SFTP_QUOTE);
998 state(data, SSH_SFTP_GETINFO);
1002 case SSH_SFTP_POSTQUOTE_INIT:
1003 if(data->set.postquote) {
1004 infof(data, "Sending quote commands");
1005 sshc->quote_item = data->set.postquote;
1006 state(data, SSH_SFTP_QUOTE);
1009 state(data, SSH_STOP);
1013 case SSH_SFTP_QUOTE:
1014 /* Send any quote commands */
1018 case SSH_SFTP_NEXT_QUOTE:
1019 Curl_safefree(sshc->quote_path1);
1020 Curl_safefree(sshc->quote_path2);
1022 sshc->quote_item = sshc->quote_item->next;
1024 if(sshc->quote_item) {
1025 state(data, SSH_SFTP_QUOTE);
1028 if(sshc->nextstate != SSH_NO_STATE) {
1029 state(data, sshc->nextstate);
1030 sshc->nextstate = SSH_NO_STATE;
1033 state(data, SSH_SFTP_GETINFO);
1038 case SSH_SFTP_QUOTE_STAT:
1039 sftp_quote_stat(data);
1042 case SSH_SFTP_QUOTE_SETSTAT:
1043 rc = sftp_setstat(sshc->sftp_session, sshc->quote_path2,
1045 if(rc && !sshc->acceptfail) {
1046 Curl_safefree(sshc->quote_path1);
1047 Curl_safefree(sshc->quote_path2);
1048 failf(data, "Attempt to set SFTP stats failed: %s",
1049 ssh_get_error(sshc->ssh_session));
1050 state(data, SSH_SFTP_CLOSE);
1051 sshc->nextstate = SSH_NO_STATE;
1052 sshc->actualcode = CURLE_QUOTE_ERROR;
1053 /* sshc->actualcode = sftp_error_to_CURLE(err);
1054 * we do not send the actual error; we return
1055 * the error the libssh2 backend is returning */
1058 state(data, SSH_SFTP_NEXT_QUOTE);
1061 case SSH_SFTP_QUOTE_SYMLINK:
1062 rc = sftp_symlink(sshc->sftp_session, sshc->quote_path2,
1064 if(rc && !sshc->acceptfail) {
1065 Curl_safefree(sshc->quote_path1);
1066 Curl_safefree(sshc->quote_path2);
1067 failf(data, "symlink command failed: %s",
1068 ssh_get_error(sshc->ssh_session));
1069 state(data, SSH_SFTP_CLOSE);
1070 sshc->nextstate = SSH_NO_STATE;
1071 sshc->actualcode = CURLE_QUOTE_ERROR;
1074 state(data, SSH_SFTP_NEXT_QUOTE);
1077 case SSH_SFTP_QUOTE_MKDIR:
1078 rc = sftp_mkdir(sshc->sftp_session, sshc->quote_path1,
1079 (mode_t)data->set.new_directory_perms);
1080 if(rc && !sshc->acceptfail) {
1081 Curl_safefree(sshc->quote_path1);
1082 failf(data, "mkdir command failed: %s",
1083 ssh_get_error(sshc->ssh_session));
1084 state(data, SSH_SFTP_CLOSE);
1085 sshc->nextstate = SSH_NO_STATE;
1086 sshc->actualcode = CURLE_QUOTE_ERROR;
1089 state(data, SSH_SFTP_NEXT_QUOTE);
1092 case SSH_SFTP_QUOTE_RENAME:
1093 rc = sftp_rename(sshc->sftp_session, sshc->quote_path1,
1095 if(rc && !sshc->acceptfail) {
1096 Curl_safefree(sshc->quote_path1);
1097 Curl_safefree(sshc->quote_path2);
1098 failf(data, "rename command failed: %s",
1099 ssh_get_error(sshc->ssh_session));
1100 state(data, SSH_SFTP_CLOSE);
1101 sshc->nextstate = SSH_NO_STATE;
1102 sshc->actualcode = CURLE_QUOTE_ERROR;
1105 state(data, SSH_SFTP_NEXT_QUOTE);
1108 case SSH_SFTP_QUOTE_RMDIR:
1109 rc = sftp_rmdir(sshc->sftp_session, sshc->quote_path1);
1110 if(rc && !sshc->acceptfail) {
1111 Curl_safefree(sshc->quote_path1);
1112 failf(data, "rmdir command failed: %s",
1113 ssh_get_error(sshc->ssh_session));
1114 state(data, SSH_SFTP_CLOSE);
1115 sshc->nextstate = SSH_NO_STATE;
1116 sshc->actualcode = CURLE_QUOTE_ERROR;
1119 state(data, SSH_SFTP_NEXT_QUOTE);
1122 case SSH_SFTP_QUOTE_UNLINK:
1123 rc = sftp_unlink(sshc->sftp_session, sshc->quote_path1);
1124 if(rc && !sshc->acceptfail) {
1125 Curl_safefree(sshc->quote_path1);
1126 failf(data, "rm command failed: %s",
1127 ssh_get_error(sshc->ssh_session));
1128 state(data, SSH_SFTP_CLOSE);
1129 sshc->nextstate = SSH_NO_STATE;
1130 sshc->actualcode = CURLE_QUOTE_ERROR;
1133 state(data, SSH_SFTP_NEXT_QUOTE);
1136 case SSH_SFTP_QUOTE_STATVFS:
1138 sftp_statvfs_t statvfs;
1140 statvfs = sftp_statvfs(sshc->sftp_session, sshc->quote_path1);
1141 if(!statvfs && !sshc->acceptfail) {
1142 Curl_safefree(sshc->quote_path1);
1143 failf(data, "statvfs command failed: %s",
1144 ssh_get_error(sshc->ssh_session));
1145 state(data, SSH_SFTP_CLOSE);
1146 sshc->nextstate = SSH_NO_STATE;
1147 sshc->actualcode = CURLE_QUOTE_ERROR;
1151 char *tmp = aprintf("statvfs:\n"
1152 "f_bsize: %llu\n" "f_frsize: %llu\n"
1153 "f_blocks: %llu\n" "f_bfree: %llu\n"
1154 "f_bavail: %llu\n" "f_files: %llu\n"
1155 "f_ffree: %llu\n" "f_favail: %llu\n"
1156 "f_fsid: %llu\n" "f_flag: %llu\n"
1157 "f_namemax: %llu\n",
1158 statvfs->f_bsize, statvfs->f_frsize,
1159 statvfs->f_blocks, statvfs->f_bfree,
1160 statvfs->f_bavail, statvfs->f_files,
1161 statvfs->f_ffree, statvfs->f_favail,
1162 statvfs->f_fsid, statvfs->f_flag,
1163 statvfs->f_namemax);
1164 sftp_statvfs_free(statvfs);
1167 result = CURLE_OUT_OF_MEMORY;
1168 state(data, SSH_SFTP_CLOSE);
1169 sshc->nextstate = SSH_NO_STATE;
1173 result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
1176 state(data, SSH_SFTP_CLOSE);
1177 sshc->nextstate = SSH_NO_STATE;
1178 sshc->actualcode = result;
1181 state(data, SSH_SFTP_NEXT_QUOTE);
1185 case SSH_SFTP_GETINFO:
1186 if(data->set.get_filetime) {
1187 state(data, SSH_SFTP_FILETIME);
1190 state(data, SSH_SFTP_TRANS_INIT);
1194 case SSH_SFTP_FILETIME:
1196 sftp_attributes attrs;
1198 attrs = sftp_stat(sshc->sftp_session, protop->path);
1200 data->info.filetime = attrs->mtime;
1201 sftp_attributes_free(attrs);
1204 state(data, SSH_SFTP_TRANS_INIT);
1208 case SSH_SFTP_TRANS_INIT:
1209 if(data->set.upload)
1210 state(data, SSH_SFTP_UPLOAD_INIT);
1212 if(protop->path[strlen(protop->path)-1] == '/')
1213 state(data, SSH_SFTP_READDIR_INIT);
1215 state(data, SSH_SFTP_DOWNLOAD_INIT);
1219 case SSH_SFTP_UPLOAD_INIT:
1223 if(data->state.resume_from) {
1224 sftp_attributes attrs;
1226 if(data->state.resume_from < 0) {
1227 attrs = sftp_stat(sshc->sftp_session, protop->path);
1229 curl_off_t size = attrs->size;
1231 failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
1232 MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME);
1235 data->state.resume_from = attrs->size;
1237 sftp_attributes_free(attrs);
1240 data->state.resume_from = 0;
1245 if(data->set.remote_append)
1246 /* Try to open for append, but create if nonexisting */
1247 flags = O_WRONLY|O_CREAT|O_APPEND;
1248 else if(data->state.resume_from > 0)
1249 /* If we have restart position then open for append */
1250 flags = O_WRONLY|O_APPEND;
1252 /* Clear file before writing (normal behavior) */
1253 flags = O_WRONLY|O_CREAT|O_TRUNC;
1256 sftp_close(sshc->sftp_file);
1258 sftp_open(sshc->sftp_session, protop->path,
1259 flags, (mode_t)data->set.new_file_perms);
1260 if(!sshc->sftp_file) {
1261 err = sftp_get_error(sshc->sftp_session);
1263 if(((err == SSH_FX_NO_SUCH_FILE || err == SSH_FX_FAILURE ||
1264 err == SSH_FX_NO_SUCH_PATH)) &&
1265 (data->set.ftp_create_missing_dirs &&
1266 (strlen(protop->path) > 1))) {
1267 /* try to create the path remotely */
1269 sshc->secondCreateDirs = 1;
1270 state(data, SSH_SFTP_CREATE_DIRS_INIT);
1274 MOVE_TO_SFTP_CLOSE_STATE();
1279 /* If we have a restart point then we need to seek to the correct
1281 if(data->state.resume_from > 0) {
1282 /* Let's read off the proper amount of bytes from the input. */
1283 if(conn->seek_func) {
1284 Curl_set_in_callback(data, true);
1285 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1287 Curl_set_in_callback(data, false);
1290 if(seekerr != CURL_SEEKFUNC_OK) {
1291 curl_off_t passed = 0;
1293 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1294 failf(data, "Could not seek stream");
1295 return CURLE_FTP_COULDNT_USE_REST;
1297 /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
1299 size_t readthisamountnow =
1300 (data->state.resume_from - passed > data->set.buffer_size) ?
1301 (size_t)data->set.buffer_size :
1302 curlx_sotouz(data->state.resume_from - passed);
1304 size_t actuallyread =
1305 data->state.fread_func(data->state.buffer, 1,
1306 readthisamountnow, data->state.in);
1308 passed += actuallyread;
1309 if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1310 /* this checks for greater-than only to make sure that the
1311 CURL_READFUNC_ABORT return code still aborts */
1312 failf(data, "Failed to read data");
1313 MOVE_TO_ERROR_STATE(CURLE_FTP_COULDNT_USE_REST);
1316 } while(passed < data->state.resume_from);
1321 /* now, decrease the size of the read */
1322 if(data->state.infilesize > 0) {
1323 data->state.infilesize -= data->state.resume_from;
1324 data->req.size = data->state.infilesize;
1325 Curl_pgrsSetUploadSize(data, data->state.infilesize);
1328 rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
1330 MOVE_TO_SFTP_CLOSE_STATE();
1334 if(data->state.infilesize > 0) {
1335 data->req.size = data->state.infilesize;
1336 Curl_pgrsSetUploadSize(data, data->state.infilesize);
1339 Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
1341 /* not set by Curl_setup_transfer to preserve keepon bits */
1342 conn->sockfd = conn->writesockfd;
1344 /* store this original bitmask setup to use later on if we can't
1345 figure out a "real" bitmask */
1346 sshc->orig_waitfor = data->req.keepon;
1348 /* we want to use the _sending_ function even when the socket turns
1349 out readable as the underlying libssh sftp send function will deal
1350 with both accordingly */
1351 conn->cselect_bits = CURL_CSELECT_OUT;
1353 /* since we don't really wait for anything at this point, we want the
1354 state machine to move on as soon as possible so we set a very short
1356 Curl_expire(data, 0, EXPIRE_RUN_NOW);
1358 state(data, SSH_STOP);
1362 case SSH_SFTP_CREATE_DIRS_INIT:
1363 if(strlen(protop->path) > 1) {
1364 sshc->slash_pos = protop->path + 1; /* ignore the leading '/' */
1365 state(data, SSH_SFTP_CREATE_DIRS);
1368 state(data, SSH_SFTP_UPLOAD_INIT);
1372 case SSH_SFTP_CREATE_DIRS:
1373 sshc->slash_pos = strchr(sshc->slash_pos, '/');
1374 if(sshc->slash_pos) {
1375 *sshc->slash_pos = 0;
1377 infof(data, "Creating directory '%s'", protop->path);
1378 state(data, SSH_SFTP_CREATE_DIRS_MKDIR);
1381 state(data, SSH_SFTP_UPLOAD_INIT);
1384 case SSH_SFTP_CREATE_DIRS_MKDIR:
1385 /* 'mode' - parameter is preliminary - default to 0644 */
1386 rc = sftp_mkdir(sshc->sftp_session, protop->path,
1387 (mode_t)data->set.new_directory_perms);
1388 *sshc->slash_pos = '/';
1392 * Abort if failure wasn't that the dir already exists or the
1393 * permission was denied (creation might succeed further down the
1394 * path) - retry on unspecific FAILURE also
1396 err = sftp_get_error(sshc->sftp_session);
1397 if((err != SSH_FX_FILE_ALREADY_EXISTS) &&
1398 (err != SSH_FX_FAILURE) &&
1399 (err != SSH_FX_PERMISSION_DENIED)) {
1400 MOVE_TO_SFTP_CLOSE_STATE();
1403 rc = 0; /* clear rc and continue */
1405 state(data, SSH_SFTP_CREATE_DIRS);
1408 case SSH_SFTP_READDIR_INIT:
1409 Curl_pgrsSetDownloadSize(data, -1);
1410 if(data->set.opt_no_body) {
1411 state(data, SSH_STOP);
1416 * This is a directory that we are trying to get, so produce a directory
1419 sshc->sftp_dir = sftp_opendir(sshc->sftp_session,
1421 if(!sshc->sftp_dir) {
1422 failf(data, "Could not open directory for reading: %s",
1423 ssh_get_error(sshc->ssh_session));
1424 MOVE_TO_SFTP_CLOSE_STATE();
1427 state(data, SSH_SFTP_READDIR);
1430 case SSH_SFTP_READDIR:
1432 if(sshc->readdir_attrs)
1433 sftp_attributes_free(sshc->readdir_attrs);
1435 sshc->readdir_attrs = sftp_readdir(sshc->sftp_session, sshc->sftp_dir);
1436 if(sshc->readdir_attrs) {
1437 sshc->readdir_filename = sshc->readdir_attrs->name;
1438 sshc->readdir_longentry = sshc->readdir_attrs->longname;
1439 sshc->readdir_len = strlen(sshc->readdir_filename);
1441 if(data->set.list_only) {
1444 tmpLine = aprintf("%s\n", sshc->readdir_filename);
1446 state(data, SSH_SFTP_CLOSE);
1447 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1450 result = Curl_client_write(data, CLIENTWRITE_BODY,
1451 tmpLine, sshc->readdir_len + 1);
1455 state(data, SSH_STOP);
1458 /* since this counts what we send to the client, we include the
1459 newline in this counter */
1460 data->req.bytecount += sshc->readdir_len + 1;
1462 /* output debug output if that is requested */
1463 Curl_debug(data, CURLINFO_DATA_OUT, (char *)sshc->readdir_filename,
1467 sshc->readdir_currLen = strlen(sshc->readdir_longentry);
1468 sshc->readdir_totalLen = 80 + sshc->readdir_currLen;
1469 sshc->readdir_line = calloc(sshc->readdir_totalLen, 1);
1470 if(!sshc->readdir_line) {
1471 state(data, SSH_SFTP_CLOSE);
1472 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1476 memcpy(sshc->readdir_line, sshc->readdir_longentry,
1477 sshc->readdir_currLen);
1478 if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
1479 ((sshc->readdir_attrs->permissions & SSH_S_IFMT) ==
1481 sshc->readdir_linkPath = aprintf("%s%s", protop->path,
1482 sshc->readdir_filename);
1484 if(!sshc->readdir_linkPath) {
1485 state(data, SSH_SFTP_CLOSE);
1486 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1490 state(data, SSH_SFTP_READDIR_LINK);
1493 state(data, SSH_SFTP_READDIR_BOTTOM);
1497 else if(sftp_dir_eof(sshc->sftp_dir)) {
1498 state(data, SSH_SFTP_READDIR_DONE);
1502 failf(data, "Could not open remote file for reading: %s",
1503 ssh_get_error(sshc->ssh_session));
1504 MOVE_TO_SFTP_CLOSE_STATE();
1509 case SSH_SFTP_READDIR_LINK:
1510 if(sshc->readdir_link_attrs)
1511 sftp_attributes_free(sshc->readdir_link_attrs);
1513 sshc->readdir_link_attrs = sftp_lstat(sshc->sftp_session,
1514 sshc->readdir_linkPath);
1515 if(sshc->readdir_link_attrs == 0) {
1516 failf(data, "Could not read symlink for reading: %s",
1517 ssh_get_error(sshc->ssh_session));
1518 MOVE_TO_SFTP_CLOSE_STATE();
1522 if(!sshc->readdir_link_attrs->name) {
1523 sshc->readdir_tmp = sftp_readlink(sshc->sftp_session,
1524 sshc->readdir_linkPath);
1525 if(!sshc->readdir_filename)
1526 sshc->readdir_len = 0;
1528 sshc->readdir_len = strlen(sshc->readdir_tmp);
1529 sshc->readdir_longentry = NULL;
1530 sshc->readdir_filename = sshc->readdir_tmp;
1533 sshc->readdir_len = strlen(sshc->readdir_link_attrs->name);
1534 sshc->readdir_filename = sshc->readdir_link_attrs->name;
1535 sshc->readdir_longentry = sshc->readdir_link_attrs->longname;
1538 Curl_safefree(sshc->readdir_linkPath);
1540 /* get room for the filename and extra output */
1541 sshc->readdir_totalLen += 4 + sshc->readdir_len;
1542 new_readdir_line = Curl_saferealloc(sshc->readdir_line,
1543 sshc->readdir_totalLen);
1544 if(!new_readdir_line) {
1545 sshc->readdir_line = NULL;
1546 state(data, SSH_SFTP_CLOSE);
1547 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1550 sshc->readdir_line = new_readdir_line;
1552 sshc->readdir_currLen += msnprintf(sshc->readdir_line +
1553 sshc->readdir_currLen,
1554 sshc->readdir_totalLen -
1555 sshc->readdir_currLen,
1557 sshc->readdir_filename);
1559 sftp_attributes_free(sshc->readdir_link_attrs);
1560 sshc->readdir_link_attrs = NULL;
1561 sshc->readdir_filename = NULL;
1562 sshc->readdir_longentry = NULL;
1564 state(data, SSH_SFTP_READDIR_BOTTOM);
1566 case SSH_SFTP_READDIR_BOTTOM:
1567 sshc->readdir_currLen += msnprintf(sshc->readdir_line +
1568 sshc->readdir_currLen,
1569 sshc->readdir_totalLen -
1570 sshc->readdir_currLen, "\n");
1571 result = Curl_client_write(data, CLIENTWRITE_BODY,
1573 sshc->readdir_currLen);
1576 /* output debug output if that is requested */
1577 Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_line,
1578 sshc->readdir_currLen);
1579 data->req.bytecount += sshc->readdir_currLen;
1581 Curl_safefree(sshc->readdir_line);
1582 ssh_string_free_char(sshc->readdir_tmp);
1583 sshc->readdir_tmp = NULL;
1586 state(data, SSH_STOP);
1589 state(data, SSH_SFTP_READDIR);
1592 case SSH_SFTP_READDIR_DONE:
1593 sftp_closedir(sshc->sftp_dir);
1594 sshc->sftp_dir = NULL;
1596 /* no data to transfer */
1597 Curl_setup_transfer(data, -1, -1, FALSE, -1);
1598 state(data, SSH_STOP);
1601 case SSH_SFTP_DOWNLOAD_INIT:
1603 * Work on getting the specified file
1606 sftp_close(sshc->sftp_file);
1608 sshc->sftp_file = sftp_open(sshc->sftp_session, protop->path,
1609 O_RDONLY, (mode_t)data->set.new_file_perms);
1610 if(!sshc->sftp_file) {
1611 failf(data, "Could not open remote file for reading: %s",
1612 ssh_get_error(sshc->ssh_session));
1614 MOVE_TO_SFTP_CLOSE_STATE();
1618 state(data, SSH_SFTP_DOWNLOAD_STAT);
1621 case SSH_SFTP_DOWNLOAD_STAT:
1623 sftp_attributes attrs;
1626 attrs = sftp_fstat(sshc->sftp_file);
1628 !(attrs->flags & SSH_FILEXFER_ATTR_SIZE) ||
1629 (attrs->size == 0)) {
1631 * sftp_fstat didn't return an error, so maybe the server
1632 * just doesn't support stat()
1633 * OR the server doesn't return a file size with a stat()
1636 data->req.size = -1;
1637 data->req.maxdownload = -1;
1638 Curl_pgrsSetDownloadSize(data, -1);
1644 sftp_attributes_free(attrs);
1647 failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
1648 return CURLE_BAD_DOWNLOAD_RESUME;
1650 if(data->state.use_range) {
1651 curl_off_t from, to;
1657 from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from);
1658 if(from_t == CURL_OFFT_FLOW) {
1659 return CURLE_RANGE_ERROR;
1661 while(*ptr && (ISSPACE(*ptr) || (*ptr == '-')))
1663 to_t = curlx_strtoofft(ptr, &ptr2, 0, &to);
1664 if(to_t == CURL_OFFT_FLOW) {
1665 return CURLE_RANGE_ERROR;
1667 if((to_t == CURL_OFFT_INVAL) /* no "to" value given */
1672 /* from is relative to end of file */
1677 failf(data, "Offset (%"
1678 CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
1679 CURL_FORMAT_CURL_OFF_T ")", from, size);
1680 return CURLE_BAD_DOWNLOAD_RESUME;
1687 size = to - from + 1;
1690 rc = sftp_seek64(sshc->sftp_file, from);
1692 MOVE_TO_SFTP_CLOSE_STATE();
1696 data->req.size = size;
1697 data->req.maxdownload = size;
1698 Curl_pgrsSetDownloadSize(data, size);
1701 /* We can resume if we can seek to the resume position */
1702 if(data->state.resume_from) {
1703 if(data->state.resume_from < 0) {
1704 /* We're supposed to download the last abs(from) bytes */
1705 if((curl_off_t)size < -data->state.resume_from) {
1706 failf(data, "Offset (%"
1707 CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
1708 CURL_FORMAT_CURL_OFF_T ")",
1709 data->state.resume_from, size);
1710 return CURLE_BAD_DOWNLOAD_RESUME;
1712 /* download from where? */
1713 data->state.resume_from += size;
1716 if((curl_off_t)size < data->state.resume_from) {
1717 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
1718 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
1719 data->state.resume_from, size);
1720 return CURLE_BAD_DOWNLOAD_RESUME;
1723 /* Now store the number of bytes we are expected to download */
1724 data->req.size = size - data->state.resume_from;
1725 data->req.maxdownload = size - data->state.resume_from;
1726 Curl_pgrsSetDownloadSize(data,
1727 size - data->state.resume_from);
1729 rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
1731 MOVE_TO_SFTP_CLOSE_STATE();
1737 /* Setup the actual download */
1738 if(data->req.size == 0) {
1739 /* no data to transfer */
1740 Curl_setup_transfer(data, -1, -1, FALSE, -1);
1741 infof(data, "File already completely downloaded");
1742 state(data, SSH_STOP);
1745 Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1);
1747 /* not set by Curl_setup_transfer to preserve keepon bits */
1748 conn->writesockfd = conn->sockfd;
1750 /* we want to use the _receiving_ function even when the socket turns
1751 out writableable as the underlying libssh recv function will deal
1752 with both accordingly */
1753 conn->cselect_bits = CURL_CSELECT_IN;
1756 /* this should never occur; the close state should be entered
1757 at the time the error occurs */
1758 state(data, SSH_SFTP_CLOSE);
1759 sshc->actualcode = result;
1762 sshc->sftp_recv_state = 0;
1763 state(data, SSH_STOP);
1767 case SSH_SFTP_CLOSE:
1768 if(sshc->sftp_file) {
1769 sftp_close(sshc->sftp_file);
1770 sshc->sftp_file = NULL;
1772 Curl_safefree(protop->path);
1774 DEBUGF(infof(data, "SFTP DONE done"));
1776 /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT
1777 After nextstate is executed, the control should come back to
1778 SSH_SFTP_CLOSE to pass the correct result back */
1779 if(sshc->nextstate != SSH_NO_STATE &&
1780 sshc->nextstate != SSH_SFTP_CLOSE) {
1781 state(data, sshc->nextstate);
1782 sshc->nextstate = SSH_SFTP_CLOSE;
1785 state(data, SSH_STOP);
1786 result = sshc->actualcode;
1790 case SSH_SFTP_SHUTDOWN:
1791 /* during times we get here due to a broken transfer and then the
1792 sftp_handle might not have been taken down so make sure that is done
1793 before we proceed */
1795 if(sshc->sftp_file) {
1796 sftp_close(sshc->sftp_file);
1797 sshc->sftp_file = NULL;
1800 if(sshc->sftp_session) {
1801 sftp_free(sshc->sftp_session);
1802 sshc->sftp_session = NULL;
1805 SSH_STRING_FREE_CHAR(sshc->homedir);
1806 data->state.most_recent_ftp_entrypath = NULL;
1808 state(data, SSH_SESSION_DISCONNECT);
1811 case SSH_SCP_TRANS_INIT:
1812 result = Curl_getworkingpath(data, sshc->homedir, &protop->path);
1814 sshc->actualcode = result;
1815 state(data, SSH_STOP);
1819 /* Functions from the SCP subsystem cannot handle/return SSH_AGAIN */
1820 ssh_set_blocking(sshc->ssh_session, 1);
1822 if(data->set.upload) {
1823 if(data->state.infilesize < 0) {
1824 failf(data, "SCP requires a known file size for upload");
1825 sshc->actualcode = CURLE_UPLOAD_FAILED;
1826 MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1831 ssh_scp_new(sshc->ssh_session, SSH_SCP_WRITE, protop->path);
1832 state(data, SSH_SCP_UPLOAD_INIT);
1836 ssh_scp_new(sshc->ssh_session, SSH_SCP_READ, protop->path);
1837 state(data, SSH_SCP_DOWNLOAD_INIT);
1840 if(!sshc->scp_session) {
1841 err_msg = ssh_get_error(sshc->ssh_session);
1842 failf(data, "%s", err_msg);
1843 MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1848 case SSH_SCP_UPLOAD_INIT:
1850 rc = ssh_scp_init(sshc->scp_session);
1852 err_msg = ssh_get_error(sshc->ssh_session);
1853 failf(data, "%s", err_msg);
1854 MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1858 rc = ssh_scp_push_file(sshc->scp_session, protop->path,
1859 data->state.infilesize,
1860 (int)data->set.new_file_perms);
1862 err_msg = ssh_get_error(sshc->ssh_session);
1863 failf(data, "%s", err_msg);
1864 MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1869 Curl_setup_transfer(data, -1, data->req.size, FALSE, FIRSTSOCKET);
1871 /* not set by Curl_setup_transfer to preserve keepon bits */
1872 conn->sockfd = conn->writesockfd;
1874 /* store this original bitmask setup to use later on if we can't
1875 figure out a "real" bitmask */
1876 sshc->orig_waitfor = data->req.keepon;
1878 /* we want to use the _sending_ function even when the socket turns
1879 out readable as the underlying libssh scp send function will deal
1880 with both accordingly */
1881 conn->cselect_bits = CURL_CSELECT_OUT;
1883 state(data, SSH_STOP);
1887 case SSH_SCP_DOWNLOAD_INIT:
1889 rc = ssh_scp_init(sshc->scp_session);
1891 err_msg = ssh_get_error(sshc->ssh_session);
1892 failf(data, "%s", err_msg);
1893 MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
1896 state(data, SSH_SCP_DOWNLOAD);
1899 case SSH_SCP_DOWNLOAD:{
1900 curl_off_t bytecount;
1902 rc = ssh_scp_pull_request(sshc->scp_session);
1903 if(rc != SSH_SCP_REQUEST_NEWFILE) {
1904 err_msg = ssh_get_error(sshc->ssh_session);
1905 failf(data, "%s", err_msg);
1906 MOVE_TO_ERROR_STATE(CURLE_REMOTE_FILE_NOT_FOUND);
1911 bytecount = ssh_scp_request_get_size(sshc->scp_session);
1912 data->req.maxdownload = (curl_off_t) bytecount;
1913 Curl_setup_transfer(data, FIRSTSOCKET, bytecount, FALSE, -1);
1915 /* not set by Curl_setup_transfer to preserve keepon bits */
1916 conn->writesockfd = conn->sockfd;
1918 /* we want to use the _receiving_ function even when the socket turns
1919 out writableable as the underlying libssh recv function will deal
1920 with both accordingly */
1921 conn->cselect_bits = CURL_CSELECT_IN;
1923 state(data, SSH_STOP);
1927 if(data->set.upload)
1928 state(data, SSH_SCP_SEND_EOF);
1930 state(data, SSH_SCP_CHANNEL_FREE);
1933 case SSH_SCP_SEND_EOF:
1934 if(sshc->scp_session) {
1935 rc = ssh_scp_close(sshc->scp_session);
1936 if(rc == SSH_AGAIN) {
1937 /* Currently the ssh_scp_close handles waiting for EOF in
1943 infof(data, "Failed to close libssh scp channel: %s",
1944 ssh_get_error(sshc->ssh_session));
1948 state(data, SSH_SCP_CHANNEL_FREE);
1951 case SSH_SCP_CHANNEL_FREE:
1952 if(sshc->scp_session) {
1953 ssh_scp_free(sshc->scp_session);
1954 sshc->scp_session = NULL;
1956 DEBUGF(infof(data, "SCP DONE phase complete"));
1958 ssh_set_blocking(sshc->ssh_session, 0);
1960 state(data, SSH_SESSION_DISCONNECT);
1963 case SSH_SESSION_DISCONNECT:
1964 /* during weird times when we've been prematurely aborted, the channel
1965 is still alive when we reach this state and we MUST kill the channel
1967 if(sshc->scp_session) {
1968 ssh_scp_free(sshc->scp_session);
1969 sshc->scp_session = NULL;
1972 ssh_disconnect(sshc->ssh_session);
1973 /* conn->sock[FIRSTSOCKET] is closed by ssh_disconnect behind our back,
1974 explicitly mark it as closed with the memdebug macro: */
1975 fake_sclose(conn->sock[FIRSTSOCKET]);
1976 conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD;
1978 SSH_STRING_FREE_CHAR(sshc->homedir);
1979 data->state.most_recent_ftp_entrypath = NULL;
1981 state(data, SSH_SESSION_FREE);
1983 case SSH_SESSION_FREE:
1984 if(sshc->ssh_session) {
1985 ssh_free(sshc->ssh_session);
1986 sshc->ssh_session = NULL;
1989 /* worst-case scenario cleanup */
1991 DEBUGASSERT(sshc->ssh_session == NULL);
1992 DEBUGASSERT(sshc->scp_session == NULL);
1994 if(sshc->readdir_tmp) {
1995 ssh_string_free_char(sshc->readdir_tmp);
1996 sshc->readdir_tmp = NULL;
1999 if(sshc->quote_attrs)
2000 sftp_attributes_free(sshc->quote_attrs);
2002 if(sshc->readdir_attrs)
2003 sftp_attributes_free(sshc->readdir_attrs);
2005 if(sshc->readdir_link_attrs)
2006 sftp_attributes_free(sshc->readdir_link_attrs);
2009 ssh_key_free(sshc->privkey);
2011 ssh_key_free(sshc->pubkey);
2013 Curl_safefree(sshc->rsa_pub);
2014 Curl_safefree(sshc->rsa);
2015 Curl_safefree(sshc->quote_path1);
2016 Curl_safefree(sshc->quote_path2);
2017 Curl_safefree(sshc->readdir_line);
2018 Curl_safefree(sshc->readdir_linkPath);
2019 SSH_STRING_FREE_CHAR(sshc->homedir);
2021 /* the code we are about to return */
2022 result = sshc->actualcode;
2024 memset(sshc, 0, sizeof(struct ssh_conn));
2026 connclose(conn, "SSH session free");
2027 sshc->state = SSH_SESSION_FREE; /* current */
2028 sshc->nextstate = SSH_NO_STATE;
2029 state(data, SSH_STOP);
2033 /* fallthrough, just stop! */
2035 /* internal error */
2036 sshc->nextstate = SSH_NO_STATE;
2037 state(data, SSH_STOP);
2041 } while(!rc && (sshc->state != SSH_STOP));
2044 if(rc == SSH_AGAIN) {
2045 /* we would block, we need to wait for the socket to be ready (in the
2046 right direction too)! */
2054 /* called by the multi interface to figure out what socket(s) to wait for and
2055 for what actions in the DO_DONE, PERFORM and WAITPERFORM states */
2056 static int myssh_getsock(struct Curl_easy *data,
2057 struct connectdata *conn,
2058 curl_socket_t *sock)
2060 int bitmap = GETSOCK_BLANK;
2062 sock[0] = conn->sock[FIRSTSOCKET];
2064 if(conn->waitfor & KEEP_RECV)
2065 bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
2067 if(conn->waitfor & KEEP_SEND)
2068 bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
2071 bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
2076 static void myssh_block2waitfor(struct connectdata *conn, bool block)
2078 struct ssh_conn *sshc = &conn->proto.sshc;
2080 /* If it didn't block, or nothing was returned by ssh_get_poll_flags
2081 * have the original set */
2082 conn->waitfor = sshc->orig_waitfor;
2085 int dir = ssh_get_poll_flags(sshc->ssh_session);
2086 if(dir & SSH_READ_PENDING) {
2087 /* translate the libssh define bits into our own bit defines */
2088 conn->waitfor = KEEP_RECV;
2090 else if(dir & SSH_WRITE_PENDING) {
2091 conn->waitfor = KEEP_SEND;
2096 /* called repeatedly until done from multi.c */
2097 static CURLcode myssh_multi_statemach(struct Curl_easy *data,
2100 struct connectdata *conn = data->conn;
2101 struct ssh_conn *sshc = &conn->proto.sshc;
2102 bool block; /* we store the status and use that to provide a ssh_getsock()
2104 CURLcode result = myssh_statemach_act(data, &block);
2106 *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
2107 myssh_block2waitfor(conn, block);
2112 static CURLcode myssh_block_statemach(struct Curl_easy *data,
2115 struct connectdata *conn = data->conn;
2116 struct ssh_conn *sshc = &conn->proto.sshc;
2117 CURLcode result = CURLE_OK;
2119 while((sshc->state != SSH_STOP) && !result) {
2121 timediff_t left = 1000;
2122 struct curltime now = Curl_now();
2124 result = myssh_statemach_act(data, &block);
2129 if(Curl_pgrsUpdate(data))
2130 return CURLE_ABORTED_BY_CALLBACK;
2132 result = Curl_speedcheck(data, now);
2136 left = Curl_timeleft(data, NULL, FALSE);
2138 failf(data, "Operation timed out");
2139 return CURLE_OPERATION_TIMEDOUT;
2144 curl_socket_t fd_read = conn->sock[FIRSTSOCKET];
2145 /* wait for the socket to become ready */
2146 (void) Curl_socket_check(fd_read, CURL_SOCKET_BAD,
2147 CURL_SOCKET_BAD, left > 1000 ? 1000 : left);
2156 * SSH setup connection
2158 static CURLcode myssh_setup_connection(struct Curl_easy *data,
2159 struct connectdata *conn)
2161 struct SSHPROTO *ssh;
2164 data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
2166 return CURLE_OUT_OF_MEMORY;
2171 static Curl_recv scp_recv, sftp_recv;
2172 static Curl_send scp_send, sftp_send;
2175 * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to
2176 * do protocol-specific actions at connect-time.
2178 static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
2180 struct ssh_conn *ssh;
2182 struct connectdata *conn = data->conn;
2183 curl_socket_t sock = conn->sock[FIRSTSOCKET];
2186 /* initialize per-handle data if not already */
2187 if(!data->req.p.ssh)
2188 myssh_setup_connection(data, conn);
2190 /* We default to persistent connections. We set this already in this connect
2191 function to make the re-use checks properly be able to check this bit. */
2192 connkeep(conn, "SSH default");
2194 if(conn->handler->protocol & CURLPROTO_SCP) {
2195 conn->recv[FIRSTSOCKET] = scp_recv;
2196 conn->send[FIRSTSOCKET] = scp_send;
2199 conn->recv[FIRSTSOCKET] = sftp_recv;
2200 conn->send[FIRSTSOCKET] = sftp_send;
2203 ssh = &conn->proto.sshc;
2205 ssh->ssh_session = ssh_new();
2206 if(!ssh->ssh_session) {
2207 failf(data, "Failure initialising ssh session");
2208 return CURLE_FAILED_INIT;
2211 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, conn->host.name);
2213 failf(data, "Could not set remote host");
2214 return CURLE_FAILED_INIT;
2217 rc = ssh_options_parse_config(ssh->ssh_session, NULL);
2219 infof(data, "Could not parse SSH configuration files");
2223 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_FD, &sock);
2225 failf(data, "Could not set socket");
2226 return CURLE_FAILED_INIT;
2229 if(conn->user && conn->user[0] != '\0') {
2230 infof(data, "User: %s", conn->user);
2231 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user);
2233 failf(data, "Could not set user");
2234 return CURLE_FAILED_INIT;
2238 if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
2239 infof(data, "Known hosts: %s", data->set.str[STRING_SSH_KNOWNHOSTS]);
2240 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS,
2241 data->set.str[STRING_SSH_KNOWNHOSTS]);
2243 failf(data, "Could not set known hosts file path");
2244 return CURLE_FAILED_INIT;
2248 if(conn->remote_port) {
2249 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_PORT,
2250 &conn->remote_port);
2252 failf(data, "Could not set remote port");
2253 return CURLE_FAILED_INIT;
2257 if(data->set.ssh_compression) {
2258 rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_COMPRESSION,
2259 "zlib,zlib@openssh.com,none");
2261 failf(data, "Could not set compression");
2262 return CURLE_FAILED_INIT;
2266 ssh->privkey = NULL;
2269 if(data->set.str[STRING_SSH_PUBLIC_KEY]) {
2270 rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY],
2273 failf(data, "Could not load public key file");
2274 return CURLE_FAILED_INIT;
2278 /* we do not verify here, we do it at the state machine,
2279 * after connection */
2281 state(data, SSH_INIT);
2283 result = myssh_multi_statemach(data, done);
2288 /* called from multi.c while DOing */
2289 static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done)
2293 result = myssh_multi_statemach(data, dophase_done);
2296 DEBUGF(infof(data, "DO phase is complete"));
2302 ***********************************************************************
2306 * This is the actual DO function for SCP. Get a file according to
2307 * the options previously setup.
2311 CURLcode scp_perform(struct Curl_easy *data,
2312 bool *connected, bool *dophase_done)
2314 CURLcode result = CURLE_OK;
2315 struct connectdata *conn = data->conn;
2317 DEBUGF(infof(data, "DO phase starts"));
2319 *dophase_done = FALSE; /* not done yet */
2321 /* start the first command in the DO phase */
2322 state(data, SSH_SCP_TRANS_INIT);
2324 result = myssh_multi_statemach(data, dophase_done);
2326 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
2329 DEBUGF(infof(data, "DO phase is complete"));
2335 static CURLcode myssh_do_it(struct Curl_easy *data, bool *done)
2339 struct connectdata *conn = data->conn;
2340 struct ssh_conn *sshc = &conn->proto.sshc;
2342 *done = FALSE; /* default to false */
2344 data->req.size = -1; /* make sure this is unknown at this point */
2346 sshc->actualcode = CURLE_OK; /* reset error code */
2347 sshc->secondCreateDirs = 0; /* reset the create dir attempt state
2350 Curl_pgrsSetUploadCounter(data, 0);
2351 Curl_pgrsSetDownloadCounter(data, 0);
2352 Curl_pgrsSetUploadSize(data, -1);
2353 Curl_pgrsSetDownloadSize(data, -1);
2355 if(conn->handler->protocol & CURLPROTO_SCP)
2356 result = scp_perform(data, &connected, done);
2358 result = sftp_perform(data, &connected, done);
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 */
2366 static CURLcode scp_disconnect(struct Curl_easy *data,
2367 struct connectdata *conn,
2368 bool dead_connection)
2370 CURLcode result = CURLE_OK;
2371 struct ssh_conn *ssh = &conn->proto.sshc;
2372 (void) dead_connection;
2374 if(ssh->ssh_session) {
2375 /* only if there's a session still around to use! */
2377 state(data, SSH_SESSION_DISCONNECT);
2379 result = myssh_block_statemach(data, TRUE);
2385 /* generic done function for both SCP and SFTP called from their specific
2387 static CURLcode myssh_done(struct Curl_easy *data, CURLcode status)
2389 CURLcode result = CURLE_OK;
2390 struct SSHPROTO *protop = data->req.p.ssh;
2393 /* run the state-machine */
2394 result = myssh_block_statemach(data, FALSE);
2400 Curl_safefree(protop->path);
2401 if(Curl_pgrsDone(data))
2402 return CURLE_ABORTED_BY_CALLBACK;
2404 data->req.keepon = 0; /* clear all bits */
2409 static CURLcode scp_done(struct Curl_easy *data, CURLcode status,
2412 (void) premature; /* not used */
2415 state(data, SSH_SCP_DONE);
2417 return myssh_done(data, status);
2421 static ssize_t scp_send(struct Curl_easy *data, int sockindex,
2422 const void *mem, size_t len, CURLcode *err)
2425 struct connectdata *conn = data->conn;
2426 (void) sockindex; /* we only support SCP on the fixed known primary socket */
2429 rc = ssh_scp_write(conn->proto.sshc.scp_session, mem, len);
2432 /* The following code is misleading, mostly added as wishful thinking
2433 * that libssh at some point will implement non-blocking ssh_scp_write/read.
2434 * Currently rc can only be number of bytes read or SSH_ERROR. */
2435 myssh_block2waitfor(conn, (rc == SSH_AGAIN) ? TRUE : FALSE);
2437 if(rc == SSH_AGAIN) {
2451 static ssize_t scp_recv(struct Curl_easy *data, int sockindex,
2452 char *mem, size_t len, CURLcode *err)
2455 struct connectdata *conn = data->conn;
2457 (void) sockindex; /* we only support SCP on the fixed known primary socket */
2459 /* libssh returns int */
2460 nread = ssh_scp_read(conn->proto.sshc.scp_session, mem, len);
2463 /* The following code is misleading, mostly added as wishful thinking
2464 * that libssh at some point will implement non-blocking ssh_scp_write/read.
2465 * Currently rc can only be SSH_OK or SSH_ERROR. */
2467 myssh_block2waitfor(conn, (nread == SSH_AGAIN) ? TRUE : FALSE);
2468 if(nread == SSH_AGAIN) {
2478 * =============== SFTP ===============
2482 ***********************************************************************
2486 * This is the actual DO function for SFTP. Get a file/directory according to
2487 * the options previously setup.
2491 CURLcode sftp_perform(struct Curl_easy *data,
2495 CURLcode result = CURLE_OK;
2496 struct connectdata *conn = data->conn;
2498 DEBUGF(infof(data, "DO phase starts"));
2500 *dophase_done = FALSE; /* not done yet */
2502 /* start the first command in the DO phase */
2503 state(data, SSH_SFTP_QUOTE_INIT);
2505 /* run the state-machine */
2506 result = myssh_multi_statemach(data, dophase_done);
2508 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
2511 DEBUGF(infof(data, "DO phase is complete"));
2517 /* called from multi.c while DOing */
2518 static CURLcode sftp_doing(struct Curl_easy *data,
2521 CURLcode result = myssh_multi_statemach(data, dophase_done);
2523 DEBUGF(infof(data, "DO phase is complete"));
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 */
2531 static CURLcode sftp_disconnect(struct Curl_easy *data,
2532 struct connectdata *conn,
2533 bool dead_connection)
2535 CURLcode result = CURLE_OK;
2536 (void) dead_connection;
2538 DEBUGF(infof(data, "SSH DISCONNECT starts now"));
2540 if(conn->proto.sshc.ssh_session) {
2541 /* only if there's a session still around to use! */
2542 state(data, SSH_SFTP_SHUTDOWN);
2543 result = myssh_block_statemach(data, TRUE);
2546 DEBUGF(infof(data, "SSH DISCONNECT is done"));
2552 static CURLcode sftp_done(struct Curl_easy *data, CURLcode status,
2555 struct connectdata *conn = data->conn;
2556 struct ssh_conn *sshc = &conn->proto.sshc;
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
2562 if(!premature && data->set.postquote && !conn->bits.retry)
2563 sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
2564 state(data, SSH_SFTP_CLOSE);
2566 return myssh_done(data, status);
2569 /* return number of sent bytes */
2570 static ssize_t sftp_send(struct Curl_easy *data, int sockindex,
2571 const void *mem, size_t len, CURLcode *err)
2574 struct connectdata *conn = data->conn;
2577 nwrite = sftp_write(conn->proto.sshc.sftp_file, mem, len);
2579 myssh_block2waitfor(conn, FALSE);
2581 #if 0 /* not returned by libssh on write */
2582 if(nwrite == SSH_AGAIN) {
2597 * Return number of received (decrypted) bytes
2600 static ssize_t sftp_recv(struct Curl_easy *data, int sockindex,
2601 char *mem, size_t len, CURLcode *err)
2604 struct connectdata *conn = data->conn;
2607 DEBUGASSERT(len < CURL_MAX_READ_SIZE);
2609 switch(conn->proto.sshc.sftp_recv_state) {
2611 conn->proto.sshc.sftp_file_index =
2612 sftp_async_read_begin(conn->proto.sshc.sftp_file,
2614 if(conn->proto.sshc.sftp_file_index < 0) {
2615 *err = CURLE_RECV_ERROR;
2621 conn->proto.sshc.sftp_recv_state = 1;
2623 nread = sftp_async_read(conn->proto.sshc.sftp_file,
2625 conn->proto.sshc.sftp_file_index);
2627 myssh_block2waitfor(conn, (nread == SSH_AGAIN)?TRUE:FALSE);
2629 if(nread == SSH_AGAIN) {
2633 else if(nread < 0) {
2634 *err = CURLE_RECV_ERROR;
2638 conn->proto.sshc.sftp_recv_state = 0;
2642 /* we never reach here */
2647 static void sftp_quote(struct Curl_easy *data)
2650 struct connectdata *conn = data->conn;
2651 struct SSHPROTO *protop = data->req.p.ssh;
2652 struct ssh_conn *sshc = &conn->proto.sshc;
2656 * Support some of the "FTP" commands
2658 char *cmd = sshc->quote_item->data;
2659 sshc->acceptfail = FALSE;
2661 /* if a command starts with an asterisk, which a legal SFTP command never
2662 can, the command will be allowed to fail without it causing any
2663 aborts or cancels etc. It will cause libcurl to act as if the command
2664 is successful, whatever the server reponds. */
2668 sshc->acceptfail = TRUE;
2671 if(strcasecompare("pwd", cmd)) {
2672 /* output debug output if that is requested */
2673 char *tmp = aprintf("257 \"%s\" is current directory.\n",
2676 sshc->actualcode = CURLE_OUT_OF_MEMORY;
2677 state(data, SSH_SFTP_CLOSE);
2678 sshc->nextstate = SSH_NO_STATE;
2681 Curl_debug(data, CURLINFO_HEADER_OUT, (char *) "PWD\n", 4);
2682 Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
2684 /* this sends an FTP-like "header" to the header callback so that the
2685 current directory can be read very similar to how it is read when
2686 using ordinary FTP. */
2687 result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
2690 state(data, SSH_SFTP_CLOSE);
2691 sshc->nextstate = SSH_NO_STATE;
2692 sshc->actualcode = result;
2695 state(data, SSH_SFTP_NEXT_QUOTE);
2700 * the arguments following the command must be separated from the
2701 * command with a space so we can check for it unconditionally
2703 cp = strchr(cmd, ' ');
2705 failf(data, "Syntax error in SFTP command. Supply parameter(s)");
2706 state(data, SSH_SFTP_CLOSE);
2707 sshc->nextstate = SSH_NO_STATE;
2708 sshc->actualcode = CURLE_QUOTE_ERROR;
2713 * also, every command takes at least one argument so we get that
2714 * first argument right now
2716 result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir);
2718 if(result == CURLE_OUT_OF_MEMORY)
2719 failf(data, "Out of memory");
2721 failf(data, "Syntax error: Bad first parameter");
2722 state(data, SSH_SFTP_CLOSE);
2723 sshc->nextstate = SSH_NO_STATE;
2724 sshc->actualcode = result;
2729 * SFTP is a binary protocol, so we don't send text commands
2730 * to the server. Instead, we scan for commands used by
2731 * OpenSSH's sftp program and call the appropriate libssh
2734 if(strncasecompare(cmd, "chgrp ", 6) ||
2735 strncasecompare(cmd, "chmod ", 6) ||
2736 strncasecompare(cmd, "chown ", 6) ||
2737 strncasecompare(cmd, "atime ", 6) ||
2738 strncasecompare(cmd, "mtime ", 6)) {
2739 /* attribute change */
2741 /* sshc->quote_path1 contains the mode to set */
2742 /* get the destination */
2743 result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2745 if(result == CURLE_OUT_OF_MEMORY)
2746 failf(data, "Out of memory");
2748 failf(data, "Syntax error in chgrp/chmod/chown/atime/mtime: "
2749 "Bad second parameter");
2750 Curl_safefree(sshc->quote_path1);
2751 state(data, SSH_SFTP_CLOSE);
2752 sshc->nextstate = SSH_NO_STATE;
2753 sshc->actualcode = result;
2756 sshc->quote_attrs = NULL;
2757 state(data, SSH_SFTP_QUOTE_STAT);
2760 if(strncasecompare(cmd, "ln ", 3) ||
2761 strncasecompare(cmd, "symlink ", 8)) {
2762 /* symbolic linking */
2763 /* sshc->quote_path1 is the source */
2764 /* get the destination */
2765 result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2767 if(result == CURLE_OUT_OF_MEMORY)
2768 failf(data, "Out of memory");
2770 failf(data, "Syntax error in ln/symlink: Bad second parameter");
2771 Curl_safefree(sshc->quote_path1);
2772 state(data, SSH_SFTP_CLOSE);
2773 sshc->nextstate = SSH_NO_STATE;
2774 sshc->actualcode = result;
2777 state(data, SSH_SFTP_QUOTE_SYMLINK);
2780 else if(strncasecompare(cmd, "mkdir ", 6)) {
2782 state(data, SSH_SFTP_QUOTE_MKDIR);
2785 else if(strncasecompare(cmd, "rename ", 7)) {
2787 /* first param is the source path */
2788 /* second param is the dest. path */
2789 result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2791 if(result == CURLE_OUT_OF_MEMORY)
2792 failf(data, "Out of memory");
2794 failf(data, "Syntax error in rename: Bad second parameter");
2795 Curl_safefree(sshc->quote_path1);
2796 state(data, SSH_SFTP_CLOSE);
2797 sshc->nextstate = SSH_NO_STATE;
2798 sshc->actualcode = result;
2801 state(data, SSH_SFTP_QUOTE_RENAME);
2804 else if(strncasecompare(cmd, "rmdir ", 6)) {
2806 state(data, SSH_SFTP_QUOTE_RMDIR);
2809 else if(strncasecompare(cmd, "rm ", 3)) {
2810 state(data, SSH_SFTP_QUOTE_UNLINK);
2813 #ifdef HAS_STATVFS_SUPPORT
2814 else if(strncasecompare(cmd, "statvfs ", 8)) {
2815 state(data, SSH_SFTP_QUOTE_STATVFS);
2820 failf(data, "Unknown SFTP command");
2821 Curl_safefree(sshc->quote_path1);
2822 Curl_safefree(sshc->quote_path2);
2823 state(data, SSH_SFTP_CLOSE);
2824 sshc->nextstate = SSH_NO_STATE;
2825 sshc->actualcode = CURLE_QUOTE_ERROR;
2828 static void sftp_quote_stat(struct Curl_easy *data)
2830 struct connectdata *conn = data->conn;
2831 struct ssh_conn *sshc = &conn->proto.sshc;
2832 char *cmd = sshc->quote_item->data;
2833 sshc->acceptfail = FALSE;
2835 /* if a command starts with an asterisk, which a legal SFTP command never
2836 can, the command will be allowed to fail without it causing any
2837 aborts or cancels etc. It will cause libcurl to act as if the command
2838 is successful, whatever the server reponds. */
2842 sshc->acceptfail = TRUE;
2845 /* We read the file attributes, store them in sshc->quote_attrs
2846 * and modify them accordingly to command. Then we switch to
2847 * QUOTE_SETSTAT state to write new ones.
2850 if(sshc->quote_attrs)
2851 sftp_attributes_free(sshc->quote_attrs);
2852 sshc->quote_attrs = sftp_stat(sshc->sftp_session, sshc->quote_path2);
2853 if(!sshc->quote_attrs) {
2854 Curl_safefree(sshc->quote_path1);
2855 Curl_safefree(sshc->quote_path2);
2856 failf(data, "Attempt to get SFTP stats failed: %d",
2857 sftp_get_error(sshc->sftp_session));
2858 state(data, SSH_SFTP_CLOSE);
2859 sshc->nextstate = SSH_NO_STATE;
2860 sshc->actualcode = CURLE_QUOTE_ERROR;
2864 /* Now set the new attributes... */
2865 if(strncasecompare(cmd, "chgrp", 5)) {
2866 sshc->quote_attrs->gid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2867 if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
2868 !sshc->acceptfail) {
2869 Curl_safefree(sshc->quote_path1);
2870 Curl_safefree(sshc->quote_path2);
2871 failf(data, "Syntax error: chgrp gid not a number");
2872 state(data, SSH_SFTP_CLOSE);
2873 sshc->nextstate = SSH_NO_STATE;
2874 sshc->actualcode = CURLE_QUOTE_ERROR;
2877 sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2879 else if(strncasecompare(cmd, "chmod", 5)) {
2881 perms = (mode_t)strtoul(sshc->quote_path1, NULL, 8);
2882 /* permissions are octal */
2883 if(perms == 0 && !ISDIGIT(sshc->quote_path1[0])) {
2884 Curl_safefree(sshc->quote_path1);
2885 Curl_safefree(sshc->quote_path2);
2886 failf(data, "Syntax error: chmod permissions not a number");
2887 state(data, SSH_SFTP_CLOSE);
2888 sshc->nextstate = SSH_NO_STATE;
2889 sshc->actualcode = CURLE_QUOTE_ERROR;
2892 sshc->quote_attrs->permissions = perms;
2893 sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_PERMISSIONS;
2895 else if(strncasecompare(cmd, "chown", 5)) {
2896 sshc->quote_attrs->uid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2897 if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
2898 !sshc->acceptfail) {
2899 Curl_safefree(sshc->quote_path1);
2900 Curl_safefree(sshc->quote_path2);
2901 failf(data, "Syntax error: chown uid not a number");
2902 state(data, SSH_SFTP_CLOSE);
2903 sshc->nextstate = SSH_NO_STATE;
2904 sshc->actualcode = CURLE_QUOTE_ERROR;
2907 sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2909 else if(strncasecompare(cmd, "atime", 5)) {
2910 time_t date = Curl_getdate_capped(sshc->quote_path1);
2912 Curl_safefree(sshc->quote_path1);
2913 Curl_safefree(sshc->quote_path2);
2914 failf(data, "Syntax error: incorrect access date format");
2915 state(data, SSH_SFTP_CLOSE);
2916 sshc->nextstate = SSH_NO_STATE;
2917 sshc->actualcode = CURLE_QUOTE_ERROR;
2920 sshc->quote_attrs->atime = (uint32_t)date;
2921 sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_ACMODTIME;
2923 else if(strncasecompare(cmd, "mtime", 5)) {
2924 time_t date = Curl_getdate_capped(sshc->quote_path1);
2926 Curl_safefree(sshc->quote_path1);
2927 Curl_safefree(sshc->quote_path2);
2928 failf(data, "Syntax error: incorrect modification date format");
2929 state(data, SSH_SFTP_CLOSE);
2930 sshc->nextstate = SSH_NO_STATE;
2931 sshc->actualcode = CURLE_QUOTE_ERROR;
2934 sshc->quote_attrs->mtime = (uint32_t)date;
2935 sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_ACMODTIME;
2938 /* Now send the completed structure... */
2939 state(data, SSH_SFTP_QUOTE_SETSTAT);
2943 CURLcode Curl_ssh_init(void)
2946 DEBUGF(fprintf(stderr, "Error: libssh_init failed\n"));
2947 return CURLE_FAILED_INIT;
2952 void Curl_ssh_cleanup(void)
2954 (void)ssh_finalize();
2957 void Curl_ssh_version(char *buffer, size_t buflen)
2959 (void)msnprintf(buffer, buflen, "libssh/%s", CURL_LIBSSH_VERSION);
2962 #endif /* USE_LIBSSH */