VirtualBox

source: vbox/trunk/src/libs/curl-7.83.1/lib/vssh/libssh.c@ 97138

最後變更 在這個檔案從97138是 95312,由 vboxsync 提交於 3 年 前

libs/{curl,libxml2}: OSE export fixes, bugref:8515

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

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