VirtualBox

source: vbox/trunk/src/libs/curl-7.87.0/lib/vssh/libssh.c@ 98326

最後變更 在這個檔案從98326是 98326,由 vboxsync 提交於 2 年 前

curl-7.87.0: Applied and adjusted our curl changes to 7.83.1. bugref:10356

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette