1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 2017 - 2018 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.haxx.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>
39 #ifdef HAVE_NETINET_IN_H
40 #include <netinet/in.h>
42 #ifdef HAVE_ARPA_INET_H
43 #include <arpa/inet.h>
46 #include <sys/utsname.h>
56 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
58 #define in_addr_t unsigned long
61 #include <curl/curl.h>
68 #include "http.h" /* for HTTP proxy tunnel stuff */
71 #include "speedcheck.h"
75 #include "vtls/vtls.h"
78 #include "inet_ntop.h"
79 #include "parsedate.h" /* for the week day and month names */
80 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
81 #include "strtoofft.h"
86 /* for permission and open flags */
87 #include <sys/types.h>
92 /* The last 3 #include files should be in this order */
93 #include "curl_printf.h"
94 #include "curl_memory.h"
96 #include "curl_path.h"
98 /* Local functions: */
99 static CURLcode myssh_connect(struct connectdata *conn, bool *done);
100 static CURLcode myssh_multi_statemach(struct connectdata *conn,
102 static CURLcode myssh_do_it(struct connectdata *conn, bool *done);
104 static CURLcode scp_done(struct connectdata *conn,
105 CURLcode, bool premature);
106 static CURLcode scp_doing(struct connectdata *conn, bool *dophase_done);
107 static CURLcode scp_disconnect(struct connectdata *conn,
108 bool dead_connection);
110 static CURLcode sftp_done(struct connectdata *conn,
111 CURLcode, bool premature);
112 static CURLcode sftp_doing(struct connectdata *conn,
114 static CURLcode sftp_disconnect(struct connectdata *conn, bool dead);
116 CURLcode sftp_perform(struct connectdata *conn,
120 static void sftp_quote(struct connectdata *conn);
121 static void sftp_quote_stat(struct connectdata *conn);
123 static int myssh_getsock(struct connectdata *conn, curl_socket_t *sock,
126 static int myssh_perform_getsock(const struct connectdata *conn,
130 static CURLcode myssh_setup_connection(struct connectdata *conn);
133 * SCP protocol handler.
136 const struct Curl_handler Curl_handler_scp = {
138 myssh_setup_connection, /* setup_connection */
139 myssh_do_it, /* do_it */
141 ZERO_NULL, /* do_more */
142 myssh_connect, /* connect_it */
143 myssh_multi_statemach, /* connecting */
144 scp_doing, /* doing */
145 myssh_getsock, /* proto_getsock */
146 myssh_getsock, /* doing_getsock */
147 ZERO_NULL, /* domore_getsock */
148 myssh_perform_getsock, /* perform_getsock */
149 scp_disconnect, /* disconnect */
150 ZERO_NULL, /* readwrite */
151 ZERO_NULL, /* connection_check */
152 PORT_SSH, /* defport */
153 CURLPROTO_SCP, /* protocol */
154 PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */
158 * SFTP protocol handler.
161 const struct Curl_handler Curl_handler_sftp = {
163 myssh_setup_connection, /* setup_connection */
164 myssh_do_it, /* do_it */
165 sftp_done, /* done */
166 ZERO_NULL, /* do_more */
167 myssh_connect, /* connect_it */
168 myssh_multi_statemach, /* connecting */
169 sftp_doing, /* doing */
170 myssh_getsock, /* proto_getsock */
171 myssh_getsock, /* doing_getsock */
172 ZERO_NULL, /* domore_getsock */
173 myssh_perform_getsock, /* perform_getsock */
174 sftp_disconnect, /* disconnect */
175 ZERO_NULL, /* readwrite */
176 ZERO_NULL, /* connection_check */
177 PORT_SSH, /* defport */
178 CURLPROTO_SFTP, /* protocol */
179 PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
180 | PROTOPT_NOURLQUERY /* flags */
183 static CURLcode sftp_error_to_CURLE(int err)
189 case SSH_FX_NO_SUCH_FILE:
190 case SSH_FX_NO_SUCH_PATH:
191 return CURLE_REMOTE_FILE_NOT_FOUND;
193 case SSH_FX_PERMISSION_DENIED:
194 case SSH_FX_WRITE_PROTECT:
195 return CURLE_REMOTE_ACCESS_DENIED;
197 case SSH_FX_FILE_ALREADY_EXISTS:
198 return CURLE_REMOTE_FILE_EXISTS;
208 * SSH State machine related code
210 /* This is the ONLY way to change SSH state! */
211 static void state(struct connectdata *conn, sshstate nowstate)
213 struct ssh_conn *sshc = &conn->proto.sshc;
214 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
215 /* for debug purposes */
216 static const char *const names[] = {
222 "SSH_AUTH_PKEY_INIT",
224 "SSH_AUTH_PASS_INIT",
226 "SSH_AUTH_AGENT_INIT",
227 "SSH_AUTH_AGENT_LIST",
229 "SSH_AUTH_HOST_INIT",
237 "SSH_SFTP_QUOTE_INIT",
238 "SSH_SFTP_POSTQUOTE_INIT",
240 "SSH_SFTP_NEXT_QUOTE",
241 "SSH_SFTP_QUOTE_STAT",
242 "SSH_SFTP_QUOTE_SETSTAT",
243 "SSH_SFTP_QUOTE_SYMLINK",
244 "SSH_SFTP_QUOTE_MKDIR",
245 "SSH_SFTP_QUOTE_RENAME",
246 "SSH_SFTP_QUOTE_RMDIR",
247 "SSH_SFTP_QUOTE_UNLINK",
248 "SSH_SFTP_QUOTE_STATVFS",
251 "SSH_SFTP_TRANS_INIT",
252 "SSH_SFTP_UPLOAD_INIT",
253 "SSH_SFTP_CREATE_DIRS_INIT",
254 "SSH_SFTP_CREATE_DIRS",
255 "SSH_SFTP_CREATE_DIRS_MKDIR",
256 "SSH_SFTP_READDIR_INIT",
258 "SSH_SFTP_READDIR_LINK",
259 "SSH_SFTP_READDIR_BOTTOM",
260 "SSH_SFTP_READDIR_DONE",
261 "SSH_SFTP_DOWNLOAD_INIT",
262 "SSH_SFTP_DOWNLOAD_STAT",
265 "SSH_SCP_TRANS_INIT",
266 "SSH_SCP_UPLOAD_INIT",
267 "SSH_SCP_DOWNLOAD_INIT",
272 "SSH_SCP_WAIT_CLOSE",
273 "SSH_SCP_CHANNEL_FREE",
274 "SSH_SESSION_DISCONNECT",
280 if(sshc->state != nowstate) {
281 infof(conn->data, "SSH %p state change from %s to %s\n",
282 (void *) sshc, names[sshc->state], names[nowstate]);
286 sshc->state = nowstate;
290 * 1. data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] is set with an MD5
291 * hash (90s style auth, not sure we should have it here)
292 * 2. data->set.ssh_keyfunc callback is set. Then we do trust on first
293 * use. We even save on knownhosts if CURLKHSTAT_FINE_ADD_TO_FILE
295 * 3. none of the above. We only accept if it is present on known hosts.
297 * Returns SSH_OK or SSH_ERROR.
299 static int myssh_is_known(struct connectdata *conn)
302 struct Curl_easy *data = conn->data;
303 struct ssh_conn *sshc = &conn->proto.sshc;
306 unsigned char *hash = NULL;
309 enum curl_khmatch keymatch;
310 struct curl_khkey foundkey;
311 curl_sshkeycallback func =
312 data->set.ssh_keyfunc;
314 rc = ssh_get_publickey(sshc->ssh_session, &pubkey);
318 if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) {
319 rc = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_MD5,
324 if(hlen != strlen(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) ||
325 memcmp(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5], hash, hlen)) {
334 if(data->set.ssl.primary.verifyhost != TRUE) {
339 vstate = ssh_is_server_known(sshc->ssh_session);
341 case SSH_SERVER_KNOWN_OK:
342 keymatch = CURLKHMATCH_OK;
344 case SSH_SERVER_FILE_NOT_FOUND:
346 case SSH_SERVER_NOT_KNOWN:
347 keymatch = CURLKHMATCH_MISSING;
350 keymatch = CURLKHMATCH_MISMATCH;
354 if(func) { /* use callback to determine action */
355 rc = ssh_pki_export_pubkey_base64(pubkey, &base64);
359 foundkey.key = base64;
360 foundkey.len = strlen(base64);
362 switch(ssh_key_type(pubkey)) {
363 case SSH_KEYTYPE_RSA:
364 foundkey.keytype = CURLKHTYPE_RSA;
366 case SSH_KEYTYPE_RSA1:
367 foundkey.keytype = CURLKHTYPE_RSA1;
369 case SSH_KEYTYPE_ECDSA:
370 foundkey.keytype = CURLKHTYPE_ECDSA;
372 #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,7,0)
373 case SSH_KEYTYPE_ED25519:
374 foundkey.keytype = CURLKHTYPE_ED25519;
377 case SSH_KEYTYPE_DSS:
378 foundkey.keytype = CURLKHTYPE_DSS;
385 /* we don't have anything equivalent to knownkey. Always NULL */
386 Curl_set_in_callback(data, true);
387 rc = func(data, NULL, &foundkey, /* from the remote host */
388 keymatch, data->set.ssh_keyfunc_userp);
389 Curl_set_in_callback(data, false);
392 case CURLKHSTAT_FINE_ADD_TO_FILE:
393 rc = ssh_write_knownhost(sshc->ssh_session);
398 case CURLKHSTAT_FINE:
400 default: /* REJECT/DEFER */
406 if(keymatch != CURLKHMATCH_OK) {
415 ssh_clean_pubkey_hash(&hash);
416 ssh_key_free(pubkey);
420 #define MOVE_TO_ERROR_STATE(_r) { \
421 state(conn, SSH_SESSION_FREE); \
422 sshc->actualcode = _r; \
427 #define MOVE_TO_SFTP_CLOSE_STATE() { \
428 state(conn, SSH_SFTP_CLOSE); \
429 sshc->actualcode = sftp_error_to_CURLE(sftp_get_error(sshc->sftp_session)); \
434 #define MOVE_TO_LAST_AUTH \
435 if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) { \
437 state(conn, SSH_AUTH_PASS_INIT); \
441 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); \
444 #define MOVE_TO_TERTIARY_AUTH \
445 if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) { \
447 state(conn, SSH_AUTH_KEY_INIT); \
454 #define MOVE_TO_SECONDARY_AUTH \
455 if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) { \
457 state(conn, SSH_AUTH_GSSAPI); \
461 MOVE_TO_TERTIARY_AUTH; \
465 int myssh_auth_interactive(struct connectdata *conn)
468 struct ssh_conn *sshc = &conn->proto.sshc;
472 switch(sshc->kbd_state) {
474 rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
475 if(rc == SSH_AUTH_AGAIN)
478 if(rc != SSH_AUTH_INFO)
481 nprompts = ssh_userauth_kbdint_getnprompts(sshc->ssh_session);
482 if(nprompts == SSH_ERROR || nprompts != 1)
485 rc = ssh_userauth_kbdint_setanswer(sshc->ssh_session, 0, conn->passwd);
493 rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
494 if(rc == SSH_AUTH_AGAIN)
496 else if(rc == SSH_AUTH_SUCCESS)
498 else if(rc == SSH_AUTH_INFO) {
499 nprompts = ssh_userauth_kbdint_getnprompts(sshc->ssh_session);
512 rc = ssh_userauth_kbdint(sshc->ssh_session, NULL, NULL);
513 if(rc == SSH_AUTH_AGAIN)
515 else if(rc == SSH_AUTH_SUCCESS)
530 * ssh_statemach_act() runs the SSH state machine as far as it can without
531 * blocking and without reaching the end. The data the pointer 'block' points
532 * to will be set to TRUE if the libssh function returns SSH_AGAIN
533 * meaning it wants to be called again when the socket is ready
535 static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
537 CURLcode result = CURLE_OK;
538 struct Curl_easy *data = conn->data;
539 struct SSHPROTO *protop = data->req.protop;
540 struct ssh_conn *sshc = &conn->proto.sshc;
541 int rc = SSH_NO_ERROR, err;
542 char *new_readdir_line;
543 int seekerr = CURL_SEEKFUNC_OK;
545 *block = 0; /* we're not blocking by default */
549 switch(sshc->state) {
551 sshc->secondCreateDirs = 0;
552 sshc->nextstate = SSH_NO_STATE;
553 sshc->actualcode = CURLE_OK;
556 ssh_set_log_level(SSH_LOG_PROTOCOL);
559 /* Set libssh to non-blocking, since everything internally is
561 ssh_set_blocking(sshc->ssh_session, 0);
563 state(conn, SSH_S_STARTUP);
567 rc = ssh_connect(sshc->ssh_session);
572 failf(data, "Failure establishing ssh session");
573 MOVE_TO_ERROR_STATE(CURLE_FAILED_INIT);
576 state(conn, SSH_HOSTKEY);
581 rc = myssh_is_known(conn);
583 MOVE_TO_ERROR_STATE(CURLE_PEER_FAILED_VERIFICATION);
586 state(conn, SSH_AUTHLIST);
589 sshc->authed = FALSE;
591 rc = ssh_userauth_none(sshc->ssh_session, NULL);
592 if(rc == SSH_AUTH_AGAIN) {
597 if(rc == SSH_AUTH_SUCCESS) {
599 infof(data, "Authenticated with none\n");
600 state(conn, SSH_AUTH_DONE);
603 else if(rc == SSH_AUTH_ERROR) {
604 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
607 sshc->auth_methods = ssh_userauth_list(sshc->ssh_session, NULL);
608 if(sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) {
609 state(conn, SSH_AUTH_PKEY_INIT);
611 else if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) {
612 state(conn, SSH_AUTH_GSSAPI);
614 else if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) {
615 state(conn, SSH_AUTH_KEY_INIT);
617 else if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) {
618 state(conn, SSH_AUTH_PASS_INIT);
620 else { /* unsupported authentication method */
621 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
626 case SSH_AUTH_PKEY_INIT:
627 if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY)) {
628 MOVE_TO_SECONDARY_AUTH;
631 /* Two choices, (1) private key was given on CMD,
632 * (2) use the "default" keys. */
633 if(data->set.str[STRING_SSH_PRIVATE_KEY]) {
634 if(sshc->pubkey && !data->set.ssl.key_passwd) {
635 rc = ssh_userauth_try_publickey(sshc->ssh_session, NULL,
637 if(rc == SSH_AUTH_AGAIN) {
643 MOVE_TO_SECONDARY_AUTH;
647 rc = ssh_pki_import_privkey_file(data->
648 set.str[STRING_SSH_PRIVATE_KEY],
649 data->set.ssl.key_passwd, NULL,
650 NULL, &sshc->privkey);
652 failf(data, "Could not load private key file %s",
653 data->set.str[STRING_SSH_PRIVATE_KEY]);
657 state(conn, SSH_AUTH_PKEY);
662 infof(data, "Authentication using SSH public key file\n");
664 rc = ssh_userauth_publickey_auto(sshc->ssh_session, NULL,
665 data->set.ssl.key_passwd);
666 if(rc == SSH_AUTH_AGAIN) {
670 if(rc == SSH_AUTH_SUCCESS) {
673 infof(data, "Completed public key authentication\n");
674 state(conn, SSH_AUTH_DONE);
678 MOVE_TO_SECONDARY_AUTH;
682 rc = ssh_userauth_publickey(sshc->ssh_session, NULL, sshc->privkey);
683 if(rc == SSH_AUTH_AGAIN) {
688 if(rc == SSH_AUTH_SUCCESS) {
690 infof(data, "Completed public key authentication\n");
691 state(conn, SSH_AUTH_DONE);
695 infof(data, "Failed public key authentication (rc: %d)\n", rc);
696 MOVE_TO_SECONDARY_AUTH;
700 case SSH_AUTH_GSSAPI:
701 if(!(data->set.ssh_auth_types & CURLSSH_AUTH_GSSAPI)) {
702 MOVE_TO_TERTIARY_AUTH;
705 rc = ssh_userauth_gssapi(sshc->ssh_session);
706 if(rc == SSH_AUTH_AGAIN) {
711 if(rc == SSH_AUTH_SUCCESS) {
714 infof(data, "Completed gssapi authentication\n");
715 state(conn, SSH_AUTH_DONE);
719 MOVE_TO_TERTIARY_AUTH;
722 case SSH_AUTH_KEY_INIT:
723 if(data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) {
724 state(conn, SSH_AUTH_KEY);
733 /* Authentication failed. Continue with keyboard-interactive now. */
734 rc = myssh_auth_interactive(conn);
735 if(rc == SSH_AGAIN) {
740 infof(data, "completed keyboard interactive authentication\n");
742 state(conn, SSH_AUTH_DONE);
745 case SSH_AUTH_PASS_INIT:
746 if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD)) {
747 /* Host key authentication is intentionally not implemented */
748 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
750 state(conn, SSH_AUTH_PASS);
754 rc = ssh_userauth_password(sshc->ssh_session, NULL, conn->passwd);
755 if(rc == SSH_AUTH_AGAIN) {
760 if(rc == SSH_AUTH_SUCCESS) {
762 infof(data, "Completed password authentication\n");
763 state(conn, SSH_AUTH_DONE);
766 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
772 failf(data, "Authentication failure");
773 MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
778 * At this point we have an authenticated ssh session.
780 infof(data, "Authentication complete\n");
782 Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSH is connected */
784 conn->sockfd = ssh_get_fd(sshc->ssh_session);
785 conn->writesockfd = CURL_SOCKET_BAD;
787 if(conn->handler->protocol == CURLPROTO_SFTP) {
788 state(conn, SSH_SFTP_INIT);
791 infof(data, "SSH CONNECT phase done\n");
792 state(conn, SSH_STOP);
796 ssh_set_blocking(sshc->ssh_session, 1);
798 sshc->sftp_session = sftp_new(sshc->ssh_session);
799 if(!sshc->sftp_session) {
800 failf(data, "Failure initializing sftp session: %s",
801 ssh_get_error(sshc->ssh_session));
802 MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
806 rc = sftp_init(sshc->sftp_session);
808 rc = sftp_get_error(sshc->sftp_session);
809 failf(data, "Failure initializing sftp session: %s",
810 ssh_get_error(sshc->ssh_session));
811 MOVE_TO_ERROR_STATE(sftp_error_to_CURLE(rc));
814 state(conn, SSH_SFTP_REALPATH);
816 case SSH_SFTP_REALPATH:
818 * Get the "home" directory
820 sshc->homedir = sftp_canonicalize_path(sshc->sftp_session, ".");
821 if(sshc->homedir == NULL) {
822 MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
824 conn->data->state.most_recent_ftp_entrypath = sshc->homedir;
826 /* This is the last step in the SFTP connect phase. Do note that while
827 we get the homedir here, we get the "workingpath" in the DO action
828 since the homedir will remain the same between request but the
829 working path will not. */
830 DEBUGF(infof(data, "SSH CONNECT phase done\n"));
831 state(conn, SSH_STOP);
834 case SSH_SFTP_QUOTE_INIT:
836 result = Curl_getworkingpath(conn, sshc->homedir, &protop->path);
838 sshc->actualcode = result;
839 state(conn, SSH_STOP);
843 if(data->set.quote) {
844 infof(data, "Sending quote commands\n");
845 sshc->quote_item = data->set.quote;
846 state(conn, SSH_SFTP_QUOTE);
849 state(conn, SSH_SFTP_GETINFO);
853 case SSH_SFTP_POSTQUOTE_INIT:
854 if(data->set.postquote) {
855 infof(data, "Sending quote commands\n");
856 sshc->quote_item = data->set.postquote;
857 state(conn, SSH_SFTP_QUOTE);
860 state(conn, SSH_STOP);
865 /* Send any quote commands */
869 case SSH_SFTP_NEXT_QUOTE:
870 Curl_safefree(sshc->quote_path1);
871 Curl_safefree(sshc->quote_path2);
873 sshc->quote_item = sshc->quote_item->next;
875 if(sshc->quote_item) {
876 state(conn, SSH_SFTP_QUOTE);
879 if(sshc->nextstate != SSH_NO_STATE) {
880 state(conn, sshc->nextstate);
881 sshc->nextstate = SSH_NO_STATE;
884 state(conn, SSH_SFTP_GETINFO);
889 case SSH_SFTP_QUOTE_STAT:
890 sftp_quote_stat(conn);
893 case SSH_SFTP_QUOTE_SETSTAT:
894 rc = sftp_setstat(sshc->sftp_session, sshc->quote_path2,
896 if(rc != 0 && !sshc->acceptfail) {
897 Curl_safefree(sshc->quote_path1);
898 Curl_safefree(sshc->quote_path2);
899 failf(data, "Attempt to set SFTP stats failed: %s",
900 ssh_get_error(sshc->ssh_session));
901 state(conn, SSH_SFTP_CLOSE);
902 sshc->nextstate = SSH_NO_STATE;
903 sshc->actualcode = CURLE_QUOTE_ERROR;
904 /* sshc->actualcode = sftp_error_to_CURLE(err);
905 * we do not send the actual error; we return
906 * the error the libssh2 backend is returning */
909 state(conn, SSH_SFTP_NEXT_QUOTE);
912 case SSH_SFTP_QUOTE_SYMLINK:
913 rc = sftp_symlink(sshc->sftp_session, sshc->quote_path2,
915 if(rc != 0 && !sshc->acceptfail) {
916 Curl_safefree(sshc->quote_path1);
917 Curl_safefree(sshc->quote_path2);
918 failf(data, "symlink command failed: %s",
919 ssh_get_error(sshc->ssh_session));
920 state(conn, SSH_SFTP_CLOSE);
921 sshc->nextstate = SSH_NO_STATE;
922 sshc->actualcode = CURLE_QUOTE_ERROR;
925 state(conn, SSH_SFTP_NEXT_QUOTE);
928 case SSH_SFTP_QUOTE_MKDIR:
929 rc = sftp_mkdir(sshc->sftp_session, sshc->quote_path1,
930 (mode_t)data->set.new_directory_perms);
931 if(rc != 0 && !sshc->acceptfail) {
932 Curl_safefree(sshc->quote_path1);
933 failf(data, "mkdir command failed: %s",
934 ssh_get_error(sshc->ssh_session));
935 state(conn, SSH_SFTP_CLOSE);
936 sshc->nextstate = SSH_NO_STATE;
937 sshc->actualcode = CURLE_QUOTE_ERROR;
940 state(conn, SSH_SFTP_NEXT_QUOTE);
943 case SSH_SFTP_QUOTE_RENAME:
944 rc = sftp_rename(sshc->sftp_session, sshc->quote_path1,
946 if(rc != 0 && !sshc->acceptfail) {
947 Curl_safefree(sshc->quote_path1);
948 Curl_safefree(sshc->quote_path2);
949 failf(data, "rename command failed: %s",
950 ssh_get_error(sshc->ssh_session));
951 state(conn, SSH_SFTP_CLOSE);
952 sshc->nextstate = SSH_NO_STATE;
953 sshc->actualcode = CURLE_QUOTE_ERROR;
956 state(conn, SSH_SFTP_NEXT_QUOTE);
959 case SSH_SFTP_QUOTE_RMDIR:
960 rc = sftp_rmdir(sshc->sftp_session, sshc->quote_path1);
961 if(rc != 0 && !sshc->acceptfail) {
962 Curl_safefree(sshc->quote_path1);
963 failf(data, "rmdir command failed: %s",
964 ssh_get_error(sshc->ssh_session));
965 state(conn, SSH_SFTP_CLOSE);
966 sshc->nextstate = SSH_NO_STATE;
967 sshc->actualcode = CURLE_QUOTE_ERROR;
970 state(conn, SSH_SFTP_NEXT_QUOTE);
973 case SSH_SFTP_QUOTE_UNLINK:
974 rc = sftp_unlink(sshc->sftp_session, sshc->quote_path1);
975 if(rc != 0 && !sshc->acceptfail) {
976 Curl_safefree(sshc->quote_path1);
977 failf(data, "rm command failed: %s",
978 ssh_get_error(sshc->ssh_session));
979 state(conn, SSH_SFTP_CLOSE);
980 sshc->nextstate = SSH_NO_STATE;
981 sshc->actualcode = CURLE_QUOTE_ERROR;
984 state(conn, SSH_SFTP_NEXT_QUOTE);
987 case SSH_SFTP_QUOTE_STATVFS:
989 sftp_statvfs_t statvfs;
991 statvfs = sftp_statvfs(sshc->sftp_session, sshc->quote_path1);
992 if(!statvfs && !sshc->acceptfail) {
993 Curl_safefree(sshc->quote_path1);
994 failf(data, "statvfs command failed: %s",
995 ssh_get_error(sshc->ssh_session));
996 state(conn, SSH_SFTP_CLOSE);
997 sshc->nextstate = SSH_NO_STATE;
998 sshc->actualcode = CURLE_QUOTE_ERROR;
1002 char *tmp = aprintf("statvfs:\n"
1003 "f_bsize: %llu\n" "f_frsize: %llu\n"
1004 "f_blocks: %llu\n" "f_bfree: %llu\n"
1005 "f_bavail: %llu\n" "f_files: %llu\n"
1006 "f_ffree: %llu\n" "f_favail: %llu\n"
1007 "f_fsid: %llu\n" "f_flag: %llu\n"
1008 "f_namemax: %llu\n",
1009 statvfs->f_bsize, statvfs->f_frsize,
1010 statvfs->f_blocks, statvfs->f_bfree,
1011 statvfs->f_bavail, statvfs->f_files,
1012 statvfs->f_ffree, statvfs->f_favail,
1013 statvfs->f_fsid, statvfs->f_flag,
1014 statvfs->f_namemax);
1015 sftp_statvfs_free(statvfs);
1018 result = CURLE_OUT_OF_MEMORY;
1019 state(conn, SSH_SFTP_CLOSE);
1020 sshc->nextstate = SSH_NO_STATE;
1024 result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp));
1027 state(conn, SSH_SFTP_CLOSE);
1028 sshc->nextstate = SSH_NO_STATE;
1029 sshc->actualcode = result;
1032 state(conn, SSH_SFTP_NEXT_QUOTE);
1036 case SSH_SFTP_GETINFO:
1037 if(data->set.get_filetime) {
1038 state(conn, SSH_SFTP_FILETIME);
1041 state(conn, SSH_SFTP_TRANS_INIT);
1045 case SSH_SFTP_FILETIME:
1047 sftp_attributes attrs;
1049 attrs = sftp_stat(sshc->sftp_session, protop->path);
1051 data->info.filetime = attrs->mtime;
1052 sftp_attributes_free(attrs);
1055 state(conn, SSH_SFTP_TRANS_INIT);
1059 case SSH_SFTP_TRANS_INIT:
1060 if(data->set.upload)
1061 state(conn, SSH_SFTP_UPLOAD_INIT);
1063 if(protop->path[strlen(protop->path)-1] == '/')
1064 state(conn, SSH_SFTP_READDIR_INIT);
1066 state(conn, SSH_SFTP_DOWNLOAD_INIT);
1070 case SSH_SFTP_UPLOAD_INIT:
1074 if(data->state.resume_from != 0) {
1075 sftp_attributes attrs;
1077 if(data->state.resume_from < 0) {
1078 attrs = sftp_stat(sshc->sftp_session, protop->path);
1080 curl_off_t size = attrs->size;
1082 failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
1083 MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME);
1085 data->state.resume_from = attrs->size;
1087 sftp_attributes_free(attrs);
1090 data->state.resume_from = 0;
1095 if(data->set.ftp_append)
1096 /* Try to open for append, but create if nonexisting */
1097 flags = O_WRONLY|O_CREAT|O_APPEND;
1098 else if(data->state.resume_from > 0)
1099 /* If we have restart position then open for append */
1100 flags = O_WRONLY|O_APPEND;
1102 /* Clear file before writing (normal behaviour) */
1103 flags = O_WRONLY|O_APPEND|O_CREAT|O_TRUNC;
1106 sftp_close(sshc->sftp_file);
1108 sftp_open(sshc->sftp_session, protop->path,
1109 flags, (mode_t)data->set.new_file_perms);
1110 if(!sshc->sftp_file) {
1111 err = sftp_get_error(sshc->sftp_session);
1113 if(((err == SSH_FX_NO_SUCH_FILE || err == SSH_FX_FAILURE ||
1114 err == SSH_FX_NO_SUCH_PATH)) &&
1115 (data->set.ftp_create_missing_dirs &&
1116 (strlen(protop->path) > 1))) {
1117 /* try to create the path remotely */
1119 sshc->secondCreateDirs = 1;
1120 state(conn, SSH_SFTP_CREATE_DIRS_INIT);
1124 MOVE_TO_SFTP_CLOSE_STATE();
1128 /* If we have a restart point then we need to seek to the correct
1130 if(data->state.resume_from > 0) {
1131 /* Let's read off the proper amount of bytes from the input. */
1132 if(conn->seek_func) {
1133 Curl_set_in_callback(data, true);
1134 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1136 Curl_set_in_callback(data, false);
1139 if(seekerr != CURL_SEEKFUNC_OK) {
1140 curl_off_t passed = 0;
1142 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1143 failf(data, "Could not seek stream");
1144 return CURLE_FTP_COULDNT_USE_REST;
1146 /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
1148 size_t readthisamountnow =
1149 (data->state.resume_from - passed > data->set.buffer_size) ?
1150 (size_t)data->set.buffer_size :
1151 curlx_sotouz(data->state.resume_from - passed);
1153 size_t actuallyread =
1154 data->state.fread_func(data->state.buffer, 1,
1155 readthisamountnow, data->state.in);
1157 passed += actuallyread;
1158 if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1159 /* this checks for greater-than only to make sure that the
1160 CURL_READFUNC_ABORT return code still aborts */
1161 failf(data, "Failed to read data");
1162 MOVE_TO_ERROR_STATE(CURLE_FTP_COULDNT_USE_REST);
1164 } while(passed < data->state.resume_from);
1167 /* now, decrease the size of the read */
1168 if(data->state.infilesize > 0) {
1169 data->state.infilesize -= data->state.resume_from;
1170 data->req.size = data->state.infilesize;
1171 Curl_pgrsSetUploadSize(data, data->state.infilesize);
1174 rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
1176 MOVE_TO_SFTP_CLOSE_STATE();
1179 if(data->state.infilesize > 0) {
1180 data->req.size = data->state.infilesize;
1181 Curl_pgrsSetUploadSize(data, data->state.infilesize);
1184 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
1186 /* not set by Curl_setup_transfer to preserve keepon bits */
1187 conn->sockfd = conn->writesockfd;
1189 /* store this original bitmask setup to use later on if we can't
1190 figure out a "real" bitmask */
1191 sshc->orig_waitfor = data->req.keepon;
1193 /* we want to use the _sending_ function even when the socket turns
1194 out readable as the underlying libssh sftp send function will deal
1195 with both accordingly */
1196 conn->cselect_bits = CURL_CSELECT_OUT;
1198 /* since we don't really wait for anything at this point, we want the
1199 state machine to move on as soon as possible so we set a very short
1201 Curl_expire(data, 0, EXPIRE_RUN_NOW);
1203 state(conn, SSH_STOP);
1207 case SSH_SFTP_CREATE_DIRS_INIT:
1208 if(strlen(protop->path) > 1) {
1209 sshc->slash_pos = protop->path + 1; /* ignore the leading '/' */
1210 state(conn, SSH_SFTP_CREATE_DIRS);
1213 state(conn, SSH_SFTP_UPLOAD_INIT);
1217 case SSH_SFTP_CREATE_DIRS:
1218 sshc->slash_pos = strchr(sshc->slash_pos, '/');
1219 if(sshc->slash_pos) {
1220 *sshc->slash_pos = 0;
1222 infof(data, "Creating directory '%s'\n", protop->path);
1223 state(conn, SSH_SFTP_CREATE_DIRS_MKDIR);
1226 state(conn, SSH_SFTP_UPLOAD_INIT);
1229 case SSH_SFTP_CREATE_DIRS_MKDIR:
1230 /* 'mode' - parameter is preliminary - default to 0644 */
1231 rc = sftp_mkdir(sshc->sftp_session, protop->path,
1232 (mode_t)data->set.new_directory_perms);
1233 *sshc->slash_pos = '/';
1237 * Abort if failure wasn't that the dir already exists or the
1238 * permission was denied (creation might succeed further down the
1239 * path) - retry on unspecific FAILURE also
1241 err = sftp_get_error(sshc->sftp_session);
1242 if((err != SSH_FX_FILE_ALREADY_EXISTS) &&
1243 (err != SSH_FX_FAILURE) &&
1244 (err != SSH_FX_PERMISSION_DENIED)) {
1245 MOVE_TO_SFTP_CLOSE_STATE();
1247 rc = 0; /* clear rc and continue */
1249 state(conn, SSH_SFTP_CREATE_DIRS);
1252 case SSH_SFTP_READDIR_INIT:
1253 Curl_pgrsSetDownloadSize(data, -1);
1254 if(data->set.opt_no_body) {
1255 state(conn, SSH_STOP);
1260 * This is a directory that we are trying to get, so produce a directory
1263 sshc->sftp_dir = sftp_opendir(sshc->sftp_session,
1265 if(!sshc->sftp_dir) {
1266 failf(data, "Could not open directory for reading: %s",
1267 ssh_get_error(sshc->ssh_session));
1268 MOVE_TO_SFTP_CLOSE_STATE();
1270 state(conn, SSH_SFTP_READDIR);
1273 case SSH_SFTP_READDIR:
1275 if(sshc->readdir_attrs)
1276 sftp_attributes_free(sshc->readdir_attrs);
1278 sshc->readdir_attrs = sftp_readdir(sshc->sftp_session, sshc->sftp_dir);
1279 if(sshc->readdir_attrs) {
1280 sshc->readdir_filename = sshc->readdir_attrs->name;
1281 sshc->readdir_longentry = sshc->readdir_attrs->longname;
1282 sshc->readdir_len = (int)strlen(sshc->readdir_filename);
1284 if(data->set.ftp_list_only) {
1287 tmpLine = aprintf("%s\n", sshc->readdir_filename);
1288 if(tmpLine == NULL) {
1289 state(conn, SSH_SFTP_CLOSE);
1290 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1293 result = Curl_client_write(conn, CLIENTWRITE_BODY,
1294 tmpLine, sshc->readdir_len + 1);
1298 state(conn, SSH_STOP);
1301 /* since this counts what we send to the client, we include the
1302 newline in this counter */
1303 data->req.bytecount += sshc->readdir_len + 1;
1305 /* output debug output if that is requested */
1306 if(data->set.verbose) {
1307 Curl_debug(data, CURLINFO_DATA_OUT,
1308 (char *)sshc->readdir_filename,
1309 sshc->readdir_len, conn);
1313 sshc->readdir_currLen = (int)strlen(sshc->readdir_longentry);
1314 sshc->readdir_totalLen = 80 + sshc->readdir_currLen;
1315 sshc->readdir_line = calloc(sshc->readdir_totalLen, 1);
1316 if(!sshc->readdir_line) {
1317 state(conn, SSH_SFTP_CLOSE);
1318 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1322 memcpy(sshc->readdir_line, sshc->readdir_longentry,
1323 sshc->readdir_currLen);
1324 if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
1325 ((sshc->readdir_attrs->permissions & S_IFMT) ==
1327 sshc->readdir_linkPath = malloc(PATH_MAX + 1);
1328 if(sshc->readdir_linkPath == NULL) {
1329 state(conn, SSH_SFTP_CLOSE);
1330 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1334 snprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", protop->path,
1335 sshc->readdir_filename);
1337 state(conn, SSH_SFTP_READDIR_LINK);
1340 state(conn, SSH_SFTP_READDIR_BOTTOM);
1344 else if(sshc->readdir_attrs == NULL && sftp_dir_eof(sshc->sftp_dir)) {
1345 state(conn, SSH_SFTP_READDIR_DONE);
1349 failf(data, "Could not open remote file for reading: %s",
1350 ssh_get_error(sshc->ssh_session));
1351 MOVE_TO_SFTP_CLOSE_STATE();
1356 case SSH_SFTP_READDIR_LINK:
1357 if(sshc->readdir_link_attrs)
1358 sftp_attributes_free(sshc->readdir_link_attrs);
1360 sshc->readdir_link_attrs = sftp_lstat(sshc->sftp_session,
1361 sshc->readdir_linkPath);
1362 if(sshc->readdir_link_attrs == 0) {
1363 failf(data, "Could not read symlink for reading: %s",
1364 ssh_get_error(sshc->ssh_session));
1365 MOVE_TO_SFTP_CLOSE_STATE();
1368 if(sshc->readdir_link_attrs->name == NULL) {
1369 sshc->readdir_tmp = sftp_readlink(sshc->sftp_session,
1370 sshc->readdir_linkPath);
1371 if(sshc->readdir_filename == NULL)
1372 sshc->readdir_len = 0;
1374 sshc->readdir_len = (int)strlen(sshc->readdir_tmp);
1375 sshc->readdir_longentry = NULL;
1376 sshc->readdir_filename = sshc->readdir_tmp;
1379 sshc->readdir_len = (int)strlen(sshc->readdir_link_attrs->name);
1380 sshc->readdir_filename = sshc->readdir_link_attrs->name;
1381 sshc->readdir_longentry = sshc->readdir_link_attrs->longname;
1384 Curl_safefree(sshc->readdir_linkPath);
1386 /* get room for the filename and extra output */
1387 sshc->readdir_totalLen += 4 + sshc->readdir_len;
1388 new_readdir_line = Curl_saferealloc(sshc->readdir_line,
1389 sshc->readdir_totalLen);
1390 if(!new_readdir_line) {
1391 sshc->readdir_line = NULL;
1392 state(conn, SSH_SFTP_CLOSE);
1393 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1396 sshc->readdir_line = new_readdir_line;
1398 sshc->readdir_currLen += snprintf(sshc->readdir_line +
1399 sshc->readdir_currLen,
1400 sshc->readdir_totalLen -
1401 sshc->readdir_currLen,
1403 sshc->readdir_filename);
1405 sftp_attributes_free(sshc->readdir_link_attrs);
1406 sshc->readdir_link_attrs = NULL;
1407 sshc->readdir_filename = NULL;
1408 sshc->readdir_longentry = NULL;
1410 state(conn, SSH_SFTP_READDIR_BOTTOM);
1412 case SSH_SFTP_READDIR_BOTTOM:
1413 sshc->readdir_currLen += snprintf(sshc->readdir_line +
1414 sshc->readdir_currLen,
1415 sshc->readdir_totalLen -
1416 sshc->readdir_currLen, "\n");
1417 result = Curl_client_write(conn, CLIENTWRITE_BODY,
1419 sshc->readdir_currLen);
1423 /* output debug output if that is requested */
1424 if(data->set.verbose) {
1425 Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_line,
1426 sshc->readdir_currLen, conn);
1428 data->req.bytecount += sshc->readdir_currLen;
1430 Curl_safefree(sshc->readdir_line);
1431 ssh_string_free_char(sshc->readdir_tmp);
1432 sshc->readdir_tmp = NULL;
1435 state(conn, SSH_STOP);
1438 state(conn, SSH_SFTP_READDIR);
1441 case SSH_SFTP_READDIR_DONE:
1442 sftp_closedir(sshc->sftp_dir);
1443 sshc->sftp_dir = NULL;
1445 /* no data to transfer */
1446 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1447 state(conn, SSH_STOP);
1450 case SSH_SFTP_DOWNLOAD_INIT:
1452 * Work on getting the specified file
1455 sftp_close(sshc->sftp_file);
1457 sshc->sftp_file = sftp_open(sshc->sftp_session, protop->path,
1458 O_RDONLY, (mode_t)data->set.new_file_perms);
1459 if(!sshc->sftp_file) {
1460 failf(data, "Could not open remote file for reading: %s",
1461 ssh_get_error(sshc->ssh_session));
1463 MOVE_TO_SFTP_CLOSE_STATE();
1466 state(conn, SSH_SFTP_DOWNLOAD_STAT);
1469 case SSH_SFTP_DOWNLOAD_STAT:
1471 sftp_attributes attrs;
1474 attrs = sftp_fstat(sshc->sftp_file);
1476 !(attrs->flags & SSH_FILEXFER_ATTR_SIZE) ||
1477 (attrs->size == 0)) {
1479 * sftp_fstat didn't return an error, so maybe the server
1480 * just doesn't support stat()
1481 * OR the server doesn't return a file size with a stat()
1484 data->req.size = -1;
1485 data->req.maxdownload = -1;
1486 Curl_pgrsSetDownloadSize(data, -1);
1492 sftp_attributes_free(attrs);
1495 failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
1496 return CURLE_BAD_DOWNLOAD_RESUME;
1498 if(conn->data->state.use_range) {
1499 curl_off_t from, to;
1505 from_t = curlx_strtoofft(conn->data->state.range, &ptr, 0, &from);
1506 if(from_t == CURL_OFFT_FLOW) {
1507 return CURLE_RANGE_ERROR;
1509 while(*ptr && (ISSPACE(*ptr) || (*ptr == '-')))
1511 to_t = curlx_strtoofft(ptr, &ptr2, 0, &to);
1512 if(to_t == CURL_OFFT_FLOW) {
1513 return CURLE_RANGE_ERROR;
1515 if((to_t == CURL_OFFT_INVAL) /* no "to" value given */
1520 /* from is relative to end of file */
1525 failf(data, "Offset (%"
1526 CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
1527 CURL_FORMAT_CURL_OFF_T ")", from, size);
1528 return CURLE_BAD_DOWNLOAD_RESUME;
1535 size = to - from + 1;
1538 rc = sftp_seek64(sshc->sftp_file, from);
1540 MOVE_TO_SFTP_CLOSE_STATE();
1543 data->req.size = size;
1544 data->req.maxdownload = size;
1545 Curl_pgrsSetDownloadSize(data, size);
1548 /* We can resume if we can seek to the resume position */
1549 if(data->state.resume_from) {
1550 if(data->state.resume_from < 0) {
1551 /* We're supposed to download the last abs(from) bytes */
1552 if((curl_off_t)size < -data->state.resume_from) {
1553 failf(data, "Offset (%"
1554 CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
1555 CURL_FORMAT_CURL_OFF_T ")",
1556 data->state.resume_from, size);
1557 return CURLE_BAD_DOWNLOAD_RESUME;
1559 /* download from where? */
1560 data->state.resume_from += size;
1563 if((curl_off_t)size < data->state.resume_from) {
1564 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
1565 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
1566 data->state.resume_from, size);
1567 return CURLE_BAD_DOWNLOAD_RESUME;
1570 /* Does a completed file need to be seeked and started or closed ? */
1571 /* Now store the number of bytes we are expected to download */
1572 data->req.size = size - data->state.resume_from;
1573 data->req.maxdownload = size - data->state.resume_from;
1574 Curl_pgrsSetDownloadSize(data,
1575 size - data->state.resume_from);
1577 rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
1579 MOVE_TO_SFTP_CLOSE_STATE();
1584 /* Setup the actual download */
1585 if(data->req.size == 0) {
1586 /* no data to transfer */
1587 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1588 infof(data, "File already completely downloaded\n");
1589 state(conn, SSH_STOP);
1592 Curl_setup_transfer(conn, FIRSTSOCKET, data->req.size,
1593 FALSE, NULL, -1, NULL);
1595 /* not set by Curl_setup_transfer to preserve keepon bits */
1596 conn->writesockfd = conn->sockfd;
1598 /* we want to use the _receiving_ function even when the socket turns
1599 out writableable as the underlying libssh recv function will deal
1600 with both accordingly */
1601 conn->cselect_bits = CURL_CSELECT_IN;
1604 /* this should never occur; the close state should be entered
1605 at the time the error occurs */
1606 state(conn, SSH_SFTP_CLOSE);
1607 sshc->actualcode = result;
1610 sshc->sftp_recv_state = 0;
1611 state(conn, SSH_STOP);
1615 case SSH_SFTP_CLOSE:
1616 if(sshc->sftp_file) {
1617 sftp_close(sshc->sftp_file);
1618 sshc->sftp_file = NULL;
1620 Curl_safefree(protop->path);
1622 DEBUGF(infof(data, "SFTP DONE done\n"));
1624 /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT
1625 After nextstate is executed, the control should come back to
1626 SSH_SFTP_CLOSE to pass the correct result back */
1627 if(sshc->nextstate != SSH_NO_STATE &&
1628 sshc->nextstate != SSH_SFTP_CLOSE) {
1629 state(conn, sshc->nextstate);
1630 sshc->nextstate = SSH_SFTP_CLOSE;
1633 state(conn, SSH_STOP);
1634 result = sshc->actualcode;
1638 case SSH_SFTP_SHUTDOWN:
1639 /* during times we get here due to a broken transfer and then the
1640 sftp_handle might not have been taken down so make sure that is done
1641 before we proceed */
1643 if(sshc->sftp_file) {
1644 sftp_close(sshc->sftp_file);
1645 sshc->sftp_file = NULL;
1648 if(sshc->sftp_session) {
1649 sftp_free(sshc->sftp_session);
1650 sshc->sftp_session = NULL;
1653 Curl_safefree(sshc->homedir);
1654 conn->data->state.most_recent_ftp_entrypath = NULL;
1656 state(conn, SSH_SESSION_DISCONNECT);
1660 case SSH_SCP_TRANS_INIT:
1661 result = Curl_getworkingpath(conn, sshc->homedir, &protop->path);
1663 sshc->actualcode = result;
1664 state(conn, SSH_STOP);
1668 /* Functions from the SCP subsystem cannot handle/return SSH_AGAIN */
1669 ssh_set_blocking(sshc->ssh_session, 1);
1671 if(data->set.upload) {
1672 if(data->state.infilesize < 0) {
1673 failf(data, "SCP requires a known file size for upload");
1674 sshc->actualcode = CURLE_UPLOAD_FAILED;
1675 MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1679 ssh_scp_new(sshc->ssh_session, SSH_SCP_WRITE, protop->path);
1680 state(conn, SSH_SCP_UPLOAD_INIT);
1684 ssh_scp_new(sshc->ssh_session, SSH_SCP_READ, protop->path);
1685 state(conn, SSH_SCP_DOWNLOAD_INIT);
1688 if(!sshc->scp_session) {
1689 err_msg = ssh_get_error(sshc->ssh_session);
1690 failf(conn->data, "%s", err_msg);
1691 MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1696 case SSH_SCP_UPLOAD_INIT:
1698 rc = ssh_scp_init(sshc->scp_session);
1700 err_msg = ssh_get_error(sshc->ssh_session);
1701 failf(conn->data, "%s", err_msg);
1702 MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1705 rc = ssh_scp_push_file(sshc->scp_session, protop->path,
1706 data->state.infilesize,
1707 (int)data->set.new_file_perms);
1709 err_msg = ssh_get_error(sshc->ssh_session);
1710 failf(conn->data, "%s", err_msg);
1711 MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
1715 Curl_setup_transfer(conn, -1, data->req.size, FALSE, NULL,
1718 /* not set by Curl_setup_transfer to preserve keepon bits */
1719 conn->sockfd = conn->writesockfd;
1721 /* store this original bitmask setup to use later on if we can't
1722 figure out a "real" bitmask */
1723 sshc->orig_waitfor = data->req.keepon;
1725 /* we want to use the _sending_ function even when the socket turns
1726 out readable as the underlying libssh scp send function will deal
1727 with both accordingly */
1728 conn->cselect_bits = CURL_CSELECT_OUT;
1730 state(conn, SSH_STOP);
1734 case SSH_SCP_DOWNLOAD_INIT:
1736 rc = ssh_scp_init(sshc->scp_session);
1738 err_msg = ssh_get_error(sshc->ssh_session);
1739 failf(conn->data, "%s", err_msg);
1740 MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
1742 state(conn, SSH_SCP_DOWNLOAD);
1745 case SSH_SCP_DOWNLOAD:{
1746 curl_off_t bytecount;
1748 rc = ssh_scp_pull_request(sshc->scp_session);
1749 if(rc != SSH_SCP_REQUEST_NEWFILE) {
1750 err_msg = ssh_get_error(sshc->ssh_session);
1751 failf(conn->data, "%s", err_msg);
1752 MOVE_TO_ERROR_STATE(CURLE_REMOTE_FILE_NOT_FOUND);
1757 bytecount = ssh_scp_request_get_size(sshc->scp_session);
1758 data->req.maxdownload = (curl_off_t) bytecount;
1759 Curl_setup_transfer(conn, FIRSTSOCKET, bytecount, FALSE, NULL, -1,
1762 /* not set by Curl_setup_transfer to preserve keepon bits */
1763 conn->writesockfd = conn->sockfd;
1765 /* we want to use the _receiving_ function even when the socket turns
1766 out writableable as the underlying libssh recv function will deal
1767 with both accordingly */
1768 conn->cselect_bits = CURL_CSELECT_IN;
1770 state(conn, SSH_STOP);
1774 if(data->set.upload)
1775 state(conn, SSH_SCP_SEND_EOF);
1777 state(conn, SSH_SCP_CHANNEL_FREE);
1780 case SSH_SCP_SEND_EOF:
1781 if(sshc->scp_session) {
1782 rc = ssh_scp_close(sshc->scp_session);
1783 if(rc == SSH_AGAIN) {
1784 /* Currently the ssh_scp_close handles waiting for EOF in
1790 infof(data, "Failed to close libssh scp channel: %s\n",
1791 ssh_get_error(sshc->ssh_session));
1795 state(conn, SSH_SCP_CHANNEL_FREE);
1798 case SSH_SCP_CHANNEL_FREE:
1799 if(sshc->scp_session) {
1800 ssh_scp_free(sshc->scp_session);
1801 sshc->scp_session = NULL;
1803 DEBUGF(infof(data, "SCP DONE phase complete\n"));
1805 ssh_set_blocking(sshc->ssh_session, 0);
1807 state(conn, SSH_SESSION_DISCONNECT);
1810 case SSH_SESSION_DISCONNECT:
1811 /* during weird times when we've been prematurely aborted, the channel
1812 is still alive when we reach this state and we MUST kill the channel
1814 if(sshc->scp_session) {
1815 ssh_scp_free(sshc->scp_session);
1816 sshc->scp_session = NULL;
1819 ssh_disconnect(sshc->ssh_session);
1821 Curl_safefree(sshc->homedir);
1822 conn->data->state.most_recent_ftp_entrypath = NULL;
1824 state(conn, SSH_SESSION_FREE);
1826 case SSH_SESSION_FREE:
1827 if(sshc->ssh_session) {
1828 ssh_free(sshc->ssh_session);
1829 sshc->ssh_session = NULL;
1832 /* worst-case scenario cleanup */
1834 DEBUGASSERT(sshc->ssh_session == NULL);
1835 DEBUGASSERT(sshc->scp_session == NULL);
1837 if(sshc->readdir_tmp) {
1838 ssh_string_free_char(sshc->readdir_tmp);
1839 sshc->readdir_tmp = NULL;
1842 if(sshc->quote_attrs)
1843 sftp_attributes_free(sshc->quote_attrs);
1845 if(sshc->readdir_attrs)
1846 sftp_attributes_free(sshc->readdir_attrs);
1848 if(sshc->readdir_link_attrs)
1849 sftp_attributes_free(sshc->readdir_link_attrs);
1852 ssh_key_free(sshc->privkey);
1854 ssh_key_free(sshc->pubkey);
1856 Curl_safefree(sshc->rsa_pub);
1857 Curl_safefree(sshc->rsa);
1859 Curl_safefree(sshc->quote_path1);
1860 Curl_safefree(sshc->quote_path2);
1862 Curl_safefree(sshc->homedir);
1864 Curl_safefree(sshc->readdir_line);
1865 Curl_safefree(sshc->readdir_linkPath);
1867 /* the code we are about to return */
1868 result = sshc->actualcode;
1870 memset(sshc, 0, sizeof(struct ssh_conn));
1872 connclose(conn, "SSH session free");
1873 sshc->state = SSH_SESSION_FREE; /* current */
1874 sshc->nextstate = SSH_NO_STATE;
1875 state(conn, SSH_STOP);
1879 /* fallthrough, just stop! */
1881 /* internal error */
1882 sshc->nextstate = SSH_NO_STATE;
1883 state(conn, SSH_STOP);
1887 } while(!rc && (sshc->state != SSH_STOP));
1890 if(rc == SSH_AGAIN) {
1891 /* we would block, we need to wait for the socket to be ready (in the
1892 right direction too)! */
1900 /* called by the multi interface to figure out what socket(s) to wait for and
1901 for what actions in the DO_DONE, PERFORM and WAITPERFORM states */
1902 static int myssh_perform_getsock(const struct connectdata *conn,
1903 curl_socket_t *sock, /* points to numsocks
1904 number of sockets */
1907 int bitmap = GETSOCK_BLANK;
1910 sock[0] = conn->sock[FIRSTSOCKET];
1912 if(conn->waitfor & KEEP_RECV)
1913 bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
1915 if(conn->waitfor & KEEP_SEND)
1916 bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
1921 /* Generic function called by the multi interface to figure out what socket(s)
1922 to wait for and for what actions during the DOING and PROTOCONNECT states*/
1923 static int myssh_getsock(struct connectdata *conn,
1924 curl_socket_t *sock, /* points to numsocks
1925 number of sockets */
1928 /* if we know the direction we can use the generic *_getsock() function even
1929 for the protocol_connect and doing states */
1930 return myssh_perform_getsock(conn, sock, numsocks);
1933 static void myssh_block2waitfor(struct connectdata *conn, bool block)
1935 struct ssh_conn *sshc = &conn->proto.sshc;
1938 /* If it didn't block, or nothing was returned by ssh_get_poll_flags
1939 * have the original set */
1940 conn->waitfor = sshc->orig_waitfor;
1943 dir = ssh_get_poll_flags(sshc->ssh_session);
1944 if(dir & SSH_READ_PENDING) {
1945 /* translate the libssh define bits into our own bit defines */
1946 conn->waitfor = KEEP_RECV;
1948 else if(dir & SSH_WRITE_PENDING) {
1949 conn->waitfor = KEEP_SEND;
1954 /* called repeatedly until done from multi.c */
1955 static CURLcode myssh_multi_statemach(struct connectdata *conn,
1958 struct ssh_conn *sshc = &conn->proto.sshc;
1959 CURLcode result = CURLE_OK;
1960 bool block; /* we store the status and use that to provide a ssh_getsock()
1963 result = myssh_statemach_act(conn, &block);
1964 *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
1965 myssh_block2waitfor(conn, block);
1970 static CURLcode myssh_block_statemach(struct connectdata *conn,
1973 struct ssh_conn *sshc = &conn->proto.sshc;
1974 CURLcode result = CURLE_OK;
1975 struct Curl_easy *data = conn->data;
1977 while((sshc->state != SSH_STOP) && !result) {
1979 timediff_t left = 1000;
1980 struct curltime now = Curl_now();
1982 result = myssh_statemach_act(conn, &block);
1987 if(Curl_pgrsUpdate(conn))
1988 return CURLE_ABORTED_BY_CALLBACK;
1990 result = Curl_speedcheck(data, now);
1994 left = Curl_timeleft(data, NULL, FALSE);
1996 failf(data, "Operation timed out");
1997 return CURLE_OPERATION_TIMEDOUT;
2001 if(!result && block) {
2002 curl_socket_t sock = conn->sock[FIRSTSOCKET];
2003 curl_socket_t fd_read = CURL_SOCKET_BAD;
2005 /* wait for the socket to become ready */
2006 (void) Curl_socket_check(fd_read, CURL_SOCKET_BAD,
2007 CURL_SOCKET_BAD, left > 1000 ? 1000 : left);
2016 * SSH setup connection
2018 static CURLcode myssh_setup_connection(struct connectdata *conn)
2020 struct SSHPROTO *ssh;
2022 conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO));
2024 return CURLE_OUT_OF_MEMORY;
2029 static Curl_recv scp_recv, sftp_recv;
2030 static Curl_send scp_send, sftp_send;
2033 * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to
2034 * do protocol-specific actions at connect-time.
2036 static CURLcode myssh_connect(struct connectdata *conn, bool *done)
2038 struct ssh_conn *ssh;
2040 struct Curl_easy *data = conn->data;
2043 /* initialize per-handle data if not already */
2044 if(!data->req.protop)
2045 myssh_setup_connection(conn);
2047 /* We default to persistent connections. We set this already in this connect
2048 function to make the re-use checks properly be able to check this bit. */
2049 connkeep(conn, "SSH default");
2051 if(conn->handler->protocol & CURLPROTO_SCP) {
2052 conn->recv[FIRSTSOCKET] = scp_recv;
2053 conn->send[FIRSTSOCKET] = scp_send;
2056 conn->recv[FIRSTSOCKET] = sftp_recv;
2057 conn->send[FIRSTSOCKET] = sftp_send;
2060 ssh = &conn->proto.sshc;
2062 ssh->ssh_session = ssh_new();
2063 if(ssh->ssh_session == NULL) {
2064 failf(data, "Failure initialising ssh session");
2065 return CURLE_FAILED_INIT;
2069 infof(data, "User: %s\n", conn->user);
2070 ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user);
2073 if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
2074 infof(data, "Known hosts: %s\n", data->set.str[STRING_SSH_KNOWNHOSTS]);
2075 ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS,
2076 data->set.str[STRING_SSH_KNOWNHOSTS]);
2079 ssh_options_set(ssh->ssh_session, SSH_OPTIONS_HOST, conn->host.name);
2080 if(conn->remote_port)
2081 ssh_options_set(ssh->ssh_session, SSH_OPTIONS_PORT,
2082 &conn->remote_port);
2084 if(data->set.ssh_compression) {
2085 ssh_options_set(ssh->ssh_session, SSH_OPTIONS_COMPRESSION,
2086 "zlib,zlib@openssh.com,none");
2089 ssh->privkey = NULL;
2092 if(data->set.str[STRING_SSH_PUBLIC_KEY]) {
2093 rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY],
2096 failf(data, "Could not load public key file");
2101 /* we do not verify here, we do it at the state machine,
2102 * after connection */
2104 state(conn, SSH_INIT);
2106 result = myssh_multi_statemach(conn, done);
2111 /* called from multi.c while DOing */
2112 static CURLcode scp_doing(struct connectdata *conn, bool *dophase_done)
2116 result = myssh_multi_statemach(conn, dophase_done);
2119 DEBUGF(infof(conn->data, "DO phase is complete\n"));
2125 ***********************************************************************
2129 * This is the actual DO function for SCP. Get a file according to
2130 * the options previously setup.
2134 CURLcode scp_perform(struct connectdata *conn,
2135 bool *connected, bool *dophase_done)
2137 CURLcode result = CURLE_OK;
2139 DEBUGF(infof(conn->data, "DO phase starts\n"));
2141 *dophase_done = FALSE; /* not done yet */
2143 /* start the first command in the DO phase */
2144 state(conn, SSH_SCP_TRANS_INIT);
2146 result = myssh_multi_statemach(conn, dophase_done);
2148 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
2151 DEBUGF(infof(conn->data, "DO phase is complete\n"));
2157 static CURLcode myssh_do_it(struct connectdata *conn, bool *done)
2161 struct Curl_easy *data = conn->data;
2162 struct ssh_conn *sshc = &conn->proto.sshc;
2164 *done = FALSE; /* default to false */
2166 data->req.size = -1; /* make sure this is unknown at this point */
2168 sshc->actualcode = CURLE_OK; /* reset error code */
2169 sshc->secondCreateDirs = 0; /* reset the create dir attempt state
2172 Curl_pgrsSetUploadCounter(data, 0);
2173 Curl_pgrsSetDownloadCounter(data, 0);
2174 Curl_pgrsSetUploadSize(data, -1);
2175 Curl_pgrsSetDownloadSize(data, -1);
2177 if(conn->handler->protocol & CURLPROTO_SCP)
2178 result = scp_perform(conn, &connected, done);
2180 result = sftp_perform(conn, &connected, done);
2185 /* BLOCKING, but the function is using the state machine so the only reason
2186 this is still blocking is that the multi interface code has no support for
2187 disconnecting operations that takes a while */
2188 static CURLcode scp_disconnect(struct connectdata *conn,
2189 bool dead_connection)
2191 CURLcode result = CURLE_OK;
2192 struct ssh_conn *ssh = &conn->proto.sshc;
2193 (void) dead_connection;
2195 if(ssh->ssh_session) {
2196 /* only if there's a session still around to use! */
2198 state(conn, SSH_SESSION_DISCONNECT);
2200 result = myssh_block_statemach(conn, TRUE);
2206 /* generic done function for both SCP and SFTP called from their specific
2208 static CURLcode myssh_done(struct connectdata *conn, CURLcode status)
2210 CURLcode result = CURLE_OK;
2211 struct SSHPROTO *protop = conn->data->req.protop;
2214 /* run the state-machine
2216 TODO: when the multi interface is used, this _really_ should be using
2217 the ssh_multi_statemach function but we have no general support for
2218 non-blocking DONE operations!
2220 result = myssh_block_statemach(conn, FALSE);
2226 Curl_safefree(protop->path);
2227 if(Curl_pgrsDone(conn))
2228 return CURLE_ABORTED_BY_CALLBACK;
2230 conn->data->req.keepon = 0; /* clear all bits */
2235 static CURLcode scp_done(struct connectdata *conn, CURLcode status,
2238 (void) premature; /* not used */
2241 state(conn, SSH_SCP_DONE);
2243 return myssh_done(conn, status);
2247 static ssize_t scp_send(struct connectdata *conn, int sockindex,
2248 const void *mem, size_t len, CURLcode *err)
2251 (void) sockindex; /* we only support SCP on the fixed known primary socket */
2254 rc = ssh_scp_write(conn->proto.sshc.scp_session, mem, len);
2257 /* The following code is misleading, mostly added as wishful thinking
2258 * that libssh at some point will implement non-blocking ssh_scp_write/read.
2259 * Currently rc can only be number of bytes read or SSH_ERROR. */
2260 myssh_block2waitfor(conn, (rc == SSH_AGAIN) ? TRUE : FALSE);
2262 if(rc == SSH_AGAIN) {
2276 static ssize_t scp_recv(struct connectdata *conn, int sockindex,
2277 char *mem, size_t len, CURLcode *err)
2281 (void) sockindex; /* we only support SCP on the fixed known primary socket */
2283 /* libssh returns int */
2284 nread = ssh_scp_read(conn->proto.sshc.scp_session, mem, len);
2287 /* The following code is misleading, mostly added as wishful thinking
2288 * that libssh at some point will implement non-blocking ssh_scp_write/read.
2289 * Currently rc can only be SSH_OK or SSH_ERROR. */
2291 myssh_block2waitfor(conn, (nread == SSH_AGAIN) ? TRUE : FALSE);
2292 if(nread == SSH_AGAIN) {
2302 * =============== SFTP ===============
2306 ***********************************************************************
2310 * This is the actual DO function for SFTP. Get a file/directory according to
2311 * the options previously setup.
2315 CURLcode sftp_perform(struct connectdata *conn,
2319 CURLcode result = CURLE_OK;
2321 DEBUGF(infof(conn->data, "DO phase starts\n"));
2323 *dophase_done = FALSE; /* not done yet */
2325 /* start the first command in the DO phase */
2326 state(conn, SSH_SFTP_QUOTE_INIT);
2328 /* run the state-machine */
2329 result = myssh_multi_statemach(conn, dophase_done);
2331 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
2334 DEBUGF(infof(conn->data, "DO phase is complete\n"));
2340 /* called from multi.c while DOing */
2341 static CURLcode sftp_doing(struct connectdata *conn,
2344 CURLcode result = myssh_multi_statemach(conn, dophase_done);
2346 DEBUGF(infof(conn->data, "DO phase is complete\n"));
2351 /* BLOCKING, but the function is using the state machine so the only reason
2352 this is still blocking is that the multi interface code has no support for
2353 disconnecting operations that takes a while */
2354 static CURLcode sftp_disconnect(struct connectdata *conn, bool dead_connection)
2356 CURLcode result = CURLE_OK;
2357 (void) dead_connection;
2359 DEBUGF(infof(conn->data, "SSH DISCONNECT starts now\n"));
2361 if(conn->proto.sshc.ssh_session) {
2362 /* only if there's a session still around to use! */
2363 state(conn, SSH_SFTP_SHUTDOWN);
2364 result = myssh_block_statemach(conn, TRUE);
2367 DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n"));
2373 static CURLcode sftp_done(struct connectdata *conn, CURLcode status,
2376 struct ssh_conn *sshc = &conn->proto.sshc;
2379 /* Post quote commands are executed after the SFTP_CLOSE state to avoid
2380 errors that could happen due to open file handles during POSTQUOTE
2382 if(!status && !premature && conn->data->set.postquote) {
2383 sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
2384 state(conn, SSH_SFTP_CLOSE);
2387 state(conn, SSH_SFTP_CLOSE);
2389 return myssh_done(conn, status);
2392 /* return number of sent bytes */
2393 static ssize_t sftp_send(struct connectdata *conn, int sockindex,
2394 const void *mem, size_t len, CURLcode *err)
2399 nwrite = sftp_write(conn->proto.sshc.sftp_file, mem, len);
2401 myssh_block2waitfor(conn, FALSE);
2403 #if 0 /* not returned by libssh on write */
2404 if(nwrite == SSH_AGAIN) {
2419 * Return number of received (decrypted) bytes
2422 static ssize_t sftp_recv(struct connectdata *conn, int sockindex,
2423 char *mem, size_t len, CURLcode *err)
2428 if(len >= (size_t)1<<32)
2429 len = (size_t)(1<<31)-1;
2431 switch(conn->proto.sshc.sftp_recv_state) {
2433 conn->proto.sshc.sftp_file_index =
2434 sftp_async_read_begin(conn->proto.sshc.sftp_file,
2436 if(conn->proto.sshc.sftp_file_index < 0) {
2437 *err = CURLE_RECV_ERROR;
2443 conn->proto.sshc.sftp_recv_state = 1;
2445 nread = sftp_async_read(conn->proto.sshc.sftp_file,
2447 conn->proto.sshc.sftp_file_index);
2449 myssh_block2waitfor(conn, (nread == SSH_AGAIN)?TRUE:FALSE);
2451 if(nread == SSH_AGAIN) {
2455 else if(nread < 0) {
2456 *err = CURLE_RECV_ERROR;
2460 conn->proto.sshc.sftp_recv_state = 0;
2464 /* we never reach here */
2469 static void sftp_quote(struct connectdata *conn)
2472 struct Curl_easy *data = conn->data;
2473 struct SSHPROTO *protop = data->req.protop;
2474 struct ssh_conn *sshc = &conn->proto.sshc;
2478 * Support some of the "FTP" commands
2480 char *cmd = sshc->quote_item->data;
2481 sshc->acceptfail = FALSE;
2483 /* if a command starts with an asterisk, which a legal SFTP command never
2484 can, the command will be allowed to fail without it causing any
2485 aborts or cancels etc. It will cause libcurl to act as if the command
2486 is successful, whatever the server reponds. */
2490 sshc->acceptfail = TRUE;
2493 if(strcasecompare("pwd", cmd)) {
2494 /* output debug output if that is requested */
2495 char *tmp = aprintf("257 \"%s\" is current directory.\n",
2498 sshc->actualcode = CURLE_OUT_OF_MEMORY;
2499 state(conn, SSH_SFTP_CLOSE);
2500 sshc->nextstate = SSH_NO_STATE;
2503 if(data->set.verbose) {
2504 Curl_debug(data, CURLINFO_HEADER_OUT, (char *) "PWD\n", 4, conn);
2505 Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp), conn);
2507 /* this sends an FTP-like "header" to the header callback so that the
2508 current directory can be read very similar to how it is read when
2509 using ordinary FTP. */
2510 result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp));
2513 state(conn, SSH_SFTP_CLOSE);
2514 sshc->nextstate = SSH_NO_STATE;
2515 sshc->actualcode = result;
2518 state(conn, SSH_SFTP_NEXT_QUOTE);
2523 * the arguments following the command must be separated from the
2524 * command with a space so we can check for it unconditionally
2526 cp = strchr(cmd, ' ');
2528 failf(data, "Syntax error in SFTP command. Supply parameter(s)!");
2529 state(conn, SSH_SFTP_CLOSE);
2530 sshc->nextstate = SSH_NO_STATE;
2531 sshc->actualcode = CURLE_QUOTE_ERROR;
2536 * also, every command takes at least one argument so we get that
2537 * first argument right now
2539 result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir);
2541 if(result == CURLE_OUT_OF_MEMORY)
2542 failf(data, "Out of memory");
2544 failf(data, "Syntax error: Bad first parameter");
2545 state(conn, SSH_SFTP_CLOSE);
2546 sshc->nextstate = SSH_NO_STATE;
2547 sshc->actualcode = result;
2552 * SFTP is a binary protocol, so we don't send text commands
2553 * to the server. Instead, we scan for commands used by
2554 * OpenSSH's sftp program and call the appropriate libssh
2557 if(strncasecompare(cmd, "chgrp ", 6) ||
2558 strncasecompare(cmd, "chmod ", 6) ||
2559 strncasecompare(cmd, "chown ", 6)) {
2560 /* attribute change */
2562 /* sshc->quote_path1 contains the mode to set */
2563 /* get the destination */
2564 result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2566 if(result == CURLE_OUT_OF_MEMORY)
2567 failf(data, "Out of memory");
2569 failf(data, "Syntax error in chgrp/chmod/chown: "
2570 "Bad second parameter");
2571 Curl_safefree(sshc->quote_path1);
2572 state(conn, SSH_SFTP_CLOSE);
2573 sshc->nextstate = SSH_NO_STATE;
2574 sshc->actualcode = result;
2577 sshc->quote_attrs = NULL;
2578 state(conn, SSH_SFTP_QUOTE_STAT);
2581 if(strncasecompare(cmd, "ln ", 3) ||
2582 strncasecompare(cmd, "symlink ", 8)) {
2583 /* symbolic linking */
2584 /* sshc->quote_path1 is the source */
2585 /* get the destination */
2586 result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2588 if(result == CURLE_OUT_OF_MEMORY)
2589 failf(data, "Out of memory");
2591 failf(data, "Syntax error in ln/symlink: Bad second parameter");
2592 Curl_safefree(sshc->quote_path1);
2593 state(conn, SSH_SFTP_CLOSE);
2594 sshc->nextstate = SSH_NO_STATE;
2595 sshc->actualcode = result;
2598 state(conn, SSH_SFTP_QUOTE_SYMLINK);
2601 else if(strncasecompare(cmd, "mkdir ", 6)) {
2603 state(conn, SSH_SFTP_QUOTE_MKDIR);
2606 else if(strncasecompare(cmd, "rename ", 7)) {
2608 /* first param is the source path */
2609 /* second param is the dest. path */
2610 result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
2612 if(result == CURLE_OUT_OF_MEMORY)
2613 failf(data, "Out of memory");
2615 failf(data, "Syntax error in rename: Bad second parameter");
2616 Curl_safefree(sshc->quote_path1);
2617 state(conn, SSH_SFTP_CLOSE);
2618 sshc->nextstate = SSH_NO_STATE;
2619 sshc->actualcode = result;
2622 state(conn, SSH_SFTP_QUOTE_RENAME);
2625 else if(strncasecompare(cmd, "rmdir ", 6)) {
2627 state(conn, SSH_SFTP_QUOTE_RMDIR);
2630 else if(strncasecompare(cmd, "rm ", 3)) {
2631 state(conn, SSH_SFTP_QUOTE_UNLINK);
2634 #ifdef HAS_STATVFS_SUPPORT
2635 else if(strncasecompare(cmd, "statvfs ", 8)) {
2636 state(conn, SSH_SFTP_QUOTE_STATVFS);
2641 failf(data, "Unknown SFTP command");
2642 Curl_safefree(sshc->quote_path1);
2643 Curl_safefree(sshc->quote_path2);
2644 state(conn, SSH_SFTP_CLOSE);
2645 sshc->nextstate = SSH_NO_STATE;
2646 sshc->actualcode = CURLE_QUOTE_ERROR;
2649 static void sftp_quote_stat(struct connectdata *conn)
2651 struct Curl_easy *data = conn->data;
2652 struct ssh_conn *sshc = &conn->proto.sshc;
2653 char *cmd = sshc->quote_item->data;
2654 sshc->acceptfail = FALSE;
2656 /* if a command starts with an asterisk, which a legal SFTP command never
2657 can, the command will be allowed to fail without it causing any
2658 aborts or cancels etc. It will cause libcurl to act as if the command
2659 is successful, whatever the server reponds. */
2663 sshc->acceptfail = TRUE;
2666 /* We read the file attributes, store them in sshc->quote_attrs
2667 * and modify them accordingly to command. Then we switch to
2668 * QUOTE_SETSTAT state to write new ones.
2671 if(sshc->quote_attrs)
2672 sftp_attributes_free(sshc->quote_attrs);
2673 sshc->quote_attrs = sftp_stat(sshc->sftp_session, sshc->quote_path2);
2674 if(sshc->quote_attrs == NULL) {
2675 Curl_safefree(sshc->quote_path1);
2676 Curl_safefree(sshc->quote_path2);
2677 failf(data, "Attempt to get SFTP stats failed: %d",
2678 sftp_get_error(sshc->sftp_session));
2679 state(conn, SSH_SFTP_CLOSE);
2680 sshc->nextstate = SSH_NO_STATE;
2681 sshc->actualcode = CURLE_QUOTE_ERROR;
2685 /* Now set the new attributes... */
2686 if(strncasecompare(cmd, "chgrp", 5)) {
2687 sshc->quote_attrs->gid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2688 if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
2689 !sshc->acceptfail) {
2690 Curl_safefree(sshc->quote_path1);
2691 Curl_safefree(sshc->quote_path2);
2692 failf(data, "Syntax error: chgrp gid not a number");
2693 state(conn, SSH_SFTP_CLOSE);
2694 sshc->nextstate = SSH_NO_STATE;
2695 sshc->actualcode = CURLE_QUOTE_ERROR;
2698 sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2700 else if(strncasecompare(cmd, "chmod", 5)) {
2702 perms = (mode_t)strtoul(sshc->quote_path1, NULL, 8);
2703 /* permissions are octal */
2704 if(perms == 0 && !ISDIGIT(sshc->quote_path1[0])) {
2705 Curl_safefree(sshc->quote_path1);
2706 Curl_safefree(sshc->quote_path2);
2707 failf(data, "Syntax error: chmod permissions not a number");
2708 state(conn, SSH_SFTP_CLOSE);
2709 sshc->nextstate = SSH_NO_STATE;
2710 sshc->actualcode = CURLE_QUOTE_ERROR;
2713 sshc->quote_attrs->permissions = perms;
2714 sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_PERMISSIONS;
2716 else if(strncasecompare(cmd, "chown", 5)) {
2717 sshc->quote_attrs->uid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
2718 if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
2719 !sshc->acceptfail) {
2720 Curl_safefree(sshc->quote_path1);
2721 Curl_safefree(sshc->quote_path2);
2722 failf(data, "Syntax error: chown uid not a number");
2723 state(conn, SSH_SFTP_CLOSE);
2724 sshc->nextstate = SSH_NO_STATE;
2725 sshc->actualcode = CURLE_QUOTE_ERROR;
2728 sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
2731 /* Now send the completed structure... */
2732 state(conn, SSH_SFTP_QUOTE_SETSTAT);
2737 #endif /* USE_LIBSSH */