VirtualBox

source: vbox/trunk/src/libs/curl-8.0.1/lib/vssh/libssh2.c@ 99797

Last change on this file since 99797 was 99344, checked in by vboxsync, 2 years ago

curl-8.0.1: Applied and adjusted our curl changes to 7.87.0 bugref:10417

  • Property svn:eol-style set to native
File size: 119.9 KB
Line 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24
25/* #define CURL_LIBSSH2_DEBUG */
26
27#include "curl_setup.h"
28
29#ifdef USE_LIBSSH2
30
31#include <limits.h>
32
33#include <libssh2.h>
34#include <libssh2_sftp.h>
35
36#ifdef HAVE_FCNTL_H
37#include <fcntl.h>
38#endif
39
40#ifdef HAVE_NETINET_IN_H
41#include <netinet/in.h>
42#endif
43#ifdef HAVE_ARPA_INET_H
44#include <arpa/inet.h>
45#endif
46#ifdef HAVE_UTSNAME_H
47#include <sys/utsname.h>
48#endif
49#ifdef HAVE_NETDB_H
50#include <netdb.h>
51#endif
52#ifdef __VMS
53#include <in.h>
54#include <inet.h>
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 "cfilters.h"
73#include "connect.h"
74#include "inet_ntop.h"
75#include "parsedate.h" /* for the week day and month names */
76#include "sockaddr.h" /* required for Curl_sockaddr_storage */
77#include "strtoofft.h"
78#include "multiif.h"
79#include "select.h"
80#include "warnless.h"
81#include "curl_path.h"
82
83#include <curl_base64.h> /* for base64 encoding/decoding */
84#include <curl_sha256.h>
85
86
87/* The last 3 #include files should be in this order */
88#include "curl_printf.h"
89#include "curl_memory.h"
90#include "memdebug.h"
91
92#if LIBSSH2_VERSION_NUM >= 0x010206
93/* libssh2_sftp_statvfs and friends were added in 1.2.6 */
94#define HAS_STATVFS_SUPPORT 1
95#endif
96
97#define sftp_libssh2_realpath(s,p,t,m) \
98 libssh2_sftp_symlink_ex((s), (p), curlx_uztoui(strlen(p)), \
99 (t), (m), LIBSSH2_SFTP_REALPATH)
100
101/* Local functions: */
102static const char *sftp_libssh2_strerror(unsigned long err);
103#ifdef CURL_LIBSSH2_DEBUG
104static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc);
105static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc);
106static LIBSSH2_FREE_FUNC(my_libssh2_free);
107#endif
108static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data);
109static CURLcode ssh_connect(struct Curl_easy *data, bool *done);
110static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done);
111static CURLcode ssh_do(struct Curl_easy *data, bool *done);
112static CURLcode scp_done(struct Curl_easy *data, CURLcode c, bool premature);
113static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done);
114static CURLcode scp_disconnect(struct Curl_easy *data,
115 struct connectdata *conn, bool dead_connection);
116static CURLcode sftp_done(struct Curl_easy *data, CURLcode, bool premature);
117static CURLcode sftp_doing(struct Curl_easy *data, bool *dophase_done);
118static CURLcode sftp_disconnect(struct Curl_easy *data,
119 struct connectdata *conn, bool dead);
120static CURLcode sftp_perform(struct Curl_easy *data, bool *connected,
121 bool *dophase_done);
122static int ssh_getsock(struct Curl_easy *data, struct connectdata *conn,
123 curl_socket_t *sock);
124static CURLcode ssh_setup_connection(struct Curl_easy *data,
125 struct connectdata *conn);
126static void ssh_attach(struct Curl_easy *data, struct connectdata *conn);
127
128/*
129 * SCP protocol handler.
130 */
131
132const struct Curl_handler Curl_handler_scp = {
133 "SCP", /* scheme */
134 ssh_setup_connection, /* setup_connection */
135 ssh_do, /* do_it */
136 scp_done, /* done */
137 ZERO_NULL, /* do_more */
138 ssh_connect, /* connect_it */
139 ssh_multi_statemach, /* connecting */
140 scp_doing, /* doing */
141 ssh_getsock, /* proto_getsock */
142 ssh_getsock, /* doing_getsock */
143 ZERO_NULL, /* domore_getsock */
144 ssh_getsock, /* perform_getsock */
145 scp_disconnect, /* disconnect */
146 ZERO_NULL, /* readwrite */
147 ZERO_NULL, /* connection_check */
148 ssh_attach, /* attach */
149 PORT_SSH, /* defport */
150 CURLPROTO_SCP, /* protocol */
151 CURLPROTO_SCP, /* family */
152 PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
153 | PROTOPT_NOURLQUERY /* flags */
154};
155
156
157/*
158 * SFTP protocol handler.
159 */
160
161const struct Curl_handler Curl_handler_sftp = {
162 "SFTP", /* scheme */
163 ssh_setup_connection, /* setup_connection */
164 ssh_do, /* do_it */
165 sftp_done, /* done */
166 ZERO_NULL, /* do_more */
167 ssh_connect, /* connect_it */
168 ssh_multi_statemach, /* connecting */
169 sftp_doing, /* doing */
170 ssh_getsock, /* proto_getsock */
171 ssh_getsock, /* doing_getsock */
172 ZERO_NULL, /* domore_getsock */
173 ssh_getsock, /* perform_getsock */
174 sftp_disconnect, /* disconnect */
175 ZERO_NULL, /* readwrite */
176 ZERO_NULL, /* connection_check */
177 ssh_attach, /* attach */
178 PORT_SSH, /* defport */
179 CURLPROTO_SFTP, /* protocol */
180 CURLPROTO_SFTP, /* family */
181 PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
182 | PROTOPT_NOURLQUERY /* flags */
183};
184
185static void
186kbd_callback(const char *name, int name_len, const char *instruction,
187 int instruction_len, int num_prompts,
188 const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
189 LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
190 void **abstract)
191{
192 struct Curl_easy *data = (struct Curl_easy *)*abstract;
193
194#ifdef CURL_LIBSSH2_DEBUG
195 fprintf(stderr, "name=%s\n", name);
196 fprintf(stderr, "name_len=%d\n", name_len);
197 fprintf(stderr, "instruction=%s\n", instruction);
198 fprintf(stderr, "instruction_len=%d\n", instruction_len);
199 fprintf(stderr, "num_prompts=%d\n", num_prompts);
200#else
201 (void)name;
202 (void)name_len;
203 (void)instruction;
204 (void)instruction_len;
205#endif /* CURL_LIBSSH2_DEBUG */
206 if(num_prompts == 1) {
207 struct connectdata *conn = data->conn;
208 responses[0].text = strdup(conn->passwd);
209 responses[0].length = curlx_uztoui(strlen(conn->passwd));
210 }
211 (void)prompts;
212} /* kbd_callback */
213
214static CURLcode sftp_libssh2_error_to_CURLE(unsigned long err)
215{
216 switch(err) {
217 case LIBSSH2_FX_OK:
218 return CURLE_OK;
219
220 case LIBSSH2_FX_NO_SUCH_FILE:
221 case LIBSSH2_FX_NO_SUCH_PATH:
222 return CURLE_REMOTE_FILE_NOT_FOUND;
223
224 case LIBSSH2_FX_PERMISSION_DENIED:
225 case LIBSSH2_FX_WRITE_PROTECT:
226 case LIBSSH2_FX_LOCK_CONFlICT:
227 return CURLE_REMOTE_ACCESS_DENIED;
228
229 case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM:
230 case LIBSSH2_FX_QUOTA_EXCEEDED:
231 return CURLE_REMOTE_DISK_FULL;
232
233 case LIBSSH2_FX_FILE_ALREADY_EXISTS:
234 return CURLE_REMOTE_FILE_EXISTS;
235
236 case LIBSSH2_FX_DIR_NOT_EMPTY:
237 return CURLE_QUOTE_ERROR;
238
239 default:
240 break;
241 }
242
243 return CURLE_SSH;
244}
245
246static CURLcode libssh2_session_error_to_CURLE(int err)
247{
248 switch(err) {
249 /* Ordered by order of appearance in libssh2.h */
250 case LIBSSH2_ERROR_NONE:
251 return CURLE_OK;
252
253 /* This is the error returned by libssh2_scp_recv2
254 * on unknown file */
255 case LIBSSH2_ERROR_SCP_PROTOCOL:
256 return CURLE_REMOTE_FILE_NOT_FOUND;
257
258 case LIBSSH2_ERROR_SOCKET_NONE:
259 return CURLE_COULDNT_CONNECT;
260
261 case LIBSSH2_ERROR_ALLOC:
262 return CURLE_OUT_OF_MEMORY;
263
264 case LIBSSH2_ERROR_SOCKET_SEND:
265 return CURLE_SEND_ERROR;
266
267 case LIBSSH2_ERROR_HOSTKEY_INIT:
268 case LIBSSH2_ERROR_HOSTKEY_SIGN:
269 case LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED:
270 case LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED:
271 return CURLE_PEER_FAILED_VERIFICATION;
272
273 case LIBSSH2_ERROR_PASSWORD_EXPIRED:
274 return CURLE_LOGIN_DENIED;
275
276 case LIBSSH2_ERROR_SOCKET_TIMEOUT:
277 case LIBSSH2_ERROR_TIMEOUT:
278 return CURLE_OPERATION_TIMEDOUT;
279
280 case LIBSSH2_ERROR_EAGAIN:
281 return CURLE_AGAIN;
282 }
283
284 return CURLE_SSH;
285}
286
287#ifdef CURL_LIBSSH2_DEBUG
288
289static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc)
290{
291 (void)abstract; /* arg not used */
292 return malloc(count);
293}
294
295static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc)
296{
297 (void)abstract; /* arg not used */
298 return realloc(ptr, count);
299}
300
301static LIBSSH2_FREE_FUNC(my_libssh2_free)
302{
303 (void)abstract; /* arg not used */
304 if(ptr) /* ssh2 agent sometimes call free with null ptr */
305 free(ptr);
306}
307
308#endif
309
310/*
311 * SSH State machine related code
312 */
313/* This is the ONLY way to change SSH state! */
314static void state(struct Curl_easy *data, sshstate nowstate)
315{
316 struct connectdata *conn = data->conn;
317 struct ssh_conn *sshc = &conn->proto.sshc;
318#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
319 /* for debug purposes */
320 static const char * const names[] = {
321 "SSH_STOP",
322 "SSH_INIT",
323 "SSH_S_STARTUP",
324 "SSH_HOSTKEY",
325 "SSH_AUTHLIST",
326 "SSH_AUTH_PKEY_INIT",
327 "SSH_AUTH_PKEY",
328 "SSH_AUTH_PASS_INIT",
329 "SSH_AUTH_PASS",
330 "SSH_AUTH_AGENT_INIT",
331 "SSH_AUTH_AGENT_LIST",
332 "SSH_AUTH_AGENT",
333 "SSH_AUTH_HOST_INIT",
334 "SSH_AUTH_HOST",
335 "SSH_AUTH_KEY_INIT",
336 "SSH_AUTH_KEY",
337 "SSH_AUTH_GSSAPI",
338 "SSH_AUTH_DONE",
339 "SSH_SFTP_INIT",
340 "SSH_SFTP_REALPATH",
341 "SSH_SFTP_QUOTE_INIT",
342 "SSH_SFTP_POSTQUOTE_INIT",
343 "SSH_SFTP_QUOTE",
344 "SSH_SFTP_NEXT_QUOTE",
345 "SSH_SFTP_QUOTE_STAT",
346 "SSH_SFTP_QUOTE_SETSTAT",
347 "SSH_SFTP_QUOTE_SYMLINK",
348 "SSH_SFTP_QUOTE_MKDIR",
349 "SSH_SFTP_QUOTE_RENAME",
350 "SSH_SFTP_QUOTE_RMDIR",
351 "SSH_SFTP_QUOTE_UNLINK",
352 "SSH_SFTP_QUOTE_STATVFS",
353 "SSH_SFTP_GETINFO",
354 "SSH_SFTP_FILETIME",
355 "SSH_SFTP_TRANS_INIT",
356 "SSH_SFTP_UPLOAD_INIT",
357 "SSH_SFTP_CREATE_DIRS_INIT",
358 "SSH_SFTP_CREATE_DIRS",
359 "SSH_SFTP_CREATE_DIRS_MKDIR",
360 "SSH_SFTP_READDIR_INIT",
361 "SSH_SFTP_READDIR",
362 "SSH_SFTP_READDIR_LINK",
363 "SSH_SFTP_READDIR_BOTTOM",
364 "SSH_SFTP_READDIR_DONE",
365 "SSH_SFTP_DOWNLOAD_INIT",
366 "SSH_SFTP_DOWNLOAD_STAT",
367 "SSH_SFTP_CLOSE",
368 "SSH_SFTP_SHUTDOWN",
369 "SSH_SCP_TRANS_INIT",
370 "SSH_SCP_UPLOAD_INIT",
371 "SSH_SCP_DOWNLOAD_INIT",
372 "SSH_SCP_DOWNLOAD",
373 "SSH_SCP_DONE",
374 "SSH_SCP_SEND_EOF",
375 "SSH_SCP_WAIT_EOF",
376 "SSH_SCP_WAIT_CLOSE",
377 "SSH_SCP_CHANNEL_FREE",
378 "SSH_SESSION_DISCONNECT",
379 "SSH_SESSION_FREE",
380 "QUIT"
381 };
382
383 /* a precaution to make sure the lists are in sync */
384 DEBUGASSERT(sizeof(names)/sizeof(names[0]) == SSH_LAST);
385
386 if(sshc->state != nowstate) {
387 infof(data, "SFTP %p state change from %s to %s",
388 (void *)sshc, names[sshc->state], names[nowstate]);
389 }
390#endif
391
392 sshc->state = nowstate;
393}
394
395
396#ifdef HAVE_LIBSSH2_KNOWNHOST_API
397static int sshkeycallback(struct Curl_easy *easy,
398 const struct curl_khkey *knownkey, /* known */
399 const struct curl_khkey *foundkey, /* found */
400 enum curl_khmatch match,
401 void *clientp)
402{
403 (void)easy;
404 (void)knownkey;
405 (void)foundkey;
406 (void)clientp;
407
408 /* we only allow perfect matches, and we reject everything else */
409 return (match != CURLKHMATCH_OK)?CURLKHSTAT_REJECT:CURLKHSTAT_FINE;
410}
411#endif
412
413/*
414 * Earlier libssh2 versions didn't have the ability to seek to 64bit positions
415 * with 32bit size_t.
416 */
417#ifdef HAVE_LIBSSH2_SFTP_SEEK64
418#define SFTP_SEEK(x,y) libssh2_sftp_seek64(x, (libssh2_uint64_t)y)
419#else
420#define SFTP_SEEK(x,y) libssh2_sftp_seek(x, (size_t)y)
421#endif
422
423/*
424 * Earlier libssh2 versions didn't do SCP properly beyond 32bit sizes on 32bit
425 * architectures so we check of the necessary function is present.
426 */
427#ifndef HAVE_LIBSSH2_SCP_SEND64
428#define SCP_SEND(a,b,c,d) libssh2_scp_send_ex(a, b, (int)(c), (size_t)d, 0, 0)
429#else
430#define SCP_SEND(a,b,c,d) libssh2_scp_send64(a, b, (int)(c), \
431 (libssh2_uint64_t)d, 0, 0)
432#endif
433
434/*
435 * libssh2 1.2.8 fixed the problem with 32bit ints used for sockets on win64.
436 */
437#ifdef HAVE_LIBSSH2_SESSION_HANDSHAKE
438#define session_startup(x,y) libssh2_session_handshake(x, y)
439#else
440#define session_startup(x,y) libssh2_session_startup(x, (int)y)
441#endif
442static int convert_ssh2_keytype(int sshkeytype)
443{
444 int keytype = CURLKHTYPE_UNKNOWN;
445 switch(sshkeytype) {
446 case LIBSSH2_HOSTKEY_TYPE_RSA:
447 keytype = CURLKHTYPE_RSA;
448 break;
449 case LIBSSH2_HOSTKEY_TYPE_DSS:
450 keytype = CURLKHTYPE_DSS;
451 break;
452#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256
453 case LIBSSH2_HOSTKEY_TYPE_ECDSA_256:
454 keytype = CURLKHTYPE_ECDSA;
455 break;
456#endif
457#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_384
458 case LIBSSH2_HOSTKEY_TYPE_ECDSA_384:
459 keytype = CURLKHTYPE_ECDSA;
460 break;
461#endif
462#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_521
463 case LIBSSH2_HOSTKEY_TYPE_ECDSA_521:
464 keytype = CURLKHTYPE_ECDSA;
465 break;
466#endif
467#ifdef LIBSSH2_HOSTKEY_TYPE_ED25519
468 case LIBSSH2_HOSTKEY_TYPE_ED25519:
469 keytype = CURLKHTYPE_ED25519;
470 break;
471#endif
472 }
473 return keytype;
474}
475
476static CURLcode ssh_knownhost(struct Curl_easy *data)
477{
478 int sshkeytype = 0;
479 size_t keylen = 0;
480 int rc = 0;
481 CURLcode result = CURLE_OK;
482
483#ifdef HAVE_LIBSSH2_KNOWNHOST_API
484 if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
485 /* we're asked to verify the host against a file */
486 struct connectdata *conn = data->conn;
487 struct ssh_conn *sshc = &conn->proto.sshc;
488 struct libssh2_knownhost *host = NULL;
489 const char *remotekey = libssh2_session_hostkey(sshc->ssh_session,
490 &keylen, &sshkeytype);
491 int keycheck = LIBSSH2_KNOWNHOST_CHECK_FAILURE;
492 int keybit = 0;
493
494 if(remotekey) {
495 /*
496 * A subject to figure out is what host name we need to pass in here.
497 * What host name does OpenSSH store in its file if an IDN name is
498 * used?
499 */
500 enum curl_khmatch keymatch;
501 curl_sshkeycallback func =
502 data->set.ssh_keyfunc ? data->set.ssh_keyfunc : sshkeycallback;
503 struct curl_khkey knownkey;
504 struct curl_khkey *knownkeyp = NULL;
505 struct curl_khkey foundkey;
506
507 switch(sshkeytype) {
508 case LIBSSH2_HOSTKEY_TYPE_RSA:
509 keybit = LIBSSH2_KNOWNHOST_KEY_SSHRSA;
510 break;
511 case LIBSSH2_HOSTKEY_TYPE_DSS:
512 keybit = LIBSSH2_KNOWNHOST_KEY_SSHDSS;
513 break;
514#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256
515 case LIBSSH2_HOSTKEY_TYPE_ECDSA_256:
516 keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_256;
517 break;
518#endif
519#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_384
520 case LIBSSH2_HOSTKEY_TYPE_ECDSA_384:
521 keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_384;
522 break;
523#endif
524#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_521
525 case LIBSSH2_HOSTKEY_TYPE_ECDSA_521:
526 keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_521;
527 break;
528#endif
529#ifdef LIBSSH2_HOSTKEY_TYPE_ED25519
530 case LIBSSH2_HOSTKEY_TYPE_ED25519:
531 keybit = LIBSSH2_KNOWNHOST_KEY_ED25519;
532 break;
533#endif
534 default:
535 infof(data, "unsupported key type, can't check knownhosts");
536 keybit = 0;
537 break;
538 }
539 if(!keybit)
540 /* no check means failure! */
541 rc = CURLKHSTAT_REJECT;
542 else {
543#ifdef HAVE_LIBSSH2_KNOWNHOST_CHECKP
544 keycheck = libssh2_knownhost_checkp(sshc->kh,
545 conn->host.name,
546 (conn->remote_port != PORT_SSH)?
547 conn->remote_port:-1,
548 remotekey, keylen,
549 LIBSSH2_KNOWNHOST_TYPE_PLAIN|
550 LIBSSH2_KNOWNHOST_KEYENC_RAW|
551 keybit,
552 &host);
553#else
554 keycheck = libssh2_knownhost_check(sshc->kh,
555 conn->host.name,
556 remotekey, keylen,
557 LIBSSH2_KNOWNHOST_TYPE_PLAIN|
558 LIBSSH2_KNOWNHOST_KEYENC_RAW|
559 keybit,
560 &host);
561#endif
562
563 infof(data, "SSH host check: %d, key: %s", keycheck,
564 (keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)?
565 host->key:"<none>");
566
567 /* setup 'knownkey' */
568 if(keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH) {
569 knownkey.key = host->key;
570 knownkey.len = 0;
571 knownkey.keytype = convert_ssh2_keytype(sshkeytype);
572 knownkeyp = &knownkey;
573 }
574
575 /* setup 'foundkey' */
576 foundkey.key = remotekey;
577 foundkey.len = keylen;
578 foundkey.keytype = convert_ssh2_keytype(sshkeytype);
579
580 /*
581 * if any of the LIBSSH2_KNOWNHOST_CHECK_* defines and the
582 * curl_khmatch enum are ever modified, we need to introduce a
583 * translation table here!
584 */
585 keymatch = (enum curl_khmatch)keycheck;
586
587 /* Ask the callback how to behave */
588 Curl_set_in_callback(data, true);
589 rc = func(data, knownkeyp, /* from the knownhosts file */
590 &foundkey, /* from the remote host */
591 keymatch, data->set.ssh_keyfunc_userp);
592 Curl_set_in_callback(data, false);
593 }
594 }
595 else
596 /* no remotekey means failure! */
597 rc = CURLKHSTAT_REJECT;
598
599 switch(rc) {
600 default: /* unknown return codes will equal reject */
601 /* FALLTHROUGH */
602 case CURLKHSTAT_REJECT:
603 state(data, SSH_SESSION_FREE);
604 /* FALLTHROUGH */
605 case CURLKHSTAT_DEFER:
606 /* DEFER means bail out but keep the SSH_HOSTKEY state */
607 result = sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
608 break;
609 case CURLKHSTAT_FINE_REPLACE:
610 /* remove old host+key that doesn't match */
611 if(host)
612 libssh2_knownhost_del(sshc->kh, host);
613 /* FALLTHROUGH */
614 case CURLKHSTAT_FINE:
615 /* FALLTHROUGH */
616 case CURLKHSTAT_FINE_ADD_TO_FILE:
617 /* proceed */
618 if(keycheck != LIBSSH2_KNOWNHOST_CHECK_MATCH) {
619 /* the found host+key didn't match but has been told to be fine
620 anyway so we add it in memory */
621 int addrc = libssh2_knownhost_add(sshc->kh,
622 conn->host.name, NULL,
623 remotekey, keylen,
624 LIBSSH2_KNOWNHOST_TYPE_PLAIN|
625 LIBSSH2_KNOWNHOST_KEYENC_RAW|
626 keybit, NULL);
627 if(addrc)
628 infof(data, "WARNING: adding the known host %s failed",
629 conn->host.name);
630 else if(rc == CURLKHSTAT_FINE_ADD_TO_FILE ||
631 rc == CURLKHSTAT_FINE_REPLACE) {
632 /* now we write the entire in-memory list of known hosts to the
633 known_hosts file */
634 int wrc =
635 libssh2_knownhost_writefile(sshc->kh,
636 data->set.str[STRING_SSH_KNOWNHOSTS],
637 LIBSSH2_KNOWNHOST_FILE_OPENSSH);
638 if(wrc) {
639 infof(data, "WARNING: writing %s failed",
640 data->set.str[STRING_SSH_KNOWNHOSTS]);
641 }
642 }
643 }
644 break;
645 }
646 }
647#else /* HAVE_LIBSSH2_KNOWNHOST_API */
648 (void)data;
649#endif
650 return result;
651}
652
653static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
654{
655 struct connectdata *conn = data->conn;
656 struct ssh_conn *sshc = &conn->proto.sshc;
657 const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
658 const char *pubkey_sha256 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256];
659
660 infof(data, "SSH MD5 public key: %s",
661 pubkey_md5 != NULL ? pubkey_md5 : "NULL");
662 infof(data, "SSH SHA256 public key: %s",
663 pubkey_sha256 != NULL ? pubkey_sha256 : "NULL");
664
665 if(pubkey_sha256) {
666 const char *fingerprint = NULL;
667 char *fingerprint_b64 = NULL;
668 size_t fingerprint_b64_len;
669 size_t pub_pos = 0;
670 size_t b64_pos = 0;
671
672#ifdef LIBSSH2_HOSTKEY_HASH_SHA256
673 /* The fingerprint points to static storage (!), don't free() it. */
674 fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
675 LIBSSH2_HOSTKEY_HASH_SHA256);
676#else
677 const char *hostkey;
678 size_t len = 0;
679 unsigned char hash[32];
680
681 hostkey = libssh2_session_hostkey(sshc->ssh_session, &len, NULL);
682 if(hostkey) {
683 if(!Curl_sha256it(hash, (const unsigned char *) hostkey, len))
684 fingerprint = (char *) hash;
685 }
686#endif
687
688 if(!fingerprint) {
689 failf(data,
690 "Denied establishing ssh session: sha256 fingerprint "
691 "not available");
692 state(data, SSH_SESSION_FREE);
693 sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
694 return sshc->actualcode;
695 }
696
697 /* The length of fingerprint is 32 bytes for SHA256.
698 * See libssh2_hostkey_hash documentation. */
699 if(Curl_base64_encode(fingerprint, 32, &fingerprint_b64,
700 &fingerprint_b64_len) != CURLE_OK) {
701 state(data, SSH_SESSION_FREE);
702 sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
703 return sshc->actualcode;
704 }
705
706 if(!fingerprint_b64) {
707 failf(data, "sha256 fingerprint could not be encoded");
708 state(data, SSH_SESSION_FREE);
709 sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
710 return sshc->actualcode;
711 }
712
713 infof(data, "SSH SHA256 fingerprint: %s", fingerprint_b64);
714
715 /* Find the position of any = padding characters in the public key */
716 while((pubkey_sha256[pub_pos] != '=') && pubkey_sha256[pub_pos]) {
717 pub_pos++;
718 }
719
720 /* Find the position of any = padding characters in the base64 coded
721 * hostkey fingerprint */
722 while((fingerprint_b64[b64_pos] != '=') && fingerprint_b64[b64_pos]) {
723 b64_pos++;
724 }
725
726 /* Before we authenticate we check the hostkey's sha256 fingerprint
727 * against a known fingerprint, if available.
728 */
729 if((pub_pos != b64_pos) ||
730 strncmp(fingerprint_b64, pubkey_sha256, pub_pos)) {
731 free(fingerprint_b64);
732
733 failf(data,
734 "Denied establishing ssh session: mismatch sha256 fingerprint. "
735 "Remote %s is not equal to %s", fingerprint_b64, pubkey_sha256);
736 state(data, SSH_SESSION_FREE);
737 sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
738 return sshc->actualcode;
739 }
740
741 free(fingerprint_b64);
742
743 infof(data, "SHA256 checksum match");
744 }
745
746 if(pubkey_md5) {
747 char md5buffer[33];
748 const char *fingerprint = NULL;
749
750 fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
751 LIBSSH2_HOSTKEY_HASH_MD5);
752
753 if(fingerprint) {
754 /* The fingerprint points to static storage (!), don't free() it. */
755 int i;
756 for(i = 0; i < 16; i++) {
757 msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]);
758 }
759
760 infof(data, "SSH MD5 fingerprint: %s", md5buffer);
761 }
762
763 /* This does NOT verify the length of 'pubkey_md5' separately, which will
764 make the comparison below fail unless it is exactly 32 characters */
765 if(!fingerprint || !strcasecompare(md5buffer, pubkey_md5)) {
766 if(fingerprint) {
767 failf(data,
768 "Denied establishing ssh session: mismatch md5 fingerprint. "
769 "Remote %s is not equal to %s", md5buffer, pubkey_md5);
770 }
771 else {
772 failf(data,
773 "Denied establishing ssh session: md5 fingerprint "
774 "not available");
775 }
776 state(data, SSH_SESSION_FREE);
777 sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
778 return sshc->actualcode;
779 }
780 infof(data, "MD5 checksum match");
781 }
782
783 if(!pubkey_md5 && !pubkey_sha256) {
784 if(data->set.ssh_hostkeyfunc) {
785 size_t keylen = 0;
786 int sshkeytype = 0;
787 int rc = 0;
788 /* we handle the process to the callback */
789 const char *remotekey = libssh2_session_hostkey(sshc->ssh_session,
790 &keylen, &sshkeytype);
791 if(remotekey) {
792 int keytype = convert_ssh2_keytype(sshkeytype);
793 Curl_set_in_callback(data, true);
794 rc = data->set.ssh_hostkeyfunc(data->set.ssh_hostkeyfunc_userp,
795 keytype, remotekey, keylen);
796 Curl_set_in_callback(data, false);
797 if(rc!= CURLKHMATCH_OK) {
798 state(data, SSH_SESSION_FREE);
799 sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
800 return sshc->actualcode;
801 }
802 }
803 else {
804 state(data, SSH_SESSION_FREE);
805 sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
806 return sshc->actualcode;
807 }
808 return CURLE_OK;
809 }
810 else {
811 return ssh_knownhost(data);
812 }
813 }
814 else {
815 /* as we already matched, we skip the check for known hosts */
816 return CURLE_OK;
817 }
818}
819
820/*
821 * ssh_force_knownhost_key_type() will check the known hosts file and try to
822 * force a specific public key type from the server if an entry is found.
823 */
824static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data)
825{
826 CURLcode result = CURLE_OK;
827
828#ifdef HAVE_LIBSSH2_KNOWNHOST_API
829
830#ifdef LIBSSH2_KNOWNHOST_KEY_ED25519
831 static const char * const hostkey_method_ssh_ed25519
832 = "ssh-ed25519";
833#endif
834#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_521
835 static const char * const hostkey_method_ssh_ecdsa_521
836 = "ecdsa-sha2-nistp521";
837#endif
838#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_384
839 static const char * const hostkey_method_ssh_ecdsa_384
840 = "ecdsa-sha2-nistp384";
841#endif
842#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256
843 static const char * const hostkey_method_ssh_ecdsa_256
844 = "ecdsa-sha2-nistp256";
845#endif
846 static const char * const hostkey_method_ssh_rsa
847 = "ssh-rsa";
848 static const char * const hostkey_method_ssh_rsa_all
849 = "rsa-sha2-256,rsa-sha2-512,ssh-rsa";
850 static const char * const hostkey_method_ssh_dss
851 = "ssh-dss";
852
853 const char *hostkey_method = NULL;
854 struct connectdata *conn = data->conn;
855 struct ssh_conn *sshc = &conn->proto.sshc;
856 struct libssh2_knownhost* store = NULL;
857 const char *kh_name_end = NULL;
858 size_t kh_name_size = 0;
859 int port = 0;
860 bool found = false;
861
862 if(sshc->kh && !data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) {
863 /* lets try to find our host in the known hosts file */
864 while(!libssh2_knownhost_get(sshc->kh, &store, store)) {
865 /* For non-standard ports, the name will be enclosed in */
866 /* square brackets, followed by a colon and the port */
867 if(store) {
868 if(store->name) {
869 if(store->name[0] == '[') {
870 kh_name_end = strstr(store->name, "]:");
871 if(!kh_name_end) {
872 infof(data, "Invalid host pattern %s in %s",
873 store->name, data->set.str[STRING_SSH_KNOWNHOSTS]);
874 continue;
875 }
876 port = atoi(kh_name_end + 2);
877 if(kh_name_end && (port == conn->remote_port)) {
878 kh_name_size = strlen(store->name) - 1 - strlen(kh_name_end);
879 if(strncmp(store->name + 1,
880 conn->host.name, kh_name_size) == 0) {
881 found = true;
882 break;
883 }
884 }
885 }
886 else if(strcmp(store->name, conn->host.name) == 0) {
887 found = true;
888 break;
889 }
890 }
891 else {
892 found = true;
893 break;
894 }
895 }
896 }
897
898 if(found) {
899 infof(data, "Found host %s in %s",
900 conn->host.name, data->set.str[STRING_SSH_KNOWNHOSTS]);
901
902 switch(store->typemask & LIBSSH2_KNOWNHOST_KEY_MASK) {
903#ifdef LIBSSH2_KNOWNHOST_KEY_ED25519
904 case LIBSSH2_KNOWNHOST_KEY_ED25519:
905 hostkey_method = hostkey_method_ssh_ed25519;
906 break;
907#endif
908#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_521
909 case LIBSSH2_KNOWNHOST_KEY_ECDSA_521:
910 hostkey_method = hostkey_method_ssh_ecdsa_521;
911 break;
912#endif
913#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_384
914 case LIBSSH2_KNOWNHOST_KEY_ECDSA_384:
915 hostkey_method = hostkey_method_ssh_ecdsa_384;
916 break;
917#endif
918#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256
919 case LIBSSH2_KNOWNHOST_KEY_ECDSA_256:
920 hostkey_method = hostkey_method_ssh_ecdsa_256;
921 break;
922#endif
923 case LIBSSH2_KNOWNHOST_KEY_SSHRSA:
924#ifdef HAVE_LIBSSH2_VERSION
925 if(libssh2_version(0x010900))
926 /* since 1.9.0 libssh2_session_method_pref() works as expected */
927 hostkey_method = hostkey_method_ssh_rsa_all;
928 else
929#endif
930 /* old libssh2 which cannot correctly remove unsupported methods due
931 * to bug in src/kex.c or does not support the new methods anyways.
932 */
933 hostkey_method = hostkey_method_ssh_rsa;
934 break;
935 case LIBSSH2_KNOWNHOST_KEY_SSHDSS:
936 hostkey_method = hostkey_method_ssh_dss;
937 break;
938 case LIBSSH2_KNOWNHOST_KEY_RSA1:
939 failf(data, "Found host key type RSA1 which is not supported");
940 return CURLE_SSH;
941 default:
942 failf(data, "Unknown host key type: %i",
943 (store->typemask & LIBSSH2_KNOWNHOST_KEY_MASK));
944 return CURLE_SSH;
945 }
946
947 infof(data, "Set \"%s\" as SSH hostkey type", hostkey_method);
948 result = libssh2_session_error_to_CURLE(
949 libssh2_session_method_pref(
950 sshc->ssh_session, LIBSSH2_METHOD_HOSTKEY, hostkey_method));
951 }
952 else {
953 infof(data, "Did not find host %s in %s",
954 conn->host.name, data->set.str[STRING_SSH_KNOWNHOSTS]);
955 }
956 }
957
958#endif /* HAVE_LIBSSH2_KNOWNHOST_API */
959
960 return result;
961}
962
963/*
964 * ssh_statemach_act() runs the SSH state machine as far as it can without
965 * blocking and without reaching the end. The data the pointer 'block' points
966 * to will be set to TRUE if the libssh2 function returns LIBSSH2_ERROR_EAGAIN
967 * meaning it wants to be called again when the socket is ready
968 */
969
970static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
971{
972 CURLcode result = CURLE_OK;
973 struct connectdata *conn = data->conn;
974 struct SSHPROTO *sshp = data->req.p.ssh;
975 struct ssh_conn *sshc = &conn->proto.sshc;
976 curl_socket_t sock = conn->sock[FIRSTSOCKET];
977 int rc = LIBSSH2_ERROR_NONE;
978 int ssherr;
979 unsigned long sftperr;
980 int seekerr = CURL_SEEKFUNC_OK;
981 size_t readdir_len;
982 *block = 0; /* we're not blocking by default */
983
984 do {
985 switch(sshc->state) {
986 case SSH_INIT:
987 sshc->secondCreateDirs = 0;
988 sshc->nextstate = SSH_NO_STATE;
989 sshc->actualcode = CURLE_OK;
990
991 /* Set libssh2 to non-blocking, since everything internally is
992 non-blocking */
993 libssh2_session_set_blocking(sshc->ssh_session, 0);
994
995 result = ssh_force_knownhost_key_type(data);
996 if(result) {
997 state(data, SSH_SESSION_FREE);
998 sshc->actualcode = result;
999 break;
1000 }
1001
1002 state(data, SSH_S_STARTUP);
1003 /* FALLTHROUGH */
1004
1005 case SSH_S_STARTUP:
1006 rc = session_startup(sshc->ssh_session, sock);
1007 if(rc == LIBSSH2_ERROR_EAGAIN) {
1008 break;
1009 }
1010 if(rc) {
1011 char *err_msg = NULL;
1012 (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0);
1013 failf(data, "Failure establishing ssh session: %d, %s", rc, err_msg);
1014
1015 state(data, SSH_SESSION_FREE);
1016 sshc->actualcode = CURLE_FAILED_INIT;
1017 break;
1018 }
1019
1020 state(data, SSH_HOSTKEY);
1021
1022 /* FALLTHROUGH */
1023 case SSH_HOSTKEY:
1024 /*
1025 * Before we authenticate we should check the hostkey's fingerprint
1026 * against our known hosts. How that is handled (reading from file,
1027 * whatever) is up to us.
1028 */
1029 result = ssh_check_fingerprint(data);
1030 if(!result)
1031 state(data, SSH_AUTHLIST);
1032 /* ssh_check_fingerprint sets state appropriately on error */
1033 break;
1034
1035 case SSH_AUTHLIST:
1036 /*
1037 * Figure out authentication methods
1038 * NB: As soon as we have provided a username to an openssh server we
1039 * must never change it later. Thus, always specify the correct username
1040 * here, even though the libssh2 docs kind of indicate that it should be
1041 * possible to get a 'generic' list (not user-specific) of authentication
1042 * methods, presumably with a blank username. That won't work in my
1043 * experience.
1044 * So always specify it here.
1045 */
1046 sshc->authlist = libssh2_userauth_list(sshc->ssh_session,
1047 conn->user,
1048 curlx_uztoui(strlen(conn->user)));
1049
1050 if(!sshc->authlist) {
1051 if(libssh2_userauth_authenticated(sshc->ssh_session)) {
1052 sshc->authed = TRUE;
1053 infof(data, "SSH user accepted with no authentication");
1054 state(data, SSH_AUTH_DONE);
1055 break;
1056 }
1057 ssherr = libssh2_session_last_errno(sshc->ssh_session);
1058 if(ssherr == LIBSSH2_ERROR_EAGAIN)
1059 rc = LIBSSH2_ERROR_EAGAIN;
1060 else {
1061 state(data, SSH_SESSION_FREE);
1062 sshc->actualcode = libssh2_session_error_to_CURLE(ssherr);
1063 }
1064 break;
1065 }
1066 infof(data, "SSH authentication methods available: %s",
1067 sshc->authlist);
1068
1069 state(data, SSH_AUTH_PKEY_INIT);
1070 break;
1071
1072 case SSH_AUTH_PKEY_INIT:
1073 /*
1074 * Check the supported auth types in the order I feel is most secure
1075 * with the requested type of authentication
1076 */
1077 sshc->authed = FALSE;
1078
1079 if((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) &&
1080 (strstr(sshc->authlist, "publickey") != NULL)) {
1081 bool out_of_memory = FALSE;
1082
1083 sshc->rsa_pub = sshc->rsa = NULL;
1084
1085 if(data->set.str[STRING_SSH_PRIVATE_KEY])
1086 sshc->rsa = strdup(data->set.str[STRING_SSH_PRIVATE_KEY]);
1087 else {
1088 /* To ponder about: should really the lib be messing about with the
1089 HOME environment variable etc? */
1090 char *home = curl_getenv("HOME");
1091
1092 /* If no private key file is specified, try some common paths. */
1093 if(home) {
1094 /* Try ~/.ssh first. */
1095 sshc->rsa = aprintf("%s/.ssh/id_rsa", home);
1096 if(!sshc->rsa)
1097 out_of_memory = TRUE;
1098 else if(access(sshc->rsa, R_OK) != 0) {
1099 Curl_safefree(sshc->rsa);
1100 sshc->rsa = aprintf("%s/.ssh/id_dsa", home);
1101 if(!sshc->rsa)
1102 out_of_memory = TRUE;
1103 else if(access(sshc->rsa, R_OK) != 0) {
1104 Curl_safefree(sshc->rsa);
1105 }
1106 }
1107 free(home);
1108 }
1109 if(!out_of_memory && !sshc->rsa) {
1110 /* Nothing found; try the current dir. */
1111 sshc->rsa = strdup("id_rsa");
1112 if(sshc->rsa && access(sshc->rsa, R_OK) != 0) {
1113 Curl_safefree(sshc->rsa);
1114 sshc->rsa = strdup("id_dsa");
1115 if(sshc->rsa && access(sshc->rsa, R_OK) != 0) {
1116 Curl_safefree(sshc->rsa);
1117 /* Out of guesses. Set to the empty string to avoid
1118 * surprising info messages. */
1119 sshc->rsa = strdup("");
1120 }
1121 }
1122 }
1123 }
1124
1125 /*
1126 * Unless the user explicitly specifies a public key file, let
1127 * libssh2 extract the public key from the private key file.
1128 * This is done by simply passing sshc->rsa_pub = NULL.
1129 */
1130 if(data->set.str[STRING_SSH_PUBLIC_KEY]
1131 /* treat empty string the same way as NULL */
1132 && data->set.str[STRING_SSH_PUBLIC_KEY][0]) {
1133 sshc->rsa_pub = strdup(data->set.str[STRING_SSH_PUBLIC_KEY]);
1134 if(!sshc->rsa_pub)
1135 out_of_memory = TRUE;
1136 }
1137
1138 if(out_of_memory || !sshc->rsa) {
1139 Curl_safefree(sshc->rsa);
1140 Curl_safefree(sshc->rsa_pub);
1141 state(data, SSH_SESSION_FREE);
1142 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1143 break;
1144 }
1145
1146 sshc->passphrase = data->set.ssl.key_passwd;
1147 if(!sshc->passphrase)
1148 sshc->passphrase = "";
1149
1150 if(sshc->rsa_pub)
1151 infof(data, "Using SSH public key file '%s'", sshc->rsa_pub);
1152 infof(data, "Using SSH private key file '%s'", sshc->rsa);
1153
1154 state(data, SSH_AUTH_PKEY);
1155 }
1156 else {
1157 state(data, SSH_AUTH_PASS_INIT);
1158 }
1159 break;
1160
1161 case SSH_AUTH_PKEY:
1162 /* The function below checks if the files exists, no need to stat() here.
1163 */
1164 rc = libssh2_userauth_publickey_fromfile_ex(sshc->ssh_session,
1165 conn->user,
1166 curlx_uztoui(
1167 strlen(conn->user)),
1168 sshc->rsa_pub,
1169 sshc->rsa, sshc->passphrase);
1170 if(rc == LIBSSH2_ERROR_EAGAIN) {
1171 break;
1172 }
1173
1174 Curl_safefree(sshc->rsa_pub);
1175 Curl_safefree(sshc->rsa);
1176
1177 if(rc == 0) {
1178 sshc->authed = TRUE;
1179 infof(data, "Initialized SSH public key authentication");
1180 state(data, SSH_AUTH_DONE);
1181 }
1182 else {
1183 char *err_msg = NULL;
1184 (void)libssh2_session_last_error(sshc->ssh_session,
1185 &err_msg, NULL, 0);
1186 infof(data, "SSH public key authentication failed: %s", err_msg);
1187 state(data, SSH_AUTH_PASS_INIT);
1188 rc = 0; /* clear rc and continue */
1189 }
1190 break;
1191
1192 case SSH_AUTH_PASS_INIT:
1193 if((data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD) &&
1194 (strstr(sshc->authlist, "password") != NULL)) {
1195 state(data, SSH_AUTH_PASS);
1196 }
1197 else {
1198 state(data, SSH_AUTH_HOST_INIT);
1199 rc = 0; /* clear rc and continue */
1200 }
1201 break;
1202
1203 case SSH_AUTH_PASS:
1204 rc = libssh2_userauth_password_ex(sshc->ssh_session, conn->user,
1205 curlx_uztoui(strlen(conn->user)),
1206 conn->passwd,
1207 curlx_uztoui(strlen(conn->passwd)),
1208 NULL);
1209 if(rc == LIBSSH2_ERROR_EAGAIN) {
1210 break;
1211 }
1212 if(rc == 0) {
1213 sshc->authed = TRUE;
1214 infof(data, "Initialized password authentication");
1215 state(data, SSH_AUTH_DONE);
1216 }
1217 else {
1218 state(data, SSH_AUTH_HOST_INIT);
1219 rc = 0; /* clear rc and continue */
1220 }
1221 break;
1222
1223 case SSH_AUTH_HOST_INIT:
1224 if((data->set.ssh_auth_types & CURLSSH_AUTH_HOST) &&
1225 (strstr(sshc->authlist, "hostbased") != NULL)) {
1226 state(data, SSH_AUTH_HOST);
1227 }
1228 else {
1229 state(data, SSH_AUTH_AGENT_INIT);
1230 }
1231 break;
1232
1233 case SSH_AUTH_HOST:
1234 state(data, SSH_AUTH_AGENT_INIT);
1235 break;
1236
1237 case SSH_AUTH_AGENT_INIT:
1238#ifdef HAVE_LIBSSH2_AGENT_API
1239 if((data->set.ssh_auth_types & CURLSSH_AUTH_AGENT)
1240 && (strstr(sshc->authlist, "publickey") != NULL)) {
1241
1242 /* Connect to the ssh-agent */
1243 /* The agent could be shared by a curl thread i believe
1244 but nothing obvious as keys can be added/removed at any time */
1245 if(!sshc->ssh_agent) {
1246 sshc->ssh_agent = libssh2_agent_init(sshc->ssh_session);
1247 if(!sshc->ssh_agent) {
1248 infof(data, "Could not create agent object");
1249
1250 state(data, SSH_AUTH_KEY_INIT);
1251 break;
1252 }
1253 }
1254
1255 rc = libssh2_agent_connect(sshc->ssh_agent);
1256 if(rc == LIBSSH2_ERROR_EAGAIN)
1257 break;
1258 if(rc < 0) {
1259 infof(data, "Failure connecting to agent");
1260 state(data, SSH_AUTH_KEY_INIT);
1261 rc = 0; /* clear rc and continue */
1262 }
1263 else {
1264 state(data, SSH_AUTH_AGENT_LIST);
1265 }
1266 }
1267 else
1268#endif /* HAVE_LIBSSH2_AGENT_API */
1269 state(data, SSH_AUTH_KEY_INIT);
1270 break;
1271
1272 case SSH_AUTH_AGENT_LIST:
1273#ifdef HAVE_LIBSSH2_AGENT_API
1274 rc = libssh2_agent_list_identities(sshc->ssh_agent);
1275
1276 if(rc == LIBSSH2_ERROR_EAGAIN)
1277 break;
1278 if(rc < 0) {
1279 infof(data, "Failure requesting identities to agent");
1280 state(data, SSH_AUTH_KEY_INIT);
1281 rc = 0; /* clear rc and continue */
1282 }
1283 else {
1284 state(data, SSH_AUTH_AGENT);
1285 sshc->sshagent_prev_identity = NULL;
1286 }
1287#endif
1288 break;
1289
1290 case SSH_AUTH_AGENT:
1291#ifdef HAVE_LIBSSH2_AGENT_API
1292 /* as prev_identity evolves only after an identity user auth finished we
1293 can safely request it again as long as EAGAIN is returned here or by
1294 libssh2_agent_userauth */
1295 rc = libssh2_agent_get_identity(sshc->ssh_agent,
1296 &sshc->sshagent_identity,
1297 sshc->sshagent_prev_identity);
1298 if(rc == LIBSSH2_ERROR_EAGAIN)
1299 break;
1300
1301 if(rc == 0) {
1302 rc = libssh2_agent_userauth(sshc->ssh_agent, conn->user,
1303 sshc->sshagent_identity);
1304
1305 if(rc < 0) {
1306 if(rc != LIBSSH2_ERROR_EAGAIN) {
1307 /* tried and failed? go to next identity */
1308 sshc->sshagent_prev_identity = sshc->sshagent_identity;
1309 }
1310 break;
1311 }
1312 }
1313
1314 if(rc < 0)
1315 infof(data, "Failure requesting identities to agent");
1316 else if(rc == 1)
1317 infof(data, "No identity would match");
1318
1319 if(rc == LIBSSH2_ERROR_NONE) {
1320 sshc->authed = TRUE;
1321 infof(data, "Agent based authentication successful");
1322 state(data, SSH_AUTH_DONE);
1323 }
1324 else {
1325 state(data, SSH_AUTH_KEY_INIT);
1326 rc = 0; /* clear rc and continue */
1327 }
1328#endif
1329 break;
1330
1331 case SSH_AUTH_KEY_INIT:
1332 if((data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD)
1333 && (strstr(sshc->authlist, "keyboard-interactive") != NULL)) {
1334 state(data, SSH_AUTH_KEY);
1335 }
1336 else {
1337 state(data, SSH_AUTH_DONE);
1338 }
1339 break;
1340
1341 case SSH_AUTH_KEY:
1342 /* Authentication failed. Continue with keyboard-interactive now. */
1343 rc = libssh2_userauth_keyboard_interactive_ex(sshc->ssh_session,
1344 conn->user,
1345 curlx_uztoui(
1346 strlen(conn->user)),
1347 &kbd_callback);
1348 if(rc == LIBSSH2_ERROR_EAGAIN) {
1349 break;
1350 }
1351 if(rc == 0) {
1352 sshc->authed = TRUE;
1353 infof(data, "Initialized keyboard interactive authentication");
1354 }
1355 state(data, SSH_AUTH_DONE);
1356 break;
1357
1358 case SSH_AUTH_DONE:
1359 if(!sshc->authed) {
1360 failf(data, "Authentication failure");
1361 state(data, SSH_SESSION_FREE);
1362 sshc->actualcode = CURLE_LOGIN_DENIED;
1363 break;
1364 }
1365
1366 /*
1367 * At this point we have an authenticated ssh session.
1368 */
1369 infof(data, "Authentication complete");
1370
1371 Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSH is connected */
1372
1373 conn->sockfd = sock;
1374 conn->writesockfd = CURL_SOCKET_BAD;
1375
1376 if(conn->handler->protocol == CURLPROTO_SFTP) {
1377 state(data, SSH_SFTP_INIT);
1378 break;
1379 }
1380 infof(data, "SSH CONNECT phase done");
1381 state(data, SSH_STOP);
1382 break;
1383
1384 case SSH_SFTP_INIT:
1385 /*
1386 * Start the libssh2 sftp session
1387 */
1388 sshc->sftp_session = libssh2_sftp_init(sshc->ssh_session);
1389 if(!sshc->sftp_session) {
1390 char *err_msg = NULL;
1391 if(libssh2_session_last_errno(sshc->ssh_session) ==
1392 LIBSSH2_ERROR_EAGAIN) {
1393 rc = LIBSSH2_ERROR_EAGAIN;
1394 break;
1395 }
1396
1397 (void)libssh2_session_last_error(sshc->ssh_session,
1398 &err_msg, NULL, 0);
1399 failf(data, "Failure initializing sftp session: %s", err_msg);
1400 state(data, SSH_SESSION_FREE);
1401 sshc->actualcode = CURLE_FAILED_INIT;
1402 break;
1403 }
1404 state(data, SSH_SFTP_REALPATH);
1405 break;
1406
1407 case SSH_SFTP_REALPATH:
1408 {
1409 char tempHome[PATH_MAX];
1410
1411 /*
1412 * Get the "home" directory
1413 */
1414 rc = sftp_libssh2_realpath(sshc->sftp_session, ".",
1415 tempHome, PATH_MAX-1);
1416 if(rc == LIBSSH2_ERROR_EAGAIN) {
1417 break;
1418 }
1419 if(rc > 0) {
1420 /* It seems that this string is not always NULL terminated */
1421 tempHome[rc] = '\0';
1422 sshc->homedir = strdup(tempHome);
1423 if(!sshc->homedir) {
1424 state(data, SSH_SFTP_CLOSE);
1425 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1426 break;
1427 }
1428 data->state.most_recent_ftp_entrypath = sshc->homedir;
1429 }
1430 else {
1431 /* Return the error type */
1432 sftperr = libssh2_sftp_last_error(sshc->sftp_session);
1433 if(sftperr)
1434 result = sftp_libssh2_error_to_CURLE(sftperr);
1435 else
1436 /* in this case, the error wasn't in the SFTP level but for example
1437 a time-out or similar */
1438 result = CURLE_SSH;
1439 sshc->actualcode = result;
1440 DEBUGF(infof(data, "error = %lu makes libcurl = %d",
1441 sftperr, (int)result));
1442 state(data, SSH_STOP);
1443 break;
1444 }
1445 }
1446 /* This is the last step in the SFTP connect phase. Do note that while
1447 we get the homedir here, we get the "workingpath" in the DO action
1448 since the homedir will remain the same between request but the
1449 working path will not. */
1450 DEBUGF(infof(data, "SSH CONNECT phase done"));
1451 state(data, SSH_STOP);
1452 break;
1453
1454 case SSH_SFTP_QUOTE_INIT:
1455
1456 result = Curl_getworkingpath(data, sshc->homedir, &sshp->path);
1457 if(result) {
1458 sshc->actualcode = result;
1459 state(data, SSH_STOP);
1460 break;
1461 }
1462
1463 if(data->set.quote) {
1464 infof(data, "Sending quote commands");
1465 sshc->quote_item = data->set.quote;
1466 state(data, SSH_SFTP_QUOTE);
1467 }
1468 else {
1469 state(data, SSH_SFTP_GETINFO);
1470 }
1471 break;
1472
1473 case SSH_SFTP_POSTQUOTE_INIT:
1474 if(data->set.postquote) {
1475 infof(data, "Sending quote commands");
1476 sshc->quote_item = data->set.postquote;
1477 state(data, SSH_SFTP_QUOTE);
1478 }
1479 else {
1480 state(data, SSH_STOP);
1481 }
1482 break;
1483
1484 case SSH_SFTP_QUOTE:
1485 /* Send any quote commands */
1486 {
1487 const char *cp;
1488
1489 /*
1490 * Support some of the "FTP" commands
1491 *
1492 * 'sshc->quote_item' is already verified to be non-NULL before it
1493 * switched to this state.
1494 */
1495 char *cmd = sshc->quote_item->data;
1496 sshc->acceptfail = FALSE;
1497
1498 /* if a command starts with an asterisk, which a legal SFTP command never
1499 can, the command will be allowed to fail without it causing any
1500 aborts or cancels etc. It will cause libcurl to act as if the command
1501 is successful, whatever the server reponds. */
1502
1503 if(cmd[0] == '*') {
1504 cmd++;
1505 sshc->acceptfail = TRUE;
1506 }
1507
1508 if(strcasecompare("pwd", cmd)) {
1509 /* output debug output if that is requested */
1510 char *tmp = aprintf("257 \"%s\" is current directory.\n",
1511 sshp->path);
1512 if(!tmp) {
1513 result = CURLE_OUT_OF_MEMORY;
1514 state(data, SSH_SFTP_CLOSE);
1515 sshc->nextstate = SSH_NO_STATE;
1516 break;
1517 }
1518 Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"PWD\n", 4);
1519 Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
1520
1521 /* this sends an FTP-like "header" to the header callback so that the
1522 current directory can be read very similar to how it is read when
1523 using ordinary FTP. */
1524 result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
1525 free(tmp);
1526 if(result) {
1527 state(data, SSH_SFTP_CLOSE);
1528 sshc->nextstate = SSH_NO_STATE;
1529 sshc->actualcode = result;
1530 }
1531 else
1532 state(data, SSH_SFTP_NEXT_QUOTE);
1533 break;
1534 }
1535 {
1536 /*
1537 * the arguments following the command must be separated from the
1538 * command with a space so we can check for it unconditionally
1539 */
1540 cp = strchr(cmd, ' ');
1541 if(!cp) {
1542 failf(data, "Syntax error command '%s', missing parameter",
1543 cmd);
1544 state(data, SSH_SFTP_CLOSE);
1545 sshc->nextstate = SSH_NO_STATE;
1546 sshc->actualcode = CURLE_QUOTE_ERROR;
1547 break;
1548 }
1549
1550 /*
1551 * also, every command takes at least one argument so we get that
1552 * first argument right now
1553 */
1554 result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir);
1555 if(result) {
1556 if(result == CURLE_OUT_OF_MEMORY)
1557 failf(data, "Out of memory");
1558 else
1559 failf(data, "Syntax error: Bad first parameter to '%s'", cmd);
1560 state(data, SSH_SFTP_CLOSE);
1561 sshc->nextstate = SSH_NO_STATE;
1562 sshc->actualcode = result;
1563 break;
1564 }
1565
1566 /*
1567 * SFTP is a binary protocol, so we don't send text commands
1568 * to the server. Instead, we scan for commands used by
1569 * OpenSSH's sftp program and call the appropriate libssh2
1570 * functions.
1571 */
1572 if(strncasecompare(cmd, "chgrp ", 6) ||
1573 strncasecompare(cmd, "chmod ", 6) ||
1574 strncasecompare(cmd, "chown ", 6) ||
1575 strncasecompare(cmd, "atime ", 6) ||
1576 strncasecompare(cmd, "mtime ", 6)) {
1577 /* attribute change */
1578
1579 /* sshc->quote_path1 contains the mode to set */
1580 /* get the destination */
1581 result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
1582 if(result) {
1583 if(result == CURLE_OUT_OF_MEMORY)
1584 failf(data, "Out of memory");
1585 else
1586 failf(data, "Syntax error in %s: Bad second parameter", cmd);
1587 Curl_safefree(sshc->quote_path1);
1588 state(data, SSH_SFTP_CLOSE);
1589 sshc->nextstate = SSH_NO_STATE;
1590 sshc->actualcode = result;
1591 break;
1592 }
1593 memset(&sshp->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
1594 state(data, SSH_SFTP_QUOTE_STAT);
1595 break;
1596 }
1597 if(strncasecompare(cmd, "ln ", 3) ||
1598 strncasecompare(cmd, "symlink ", 8)) {
1599 /* symbolic linking */
1600 /* sshc->quote_path1 is the source */
1601 /* get the destination */
1602 result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
1603 if(result) {
1604 if(result == CURLE_OUT_OF_MEMORY)
1605 failf(data, "Out of memory");
1606 else
1607 failf(data,
1608 "Syntax error in ln/symlink: Bad second parameter");
1609 Curl_safefree(sshc->quote_path1);
1610 state(data, SSH_SFTP_CLOSE);
1611 sshc->nextstate = SSH_NO_STATE;
1612 sshc->actualcode = result;
1613 break;
1614 }
1615 state(data, SSH_SFTP_QUOTE_SYMLINK);
1616 break;
1617 }
1618 else if(strncasecompare(cmd, "mkdir ", 6)) {
1619 /* create dir */
1620 state(data, SSH_SFTP_QUOTE_MKDIR);
1621 break;
1622 }
1623 else if(strncasecompare(cmd, "rename ", 7)) {
1624 /* rename file */
1625 /* first param is the source path */
1626 /* second param is the dest. path */
1627 result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
1628 if(result) {
1629 if(result == CURLE_OUT_OF_MEMORY)
1630 failf(data, "Out of memory");
1631 else
1632 failf(data, "Syntax error in rename: Bad second parameter");
1633 Curl_safefree(sshc->quote_path1);
1634 state(data, SSH_SFTP_CLOSE);
1635 sshc->nextstate = SSH_NO_STATE;
1636 sshc->actualcode = result;
1637 break;
1638 }
1639 state(data, SSH_SFTP_QUOTE_RENAME);
1640 break;
1641 }
1642 else if(strncasecompare(cmd, "rmdir ", 6)) {
1643 /* delete dir */
1644 state(data, SSH_SFTP_QUOTE_RMDIR);
1645 break;
1646 }
1647 else if(strncasecompare(cmd, "rm ", 3)) {
1648 state(data, SSH_SFTP_QUOTE_UNLINK);
1649 break;
1650 }
1651#ifdef HAS_STATVFS_SUPPORT
1652 else if(strncasecompare(cmd, "statvfs ", 8)) {
1653 state(data, SSH_SFTP_QUOTE_STATVFS);
1654 break;
1655 }
1656#endif
1657
1658 failf(data, "Unknown SFTP command");
1659 Curl_safefree(sshc->quote_path1);
1660 Curl_safefree(sshc->quote_path2);
1661 state(data, SSH_SFTP_CLOSE);
1662 sshc->nextstate = SSH_NO_STATE;
1663 sshc->actualcode = CURLE_QUOTE_ERROR;
1664 break;
1665 }
1666 }
1667 break;
1668
1669 case SSH_SFTP_NEXT_QUOTE:
1670 Curl_safefree(sshc->quote_path1);
1671 Curl_safefree(sshc->quote_path2);
1672
1673 sshc->quote_item = sshc->quote_item->next;
1674
1675 if(sshc->quote_item) {
1676 state(data, SSH_SFTP_QUOTE);
1677 }
1678 else {
1679 if(sshc->nextstate != SSH_NO_STATE) {
1680 state(data, sshc->nextstate);
1681 sshc->nextstate = SSH_NO_STATE;
1682 }
1683 else {
1684 state(data, SSH_SFTP_GETINFO);
1685 }
1686 }
1687 break;
1688
1689 case SSH_SFTP_QUOTE_STAT:
1690 {
1691 char *cmd = sshc->quote_item->data;
1692 sshc->acceptfail = FALSE;
1693
1694 /* if a command starts with an asterisk, which a legal SFTP command never
1695 can, the command will be allowed to fail without it causing any
1696 aborts or cancels etc. It will cause libcurl to act as if the command
1697 is successful, whatever the server reponds. */
1698
1699 if(cmd[0] == '*') {
1700 cmd++;
1701 sshc->acceptfail = TRUE;
1702 }
1703
1704 if(!strncasecompare(cmd, "chmod", 5)) {
1705 /* Since chown and chgrp only set owner OR group but libssh2 wants to
1706 * set them both at once, we need to obtain the current ownership
1707 * first. This takes an extra protocol round trip.
1708 */
1709 rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2,
1710 curlx_uztoui(strlen(sshc->quote_path2)),
1711 LIBSSH2_SFTP_STAT,
1712 &sshp->quote_attrs);
1713 if(rc == LIBSSH2_ERROR_EAGAIN) {
1714 break;
1715 }
1716 if(rc && !sshc->acceptfail) { /* get those attributes */
1717 sftperr = libssh2_sftp_last_error(sshc->sftp_session);
1718 Curl_safefree(sshc->quote_path1);
1719 Curl_safefree(sshc->quote_path2);
1720 failf(data, "Attempt to get SFTP stats failed: %s",
1721 sftp_libssh2_strerror(sftperr));
1722 state(data, SSH_SFTP_CLOSE);
1723 sshc->nextstate = SSH_NO_STATE;
1724 sshc->actualcode = CURLE_QUOTE_ERROR;
1725 break;
1726 }
1727 }
1728
1729 /* Now set the new attributes... */
1730 if(strncasecompare(cmd, "chgrp", 5)) {
1731 sshp->quote_attrs.gid = strtoul(sshc->quote_path1, NULL, 10);
1732 sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
1733 if(sshp->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
1734 !sshc->acceptfail) {
1735 Curl_safefree(sshc->quote_path1);
1736 Curl_safefree(sshc->quote_path2);
1737 failf(data, "Syntax error: chgrp gid not a number");
1738 state(data, SSH_SFTP_CLOSE);
1739 sshc->nextstate = SSH_NO_STATE;
1740 sshc->actualcode = CURLE_QUOTE_ERROR;
1741 break;
1742 }
1743 }
1744 else if(strncasecompare(cmd, "chmod", 5)) {
1745 sshp->quote_attrs.permissions = strtoul(sshc->quote_path1, NULL, 8);
1746 sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS;
1747 /* permissions are octal */
1748 if(sshp->quote_attrs.permissions == 0 &&
1749 !ISDIGIT(sshc->quote_path1[0])) {
1750 Curl_safefree(sshc->quote_path1);
1751 Curl_safefree(sshc->quote_path2);
1752 failf(data, "Syntax error: chmod permissions not a number");
1753 state(data, SSH_SFTP_CLOSE);
1754 sshc->nextstate = SSH_NO_STATE;
1755 sshc->actualcode = CURLE_QUOTE_ERROR;
1756 break;
1757 }
1758 }
1759 else if(strncasecompare(cmd, "chown", 5)) {
1760 sshp->quote_attrs.uid = strtoul(sshc->quote_path1, NULL, 10);
1761 sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
1762 if(sshp->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
1763 !sshc->acceptfail) {
1764 Curl_safefree(sshc->quote_path1);
1765 Curl_safefree(sshc->quote_path2);
1766 failf(data, "Syntax error: chown uid not a number");
1767 state(data, SSH_SFTP_CLOSE);
1768 sshc->nextstate = SSH_NO_STATE;
1769 sshc->actualcode = CURLE_QUOTE_ERROR;
1770 break;
1771 }
1772 }
1773 else if(strncasecompare(cmd, "atime", 5) ||
1774 strncasecompare(cmd, "mtime", 5)) {
1775 time_t date = Curl_getdate_capped(sshc->quote_path1);
1776 bool fail = FALSE;
1777
1778 if(date == -1) {
1779 failf(data, "incorrect date format for %.*s", 5, cmd);
1780 fail = TRUE;
1781 }
1782#if SIZEOF_TIME_T > SIZEOF_LONG
1783 if(date > 0xffffffff) {
1784 /* if 'long' can't old >32bit, this date cannot be sent */
1785 failf(data, "date overflow");
1786 fail = TRUE;
1787 }
1788#endif
1789 if(fail) {
1790 Curl_safefree(sshc->quote_path1);
1791 Curl_safefree(sshc->quote_path2);
1792 state(data, SSH_SFTP_CLOSE);
1793 sshc->nextstate = SSH_NO_STATE;
1794 sshc->actualcode = CURLE_QUOTE_ERROR;
1795 break;
1796 }
1797 if(strncasecompare(cmd, "atime", 5))
1798 sshp->quote_attrs.atime = (unsigned long)date;
1799 else /* mtime */
1800 sshp->quote_attrs.mtime = (unsigned long)date;
1801
1802 sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_ACMODTIME;
1803 }
1804
1805 /* Now send the completed structure... */
1806 state(data, SSH_SFTP_QUOTE_SETSTAT);
1807 break;
1808 }
1809
1810 case SSH_SFTP_QUOTE_SETSTAT:
1811 rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2,
1812 curlx_uztoui(strlen(sshc->quote_path2)),
1813 LIBSSH2_SFTP_SETSTAT,
1814 &sshp->quote_attrs);
1815 if(rc == LIBSSH2_ERROR_EAGAIN) {
1816 break;
1817 }
1818 if(rc && !sshc->acceptfail) {
1819 sftperr = libssh2_sftp_last_error(sshc->sftp_session);
1820 Curl_safefree(sshc->quote_path1);
1821 Curl_safefree(sshc->quote_path2);
1822 failf(data, "Attempt to set SFTP stats failed: %s",
1823 sftp_libssh2_strerror(sftperr));
1824 state(data, SSH_SFTP_CLOSE);
1825 sshc->nextstate = SSH_NO_STATE;
1826 sshc->actualcode = CURLE_QUOTE_ERROR;
1827 break;
1828 }
1829 state(data, SSH_SFTP_NEXT_QUOTE);
1830 break;
1831
1832 case SSH_SFTP_QUOTE_SYMLINK:
1833 rc = libssh2_sftp_symlink_ex(sshc->sftp_session, sshc->quote_path1,
1834 curlx_uztoui(strlen(sshc->quote_path1)),
1835 sshc->quote_path2,
1836 curlx_uztoui(strlen(sshc->quote_path2)),
1837 LIBSSH2_SFTP_SYMLINK);
1838 if(rc == LIBSSH2_ERROR_EAGAIN) {
1839 break;
1840 }
1841 if(rc && !sshc->acceptfail) {
1842 sftperr = libssh2_sftp_last_error(sshc->sftp_session);
1843 Curl_safefree(sshc->quote_path1);
1844 Curl_safefree(sshc->quote_path2);
1845 failf(data, "symlink command failed: %s",
1846 sftp_libssh2_strerror(sftperr));
1847 state(data, SSH_SFTP_CLOSE);
1848 sshc->nextstate = SSH_NO_STATE;
1849 sshc->actualcode = CURLE_QUOTE_ERROR;
1850 break;
1851 }
1852 state(data, SSH_SFTP_NEXT_QUOTE);
1853 break;
1854
1855 case SSH_SFTP_QUOTE_MKDIR:
1856 rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sshc->quote_path1,
1857 curlx_uztoui(strlen(sshc->quote_path1)),
1858 data->set.new_directory_perms);
1859 if(rc == LIBSSH2_ERROR_EAGAIN) {
1860 break;
1861 }
1862 if(rc && !sshc->acceptfail) {
1863 sftperr = libssh2_sftp_last_error(sshc->sftp_session);
1864 Curl_safefree(sshc->quote_path1);
1865 failf(data, "mkdir command failed: %s",
1866 sftp_libssh2_strerror(sftperr));
1867 state(data, SSH_SFTP_CLOSE);
1868 sshc->nextstate = SSH_NO_STATE;
1869 sshc->actualcode = CURLE_QUOTE_ERROR;
1870 break;
1871 }
1872 state(data, SSH_SFTP_NEXT_QUOTE);
1873 break;
1874
1875 case SSH_SFTP_QUOTE_RENAME:
1876 rc = libssh2_sftp_rename_ex(sshc->sftp_session, sshc->quote_path1,
1877 curlx_uztoui(strlen(sshc->quote_path1)),
1878 sshc->quote_path2,
1879 curlx_uztoui(strlen(sshc->quote_path2)),
1880 LIBSSH2_SFTP_RENAME_OVERWRITE |
1881 LIBSSH2_SFTP_RENAME_ATOMIC |
1882 LIBSSH2_SFTP_RENAME_NATIVE);
1883
1884 if(rc == LIBSSH2_ERROR_EAGAIN) {
1885 break;
1886 }
1887 if(rc && !sshc->acceptfail) {
1888 sftperr = libssh2_sftp_last_error(sshc->sftp_session);
1889 Curl_safefree(sshc->quote_path1);
1890 Curl_safefree(sshc->quote_path2);
1891 failf(data, "rename command failed: %s",
1892 sftp_libssh2_strerror(sftperr));
1893 state(data, SSH_SFTP_CLOSE);
1894 sshc->nextstate = SSH_NO_STATE;
1895 sshc->actualcode = CURLE_QUOTE_ERROR;
1896 break;
1897 }
1898 state(data, SSH_SFTP_NEXT_QUOTE);
1899 break;
1900
1901 case SSH_SFTP_QUOTE_RMDIR:
1902 rc = libssh2_sftp_rmdir_ex(sshc->sftp_session, sshc->quote_path1,
1903 curlx_uztoui(strlen(sshc->quote_path1)));
1904 if(rc == LIBSSH2_ERROR_EAGAIN) {
1905 break;
1906 }
1907 if(rc && !sshc->acceptfail) {
1908 sftperr = libssh2_sftp_last_error(sshc->sftp_session);
1909 Curl_safefree(sshc->quote_path1);
1910 failf(data, "rmdir command failed: %s",
1911 sftp_libssh2_strerror(sftperr));
1912 state(data, SSH_SFTP_CLOSE);
1913 sshc->nextstate = SSH_NO_STATE;
1914 sshc->actualcode = CURLE_QUOTE_ERROR;
1915 break;
1916 }
1917 state(data, SSH_SFTP_NEXT_QUOTE);
1918 break;
1919
1920 case SSH_SFTP_QUOTE_UNLINK:
1921 rc = libssh2_sftp_unlink_ex(sshc->sftp_session, sshc->quote_path1,
1922 curlx_uztoui(strlen(sshc->quote_path1)));
1923 if(rc == LIBSSH2_ERROR_EAGAIN) {
1924 break;
1925 }
1926 if(rc && !sshc->acceptfail) {
1927 sftperr = libssh2_sftp_last_error(sshc->sftp_session);
1928 Curl_safefree(sshc->quote_path1);
1929 failf(data, "rm command failed: %s", sftp_libssh2_strerror(sftperr));
1930 state(data, SSH_SFTP_CLOSE);
1931 sshc->nextstate = SSH_NO_STATE;
1932 sshc->actualcode = CURLE_QUOTE_ERROR;
1933 break;
1934 }
1935 state(data, SSH_SFTP_NEXT_QUOTE);
1936 break;
1937
1938#ifdef HAS_STATVFS_SUPPORT
1939 case SSH_SFTP_QUOTE_STATVFS:
1940 {
1941 LIBSSH2_SFTP_STATVFS statvfs;
1942 rc = libssh2_sftp_statvfs(sshc->sftp_session, sshc->quote_path1,
1943 curlx_uztoui(strlen(sshc->quote_path1)),
1944 &statvfs);
1945
1946 if(rc == LIBSSH2_ERROR_EAGAIN) {
1947 break;
1948 }
1949 if(rc && !sshc->acceptfail) {
1950 sftperr = libssh2_sftp_last_error(sshc->sftp_session);
1951 Curl_safefree(sshc->quote_path1);
1952 failf(data, "statvfs command failed: %s",
1953 sftp_libssh2_strerror(sftperr));
1954 state(data, SSH_SFTP_CLOSE);
1955 sshc->nextstate = SSH_NO_STATE;
1956 sshc->actualcode = CURLE_QUOTE_ERROR;
1957 break;
1958 }
1959 else if(rc == 0) {
1960 char *tmp = aprintf("statvfs:\n"
1961 "f_bsize: %llu\n" "f_frsize: %llu\n"
1962 "f_blocks: %llu\n" "f_bfree: %llu\n"
1963 "f_bavail: %llu\n" "f_files: %llu\n"
1964 "f_ffree: %llu\n" "f_favail: %llu\n"
1965 "f_fsid: %llu\n" "f_flag: %llu\n"
1966 "f_namemax: %llu\n",
1967 statvfs.f_bsize, statvfs.f_frsize,
1968 statvfs.f_blocks, statvfs.f_bfree,
1969 statvfs.f_bavail, statvfs.f_files,
1970 statvfs.f_ffree, statvfs.f_favail,
1971 statvfs.f_fsid, statvfs.f_flag,
1972 statvfs.f_namemax);
1973 if(!tmp) {
1974 result = CURLE_OUT_OF_MEMORY;
1975 state(data, SSH_SFTP_CLOSE);
1976 sshc->nextstate = SSH_NO_STATE;
1977 break;
1978 }
1979
1980 result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
1981 free(tmp);
1982 if(result) {
1983 state(data, SSH_SFTP_CLOSE);
1984 sshc->nextstate = SSH_NO_STATE;
1985 sshc->actualcode = result;
1986 }
1987 }
1988 state(data, SSH_SFTP_NEXT_QUOTE);
1989 break;
1990 }
1991#endif
1992 case SSH_SFTP_GETINFO:
1993 {
1994 if(data->set.get_filetime) {
1995 state(data, SSH_SFTP_FILETIME);
1996 }
1997 else {
1998 state(data, SSH_SFTP_TRANS_INIT);
1999 }
2000 break;
2001 }
2002
2003 case SSH_SFTP_FILETIME:
2004 {
2005 LIBSSH2_SFTP_ATTRIBUTES attrs;
2006
2007 rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path,
2008 curlx_uztoui(strlen(sshp->path)),
2009 LIBSSH2_SFTP_STAT, &attrs);
2010 if(rc == LIBSSH2_ERROR_EAGAIN) {
2011 break;
2012 }
2013 if(rc == 0) {
2014 data->info.filetime = attrs.mtime;
2015 }
2016
2017 state(data, SSH_SFTP_TRANS_INIT);
2018 break;
2019 }
2020
2021 case SSH_SFTP_TRANS_INIT:
2022 if(data->set.upload)
2023 state(data, SSH_SFTP_UPLOAD_INIT);
2024 else {
2025 if(sshp->path[strlen(sshp->path)-1] == '/')
2026 state(data, SSH_SFTP_READDIR_INIT);
2027 else
2028 state(data, SSH_SFTP_DOWNLOAD_INIT);
2029 }
2030 break;
2031
2032 case SSH_SFTP_UPLOAD_INIT:
2033 {
2034 unsigned long flags;
2035 /*
2036 * NOTE!!! libssh2 requires that the destination path is a full path
2037 * that includes the destination file and name OR ends in a "/"
2038 * If this is not done the destination file will be named the
2039 * same name as the last directory in the path.
2040 */
2041
2042 if(data->state.resume_from) {
2043 LIBSSH2_SFTP_ATTRIBUTES attrs;
2044 if(data->state.resume_from < 0) {
2045 rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path,
2046 curlx_uztoui(strlen(sshp->path)),
2047 LIBSSH2_SFTP_STAT, &attrs);
2048 if(rc == LIBSSH2_ERROR_EAGAIN) {
2049 break;
2050 }
2051 if(rc) {
2052 data->state.resume_from = 0;
2053 }
2054 else {
2055 curl_off_t size = attrs.filesize;
2056 if(size < 0) {
2057 failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
2058 return CURLE_BAD_DOWNLOAD_RESUME;
2059 }
2060 data->state.resume_from = attrs.filesize;
2061 }
2062 }
2063 }
2064
2065 if(data->set.remote_append)
2066 /* Try to open for append, but create if nonexisting */
2067 flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_APPEND;
2068 else if(data->state.resume_from > 0)
2069 /* If we have restart position then open for append */
2070 flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_APPEND;
2071 else
2072 /* Clear file before writing (normal behavior) */
2073 flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC;
2074
2075 sshc->sftp_handle =
2076 libssh2_sftp_open_ex(sshc->sftp_session, sshp->path,
2077 curlx_uztoui(strlen(sshp->path)),
2078 flags, data->set.new_file_perms,
2079 LIBSSH2_SFTP_OPENFILE);
2080
2081 if(!sshc->sftp_handle) {
2082 rc = libssh2_session_last_errno(sshc->ssh_session);
2083
2084 if(LIBSSH2_ERROR_EAGAIN == rc)
2085 break;
2086
2087 if(LIBSSH2_ERROR_SFTP_PROTOCOL == rc)
2088 /* only when there was an SFTP protocol error can we extract
2089 the sftp error! */
2090 sftperr = libssh2_sftp_last_error(sshc->sftp_session);
2091 else
2092 sftperr = LIBSSH2_FX_OK; /* not an sftp error at all */
2093
2094 if(sshc->secondCreateDirs) {
2095 state(data, SSH_SFTP_CLOSE);
2096 sshc->actualcode = sftperr != LIBSSH2_FX_OK ?
2097 sftp_libssh2_error_to_CURLE(sftperr):CURLE_SSH;
2098 failf(data, "Creating the dir/file failed: %s",
2099 sftp_libssh2_strerror(sftperr));
2100 break;
2101 }
2102 if(((sftperr == LIBSSH2_FX_NO_SUCH_FILE) ||
2103 (sftperr == LIBSSH2_FX_FAILURE) ||
2104 (sftperr == LIBSSH2_FX_NO_SUCH_PATH)) &&
2105 (data->set.ftp_create_missing_dirs &&
2106 (strlen(sshp->path) > 1))) {
2107 /* try to create the path remotely */
2108 rc = 0; /* clear rc and continue */
2109 sshc->secondCreateDirs = 1;
2110 state(data, SSH_SFTP_CREATE_DIRS_INIT);
2111 break;
2112 }
2113 state(data, SSH_SFTP_CLOSE);
2114 sshc->actualcode = sftperr != LIBSSH2_FX_OK ?
2115 sftp_libssh2_error_to_CURLE(sftperr):CURLE_SSH;
2116 if(!sshc->actualcode) {
2117 /* Sometimes, for some reason libssh2_sftp_last_error() returns zero
2118 even though libssh2_sftp_open() failed previously! We need to
2119 work around that! */
2120 sshc->actualcode = CURLE_SSH;
2121 sftperr = LIBSSH2_FX_OK;
2122 }
2123 failf(data, "Upload failed: %s (%lu/%d)",
2124 sftperr != LIBSSH2_FX_OK ?
2125 sftp_libssh2_strerror(sftperr):"ssh error",
2126 sftperr, rc);
2127 break;
2128 }
2129
2130 /* If we have a restart point then we need to seek to the correct
2131 position. */
2132 if(data->state.resume_from > 0) {
2133 /* Let's read off the proper amount of bytes from the input. */
2134 if(conn->seek_func) {
2135 Curl_set_in_callback(data, true);
2136 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
2137 SEEK_SET);
2138 Curl_set_in_callback(data, false);
2139 }
2140
2141 if(seekerr != CURL_SEEKFUNC_OK) {
2142 curl_off_t passed = 0;
2143
2144 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
2145 failf(data, "Could not seek stream");
2146 return CURLE_FTP_COULDNT_USE_REST;
2147 }
2148 /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
2149 do {
2150 size_t readthisamountnow =
2151 (data->state.resume_from - passed > data->set.buffer_size) ?
2152 (size_t)data->set.buffer_size :
2153 curlx_sotouz(data->state.resume_from - passed);
2154
2155 size_t actuallyread;
2156 Curl_set_in_callback(data, true);
2157 actuallyread = data->state.fread_func(data->state.buffer, 1,
2158 readthisamountnow,
2159 data->state.in);
2160 Curl_set_in_callback(data, false);
2161
2162 passed += actuallyread;
2163 if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
2164 /* this checks for greater-than only to make sure that the
2165 CURL_READFUNC_ABORT return code still aborts */
2166 failf(data, "Failed to read data");
2167 return CURLE_FTP_COULDNT_USE_REST;
2168 }
2169 } while(passed < data->state.resume_from);
2170 }
2171
2172 /* now, decrease the size of the read */
2173 if(data->state.infilesize > 0) {
2174 data->state.infilesize -= data->state.resume_from;
2175 data->req.size = data->state.infilesize;
2176 Curl_pgrsSetUploadSize(data, data->state.infilesize);
2177 }
2178
2179 SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
2180 }
2181 if(data->state.infilesize > 0) {
2182 data->req.size = data->state.infilesize;
2183 Curl_pgrsSetUploadSize(data, data->state.infilesize);
2184 }
2185 /* upload data */
2186 Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
2187
2188 /* not set by Curl_setup_transfer to preserve keepon bits */
2189 conn->sockfd = conn->writesockfd;
2190
2191 if(result) {
2192 state(data, SSH_SFTP_CLOSE);
2193 sshc->actualcode = result;
2194 }
2195 else {
2196 /* store this original bitmask setup to use later on if we can't
2197 figure out a "real" bitmask */
2198 sshc->orig_waitfor = data->req.keepon;
2199
2200 /* we want to use the _sending_ function even when the socket turns
2201 out readable as the underlying libssh2 sftp send function will deal
2202 with both accordingly */
2203 conn->cselect_bits = CURL_CSELECT_OUT;
2204
2205 /* since we don't really wait for anything at this point, we want the
2206 state machine to move on as soon as possible so we set a very short
2207 timeout here */
2208 Curl_expire(data, 0, EXPIRE_RUN_NOW);
2209
2210 state(data, SSH_STOP);
2211 }
2212 break;
2213 }
2214
2215 case SSH_SFTP_CREATE_DIRS_INIT:
2216 if(strlen(sshp->path) > 1) {
2217 sshc->slash_pos = sshp->path + 1; /* ignore the leading '/' */
2218 state(data, SSH_SFTP_CREATE_DIRS);
2219 }
2220 else {
2221 state(data, SSH_SFTP_UPLOAD_INIT);
2222 }
2223 break;
2224
2225 case SSH_SFTP_CREATE_DIRS:
2226 sshc->slash_pos = strchr(sshc->slash_pos, '/');
2227 if(sshc->slash_pos) {
2228 *sshc->slash_pos = 0;
2229
2230 infof(data, "Creating directory '%s'", sshp->path);
2231 state(data, SSH_SFTP_CREATE_DIRS_MKDIR);
2232 break;
2233 }
2234 state(data, SSH_SFTP_UPLOAD_INIT);
2235 break;
2236
2237 case SSH_SFTP_CREATE_DIRS_MKDIR:
2238 /* 'mode' - parameter is preliminary - default to 0644 */
2239 rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sshp->path,
2240 curlx_uztoui(strlen(sshp->path)),
2241 data->set.new_directory_perms);
2242 if(rc == LIBSSH2_ERROR_EAGAIN) {
2243 break;
2244 }
2245 *sshc->slash_pos = '/';
2246 ++sshc->slash_pos;
2247 if(rc < 0) {
2248 /*
2249 * Abort if failure wasn't that the dir already exists or the
2250 * permission was denied (creation might succeed further down the
2251 * path) - retry on unspecific FAILURE also
2252 */
2253 sftperr = libssh2_sftp_last_error(sshc->sftp_session);
2254 if((sftperr != LIBSSH2_FX_FILE_ALREADY_EXISTS) &&
2255 (sftperr != LIBSSH2_FX_FAILURE) &&
2256 (sftperr != LIBSSH2_FX_PERMISSION_DENIED)) {
2257 result = sftp_libssh2_error_to_CURLE(sftperr);
2258 state(data, SSH_SFTP_CLOSE);
2259 sshc->actualcode = result?result:CURLE_SSH;
2260 break;
2261 }
2262 rc = 0; /* clear rc and continue */
2263 }
2264 state(data, SSH_SFTP_CREATE_DIRS);
2265 break;
2266
2267 case SSH_SFTP_READDIR_INIT:
2268 Curl_pgrsSetDownloadSize(data, -1);
2269 if(data->req.no_body) {
2270 state(data, SSH_STOP);
2271 break;
2272 }
2273
2274 /*
2275 * This is a directory that we are trying to get, so produce a directory
2276 * listing
2277 */
2278 sshc->sftp_handle = libssh2_sftp_open_ex(sshc->sftp_session,
2279 sshp->path,
2280 curlx_uztoui(
2281 strlen(sshp->path)),
2282 0, 0, LIBSSH2_SFTP_OPENDIR);
2283 if(!sshc->sftp_handle) {
2284 if(libssh2_session_last_errno(sshc->ssh_session) ==
2285 LIBSSH2_ERROR_EAGAIN) {
2286 rc = LIBSSH2_ERROR_EAGAIN;
2287 break;
2288 }
2289 sftperr = libssh2_sftp_last_error(sshc->sftp_session);
2290 failf(data, "Could not open directory for reading: %s",
2291 sftp_libssh2_strerror(sftperr));
2292 state(data, SSH_SFTP_CLOSE);
2293 result = sftp_libssh2_error_to_CURLE(sftperr);
2294 sshc->actualcode = result?result:CURLE_SSH;
2295 break;
2296 }
2297 sshp->readdir_filename = malloc(PATH_MAX + 1);
2298 if(!sshp->readdir_filename) {
2299 state(data, SSH_SFTP_CLOSE);
2300 sshc->actualcode = CURLE_OUT_OF_MEMORY;
2301 break;
2302 }
2303 sshp->readdir_longentry = malloc(PATH_MAX + 1);
2304 if(!sshp->readdir_longentry) {
2305 Curl_safefree(sshp->readdir_filename);
2306 state(data, SSH_SFTP_CLOSE);
2307 sshc->actualcode = CURLE_OUT_OF_MEMORY;
2308 break;
2309 }
2310 Curl_dyn_init(&sshp->readdir, PATH_MAX * 2);
2311 state(data, SSH_SFTP_READDIR);
2312 break;
2313
2314 case SSH_SFTP_READDIR:
2315 rc = libssh2_sftp_readdir_ex(sshc->sftp_handle,
2316 sshp->readdir_filename,
2317 PATH_MAX,
2318 sshp->readdir_longentry,
2319 PATH_MAX,
2320 &sshp->readdir_attrs);
2321 if(rc == LIBSSH2_ERROR_EAGAIN) {
2322 break;
2323 }
2324 if(rc > 0) {
2325 readdir_len = (size_t) rc;
2326 sshp->readdir_filename[readdir_len] = '\0';
2327
2328 if(data->set.list_only) {
2329 result = Curl_client_write(data, CLIENTWRITE_BODY,
2330 sshp->readdir_filename,
2331 readdir_len);
2332 if(!result)
2333 result = Curl_client_write(data, CLIENTWRITE_BODY,
2334 (char *)"\n", 1);
2335 if(result) {
2336 state(data, SSH_STOP);
2337 break;
2338 }
2339 /* since this counts what we send to the client, we include the
2340 newline in this counter */
2341 data->req.bytecount += readdir_len + 1;
2342
2343 /* output debug output if that is requested */
2344 Curl_debug(data, CURLINFO_DATA_IN, sshp->readdir_filename,
2345 readdir_len);
2346 Curl_debug(data, CURLINFO_DATA_IN, (char *)"\n", 1);
2347 }
2348 else {
2349 result = Curl_dyn_add(&sshp->readdir, sshp->readdir_longentry);
2350
2351 if(!result) {
2352 if((sshp->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
2353 ((sshp->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
2354 LIBSSH2_SFTP_S_IFLNK)) {
2355 Curl_dyn_init(&sshp->readdir_link, PATH_MAX);
2356 result = Curl_dyn_addf(&sshp->readdir_link, "%s%s", sshp->path,
2357 sshp->readdir_filename);
2358 state(data, SSH_SFTP_READDIR_LINK);
2359 if(!result)
2360 break;
2361 }
2362 else {
2363 state(data, SSH_SFTP_READDIR_BOTTOM);
2364 break;
2365 }
2366 }
2367 sshc->actualcode = result;
2368 state(data, SSH_SFTP_CLOSE);
2369 break;
2370 }
2371 }
2372 else if(rc == 0) {
2373 Curl_safefree(sshp->readdir_filename);
2374 Curl_safefree(sshp->readdir_longentry);
2375 state(data, SSH_SFTP_READDIR_DONE);
2376 break;
2377 }
2378 else if(rc < 0) {
2379 sftperr = libssh2_sftp_last_error(sshc->sftp_session);
2380 result = sftp_libssh2_error_to_CURLE(sftperr);
2381 sshc->actualcode = result?result:CURLE_SSH;
2382 failf(data, "Could not open remote file for reading: %s :: %d",
2383 sftp_libssh2_strerror(sftperr),
2384 libssh2_session_last_errno(sshc->ssh_session));
2385 Curl_safefree(sshp->readdir_filename);
2386 Curl_safefree(sshp->readdir_longentry);
2387 state(data, SSH_SFTP_CLOSE);
2388 break;
2389 }
2390 break;
2391
2392 case SSH_SFTP_READDIR_LINK:
2393 rc =
2394 libssh2_sftp_symlink_ex(sshc->sftp_session,
2395 Curl_dyn_ptr(&sshp->readdir_link),
2396 (int)Curl_dyn_len(&sshp->readdir_link),
2397 sshp->readdir_filename,
2398 PATH_MAX, LIBSSH2_SFTP_READLINK);
2399 if(rc == LIBSSH2_ERROR_EAGAIN) {
2400 break;
2401 }
2402 Curl_dyn_free(&sshp->readdir_link);
2403
2404 /* append filename and extra output */
2405 result = Curl_dyn_addf(&sshp->readdir, " -> %s", sshp->readdir_filename);
2406
2407 if(result) {
2408 Curl_safefree(sshp->readdir_filename);
2409 Curl_safefree(sshp->readdir_longentry);
2410 state(data, SSH_SFTP_CLOSE);
2411 sshc->actualcode = result;
2412 break;
2413 }
2414
2415 state(data, SSH_SFTP_READDIR_BOTTOM);
2416 break;
2417
2418 case SSH_SFTP_READDIR_BOTTOM:
2419 result = Curl_dyn_addn(&sshp->readdir, "\n", 1);
2420 if(!result)
2421 result = Curl_client_write(data, CLIENTWRITE_BODY,
2422 Curl_dyn_ptr(&sshp->readdir),
2423 Curl_dyn_len(&sshp->readdir));
2424
2425 if(!result) {
2426 /* output debug output if that is requested */
2427 Curl_debug(data, CURLINFO_DATA_IN,
2428 Curl_dyn_ptr(&sshp->readdir),
2429 Curl_dyn_len(&sshp->readdir));
2430 data->req.bytecount += Curl_dyn_len(&sshp->readdir);
2431 }
2432 if(result) {
2433 Curl_dyn_free(&sshp->readdir);
2434 state(data, SSH_STOP);
2435 }
2436 else {
2437 Curl_dyn_reset(&sshp->readdir);
2438 state(data, SSH_SFTP_READDIR);
2439 }
2440 break;
2441
2442 case SSH_SFTP_READDIR_DONE:
2443 if(libssh2_sftp_closedir(sshc->sftp_handle) ==
2444 LIBSSH2_ERROR_EAGAIN) {
2445 rc = LIBSSH2_ERROR_EAGAIN;
2446 break;
2447 }
2448 sshc->sftp_handle = NULL;
2449 Curl_safefree(sshp->readdir_filename);
2450 Curl_safefree(sshp->readdir_longentry);
2451
2452 /* no data to transfer */
2453 Curl_setup_transfer(data, -1, -1, FALSE, -1);
2454 state(data, SSH_STOP);
2455 break;
2456
2457 case SSH_SFTP_DOWNLOAD_INIT:
2458 /*
2459 * Work on getting the specified file
2460 */
2461 sshc->sftp_handle =
2462 libssh2_sftp_open_ex(sshc->sftp_session, sshp->path,
2463 curlx_uztoui(strlen(sshp->path)),
2464 LIBSSH2_FXF_READ, data->set.new_file_perms,
2465 LIBSSH2_SFTP_OPENFILE);
2466 if(!sshc->sftp_handle) {
2467 if(libssh2_session_last_errno(sshc->ssh_session) ==
2468 LIBSSH2_ERROR_EAGAIN) {
2469 rc = LIBSSH2_ERROR_EAGAIN;
2470 break;
2471 }
2472 sftperr = libssh2_sftp_last_error(sshc->sftp_session);
2473 failf(data, "Could not open remote file for reading: %s",
2474 sftp_libssh2_strerror(sftperr));
2475 state(data, SSH_SFTP_CLOSE);
2476 result = sftp_libssh2_error_to_CURLE(sftperr);
2477 sshc->actualcode = result?result:CURLE_SSH;
2478 break;
2479 }
2480 state(data, SSH_SFTP_DOWNLOAD_STAT);
2481 break;
2482
2483 case SSH_SFTP_DOWNLOAD_STAT:
2484 {
2485 LIBSSH2_SFTP_ATTRIBUTES attrs;
2486
2487 rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path,
2488 curlx_uztoui(strlen(sshp->path)),
2489 LIBSSH2_SFTP_STAT, &attrs);
2490 if(rc == LIBSSH2_ERROR_EAGAIN) {
2491 break;
2492 }
2493 if(rc ||
2494 !(attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) ||
2495 (attrs.filesize == 0)) {
2496 /*
2497 * libssh2_sftp_open() didn't return an error, so maybe the server
2498 * just doesn't support stat()
2499 * OR the server doesn't return a file size with a stat()
2500 * OR file size is 0
2501 */
2502 data->req.size = -1;
2503 data->req.maxdownload = -1;
2504 Curl_pgrsSetDownloadSize(data, -1);
2505 }
2506 else {
2507 curl_off_t size = attrs.filesize;
2508
2509 if(size < 0) {
2510 failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
2511 return CURLE_BAD_DOWNLOAD_RESUME;
2512 }
2513 if(data->state.use_range) {
2514 curl_off_t from, to;
2515 char *ptr;
2516 char *ptr2;
2517 CURLofft to_t;
2518 CURLofft from_t;
2519
2520 from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from);
2521 if(from_t == CURL_OFFT_FLOW)
2522 return CURLE_RANGE_ERROR;
2523 while(*ptr && (ISBLANK(*ptr) || (*ptr == '-')))
2524 ptr++;
2525 to_t = curlx_strtoofft(ptr, &ptr2, 10, &to);
2526 if(to_t == CURL_OFFT_FLOW)
2527 return CURLE_RANGE_ERROR;
2528 if((to_t == CURL_OFFT_INVAL) /* no "to" value given */
2529 || (to >= size)) {
2530 to = size - 1;
2531 }
2532 if(from_t) {
2533 /* from is relative to end of file */
2534 from = size - to;
2535 to = size - 1;
2536 }
2537 if(from > size) {
2538 failf(data, "Offset (%"
2539 CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
2540 CURL_FORMAT_CURL_OFF_T ")", from, attrs.filesize);
2541 return CURLE_BAD_DOWNLOAD_RESUME;
2542 }
2543 if(from > to) {
2544 from = to;
2545 size = 0;
2546 }
2547 else {
2548 size = to - from + 1;
2549 }
2550
2551 SFTP_SEEK(sshc->sftp_handle, from);
2552 }
2553 data->req.size = size;
2554 data->req.maxdownload = size;
2555 Curl_pgrsSetDownloadSize(data, size);
2556 }
2557
2558 /* We can resume if we can seek to the resume position */
2559 if(data->state.resume_from) {
2560 if(data->state.resume_from < 0) {
2561 /* We're supposed to download the last abs(from) bytes */
2562 if((curl_off_t)attrs.filesize < -data->state.resume_from) {
2563 failf(data, "Offset (%"
2564 CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
2565 CURL_FORMAT_CURL_OFF_T ")",
2566 data->state.resume_from, attrs.filesize);
2567 return CURLE_BAD_DOWNLOAD_RESUME;
2568 }
2569 /* download from where? */
2570 data->state.resume_from += attrs.filesize;
2571 }
2572 else {
2573 if((curl_off_t)attrs.filesize < data->state.resume_from) {
2574 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2575 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2576 data->state.resume_from, attrs.filesize);
2577 return CURLE_BAD_DOWNLOAD_RESUME;
2578 }
2579 }
2580 /* Now store the number of bytes we are expected to download */
2581 data->req.size = attrs.filesize - data->state.resume_from;
2582 data->req.maxdownload = attrs.filesize - data->state.resume_from;
2583 Curl_pgrsSetDownloadSize(data,
2584 attrs.filesize - data->state.resume_from);
2585 SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
2586 }
2587 }
2588
2589 /* Setup the actual download */
2590 if(data->req.size == 0) {
2591 /* no data to transfer */
2592 Curl_setup_transfer(data, -1, -1, FALSE, -1);
2593 infof(data, "File already completely downloaded");
2594 state(data, SSH_STOP);
2595 break;
2596 }
2597 Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1);
2598
2599 /* not set by Curl_setup_transfer to preserve keepon bits */
2600 conn->writesockfd = conn->sockfd;
2601
2602 /* we want to use the _receiving_ function even when the socket turns
2603 out writableable as the underlying libssh2 recv function will deal
2604 with both accordingly */
2605 conn->cselect_bits = CURL_CSELECT_IN;
2606
2607 if(result) {
2608 /* this should never occur; the close state should be entered
2609 at the time the error occurs */
2610 state(data, SSH_SFTP_CLOSE);
2611 sshc->actualcode = result;
2612 }
2613 else {
2614 state(data, SSH_STOP);
2615 }
2616 break;
2617
2618 case SSH_SFTP_CLOSE:
2619 if(sshc->sftp_handle) {
2620 rc = libssh2_sftp_close(sshc->sftp_handle);
2621 if(rc == LIBSSH2_ERROR_EAGAIN) {
2622 break;
2623 }
2624 if(rc < 0) {
2625 char *err_msg = NULL;
2626 (void)libssh2_session_last_error(sshc->ssh_session,
2627 &err_msg, NULL, 0);
2628 infof(data, "Failed to close libssh2 file: %d %s", rc, err_msg);
2629 }
2630 sshc->sftp_handle = NULL;
2631 }
2632
2633 Curl_safefree(sshp->path);
2634
2635 DEBUGF(infof(data, "SFTP DONE done"));
2636
2637 /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT
2638 After nextstate is executed, the control should come back to
2639 SSH_SFTP_CLOSE to pass the correct result back */
2640 if(sshc->nextstate != SSH_NO_STATE &&
2641 sshc->nextstate != SSH_SFTP_CLOSE) {
2642 state(data, sshc->nextstate);
2643 sshc->nextstate = SSH_SFTP_CLOSE;
2644 }
2645 else {
2646 state(data, SSH_STOP);
2647 result = sshc->actualcode;
2648 }
2649 break;
2650
2651 case SSH_SFTP_SHUTDOWN:
2652 /* during times we get here due to a broken transfer and then the
2653 sftp_handle might not have been taken down so make sure that is done
2654 before we proceed */
2655
2656 if(sshc->sftp_handle) {
2657 rc = libssh2_sftp_close(sshc->sftp_handle);
2658 if(rc == LIBSSH2_ERROR_EAGAIN) {
2659 break;
2660 }
2661 if(rc < 0) {
2662 char *err_msg = NULL;
2663 (void)libssh2_session_last_error(sshc->ssh_session, &err_msg,
2664 NULL, 0);
2665 infof(data, "Failed to close libssh2 file: %d %s", rc, err_msg);
2666 }
2667 sshc->sftp_handle = NULL;
2668 }
2669 if(sshc->sftp_session) {
2670 rc = libssh2_sftp_shutdown(sshc->sftp_session);
2671 if(rc == LIBSSH2_ERROR_EAGAIN) {
2672 break;
2673 }
2674 if(rc < 0) {
2675 infof(data, "Failed to stop libssh2 sftp subsystem");
2676 }
2677 sshc->sftp_session = NULL;
2678 }
2679
2680 Curl_safefree(sshc->homedir);
2681 data->state.most_recent_ftp_entrypath = NULL;
2682
2683 state(data, SSH_SESSION_DISCONNECT);
2684 break;
2685
2686 case SSH_SCP_TRANS_INIT:
2687 result = Curl_getworkingpath(data, sshc->homedir, &sshp->path);
2688 if(result) {
2689 sshc->actualcode = result;
2690 state(data, SSH_STOP);
2691 break;
2692 }
2693
2694 if(data->set.upload) {
2695 if(data->state.infilesize < 0) {
2696 failf(data, "SCP requires a known file size for upload");
2697 sshc->actualcode = CURLE_UPLOAD_FAILED;
2698 state(data, SSH_SCP_CHANNEL_FREE);
2699 break;
2700 }
2701 state(data, SSH_SCP_UPLOAD_INIT);
2702 }
2703 else {
2704 state(data, SSH_SCP_DOWNLOAD_INIT);
2705 }
2706 break;
2707
2708 case SSH_SCP_UPLOAD_INIT:
2709 /*
2710 * libssh2 requires that the destination path is a full path that
2711 * includes the destination file and name OR ends in a "/" . If this is
2712 * not done the destination file will be named the same name as the last
2713 * directory in the path.
2714 */
2715 sshc->ssh_channel =
2716 SCP_SEND(sshc->ssh_session, sshp->path, data->set.new_file_perms,
2717 data->state.infilesize);
2718 if(!sshc->ssh_channel) {
2719 int ssh_err;
2720 char *err_msg = NULL;
2721
2722 if(libssh2_session_last_errno(sshc->ssh_session) ==
2723 LIBSSH2_ERROR_EAGAIN) {
2724 rc = LIBSSH2_ERROR_EAGAIN;
2725 break;
2726 }
2727
2728 ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session,
2729 &err_msg, NULL, 0));
2730 failf(data, "%s", err_msg);
2731 state(data, SSH_SCP_CHANNEL_FREE);
2732 sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
2733 /* Map generic errors to upload failed */
2734 if(sshc->actualcode == CURLE_SSH ||
2735 sshc->actualcode == CURLE_REMOTE_FILE_NOT_FOUND)
2736 sshc->actualcode = CURLE_UPLOAD_FAILED;
2737 break;
2738 }
2739
2740 /* upload data */
2741 data->req.size = data->state.infilesize;
2742 Curl_pgrsSetUploadSize(data, data->state.infilesize);
2743 Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
2744
2745 /* not set by Curl_setup_transfer to preserve keepon bits */
2746 conn->sockfd = conn->writesockfd;
2747
2748 if(result) {
2749 state(data, SSH_SCP_CHANNEL_FREE);
2750 sshc->actualcode = result;
2751 }
2752 else {
2753 /* store this original bitmask setup to use later on if we can't
2754 figure out a "real" bitmask */
2755 sshc->orig_waitfor = data->req.keepon;
2756
2757 /* we want to use the _sending_ function even when the socket turns
2758 out readable as the underlying libssh2 scp send function will deal
2759 with both accordingly */
2760 conn->cselect_bits = CURL_CSELECT_OUT;
2761
2762 state(data, SSH_STOP);
2763 }
2764 break;
2765
2766 case SSH_SCP_DOWNLOAD_INIT:
2767 {
2768 curl_off_t bytecount;
2769
2770 /*
2771 * We must check the remote file; if it is a directory no values will
2772 * be set in sb
2773 */
2774
2775 /*
2776 * If support for >2GB files exists, use it.
2777 */
2778
2779 /* get a fresh new channel from the ssh layer */
2780#if LIBSSH2_VERSION_NUM < 0x010700
2781 struct stat sb;
2782 memset(&sb, 0, sizeof(struct stat));
2783 sshc->ssh_channel = libssh2_scp_recv(sshc->ssh_session,
2784 sshp->path, &sb);
2785#else
2786 libssh2_struct_stat sb;
2787 memset(&sb, 0, sizeof(libssh2_struct_stat));
2788 sshc->ssh_channel = libssh2_scp_recv2(sshc->ssh_session,
2789 sshp->path, &sb);
2790#endif
2791
2792 if(!sshc->ssh_channel) {
2793 int ssh_err;
2794 char *err_msg = NULL;
2795
2796 if(libssh2_session_last_errno(sshc->ssh_session) ==
2797 LIBSSH2_ERROR_EAGAIN) {
2798 rc = LIBSSH2_ERROR_EAGAIN;
2799 break;
2800 }
2801
2802
2803 ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session,
2804 &err_msg, NULL, 0));
2805 failf(data, "%s", err_msg);
2806 state(data, SSH_SCP_CHANNEL_FREE);
2807 sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
2808 break;
2809 }
2810
2811 /* download data */
2812 bytecount = (curl_off_t)sb.st_size;
2813 data->req.maxdownload = (curl_off_t)sb.st_size;
2814 Curl_setup_transfer(data, FIRSTSOCKET, bytecount, FALSE, -1);
2815
2816 /* not set by Curl_setup_transfer to preserve keepon bits */
2817 conn->writesockfd = conn->sockfd;
2818
2819 /* we want to use the _receiving_ function even when the socket turns
2820 out writableable as the underlying libssh2 recv function will deal
2821 with both accordingly */
2822 conn->cselect_bits = CURL_CSELECT_IN;
2823
2824 if(result) {
2825 state(data, SSH_SCP_CHANNEL_FREE);
2826 sshc->actualcode = result;
2827 }
2828 else
2829 state(data, SSH_STOP);
2830 }
2831 break;
2832
2833 case SSH_SCP_DONE:
2834 if(data->set.upload)
2835 state(data, SSH_SCP_SEND_EOF);
2836 else
2837 state(data, SSH_SCP_CHANNEL_FREE);
2838 break;
2839
2840 case SSH_SCP_SEND_EOF:
2841 if(sshc->ssh_channel) {
2842 rc = libssh2_channel_send_eof(sshc->ssh_channel);
2843 if(rc == LIBSSH2_ERROR_EAGAIN) {
2844 break;
2845 }
2846 if(rc) {
2847 char *err_msg = NULL;
2848 (void)libssh2_session_last_error(sshc->ssh_session,
2849 &err_msg, NULL, 0);
2850 infof(data, "Failed to send libssh2 channel EOF: %d %s",
2851 rc, err_msg);
2852 }
2853 }
2854 state(data, SSH_SCP_WAIT_EOF);
2855 break;
2856
2857 case SSH_SCP_WAIT_EOF:
2858 if(sshc->ssh_channel) {
2859 rc = libssh2_channel_wait_eof(sshc->ssh_channel);
2860 if(rc == LIBSSH2_ERROR_EAGAIN) {
2861 break;
2862 }
2863 if(rc) {
2864 char *err_msg = NULL;
2865 (void)libssh2_session_last_error(sshc->ssh_session,
2866 &err_msg, NULL, 0);
2867 infof(data, "Failed to get channel EOF: %d %s", rc, err_msg);
2868 }
2869 }
2870 state(data, SSH_SCP_WAIT_CLOSE);
2871 break;
2872
2873 case SSH_SCP_WAIT_CLOSE:
2874 if(sshc->ssh_channel) {
2875 rc = libssh2_channel_wait_closed(sshc->ssh_channel);
2876 if(rc == LIBSSH2_ERROR_EAGAIN) {
2877 break;
2878 }
2879 if(rc) {
2880 char *err_msg = NULL;
2881 (void)libssh2_session_last_error(sshc->ssh_session,
2882 &err_msg, NULL, 0);
2883 infof(data, "Channel failed to close: %d %s", rc, err_msg);
2884 }
2885 }
2886 state(data, SSH_SCP_CHANNEL_FREE);
2887 break;
2888
2889 case SSH_SCP_CHANNEL_FREE:
2890 if(sshc->ssh_channel) {
2891 rc = libssh2_channel_free(sshc->ssh_channel);
2892 if(rc == LIBSSH2_ERROR_EAGAIN) {
2893 break;
2894 }
2895 if(rc < 0) {
2896 char *err_msg = NULL;
2897 (void)libssh2_session_last_error(sshc->ssh_session,
2898 &err_msg, NULL, 0);
2899 infof(data, "Failed to free libssh2 scp subsystem: %d %s",
2900 rc, err_msg);
2901 }
2902 sshc->ssh_channel = NULL;
2903 }
2904 DEBUGF(infof(data, "SCP DONE phase complete"));
2905#if 0 /* PREV */
2906 state(data, SSH_SESSION_DISCONNECT);
2907#endif
2908 state(data, SSH_STOP);
2909 result = sshc->actualcode;
2910 break;
2911
2912 case SSH_SESSION_DISCONNECT:
2913 /* during weird times when we've been prematurely aborted, the channel
2914 is still alive when we reach this state and we MUST kill the channel
2915 properly first */
2916 if(sshc->ssh_channel) {
2917 rc = libssh2_channel_free(sshc->ssh_channel);
2918 if(rc == LIBSSH2_ERROR_EAGAIN) {
2919 break;
2920 }
2921 if(rc < 0) {
2922 char *err_msg = NULL;
2923 (void)libssh2_session_last_error(sshc->ssh_session,
2924 &err_msg, NULL, 0);
2925 infof(data, "Failed to free libssh2 scp subsystem: %d %s",
2926 rc, err_msg);
2927 }
2928 sshc->ssh_channel = NULL;
2929 }
2930
2931 if(sshc->ssh_session) {
2932 rc = libssh2_session_disconnect(sshc->ssh_session, "Shutdown");
2933 if(rc == LIBSSH2_ERROR_EAGAIN) {
2934 break;
2935 }
2936 if(rc < 0) {
2937 char *err_msg = NULL;
2938 (void)libssh2_session_last_error(sshc->ssh_session,
2939 &err_msg, NULL, 0);
2940 infof(data, "Failed to disconnect libssh2 session: %d %s",
2941 rc, err_msg);
2942 }
2943 }
2944
2945 Curl_safefree(sshc->homedir);
2946 data->state.most_recent_ftp_entrypath = NULL;
2947
2948 state(data, SSH_SESSION_FREE);
2949 break;
2950
2951 case SSH_SESSION_FREE:
2952#ifdef HAVE_LIBSSH2_KNOWNHOST_API
2953 if(sshc->kh) {
2954 libssh2_knownhost_free(sshc->kh);
2955 sshc->kh = NULL;
2956 }
2957#endif
2958
2959#ifdef HAVE_LIBSSH2_AGENT_API
2960 if(sshc->ssh_agent) {
2961 rc = libssh2_agent_disconnect(sshc->ssh_agent);
2962 if(rc == LIBSSH2_ERROR_EAGAIN) {
2963 break;
2964 }
2965 if(rc < 0) {
2966 char *err_msg = NULL;
2967 (void)libssh2_session_last_error(sshc->ssh_session,
2968 &err_msg, NULL, 0);
2969 infof(data, "Failed to disconnect from libssh2 agent: %d %s",
2970 rc, err_msg);
2971 }
2972 libssh2_agent_free(sshc->ssh_agent);
2973 sshc->ssh_agent = NULL;
2974
2975 /* NB: there is no need to free identities, they are part of internal
2976 agent stuff */
2977 sshc->sshagent_identity = NULL;
2978 sshc->sshagent_prev_identity = NULL;
2979 }
2980#endif
2981
2982 if(sshc->ssh_session) {
2983 rc = libssh2_session_free(sshc->ssh_session);
2984 if(rc == LIBSSH2_ERROR_EAGAIN) {
2985 break;
2986 }
2987 if(rc < 0) {
2988 char *err_msg = NULL;
2989 (void)libssh2_session_last_error(sshc->ssh_session,
2990 &err_msg, NULL, 0);
2991 infof(data, "Failed to free libssh2 session: %d %s", rc, err_msg);
2992 }
2993 sshc->ssh_session = NULL;
2994 }
2995
2996 /* worst-case scenario cleanup */
2997
2998 DEBUGASSERT(sshc->ssh_session == NULL);
2999 DEBUGASSERT(sshc->ssh_channel == NULL);
3000 DEBUGASSERT(sshc->sftp_session == NULL);
3001 DEBUGASSERT(sshc->sftp_handle == NULL);
3002#ifdef HAVE_LIBSSH2_KNOWNHOST_API
3003 DEBUGASSERT(sshc->kh == NULL);
3004#endif
3005#ifdef HAVE_LIBSSH2_AGENT_API
3006 DEBUGASSERT(sshc->ssh_agent == NULL);
3007#endif
3008
3009 Curl_safefree(sshc->rsa_pub);
3010 Curl_safefree(sshc->rsa);
3011 Curl_safefree(sshc->quote_path1);
3012 Curl_safefree(sshc->quote_path2);
3013 Curl_safefree(sshc->homedir);
3014
3015 /* the code we are about to return */
3016 result = sshc->actualcode;
3017
3018 memset(sshc, 0, sizeof(struct ssh_conn));
3019
3020 connclose(conn, "SSH session free");
3021 sshc->state = SSH_SESSION_FREE; /* current */
3022 sshc->nextstate = SSH_NO_STATE;
3023 state(data, SSH_STOP);
3024 break;
3025
3026 case SSH_QUIT:
3027 /* fallthrough, just stop! */
3028 default:
3029 /* internal error */
3030 sshc->nextstate = SSH_NO_STATE;
3031 state(data, SSH_STOP);
3032 break;
3033 }
3034
3035 } while(!rc && (sshc->state != SSH_STOP));
3036
3037 if(rc == LIBSSH2_ERROR_EAGAIN) {
3038 /* we would block, we need to wait for the socket to be ready (in the
3039 right direction too)! */
3040 *block = TRUE;
3041 }
3042
3043 return result;
3044}
3045
3046/* called by the multi interface to figure out what socket(s) to wait for and
3047 for what actions in the DO_DONE, PERFORM and WAITPERFORM states */
3048static int ssh_getsock(struct Curl_easy *data,
3049 struct connectdata *conn,
3050 curl_socket_t *sock)
3051{
3052 int bitmap = GETSOCK_BLANK;
3053 (void)data;
3054
3055 sock[0] = conn->sock[FIRSTSOCKET];
3056
3057 if(conn->waitfor & KEEP_RECV)
3058 bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
3059
3060 if(conn->waitfor & KEEP_SEND)
3061 bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
3062
3063 return bitmap;
3064}
3065
3066/*
3067 * When one of the libssh2 functions has returned LIBSSH2_ERROR_EAGAIN this
3068 * function is used to figure out in what direction and stores this info so
3069 * that the multi interface can take advantage of it. Make sure to call this
3070 * function in all cases so that when it _doesn't_ return EAGAIN we can
3071 * restore the default wait bits.
3072 */
3073static void ssh_block2waitfor(struct Curl_easy *data, bool block)
3074{
3075 struct connectdata *conn = data->conn;
3076 struct ssh_conn *sshc = &conn->proto.sshc;
3077 int dir = 0;
3078 if(block) {
3079 dir = libssh2_session_block_directions(sshc->ssh_session);
3080 if(dir) {
3081 /* translate the libssh2 define bits into our own bit defines */
3082 conn->waitfor = ((dir&LIBSSH2_SESSION_BLOCK_INBOUND)?KEEP_RECV:0) |
3083 ((dir&LIBSSH2_SESSION_BLOCK_OUTBOUND)?KEEP_SEND:0);
3084 }
3085 }
3086 if(!dir)
3087 /* It didn't block or libssh2 didn't reveal in which direction, put back
3088 the original set */
3089 conn->waitfor = sshc->orig_waitfor;
3090}
3091
3092/* called repeatedly until done from multi.c */
3093static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done)
3094{
3095 struct connectdata *conn = data->conn;
3096 struct ssh_conn *sshc = &conn->proto.sshc;
3097 CURLcode result = CURLE_OK;
3098 bool block; /* we store the status and use that to provide a ssh_getsock()
3099 implementation */
3100 do {
3101 result = ssh_statemach_act(data, &block);
3102 *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
3103 /* if there's no error, it isn't done and it didn't EWOULDBLOCK, then
3104 try again */
3105 } while(!result && !*done && !block);
3106 ssh_block2waitfor(data, block);
3107
3108 return result;
3109}
3110
3111static CURLcode ssh_block_statemach(struct Curl_easy *data,
3112 struct connectdata *conn,
3113 bool disconnect)
3114{
3115 struct ssh_conn *sshc = &conn->proto.sshc;
3116 CURLcode result = CURLE_OK;
3117 struct curltime dis = Curl_now();
3118
3119 while((sshc->state != SSH_STOP) && !result) {
3120 bool block;
3121 timediff_t left = 1000;
3122 struct curltime now = Curl_now();
3123
3124 result = ssh_statemach_act(data, &block);
3125 if(result)
3126 break;
3127
3128 if(!disconnect) {
3129 if(Curl_pgrsUpdate(data))
3130 return CURLE_ABORTED_BY_CALLBACK;
3131
3132 result = Curl_speedcheck(data, now);
3133 if(result)
3134 break;
3135
3136 left = Curl_timeleft(data, NULL, FALSE);
3137 if(left < 0) {
3138 failf(data, "Operation timed out");
3139 return CURLE_OPERATION_TIMEDOUT;
3140 }
3141 }
3142 else if(Curl_timediff(now, dis) > 1000) {
3143 /* disconnect timeout */
3144 failf(data, "Disconnect timed out");
3145 result = CURLE_OK;
3146 break;
3147 }
3148
3149 if(block) {
3150 int dir = libssh2_session_block_directions(sshc->ssh_session);
3151 curl_socket_t sock = conn->sock[FIRSTSOCKET];
3152 curl_socket_t fd_read = CURL_SOCKET_BAD;
3153 curl_socket_t fd_write = CURL_SOCKET_BAD;
3154 if(LIBSSH2_SESSION_BLOCK_INBOUND & dir)
3155 fd_read = sock;
3156 if(LIBSSH2_SESSION_BLOCK_OUTBOUND & dir)
3157 fd_write = sock;
3158 /* wait for the socket to become ready */
3159 (void)Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write,
3160 left>1000?1000:left);
3161 }
3162 }
3163
3164 return result;
3165}
3166
3167/*
3168 * SSH setup and connection
3169 */
3170static CURLcode ssh_setup_connection(struct Curl_easy *data,
3171 struct connectdata *conn)
3172{
3173 struct SSHPROTO *ssh;
3174 (void)conn;
3175
3176 data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
3177 if(!ssh)
3178 return CURLE_OUT_OF_MEMORY;
3179
3180 return CURLE_OK;
3181}
3182
3183static Curl_recv scp_recv, sftp_recv;
3184static Curl_send scp_send, sftp_send;
3185
3186#ifndef CURL_DISABLE_PROXY
3187static ssize_t ssh_tls_recv(libssh2_socket_t sock, void *buffer,
3188 size_t length, int flags, void **abstract)
3189{
3190 struct Curl_easy *data = (struct Curl_easy *)*abstract;
3191 ssize_t nread;
3192 CURLcode result;
3193 struct connectdata *conn = data->conn;
3194 Curl_recv *backup = conn->recv[0];
3195 struct ssh_conn *ssh = &conn->proto.sshc;
3196 (void)flags;
3197
3198 /* swap in the TLS reader function for this call only, and then swap back
3199 the SSH one again */
3200 conn->recv[0] = ssh->tls_recv;
3201 result = Curl_read(data, sock, buffer, length, &nread);
3202 conn->recv[0] = backup;
3203 if(result == CURLE_AGAIN)
3204 return -EAGAIN; /* magic return code for libssh2 */
3205 else if(result)
3206 return -1; /* generic error */
3207 Curl_debug(data, CURLINFO_DATA_IN, (char *)buffer, (size_t)nread);
3208 return nread;
3209}
3210
3211static ssize_t ssh_tls_send(libssh2_socket_t sock, const void *buffer,
3212 size_t length, int flags, void **abstract)
3213{
3214 struct Curl_easy *data = (struct Curl_easy *)*abstract;
3215 ssize_t nwrite;
3216 CURLcode result;
3217 struct connectdata *conn = data->conn;
3218 Curl_send *backup = conn->send[0];
3219 struct ssh_conn *ssh = &conn->proto.sshc;
3220 (void)flags;
3221
3222 /* swap in the TLS writer function for this call only, and then swap back
3223 the SSH one again */
3224 conn->send[0] = ssh->tls_send;
3225 result = Curl_write(data, sock, buffer, length, &nwrite);
3226 conn->send[0] = backup;
3227 if(result == CURLE_AGAIN)
3228 return -EAGAIN; /* magic return code for libssh2 */
3229 else if(result)
3230 return -1; /* error */
3231 Curl_debug(data, CURLINFO_DATA_OUT, (char *)buffer, (size_t)nwrite);
3232 return nwrite;
3233}
3234#endif
3235
3236/*
3237 * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to
3238 * do protocol-specific actions at connect-time.
3239 */
3240static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
3241{
3242#ifdef CURL_LIBSSH2_DEBUG
3243 curl_socket_t sock;
3244#endif
3245 struct ssh_conn *sshc;
3246 CURLcode result;
3247 struct connectdata *conn = data->conn;
3248
3249 /* initialize per-handle data if not already */
3250 if(!data->req.p.ssh) {
3251 result = ssh_setup_connection(data, conn);
3252 if(result)
3253 return result;
3254 }
3255
3256 /* We default to persistent connections. We set this already in this connect
3257 function to make the re-use checks properly be able to check this bit. */
3258 connkeep(conn, "SSH default");
3259
3260 sshc = &conn->proto.sshc;
3261
3262#ifdef CURL_LIBSSH2_DEBUG
3263 if(conn->user) {
3264 infof(data, "User: %s", conn->user);
3265 }
3266 if(conn->passwd) {
3267 infof(data, "Password: %s", conn->passwd);
3268 }
3269 sock = conn->sock[FIRSTSOCKET];
3270#endif /* CURL_LIBSSH2_DEBUG */
3271
3272#ifdef CURL_LIBSSH2_DEBUG
3273 sshc->ssh_session = libssh2_session_init_ex(my_libssh2_malloc,
3274 my_libssh2_free,
3275 my_libssh2_realloc, data);
3276#else
3277 sshc->ssh_session = libssh2_session_init();
3278#endif
3279 if(!sshc->ssh_session) {
3280 failf(data, "Failure initialising ssh session");
3281 return CURLE_FAILED_INIT;
3282 }
3283
3284#ifndef CURL_DISABLE_PROXY
3285 if(conn->http_proxy.proxytype == CURLPROXY_HTTPS) {
3286 /*
3287 * This crazy union dance is here to avoid assigning a void pointer a
3288 * function pointer as it is invalid C. The problem is of course that
3289 * libssh2 has such an API...
3290 */
3291 union receive {
3292 void *recvp;
3293 ssize_t (*recvptr)(libssh2_socket_t, void *, size_t, int, void **);
3294 };
3295 union transfer {
3296 void *sendp;
3297 ssize_t (*sendptr)(libssh2_socket_t, const void *, size_t, int, void **);
3298 };
3299 union receive sshrecv;
3300 union transfer sshsend;
3301
3302 sshrecv.recvptr = ssh_tls_recv;
3303 sshsend.sendptr = ssh_tls_send;
3304
3305 infof(data, "Uses HTTPS proxy");
3306 /*
3307 Setup libssh2 callbacks to make it read/write TLS from the socket.
3308
3309 ssize_t
3310 recvcb(libssh2_socket_t sock, void *buffer, size_t length,
3311 int flags, void **abstract);
3312
3313 ssize_t
3314 sendcb(libssh2_socket_t sock, const void *buffer, size_t length,
3315 int flags, void **abstract);
3316
3317 */
3318 libssh2_session_callback_set(sshc->ssh_session,
3319 LIBSSH2_CALLBACK_RECV, sshrecv.recvp);
3320 libssh2_session_callback_set(sshc->ssh_session,
3321 LIBSSH2_CALLBACK_SEND, sshsend.sendp);
3322
3323 /* Store the underlying TLS recv/send function pointers to be used when
3324 reading from the proxy */
3325 sshc->tls_recv = conn->recv[FIRSTSOCKET];
3326 sshc->tls_send = conn->send[FIRSTSOCKET];
3327 }
3328
3329#endif /* CURL_DISABLE_PROXY */
3330 if(conn->handler->protocol & CURLPROTO_SCP) {
3331 conn->recv[FIRSTSOCKET] = scp_recv;
3332 conn->send[FIRSTSOCKET] = scp_send;
3333 }
3334 else {
3335 conn->recv[FIRSTSOCKET] = sftp_recv;
3336 conn->send[FIRSTSOCKET] = sftp_send;
3337 }
3338
3339 if(data->set.ssh_compression) {
3340#if LIBSSH2_VERSION_NUM >= 0x010208
3341 if(libssh2_session_flag(sshc->ssh_session, LIBSSH2_FLAG_COMPRESS, 1) < 0)
3342#endif
3343 infof(data, "Failed to enable compression for ssh session");
3344 }
3345
3346#ifdef HAVE_LIBSSH2_KNOWNHOST_API
3347 if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
3348 int rc;
3349 sshc->kh = libssh2_knownhost_init(sshc->ssh_session);
3350 if(!sshc->kh) {
3351 libssh2_session_free(sshc->ssh_session);
3352 sshc->ssh_session = NULL;
3353 return CURLE_FAILED_INIT;
3354 }
3355
3356 /* read all known hosts from there */
3357 rc = libssh2_knownhost_readfile(sshc->kh,
3358 data->set.str[STRING_SSH_KNOWNHOSTS],
3359 LIBSSH2_KNOWNHOST_FILE_OPENSSH);
3360 if(rc < 0)
3361 infof(data, "Failed to read known hosts from %s",
3362 data->set.str[STRING_SSH_KNOWNHOSTS]);
3363 }
3364#endif /* HAVE_LIBSSH2_KNOWNHOST_API */
3365
3366#ifdef CURL_LIBSSH2_DEBUG
3367 libssh2_trace(sshc->ssh_session, ~0);
3368 infof(data, "SSH socket: %d", (int)sock);
3369#endif /* CURL_LIBSSH2_DEBUG */
3370
3371 state(data, SSH_INIT);
3372
3373 result = ssh_multi_statemach(data, done);
3374
3375 return result;
3376}
3377
3378/*
3379 ***********************************************************************
3380 *
3381 * scp_perform()
3382 *
3383 * This is the actual DO function for SCP. Get a file according to
3384 * the options previously setup.
3385 */
3386
3387static
3388CURLcode scp_perform(struct Curl_easy *data,
3389 bool *connected,
3390 bool *dophase_done)
3391{
3392 CURLcode result = CURLE_OK;
3393
3394 DEBUGF(infof(data, "DO phase starts"));
3395
3396 *dophase_done = FALSE; /* not done yet */
3397
3398 /* start the first command in the DO phase */
3399 state(data, SSH_SCP_TRANS_INIT);
3400
3401 /* run the state-machine */
3402 result = ssh_multi_statemach(data, dophase_done);
3403
3404 *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
3405
3406 if(*dophase_done) {
3407 DEBUGF(infof(data, "DO phase is complete"));
3408 }
3409
3410 return result;
3411}
3412
3413/* called from multi.c while DOing */
3414static CURLcode scp_doing(struct Curl_easy *data,
3415 bool *dophase_done)
3416{
3417 CURLcode result;
3418 result = ssh_multi_statemach(data, dophase_done);
3419
3420 if(*dophase_done) {
3421 DEBUGF(infof(data, "DO phase is complete"));
3422 }
3423 return result;
3424}
3425
3426/*
3427 * The DO function is generic for both protocols. There was previously two
3428 * separate ones but this way means less duplicated code.
3429 */
3430
3431static CURLcode ssh_do(struct Curl_easy *data, bool *done)
3432{
3433 CURLcode result;
3434 bool connected = 0;
3435 struct connectdata *conn = data->conn;
3436 struct ssh_conn *sshc = &conn->proto.sshc;
3437
3438 *done = FALSE; /* default to false */
3439
3440 data->req.size = -1; /* make sure this is unknown at this point */
3441
3442 sshc->actualcode = CURLE_OK; /* reset error code */
3443 sshc->secondCreateDirs = 0; /* reset the create dir attempt state
3444 variable */
3445
3446 Curl_pgrsSetUploadCounter(data, 0);
3447 Curl_pgrsSetDownloadCounter(data, 0);
3448 Curl_pgrsSetUploadSize(data, -1);
3449 Curl_pgrsSetDownloadSize(data, -1);
3450
3451 if(conn->handler->protocol & CURLPROTO_SCP)
3452 result = scp_perform(data, &connected, done);
3453 else
3454 result = sftp_perform(data, &connected, done);
3455
3456 return result;
3457}
3458
3459/* BLOCKING, but the function is using the state machine so the only reason
3460 this is still blocking is that the multi interface code has no support for
3461 disconnecting operations that takes a while */
3462static CURLcode scp_disconnect(struct Curl_easy *data,
3463 struct connectdata *conn,
3464 bool dead_connection)
3465{
3466 CURLcode result = CURLE_OK;
3467 struct ssh_conn *sshc = &conn->proto.sshc;
3468 (void) dead_connection;
3469
3470 if(sshc->ssh_session) {
3471 /* only if there's a session still around to use! */
3472 state(data, SSH_SESSION_DISCONNECT);
3473 result = ssh_block_statemach(data, conn, TRUE);
3474 }
3475
3476 return result;
3477}
3478
3479/* generic done function for both SCP and SFTP called from their specific
3480 done functions */
3481static CURLcode ssh_done(struct Curl_easy *data, CURLcode status)
3482{
3483 CURLcode result = CURLE_OK;
3484 struct SSHPROTO *sshp = data->req.p.ssh;
3485 struct connectdata *conn = data->conn;
3486
3487 if(!status)
3488 /* run the state-machine */
3489 result = ssh_block_statemach(data, conn, FALSE);
3490 else
3491 result = status;
3492
3493 Curl_safefree(sshp->path);
3494 Curl_safefree(sshp->readdir_filename);
3495 Curl_safefree(sshp->readdir_longentry);
3496 Curl_dyn_free(&sshp->readdir);
3497
3498 if(Curl_pgrsDone(data))
3499 return CURLE_ABORTED_BY_CALLBACK;
3500
3501 data->req.keepon = 0; /* clear all bits */
3502 return result;
3503}
3504
3505
3506static CURLcode scp_done(struct Curl_easy *data, CURLcode status,
3507 bool premature)
3508{
3509 (void)premature; /* not used */
3510
3511 if(!status)
3512 state(data, SSH_SCP_DONE);
3513
3514 return ssh_done(data, status);
3515
3516}
3517
3518static ssize_t scp_send(struct Curl_easy *data, int sockindex,
3519 const void *mem, size_t len, CURLcode *err)
3520{
3521 ssize_t nwrite;
3522 struct connectdata *conn = data->conn;
3523 struct ssh_conn *sshc = &conn->proto.sshc;
3524 (void)sockindex; /* we only support SCP on the fixed known primary socket */
3525
3526 /* libssh2_channel_write() returns int! */
3527 nwrite = (ssize_t) libssh2_channel_write(sshc->ssh_channel, mem, len);
3528
3529 ssh_block2waitfor(data, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
3530
3531 if(nwrite == LIBSSH2_ERROR_EAGAIN) {
3532 *err = CURLE_AGAIN;
3533 nwrite = 0;
3534 }
3535 else if(nwrite < LIBSSH2_ERROR_NONE) {
3536 *err = libssh2_session_error_to_CURLE((int)nwrite);
3537 nwrite = -1;
3538 }
3539
3540 return nwrite;
3541}
3542
3543static ssize_t scp_recv(struct Curl_easy *data, int sockindex,
3544 char *mem, size_t len, CURLcode *err)
3545{
3546 ssize_t nread;
3547 struct connectdata *conn = data->conn;
3548 struct ssh_conn *sshc = &conn->proto.sshc;
3549 (void)sockindex; /* we only support SCP on the fixed known primary socket */
3550
3551 /* libssh2_channel_read() returns int */
3552 nread = (ssize_t) libssh2_channel_read(sshc->ssh_channel, mem, len);
3553
3554 ssh_block2waitfor(data, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
3555 if(nread == LIBSSH2_ERROR_EAGAIN) {
3556 *err = CURLE_AGAIN;
3557 nread = -1;
3558 }
3559
3560 return nread;
3561}
3562
3563/*
3564 * =============== SFTP ===============
3565 */
3566
3567/*
3568 ***********************************************************************
3569 *
3570 * sftp_perform()
3571 *
3572 * This is the actual DO function for SFTP. Get a file/directory according to
3573 * the options previously setup.
3574 */
3575
3576static
3577CURLcode sftp_perform(struct Curl_easy *data,
3578 bool *connected,
3579 bool *dophase_done)
3580{
3581 CURLcode result = CURLE_OK;
3582
3583 DEBUGF(infof(data, "DO phase starts"));
3584
3585 *dophase_done = FALSE; /* not done yet */
3586
3587 /* start the first command in the DO phase */
3588 state(data, SSH_SFTP_QUOTE_INIT);
3589
3590 /* run the state-machine */
3591 result = ssh_multi_statemach(data, dophase_done);
3592
3593 *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
3594
3595 if(*dophase_done) {
3596 DEBUGF(infof(data, "DO phase is complete"));
3597 }
3598
3599 return result;
3600}
3601
3602/* called from multi.c while DOing */
3603static CURLcode sftp_doing(struct Curl_easy *data,
3604 bool *dophase_done)
3605{
3606 CURLcode result = ssh_multi_statemach(data, dophase_done);
3607
3608 if(*dophase_done) {
3609 DEBUGF(infof(data, "DO phase is complete"));
3610 }
3611 return result;
3612}
3613
3614/* BLOCKING, but the function is using the state machine so the only reason
3615 this is still blocking is that the multi interface code has no support for
3616 disconnecting operations that takes a while */
3617static CURLcode sftp_disconnect(struct Curl_easy *data,
3618 struct connectdata *conn, bool dead_connection)
3619{
3620 CURLcode result = CURLE_OK;
3621 struct ssh_conn *sshc = &conn->proto.sshc;
3622 (void) dead_connection;
3623
3624 DEBUGF(infof(data, "SSH DISCONNECT starts now"));
3625
3626 if(sshc->ssh_session) {
3627 /* only if there's a session still around to use! */
3628 state(data, SSH_SFTP_SHUTDOWN);
3629 result = ssh_block_statemach(data, conn, TRUE);
3630 }
3631
3632 DEBUGF(infof(data, "SSH DISCONNECT is done"));
3633
3634 return result;
3635
3636}
3637
3638static CURLcode sftp_done(struct Curl_easy *data, CURLcode status,
3639 bool premature)
3640{
3641 struct connectdata *conn = data->conn;
3642 struct ssh_conn *sshc = &conn->proto.sshc;
3643
3644 if(!status) {
3645 /* Post quote commands are executed after the SFTP_CLOSE state to avoid
3646 errors that could happen due to open file handles during POSTQUOTE
3647 operation */
3648 if(!premature && data->set.postquote && !conn->bits.retry)
3649 sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
3650 state(data, SSH_SFTP_CLOSE);
3651 }
3652 return ssh_done(data, status);
3653}
3654
3655/* return number of sent bytes */
3656static ssize_t sftp_send(struct Curl_easy *data, int sockindex,
3657 const void *mem, size_t len, CURLcode *err)
3658{
3659 ssize_t nwrite;
3660 struct connectdata *conn = data->conn;
3661 struct ssh_conn *sshc = &conn->proto.sshc;
3662 (void)sockindex;
3663
3664 nwrite = libssh2_sftp_write(sshc->sftp_handle, mem, len);
3665
3666 ssh_block2waitfor(data, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
3667
3668 if(nwrite == LIBSSH2_ERROR_EAGAIN) {
3669 *err = CURLE_AGAIN;
3670 nwrite = 0;
3671 }
3672 else if(nwrite < LIBSSH2_ERROR_NONE) {
3673 *err = libssh2_session_error_to_CURLE((int)nwrite);
3674 nwrite = -1;
3675 }
3676
3677 return nwrite;
3678}
3679
3680/*
3681 * Return number of received (decrypted) bytes
3682 * or <0 on error
3683 */
3684static ssize_t sftp_recv(struct Curl_easy *data, int sockindex,
3685 char *mem, size_t len, CURLcode *err)
3686{
3687 ssize_t nread;
3688 struct connectdata *conn = data->conn;
3689 struct ssh_conn *sshc = &conn->proto.sshc;
3690 (void)sockindex;
3691
3692 nread = libssh2_sftp_read(sshc->sftp_handle, mem, len);
3693
3694 ssh_block2waitfor(data, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
3695
3696 if(nread == LIBSSH2_ERROR_EAGAIN) {
3697 *err = CURLE_AGAIN;
3698 nread = -1;
3699
3700 }
3701 else if(nread < 0) {
3702 *err = libssh2_session_error_to_CURLE((int)nread);
3703 }
3704 return nread;
3705}
3706
3707static const char *sftp_libssh2_strerror(unsigned long err)
3708{
3709 switch(err) {
3710 case LIBSSH2_FX_NO_SUCH_FILE:
3711 return "No such file or directory";
3712
3713 case LIBSSH2_FX_PERMISSION_DENIED:
3714 return "Permission denied";
3715
3716 case LIBSSH2_FX_FAILURE:
3717 return "Operation failed";
3718
3719 case LIBSSH2_FX_BAD_MESSAGE:
3720 return "Bad message from SFTP server";
3721
3722 case LIBSSH2_FX_NO_CONNECTION:
3723 return "Not connected to SFTP server";
3724
3725 case LIBSSH2_FX_CONNECTION_LOST:
3726 return "Connection to SFTP server lost";
3727
3728 case LIBSSH2_FX_OP_UNSUPPORTED:
3729 return "Operation not supported by SFTP server";
3730
3731 case LIBSSH2_FX_INVALID_HANDLE:
3732 return "Invalid handle";
3733
3734 case LIBSSH2_FX_NO_SUCH_PATH:
3735 return "No such file or directory";
3736
3737 case LIBSSH2_FX_FILE_ALREADY_EXISTS:
3738 return "File already exists";
3739
3740 case LIBSSH2_FX_WRITE_PROTECT:
3741 return "File is write protected";
3742
3743 case LIBSSH2_FX_NO_MEDIA:
3744 return "No media";
3745
3746 case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM:
3747 return "Disk full";
3748
3749 case LIBSSH2_FX_QUOTA_EXCEEDED:
3750 return "User quota exceeded";
3751
3752 case LIBSSH2_FX_UNKNOWN_PRINCIPLE:
3753 return "Unknown principle";
3754
3755 case LIBSSH2_FX_LOCK_CONFlICT:
3756 return "File lock conflict";
3757
3758 case LIBSSH2_FX_DIR_NOT_EMPTY:
3759 return "Directory not empty";
3760
3761 case LIBSSH2_FX_NOT_A_DIRECTORY:
3762 return "Not a directory";
3763
3764 case LIBSSH2_FX_INVALID_FILENAME:
3765 return "Invalid filename";
3766
3767 case LIBSSH2_FX_LINK_LOOP:
3768 return "Link points to itself";
3769 }
3770 return "Unknown error in libssh2";
3771}
3772
3773CURLcode Curl_ssh_init(void)
3774{
3775#ifdef HAVE_LIBSSH2_INIT
3776 if(libssh2_init(0)) {
3777 DEBUGF(fprintf(stderr, "Error: libssh2_init failed\n"));
3778 return CURLE_FAILED_INIT;
3779 }
3780#endif
3781 return CURLE_OK;
3782}
3783
3784void Curl_ssh_cleanup(void)
3785{
3786#ifdef HAVE_LIBSSH2_EXIT
3787 (void)libssh2_exit();
3788#endif
3789}
3790
3791void Curl_ssh_version(char *buffer, size_t buflen)
3792{
3793 (void)msnprintf(buffer, buflen, "libssh2/%s", CURL_LIBSSH2_VERSION);
3794}
3795
3796/* The SSH session is associated with the *CONNECTION* but the callback user
3797 * pointer is an easy handle pointer. This function allows us to reassign the
3798 * user pointer to the *CURRENT* (new) easy handle.
3799 */
3800static void ssh_attach(struct Curl_easy *data, struct connectdata *conn)
3801{
3802 DEBUGASSERT(data);
3803 DEBUGASSERT(conn);
3804 if(conn->handler->protocol & PROTO_FAMILY_SSH) {
3805 struct ssh_conn *sshc = &conn->proto.sshc;
3806 if(sshc->ssh_session) {
3807 /* only re-attach if the session already exists */
3808 void **abstract = libssh2_session_abstract(sshc->ssh_session);
3809 *abstract = data;
3810 }
3811 }
3812}
3813#endif /* USE_LIBSSH2 */
Note: See TracBrowser for help on using the repository browser.

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