VirtualBox

source: vbox/trunk/src/libs/curl-7.87.0/lib/vssh/libssh2.c@ 98341

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

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

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

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