Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Utilities / cmcurl-7.19.0 / lib / ssh.c
blob5145e2ebe3546da80b1ee61ae2d3abc01391c0bb
1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
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 http://curl.haxx.se/docs/copyright.html.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * $Id: ssh.c,v 1.1.1.1 2008-09-23 16:32:05 hoffman Exp $
22 ***************************************************************************/
24 /* #define CURL_LIBSSH2_DEBUG */
26 #include "setup.h"
28 #ifdef USE_LIBSSH2
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #include <ctype.h>
34 #include <limits.h>
36 #include <libssh2.h>
37 #include <libssh2_sftp.h>
39 #if !defined(LIBSSH2_VERSION_NUM) || (LIBSSH2_VERSION_NUM < 0x001000)
40 #error "this requires libssh2 0.16 or later"
41 #endif
43 #ifdef HAVE_UNISTD_H
44 #include <unistd.h>
45 #endif
47 #ifdef HAVE_FCNTL_H
48 #include <fcntl.h>
49 #endif
51 #ifdef HAVE_TIME_H
52 #include <time.h>
53 #endif
55 #ifndef WIN32
56 #ifdef HAVE_SYS_SOCKET_H
57 #include <sys/socket.h>
58 #endif
59 #ifdef HAVE_NETINET_IN_H
60 #include <netinet/in.h>
61 #endif
62 #ifdef HAVE_ARPA_INET_H
63 #include <arpa/inet.h>
64 #endif
65 #ifdef HAVE_UTSNAME_H
66 #include <sys/utsname.h>
67 #endif
68 #ifdef HAVE_NETDB_H
69 #include <netdb.h>
70 #endif
71 #ifdef VMS
72 #include <in.h>
73 #include <inet.h>
74 #endif
75 #endif /* !WIN32 */
77 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
78 #undef in_addr_t
79 #define in_addr_t unsigned long
80 #endif
82 #include <curl/curl.h>
83 #include "urldata.h"
84 #include "sendf.h"
85 #include "easyif.h" /* for Curl_convert_... prototypes */
87 #include "hostip.h"
88 #include "progress.h"
89 #include "transfer.h"
90 #include "escape.h"
91 #include "http.h" /* for HTTP proxy tunnel stuff */
92 #include "ssh.h"
93 #include "url.h"
94 #include "speedcheck.h"
95 #include "getinfo.h"
97 #include "strequal.h"
98 #include "sslgen.h"
99 #include "connect.h"
100 #include "strerror.h"
101 #include "memory.h"
102 #include "inet_ntop.h"
103 #include "parsedate.h" /* for the week day and month names */
104 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
105 #include "multiif.h"
107 #if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
108 #include "inet_ntoa_r.h"
109 #endif
111 #define _MPRINTF_REPLACE /* use our functions only */
112 #include <curl/mprintf.h>
114 /* The last #include file should be: */
115 #ifdef CURLDEBUG
116 #include "memdebug.h"
117 #endif
119 #ifndef PATH_MAX
120 #define PATH_MAX 1024 /* just an extra precaution since there are systems that
121 have their definition hidden well */
122 #endif
124 /* Local functions: */
125 static const char *sftp_libssh2_strerror(unsigned long err);
126 static LIBSSH2_ALLOC_FUNC(libssh2_malloc);
127 static LIBSSH2_REALLOC_FUNC(libssh2_realloc);
128 static LIBSSH2_FREE_FUNC(libssh2_free);
130 static CURLcode get_pathname(const char **cpp, char **path);
132 static CURLcode ssh_connect(struct connectdata *conn, bool *done);
133 static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done);
134 static CURLcode ssh_do(struct connectdata *conn, bool *done);
136 static CURLcode ssh_getworkingpath(struct connectdata *conn,
137 char *homedir, /* when SFTP is used */
138 char **path);
140 static CURLcode scp_done(struct connectdata *conn,
141 CURLcode, bool premature);
142 static CURLcode scp_doing(struct connectdata *conn,
143 bool *dophase_done);
144 static CURLcode scp_disconnect(struct connectdata *conn);
146 static CURLcode sftp_done(struct connectdata *conn,
147 CURLcode, bool premature);
148 static CURLcode sftp_doing(struct connectdata *conn,
149 bool *dophase_done);
150 static CURLcode sftp_disconnect(struct connectdata *conn);
151 static
152 CURLcode sftp_perform(struct connectdata *conn,
153 bool *connected,
154 bool *dophase_done);
156 * SCP protocol handler.
159 const struct Curl_handler Curl_handler_scp = {
160 "SCP", /* scheme */
161 ZERO_NULL, /* setup_connection */
162 ssh_do, /* do_it */
163 scp_done, /* done */
164 ZERO_NULL, /* do_more */
165 ssh_connect, /* connect_it */
166 ssh_multi_statemach, /* connecting */
167 scp_doing, /* doing */
168 ZERO_NULL, /* proto_getsock */
169 ZERO_NULL, /* doing_getsock */
170 scp_disconnect, /* disconnect */
171 PORT_SSH, /* defport */
172 PROT_SCP /* protocol */
177 * SFTP protocol handler.
180 const struct Curl_handler Curl_handler_sftp = {
181 "SFTP", /* scheme */
182 ZERO_NULL, /* setup_connection */
183 ssh_do, /* do_it */
184 sftp_done, /* done */
185 ZERO_NULL, /* do_more */
186 ssh_connect, /* connect_it */
187 ssh_multi_statemach, /* connecting */
188 sftp_doing, /* doing */
189 ZERO_NULL, /* proto_getsock */
190 ZERO_NULL, /* doing_getsock */
191 sftp_disconnect, /* disconnect */
192 PORT_SSH, /* defport */
193 PROT_SFTP /* protocol */
197 static void
198 kbd_callback(const char *name, int name_len, const char *instruction,
199 int instruction_len, int num_prompts,
200 const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
201 LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
202 void **abstract)
204 struct connectdata *conn = (struct connectdata *)*abstract;
206 #ifdef CURL_LIBSSH2_DEBUG
207 fprintf(stderr, "name=%s\n", name);
208 fprintf(stderr, "name_len=%d\n", name_len);
209 fprintf(stderr, "instruction=%s\n", instruction);
210 fprintf(stderr, "instruction_len=%d\n", instruction_len);
211 fprintf(stderr, "num_prompts=%d\n", num_prompts);
212 #else
213 (void)name;
214 (void)name_len;
215 (void)instruction;
216 (void)instruction_len;
217 #endif /* CURL_LIBSSH2_DEBUG */
218 if(num_prompts == 1) {
219 responses[0].text = strdup(conn->passwd);
220 responses[0].length = strlen(conn->passwd);
222 (void)prompts;
223 (void)abstract;
224 } /* kbd_callback */
226 static CURLcode sftp_libssh2_error_to_CURLE(unsigned long err)
228 switch (err) {
229 case LIBSSH2_FX_OK:
230 return CURLE_OK;
232 case LIBSSH2_ERROR_ALLOC:
233 return CURLE_OUT_OF_MEMORY;
235 case LIBSSH2_FX_NO_SUCH_FILE:
236 case LIBSSH2_FX_NO_SUCH_PATH:
237 return CURLE_REMOTE_FILE_NOT_FOUND;
239 case LIBSSH2_FX_PERMISSION_DENIED:
240 case LIBSSH2_FX_WRITE_PROTECT:
241 case LIBSSH2_FX_LOCK_CONFlICT:
242 return CURLE_REMOTE_ACCESS_DENIED;
244 case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM:
245 case LIBSSH2_FX_QUOTA_EXCEEDED:
246 return CURLE_REMOTE_DISK_FULL;
248 case LIBSSH2_FX_FILE_ALREADY_EXISTS:
249 return CURLE_REMOTE_FILE_EXISTS;
251 case LIBSSH2_FX_DIR_NOT_EMPTY:
252 return CURLE_QUOTE_ERROR;
254 default:
255 break;
258 return CURLE_SSH;
261 static CURLcode libssh2_session_error_to_CURLE(int err)
263 if(err == LIBSSH2_ERROR_ALLOC)
264 return CURLE_OUT_OF_MEMORY;
266 /* TODO: map some more of the libssh2 errors to the more appropriate CURLcode
267 error code, and possibly add a few new SSH-related one. We must however
268 not return or even depend on libssh2 errors in the public libcurl API */
270 return CURLE_SSH;
273 static LIBSSH2_ALLOC_FUNC(libssh2_malloc)
275 (void)abstract; /* arg not used */
276 return malloc(count);
279 static LIBSSH2_REALLOC_FUNC(libssh2_realloc)
281 (void)abstract; /* arg not used */
282 return realloc(ptr, count);
285 static LIBSSH2_FREE_FUNC(libssh2_free)
287 (void)abstract; /* arg not used */
288 free(ptr);
292 * SSH State machine related code
294 /* This is the ONLY way to change SSH state! */
295 static void state(struct connectdata *conn, sshstate nowstate)
297 #if defined(CURLDEBUG) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
298 /* for debug purposes */
299 static const char * const names[] = {
300 "SSH_STOP",
301 "SSH_S_STARTUP",
302 "SSH_AUTHLIST",
303 "SSH_AUTH_PKEY_INIT",
304 "SSH_AUTH_PKEY",
305 "SSH_AUTH_PASS_INIT",
306 "SSH_AUTH_PASS",
307 "SSH_AUTH_HOST_INIT",
308 "SSH_AUTH_HOST",
309 "SSH_AUTH_KEY_INIT",
310 "SSH_AUTH_KEY",
311 "SSH_AUTH_DONE",
312 "SSH_SFTP_INIT",
313 "SSH_SFTP_REALPATH",
314 "SSH_SFTP_QUOTE_INIT",
315 "SSH_SFTP_POSTQUOTE_INIT",
316 "SSH_SFTP_QUOTE",
317 "SSH_SFTP_NEXT_QUOTE",
318 "SSH_SFTP_QUOTE_STAT",
319 "SSH_SFTP_QUOTE_SETSTAT",
320 "SSH_SFTP_QUOTE_SYMLINK",
321 "SSH_SFTP_QUOTE_MKDIR",
322 "SSH_SFTP_QUOTE_RENAME",
323 "SSH_SFTP_QUOTE_RMDIR",
324 "SSH_SFTP_QUOTE_UNLINK",
325 "SSH_SFTP_TRANS_INIT",
326 "SSH_SFTP_UPLOAD_INIT",
327 "SSH_SFTP_CREATE_DIRS_INIT",
328 "SSH_SFTP_CREATE_DIRS",
329 "SSH_SFTP_CREATE_DIRS_MKDIR",
330 "SSH_SFTP_READDIR_INIT",
331 "SSH_SFTP_READDIR",
332 "SSH_SFTP_READDIR_LINK",
333 "SSH_SFTP_READDIR_BOTTOM",
334 "SSH_SFTP_READDIR_DONE",
335 "SSH_SFTP_DOWNLOAD_INIT",
336 "SSH_SFTP_DOWNLOAD_STAT",
337 "SSH_SFTP_CLOSE",
338 "SSH_SFTP_SHUTDOWN",
339 "SSH_SCP_TRANS_INIT",
340 "SSH_SCP_UPLOAD_INIT",
341 "SSH_SCP_DOWNLOAD_INIT",
342 "SSH_SCP_DONE",
343 "SSH_SCP_SEND_EOF",
344 "SSH_SCP_WAIT_EOF",
345 "SSH_SCP_WAIT_CLOSE",
346 "SSH_SCP_CHANNEL_FREE",
347 "SSH_SESSION_DISCONNECT",
348 "SSH_SESSION_FREE",
349 "QUIT"
351 #endif
352 struct ssh_conn *sshc = &conn->proto.sshc;
354 #if defined(CURLDEBUG) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
355 if(sshc->state != nowstate) {
356 infof(conn->data, "SFTP %p state change from %s to %s\n",
357 sshc, names[sshc->state], names[nowstate]);
359 #endif
361 sshc->state = nowstate;
364 /* figure out the path to work with in this particular request */
365 static CURLcode ssh_getworkingpath(struct connectdata *conn,
366 char *homedir, /* when SFTP is used */
367 char **path) /* returns the allocated
368 real path to work with */
370 struct SessionHandle *data = conn->data;
371 char *real_path = NULL;
372 char *working_path;
373 int working_path_len;
375 working_path = curl_easy_unescape(data, data->state.path, 0,
376 &working_path_len);
377 if(!working_path)
378 return CURLE_OUT_OF_MEMORY;
380 /* Check for /~/ , indicating relative to the user's home directory */
381 if(conn->protocol & PROT_SCP) {
382 real_path = (char *)malloc(working_path_len+1);
383 if(real_path == NULL) {
384 free(working_path);
385 return CURLE_OUT_OF_MEMORY;
387 if((working_path_len > 1) && (working_path[1] == '~'))
388 /* It is referenced to the home directory, so strip the leading '/' */
389 memcpy(real_path, working_path+1, 1 + working_path_len-1);
390 else
391 memcpy(real_path, working_path, 1 + working_path_len);
393 else if(conn->protocol & PROT_SFTP) {
394 if((working_path_len > 1) && (working_path[1] == '~')) {
395 size_t homelen = strlen(homedir);
396 real_path = (char *)malloc(homelen + working_path_len + 1);
397 if(real_path == NULL) {
398 free(working_path);
399 return CURLE_OUT_OF_MEMORY;
401 /* It is referenced to the home directory, so strip the
402 leading '/' */
403 memcpy(real_path, homedir, homelen);
404 real_path[homelen] = '/';
405 real_path[homelen+1] = '\0';
406 if(working_path_len > 3) {
407 memcpy(real_path+homelen+1, working_path + 3,
408 1 + working_path_len -3);
411 else {
412 real_path = (char *)malloc(working_path_len+1);
413 if(real_path == NULL) {
414 free(working_path);
415 return CURLE_OUT_OF_MEMORY;
417 memcpy(real_path, working_path, 1+working_path_len);
421 free(working_path);
423 /* store the pointer for the caller to receive */
424 *path = real_path;
426 return CURLE_OK;
429 static CURLcode ssh_statemach_act(struct connectdata *conn)
431 CURLcode result = CURLE_OK;
432 struct SessionHandle *data = conn->data;
433 struct SSHPROTO *sftp_scp = data->state.proto.ssh;
434 struct ssh_conn *sshc = &conn->proto.sshc;
435 curl_socket_t sock = conn->sock[FIRSTSOCKET];
436 #ifdef CURL_LIBSSH2_DEBUG
437 const char *fingerprint;
438 #endif /* CURL_LIBSSH2_DEBUG */
439 const char *host_public_key_md5;
440 int rc,i;
441 int err;
443 switch(sshc->state) {
444 case SSH_S_STARTUP:
445 sshc->secondCreateDirs = 0;
446 sshc->nextstate = SSH_NO_STATE;
447 sshc->actualcode = CURLE_OK;
449 rc = libssh2_session_startup(sshc->ssh_session, sock);
450 if(rc == LIBSSH2_ERROR_EAGAIN) {
451 break;
453 else if(rc) {
454 failf(data, "Failure establishing ssh session");
455 state(conn, SSH_SESSION_FREE);
456 sshc->actualcode = CURLE_FAILED_INIT;
457 break;
460 /* Set libssh2 to non-blocking, since cURL is all non-blocking */
461 libssh2_session_set_blocking(sshc->ssh_session, 0);
463 #ifdef CURL_LIBSSH2_DEBUG
465 * Before we authenticate we should check the hostkey's fingerprint
466 * against our known hosts. How that is handled (reading from file,
467 * whatever) is up to us. As for know not much is implemented, besides
468 * showing how to get the fingerprint.
470 fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
471 LIBSSH2_HOSTKEY_HASH_MD5);
473 /* The fingerprint points to static storage (!), don't free() it. */
474 infof(data, "Fingerprint: ");
475 for (rc = 0; rc < 16; rc++) {
476 infof(data, "%02X ", (unsigned char) fingerprint[rc]);
478 infof(data, "\n");
479 #endif /* CURL_LIBSSH2_DEBUG */
481 /* Before we authenticate we check the hostkey's MD5 fingerprint
482 * against a known fingerprint, if available. This implementation pulls
483 * it from the curl option.
485 if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] &&
486 strlen(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) == 32) {
487 char buf[33];
488 host_public_key_md5 = libssh2_hostkey_hash(sshc->ssh_session,
489 LIBSSH2_HOSTKEY_HASH_MD5);
490 for (i = 0; i < 16; i++)
491 snprintf(&buf[i*2], 3, "%02x",
492 (unsigned char) host_public_key_md5[i]);
493 if(!strequal(buf, data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5])) {
494 failf(data,
495 "Denied establishing ssh session: mismatch md5 fingerprint. "
496 "Remote %s is not equal to %s",
497 buf, data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]);
498 state(conn, SSH_SESSION_FREE);
499 sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
500 break;
504 state(conn, SSH_AUTHLIST);
505 break;
507 case SSH_AUTHLIST:
508 /* TBD - methods to check the host keys need to be done */
511 * Figure out authentication methods
512 * NB: As soon as we have provided a username to an openssh server we
513 * must never change it later. Thus, always specify the correct username
514 * here, even though the libssh2 docs kind of indicate that it should be
515 * possible to get a 'generic' list (not user-specific) of authentication
516 * methods, presumably with a blank username. That won't work in my
517 * experience.
518 * So always specify it here.
520 sshc->authlist = libssh2_userauth_list(sshc->ssh_session,
521 conn->user,
522 strlen(conn->user));
524 if(!sshc->authlist) {
525 if((err = libssh2_session_last_errno(sshc->ssh_session)) ==
526 LIBSSH2_ERROR_EAGAIN) {
527 break;
529 else {
530 state(conn, SSH_SESSION_FREE);
531 sshc->actualcode = libssh2_session_error_to_CURLE(err);
532 break;
535 infof(data, "SSH authentication methods available: %s\n", sshc->authlist);
537 state(conn, SSH_AUTH_PKEY_INIT);
538 break;
540 case SSH_AUTH_PKEY_INIT:
542 * Check the supported auth types in the order I feel is most secure
543 * with the requested type of authentication
545 sshc->authed = FALSE;
547 if((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) &&
548 (strstr(sshc->authlist, "publickey") != NULL)) {
549 char *home;
551 sshc->rsa_pub = sshc->rsa = NULL;
553 /* To ponder about: should really the lib be messing about with the
554 HOME environment variable etc? */
555 home = curl_getenv("HOME");
557 if(data->set.str[STRING_SSH_PUBLIC_KEY])
558 sshc->rsa_pub = aprintf("%s", data->set.str[STRING_SSH_PUBLIC_KEY]);
559 else if(home)
560 sshc->rsa_pub = aprintf("%s/.ssh/id_dsa.pub", home);
561 else
562 /* as a final resort, try current dir! */
563 sshc->rsa_pub = strdup("id_dsa.pub");
565 if(sshc->rsa_pub == NULL) {
566 Curl_safefree(home);
567 home = NULL;
568 state(conn, SSH_SESSION_FREE);
569 sshc->actualcode = CURLE_OUT_OF_MEMORY;
570 break;
573 if(data->set.str[STRING_SSH_PRIVATE_KEY])
574 sshc->rsa = aprintf("%s", data->set.str[STRING_SSH_PRIVATE_KEY]);
575 else if(home)
576 sshc->rsa = aprintf("%s/.ssh/id_dsa", home);
577 else
578 /* as a final resort, try current dir! */
579 sshc->rsa = strdup("id_dsa");
581 if(sshc->rsa == NULL) {
582 Curl_safefree(home);
583 home = NULL;
584 Curl_safefree(sshc->rsa_pub);
585 sshc->rsa_pub = NULL;
586 state(conn, SSH_SESSION_FREE);
587 sshc->actualcode = CURLE_OUT_OF_MEMORY;
588 break;
591 sshc->passphrase = data->set.str[STRING_KEY_PASSWD];
592 if(!sshc->passphrase)
593 sshc->passphrase = "";
595 Curl_safefree(home);
596 home = NULL;
598 infof(data, "Using ssh public key file %s\n", sshc->rsa_pub);
599 infof(data, "Using ssh private key file %s\n", sshc->rsa);
601 state(conn, SSH_AUTH_PKEY);
603 else {
604 state(conn, SSH_AUTH_PASS_INIT);
606 break;
608 case SSH_AUTH_PKEY:
609 /* The function below checks if the files exists, no need to stat() here.
611 rc = libssh2_userauth_publickey_fromfile(sshc->ssh_session,
612 conn->user, sshc->rsa_pub,
613 sshc->rsa, sshc->passphrase);
614 if(rc == LIBSSH2_ERROR_EAGAIN) {
615 break;
618 Curl_safefree(sshc->rsa_pub);
619 sshc->rsa_pub = NULL;
620 Curl_safefree(sshc->rsa);
621 sshc->rsa = NULL;
623 if(rc == 0) {
624 sshc->authed = TRUE;
625 infof(data, "Initialized SSH public key authentication\n");
626 state(conn, SSH_AUTH_DONE);
628 else {
629 char *err_msg;
630 (void)libssh2_session_last_error(sshc->ssh_session,
631 &err_msg, NULL, 0);
632 infof(data, "SSH public key authentication failed: %s\n", err_msg);
633 state(conn, SSH_AUTH_PASS_INIT);
635 break;
637 case SSH_AUTH_PASS_INIT:
638 if((data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD) &&
639 (strstr(sshc->authlist, "password") != NULL)) {
640 state(conn, SSH_AUTH_PASS);
642 else {
643 state(conn, SSH_AUTH_HOST_INIT);
645 break;
647 case SSH_AUTH_PASS:
648 rc = libssh2_userauth_password(sshc->ssh_session, conn->user,
649 conn->passwd);
650 if(rc == LIBSSH2_ERROR_EAGAIN) {
651 break;
653 else if(rc == 0) {
654 sshc->authed = TRUE;
655 infof(data, "Initialized password authentication\n");
656 state(conn, SSH_AUTH_DONE);
658 else {
659 state(conn, SSH_AUTH_HOST_INIT);
661 break;
663 case SSH_AUTH_HOST_INIT:
664 if((data->set.ssh_auth_types & CURLSSH_AUTH_HOST) &&
665 (strstr(sshc->authlist, "hostbased") != NULL)) {
666 state(conn, SSH_AUTH_HOST);
668 else {
669 state(conn, SSH_AUTH_KEY_INIT);
671 break;
673 case SSH_AUTH_HOST:
674 state(conn, SSH_AUTH_KEY_INIT);
675 break;
677 case SSH_AUTH_KEY_INIT:
678 if((data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD)
679 && (strstr(sshc->authlist, "keyboard-interactive") != NULL)) {
680 state(conn, SSH_AUTH_KEY);
682 else {
683 state(conn, SSH_AUTH_DONE);
685 break;
687 case SSH_AUTH_KEY:
688 /* Authentication failed. Continue with keyboard-interactive now. */
689 rc = libssh2_userauth_keyboard_interactive_ex(sshc->ssh_session,
690 conn->user,
691 strlen(conn->user),
692 &kbd_callback);
693 if(rc == LIBSSH2_ERROR_EAGAIN) {
694 break;
696 else if(rc == 0) {
697 sshc->authed = TRUE;
698 infof(data, "Initialized keyboard interactive authentication\n");
700 state(conn, SSH_AUTH_DONE);
701 break;
703 case SSH_AUTH_DONE:
704 if(!sshc->authed) {
705 failf(data, "Authentication failure");
706 state(conn, SSH_SESSION_FREE);
707 sshc->actualcode = CURLE_LOGIN_DENIED;
708 break;
712 * At this point we have an authenticated ssh session.
714 infof(data, "Authentication complete\n");
716 Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSH is connected */
718 conn->sockfd = sock;
719 conn->writesockfd = CURL_SOCKET_BAD;
721 if(conn->protocol == PROT_SFTP) {
722 state(conn, SSH_SFTP_INIT);
723 break;
725 infof(data, "SSH CONNECT phase done\n");
726 state(conn, SSH_STOP);
727 break;
729 case SSH_SFTP_INIT:
731 * Start the libssh2 sftp session
733 sshc->sftp_session = libssh2_sftp_init(sshc->ssh_session);
734 if(!sshc->sftp_session) {
735 if(libssh2_session_last_errno(sshc->ssh_session) ==
736 LIBSSH2_ERROR_EAGAIN) {
737 break;
739 else {
740 char *err_msg;
742 (void)libssh2_session_last_error(sshc->ssh_session,
743 &err_msg, NULL, 0);
744 failf(data, "Failure initializing sftp session: %s", err_msg);
745 state(conn, SSH_SESSION_FREE);
746 sshc->actualcode = CURLE_FAILED_INIT;
747 break;
750 state(conn, SSH_SFTP_REALPATH);
751 break;
753 case SSH_SFTP_REALPATH:
755 char tempHome[PATH_MAX];
758 * Get the "home" directory
760 rc = libssh2_sftp_realpath(sshc->sftp_session, ".",
761 tempHome, PATH_MAX-1);
762 if(rc == LIBSSH2_ERROR_EAGAIN) {
763 break;
765 else if(rc > 0) {
766 /* It seems that this string is not always NULL terminated */
767 tempHome[rc] = '\0';
768 sshc->homedir = (char *)strdup(tempHome);
769 if(!sshc->homedir) {
770 state(conn, SSH_SFTP_CLOSE);
771 sshc->actualcode = CURLE_OUT_OF_MEMORY;
772 break;
775 else {
776 /* Return the error type */
777 err = libssh2_sftp_last_error(sshc->sftp_session);
778 result = sftp_libssh2_error_to_CURLE(err);
779 DEBUGF(infof(data, "error = %d makes libcurl = %d\n", err, result));
780 state(conn, SSH_STOP);
781 break;
784 /* This is the last step in the SFTP connect phase. Do note that while
785 we get the homedir here, we get the "workingpath" in the DO action
786 since the homedir will remain the same between request but the
787 working path will not. */
788 DEBUGF(infof(data, "SSH CONNECT phase done\n"));
789 state(conn, SSH_STOP);
790 break;
792 case SSH_SFTP_QUOTE_INIT:
794 result = ssh_getworkingpath(conn, sshc->homedir, &sftp_scp->path);
795 if(result) {
796 sshc->actualcode = result;
797 state(conn, SSH_STOP);
798 break;
801 if(data->set.quote) {
802 infof(data, "Sending quote commands\n");
803 sshc->quote_item = data->set.quote;
804 state(conn, SSH_SFTP_QUOTE);
806 else {
807 state(conn, SSH_SFTP_TRANS_INIT);
809 break;
811 case SSH_SFTP_POSTQUOTE_INIT:
812 if(data->set.postquote) {
813 infof(data, "Sending quote commands\n");
814 sshc->quote_item = data->set.postquote;
815 state(conn, SSH_SFTP_QUOTE);
817 else {
818 state(conn, SSH_STOP);
820 break;
822 case SSH_SFTP_QUOTE:
823 /* Send any quote commands */
825 const char *cp;
828 * Support some of the "FTP" commands
830 if(curl_strnequal(sshc->quote_item->data, "PWD", 3)) {
831 /* output debug output if that is requested */
832 if(data->set.verbose) {
833 char tmp[PATH_MAX+1];
835 Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"PWD\n", 4, conn);
836 snprintf(tmp, PATH_MAX, "257 \"%s\" is current directory.\n",
837 sftp_scp->path);
838 Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp), conn);
840 state(conn, SSH_SFTP_NEXT_QUOTE);
841 break;
843 else if(sshc->quote_item->data) {
845 * the arguments following the command must be separated from the
846 * command with a space so we can check for it unconditionally
848 cp = strchr(sshc->quote_item->data, ' ');
849 if(cp == NULL) {
850 failf(data, "Syntax error in SFTP command. Supply parameter(s)!");
851 state(conn, SSH_SFTP_CLOSE);
852 sshc->actualcode = CURLE_QUOTE_ERROR;
853 break;
857 * also, every command takes at least one argument so we get that
858 * first argument right now
860 result = get_pathname(&cp, &sshc->quote_path1);
861 if(result) {
862 if(result == CURLE_OUT_OF_MEMORY)
863 failf(data, "Out of memory");
864 else
865 failf(data, "Syntax error: Bad first parameter");
866 state(conn, SSH_SFTP_CLOSE);
867 sshc->actualcode = result;
868 break;
872 * SFTP is a binary protocol, so we don't send text commands to
873 * the server. Instead, we scan for commands for commands used by
874 * OpenSSH's sftp program and call the appropriate libssh2
875 * functions.
877 if(curl_strnequal(sshc->quote_item->data, "chgrp ", 6) ||
878 curl_strnequal(sshc->quote_item->data, "chmod ", 6) ||
879 curl_strnequal(sshc->quote_item->data, "chown ", 6) ) {
880 /* attribute change */
882 /* sshc->quote_path1 contains the mode to set */
883 /* get the destination */
884 result = get_pathname(&cp, &sshc->quote_path2);
885 if(result) {
886 if(result == CURLE_OUT_OF_MEMORY)
887 failf(data, "Out of memory");
888 else
889 failf(data, "Syntax error in chgrp/chmod/chown: "
890 "Bad second parameter");
891 Curl_safefree(sshc->quote_path1);
892 sshc->quote_path1 = NULL;
893 state(conn, SSH_SFTP_CLOSE);
894 sshc->actualcode = result;
895 break;
897 memset(&sshc->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
898 state(conn, SSH_SFTP_QUOTE_STAT);
899 break;
901 else if(curl_strnequal(sshc->quote_item->data, "ln ", 3) ||
902 curl_strnequal(sshc->quote_item->data, "symlink ", 8)) {
903 /* symbolic linking */
904 /* sshc->quote_path1 is the source */
905 /* get the destination */
906 result = get_pathname(&cp, &sshc->quote_path2);
907 if(result) {
908 if(result == CURLE_OUT_OF_MEMORY)
909 failf(data, "Out of memory");
910 else
911 failf(data,
912 "Syntax error in ln/symlink: Bad second parameter");
913 Curl_safefree(sshc->quote_path1);
914 sshc->quote_path1 = NULL;
915 state(conn, SSH_SFTP_CLOSE);
916 sshc->actualcode = result;
917 break;
919 state(conn, SSH_SFTP_QUOTE_SYMLINK);
920 break;
922 else if(curl_strnequal(sshc->quote_item->data, "mkdir ", 6)) {
923 /* create dir */
924 state(conn, SSH_SFTP_QUOTE_MKDIR);
925 break;
927 else if(curl_strnequal(sshc->quote_item->data, "rename ", 7)) {
928 /* rename file */
929 /* first param is the source path */
930 /* second param is the dest. path */
931 result = get_pathname(&cp, &sshc->quote_path2);
932 if(result) {
933 if(result == CURLE_OUT_OF_MEMORY)
934 failf(data, "Out of memory");
935 else
936 failf(data, "Syntax error in rename: Bad second parameter");
937 Curl_safefree(sshc->quote_path1);
938 sshc->quote_path1 = NULL;
939 state(conn, SSH_SFTP_CLOSE);
940 sshc->actualcode = result;
941 break;
943 state(conn, SSH_SFTP_QUOTE_RENAME);
944 break;
946 else if(curl_strnequal(sshc->quote_item->data, "rmdir ", 6)) {
947 /* delete dir */
948 state(conn, SSH_SFTP_QUOTE_RMDIR);
949 break;
951 else if(curl_strnequal(sshc->quote_item->data, "rm ", 3)) {
952 state(conn, SSH_SFTP_QUOTE_UNLINK);
953 break;
956 failf(data, "Unknown SFTP command");
957 Curl_safefree(sshc->quote_path1);
958 sshc->quote_path1 = NULL;
959 Curl_safefree(sshc->quote_path2);
960 sshc->quote_path2 = NULL;
961 state(conn, SSH_SFTP_CLOSE);
962 sshc->actualcode = CURLE_QUOTE_ERROR;
963 break;
966 if(!sshc->quote_item) {
967 state(conn, SSH_SFTP_TRANS_INIT);
969 break;
971 case SSH_SFTP_NEXT_QUOTE:
972 if(sshc->quote_path1) {
973 Curl_safefree(sshc->quote_path1);
974 sshc->quote_path1 = NULL;
976 if(sshc->quote_path2) {
977 Curl_safefree(sshc->quote_path2);
978 sshc->quote_path2 = NULL;
981 sshc->quote_item = sshc->quote_item->next;
983 if(sshc->quote_item) {
984 state(conn, SSH_SFTP_QUOTE);
986 else {
987 if(sshc->nextstate != SSH_NO_STATE) {
988 state(conn, sshc->nextstate);
989 sshc->nextstate = SSH_NO_STATE;
991 else {
992 state(conn, SSH_SFTP_TRANS_INIT);
995 break;
997 case SSH_SFTP_QUOTE_STAT:
998 if(!curl_strnequal(sshc->quote_item->data, "chmod", 5)) {
999 /* Since chown and chgrp only set owner OR group but libssh2 wants to
1000 * set them both at once, we need to obtain the current ownership first.
1001 * This takes an extra protocol round trip.
1003 rc = libssh2_sftp_stat(sshc->sftp_session, sshc->quote_path2,
1004 &sshc->quote_attrs);
1005 if(rc == LIBSSH2_ERROR_EAGAIN) {
1006 break;
1008 else if(rc != 0) { /* get those attributes */
1009 err = libssh2_sftp_last_error(sshc->sftp_session);
1010 Curl_safefree(sshc->quote_path1);
1011 sshc->quote_path1 = NULL;
1012 Curl_safefree(sshc->quote_path2);
1013 sshc->quote_path2 = NULL;
1014 failf(data, "Attempt to get SFTP stats failed: %s",
1015 sftp_libssh2_strerror(err));
1016 state(conn, SSH_SFTP_CLOSE);
1017 sshc->actualcode = CURLE_QUOTE_ERROR;
1018 break;
1022 /* Now set the new attributes... */
1023 if(curl_strnequal(sshc->quote_item->data, "chgrp", 5)) {
1024 sshc->quote_attrs.gid = strtol(sshc->quote_path1, NULL, 10);
1025 sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
1026 if(sshc->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0])) {
1027 Curl_safefree(sshc->quote_path1);
1028 sshc->quote_path1 = NULL;
1029 Curl_safefree(sshc->quote_path2);
1030 sshc->quote_path2 = NULL;
1031 failf(data, "Syntax error: chgrp gid not a number");
1032 state(conn, SSH_SFTP_CLOSE);
1033 sshc->actualcode = CURLE_QUOTE_ERROR;
1034 break;
1037 else if(curl_strnequal(sshc->quote_item->data, "chmod", 5)) {
1038 sshc->quote_attrs.permissions = strtol(sshc->quote_path1, NULL, 8);
1039 sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS;
1040 /* permissions are octal */
1041 if(sshc->quote_attrs.permissions == 0 &&
1042 !ISDIGIT(sshc->quote_path1[0])) {
1043 Curl_safefree(sshc->quote_path1);
1044 sshc->quote_path1 = NULL;
1045 Curl_safefree(sshc->quote_path2);
1046 sshc->quote_path2 = NULL;
1047 failf(data, "Syntax error: chmod permissions not a number");
1048 state(conn, SSH_SFTP_CLOSE);
1049 sshc->actualcode = CURLE_QUOTE_ERROR;
1050 break;
1053 else if(curl_strnequal(sshc->quote_item->data, "chown", 5)) {
1054 sshc->quote_attrs.uid = strtol(sshc->quote_path1, NULL, 10);
1055 sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
1056 if(sshc->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0])) {
1057 Curl_safefree(sshc->quote_path1);
1058 sshc->quote_path1 = NULL;
1059 Curl_safefree(sshc->quote_path2);
1060 sshc->quote_path2 = NULL;
1061 failf(data, "Syntax error: chown uid not a number");
1062 state(conn, SSH_SFTP_CLOSE);
1063 sshc->actualcode = CURLE_QUOTE_ERROR;
1064 break;
1068 /* Now send the completed structure... */
1069 state(conn, SSH_SFTP_QUOTE_SETSTAT);
1070 break;
1072 case SSH_SFTP_QUOTE_SETSTAT:
1073 rc = libssh2_sftp_setstat(sshc->sftp_session, sshc->quote_path2,
1074 &sshc->quote_attrs);
1075 if(rc == LIBSSH2_ERROR_EAGAIN) {
1076 break;
1078 else if(rc != 0) {
1079 err = libssh2_sftp_last_error(sshc->sftp_session);
1080 Curl_safefree(sshc->quote_path1);
1081 sshc->quote_path1 = NULL;
1082 Curl_safefree(sshc->quote_path2);
1083 sshc->quote_path2 = NULL;
1084 failf(data, "Attempt to set SFTP stats failed: %s",
1085 sftp_libssh2_strerror(err));
1086 state(conn, SSH_SFTP_CLOSE);
1087 sshc->actualcode = CURLE_QUOTE_ERROR;
1088 break;
1090 state(conn, SSH_SFTP_NEXT_QUOTE);
1091 break;
1093 case SSH_SFTP_QUOTE_SYMLINK:
1094 rc = libssh2_sftp_symlink(sshc->sftp_session, sshc->quote_path1,
1095 sshc->quote_path2);
1096 if(rc == LIBSSH2_ERROR_EAGAIN) {
1097 break;
1099 else if(rc != 0) {
1100 err = libssh2_sftp_last_error(sshc->sftp_session);
1101 Curl_safefree(sshc->quote_path1);
1102 sshc->quote_path1 = NULL;
1103 Curl_safefree(sshc->quote_path2);
1104 sshc->quote_path2 = NULL;
1105 failf(data, "symlink command failed: %s",
1106 sftp_libssh2_strerror(err));
1107 state(conn, SSH_SFTP_CLOSE);
1108 sshc->actualcode = CURLE_QUOTE_ERROR;
1109 break;
1111 state(conn, SSH_SFTP_NEXT_QUOTE);
1112 break;
1114 case SSH_SFTP_QUOTE_MKDIR:
1115 rc = libssh2_sftp_mkdir(sshc->sftp_session, sshc->quote_path1, 0755);
1116 if(rc == LIBSSH2_ERROR_EAGAIN) {
1117 break;
1119 else if(rc != 0) {
1120 err = libssh2_sftp_last_error(sshc->sftp_session);
1121 Curl_safefree(sshc->quote_path1);
1122 sshc->quote_path1 = NULL;
1123 failf(data, "mkdir command failed: %s", sftp_libssh2_strerror(err));
1124 state(conn, SSH_SFTP_CLOSE);
1125 sshc->actualcode = CURLE_QUOTE_ERROR;
1126 break;
1128 state(conn, SSH_SFTP_NEXT_QUOTE);
1129 break;
1131 case SSH_SFTP_QUOTE_RENAME:
1132 rc = libssh2_sftp_rename(sshc->sftp_session, sshc->quote_path1,
1133 sshc->quote_path2);
1134 if(rc == LIBSSH2_ERROR_EAGAIN) {
1135 break;
1137 else if(rc != 0) {
1138 err = libssh2_sftp_last_error(sshc->sftp_session);
1139 Curl_safefree(sshc->quote_path1);
1140 sshc->quote_path1 = NULL;
1141 Curl_safefree(sshc->quote_path2);
1142 sshc->quote_path2 = NULL;
1143 failf(data, "rename command failed: %s", sftp_libssh2_strerror(err));
1144 state(conn, SSH_SFTP_CLOSE);
1145 sshc->actualcode = CURLE_QUOTE_ERROR;
1146 break;
1148 state(conn, SSH_SFTP_NEXT_QUOTE);
1149 break;
1151 case SSH_SFTP_QUOTE_RMDIR:
1152 rc = libssh2_sftp_rmdir(sshc->sftp_session, sshc->quote_path1);
1153 if(rc == LIBSSH2_ERROR_EAGAIN) {
1154 break;
1156 else if(rc != 0) {
1157 err = libssh2_sftp_last_error(sshc->sftp_session);
1158 Curl_safefree(sshc->quote_path1);
1159 sshc->quote_path1 = NULL;
1160 failf(data, "rmdir command failed: %s", sftp_libssh2_strerror(err));
1161 state(conn, SSH_SFTP_CLOSE);
1162 sshc->actualcode = CURLE_QUOTE_ERROR;
1163 break;
1165 state(conn, SSH_SFTP_NEXT_QUOTE);
1166 break;
1168 case SSH_SFTP_QUOTE_UNLINK:
1169 rc = libssh2_sftp_unlink(sshc->sftp_session, sshc->quote_path1);
1170 if(rc == LIBSSH2_ERROR_EAGAIN) {
1171 break;
1173 else if(rc != 0) {
1174 err = libssh2_sftp_last_error(sshc->sftp_session);
1175 Curl_safefree(sshc->quote_path1);
1176 sshc->quote_path1 = NULL;
1177 failf(data, "rm command failed: %s", sftp_libssh2_strerror(err));
1178 state(conn, SSH_SFTP_CLOSE);
1179 sshc->actualcode = CURLE_QUOTE_ERROR;
1180 break;
1182 state(conn, SSH_SFTP_NEXT_QUOTE);
1183 break;
1185 case SSH_SFTP_TRANS_INIT:
1186 if(data->set.upload)
1187 state(conn, SSH_SFTP_UPLOAD_INIT);
1188 else {
1189 if(data->set.opt_no_body)
1190 state(conn, SSH_STOP);
1191 else if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/')
1192 state(conn, SSH_SFTP_READDIR_INIT);
1193 else
1194 state(conn, SSH_SFTP_DOWNLOAD_INIT);
1196 break;
1198 case SSH_SFTP_UPLOAD_INIT:
1200 unsigned long flags;
1202 * NOTE!!! libssh2 requires that the destination path is a full path
1203 * that includes the destination file and name OR ends in a "/"
1204 * If this is not done the destination file will be named the
1205 * same name as the last directory in the path.
1208 if(data->state.resume_from != 0) {
1209 LIBSSH2_SFTP_ATTRIBUTES attrs;
1210 if(data->state.resume_from< 0) {
1211 rc = libssh2_sftp_stat(sshc->sftp_session, sftp_scp->path, &attrs);
1212 if(rc == LIBSSH2_ERROR_EAGAIN) {
1213 break;
1215 else if(rc) {
1216 data->state.resume_from = 0;
1218 else {
1219 data->state.resume_from = attrs.filesize;
1224 if(data->set.ftp_append)
1225 /* Try to open for append, but create if nonexisting */
1226 flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_APPEND;
1227 else if (data->state.resume_from > 0)
1228 /* If we have restart position then open for append */
1229 flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_APPEND;
1230 else
1231 /* Clear file before writing (normal behaviour) */
1232 flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC;
1234 sshc->sftp_handle =
1235 libssh2_sftp_open(sshc->sftp_session, sftp_scp->path,
1236 flags, data->set.new_file_perms);
1238 if(!sshc->sftp_handle) {
1239 if(libssh2_session_last_errno(sshc->ssh_session) ==
1240 LIBSSH2_ERROR_EAGAIN) {
1241 break;
1243 else {
1244 err = libssh2_sftp_last_error(sshc->sftp_session);
1245 if(sshc->secondCreateDirs) {
1246 state(conn, SSH_SFTP_CLOSE);
1247 sshc->actualcode = sftp_libssh2_error_to_CURLE(err);
1248 failf(data, "Creating the dir/file failed: %s",
1249 sftp_libssh2_strerror(err));
1250 break;
1252 else if(((err == LIBSSH2_FX_NO_SUCH_FILE) ||
1253 (err == LIBSSH2_FX_FAILURE) ||
1254 (err == LIBSSH2_FX_NO_SUCH_PATH)) &&
1255 (data->set.ftp_create_missing_dirs &&
1256 (strlen(sftp_scp->path) > 1))) {
1257 /* try to create the path remotely */
1258 sshc->secondCreateDirs = 1;
1259 state(conn, SSH_SFTP_CREATE_DIRS_INIT);
1260 break;
1262 state(conn, SSH_SFTP_CLOSE);
1263 sshc->actualcode = sftp_libssh2_error_to_CURLE(err);
1264 failf(data, "Upload failed: %s", sftp_libssh2_strerror(err));
1265 break;
1269 /* If we have restart point then we need to seek to the correct position. */
1270 if(data->state.resume_from > 0) {
1271 /* Let's read off the proper amount of bytes from the input. */
1272 if(conn->seek_func) {
1273 curl_off_t readthisamountnow = data->state.resume_from;
1275 if(conn->seek_func(conn->seek_client,
1276 readthisamountnow, SEEK_SET) != 0) {
1277 failf(data, "Could not seek stream");
1278 return CURLE_FTP_COULDNT_USE_REST;
1281 else {
1282 curl_off_t passed=0;
1283 curl_off_t readthisamountnow;
1284 curl_off_t actuallyread;
1285 do {
1286 readthisamountnow = (data->state.resume_from - passed);
1288 if(readthisamountnow > BUFSIZE)
1289 readthisamountnow = BUFSIZE;
1291 actuallyread =
1292 (curl_off_t) conn->fread_func(data->state.buffer, 1,
1293 (size_t)readthisamountnow,
1294 conn->fread_in);
1296 passed += actuallyread;
1297 if((actuallyread <= 0) || (actuallyread > readthisamountnow)) {
1298 /* this checks for greater-than only to make sure that the
1299 CURL_READFUNC_ABORT return code still aborts */
1300 failf(data, "Failed to read data");
1301 return CURLE_FTP_COULDNT_USE_REST;
1303 } while(passed < data->state.resume_from);
1306 /* now, decrease the size of the read */
1307 if(data->set.infilesize>0) {
1308 data->set.infilesize -= data->state.resume_from;
1309 data->req.size = data->set.infilesize;
1310 Curl_pgrsSetUploadSize(data, data->set.infilesize);
1313 libssh2_sftp_seek(sshc->sftp_handle, data->state.resume_from);
1315 if(data->set.infilesize>0) {
1316 data->req.size = data->set.infilesize;
1317 Curl_pgrsSetUploadSize(data, data->set.infilesize);
1319 /* upload data */
1320 result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL,
1321 FIRSTSOCKET, NULL);
1323 if(result) {
1324 state(conn, SSH_SFTP_CLOSE);
1325 sshc->actualcode = result;
1327 else {
1328 state(conn, SSH_STOP);
1330 break;
1333 case SSH_SFTP_CREATE_DIRS_INIT:
1334 if(strlen(sftp_scp->path) > 1) {
1335 sshc->slash_pos = sftp_scp->path + 1; /* ignore the leading '/' */
1336 state(conn, SSH_SFTP_CREATE_DIRS);
1338 else {
1339 state(conn, SSH_SFTP_UPLOAD_INIT);
1341 break;
1343 case SSH_SFTP_CREATE_DIRS:
1344 if((sshc->slash_pos = strchr(sshc->slash_pos, '/')) != NULL) {
1345 *sshc->slash_pos = 0;
1347 infof(data, "Creating directory '%s'\n", sftp_scp->path);
1348 state(conn, SSH_SFTP_CREATE_DIRS_MKDIR);
1349 break;
1351 else {
1352 state(conn, SSH_SFTP_UPLOAD_INIT);
1354 break;
1356 case SSH_SFTP_CREATE_DIRS_MKDIR:
1357 /* 'mode' - parameter is preliminary - default to 0644 */
1358 rc = libssh2_sftp_mkdir(sshc->sftp_session, sftp_scp->path,
1359 data->set.new_directory_perms);
1360 if(rc == LIBSSH2_ERROR_EAGAIN) {
1361 break;
1363 *sshc->slash_pos = '/';
1364 ++sshc->slash_pos;
1365 if(rc == -1) {
1366 unsigned int sftp_err = 0;
1368 * abort if failure wasn't that the dir already exists or the
1369 * permission was denied (creation might succeed further
1370 * down the path) - retry on unspecific FAILURE also
1372 sftp_err = libssh2_sftp_last_error(sshc->sftp_session);
1373 if((sftp_err != LIBSSH2_FX_FILE_ALREADY_EXISTS) &&
1374 (sftp_err != LIBSSH2_FX_FAILURE) &&
1375 (sftp_err != LIBSSH2_FX_PERMISSION_DENIED)) {
1376 result = sftp_libssh2_error_to_CURLE(sftp_err);
1377 state(conn, SSH_SFTP_CLOSE);
1378 sshc->actualcode = result;
1379 break;
1382 state(conn, SSH_SFTP_CREATE_DIRS);
1383 break;
1385 case SSH_SFTP_READDIR_INIT:
1387 * This is a directory that we are trying to get, so produce a
1388 * directory listing
1390 sshc->sftp_handle = libssh2_sftp_opendir(sshc->sftp_session,
1391 sftp_scp->path);
1392 if(!sshc->sftp_handle) {
1393 if(libssh2_session_last_errno(sshc->ssh_session) ==
1394 LIBSSH2_ERROR_EAGAIN) {
1395 break;
1397 else {
1398 err = libssh2_sftp_last_error(sshc->sftp_session);
1399 failf(data, "Could not open directory for reading: %s",
1400 sftp_libssh2_strerror(err));
1401 state(conn, SSH_SFTP_CLOSE);
1402 sshc->actualcode = sftp_libssh2_error_to_CURLE(err);
1403 break;
1406 if((sshc->readdir_filename = (char *)malloc(PATH_MAX+1)) == NULL) {
1407 state(conn, SSH_SFTP_CLOSE);
1408 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1409 break;
1411 if((sshc->readdir_longentry = (char *)malloc(PATH_MAX+1)) == NULL) {
1412 Curl_safefree(sshc->readdir_filename);
1413 sshc->readdir_filename = NULL;
1414 state(conn, SSH_SFTP_CLOSE);
1415 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1416 break;
1418 state(conn, SSH_SFTP_READDIR);
1419 break;
1421 case SSH_SFTP_READDIR:
1422 sshc->readdir_len = libssh2_sftp_readdir_ex(sshc->sftp_handle,
1423 sshc->readdir_filename,
1424 PATH_MAX,
1425 sshc->readdir_longentry,
1426 PATH_MAX,
1427 &sshc->readdir_attrs);
1428 if(sshc->readdir_len == LIBSSH2_ERROR_EAGAIN) {
1429 break;
1431 if(sshc->readdir_len > 0) {
1432 sshc->readdir_filename[sshc->readdir_len] = '\0';
1434 if(data->set.ftp_list_only) {
1435 char *tmpLine;
1437 tmpLine = aprintf("%s\n", sshc->readdir_filename);
1438 if(tmpLine == NULL) {
1439 state(conn, SSH_SFTP_CLOSE);
1440 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1441 break;
1443 result = Curl_client_write(conn, CLIENTWRITE_BODY,
1444 tmpLine, sshc->readdir_len+1);
1445 Curl_safefree(tmpLine);
1447 if(result) {
1448 state(conn, SSH_STOP);
1449 break;
1451 /* since this counts what we send to the client, we include the newline
1452 in this counter */
1453 data->req.bytecount += sshc->readdir_len+1;
1455 /* output debug output if that is requested */
1456 if(data->set.verbose) {
1457 Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_filename,
1458 sshc->readdir_len, conn);
1461 else {
1462 sshc->readdir_currLen = strlen(sshc->readdir_longentry);
1463 sshc->readdir_totalLen = 80 + sshc->readdir_currLen;
1464 sshc->readdir_line = (char *)calloc(sshc->readdir_totalLen, 1);
1465 if(!sshc->readdir_line) {
1466 Curl_safefree(sshc->readdir_filename);
1467 sshc->readdir_filename = NULL;
1468 Curl_safefree(sshc->readdir_longentry);
1469 sshc->readdir_longentry = NULL;
1470 state(conn, SSH_SFTP_CLOSE);
1471 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1472 break;
1475 memcpy(sshc->readdir_line, sshc->readdir_longentry,
1476 sshc->readdir_currLen);
1477 if((sshc->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
1478 ((sshc->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
1479 LIBSSH2_SFTP_S_IFLNK)) {
1480 sshc->readdir_linkPath = (char *)malloc(PATH_MAX + 1);
1481 if(sshc->readdir_linkPath == NULL) {
1482 Curl_safefree(sshc->readdir_filename);
1483 sshc->readdir_filename = NULL;
1484 Curl_safefree(sshc->readdir_longentry);
1485 sshc->readdir_longentry = NULL;
1486 state(conn, SSH_SFTP_CLOSE);
1487 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1488 break;
1491 snprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", sftp_scp->path,
1492 sshc->readdir_filename);
1493 state(conn, SSH_SFTP_READDIR_LINK);
1494 break;
1496 state(conn, SSH_SFTP_READDIR_BOTTOM);
1497 break;
1500 else if(sshc->readdir_len == 0) {
1501 Curl_safefree(sshc->readdir_filename);
1502 sshc->readdir_filename = NULL;
1503 Curl_safefree(sshc->readdir_longentry);
1504 sshc->readdir_longentry = NULL;
1505 state(conn, SSH_SFTP_READDIR_DONE);
1506 break;
1508 else if(sshc->readdir_len <= 0) {
1509 err = libssh2_sftp_last_error(sshc->sftp_session);
1510 sshc->actualcode = sftp_libssh2_error_to_CURLE(err);
1511 failf(data, "Could not open remote file for reading: %s :: %d",
1512 sftp_libssh2_strerror(err),
1513 libssh2_session_last_errno(sshc->ssh_session));
1514 Curl_safefree(sshc->readdir_filename);
1515 sshc->readdir_filename = NULL;
1516 Curl_safefree(sshc->readdir_longentry);
1517 sshc->readdir_longentry = NULL;
1518 state(conn, SSH_SFTP_CLOSE);
1519 break;
1521 break;
1523 case SSH_SFTP_READDIR_LINK:
1524 sshc->readdir_len = libssh2_sftp_readlink(sshc->sftp_session,
1525 sshc->readdir_linkPath,
1526 sshc->readdir_filename,
1527 PATH_MAX);
1528 if(sshc->readdir_len == LIBSSH2_ERROR_EAGAIN) {
1529 break;
1531 Curl_safefree(sshc->readdir_linkPath);
1532 sshc->readdir_linkPath = NULL;
1533 sshc->readdir_line = realloc(sshc->readdir_line,
1534 sshc->readdir_totalLen + 4 +
1535 sshc->readdir_len);
1536 if(!sshc->readdir_line) {
1537 Curl_safefree(sshc->readdir_filename);
1538 sshc->readdir_filename = NULL;
1539 Curl_safefree(sshc->readdir_longentry);
1540 sshc->readdir_longentry = NULL;
1541 state(conn, SSH_SFTP_CLOSE);
1542 sshc->actualcode = CURLE_OUT_OF_MEMORY;
1543 break;
1546 sshc->readdir_currLen += snprintf(sshc->readdir_line +
1547 sshc->readdir_currLen,
1548 sshc->readdir_totalLen -
1549 sshc->readdir_currLen,
1550 " -> %s",
1551 sshc->readdir_filename);
1553 state(conn, SSH_SFTP_READDIR_BOTTOM);
1554 break;
1556 case SSH_SFTP_READDIR_BOTTOM:
1557 sshc->readdir_currLen += snprintf(sshc->readdir_line +
1558 sshc->readdir_currLen,
1559 sshc->readdir_totalLen -
1560 sshc->readdir_currLen, "\n");
1561 result = Curl_client_write(conn, CLIENTWRITE_BODY,
1562 sshc->readdir_line,
1563 sshc->readdir_currLen);
1565 if(result == CURLE_OK) {
1567 /* output debug output if that is requested */
1568 if(data->set.verbose) {
1569 Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_line,
1570 sshc->readdir_currLen, conn);
1572 data->req.bytecount += sshc->readdir_currLen;
1574 Curl_safefree(sshc->readdir_line);
1575 sshc->readdir_line = NULL;
1576 if(result) {
1577 state(conn, SSH_STOP);
1579 else
1580 state(conn, SSH_SFTP_READDIR);
1581 break;
1583 case SSH_SFTP_READDIR_DONE:
1584 if(libssh2_sftp_closedir(sshc->sftp_handle) ==
1585 LIBSSH2_ERROR_EAGAIN) {
1586 break;
1588 sshc->sftp_handle = NULL;
1589 Curl_safefree(sshc->readdir_filename);
1590 sshc->readdir_filename = NULL;
1591 Curl_safefree(sshc->readdir_longentry);
1592 sshc->readdir_longentry = NULL;
1594 /* no data to transfer */
1595 result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1596 state(conn, SSH_STOP);
1597 break;
1599 case SSH_SFTP_DOWNLOAD_INIT:
1601 * Work on getting the specified file
1603 sshc->sftp_handle =
1604 libssh2_sftp_open(sshc->sftp_session, sftp_scp->path,
1605 LIBSSH2_FXF_READ, data->set.new_file_perms);
1606 if(!sshc->sftp_handle) {
1607 if(libssh2_session_last_errno(sshc->ssh_session) ==
1608 LIBSSH2_ERROR_EAGAIN) {
1609 break;
1611 else {
1612 err = libssh2_sftp_last_error(sshc->sftp_session);
1613 failf(data, "Could not open remote file for reading: %s",
1614 sftp_libssh2_strerror(err));
1615 state(conn, SSH_SFTP_CLOSE);
1616 sshc->actualcode = sftp_libssh2_error_to_CURLE(err);
1617 break;
1620 state(conn, SSH_SFTP_DOWNLOAD_STAT);
1621 break;
1623 case SSH_SFTP_DOWNLOAD_STAT:
1625 LIBSSH2_SFTP_ATTRIBUTES attrs;
1627 rc = libssh2_sftp_stat(sshc->sftp_session, sftp_scp->path, &attrs);
1628 if(rc == LIBSSH2_ERROR_EAGAIN) {
1629 break;
1631 else if(rc) {
1633 * libssh2_sftp_open() didn't return an error, so maybe the server
1634 * just doesn't support stat()
1636 data->req.size = -1;
1637 data->req.maxdownload = -1;
1639 else {
1640 data->req.size = attrs.filesize;
1641 data->req.maxdownload = attrs.filesize;
1642 Curl_pgrsSetDownloadSize(data, attrs.filesize);
1645 /* We can resume if we can seek to the resume position */
1646 if(data->state.resume_from) {
1647 if(data->state.resume_from< 0) {
1648 /* We're supposed to download the last abs(from) bytes */
1649 if((curl_off_t)attrs.filesize < -data->state.resume_from) {
1650 failf(data, "Offset (%"
1651 FORMAT_OFF_T ") was beyond file size (%" FORMAT_OFF_T ")",
1652 data->state.resume_from, attrs.filesize);
1653 return CURLE_BAD_DOWNLOAD_RESUME;
1655 /* download from where? */
1656 data->state.resume_from = attrs.filesize - data->state.resume_from;
1658 else {
1659 if((curl_off_t)attrs.filesize < data->state.resume_from) {
1660 failf(data, "Offset (%" FORMAT_OFF_T
1661 ") was beyond file size (%" FORMAT_OFF_T ")",
1662 data->state.resume_from, attrs.filesize);
1663 return CURLE_BAD_DOWNLOAD_RESUME;
1666 /* Does a completed file need to be seeked and started or closed ? */
1667 /* Now store the number of bytes we are expected to download */
1668 data->req.size = attrs.filesize - data->state.resume_from;
1669 data->req.maxdownload = attrs.filesize - data->state.resume_from;
1670 Curl_pgrsSetDownloadSize(data,
1671 attrs.filesize - data->state.resume_from);
1672 libssh2_sftp_seek(sshc->sftp_handle, data->state.resume_from);
1675 /* Setup the actual download */
1676 if(data->req.size == 0) {
1677 /* no data to transfer */
1678 result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1679 infof(data, "File already completely downloaded\n");
1680 state(conn, SSH_STOP);
1681 break;
1683 else {
1684 result = Curl_setup_transfer(conn, FIRSTSOCKET, data->req.size,
1685 FALSE, NULL, -1, NULL);
1687 if(result) {
1688 state(conn, SSH_SFTP_CLOSE);
1689 sshc->actualcode = result;
1691 else {
1692 state(conn, SSH_STOP);
1694 break;
1696 case SSH_SFTP_CLOSE:
1697 if(sshc->sftp_handle) {
1698 rc = libssh2_sftp_close(sshc->sftp_handle);
1699 if(rc == LIBSSH2_ERROR_EAGAIN) {
1700 break;
1702 else if(rc < 0) {
1703 infof(data, "Failed to close libssh2 file\n");
1705 sshc->sftp_handle = NULL;
1707 Curl_safefree(sftp_scp->path);
1708 sftp_scp->path = NULL;
1710 DEBUGF(infof(data, "SFTP DONE done\n"));
1711 #if 0 /* PREV */
1712 state(conn, SSH_SFTP_SHUTDOWN);
1713 #endif
1714 state(conn, SSH_STOP);
1715 result = sshc->actualcode;
1716 break;
1718 case SSH_SFTP_SHUTDOWN:
1719 /* during times we get here due to a broken transfer and then the
1720 sftp_handle might not have been taken down so make sure that is done
1721 before we proceed */
1723 if(sshc->sftp_handle) {
1724 rc = libssh2_sftp_close(sshc->sftp_handle);
1725 if(rc == LIBSSH2_ERROR_EAGAIN) {
1726 break;
1728 else if(rc < 0) {
1729 infof(data, "Failed to close libssh2 file\n");
1731 sshc->sftp_handle = NULL;
1733 if(sshc->sftp_session) {
1734 rc = libssh2_sftp_shutdown(sshc->sftp_session);
1735 if(rc == LIBSSH2_ERROR_EAGAIN) {
1736 break;
1738 else if(rc < 0) {
1739 infof(data, "Failed to stop libssh2 sftp subsystem\n");
1741 sshc->sftp_session = NULL;
1744 Curl_safefree(sshc->homedir);
1745 sshc->homedir = NULL;
1747 state(conn, SSH_SESSION_DISCONNECT);
1748 break;
1750 case SSH_SCP_TRANS_INIT:
1751 result = ssh_getworkingpath(conn, sshc->homedir, &sftp_scp->path);
1752 if(result) {
1753 sshc->actualcode = result;
1754 state(conn, SSH_STOP);
1755 break;
1758 if(data->set.upload) {
1759 if(data->set.infilesize < 0) {
1760 failf(data, "SCP requires a known file size for upload");
1761 sshc->actualcode = CURLE_UPLOAD_FAILED;
1762 state(conn, SSH_SCP_CHANNEL_FREE);
1763 break;
1765 state(conn, SSH_SCP_UPLOAD_INIT);
1767 else {
1768 state(conn, SSH_SCP_DOWNLOAD_INIT);
1770 break;
1772 case SSH_SCP_UPLOAD_INIT:
1774 * libssh2 requires that the destination path is a full path that
1775 * includes the destination file and name OR ends in a "/" . If this is
1776 * not done the destination file will be named the same name as the last
1777 * directory in the path.
1779 sshc->ssh_channel =
1780 libssh2_scp_send_ex(sshc->ssh_session, sftp_scp->path,
1781 data->set.new_file_perms,
1782 data->set.infilesize, 0, 0);
1783 if(!sshc->ssh_channel) {
1784 if(libssh2_session_last_errno(sshc->ssh_session) ==
1785 LIBSSH2_ERROR_EAGAIN) {
1786 break;
1788 else {
1789 int ssh_err;
1790 char *err_msg;
1792 ssh_err = libssh2_session_last_error(sshc->ssh_session,
1793 &err_msg, NULL, 0);
1794 failf(conn->data, "%s", err_msg);
1795 state(conn, SSH_SCP_CHANNEL_FREE);
1796 sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
1797 break;
1801 /* upload data */
1802 result = Curl_setup_transfer(conn, -1, data->req.size, FALSE, NULL,
1803 FIRSTSOCKET, NULL);
1805 if(result) {
1806 state(conn, SSH_SCP_CHANNEL_FREE);
1807 sshc->actualcode = result;
1809 else {
1810 state(conn, SSH_STOP);
1812 break;
1814 case SSH_SCP_DOWNLOAD_INIT:
1817 * We must check the remote file; if it is a directory no values will
1818 * be set in sb
1820 struct stat sb;
1821 curl_off_t bytecount;
1823 /* clear the struct scp recv will fill in */
1824 memset(&sb, 0, sizeof(struct stat));
1826 /* get a fresh new channel from the ssh layer */
1827 sshc->ssh_channel = libssh2_scp_recv(sshc->ssh_session,
1828 sftp_scp->path, &sb);
1829 if(!sshc->ssh_channel) {
1830 if(libssh2_session_last_errno(sshc->ssh_session) ==
1831 LIBSSH2_ERROR_EAGAIN) {
1832 break;
1834 else {
1835 int ssh_err;
1836 char *err_msg;
1838 ssh_err = libssh2_session_last_error(sshc->ssh_session,
1839 &err_msg, NULL, 0);
1840 failf(conn->data, "%s", err_msg);
1841 state(conn, SSH_SCP_CHANNEL_FREE);
1842 sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
1843 break;
1847 /* download data */
1848 bytecount = (curl_off_t)sb.st_size;
1849 data->req.maxdownload = (curl_off_t)sb.st_size;
1850 result = Curl_setup_transfer(conn, FIRSTSOCKET,
1851 bytecount, FALSE, NULL, -1, NULL);
1853 if(result) {
1854 state(conn, SSH_SCP_CHANNEL_FREE);
1855 sshc->actualcode = result;
1857 else
1858 state(conn, SSH_STOP);
1860 break;
1862 case SSH_SCP_DONE:
1863 if(data->set.upload)
1864 state(conn, SSH_SCP_SEND_EOF);
1865 else
1866 state(conn, SSH_SCP_CHANNEL_FREE);
1867 break;
1869 case SSH_SCP_SEND_EOF:
1870 if(sshc->ssh_channel) {
1871 rc = libssh2_channel_send_eof(sshc->ssh_channel);
1872 if(rc == LIBSSH2_ERROR_EAGAIN) {
1873 break;
1875 else if(rc) {
1876 infof(data, "Failed to send libssh2 channel EOF\n");
1879 state(conn, SSH_SCP_WAIT_EOF);
1880 break;
1882 case SSH_SCP_WAIT_EOF:
1883 if(sshc->ssh_channel) {
1884 rc = libssh2_channel_wait_eof(sshc->ssh_channel);
1885 if(rc == LIBSSH2_ERROR_EAGAIN) {
1886 break;
1888 else if(rc) {
1889 infof(data, "Failed to get channel EOF: %d\n", rc);
1892 state(conn, SSH_SCP_WAIT_CLOSE);
1893 break;
1895 case SSH_SCP_WAIT_CLOSE:
1896 if(sshc->ssh_channel) {
1897 rc = libssh2_channel_wait_closed(sshc->ssh_channel);
1898 if(rc == LIBSSH2_ERROR_EAGAIN) {
1899 break;
1901 else if(rc) {
1902 infof(data, "Channel failed to close: %d\n", rc);
1905 state(conn, SSH_SCP_CHANNEL_FREE);
1906 break;
1908 case SSH_SCP_CHANNEL_FREE:
1909 if(sshc->ssh_channel) {
1910 rc = libssh2_channel_free(sshc->ssh_channel);
1911 if(rc == LIBSSH2_ERROR_EAGAIN) {
1912 break;
1914 else if(rc < 0) {
1915 infof(data, "Failed to free libssh2 scp subsystem\n");
1917 sshc->ssh_channel = NULL;
1919 DEBUGF(infof(data, "SCP DONE phase complete\n"));
1920 #if 0 /* PREV */
1921 state(conn, SSH_SESSION_DISCONNECT);
1922 #endif
1923 state(conn, SSH_STOP);
1924 result = sshc->actualcode;
1925 break;
1927 case SSH_SESSION_DISCONNECT:
1928 /* during weird times when we've been prematurely aborted, the channel
1929 is still alive when we reach this state and we MUST kill the channel
1930 properly first */
1931 if(sshc->ssh_channel) {
1932 rc = libssh2_channel_free(sshc->ssh_channel);
1933 if(rc == LIBSSH2_ERROR_EAGAIN) {
1934 break;
1936 else if(rc < 0) {
1937 infof(data, "Failed to free libssh2 scp subsystem\n");
1939 sshc->ssh_channel = NULL;
1942 if(sshc->ssh_session) {
1943 rc = libssh2_session_disconnect(sshc->ssh_session, "Shutdown");
1944 if(rc == LIBSSH2_ERROR_EAGAIN) {
1945 break;
1947 else if(rc < 0) {
1948 infof(data, "Failed to disconnect libssh2 session\n");
1952 Curl_safefree(sshc->homedir);
1953 sshc->homedir = NULL;
1955 state(conn, SSH_SESSION_FREE);
1956 break;
1958 case SSH_SESSION_FREE:
1959 if(sshc->ssh_session) {
1960 rc = libssh2_session_free(sshc->ssh_session);
1961 if(rc == LIBSSH2_ERROR_EAGAIN) {
1962 break;
1964 else if(rc < 0) {
1965 infof(data, "Failed to free libssh2 session\n");
1967 sshc->ssh_session = NULL;
1969 sshc->nextstate = SSH_NO_STATE;
1970 state(conn, SSH_STOP);
1971 result = sshc->actualcode;
1972 break;
1974 case SSH_QUIT:
1975 /* fallthrough, just stop! */
1976 default:
1977 /* internal error */
1978 sshc->nextstate = SSH_NO_STATE;
1979 state(conn, SSH_STOP);
1980 break;
1983 return result;
1986 /* called repeatedly until done from multi.c */
1987 static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done)
1989 struct ssh_conn *sshc = &conn->proto.sshc;
1990 CURLcode result = CURLE_OK;
1992 result = ssh_statemach_act(conn);
1993 *done = (bool)(sshc->state == SSH_STOP);
1995 return result;
1998 static CURLcode ssh_easy_statemach(struct connectdata *conn)
2000 struct ssh_conn *sshc = &conn->proto.sshc;
2001 CURLcode result = CURLE_OK;
2003 while((sshc->state != SSH_STOP) && !result)
2004 result = ssh_statemach_act(conn);
2006 return result;
2010 * SSH setup and connection
2012 static CURLcode ssh_init(struct connectdata *conn)
2014 struct SessionHandle *data = conn->data;
2015 struct SSHPROTO *ssh;
2016 struct ssh_conn *sshc = &conn->proto.sshc;
2018 sshc->actualcode = CURLE_OK; /* reset error code */
2019 sshc->secondCreateDirs =0; /* reset the create dir attempt state variable */
2021 if(data->state.proto.ssh)
2022 return CURLE_OK;
2024 ssh = (struct SSHPROTO *)calloc(sizeof(struct SSHPROTO), 1);
2025 if(!ssh)
2026 return CURLE_OUT_OF_MEMORY;
2028 data->state.proto.ssh = ssh;
2030 return CURLE_OK;
2034 * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to
2035 * do protocol-specific actions at connect-time.
2037 static CURLcode ssh_connect(struct connectdata *conn, bool *done)
2039 #ifdef CURL_LIBSSH2_DEBUG
2040 curl_socket_t sock;
2041 #endif
2042 struct ssh_conn *ssh;
2043 CURLcode result;
2044 struct SessionHandle *data = conn->data;
2046 /* We default to persistent connections. We set this already in this connect
2047 function to make the re-use checks properly be able to check this bit. */
2048 conn->bits.close = FALSE;
2050 /* If there already is a protocol-specific struct allocated for this
2051 sessionhandle, deal with it */
2052 Curl_reset_reqproto(conn);
2054 result = ssh_init(conn);
2055 if(result)
2056 return result;
2058 ssh = &conn->proto.sshc;
2060 #ifdef CURL_LIBSSH2_DEBUG
2061 if(conn->user) {
2062 infof(data, "User: %s\n", conn->user);
2064 if(conn->passwd) {
2065 infof(data, "Password: %s\n", conn->passwd);
2067 sock = conn->sock[FIRSTSOCKET];
2068 #endif /* CURL_LIBSSH2_DEBUG */
2070 ssh->ssh_session = libssh2_session_init_ex(libssh2_malloc, libssh2_free,
2071 libssh2_realloc, conn);
2072 if(ssh->ssh_session == NULL) {
2073 failf(data, "Failure initialising ssh session");
2074 return CURLE_FAILED_INIT;
2077 #ifdef CURL_LIBSSH2_DEBUG
2078 libssh2_trace(ssh->ssh_session, LIBSSH2_TRACE_CONN|LIBSSH2_TRACE_TRANS|
2079 LIBSSH2_TRACE_KEX|LIBSSH2_TRACE_AUTH|LIBSSH2_TRACE_SCP|
2080 LIBSSH2_TRACE_SFTP|LIBSSH2_TRACE_ERROR|
2081 LIBSSH2_TRACE_PUBLICKEY);
2082 infof(data, "SSH socket: %d\n", sock);
2083 #endif /* CURL_LIBSSH2_DEBUG */
2085 state(conn, SSH_S_STARTUP);
2087 if(data->state.used_interface == Curl_if_multi)
2088 result = ssh_multi_statemach(conn, done);
2089 else {
2090 result = ssh_easy_statemach(conn);
2091 if(!result)
2092 *done = TRUE;
2095 return result;
2099 ***********************************************************************
2101 * scp_perform()
2103 * This is the actual DO function for SCP. Get a file according to
2104 * the options previously setup.
2107 static
2108 CURLcode scp_perform(struct connectdata *conn,
2109 bool *connected,
2110 bool *dophase_done)
2112 CURLcode result = CURLE_OK;
2114 DEBUGF(infof(conn->data, "DO phase starts\n"));
2116 *dophase_done = FALSE; /* not done yet */
2118 /* start the first command in the DO phase */
2119 state(conn, SSH_SCP_TRANS_INIT);
2121 /* run the state-machine */
2122 if(conn->data->state.used_interface == Curl_if_multi) {
2123 result = ssh_multi_statemach(conn, dophase_done);
2125 else {
2126 result = ssh_easy_statemach(conn);
2127 *dophase_done = TRUE; /* with the easy interface we are done here */
2129 *connected = conn->bits.tcpconnect;
2131 if(*dophase_done) {
2132 DEBUGF(infof(conn->data, "DO phase is complete\n"));
2135 return result;
2138 /* called from multi.c while DOing */
2139 static CURLcode scp_doing(struct connectdata *conn,
2140 bool *dophase_done)
2142 CURLcode result;
2143 result = ssh_multi_statemach(conn, dophase_done);
2145 if(*dophase_done) {
2146 DEBUGF(infof(conn->data, "DO phase is complete\n"));
2148 return result;
2152 * The DO function is generic for both protocols. There was previously two
2153 * separate ones but this way means less duplicated code.
2156 static CURLcode ssh_do(struct connectdata *conn, bool *done)
2158 CURLcode res;
2159 bool connected = 0;
2160 struct SessionHandle *data = conn->data;
2162 *done = FALSE; /* default to false */
2165 Since connections can be re-used between SessionHandles, this might be a
2166 connection already existing but on a fresh SessionHandle struct so we must
2167 make sure we have a good 'struct SSHPROTO' to play with. For new
2168 connections, the struct SSHPROTO is allocated and setup in the
2169 ssh_connect() function.
2171 Curl_reset_reqproto(conn);
2172 res = ssh_init(conn);
2173 if(res)
2174 return res;
2176 data->req.size = -1; /* make sure this is unknown at this point */
2178 Curl_pgrsSetUploadCounter(data, 0);
2179 Curl_pgrsSetDownloadCounter(data, 0);
2180 Curl_pgrsSetUploadSize(data, 0);
2181 Curl_pgrsSetDownloadSize(data, 0);
2183 if(conn->protocol & PROT_SCP)
2184 res = scp_perform(conn, &connected, done);
2185 else
2186 res = sftp_perform(conn, &connected, done);
2188 return res;
2191 /* BLOCKING, but the function is using the state machine so the only reason this
2192 is still blocking is that the multi interface code has no support for
2193 disconnecting operations that takes a while */
2194 static CURLcode scp_disconnect(struct connectdata *conn)
2196 CURLcode result = CURLE_OK;
2198 Curl_safefree(conn->data->state.proto.ssh);
2199 conn->data->state.proto.ssh = NULL;
2201 if(conn->proto.sshc.ssh_session) {
2202 /* only if there's a session still around to use! */
2204 state(conn, SSH_SESSION_DISCONNECT);
2206 result = ssh_easy_statemach(conn);
2209 return result;
2212 /* generic done function for both SCP and SFTP called from their specific
2213 done functions */
2214 static CURLcode ssh_done(struct connectdata *conn, CURLcode status)
2216 CURLcode result = CURLE_OK;
2217 bool done = FALSE;
2219 if(status == CURLE_OK) {
2220 /* run the state-machine */
2221 if(conn->data->state.used_interface == Curl_if_multi) {
2222 result = ssh_multi_statemach(conn, &done);
2224 else {
2225 result = ssh_easy_statemach(conn);
2226 done = TRUE;
2229 else {
2230 result = status;
2231 done = TRUE;
2234 if(done) {
2235 struct SSHPROTO *sftp_scp = conn->data->state.proto.ssh;
2237 Curl_safefree(sftp_scp->path);
2238 sftp_scp->path = NULL;
2239 Curl_pgrsDone(conn);
2242 return result;
2246 static CURLcode scp_done(struct connectdata *conn, CURLcode status,
2247 bool premature)
2249 (void)premature; /* not used */
2251 if(status == CURLE_OK)
2252 state(conn, SSH_SCP_DONE);
2254 return ssh_done(conn, status);
2258 /* return number of received (decrypted) bytes */
2259 ssize_t Curl_scp_send(struct connectdata *conn, int sockindex,
2260 const void *mem, size_t len)
2262 ssize_t nwrite;
2263 (void)sockindex; /* we only support SCP on the fixed known primary socket */
2265 /* libssh2_channel_write() returns int! */
2266 nwrite = (ssize_t)
2267 libssh2_channel_write(conn->proto.sshc.ssh_channel, mem, len);
2268 if(nwrite == LIBSSH2_ERROR_EAGAIN)
2269 return 0;
2271 return nwrite;
2275 * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
2276 * a regular CURLcode value.
2278 ssize_t Curl_scp_recv(struct connectdata *conn, int sockindex,
2279 char *mem, size_t len)
2281 ssize_t nread;
2282 (void)sockindex; /* we only support SCP on the fixed known primary socket */
2284 /* libssh2_channel_read() returns int */
2285 nread = (ssize_t)
2286 libssh2_channel_read(conn->proto.sshc.ssh_channel, mem, len);
2287 return nread;
2291 * =============== SFTP ===============
2295 ***********************************************************************
2297 * sftp_perform()
2299 * This is the actual DO function for SFTP. Get a file/directory according to
2300 * the options previously setup.
2303 static
2304 CURLcode sftp_perform(struct connectdata *conn,
2305 bool *connected,
2306 bool *dophase_done)
2308 CURLcode result = CURLE_OK;
2310 DEBUGF(infof(conn->data, "DO phase starts\n"));
2312 *dophase_done = FALSE; /* not done yet */
2314 /* start the first command in the DO phase */
2315 state(conn, SSH_SFTP_QUOTE_INIT);
2317 /* run the state-machine */
2318 if(conn->data->state.used_interface == Curl_if_multi) {
2319 result = ssh_multi_statemach(conn, dophase_done);
2321 else {
2322 result = ssh_easy_statemach(conn);
2323 *dophase_done = TRUE; /* with the easy interface we are done here */
2325 *connected = conn->bits.tcpconnect;
2327 if(*dophase_done) {
2328 DEBUGF(infof(conn->data, "DO phase is complete\n"));
2331 return result;
2334 /* called from multi.c while DOing */
2335 static CURLcode sftp_doing(struct connectdata *conn,
2336 bool *dophase_done)
2338 CURLcode result;
2339 result = ssh_multi_statemach(conn, dophase_done);
2341 if(*dophase_done) {
2342 DEBUGF(infof(conn->data, "DO phase is complete\n"));
2344 return result;
2347 /* BLOCKING, but the function is using the state machine so the only reason this
2348 is still blocking is that the multi interface code has no support for
2349 disconnecting operations that takes a while */
2350 static CURLcode sftp_disconnect(struct connectdata *conn)
2352 CURLcode result = CURLE_OK;
2354 DEBUGF(infof(conn->data, "SSH DISCONNECT starts now\n"));
2356 Curl_safefree(conn->data->state.proto.ssh);
2357 conn->data->state.proto.ssh = NULL;
2359 if(conn->proto.sshc.ssh_session) {
2360 /* only if there's a session still around to use! */
2361 state(conn, SSH_SFTP_SHUTDOWN);
2362 result = ssh_easy_statemach(conn);
2365 DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n"));
2367 return result;
2371 static CURLcode sftp_done(struct connectdata *conn, CURLcode status,
2372 bool premature)
2374 struct ssh_conn *sshc = &conn->proto.sshc;
2376 if(status == CURLE_OK) {
2377 /* Before we shut down, see if there are any post-quote commands to send: */
2378 if(!status && !premature && conn->data->set.postquote) {
2379 sshc->nextstate = SSH_SFTP_CLOSE;
2380 state(conn, SSH_SFTP_POSTQUOTE_INIT);
2382 else
2383 state(conn, SSH_SFTP_CLOSE);
2385 return ssh_done(conn, status);
2388 /* return number of sent bytes */
2389 ssize_t Curl_sftp_send(struct connectdata *conn, int sockindex,
2390 const void *mem, size_t len)
2392 ssize_t nwrite; /* libssh2_sftp_write() used to return size_t in 0.14
2393 but is changed to ssize_t in 0.15. These days we don't
2394 support libssh2 0.15*/
2395 (void)sockindex;
2397 nwrite = libssh2_sftp_write(conn->proto.sshc.sftp_handle, mem, len);
2398 if(nwrite == LIBSSH2_ERROR_EAGAIN)
2399 return 0;
2401 return nwrite;
2405 * Return number of received (decrypted) bytes
2407 ssize_t Curl_sftp_recv(struct connectdata *conn, int sockindex,
2408 char *mem, size_t len)
2410 ssize_t nread;
2411 (void)sockindex;
2413 nread = libssh2_sftp_read(conn->proto.sshc.sftp_handle, mem, len);
2415 return nread;
2418 /* The get_pathname() function is being borrowed from OpenSSH sftp.c
2419 version 4.6p1. */
2421 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
2423 * Permission to use, copy, modify, and distribute this software for any
2424 * purpose with or without fee is hereby granted, provided that the above
2425 * copyright notice and this permission notice appear in all copies.
2427 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
2428 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
2429 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
2430 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2431 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
2432 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
2433 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2435 static CURLcode
2436 get_pathname(const char **cpp, char **path)
2438 const char *cp = *cpp, *end;
2439 char quot;
2440 u_int i, j;
2441 static const char * const WHITESPACE = " \t\r\n";
2443 cp += strspn(cp, WHITESPACE);
2444 if(!*cp) {
2445 *cpp = cp;
2446 *path = NULL;
2447 return CURLE_QUOTE_ERROR;
2450 *path = malloc(strlen(cp) + 1);
2451 if(*path == NULL)
2452 return CURLE_OUT_OF_MEMORY;
2454 /* Check for quoted filenames */
2455 if(*cp == '\"' || *cp == '\'') {
2456 quot = *cp++;
2458 /* Search for terminating quote, unescape some chars */
2459 for (i = j = 0; i <= strlen(cp); i++) {
2460 if(cp[i] == quot) { /* Found quote */
2461 i++;
2462 (*path)[j] = '\0';
2463 break;
2465 if(cp[i] == '\0') { /* End of string */
2466 /*error("Unterminated quote");*/
2467 goto fail;
2469 if(cp[i] == '\\') { /* Escaped characters */
2470 i++;
2471 if(cp[i] != '\'' && cp[i] != '\"' &&
2472 cp[i] != '\\') {
2473 /*error("Bad escaped character '\\%c'",
2474 cp[i]);*/
2475 goto fail;
2478 (*path)[j++] = cp[i];
2481 if(j == 0) {
2482 /*error("Empty quotes");*/
2483 goto fail;
2485 *cpp = cp + i + strspn(cp + i, WHITESPACE);
2487 else {
2488 /* Read to end of filename */
2489 end = strpbrk(cp, WHITESPACE);
2490 if(end == NULL)
2491 end = strchr(cp, '\0');
2492 *cpp = end + strspn(end, WHITESPACE);
2494 memcpy(*path, cp, end - cp);
2495 (*path)[end - cp] = '\0';
2497 return CURLE_OK;
2499 fail:
2500 Curl_safefree(*path);
2501 *path = NULL;
2502 return CURLE_QUOTE_ERROR;
2506 static const char *sftp_libssh2_strerror(unsigned long err)
2508 switch (err) {
2509 case LIBSSH2_FX_NO_SUCH_FILE:
2510 return "No such file or directory";
2512 case LIBSSH2_FX_PERMISSION_DENIED:
2513 return "Permission denied";
2515 case LIBSSH2_FX_FAILURE:
2516 return "Operation failed";
2518 case LIBSSH2_FX_BAD_MESSAGE:
2519 return "Bad message from SFTP server";
2521 case LIBSSH2_FX_NO_CONNECTION:
2522 return "Not connected to SFTP server";
2524 case LIBSSH2_FX_CONNECTION_LOST:
2525 return "Connection to SFTP server lost";
2527 case LIBSSH2_FX_OP_UNSUPPORTED:
2528 return "Operation not supported by SFTP server";
2530 case LIBSSH2_FX_INVALID_HANDLE:
2531 return "Invalid handle";
2533 case LIBSSH2_FX_NO_SUCH_PATH:
2534 return "No such file or directory";
2536 case LIBSSH2_FX_FILE_ALREADY_EXISTS:
2537 return "File already exists";
2539 case LIBSSH2_FX_WRITE_PROTECT:
2540 return "File is write protected";
2542 case LIBSSH2_FX_NO_MEDIA:
2543 return "No media";
2545 case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM:
2546 return "Disk full";
2548 case LIBSSH2_FX_QUOTA_EXCEEDED:
2549 return "User quota exceeded";
2551 case LIBSSH2_FX_UNKNOWN_PRINCIPLE:
2552 return "Unknown principle";
2554 case LIBSSH2_FX_LOCK_CONFlICT:
2555 return "File lock conflict";
2557 case LIBSSH2_FX_DIR_NOT_EMPTY:
2558 return "Directory not empty";
2560 case LIBSSH2_FX_NOT_A_DIRECTORY:
2561 return "Not a directory";
2563 case LIBSSH2_FX_INVALID_FILENAME:
2564 return "Invalid filename";
2566 case LIBSSH2_FX_LINK_LOOP:
2567 return "Link points to itself";
2569 return "Unknown error in libssh2";
2572 #endif /* USE_LIBSSH2 */