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