VirtualBox

source: vbox/trunk/src/libs/curl-7.83.1/lib/vssh/libssh2.c@ 97122

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

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

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

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