diff -x CVS -x '*~' -x '*.lo' -x '*.o' -p -N lib.orig/sftp.c lib/sftp.c *** lib.orig/sftp.c Thu Jan 1 00:00:00 1970 --- lib/sftp.c Thu May 18 20:49:35 2006 *************** *** 0 **** --- 1,288 ---- + /*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * $Id$ + ***************************************************************************/ + + #include "setup.h" + + #ifndef CURL_DISABLE_SFTP + #include + #include + #include + #include + #include + #include + + #include + #include + + #ifdef HAVE_UNISTD_H + #include + #endif + + #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__) + + #else /* probably some kind of unix */ + #ifdef HAVE_SYS_SOCKET_H + #include + #endif + #include + #ifdef HAVE_NETINET_IN_H + #include + #endif + #ifdef HAVE_ARPA_INET_H + #include + #endif + #ifdef HAVE_UTSNAME_H + #include + #endif + #ifdef HAVE_NETDB_H + #include + #endif + #ifdef VMS + #include + #include + #endif + #endif + + #if (defined(NETWARE) && defined(__NOVELL_LIBC__)) + #undef in_addr_t + #define in_addr_t unsigned long + #endif + + #include + #include "urldata.h" + #include "sendf.h" + #include "easyif.h" /* for Curl_convert_... prototypes */ + + #include "if2ip.h" + #include "hostip.h" + #include "progress.h" + #include "transfer.h" + #include "escape.h" + #include "http.h" /* for HTTP proxy tunnel stuff */ + #include "sftp.h" + + #ifdef HAVE_KRB4 + #include "krb4.h" + #endif + + #include "strtoofft.h" + #include "strequal.h" + #include "sslgen.h" + #include "connect.h" + #include "strerror.h" + #include "memory.h" + #include "inet_ntop.h" + #include "select.h" + #include "parsedate.h" /* for the week day and month names */ + #include "sockaddr.h" /* required for Curl_sockaddr_storage */ + #include "multiif.h" + + #if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) + #include "inet_ntoa_r.h" + #endif + + #define _MPRINTF_REPLACE /* use our functions only */ + #include + + /* The last #include file should be: */ + #ifdef CURLDEBUG + #include "memdebug.h" + #endif + + struct auth_ + { + const char * user; + const char * pw; + } auth; + + static void + kbd_callback (const char *name, int name_len, const char *instruction, + int instruction_len, int num_prompts, + const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, + LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, + void **abstract) + { + #if 0 + printf ("name=%s\n", name); + printf ("name_len=%d\n", name_len); + printf ("instruction=%s\n", instruction); + printf ("instruction_len=%d\n", instruction_len); + printf ("num_prompts=%d\n", num_prompts); + #endif + if (num_prompts == 1) + { + responses[0].text = strdup (auth.pw); + responses[0].length = strlen (auth.pw); + } + return; + } /* kbd_callback */ + + /* + * Curl_sftp_connect() performs SSH followed by SFTP stuff to do at + * connect-time, called from the generic Curl_connect(). + */ + CURLcode Curl_sftp_connect(struct connectdata *conn, bool *done) + { + struct SFTP *sftp; + const char *fingerprint; + const char *authlist; + char *home; + char rsa_pub[PATH_MAX]; + char rsa[PATH_MAX]; + int i; + + sftp = calloc(sizeof(struct SFTP), 1); + if(!sftp) + return CURLE_OUT_OF_MEMORY; + + conn->proto.sftp = sftp; + + sftp->user = conn->user; + sftp->passwd = conn->passwd; + #if 0 + if (sftp->user) + printf ("User: %s\n", sftp->user); + if (sftp->passwd) + printf ("Password: %s\n", sftp->passwd); + #endif + curl_socket_t sock = conn->sock[FIRSTSOCKET]; + sftp->session = libssh2_session_init(); + if (sftp->session == NULL) { + failf(conn->data, "Failure initialising ssh session\n"); + return CURLE_FAILED_INIT; + } + #if 0 + printf ("Socket: %d\n", sock); + #endif + sleep (1); /* Don't know why this is needed, my test program worked without + */ + if (libssh2_session_startup(sftp->session, sock)) { + failf(conn->data, "Failure establishing ssh session\n"); + return CURLE_FAILED_INIT; + } + + /* + * Before we authenticate we should check the hostkey's fingerprint against + * our known hosts. How that is handled (reading from file, whatever) is + * up to us. As for know not much is implemented, besides showing how to + * get the fingerprint. + */ + fingerprint = libssh2_hostkey_hash(sftp->session, + LIBSSH2_HOSTKEY_HASH_MD5); + /* The fingerprint points to static storage (!), don't free() it. */ + #if 0 + for (i = 0; i < 16; i++) { + printf ("%02X ", (unsigned char) fingerprint[i]); + } + printf ("\n"); + #endif + + /* + * Figure out authentication methods + * NB: As soon as we have provided a username to an openssh server we must + * never change it later. Thus, always specify the correct username here, + * even though the libssh2 docs kind of indicate that it should be possible + * to get a 'generic' list (not user-specific) of authentication methods, + * presumably with a blank username. That won't work in my experience. + * So always specify it here. + */ + authlist = libssh2_userauth_list(sftp->session, sftp->user, + strlen(sftp->user)); + /* + * The authlist is a comma-separated list of allowed authentication methods. + * Parse it later, for now just try RSA public key first, if it exists. + */ + home = getenv("HOME"); + if (home != NULL) { + /* FIXME: This stuff is probably elsewhere on Windows. */ + snprintf (rsa_pub, sizeof (rsa_pub), "%s/.ssh/id_rsa.pub", home); + snprintf (rsa, sizeof (rsa), "%s/.ssh/id_rsa", home); + /* The function below checks if the files exists, no need to stat() here.*/ + if (libssh2_userauth_publickey_fromfile(sftp->session, sftp->user, + rsa_pub, rsa, "")) { + /* + * That last empty parameter above is the passphrase. If you have one we + * have to add some more code. + */ + /* Authentication failed. Continue with keyboard-interactive now. */ + auth.user = sftp->user; + auth.pw = sftp->passwd; + if (libssh2_userauth_keyboard_interactive_ex(sftp->session, sftp->user, + strlen(sftp->user), + &kbd_callback)) { + /* No more authentication methods. */ + failf(conn->data, "Authentication failure\n"); + return CURLE_FAILED_INIT; + } + } + } + + /* + * At this point we have an authenticated ssh session. Start sftp subsystem. + */ + sftp->sftp = libssh2_sftp_init(sftp->session); + if (sftp->sftp == NULL) { + failf(conn->data, "Failed to start sftp subsystem\n"); + return CURLE_FAILED_INIT; + } + + /* Next we could maybe establish current directory or something? Should + * probably look at ftp code. E.g. as below: */ + #if 1 + { + char cwd[PATH_MAX]; + int ret; + ret = libssh2_sftp_realpath(sftp->sftp, ".", cwd, sizeof(cwd)); + if (ret < 0) { + failf(conn->data, "Failed to figure out current directory\n"); + } + printf("Current remote directory: %s\n", cwd); + } + #endif + + return CURLE_OK; + } + + CURLcode Curl_sftp_done(struct connectdata *conn, CURLcode status) + { + struct SFTP *sftp; + sftp = conn->proto.sftp; + + if (sftp->sftp) + if (libssh2_sftp_shutdown(sftp->sftp) < 0) + failf(conn->data, "Failed to stop sftp subsystem\n"); + + if (sftp->session) { + libssh2_session_disconnect(sftp->session, "Shutdown"); + libssh2_session_free(sftp->session); + } + + return 0; + } + + CURLcode Curl_sftp(struct connectdata *conn, bool *done) + { + *done = TRUE; + return 0; + } + #endif /* CURL_DISABLE_FTP */ diff -x CVS -x '*~' -x '*.lo' -x '*.o' -p -N lib.orig/sftp.h lib/sftp.h *** lib.orig/sftp.h Thu Jan 1 00:00:00 1970 --- lib/sftp.h Wed May 17 20:22:55 2006 *************** *** 0 **** --- 1,31 ---- + #ifndef __SFTP_H + #define __SFTP_H + + /*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * $Id$ + ***************************************************************************/ + #ifndef CURL_DISABLE_SFTP + CURLcode Curl_sftp_connect(struct connectdata *conn, bool *done); + CURLcode Curl_sftp(struct connectdata *conn, bool *done); + CURLcode Curl_sftp_done(struct connectdata *conn, CURLcode); + #endif + #endif diff -x CVS -x '*~' -x '*.lo' -x '*.o' -p -N lib.orig/url.c lib/url.c *** lib.orig/url.c Mon Oct 9 08:20:17 2006 --- lib/url.c Mon Oct 9 08:16:20 2006 *************** void idn_free (void *ptr); /* prototype *** 128,133 **** --- 128,134 ---- #include "http.h" #include "file.h" #include "ldap.h" + #include "sftp.h" #include "url.h" #include "connect.h" #include "inet_ntop.h" *************** static CURLcode CreateConnection(struct *** 3157,3162 **** --- 3158,3178 ---- " was built with TFTP disabled!"); #endif } + else if (strequal(conn->protostr, "SFTP")) { + #ifndef CURL_DISABLE_SFTP + conn->port = PORT_SSH; + conn->remote_port = PORT_SSH; + conn->protocol |= PROT_SFTP; + conn->curl_connect = Curl_sftp_connect; /* ssh_connect? */ + conn->curl_do = Curl_sftp; + conn->curl_done = Curl_sftp_done; + conn->curl_do_more = (Curl_do_more_func)NULL; /* TBD */ + #else + failf(data, LIBCUR_NAME + " was built with SFTP disoabled, sftp: not supported!"); + return CURLE_UNSUPPORTED_PROTOCOL; + #endif + } else { /* We fell through all checks and thus we don't support the specified protocol */ diff -x CVS -x '*~' -x '*.lo' -x '*.o' -p -N lib.orig/urldata.h lib/urldata.h *** lib.orig/urldata.h Mon Oct 9 08:20:17 2006 --- lib/urldata.h Mon Oct 2 11:42:12 2006 *************** *** 35,40 **** --- 35,41 ---- #define PORT_DICT 2628 #define PORT_LDAP 389 #define PORT_TFTP 69 + #define PORT_SSH 22 #define DICT_MATCH "/MATCH:" #define DICT_MATCH2 "/M:" *************** *** 109,114 **** --- 110,118 ---- # endif #endif + #include + #include + /* Download buffer size, keep it fairly big for speed reasons */ #undef BUFSIZE #define BUFSIZE CURL_MAX_WRITE_SIZE *************** struct ftp_conn { *** 392,397 **** --- 396,412 ---- ftpstate state; /* always use ftp.c:state() to change state! */ }; + struct SFTP { + char *user; + char *passwd; + LIBSSH2_SESSION *session; /* Secure Shell session */ + LIBSSH2_SFTP *sftp; /* SFTP subsystem handle */ + }; + + + + + /**************************************************************************** * FILE unique setup ***************************************************************************/ *************** struct HandleData { *** 643,648 **** --- 658,664 ---- struct HTTP *http; struct HTTP *https; /* alias, just for the sake of being more readable */ struct FTP *ftp; + struct SFTP *sftp; void *tftp; /* private for tftp.c-eyes only */ struct FILEPROTO *file; void *telnet; /* private for telnet.c-eyes only */ *************** struct connectdata { *** 681,686 **** --- 697,703 ---- #define PROT_FTPS (1<<9) #define PROT_SSL (1<<10) /* protocol requires SSL */ #define PROT_TFTP (1<<11) + #define PROT_SFTP (1<<12) /* 'dns_entry' is the particular host we use. This points to an entry in the DNS cache and it will not get pruned while locked. It gets unlocked in