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