Compare commits

...

68 Commits

Author SHA1 Message Date
Sara Golemon
7c64e21df6 Bump for release 2005-03-23 00:30:05 +00:00
Sara Golemon
c67bb667aa Add libssh2_poll() 2005-03-23 00:21:26 +00:00
Sara Golemon
141ac5b856 Add sys/uio.h for FBSD builds and remove old stdio references 2005-03-21 21:26:08 +00:00
Sara Golemon
9f64f34dfe Swap compression mode preferences, prefer none over zlib by default 2005-03-17 19:20:32 +00:00
Sara Golemon
a1b87a952c Late news 2005-03-17 19:09:45 +00:00
Sara Golemon
7db9aeecf8 Possible fix for compatability with OpenSSL < 0.9.7 2005-03-02 01:55:51 +00:00
Sara Golemon
99e5547442 strm->next_out doesn't *stay* == out, only free out 2005-02-28 17:02:39 +00:00
Sara Golemon
ef7496b29a Update copyright year 2005-02-18 16:32:02 +00:00
Sara Golemon
37c55becdc Bump for release 2005-02-18 16:19:34 +00:00
Sara Golemon
47b96a9771 Add win32/ files to dist 2005-02-18 16:15:24 +00:00
Sara Golemon
0a9a5ffc22 Genericise win32 build params 2005-02-18 16:13:03 +00:00
Sara Golemon
c6e5188fb4 Add support for MacOSX(Darwin) 2005-02-17 20:41:34 +00:00
Sara Golemon
fe7ea0df58 Add support for hostbased pubkey authentication 2005-02-14 05:51:06 +00:00
Sara Golemon
500169bf97 Acknowledge window adjustments and fix the paren bug I just introduced :) 2005-02-14 03:16:42 +00:00
Sara Golemon
10a0c20eae Fix extended data identification and make window adjust always be sent 2005-02-14 03:06:35 +00:00
Sara Golemon
2427c1b803 Remove TODO file 2005-02-09 19:26:42 +00:00
Sara Golemon
159120f844 Bump for release 2005-02-09 19:22:34 +00:00
Sara Golemon
fc1563a41d These aren't meaningful since we don't bring libssh2_config.h in 2005-02-09 18:52:59 +00:00
Sara Golemon
c6bbe0d42f Added libssh2_session_flag() and LIBSSH2_FLAG_SIGPIPE with hooks 2005-02-03 05:57:43 +00:00
Sara Golemon
a05bf84ecf Collapse state flags into single bitmask attribute 2005-02-03 05:41:35 +00:00
Sara Golemon
2c5c54e999 Fix zlib compression when internal buffer not empty 2005-02-01 05:37:42 +00:00
Bert Vermeulen
5f2864c0b4 some more info on the tests done 2005-01-25 17:15:51 +00:00
Bert Vermeulen
4675d1242b Improved error handling 2005-01-25 06:03:16 +00:00
Bert Vermeulen
b59f2ccc1b Erm... don't know what that was doing here 2005-01-25 05:47:49 +00:00
Bert Vermeulen
b25446d0a5 methods now tests all methods separately, and reports which one goes wrong
Corrected Makefile dependency
2005-01-25 05:46:00 +00:00
Bert Vermeulen
064c6cde3a First checkin of the test suite 2005-01-22 23:11:13 +00:00
Edin Kadribasic
2c5a8480b0 Silence warnings when win32 is already defined.
Enable zlib and newer diffie-hellman-group-exchange-sha1 syntax.
2005-01-22 02:29:37 +00:00
Edin Kadribasic
87d61a39e8 Adjust project files to live in /win32 2005-01-22 02:28:22 +00:00
Edin Kadribasic
0e878271db Add windows build files to ignore list 2005-01-22 01:39:50 +00:00
Edin Kadribasic
bc16411dd3 Correct line endings 2005-01-22 01:34:02 +00:00
Sara Golemon
096ef86627 Avoid segfault when libssh2_session_methods() called too early 2005-01-21 23:30:28 +00:00
Sara Golemon
2b414db02e BFN 2005-01-20 21:35:24 +00:00
Sara Golemon
5f7470700e Handle Client-To-Server channel windowing. 2005-01-20 21:33:30 +00:00
Bert Vermeulen
bfc2f5039e Added a couple of comments to keep my last-error-not-set-o-meter from going off 2005-01-19 16:29:53 +00:00
Sara Golemon
a3735795dd Can't remember why I did this, banner should always be sent before trying to receive 2005-01-18 19:17:29 +00:00
Sara Golemon
a891971a63 Simplify DSA signing process 2005-01-18 06:31:41 +00:00
Sara Golemon
d4677dba5b Fix u64int ifdef statement 2005-01-18 06:30:02 +00:00
Sara Golemon
d1ae5a501f Add MSVC6 build files 2005-01-11 19:10:53 +00:00
Sara Golemon
72c4c38e37 Finish making msvc6 happy 2005-01-11 19:05:47 +00:00
Sara Golemon
fe2513a18b Bump for release (tardy) 2005-01-11 18:59:10 +00:00
Wez Furlong
ee03669517 be nice to msvc 6 2005-01-11 14:58:04 +00:00
Wez Furlong
22c105332d Add release build for win32 2005-01-11 02:23:28 +00:00
Sara Golemon
c9e8f3a1a0 Allow alternate API prefix from CFLAGS or calling app 2005-01-10 23:56:09 +00:00
Sara Golemon
54b852dfc9 Add dist_nmake target 2005-01-10 19:58:23 +00:00
Sara Golemon
308d59910f Fix setstat calls. libssh2_attr2bin was masking out flags 2005-01-07 23:51:46 +00:00
Sara Golemon
ecd83df6a7 Need to load the cipher definitions if we expect to use them... 2005-01-07 23:14:53 +00:00
Sara Golemon
4191a8c56c Fix ssh-dss public key authentication 2005-01-07 21:07:53 +00:00
Sara Golemon
c5acc8a901 Ooops, this should have been hexits, not raw bytes 2005-01-06 17:32:17 +00:00
Sara Golemon
a119685410 Add X11 forwarding support 2005-01-06 00:51:30 +00:00
Wez Furlong
dc4bb1af96 Add support for win32.
Edit win32/config.mk to set the paths to your openssl and zlib headers and
libraries.

Then, from the root of the tree:

	nmake -f NMakefile

voila.
2005-01-03 22:46:15 +00:00
Sara Golemon
8fe47a609a Ooops, forgot to add these 2005-01-01 23:39:15 +00:00
Sara Golemon
c070bdacc7 Move towards a working win32 build 2005-01-01 23:38:34 +00:00
Sara Golemon
a9af84c51d Let ./configure populate VERSION in Makefile 2004-12-31 20:40:40 +00:00
Sara Golemon
dfb3b8f0fd Additional install docs 2004-12-31 20:31:24 +00:00
Sara Golemon
c006dd4350 Added support for MAC methods: hmac-md5 and hmac-md5-96
key_len should not have been in KEX_METHOD,
it's dependent on MAC method, not KEX method.

This is why the MD5 MACs were borked initially,
md5 has a key_len of 16, not 20.
2004-12-31 00:55:52 +00:00
Sara Golemon
4324a1a1d1 APINO should have been bumped when session_methods() proto was changed 2004-12-31 00:45:53 +00:00
Sara Golemon
cf8ca63ea0 Add ./configure option '--disable-gex-new' to fallback on
older diffie-hellman-group-exchange-sha1 syntax.

i.e. Use SSH_MSG_KEX_DH_GEX_REQUEST_OLD
rather then SSH_MSG_KEX_DH_GEX_REQUEST

See draft-ietf-secsh-dh-group-exchange section 7 for details.
2004-12-31 00:15:18 +00:00
Sara Golemon
d1b33840bf Note change to libssh2_session_methods() 2004-12-30 23:22:59 +00:00
Bert Vermeulen
eef99ca106 Changed libssh2_session_methods() to use method_type parameter 2004-12-30 22:19:53 +00:00
Sara Golemon
d86bcab2d2 Add error codes to session_method_pref() 2004-12-30 20:05:53 +00:00
Sara Golemon
2e02ad041a Add remote tcp/ip forwarding. 2004-12-29 19:26:28 +00:00
Sara Golemon
596b62c027 use actual random data with KEX_INIT cookie and packet padding 2004-12-27 20:38:44 +00:00
Sara Golemon
143c6bf97f Add DESTDIR support during 'make install' (Adam Gobiowski) 2004-12-26 21:54:19 +00:00
Sara Golemon
371f5de682 Bump for release 2004-12-24 23:23:09 +00:00
Sara Golemon
d2d8f8ad0b Added libssh2_banner_set() 2004-12-24 23:10:15 +00:00
Sara Golemon
a1e649b507 Fixed leak in sftp_symlink_ex(),
result for READLINK and REALPATH not freed unless there was an error.
2004-12-24 20:19:42 +00:00
Sara Golemon
99795a165e Plug leak in handle string provided by sftp_open 2004-12-24 03:57:10 +00:00
Sara Golemon
6f13a93be9 Fix crash in sftp_close_handle.
Don't free dir handle data when it's not a dir handle!
2004-12-24 03:49:25 +00:00
45 changed files with 6313 additions and 269 deletions

9
.cvsignore Normal file
View File

@@ -0,0 +1,9 @@
*.lib
*.pdb
*.dll
*.exe
*.obj
.*.swp
Debug
Release
*.exp

51
INSTALL
View File

@@ -5,5 +5,56 @@ Installing libssh2
* Run: ./configure (passing additional options as desired)
In addition the the standard set of ./configure options (e.g. --prefix)
there are five switches which you may wish to pay attention to:
* --with-openssl=[DIR]
libssh2 requires the OpenSSL library (http://www.openssl.org) for
cipher and hash method implementations.
./configure will attempt to locate OpenSSL in a number of default locations:
/usr/local/ssl /usr/local /usr /usr/local/openssl
If your installation of OpenSSL is in another location, specify it here.
* --with-zlib=[DIR]
If present, libssh2 will attempt to use the zlib (http://www.zlib.org)
for payload compression, however zlib is not required.
./configure will attempt to location a zlib installation in a number of default locations:
/usr/local /usr /usr/local/libz /usr/libz /usr/local/zlib /usr/zlib
If your installation of zlib is in another location, you may specify it here.
* --enable-crypt-none
The SSH2 Transport allows for unencrypted data transmission using the "none" cipher.
Because this is such a huge security hole, it is typically disabled on
SSH2 implementations and is diabled in libssh2 by default as well.
Enabling this option will allow for "none" as a negotiable method,
however it still requires that the method be advertized by the remote end
and that no more-prefferable methods are available.
* --enable-mac-none
The SSH2 Transport also allows implementations to forego a message authentication code.
While this is less of a security risk than using a "none" cipher, it is still not
recommended as disabling MAC hashes removes a layer of security.
Enabling this option will allow for "none" as a negotiable method,
however it still requires that the method be advertized by the remote end
and that no more-prefferable methods are available.
* --disable-gex-new
The diffie-hellman-group-exchange-sha1 (dh-gex) key exchange method originally defined
an exchange negotiation using packet type 30 to request a generation pair based
on a single target value. Later refinement of dh-gex provided for range and target
values. By default libssh2 will use the newer range method.
If you experience trouble connecting to an old SSH server using dh-gex,
try this option to fallback on the older more reliable method.
* Run: make all install

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,

View File

@@ -10,7 +10,7 @@ CC = @CC@
CFLAGS = -c @CFLAGS@ -Iinclude/ -Wall -g
LIBS = -lssh2 -Lsrc/
INSTALL = @INSTALL@
VERSION=0.3
VERSION=@PACKAGE_VERSION@
DISTLIB=libssh2-$(VERSION)
all:
@@ -21,14 +21,14 @@ all:
$(CC) -o ssh2_sample.o ssh2_sample.c $(CFLAGS)
$(CC) -o ssh2_sample ssh2_sample.o $(LIBS)
install:
$(top_srcdir)/mkinstalldirs $(incldir)
$(top_srcdir)/mkinstalldirs $(libdir)
$(top_srcdir)/mkinstalldirs $(DESTDIR)$(incldir)
$(top_srcdir)/mkinstalldirs $(DESTDIR)$(libdir)
@for dir in ${subdirs}; do \
(cd $$dir && $(MAKE) install) \
|| case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
done && test -z "$$fail"
$(INSTALL) -m 644 include/libssh2.h $(incldir)/
$(INSTALL) -m 644 include/libssh2_sftp.h $(incldir)/
$(INSTALL) -m 644 include/libssh2.h $(DESTDIR)$(incldir)/
$(INSTALL) -m 644 include/libssh2_sftp.h $(DESTDIR)$(incldir)/
clean:
@for dir in ${subdirs}; do \
(cd $$dir && $(MAKE) clean) \
@@ -42,9 +42,23 @@ dist:
ln -s . $(DISTLIB)
tar -zcf $(DISTLIB).tar.gz \
$(DISTLIB)/configure $(DISTLIB)/Makefile.in $(DISTLIB)/ssh2_sample.c \
$(DISTLIB)/LICENSE $(DISTLIB)/README $(DISTLIB)/TODO $(DISTLIB)/INSTALL \
$(DISTLIB)/mkinstalldirs $(DISTLIB)/install-sh \
$(DISTLIB)/LICENSE $(DISTLIB)/README $(DISTLIB)/INSTALL \
$(DISTLIB)/mkinstalldirs $(DISTLIB)/install-sh $(DISTLIB)/config.sub $(DISTLIB)/config.guess \
$(DISTLIB)/src/*.c $(DISTLIB)/src/Makefile.in \
$(DISTLIB)/include/libssh2.h $(DISTLIB)/include/libssh2_priv.h $(DISTLIB)/include/libssh2_sftp.h \
$(DISTLIB)/include/libssh2_config.h.in
$(DISTLIB)/include/libssh2_config.h.in \
$(DISTLIB)/win32/config.mk $(DISTLIB)/win32/libssh2_config.h $(DISTLIB)/win32/rules.mk \
$(DISTLIB)/win32/libssh2.dsp $(DISTLIB)/win32/libssh2.dsw $(DISTLIB)/win32/ssh2_sample.dsp
rm -f $(DISTLIB)
dist_nmake:
autoheader
autoconf
rm -f $(DISTLIB)
ln -s . $(DISTLIB)
tar -zcf $(DISTLIB)-win32.tar.gz \
$(DISTLIB)/NMakefile $(DISTLIB)/ssh2_sample.c $(DISTLIB)/src/*.c \
$(DISTLIB)/LICENSE $(DISTLIB)/README $(DISTLIB)/TODO $(DISTLIB)/INSTALL \
$(DISTLIB)/include/libssh2.h $(DISTLIB)/include/libssh2_priv.h $(DISTLIB)/include/libssh2_sftp.h \
$(DISTLIB)/win32/config.mk $(DISTLIB)/win32/libssh2_config.h $(DISTLIB)/win32/rules.mk
rm -f $(DISTLIB)

16
NMakefile Normal file
View File

@@ -0,0 +1,16 @@
!include "win32/config.mk"
SUBDIRS=src
all: all-sub ssh2_sample.exe
ssh2_sample.exe: ssh2_sample.c
$(CC) $(CFLAGS) -DWIN32 -o ssh2_sample.exe ssh2_sample.c libssh2$(SUFFIX).lib $(LIBS)
all-sub:
-for %D in ($(SUBDIRS)) do $(MAKE) /nologo /f %D/NMakefile BUILD=$(BUILD) SUBDIR=%D all-sub
clean:
rmdir /s/q $(TARGET)

79
README
View File

@@ -1,6 +1,85 @@
libssh2 - SSH2 library
======================
Version 0.8
-----------
Fix potential segfault in compression/decompression.
Fix compatability with older versions of OpenSSL
Swapped order of none,zlib compression modes to prefer no compression by default.
Added sys/uio.h for platforms (FBSD) which need it in order to define struct iovec.
Added libssh2_poll() to check status of sockets/channels/listeners.
Removed unnecessary inclusion of stdio.h (holdover from debugging)
Version 0.7
-----------
Added libssh2_userauth_hostbased_fromfile_ex() for authenticating from hostkey.
Added configure recognition for MacOSX (Darwin) (Thanks Gabe)
Fixed extended data identification in libssh2_channel_read().
Fixed window adjust code. Hadn't acknowledged adjustments correctly.
Removed initial_window_size requirement for sending window adjust packet.
Version 0.6
-----------
Added LIBSSH2_FLAG_SIGPIPE to enable/disable SIGPIPE generated by send()/recv() calls. Default off.
Added libssh2_session_flag() to set optional session flags.
Collapsed exchanging_keys/newkeys/authenticated flags into single state attribute.
Fix zlib compression issue when internal buffer state misses partial sync.
Fix segfault when libssh2_session_methods() is called prior to session_startup().
Fixed client to server channel windowing. Pervent send queue overruns.
Swapped banner send/receive order (send first, then wait for response).
Version 0.5
-----------
*** BC Break ***
Reimplemented libssh2_session_methods() to match libssh2_session_method_pref() style
Fixed libssh2_attr2bin() (effects any setstat style call).
Fixed authenticating with encrypted private key.
Fixed authenticating via ssh-dss public key.
Fixed KEX_INIT cookie and packet padding to use actual random data
Added DESTDIR support to makefiles (Adam Go<47><6F>biowski -- I hope that character set translates right)
Added libssh2_channel_forward_listen_ex(), libssh2_channel_forward_cancel(), and libssh2_channel_forward_accept().
Added ./configure option '--disable-gex-new' to allow using the older group-exchange format
Added MAC methods hmac-md5 and hmac-md5-96.
Version 0.4
-----------
Fixed crash when trying to free sftp_dirhandle data from a filehandle struct.
Fixed leak in sftp_open_ex(), handle->handle not freed in handle_close().
Fixed leak in sftp_symlink_ex(), result for READLINK and REALPATH not freed unless there was an error.
Added libssh2_banner_set(), specify an arbitrary banner to send on introduction.
Version 0.3
-----------

3
TODO
View File

@@ -1,3 +0,0 @@
* More Crypt Methods
* hmac-md5, hmac-md5-96
* Review callbacks

1415
config.guess vendored Executable file

File diff suppressed because it is too large Load Diff

1510
config.sub vendored Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,26 @@
# AC_PREREQ(2.57)
AC_INIT(libssh2, 0.3 , sarag@libssh2.org)
AC_INIT(libssh2,0.8,sarag@libssh2.org)
AC_CONFIG_SRCDIR([src])
AC_CONFIG_HEADER([include/libssh2_config.h])
SHLIB_SUFFIX_NAME="so"
SHLIB_LDFLAGS="-shared"
# Check for the OS.
AC_CANONICAL_HOST
case "$host" in
*-cygwin)
SHLIB_SUFFIX_NAME="dll"
SHLIB_LDFLAGS="-shared"
CFLAGS="$CFLAGS -DLIBSSH2_WIN32"
;;
*darwin*)
SHLIB_SUFFIX_NAME="dylib"
SHLIB_LDFLAGS="-dynamiclib -flat_namespace"
CFLAGS="$CFLAGS -DLIBSSH2_DARWIN"
;;
*)
SHLIB_SUFFIX_NAME="so"
SHLIB_LDFLAGS="-shared"
;;
esac
AC_SUBST(SHLIB_SUFFIX_NAME)
AC_SUBST(SHLIB_LDFLAGS)
@@ -138,9 +153,17 @@ AC_ARG_ENABLE(mac-none,
AC_HELP_STRING([--enable-mac-none],[Permit "none" MAC -- NOT RECOMMENDED]),
[AC_DEFINE(LIBSSH2_MAC_NONE, 1, [Enable "none" MAC -- NOT RECOMMENDED])])
AC_ARG_ENABLE(gex-new,
AC_HELP_STRING([--disable-gex-new],[Disable "new" diffie-hellman-group-exchange-sha1 method]),
[GEX_NEW=$enableval])
if test "$GEX_NEW" != "no"; then
AC_DEFINE(LIBSSH2_DH_GEX_NEW, 1, [Enable newer diffie-hellman-group-exchange-sha1 syntax])
fi
# Checks for header files.
# AC_HEADER_STDC
AC_CHECK_HEADERS([errno.h fcntl.h stdio.h stdlib.h unistd.h])
AC_CHECK_HEADERS([errno.h fcntl.h stdio.h stdlib.h unistd.h sys/uio.h sys/select.h])
AC_CHECK_FUNCS(poll gettimeofday select)
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
@@ -42,8 +42,33 @@
#include <string.h>
#include <sys/stat.h>
#define LIBSSH2_VERSION "0.3"
#define LIBSSH2_APINO 200412211608
/* Allow alternate API prefix from CFLAGS or calling app */
#ifndef LIBSSH2_API
# ifdef LIBSSH2_WIN32
# ifdef LIBSSH2_LIBRARY
# define LIBSSH2_API __declspec(dllexport)
# else
# define LIBSSH2_API __declspec(dllimport)
# endif /* LIBSSH2_LIBRARY */
# else /* !LIBSSH2_WIN32 */
# define LIBSSH2_API
# endif /* LIBSSH2_WIN32 */
#endif /* LIBSSH2_API */
#if defined(LIBSSH2_DARWIN) || (defined(LIBSSH2_WIN32) && !defined(_MSC_VER))
# include <sys/uio.h>
#endif
#if defined(LIBSSH2_WIN32) && _MSC_VER < 1300
typedef unsigned __int64 libssh2_uint64_t;
typedef __int64 libssh2_int64_t;
#else
typedef unsigned long long libssh2_uint64_t;
typedef long long libssh2_int64_t;
#endif
#define LIBSSH2_VERSION "0.8"
#define LIBSSH2_APINO 200503221619
/* Part of every banner, user specified or not */
#define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION
@@ -52,54 +77,6 @@
#define LIBSSH2_SSH_DEFAULT_BANNER LIBSSH2_SSH_BANNER
#define LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF LIBSSH2_SSH_DEFAULT_BANNER "\r\n"
/* Capabilities */
#define LIBSSH2_KEX_DH_GROUP1
#define LIBSSH2_KEX_DH_GROUP14
#define LIBSSH2_KEX_DH_GROUP_EXCHANGE
#ifndef OPENSSL_NO_RSA
#define LIBSSH2_HOSTKEY_RSA
#endif
#ifndef OPENSSL_NO_DSA
#define LIBSSH2_HOSTKEY_DSA
#endif
#ifndef OPENSSL_NO_AES
#define LIBSSH2_CRYPT_AES256_CBC
#define LIBSSH2_CRYPT_RIJNDAEL_CBC_LYSATOR_LIU_SE
#define LIBSSH2_CRYPT_AES192_CBC
#define LIBSSH2_CRYPT_AES128_CBC
#endif
#ifndef OPENSSL_NO_BLOWFISH
#define LIBSSH2_CRYPT_BLOWFISH_CBC
#endif
#ifndef OPENSSL_NO_RC4
#define LIBSSH2_CRYPT_ARCFOUR
#endif
#ifndef OPENSSL_NO_CAST
#define LIBSSH2_CRYPT_CAST128_CBC
#endif
#ifndef OPENSSL_NO_DES
#define LIBSSH2_CRYPT_3DES_CBC
#endif
/* LIBSSH2_CRYPT_NONE already defined (or not) by ./configure */
#ifdef LIBSSH2_HAVE_ZLIB
#define LIBSSH2_COMP_ZLIB
#endif
#define LIBSSH2_COMP_NONE
#define LIBSSH2_MAC_SHA1
#define LIBSSH2_MAC_SHA1_96
#ifndef OPENSSL_NO_RIPEMD
#define LIBSSH2_MAC_RIPEMD160
#define LIBSSH2_MAC_RIPEMD160_OPENSSH_COM
#endif
/* LIBSSH2_MAC_NONE already defined (or not) by ./configure */
/* Enable the "new" version of diffie-hellman-group-exchange-sha1 */
#define LIBSSH2_DH_GEX_NEW
/* Default generate and safe prime sizes for diffie-hellman-group-exchange-sha1 */
#define LIBSSH2_DH_GEX_MINGROUP 1024
#define LIBSSH2_DH_GEX_OPTGROUP 1536
@@ -136,6 +113,7 @@
#define LIBSSH2_DISCONNECT_FUNC(name) void name(LIBSSH2_SESSION *session, int reason, const char *message, int message_len, const char *language, int language_len, void **abstract)
#define LIBSSH2_PASSWD_CHANGEREQ_FUNC(name) void name(LIBSSH2_SESSION *session, char **newpw, int *newpw_len, void **abstract)
#define LIBSSH2_MACERROR_FUNC(name) int name(LIBSSH2_SESSION *session, const char *packet, int packet_len, void **abstract)
#define LIBSSH2_X11_OPEN_FUNC(name) void name(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel, char *shost, int sport, void **abstract)
#define LIBSSH2_CHANNEL_CLOSE_FUNC(name) void name(LIBSSH2_SESSION *session, void **session_abstract, LIBSSH2_CHANNEL *channel, void **channel_abstract)
@@ -144,6 +122,7 @@
#define LIBSSH2_CALLBACK_DEBUG 1
#define LIBSSH2_CALLBACK_DISCONNECT 2
#define LIBSSH2_CALLBACK_MACERROR 3
#define LIBSSH2_CALLBACK_X11 4
/* libssh2_session_method_pref() constants */
#define LIBSSH2_METHOD_KEX 0
@@ -157,15 +136,44 @@
#define LIBSSH2_METHOD_LANG_CS 8
#define LIBSSH2_METHOD_LANG_SC 9
/* session.flags bits */
#define LIBSSH2_FLAG_SIGPIPE 0x00000001
typedef struct _LIBSSH2_SESSION LIBSSH2_SESSION;
typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL;
typedef struct _LIBSSH2_LISTENER LIBSSH2_LISTENER;
#ifdef WIN_32
#define LIBSSH2_API __declspec(dllexport)
#else
#define LIBSSH2_API
#endif
typedef struct _LIBSSH2_POLLFD {
unsigned char type; /* LIBSSH2_POLLFD_* below */
union {
int socket; /* File descriptors -- examined with system select() call */
LIBSSH2_CHANNEL *channel; /* Examined by checking internal state */
LIBSSH2_LISTENER *listener; /* Read polls only -- are inbound connections waiting to be accepted? */
} fd;
unsigned long events; /* Requested Events */
unsigned long revents; /* Returned Events */
} LIBSSH2_POLLFD;
/* Poll FD Descriptor Types */
#define LIBSSH2_POLLFD_SOCKET 1
#define LIBSSH2_POLLFD_CHANNEL 2
#define LIBSSH2_POLLFD_LISTENER 3
/* Note: Win32 Doesn't actually have a poll() implementation, so some of these values are faked with select() data */
/* Poll FD events/revents -- Match sys/poll.h where possible */
#define LIBSSH2_POLLFD_POLLIN 0x0001 /* Data available to be read or connection available -- All */
#define LIBSSH2_POLLFD_POLLPRI 0x0002 /* Priority data available to be read -- Socket only */
#define LIBSSH2_POLLFD_POLLEXT 0x0002 /* Extended data available to be read -- Channel only */
#define LIBSSH2_POLLFD_POLLOUT 0x0004 /* Can may be written -- Socket/Channel */
/* revents only */
#define LIBSSH2_POLLFD_POLLERR 0x0008 /* Error Condition -- Socket */
#define LIBSSH2_POLLFD_POLLHUP 0x0010 /* HangUp/EOF -- Socket/Channel */
#define LIBSSH2_POLLFD_POLLNVAL 0x0020 /* Invalid request -- Socket Only */
#define LIBSSH2_POLLFD_POLLEX 0x0040 /* Exception Condition -- Socket/Win32 */
/* Hash Types */
#define LIBSSH2_HOSTKEY_HASH_MD5 1
#define LIBSSH2_HOSTKEY_HASH_SHA1 2
@@ -218,6 +226,10 @@ typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL;
#define LIBSSH2_ERROR_ZLIB -29
#define LIBSSH2_ERROR_SOCKET_TIMEOUT -30
#define LIBSSH2_ERROR_SFTP_PROTOCOL -31
#define LIBSSH2_ERROR_REQUEST_DENIED -32
#define LIBSSH2_ERROR_METHOD_NOT_SUPPORTED -33
#define LIBSSH2_ERROR_INVAL -34
#define LIBSSH2_ERROR_INVALID_POLL_TYPE -35
/* Session API */
LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)), LIBSSH2_FREE_FUNC((*my_free)), LIBSSH2_REALLOC_FUNC((*my_realloc)), void *abstract);
@@ -225,6 +237,7 @@ LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_all
LIBSSH2_API void **libssh2_session_abstract(LIBSSH2_SESSION *session);
LIBSSH2_API void *libssh2_session_callback_set(LIBSSH2_SESSION *session, int cbtype, void *callback);
LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session, char *banner);
LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket);
LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, char *description, char *lang);
@@ -234,14 +247,11 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session);
LIBSSH2_API char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type);
LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method_type, char *prefs);
LIBSSH2_API void libssh2_session_methods(LIBSSH2_SESSION *session, char **kex, char **hostkey,
char **crypt_cs, char **crypt_sc,
char **mac_cs, char **mac_sc,
char **comp_cs, char **comp_sc,
char **lang_cs, char **lang_sc);
LIBSSH2_API char *libssh2_session_methods(LIBSSH2_SESSION *session, int method_type);
LIBSSH2_API int libssh2_session_last_error(LIBSSH2_SESSION *session, char **errmsg, int *errmsg_len, int want_buf);
LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag, int value);
/* Userauth API */
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username, int username_len);
LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session);
@@ -253,6 +263,15 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
char *passphrase);
#define libssh2_userauth_publickey_fromfile(session, username, publickey, privatekey, passphrase) \
libssh2_userauth_publickey_fromfile_ex((session), (username), strlen(username), (publickey), (privatekey), (passphrase))
LIBSSH2_API int libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, char *username, int username_len,
char *publickey, char *privatekey,
char *passphrase,
char *hostname, int hostname_len,
char *local_username, int local_username_len);
#define libssh2_userauth_hostbased_fromfile(session, username, publickey, privatekey, passphrase, hostname) \
libssh2_userauth_hostbased_fromfile_ex((session), (username), strlen(username), (publickey), (privatekey), (passphrase), (hostname), strlen(hostname), (username), strlen(username))
LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout);
/* Channel API */
#define LIBSSH2_CHANNEL_WINDOW_DEFAULT 65536
@@ -267,15 +286,26 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, char *channel_type, int channel_type_len, int window_size, int packet_size, char *message, int message_len);
#define libssh2_channel_open_session(session) libssh2_channel_open_ex((session), "session", sizeof("session") - 1, LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0)
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, char *host, int port, char *shost, int sport);
#define libssh2_channel_direct_tcpip(session, host, port) libssh2_channel_direct_tcpip_ex((session), (host), (port), "127.0.0.1", 22)
LIBSSH2_API LIBSSH2_LISTENER *libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session, char *host, int port, int *bound_port, int queue_maxsize);
#define libssh2_channel_forward_listen(session, port) libssh2_channel_forward_listen_ex((session), NULL, (port), NULL, 16)
LIBSSH2_API int libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener);
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener);
LIBSSH2_API int libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, char *varname, int varname_len, char *value, int value_len);
#define libssh2_channel_setenv(channel, varname, value) libssh2_channel_setenv_ex((channel), (varname), strlen(varname), (value), strlen(value))
LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, char *term, int term_len, char *modes, int modes_len, int width, int height, int width_px, int height_px);
#define libssh2_channel_request_pty(channel, term) libssh2_channel_request_pty_ex((channel), (term), strlen(term), NULL, 0, LIBSSH2_TERM_WIDTH, LIBSSH2_TERM_HEIGHT, LIBSSH2_TERM_WIDTH_PX, LIBSSH2_TERM_HEIGHT_PX)
LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_connection, char *auth_proto, char *auth_cookie, int screen_number);
#define libssh2_channel_x11_req(channel, screen_number) libssh2_channel_x11_req_ex((channel), 0, NULL, NULL, (screen_number))
LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, char *request, int request_len, char *message, int message_len);
#define libssh2_channel_shell(channel) libssh2_channel_process_startup((channel), "shell", sizeof("shell") - 1, NULL, 0)
#define libssh2_channel_exec(channel, command) libssh2_channel_process_startup((channel), "exec", sizeof("exec") - 1, (command), strlen(command))

View File

@@ -6,12 +6,21 @@
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* Define to 1 if you have the `gettimeofday' function. */
#undef HAVE_GETTIMEOFDAY
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `poll' function. */
#undef HAVE_POLL
/* Define to 1 if you have the `select' function. */
#undef HAVE_SELECT
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
@@ -27,18 +36,27 @@
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the <sys/select.h> header file. */
#undef HAVE_SYS_SELECT_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <sys/uio.h> header file. */
#undef HAVE_SYS_UIO_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Enable "none" cipher -- NOT RECOMMENDED */
#undef LIBSSH2_CRYPT_NONE
/* Enable newer diffie-hellman-group-exchange-sha1 syntax */
#undef LIBSSH2_DH_GEX_NEW
/* Compile in zlib support */
#undef LIBSSH2_HAVE_ZLIB

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
@@ -38,11 +38,13 @@
#ifndef LIBSSH2_PRIV_H
#define LIBSSH2_PRIV_H 1
/* Definitions shared with the public */
#define LIBSSH2_LIBRARY
#include "libssh2_config.h"
#include "libssh2.h"
#ifndef WIN32
#include <sys/socket.h>
#endif
#include <openssl/evp.h>
#define LIBSSH2_ALLOC(session, count) session->alloc((count), &(session)->abstract)
@@ -56,6 +58,7 @@
session->ssh_msg_disconnect((session), (reason), (message), (message_len), (language), (language_len), &(session)->abstract)
#define LIBSSH2_MACERROR(session, data, datalen) session->macerror((session), (data), (datalen), &(session)->abstract)
#define LIBSSH2_X11_OPEN(channel, shost, sport) channel->session->x11(((channel)->session), (channel), (shost), (sport), (&(channel)->session->abstract))
#define LIBSSH2_CHANNEL_CLOSE(session, channel) channel->close_cb((session), &(session)->abstract, (channel), &(channel)->abstract)
@@ -123,6 +126,19 @@ struct _LIBSSH2_CHANNEL_BRIGADE {
LIBSSH2_CHANNEL *head, *tail;
};
struct _LIBSSH2_LISTENER {
LIBSSH2_SESSION *session;
char *host;
int port;
LIBSSH2_CHANNEL *queue;
int queue_size;
int queue_maxsize;
LIBSSH2_LISTENER *prev, *next;
};
typedef struct _libssh2_endpoint_data {
unsigned char *banner;
@@ -158,14 +174,14 @@ struct _LIBSSH2_SESSION {
LIBSSH2_DEBUG_FUNC((*ssh_msg_debug));
LIBSSH2_DISCONNECT_FUNC((*ssh_msg_disconnect));
LIBSSH2_MACERROR_FUNC((*macerror));
LIBSSH2_X11_OPEN_FUNC((*x11));
/* Method preferences -- NULL yields "load order" */
char *kex_prefs;
char *hostkey_prefs;
int exchanging_keys;
int newkeys;
int authenticated;
int state;
int flags;
/* Agreed Key Exchange Method */
LIBSSH2_KEX_METHOD *kex;
@@ -202,6 +218,8 @@ struct _LIBSSH2_SESSION {
LIBSSH2_CHANNEL_BRIGADE channels;
unsigned long next_channel;
LIBSSH2_LISTENER *listeners;
/* Actual I/O socket */
int socket_fd;
int socket_block;
@@ -214,14 +232,26 @@ struct _LIBSSH2_SESSION {
int err_code;
};
/* session.state bits */
#define LIBSSH2_STATE_EXCHANGING_KEYS 0x00000001
#define LIBSSH2_STATE_NEWKEYS 0x00000002
#define LIBSSH2_STATE_AUTHENTICATED 0x00000004
/* session.flag helpers */
#ifdef MSG_NOSIGNAL
#define LIBSSH2_SOCKET_SEND_FLAGS(session) (((session)->flags & LIBSSH2_FLAG_SIGPIPE) ? 0 : MSG_NOSIGNAL)
#define LIBSSH2_SOCKET_RECV_FLAGS(session) (((session)->flags & LIBSSH2_FLAG_SIGPIPE) ? 0 : MSG_NOSIGNAL)
#else
/* If MSG_NOSIGNAL isn't defined we're SOL on blocking SIGPIPE */
#define LIBSSH2_SOCKET_SEND_FLAGS(session) 0
#define LIBSSH2_SOCKET_RECV_FLAGS(session) 0
#endif
/* libssh2 extensible ssh api, ultimately I'd like to allow loading additional methods via .so/.dll */
struct _LIBSSH2_KEX_METHOD {
char *name;
/* integrity key length */
unsigned long key_len;
/* Key exchange, populates session->* and returns 0 on success, non-0 on error */
int (*exchange_keys)(LIBSSH2_SESSION *session);
@@ -278,6 +308,9 @@ struct _LIBSSH2_MAC_METHOD {
/* The length of a given MAC packet */
int mac_len;
/* integrity key length */
int key_len;
/* Message Authentication Code Hashing algo */
int (*init)(LIBSSH2_SESSION *session, unsigned char *key, int *free_key, void **abstract);
int (*hash)(LIBSSH2_SESSION *session, unsigned char *buf, unsigned long seqno, const unsigned char *packet, unsigned long packet_len, const unsigned char *addtl, unsigned long addtl_len, void **abstract);
@@ -360,9 +393,9 @@ struct _LIBSSH2_MAC_METHOD {
void libssh2_session_shutdown(LIBSSH2_SESSION *session);
unsigned long libssh2_ntohu32(const unsigned char *buf);
unsigned long long libssh2_ntohu64(const unsigned char *buf);
libssh2_uint64_t libssh2_ntohu64(const unsigned char *buf);
void libssh2_htonu32(unsigned char *buf, unsigned long val);
void libssh2_htonu64(unsigned char *buf, unsigned long long val);
void libssh2_htonu64(unsigned char *buf, libssh2_uint64_t val);
int libssh2_packet_read(LIBSSH2_SESSION *session, int block);
int libssh2_packet_ask_ex(LIBSSH2_SESSION *session, unsigned char packet_type, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len, int poll_socket);
@@ -373,6 +406,7 @@ int libssh2_packet_require_ex(LIBSSH2_SESSION *session, unsigned char packet_typ
libssh2_packet_require_ex((session), (packet_type), (data), (data_len), 0, NULL, 0)
int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned long data_len);
int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange);
unsigned long libssh2_channel_nextid(LIBSSH2_SESSION *session);
LIBSSH2_CHANNEL *libssh2_channel_locate(LIBSSH2_SESSION *session, unsigned long channel_id);
/* Let crypt.c/hostkey.c/comp.c/mac.c expose their method structs */

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
@@ -82,7 +82,7 @@ struct _LIBSSH2_SFTP_ATTRIBUTES {
*/
unsigned long flags;
unsigned long long filesize;
libssh2_uint64_t filesize;
unsigned long uid, gid;
unsigned long permissions;
unsigned long atime, mtime;

9
src/.cvsignore Normal file
View File

@@ -0,0 +1,9 @@
*.lib
*.pdb
*.dll
*.exe
*.obj
.*.swp
Debug
Release
*.exp

View File

@@ -57,7 +57,7 @@ libssh2.a: $(OBJECTS)
ar q libssh2.a $(OBJECTS)
@RANLIB@ libssh2.a
install: all
$(INSTALL) libssh2.@SHLIB_SUFFIX_NAME@ $(libdir)
$(INSTALL) libssh2.@SHLIB_SUFFIX_NAME@ $(DESTDIR)$(libdir)
clean:
rm -f *~ libssh2.a libssh2.@SHLIB_SUFFIX_NAME@ *.o

18
src/NMakefile Normal file
View File

@@ -0,0 +1,18 @@
!include "win32/config.mk"
CFLAGS=$(CFLAGS)
OBJECTS = $(INTDIR)\channel.obj $(INTDIR)\comp.obj $(INTDIR)\crypt.obj \
$(INTDIR)\hostkey.obj $(INTDIR)\kex.obj $(INTDIR)\mac.obj \
$(INTDIR)\misc.obj $(INTDIR)\packet.obj $(INTDIR)\scp.obj \
$(INTDIR)\session.obj $(INTDIR)\sftp.obj $(INTDIR)\userauth.obj
DLL=libssh2$(SUFFIX).dll
$(DLL): $(OBJECTS)
$(CC) -o $(DLL) $(DLLFLAGS) $(OBJECTS) $(LIBS)
all: $(DLL)
!include "win32/rules.mk"

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
@@ -36,12 +36,15 @@
*/
#include "libssh2_priv.h"
#include <openssl/rand.h>
#ifndef WIN32
#include <unistd.h>
#endif
/* {{{ libssh2_channel_nextid
* Determine the next channel ID we can use at our end
*/
static unsigned long libssh2_channel_nextid(LIBSSH2_SESSION *session)
unsigned long libssh2_channel_nextid(LIBSSH2_SESSION *session)
{
unsigned long id = session->next_channel;
LIBSSH2_CHANNEL *channel;
@@ -257,6 +260,191 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *se
}
/* }}} */
/* {{{ libssh2_channel_forward_listen_ex
* Bind a port on the remote host and listen for connections
*/
LIBSSH2_API LIBSSH2_LISTENER *libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session, char *host, int port, int *bound_port, int queue_maxsize)
{
unsigned char *packet, *s;
unsigned long host_len = (host ? strlen(host) : (sizeof("0.0.0.0") - 1));
unsigned long packet_len = host_len + (sizeof("tcpip-forward") - 1) + 14;
/* packet_type(1) + request_len(4) + want_replay(1) + host_len(4) + port(4) */
s = packet = LIBSSH2_ALLOC(session, packet_len);
if (!packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memeory for setenv packet", 0);
return NULL;
}
*(s++) = SSH_MSG_GLOBAL_REQUEST;
libssh2_htonu32(s, sizeof("tcpip-forward") - 1); s += 4;
memcpy(s, "tcpip-forward", sizeof("tcpip-forward") - 1); s += sizeof("tcpip-forward") - 1;
*(s++) = 0xFF; /* want_reply */
libssh2_htonu32(s, host_len); s += 4;
memcpy(s, host ? host : "0.0.0.0", host_len); s += host_len;
libssh2_htonu32(s, port); s += 4;
if (libssh2_packet_write(session, packet, packet_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send global-request packet for forward listen request", 0);
LIBSSH2_FREE(session, packet);
return NULL;
}
LIBSSH2_FREE(session, packet);
while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
unsigned char *data;
unsigned long data_len;
if (libssh2_packet_ask(session, SSH_MSG_REQUEST_SUCCESS, &data, &data_len, 1) == 0) {
LIBSSH2_LISTENER *listener;
listener = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_LISTENER));
if (!listener) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for listener queue", 0);
LIBSSH2_FREE(session, data);
return NULL;
}
memset(listener, 0, sizeof(LIBSSH2_LISTENER));
listener->session = session;
listener->host = LIBSSH2_ALLOC(session, host_len + 1);
if (!listener->host) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for listener queue", 0);
LIBSSH2_FREE(session, listener);
LIBSSH2_FREE(session, data);
return NULL;
}
memcpy(listener->host, host ? host : "0.0.0.0", host_len);
listener->host[host_len] = 0;
if (data_len >= 5 && !port) {
listener->port = libssh2_ntohu32(data + 1);
} else {
listener->port = port;
}
listener->queue_size = 0;
listener->queue_maxsize = queue_maxsize;
listener->next = session->listeners;
listener->prev = NULL;
if (session->listeners) {
session->listeners->prev = listener;
}
session->listeners = listener;
if (bound_port) {
*bound_port = listener->port;
}
LIBSSH2_FREE(session, data);
return listener;
}
if (libssh2_packet_ask(session, SSH_MSG_REQUEST_FAILURE, &data, &data_len, 0) == 0) {
LIBSSH2_FREE(session, data);
libssh2_error(session, LIBSSH2_ERROR_REQUEST_DENIED, "Unable to complete request for forward-listen", 0);
return NULL;
}
}
return NULL;
}
/* }}} */
/* {{{ libssh2_channel_forward_cancel
* Stop listening on a remote port and free the listener
* Toss out any pending (un-accept()ed) connections
*/
LIBSSH2_API int libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener)
{
LIBSSH2_SESSION *session = listener->session;
LIBSSH2_CHANNEL *queued = listener->queue;
unsigned char *packet, *s;
unsigned long host_len = strlen(listener->host);
unsigned long packet_len = host_len + 14 + sizeof("cancel-tcpip-forward") - 1;
/* packet_type(1) + request_len(4) + want_replay(1) + host_len(4) + port(4) */
s = packet = LIBSSH2_ALLOC(session, packet_len);
if (!packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memeory for setenv packet", 0);
return -1;
}
*(s++) = SSH_MSG_GLOBAL_REQUEST;
libssh2_htonu32(s, sizeof("cancel-tcpip-forward") - 1); s += 4;
memcpy(s, "cancel-tcpip-forward", sizeof("cancel-tcpip-forward") - 1); s += sizeof("cancel-tcpip-forward") - 1;
*(s++) = 0x00; /* want_reply */
libssh2_htonu32(s, host_len); s += 4;
memcpy(s, listener->host, host_len); s += host_len;
libssh2_htonu32(s, listener->port); s += 4;
if (libssh2_packet_write(session, packet, packet_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send global-request packet for forward listen request", 0);
LIBSSH2_FREE(session, packet);
return -1;
}
LIBSSH2_FREE(session, packet);
while (queued) {
LIBSSH2_CHANNEL *next = queued->next;
libssh2_channel_free(queued);
queued = next;
}
LIBSSH2_FREE(session, listener->host);
if (listener->next) {
listener->next->prev = listener->prev;
}
if (listener->prev) {
listener->prev->next = listener->next;
} else {
session->listeners = listener->next;
}
LIBSSH2_FREE(session, listener);
return 0;
}
/* }}} */
/* {{{ libssh2_channel_forward_accept
* Accept a connection
*/
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener)
{
while (libssh2_packet_read(listener->session, 0) > 0);
if (listener->queue) {
LIBSSH2_SESSION *session = listener->session;
LIBSSH2_CHANNEL *channel;
channel = listener->queue;
listener->queue = listener->queue->next;
if (listener->queue) {
listener->queue->prev = NULL;
}
channel->prev = NULL;
channel->next = session->channels.head;
session->channels.head = channel;
if (channel->next) {
channel->next->prev = channel;
} else {
session->channels.tail = channel;
}
listener->queue_size--;
return channel;
}
return NULL;
}
/* }}} */
/* {{{ libssh2_channel_setenv_ex
* Set an environment variable prior to requesting a shell/program/subsystem
*/
@@ -389,6 +577,85 @@ LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, char *t
}
/* }}} */
/* Keep this an even number */
#define LIBSSH2_X11_RANDOM_COOKIE_LEN 32
/* {{{ libssh2_channel_x11_req_ex
* Request X11 forwarding
*/
LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_connection, char *auth_proto, char *auth_cookie, int screen_number)
{
LIBSSH2_SESSION *session = channel->session;
unsigned char *s, *packet;
unsigned long proto_len = auth_proto ? strlen(auth_proto) : (sizeof("MIT-MAGIC-COOKIE-1") - 1);
unsigned long cookie_len = auth_cookie ? strlen(auth_cookie) : LIBSSH2_X11_RANDOM_COOKIE_LEN;
unsigned long packet_len = proto_len + cookie_len + 41; /* packet_type(1) + channel(4) + x11_req_len(4) + "x11-req"(7) + want_reply(1) +
single_cnx(4) + proto_len(4) + cookie_len(4) + screen_num(4) */
s = packet = LIBSSH2_ALLOC(session, packet_len);
if (!packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for pty-request", 0);
return -1;
}
*(s++) = SSH_MSG_CHANNEL_REQUEST;
libssh2_htonu32(s, channel->remote.id); s += 4;
libssh2_htonu32(s, sizeof("x11-req") - 1); s += 4;
memcpy(s, "x11-req", sizeof("x11-req") - 1); s += sizeof("x11-req") - 1;
*(s++) = 0xFF; /* want_reply */
*(s++) = single_connection ? 0xFF : 0x00;
libssh2_htonu32(s, proto_len); s += 4;
memcpy(s, auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1", proto_len);
s += proto_len;
libssh2_htonu32(s, cookie_len);
if (auth_cookie) {
memcpy(s, auth_cookie, cookie_len);
} else {
int i;
char buffer[LIBSSH2_X11_RANDOM_COOKIE_LEN / 2];
RAND_bytes(buffer, LIBSSH2_X11_RANDOM_COOKIE_LEN / 2);
for (i = 0; i < (LIBSSH2_X11_RANDOM_COOKIE_LEN / 2); i++) {
snprintf(s + (i * 2), 2, "%02X", buffer[i]);
}
}
s += cookie_len;
libssh2_htonu32(s, screen_number); s += 4;
if (libssh2_packet_write(session, packet, packet_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send pty-request packet", 0);
LIBSSH2_FREE(session, packet);
return -1;
}
LIBSSH2_FREE(session, packet);
while (1) {
unsigned char *data;
unsigned long data_len;
unsigned char local_channel[4];
libssh2_htonu32(local_channel, channel->local.id);
if (libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_SUCCESS, &data, &data_len, 1, local_channel, 4, 1) == 0) {
LIBSSH2_FREE(session, data);
return 0;
}
if (libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_FAILURE, &data, &data_len, 1, local_channel, 4, 1) == 0) {
LIBSSH2_FREE(session, data);
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED, "Unable to complete request for channel x11-req", 0);
return -1;
}
}
/* Never reached, just giving the compiler something to not complain about */
return -1;
}
/* }}} */
/* {{{ libssh2_channel_process_startup
* Primitive for libssh2_channel_(shell|exec|subsystem)
*/
@@ -560,7 +827,7 @@ LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id,
* or the standard stream (and data was available),
* or the standard stream with extended_data_merge enabled and data was available
*/
if ((stream_id && (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) && (channel->local.id == libssh2_ntohu32(packet->data + 1))) ||
if ((stream_id && (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) && (channel->local.id == libssh2_ntohu32(packet->data + 1)) && (stream_id == libssh2_ntohu32(packet->data + 5))) ||
(!stream_id && (packet->data[0] == SSH_MSG_CHANNEL_DATA) && (channel->local.id == libssh2_ntohu32(packet->data + 1))) ||
(!stream_id && (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) && (channel->local.id == libssh2_ntohu32(packet->data + 1)) && (channel->remote.extended_data_ignore_mode == LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE))) {
int want = buflen - bytes_read;
@@ -590,18 +857,19 @@ LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id,
}
LIBSSH2_FREE(session, packet->data);
if (channel->remote.window_size_initial) {
/* Adjust the window based on the block we just freed */
adjust[0] = SSH_MSG_CHANNEL_WINDOW_ADJUST;
libssh2_htonu32(adjust + 1, channel->remote.id);
libssh2_htonu32(adjust + 5, packet->data_len - (stream_id ? 13 : 9));
/* Adjust the window based on the block we just freed */
adjust[0] = SSH_MSG_CHANNEL_WINDOW_ADJUST;
libssh2_htonu32(adjust + 1, channel->remote.id);
libssh2_htonu32(adjust + 5, packet->data_len - (stream_id ? 13 : 9));
if (libssh2_packet_write(session, adjust, 9)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send transfer-window adjustment packet", 0);
}
LIBSSH2_FREE(session, packet);
if (libssh2_packet_write(session, adjust, 9)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send transfer-window adjustment packet", 0);
} else {
/* Don't forget to acknowledge the adjust on this end */
channel->remote.window_size += (packet->data_len - (stream_id ? 13 : 9));
}
LIBSSH2_FREE(session, packet);
}
}
packet = next;
@@ -635,7 +903,7 @@ LIBSSH2_API int libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_EOF_SENT, "EOF has already been sight, data might be ignored", 0);
}
if (channel->blocking && channel->local.window_size_initial && (channel->local.window_size <= 0)) {
if (channel->blocking && (channel->local.window_size <= 0)) {
/* twiddle our thumbs until there's window space available */
if (libssh2_packet_read(session, 1) < 0) {
/* Error occured, disconnect? */
@@ -658,7 +926,7 @@ LIBSSH2_API int libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id
/* Don't exceed the remote end's limits */
/* REMEMBER local means local as the SOURCE of the data */
if (channel->local.window_size_initial && (buflen > channel->local.window_size)) {
if (buflen > channel->local.window_size) {
buflen = channel->local.window_size;
}
if (buflen > channel->local.packet_size) {

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
@@ -136,12 +136,12 @@ static int libssh2_comp_method_zlib_comp(LIBSSH2_SESSION *session, int compress,
z_stream *strm = *abstract;
/* A short-term alloc of a full data chunk is better than a series of reallocs */
char *out;
int out_maxlen = compress ? src_len : (2 * src_len);
int out_maxlen = compress ? (src_len + 4) : (2 * src_len);
int limiter = 0;
/* In practice they never come smaller than this */
if (out_maxlen < 21) {
out_maxlen = 21;
if (out_maxlen < 25) {
out_maxlen = 25;
}
if (out_maxlen > payload_limit) {
@@ -166,17 +166,17 @@ static int libssh2_comp_method_zlib_comp(LIBSSH2_SESSION *session, int compress,
}
if (status != Z_OK) {
libssh2_error(session, LIBSSH2_ERROR_ZLIB, "compress/decompression failure", 0);
LIBSSH2_FREE(session, strm->next_out);
LIBSSH2_FREE(session, out);
return -1;
}
if (strm->avail_in) {
unsigned long out_ofs = out_maxlen - strm->avail_out;
out_maxlen += compress ? strm->avail_in : (2 * strm->avail_in);
out_maxlen += compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
if ((out_maxlen > payload_limit) && !compress && limiter++) {
libssh2_error(session, LIBSSH2_ERROR_ZLIB, "Excessive growth in decompression phase", 0);
LIBSSH2_FREE(session, strm->next_out);
LIBSSH2_FREE(session, out);
return -1;
}
@@ -186,7 +186,43 @@ static int libssh2_comp_method_zlib_comp(LIBSSH2_SESSION *session, int compress,
return -1;
}
strm->next_out = out + out_ofs;
strm->avail_out += compress ? strm->avail_in : (2 * strm->avail_in);
strm->avail_out += compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
} else while (!strm->avail_out) {
/* Done with input, might be a byte or two in internal buffer during compress
* Or potentially many bytes if it's a decompress
*/
int grow_size = compress ? 8 : 1024;
if (out_maxlen >= payload_limit) {
libssh2_error(session, LIBSSH2_ERROR_ZLIB, "Excessive growth in decompression phase", 0);
LIBSSH2_FREE(session, out);
return -1;
}
if (grow_size > (payload_limit - out_maxlen)) {
grow_size = payload_limit - out_maxlen;
}
out_maxlen += grow_size;
strm->avail_out = grow_size;
out = LIBSSH2_REALLOC(session, out, out_maxlen);
if (!out) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to expand final compress/decompress buffer", 0);
return -1;
}
strm->next_out = out + out_maxlen - grow_size;
if (compress) {
status = deflate(strm, Z_PARTIAL_FLUSH);
} else {
status = inflate(strm, Z_PARTIAL_FLUSH);
}
if (status != Z_OK) {
libssh2_error(session, LIBSSH2_ERROR_ZLIB, "compress/decompression failure", 0);
LIBSSH2_FREE(session, out);
return -1;
}
}
}
@@ -236,10 +272,10 @@ static LIBSSH2_COMP_METHOD libssh2_comp_method_zlib = {
*********************** */
static LIBSSH2_COMP_METHOD *_libssh2_comp_methods[] = {
&libssh2_comp_method_none,
#ifdef LIBSSH2_HAVE_ZLIB
&libssh2_comp_method_zlib,
#endif /* LIBSSH2_HAVE_ZLIB */
&libssh2_comp_method_none,
NULL
};

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
@@ -38,6 +38,12 @@
#include "libssh2_priv.h"
#include <openssl/bn.h>
#include <openssl/pem.h>
#include <openssl/evp.h>
/* Needed for struct iovec on some platforms */
#ifdef HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif
#ifndef OPENSSL_NO_RSA
/* ***********
@@ -86,7 +92,8 @@ static int libssh2_hostkey_method_ssh_rsa_init(LIBSSH2_SESSION *session, unsigne
/* {{{ libssh2_hostkey_method_ssh_rsa_passphrase_cb
* TODO: Optionally call a passphrase callback specified by the calling program
*/
static int libssh2_hostkey_method_ssh_rsadsa_passphrase_cb(char *buf, int size, int rwflag, char *passphrase){
static int libssh2_hostkey_method_ssh_rsadsa_passphrase_cb(char *buf, int size, int rwflag, char *passphrase)
{
int passphrase_len = strlen(passphrase);
if (passphrase_len > (size - 1)) {
@@ -116,6 +123,14 @@ static int libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION *session, unsi
if (!fp) {
return -1;
}
if (!EVP_get_cipherbyname("des")) {
/* If this cipher isn't loaded it's a pretty good indication that none are.
* I have *NO DOUBT* that there's a better way to deal with this ($#&%#$(%$#(
* Someone buy me an OpenSSL manual and I'll read up on it.
*/
OpenSSL_add_all_ciphers();
}
rsactx = PEM_read_RSAPrivateKey(fp, NULL, (void*)libssh2_hostkey_method_ssh_rsadsa_passphrase_cb, passphrase);
if (!rsactx) {
fclose(fp);
@@ -322,6 +337,14 @@ static int libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION *session, unsi
if (!fp) {
return -1;
}
if (!EVP_get_cipherbyname("des")) {
/* If this cipher isn't loaded it's a pretty good indication that none are.
* I have *NO DOUBT* that there's a better way to deal with this ($#&%#$(%$#(
* Someone buy me an OpenSSL manual and I'll read up on it.
*/
OpenSSL_add_all_ciphers();
}
dsactx = PEM_read_DSAPrivateKey(fp, NULL, (void*)libssh2_hostkey_method_ssh_rsadsa_passphrase_cb, passphrase);
if (!dsactx) {
fclose(fp);
@@ -371,16 +394,14 @@ static int libssh2_hostkey_method_ssh_dss_sign(LIBSSH2_SESSION *session, unsigne
const unsigned char *buf, unsigned long buf_len, void **abstract)
{
DSA *dsactx = (DSA*)(*abstract);
int ret;
DSA_SIG *sig;
unsigned char hash[SHA_DIGEST_LENGTH];
SHA_CTX ctx;
char *sig;
int sig_len;
sig_len = DSA_size(dsactx);
sig = LIBSSH2_ALLOC(session, sig_len);
*signature = LIBSSH2_ALLOC(session, 2 * SHA_DIGEST_LENGTH);
*signature_len = 2 * SHA_DIGEST_LENGTH;
if (!sig) {
if (!(*signature)) {
return -1;
}
@@ -388,14 +409,16 @@ static int libssh2_hostkey_method_ssh_dss_sign(LIBSSH2_SESSION *session, unsigne
SHA1_Update(&ctx, buf, buf_len);
SHA1_Final(hash, &ctx);
ret = DSA_sign(NID_sha1, hash, SHA_DIGEST_LENGTH, sig, &sig_len, dsactx);
if (!ret) {
LIBSSH2_FREE(session, sig);
sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx);
if (!sig) {
LIBSSH2_FREE(session, *signature);
return -1;
}
*signature = sig;
*signature_len = sig_len;
BN_bn2bin(sig->r, *signature);
BN_bn2bin(sig->s, *signature + SHA_DIGEST_LENGTH);
DSA_SIG_free(sig);
return 0;
}
@@ -408,16 +431,16 @@ static int libssh2_hostkey_method_ssh_dss_signv(LIBSSH2_SESSION *session, unsign
unsigned long veccount, const struct iovec datavec[], void **abstract)
{
DSA *dsactx = (DSA*)(*abstract);
int ret, i;
DSA_SIG *sig;
unsigned char hash[SHA_DIGEST_LENGTH];
SHA_CTX ctx;
char *sig;
int sig_len;
int r_len, s_len, rs_pad, i;
sig_len = DSA_size(dsactx);
sig = LIBSSH2_ALLOC(session, sig_len);
*signature = LIBSSH2_ALLOC(session, 2 * SHA_DIGEST_LENGTH);
*signature_len = 2 * SHA_DIGEST_LENGTH;
memset(*signature, 0, 2 * SHA_DIGEST_LENGTH);
if (!sig) {
if (!(*signature)) {
return -1;
}
@@ -427,15 +450,25 @@ static int libssh2_hostkey_method_ssh_dss_signv(LIBSSH2_SESSION *session, unsign
}
SHA1_Final(hash, &ctx);
ret = DSA_sign(NID_sha1, hash, SHA_DIGEST_LENGTH, sig, &sig_len, dsactx);
if (!ret) {
LIBSSH2_FREE(session, sig);
sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx);
if (!sig) {
LIBSSH2_FREE(session, *signature);
return -1;
}
*signature = sig;
*signature_len = sig_len;
r_len = BN_num_bytes(sig->r);
s_len = BN_num_bytes(sig->s);
rs_pad = (2 * SHA_DIGEST_LENGTH) - (r_len + s_len);
if (rs_pad < 0) {
DSA_SIG_free(sig);
LIBSSH2_FREE(session, *signature);
return -1;
}
BN_bn2bin(sig->r, *signature + rs_pad);
BN_bn2bin(sig->s, *signature + rs_pad + r_len);
DSA_SIG_free(sig);
return 0;
}

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
@@ -39,6 +39,7 @@
#include <openssl/bn.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
/* TODO: Switch this to an inline and handle alloc() failures */
/* Helper macro called from libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange */
@@ -262,7 +263,7 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
goto clean_exit;
}
/* The first key exchange has been performed, switch to active crypt/comp/mac mode */
session->newkeys = 1;
session->state |= LIBSSH2_STATE_NEWKEYS;
/* This will actually end up being just packet_type(1) for this packet type anyway */
LIBSSH2_FREE(session, tmp);
@@ -384,11 +385,11 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
unsigned char *key = NULL;
int free_key = 0;
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, session->kex->key_len, "E");
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, session->local.mac->key_len, "E");
session->local.mac->init(session, key, &free_key, &session->local.mac_abstract);
if (free_key) {
memset(key, 0, session->kex->key_len);
memset(key, 0, session->local.mac->key_len);
LIBSSH2_FREE(session, key);
}
}
@@ -401,11 +402,11 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
unsigned char *key = NULL;
int free_key = 0;
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, session->kex->key_len, "F");
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, session->remote.mac->key_len, "F");
session->remote.mac->init(session, key, &free_key, &session->remote.mac_abstract);
if (free_key) {
memset(key, 0, session->kex->key_len);
memset(key, 0, session->remote.mac->key_len);
LIBSSH2_FREE(session, key);
}
}
@@ -595,21 +596,18 @@ static int libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange(LI
LIBSSH2_KEX_METHOD libssh2_kex_method_diffie_helman_group1_sha1 = {
"diffie-hellman-group1-sha1",
SHA_DIGEST_LENGTH,
libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange,
LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
};
LIBSSH2_KEX_METHOD libssh2_kex_method_diffie_helman_group14_sha1 = {
"diffie-hellman-group14-sha1",
SHA_DIGEST_LENGTH,
libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange,
LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
};
LIBSSH2_KEX_METHOD libssh2_kex_method_diffie_helman_group_exchange_sha1 = {
"diffie-hellman-group-exchange-sha1",
SHA_DIGEST_LENGTH,
libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange,
LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
};
@@ -720,8 +718,7 @@ static int libssh2_kexinit(LIBSSH2_SESSION *session)
*(s++) = SSH_MSG_KEXINIT;
/* TODO: Build a better cookie (and the mice will beat a path to my door...) */
memcpy(s, "mysecretMYSECRET", 16);
RAND_bytes(s, 16);
s += 16;
/* Ennumerating through these lists twice is probably (certainly?) inefficient from a CPU standpoint, but it saves multiple malloc/realloc calls */
@@ -1148,7 +1145,7 @@ int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange) /* session->f
unsigned long data_len;
/* Prevent loop in packet_add() */
session->exchanging_keys = 1;
session->state |= LIBSSH2_STATE_EXCHANGING_KEYS;
if (reexchange) {
session->kex = NULL;
@@ -1194,7 +1191,7 @@ int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange) /* session->f
session->remote.kexinit = NULL;
}
session->exchanging_keys = 0;
session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
return 0;
}
@@ -1251,6 +1248,7 @@ LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method
mlist = NULL;
break;
default:
libssh2_error(session, LIBSSH2_ERROR_INVAL, "Invalid parameter specified for method_type", 0);
return -1;
}
@@ -1282,6 +1280,7 @@ LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method
}
if (strlen(newprefs) == 0) {
libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, "The requested method(s) are not currently supported", 0);
LIBSSH2_FREE(session, newprefs);
return -1;
}

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
@@ -54,6 +54,7 @@ static int libssh2_mac_none_MAC(LIBSSH2_SESSION *session, unsigned char *buf, un
static LIBSSH2_MAC_METHOD libssh2_mac_method_none = {
"none",
0,
0,
NULL,
libssh2_mac_none_MAC,
NULL
@@ -98,7 +99,7 @@ static int libssh2_mac_method_hmac_sha1_hash(LIBSSH2_SESSION *session, unsigned
libssh2_htonu32(seqno_buf, seqno);
HMAC_Init(&ctx, *abstract, session->kex->key_len, EVP_sha1());
HMAC_Init(&ctx, *abstract, 20, EVP_sha1());
HMAC_Update(&ctx, seqno_buf, 4);
HMAC_Update(&ctx, packet, packet_len);
if (addtl && addtl_len) {
@@ -113,7 +114,8 @@ static int libssh2_mac_method_hmac_sha1_hash(LIBSSH2_SESSION *session, unsigned
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_sha1 = {
"hmac-sha1",
SHA_DIGEST_LENGTH,
20,
20,
libssh2_mac_method_common_init,
libssh2_mac_method_hmac_sha1_hash,
libssh2_mac_method_common_dtor,
@@ -137,13 +139,13 @@ static int libssh2_mac_method_hmac_sha1_96_hash(LIBSSH2_SESSION *session, unsign
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_sha1_96 = {
"hmac-sha1-96",
96 / 8,
12,
20,
libssh2_mac_method_common_init,
libssh2_mac_method_hmac_sha1_96_hash,
libssh2_mac_method_common_dtor,
};
#ifdef WHY_DOESNT_MD5_WORK
/* {{{ libssh2_mac_method_hmac_md5_hash
* Calculate hash using full md5 value
*/
@@ -156,7 +158,7 @@ static int libssh2_mac_method_hmac_md5_hash(LIBSSH2_SESSION *session, unsigned c
libssh2_htonu32(seqno_buf, seqno);
HMAC_Init(&ctx, *abstract, session->kex->key_len, EVP_md5());
HMAC_Init(&ctx, *abstract, 16, EVP_md5());
HMAC_Update(&ctx, seqno_buf, 4);
HMAC_Update(&ctx, packet, packet_len);
if (addtl && addtl_len) {
@@ -171,7 +173,8 @@ static int libssh2_mac_method_hmac_md5_hash(LIBSSH2_SESSION *session, unsigned c
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_md5 = {
"hmac-md5",
MD5_DIGEST_LENGTH,
16,
16,
libssh2_mac_method_common_init,
libssh2_mac_method_hmac_md5_hash,
libssh2_mac_method_common_dtor,
@@ -180,8 +183,8 @@ static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_md5 = {
/* {{{ libssh2_mac_method_hmac_md5_96_hash
* Calculate hash using first 96 bits of md5 value
*/
static int libssh2_mac_method_hmac_md5_96_hash(LIBSSH2_SESSION *session, unsigned char *buf, unsigned seqno,
const unsigned char *packet, unsigned packet_len,
static int libssh2_mac_method_hmac_md5_96_hash(LIBSSH2_SESSION *session, unsigned char *buf, unsigned long seqno,
const unsigned char *packet, unsigned long packet_len,
const unsigned char *addtl, unsigned long addtl_len, void **abstract)
{
char temp[MD5_DIGEST_LENGTH];
@@ -195,12 +198,12 @@ static int libssh2_mac_method_hmac_md5_96_hash(LIBSSH2_SESSION *session, unsigne
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_md5_96 = {
"hmac-md5-96",
96 / 8,
12,
16,
libssh2_mac_method_common_init,
libssh2_mac_method_hmac_md5_96_hash,
libssh2_mac_method_common_dtor,
};
#endif /* WHY_DOESNT_MD5_WORK */
#ifndef OPENSSL_NO_RIPEMD
/* {{{ libssh2_mac_method_hmac_ripemd160_hash
@@ -215,7 +218,7 @@ static int libssh2_mac_method_hmac_ripemd160_hash(LIBSSH2_SESSION *session, unsi
libssh2_htonu32(seqno_buf, seqno);
HMAC_Init(&ctx, *abstract, session->kex->key_len, EVP_ripemd160());
HMAC_Init(&ctx, *abstract, 20, EVP_ripemd160());
HMAC_Update(&ctx, seqno_buf, 4);
HMAC_Update(&ctx, packet, packet_len);
if (addtl && addtl_len) {
@@ -230,7 +233,8 @@ static int libssh2_mac_method_hmac_ripemd160_hash(LIBSSH2_SESSION *session, unsi
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160 = {
"hmac-ripemd160",
160 / 8,
20,
20,
libssh2_mac_method_common_init,
libssh2_mac_method_hmac_ripemd160_hash,
libssh2_mac_method_common_dtor,
@@ -238,7 +242,8 @@ static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160 = {
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160_openssh_com = {
"hmac-ripemd160@openssh.com",
160 / 8,
20,
20,
libssh2_mac_method_common_init,
libssh2_mac_method_hmac_ripemd160_hash,
libssh2_mac_method_common_dtor,
@@ -248,10 +253,8 @@ static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160_openssh_com = {
static LIBSSH2_MAC_METHOD *_libssh2_mac_methods[] = {
&libssh2_mac_method_hmac_sha1,
&libssh2_mac_method_hmac_sha1_96,
#ifdef WHY_DOESNT_MD5_WORK
&libssh2_mac_method_hmac_md5,
&libssh2_mac_method_hmac_md5_96,
#endif /* WHY_DOESNT_MD5_WORK */
#ifndef OPENSSL_NO_RIPEMD
&libssh2_mac_method_hmac_ripemd160,
&libssh2_mac_method_hmac_ripemd160_openssh_com,

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
@@ -49,7 +49,7 @@ unsigned long libssh2_ntohu32(const unsigned char *buf)
* Note: Some 32-bit platforms have issues with bitops on long longs
* Work around this by doing expensive (but safer) arithmetic ops with optimization defying parentheses
*/
unsigned long long libssh2_ntohu64(const unsigned char *buf)
libssh2_uint64_t libssh2_ntohu64(const unsigned char *buf)
{
unsigned long msl, lsl;
@@ -73,7 +73,7 @@ void libssh2_htonu32(unsigned char *buf, unsigned long value)
/* {{{ libssh2_htonu64
*/
void libssh2_htonu64(unsigned char *buf, unsigned long long value)
void libssh2_htonu64(unsigned char *buf, libssh2_uint64_t value)
{
unsigned long msl = (value / 65536) / 65536;

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
@@ -38,8 +38,240 @@
#include "libssh2_priv.h"
#include <errno.h>
#include <fcntl.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <openssl/evp.h>
#include <openssl/rand.h>
/* Needed for struct iovec on some platforms */
#ifdef HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif
/* {{{ libssh2_packet_queue_listener
* Queue a connection request for a listener
*/
inline int libssh2_packet_queue_listener(LIBSSH2_SESSION *session, unsigned char *data, unsigned long datalen)
{
/* Look for a matching listener */
unsigned char *s = data + (sizeof("forwarded-tcpip") - 1) + 5;
unsigned long packet_len = 17 + (sizeof("Forward not requested") - 1);
unsigned char *p, packet[17 + (sizeof("Forward not requested") - 1)];
/* packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
LIBSSH2_LISTENER *l = session->listeners;
char failure_code = 1; /* SSH_OPEN_ADMINISTRATIVELY_PROHIBITED */
unsigned long sender_channel, initial_window_size, packet_size;
unsigned char *host, *shost;
unsigned long port, sport, host_len, shost_len;
sender_channel = libssh2_ntohu32(s); s += 4;
initial_window_size = libssh2_ntohu32(s); s += 4;
packet_size = libssh2_ntohu32(s); s += 4;
host_len = libssh2_ntohu32(s); s += 4;
host = s; s += host_len;
port = libssh2_ntohu32(s); s += 4;
shost_len = libssh2_ntohu32(s); s += 4;
shost = s; s += shost_len;
sport = libssh2_ntohu32(s); s += 4;
while (l) {
if ((l->port == port) &&
(strlen(l->host) == host_len) &&
(memcmp(l->host, host, host_len) == 0)) {
/* This is our listener */
LIBSSH2_CHANNEL *channel, *last_queued = l->queue;
if (l->queue_maxsize &&
(l->queue_maxsize <= l->queue_size)) {
/* Queue is full */
failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
break;
}
channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
if (!channel) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a channel for new connection", 0);
failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
break;
}
memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
channel->session = session;
channel->channel_type_len = sizeof("forwarded-tcpip") - 1;
channel->channel_type = LIBSSH2_ALLOC(session, channel->channel_type_len + 1);
if (!channel->channel_type) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a channel for new connection", 0);
LIBSSH2_FREE(session, channel);
failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
break;
}
memcpy(channel->channel_type, "forwarded-tcpip", channel->channel_type_len + 1);
channel->remote.id = sender_channel;
channel->remote.window_size_initial = LIBSSH2_CHANNEL_WINDOW_DEFAULT;
channel->remote.window_size = LIBSSH2_CHANNEL_WINDOW_DEFAULT;
channel->remote.packet_size = LIBSSH2_CHANNEL_PACKET_DEFAULT;
channel->local.id = libssh2_channel_nextid(session);
channel->local.window_size_initial = initial_window_size;
channel->local.window_size = initial_window_size;
channel->local.packet_size = packet_size;
p = packet;
*(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
libssh2_htonu32(p, channel->remote.id); p += 4;
libssh2_htonu32(p, channel->local.id); p += 4;
libssh2_htonu32(p, channel->remote.window_size_initial); p += 4;
libssh2_htonu32(p, channel->remote.packet_size); p += 4;
if (libssh2_packet_write(session, packet, 17)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel open confirmation", 0);
return -1;
}
/* Link the channel into the end of the queue list */
if (!last_queued) {
l->queue = channel;
return 0;
}
while (last_queued->next) last_queued = last_queued->next;
last_queued->next = channel;
channel->prev = last_queued;
l->queue_size++;
return 0;
}
l = l->next;
}
/* We're not listening to you */
{
p = packet;
*(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
libssh2_htonu32(p, sender_channel); p += 4;
libssh2_htonu32(p, failure_code); p += 4;
libssh2_htonu32(p, sizeof("Forward not requested") - 1); p += 4;
memcpy(s, "Forward not requested", sizeof("Forward not requested") - 1); p += sizeof("Forward not requested") - 1;
libssh2_htonu32(p, 0);
if (libssh2_packet_write(session, packet, packet_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send open failure", 0);
return -1;
}
return 0;
}
}
/* }}} */
/* {{{ libssh2_packet_x11_open
* Accept a forwarded X11 connection
*/
inline int libssh2_packet_x11_open(LIBSSH2_SESSION *session, unsigned char *data, unsigned long datalen)
{
int failure_code = 2; /* SSH_OPEN_CONNECT_FAILED */
unsigned char *s = data + (sizeof("x11") - 1) + 5;
unsigned long packet_len = 17 + (sizeof("X11 Forward Unavailable") - 1);
unsigned char *p, packet[17 + (sizeof("X11 Forward Unavailable") - 1)];
/* packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
LIBSSH2_CHANNEL *channel;
unsigned long sender_channel, initial_window_size, packet_size;
unsigned char *shost;
unsigned long sport, shost_len;
sender_channel = libssh2_ntohu32(s); s += 4;
initial_window_size = libssh2_ntohu32(s); s += 4;
packet_size = libssh2_ntohu32(s); s += 4;
shost_len = libssh2_ntohu32(s); s += 4;
shost = s; s += shost_len;
sport = libssh2_ntohu32(s); s += 4;
if (session->x11) {
channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
if (!channel) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a channel for new connection", 0);
failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
goto x11_exit;
}
memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
channel->session = session;
channel->channel_type_len = sizeof("x11") - 1;
channel->channel_type = LIBSSH2_ALLOC(session, channel->channel_type_len + 1);
if (!channel->channel_type) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a channel for new connection", 0);
LIBSSH2_FREE(session, channel);
failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
goto x11_exit;
}
memcpy(channel->channel_type, "x11", channel->channel_type_len + 1);
channel->remote.id = sender_channel;
channel->remote.window_size_initial = LIBSSH2_CHANNEL_WINDOW_DEFAULT;
channel->remote.window_size = LIBSSH2_CHANNEL_WINDOW_DEFAULT;
channel->remote.packet_size = LIBSSH2_CHANNEL_PACKET_DEFAULT;
channel->local.id = libssh2_channel_nextid(session);
channel->local.window_size_initial = initial_window_size;
channel->local.window_size = initial_window_size;
channel->local.packet_size = packet_size;
p = packet;
*(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
libssh2_htonu32(p, channel->remote.id); p += 4;
libssh2_htonu32(p, channel->local.id); p += 4;
libssh2_htonu32(p, channel->remote.window_size_initial); p += 4;
libssh2_htonu32(p, channel->remote.packet_size); p += 4;
if (libssh2_packet_write(session, packet, 17)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel open confirmation", 0);
return -1;
}
/* Link the channel into the session */
if (session->channels.tail) {
session->channels.tail->next = channel;
channel->prev = session->channels.tail;
} else {
session->channels.head = channel;
channel->prev = NULL;
}
channel->next = NULL;
session->channels.tail = channel;
/* Pass control to the callback, they may turn right around and free the channel, or actually use it */
LIBSSH2_X11_OPEN(channel, shost, sport);
return 0;
} else {
failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
}
x11_exit:
p = packet;
*(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
libssh2_htonu32(p, sender_channel); p += 4;
libssh2_htonu32(p, failure_code); p += 4;
libssh2_htonu32(p, sizeof("X11 Forward Unavailable") - 1); p += 4;
memcpy(s, "X11 Forward Unavailable", sizeof("X11 Forward Unavailable") - 1); p += sizeof("X11 Forward Unavailable") - 1;
libssh2_htonu32(p, 0);
if (libssh2_packet_write(session, packet, packet_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send open failure", 0);
return -1;
}
return 0;
}
/* }}} */
/* {{{ libssh2_packet_new
* Create a new packet and attach it to the brigade
@@ -229,6 +461,37 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
return 0;
}
break;
case SSH_MSG_CHANNEL_OPEN:
if ((datalen >= (sizeof("forwarded-tcpip") + 4)) &&
((sizeof("forwarded-tcpip")-1) == libssh2_ntohu32(data + 1)) &&
(memcmp(data + 5, "forwarded-tcpip", sizeof("forwarded-tcpip") - 1) == 0)) {
int retval = libssh2_packet_queue_listener(session, data, datalen);
LIBSSH2_FREE(session, data);
return retval;
}
if ((datalen >= (sizeof("x11") + 4)) &&
((sizeof("x11")-1) == libssh2_ntohu32(data + 1)) &&
(memcmp(data + 5, "x11", sizeof("x11") - 1) == 0)) {
int retval = libssh2_packet_x11_open(session, data, datalen);
LIBSSH2_FREE(session, data);
return retval;
}
break;
case SSH_MSG_CHANNEL_WINDOW_ADJUST:
{
LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1));
unsigned long bytestoadd = libssh2_ntohu32(data + 5);
if (channel && bytestoadd) {
channel->local.window_size += bytestoadd;
}
LIBSSH2_FREE(session, data);
return 0;
}
break;
}
packet = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
@@ -251,7 +514,7 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
packet->prev = NULL;
}
if (data[0] == SSH_MSG_KEXINIT && !session->exchanging_keys) {
if (data[0] == SSH_MSG_KEXINIT && !(session->state & LIBSSH2_STATE_EXCHANGING_KEYS)) {
/* Remote wants new keys
* Well, it's already in the brigade,
* let's just call back into ourselves
@@ -275,8 +538,17 @@ static int libssh2_blocking_read(LIBSSH2_SESSION *session, unsigned char *buf, s
while (bytes_read < count) {
int ret;
ret = read(session->socket_fd, buf + bytes_read, count - bytes_read);
ret = recv(session->socket_fd, buf + bytes_read, count - bytes_read, LIBSSH2_SOCKET_RECV_FLAGS(session));
if (ret < 0) {
#ifdef WIN32
switch (WSAGetLastError()) {
case WSAEWOULDBLOCK: errno = EAGAIN;
case WSAENOTCONN:
case WSAENOTSOCK:
case WSAECONNABORTED: errno = EBADF;
case WSAEINTR: errno = EINTR;
}
#endif
if (errno == EAGAIN) {
if (polls++ > LIBSSH2_SOCKET_POLL_MAXLOOPS) {
return -1;
@@ -315,8 +587,15 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
return 0;
}
#ifndef WIN32
fcntl(session->socket_fd, F_SETFL, O_NONBLOCK);
if (session->newkeys) {
#else
{
u_long non_block = TRUE;
ioctlsocket(session->socket_fd, FIONBIO, &non_block);
}
#endif
if (session->state & LIBSSH2_STATE_NEWKEYS) {
/* Temporary Buffer
* The largest blocksize (currently) is 32, the largest MAC (currently) is 20
*/
@@ -336,7 +615,7 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
if (should_block) {
read_len = libssh2_blocking_read(session, block, blocksize);
} else {
read_len = read(session->socket_fd, block, 1);
read_len = recv(session->socket_fd, block, 1, LIBSSH2_SOCKET_RECV_FLAGS(session));
if (read_len <= 0) {
return 0;
}
@@ -461,7 +740,7 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
if (should_block) {
buf_len = libssh2_blocking_read(session, buf, 5);
} else {
buf_len = read(session->socket_fd, buf, 1);
buf_len = recv(session->socket_fd, buf, 1, LIBSSH2_SOCKET_RECV_FLAGS(session));
if (buf_len <= 0) {
return 0;
}
@@ -481,8 +760,13 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
return (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) ? 0 : -1;
}
while (padding_length) {
int l;
/* Flush padding */
padding_length -= libssh2_blocking_read(session, buf, padding_length);
l = libssh2_blocking_read(session, buf, padding_length);
if (l > 0)
padding_length -= l;
else
break;
}
/* MACs don't exist in non-encrypted mode */
@@ -574,14 +858,14 @@ int libssh2_packet_require_ex(LIBSSH2_SESSION *session, unsigned char packet_typ
int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned long data_len)
{
unsigned long packet_length = data_len + 1;
unsigned long block_size = (session->newkeys) ? session->local.crypt->blocksize : 8;
unsigned long block_size = (session->state & LIBSSH2_STATE_NEWKEYS) ? session->local.crypt->blocksize : 8;
/* At this point packet_length doesn't include the packet_len field itself */
unsigned long padding_length;
int free_data = 0;
unsigned char buf[246]; /* 6 byte header plus max padding size(240) */
int i;
if (session->newkeys &&
if ((session->state & LIBSSH2_STATE_NEWKEYS) &&
strcmp(session->local.comp->name, "none")) {
if (session->local.comp->comp(session, 1, &data, &data_len, LIBSSH2_PACKET_MAXCOMP, &free_data, data, data_len, &session->local.comp_abstract)) {
@@ -589,7 +873,15 @@ int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned
}
}
#ifndef WIN32
fcntl(session->socket_fd, F_SETFL, 0);
#else
{
u_long non_block = FALSE;
ioctlsocket(session->socket_fd, FIONBIO, &non_block);
}
#endif
packet_length = data_len + 1; /* padding_length(1) -- MAC doesn't count -- Padding to be added soon */
padding_length = block_size - ((packet_length + 4) % block_size);
if (padding_length < 4) {
@@ -606,7 +898,7 @@ int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned
buf[5 + i] = '\0';
}
if (session->newkeys) {
if (session->state & LIBSSH2_STATE_NEWKEYS) {
/* Encryption is in effect */
unsigned char *encbuf, *s;
int ret;
@@ -627,7 +919,7 @@ int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned
/* Copy packet to encoding buffer */
memcpy(encbuf, buf, 5);
memcpy(encbuf + 5, data, data_len);
memcpy(encbuf + 5 + data_len, buf + 5, padding_length);
RAND_bytes(encbuf + 5 + data_len, padding_length);
if (free_data) {
LIBSSH2_FREE(session, data);
}
@@ -648,7 +940,7 @@ int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned
session->local.seqno++;
/* Send It */
ret = ((4 + packet_length + session->local.mac->mac_len) == write(session->socket_fd, encbuf, 4 + packet_length + session->local.mac->mac_len)) ? 0 : -1;
ret = ((4 + packet_length + session->local.mac->mac_len) == send(session->socket_fd, encbuf, 4 + packet_length + session->local.mac->mac_len, LIBSSH2_SOCKET_SEND_FLAGS(session))) ? 0 : -1;
/* Cleanup environment */
LIBSSH2_FREE(session, encbuf);

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
@@ -37,7 +37,6 @@
#include "libssh2_priv.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#define LIBSSH2_SCP_RESPONSE_BUFLEN 256
@@ -347,6 +346,7 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char
/* Allocate a channel */
if ((channel = libssh2_channel_open_session(session)) == NULL) {
/* previous call set libssh2_session_last_error(), pass it through */
LIBSSH2_FREE(session, command);
return NULL;
}
@@ -355,6 +355,7 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char
/* Request SCP for the desired file */
if (libssh2_channel_process_startup(channel, "exec", sizeof("exec") - 1, command, command_len)) {
/* previous call set libssh2_session_last_error(), pass it through */
LIBSSH2_FREE(session, command);
libssh2_channel_free(channel);
return NULL;

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
@@ -37,9 +37,31 @@
#include "libssh2_priv.h"
#include <errno.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <stdlib.h>
#ifdef HAVE_GETTIMEOFDAY
#include <sys/time.h>
#include <math.h>
#endif
#ifdef HAVE_POLL
# include <sys/poll.h>
#else
# ifdef HAVE_SELECT
# ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
# else
# include <sys/time.h>
# include <sys/types.h>
# endif
# endif
#endif
/* {{{ libssh2_default_alloc
*/
static LIBSSH2_ALLOC_FUNC(libssh2_default_alloc)
@@ -79,7 +101,7 @@ static int libssh2_banner_receive(LIBSSH2_SESSION *session)
char c = '\0';
int ret;
ret = read(session->socket_fd, &c, 1);
ret = recv(session->socket_fd, &c, 1, LIBSSH2_SOCKET_RECV_FLAGS(session));
if ((ret < 0) && (ret != EAGAIN)) {
/* Some kinda error, but don't break for non-blocking issues */
@@ -124,7 +146,38 @@ static int libssh2_banner_send(LIBSSH2_SESSION *session)
banner = session->local.banner;
}
return (write(session->socket_fd, banner, banner_len) == banner_len) ? 0 : 1;
return (send(session->socket_fd, banner, banner_len, LIBSSH2_SOCKET_SEND_FLAGS(session)) == banner_len) ? 0 : 1;
}
/* }}} */
/* {{{ libssh2_banner_set
* Set the local banner
*/
LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session, char *banner)
{
int banner_len = banner ? strlen(banner) : 0;
if (session->local.banner) {
LIBSSH2_FREE(session, session->local.banner);
session->local.banner = NULL;
}
if (!banner_len) {
return 0;
}
session->local.banner = LIBSSH2_ALLOC(session, banner_len + 3);
if (!session->local.banner) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for local banner", 0);
return -1;
}
memcpy(session->local.banner, banner, banner_len);
session->local.banner[banner_len++] = '\r';
session->local.banner[banner_len++] = '\n';
session->local.banner[banner_len++] = '\0';
return 0;
}
/* }}} */
@@ -189,6 +242,11 @@ LIBSSH2_API void* libssh2_session_callback_set(LIBSSH2_SESSION *session, int cbt
session->macerror = callback;
return oldcb;
break;
case LIBSSH2_CALLBACK_X11:
oldcb = session->x11;
session->x11 = callback;
return oldcb;
break;
}
return NULL;
@@ -216,6 +274,11 @@ LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket)
session->socket_fd = socket;
/* TODO: Liveness check */
if (libssh2_banner_send(session)) {
/* Unable to send banner? */
libssh2_error(session, LIBSSH2_ERROR_BANNER_SEND, "Error sending banner to remote host", 0);
return LIBSSH2_ERROR_BANNER_SEND;
}
if (libssh2_banner_receive(session)) {
/* Unable to receive banner from remote */
@@ -223,12 +286,6 @@ LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket)
return LIBSSH2_ERROR_BANNER_NONE;
}
if (libssh2_banner_send(session)) {
/* Unable to send banner? */
libssh2_error(session, LIBSSH2_ERROR_BANNER_SEND, "Error sending banner to remote host", 0);
return LIBSSH2_ERROR_BANNER_SEND;
}
if (libssh2_kex_exchange(session, 0)) {
libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE, "Unable to exchange encryption keys", 0);
return LIBSSH2_ERROR_KEX_FAILURE;
@@ -284,7 +341,11 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
}
}
if (session->newkeys) {
while (session->listeners) {
libssh2_channel_forward_cancel(session->listeners);
}
if (session->state & LIBSSH2_STATE_NEWKEYS) {
/* hostkey */
if (session->hostkey && session->hostkey->dtor) {
session->hostkey->dtor(session, &session->server_hostkey_abstract);
@@ -392,10 +453,6 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
LIBSSH2_FREE(session, tmp);
}
if (session->local.banner) {
LIBSSH2_FREE(session, session->local.banner);
}
LIBSSH2_FREE(session, session);
}
/* }}} */
@@ -445,51 +502,63 @@ LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reas
/* }}} */
/* {{{ libssh2_session_methods
* Return the currently active methods
* Return the currently active methods for method_type
* NOTE: Currently lang_cs and lang_sc are ALWAYS set to empty string regardless of actual negotiation
* Strings should NOT be freed
*/
LIBSSH2_API void libssh2_session_methods(LIBSSH2_SESSION *session, char **kex, char **hostkey,
char **crypt_cs, char **crypt_sc,
char **mac_cs, char **mac_sc,
char **comp_cs, char **comp_sc,
char **lang_cs, char **lang_sc)
LIBSSH2_API char *libssh2_session_methods(LIBSSH2_SESSION *session, int method_type)
{
if (kex) {
*kex = session->kex->name;
/* All methods have char *name as their first element */
LIBSSH2_KEX_METHOD *method = NULL;
switch(method_type) {
case LIBSSH2_METHOD_KEX:
method = session->kex;
break;
case LIBSSH2_METHOD_HOSTKEY:
method = (LIBSSH2_KEX_METHOD*)session->hostkey;
break;
case LIBSSH2_METHOD_CRYPT_CS:
method = (LIBSSH2_KEX_METHOD*)session->local.crypt;
break;
case LIBSSH2_METHOD_CRYPT_SC:
method = (LIBSSH2_KEX_METHOD*)session->remote.crypt;
break;
case LIBSSH2_METHOD_MAC_CS:
method = (LIBSSH2_KEX_METHOD*)session->local.mac;
break;
case LIBSSH2_METHOD_MAC_SC:
method = (LIBSSH2_KEX_METHOD*)session->remote.mac;
break;
case LIBSSH2_METHOD_COMP_CS:
method = (LIBSSH2_KEX_METHOD*)session->local.comp;
break;
case LIBSSH2_METHOD_COMP_SC:
method = (LIBSSH2_KEX_METHOD*)session->remote.comp;
break;
case LIBSSH2_METHOD_LANG_CS:
return "";
break;
case LIBSSH2_METHOD_LANG_SC:
return "";
break;
default:
libssh2_error(session, LIBSSH2_ERROR_INVAL, "Invalid parameter specified for method_type", 0);
return NULL;
break;
}
if (hostkey) {
*hostkey = session->hostkey->name;
}
if (crypt_cs) {
*crypt_cs = session->local.crypt->name;
}
if (crypt_sc) {
*crypt_sc = session->remote.crypt->name;
}
if (mac_cs) {
*mac_cs = session->local.mac->name;
}
if (mac_sc) {
*mac_sc = session->remote.mac->name;
}
if (comp_cs) {
*comp_cs = session->local.comp->name;
}
if (comp_sc) {
*comp_sc = session->remote.comp->name;
}
if (lang_cs) {
*lang_cs = "";
}
if (lang_sc) {
*lang_sc = "";
if (!method) {
libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE, "No method negotiated", 0);
return NULL;
}
return method->name;
}
/* }}} */
/* {{{ libssh2_session_abstract
* Retreive a pointer to the abstract property
* Retrieve a pointer to the abstract property
*/
LIBSSH2_API void **libssh2_session_abstract(LIBSSH2_SESSION *session)
{
@@ -551,3 +620,291 @@ LIBSSH2_API int libssh2_session_last_error(LIBSSH2_SESSION *session, char **errm
return session->err_code;
}
/* }}} */
/* {{{ libssh2_session_flag
* Set/Get session flags
* Passing flag==0 will avoid changing session->flags while still returning its current value
*/
LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag, int value)
{
if (value) {
session->flags |= flag;
} else {
session->flags &= ~flag;
}
return session->flags;
}
/* }}} */
/* {{{ libssh2_poll_channel_read
* Returns 0 if no data is waiting on channel,
* non-0 if data is available
*/
static int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended)
{
LIBSSH2_SESSION *session = channel->session;
LIBSSH2_PACKET *packet = session->packets.head;
while (packet) {
if (((packet->data[0] == SSH_MSG_CHANNEL_DATA) && (extended == 0) && (channel->local.id == libssh2_ntohu32(packet->data + 1))) ||
((packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) && (extended != 0) && (channel->local.id == libssh2_ntohu32(packet->data + 1)))) {
/* Found data waiting to be read */
return 1;
}
packet = packet->next;
}
return 0;
}
/* }}} */
/* {{{ libssh2_poll_channel_write
* Returns 0 if writing to channel would block,
* non-0 if data can be written without blocking
*/
inline int libssh2_poll_channel_write(LIBSSH2_CHANNEL *channel)
{
return channel->local.window_size ? 1 : 0;
}
/* }}} */
/* {{{ libssh2_poll_listener_queued
* Returns 0 if no connections are waiting to be accepted
* non-0 if one or more connections are available
*/
inline int libssh2_poll_listener_queued(LIBSSH2_LISTENER *listener)
{
return listener->queue ? 1 : 0;
}
/* }}} */
/* {{{ libssh2_poll
* Poll sockets, channels, and listeners for activity
*/
LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout)
{
long timeout_remaining;
int i, active_fds;
#ifdef HAVE_POLL
LIBSSH2_SESSION *session = NULL;
struct pollfd sockets[nfds];
/* Setup sockets for polling */
for(i = 0; i < nfds; i++) {
fds[i].revents = 0;
switch (fds[i].type) {
case LIBSSH2_POLLFD_SOCKET:
sockets[i].fd = fds[i].fd.socket;
sockets[i].events = fds[i].events;
sockets[i].revents = 0;
break;
case LIBSSH2_POLLFD_CHANNEL:
sockets[i].fd = fds[i].fd.channel->session->socket_fd;
sockets[i].events = POLLIN;
sockets[i].revents = 0;
if (!session) session = fds[i].fd.channel->session;
break;
case LIBSSH2_POLLFD_LISTENER:
sockets[i].fd = fds[i].fd.listener->session->socket_fd;
sockets[i].events = POLLIN;
sockets[i].revents = 0;
if (!session) session = fds[i].fd.listener->session;
break;
default:
if (session) libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE, "Invalid descriptor passed to libssh2_poll()", 0);
return -1;
}
}
#elif defined(HAVE_SELECT)
LIBSSH2_SESSION *session = NULL;
int maxfd = 0;
fd_set rfds,wfds;
struct timeval tv;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
for(i = 0; i < nfds; i++) {
fds[i].revents = 0;
switch (fds[i].type) {
case LIBSSH2_POLLFD_SOCKET:
if (fds[i].events & LIBSSH2_POLLFD_POLLIN) {
FD_SET(fds[i].fd.socket, &rfds);
if (fds[i].fd.socket > maxfd) maxfd = fds[i].fd.socket;
}
if (fds[i].events & LIBSSH2_POLLFD_POLLOUT) {
FD_SET(fds[i].fd.socket, &wfds);
if (fds[i].fd.socket > maxfd) maxfd = fds[i].fd.socket;
}
break;
case LIBSSH2_POLLFD_CHANNEL:
FD_SET(fds[i].fd.channel->session->socket_fd, &rfds);
if (fds[i].fd.channel->session->socket_fd > maxfd) maxfd = fds[i].fd.channel->session->socket_fd;
if (!session) session = fds[i].fd.channel->session;
break;
case LIBSSH2_POLLFD_LISTENER:
FD_SET(fds[i].fd.listener->session->socket_fd, &rfds);
if (fds[i].fd.listener->session->socket_fd > maxfd) maxfd = fds[i].fd.listener->session->socket_fd;
if (!session) session = fds[i].fd.listener->session;
break;
default:
if (session) libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE, "Invalid descriptor passed to libssh2_poll()", 0);
return -1;
}
}
#else
/* No select() or poll()
* no sockets sturcture to setup
*/
timeout = 0;
#endif /* HAVE_POLL or HAVE_SELECT */
timeout_remaining = timeout;
do {
#if defined(HAVE_POLL) || defined(HAVE_SELECT)
int sysret;
#endif
active_fds = 0;
for (i = 0; i < nfds; i++) {
if (fds[i].events != fds[i].revents) {
switch (fds[i].type) {
case LIBSSH2_POLLFD_CHANNEL:
if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) && /* Want to be ready for read */
((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) { /* Not yet known to be ready for read */
fds[i].revents |= libssh2_poll_channel_read(fds[i].fd.channel, 0) ? LIBSSH2_POLLFD_POLLIN : 0;
}
if ((fds[i].events & LIBSSH2_POLLFD_POLLEXT) && /* Want to be ready for extended read */
((fds[i].revents & LIBSSH2_POLLFD_POLLEXT) == 0)) { /* Not yet known to be ready for extended read */
fds[i].revents |= libssh2_poll_channel_read(fds[i].fd.channel, 1) ? LIBSSH2_POLLFD_POLLEXT : 0;
}
if ((fds[i].events & LIBSSH2_POLLFD_POLLOUT) && /* Want to be ready for write */
((fds[i].revents & LIBSSH2_POLLFD_POLLOUT) == 0)) { /* Not yet known to be ready for write */
fds[i].revents |= libssh2_poll_channel_write(fds[i].fd.channel) ? LIBSSH2_POLLFD_POLLOUT : 0;
}
break;
case LIBSSH2_POLLFD_LISTENER:
if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) && /* Want a connection */
((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) { /* No connections known of yet */
fds[i].revents |= libssh2_poll_listener_queued(fds[i].fd.listener) ? LIBSSH2_POLLFD_POLLIN : 0;
}
break;
}
}
if (fds[i].revents) {
active_fds++;
}
}
if (active_fds) {
/* Don't block on the sockets if we have channels/listeners which are ready */
timeout_remaining = 0;
}
#ifdef HAVE_POLL
#ifdef HAVE_GETTIMEOFDAY
{
struct timeval tv_begin, tv_end;
gettimeofday((struct timeval *)&tv_begin, NULL);
sysret = poll(sockets, nfds, timeout_remaining);
gettimeofday((struct timeval *)&tv_end, NULL);
timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
timeout_remaining -= ceil((tv_end.tv_usec - tv_begin.tv_usec) / 1000);
}
#else
/* If the platform doesn't support gettimeofday,
* then just make the call non-blocking and walk away
*/
sysret = poll(sockets, nfds, timeout_remaining);
timeout_remaining = 0;
#endif /* HAVE_GETTIMEOFDAY */
if (sysret > 0) {
for (i = 0; i < nfds; i++) {
switch (fds[i].type) {
case LIBSSH2_POLLFD_SOCKET:
fds[i].revents = sockets[i].revents;
sockets[i].revents = 0; /* In case we loop again, be nice */
if (fds[i].revents) {
active_fds++;
}
break;
case LIBSSH2_POLLFD_CHANNEL:
if (sockets[i].events & POLLIN) {
/* Spin session until no data available */
while (libssh2_packet_read(fds[i].fd.channel->session, 0) > 0);
}
sockets[i].revents = 0;
break;
case LIBSSH2_POLLFD_LISTENER:
if (sockets[i].events & POLLIN) {
/* Spin session until no data available */
while (libssh2_packet_read(fds[i].fd.listener->session, 0) > 0);
}
sockets[i].revents = 0;
break;
}
}
}
#elif defined(HAVE_SELECT)
tv.tv_sec = timeout_remaining / 1000;
tv.tv_usec = (timeout_remaining % 1000) * 1000;
#ifdef HAVE_GETTIMEOFDAY
{
struct timeval tv_begin, tv_end;
gettimeofday((struct timeval *)&tv_begin, NULL);
sysret = select(maxfd, &rfds, &wfds, NULL, &tv);
gettimeofday((struct timeval *)&tv_end, NULL);
timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
timeout_remaining -= ceil((tv_end.tv_usec - tv_begin.tv_usec) / 1000);
}
#else
/* If the platform doesn't support gettimeofday,
* then just make the call non-blocking and walk away
*/
sysret = select(maxfd, &rfds, &wfds, NULL, &tv);
timeout_remaining = 0;
#endif
if (sysret > 0) {
for (i = 0; i < nfds; i++) {
switch (fds[i].type) {
case LIBSSH2_POLLFD_SOCKET:
if (FD_ISSET(fds[i].fd.socket, &rfds)) {
fds[i].revents |= LIBSSH2_POLLFD_POLLIN;
}
if (FD_ISSET(fds[i].fd.socket, &wfds)) {
fds[i].revents |= LIBSSH2_POLLFD_POLLOUT;
}
if (fds[i].revents) {
active_fds++;
}
break;
case LIBSSH2_POLLFD_CHANNEL:
if (FD_ISSET(fds[i].fd.channel->session->socket_fd, &rfds)) {
/* Spin session until no data available */
while (libssh2_packet_read(fds[i].fd.channel->session, 0) > 0);
}
break;
case LIBSSH2_POLLFD_LISTENER:
if (FD_ISSET(fds[i].fd.listener->session->socket_fd, &rfds)) {
/* Spin session until no data available */
while (libssh2_packet_read(fds[i].fd.listener->session, 0) > 0);
}
break;
}
}
}
#endif /* else no select() or poll() -- timeout (and by extension timeout_remaining) will be equal to 0 */
} while ((timeout_remaining > 0) && !active_fds);
return active_fds;
}
/* }}} */

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
@@ -83,7 +83,7 @@ struct _LIBSSH2_SFTP {
LIBSSH2_SFTP_HANDLE *handles;
unsigned long errno;
unsigned long last_errno;
};
#define LIBSSH2_SFTP_HANDLE_FILE 0
@@ -100,7 +100,7 @@ struct _LIBSSH2_SFTP_HANDLE {
union _libssh2_sftp_handle_data {
struct _libssh2_sftp_handle_file_data {
unsigned long long offset;
libssh2_uint64_t offset;
} file;
struct _libssh2_sftp_handle_dir_data {
unsigned long names_left;
@@ -318,13 +318,16 @@ static int libssh2_sftp_attrsize(LIBSSH2_SFTP_ATTRIBUTES *attrs)
static int libssh2_sftp_attr2bin(unsigned char *p, LIBSSH2_SFTP_ATTRIBUTES *attrs)
{
unsigned char *s = p;
unsigned long flag_mask = LIBSSH2_SFTP_ATTR_SIZE | LIBSSH2_SFTP_ATTR_UIDGID | LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME;
/* TODO: When we add SFTP4+ functionality flag_mask can get additional bits */
if (!attrs) {
libssh2_htonu32(s, 0);
return 4;
}
libssh2_htonu32(s, attrs->flags & 0x0000000); s += 4;
libssh2_htonu32(s, attrs->flags & flag_mask); s += 4;
if (attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) {
libssh2_htonu64(s, attrs->filesize); s += 8;
@@ -542,7 +545,7 @@ LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, char *
if (data[0] == SSH_FXP_STATUS) {
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Failed opening remote file", 0);
sftp->errno = libssh2_ntohu32(data + 5);
sftp->last_errno = libssh2_ntohu32(data + 5);
LIBSSH2_FREE(session, data);
return NULL;
}
@@ -627,7 +630,7 @@ LIBSSH2_API size_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
switch (data[0]) {
case SSH_FXP_STATUS:
sftp->errno = libssh2_ntohu32(data + 5);
sftp->last_errno = libssh2_ntohu32(data + 5);
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
LIBSSH2_FREE(session, data);
return -1;
@@ -722,7 +725,7 @@ LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
if (retcode == LIBSSH2_FX_EOF) {
return 0;
} else {
sftp->errno = retcode;
sftp->last_errno = retcode;
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
return -1;
}
@@ -809,7 +812,7 @@ LIBSSH2_API size_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *b
return count;
}
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
sftp->errno = retcode;
sftp->last_errno = retcode;
return -1;
}
@@ -865,7 +868,7 @@ LIBSSH2_API int libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_
if (retcode == LIBSSH2_FX_OK) {
return 0;
} else {
sftp->errno = retcode;
sftp->last_errno = retcode;
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
return -1;
}
@@ -938,7 +941,7 @@ LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle)
LIBSSH2_FREE(session, data);
if (retcode != LIBSSH2_FX_OK) {
sftp->errno = retcode;
sftp->last_errno = retcode;
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
return -1;
}
@@ -950,10 +953,12 @@ LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle)
handle->next->prev = NULL;
}
if (handle->u.dir.names_left) {
if ((handle->handle_type == LIBSSH2_SFTP_HANDLE_DIR) &&
handle->u.dir.names_left) {
LIBSSH2_FREE(session, handle->u.dir.names_packet);
}
LIBSSH2_FREE(session, handle->handle);
LIBSSH2_FREE(session, handle);
return 0;
@@ -1006,7 +1011,7 @@ LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, char *filename, int f
if (retcode == LIBSSH2_FX_OK) {
return 0;
} else {
sftp->errno = retcode;
sftp->last_errno = retcode;
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
return -1;
}
@@ -1064,17 +1069,17 @@ LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, char *source_filenam
break;
case LIBSSH2_FX_FILE_ALREADY_EXISTS:
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "File already exists and SSH_FXP_RENAME_OVERWRITE not specified", 0);
sftp->errno = retcode;
sftp->last_errno = retcode;
retcode = -1;
break;
case LIBSSH2_FX_OP_UNSUPPORTED:
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Operation Not Supported", 0);
sftp->errno = retcode;
sftp->last_errno = retcode;
retcode = -1;
break;
default:
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
sftp->errno = retcode;
sftp->last_errno = retcode;
retcode = -1;
}
@@ -1129,7 +1134,7 @@ LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_l
return 0;
} else {
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
sftp->errno = retcode;
sftp->last_errno = retcode;
return -1;
}
}
@@ -1177,7 +1182,7 @@ LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_l
if (retcode == LIBSSH2_FX_OK) {
return 0;
} else {
sftp->errno = retcode;
sftp->last_errno = retcode;
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
return -1;
}
@@ -1243,7 +1248,7 @@ LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, char *path, int path_le
if (retcode == LIBSSH2_FX_OK) {
return 0;
} else {
sftp->errno = retcode;
sftp->last_errno = retcode;
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
return -1;
}
@@ -1317,7 +1322,7 @@ LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, in
if (retcode == LIBSSH2_FX_OK) {
return 0;
} else {
sftp->errno = retcode;
sftp->last_errno = retcode;
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
return -1;
}
@@ -1334,6 +1339,7 @@ LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, in
link_len = target_len;
}
memcpy(target, data + 13, link_len);
LIBSSH2_FREE(session, data);
return link_len;
}
@@ -1344,6 +1350,6 @@ LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, in
*/
LIBSSH2_API unsigned long libssh2_sftp_last_error(LIBSSH2_SFTP *sftp)
{
return sftp->errno;
return sftp->last_errno;
}
/* }}} */

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
@@ -36,7 +36,12 @@
*/
#include "libssh2_priv.h"
#include <stdio.h>
/* Needed for struct iovec on some platforms */
#ifdef HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif
/* {{{ proto libssh2_userauth_list
* List authentication methods
@@ -80,7 +85,7 @@ LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_SUCCESS, &data, &data_len, 1) == 0) {
/* Wow, who'dve thought... */
LIBSSH2_FREE(session, data);
session->authenticated = 1;
session->state |= LIBSSH2_STATE_AUTHENTICATED;
return NULL;
}
@@ -105,7 +110,7 @@ LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username
*/
LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session)
{
return session->authenticated;
return session->state & LIBSSH2_STATE_AUTHENTICATED;
}
/* }}} */
@@ -151,7 +156,7 @@ LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, char *use
while (1) {
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_SUCCESS, &data, &data_len, 1) == 0) {
LIBSSH2_FREE(session, data);
session->authenticated = 1;
session->state |= LIBSSH2_STATE_AUTHENTICATED;
return 0;
}
@@ -326,6 +331,137 @@ static int libssh2_file_read_privatekey(LIBSSH2_SESSION *session, LIBSSH2_HOSTKE
}
/* }}} */
/* {{{ libssh2_userauth_hostbased_fromfile_ex
* Authenticate using a keypair found in the named files
*/
LIBSSH2_API int libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, char *username, int username_len,
char *publickey, char *privatekey,
char *passphrase,
char *hostname, int hostname_len,
char *local_username, int local_username_len)
{
LIBSSH2_HOSTKEY_METHOD *privkeyobj;
void *abstract;
unsigned char buf[5];
struct iovec datavec[4];
unsigned char *method, *pubkeydata, *packet, *s, *sig;
unsigned long method_len, pubkeydata_len, packet_len, sig_len;
if (libssh2_file_read_publickey(session, &method, &method_len, &pubkeydata, &pubkeydata_len, publickey)) {
return -1;
}
packet_len = username_len + method_len + hostname_len + local_username_len + pubkeydata_len + 48;
/* packet_type(1) + username_len(4) + servicename_len(4) + service_name(14)"ssh-connection" +
* authmethod_len(4) + authmethod(9)"hostbased" + method_len(4) + pubkeydata_len(4) +
* local_username_len(4)
*/
/* Preallocate space for an overall length, method name again,
* and the signature, which won't be any larger than the size of the publickeydata itself */
s = packet = LIBSSH2_ALLOC(session, packet_len + 4 + (4 + method_len) + (4 + pubkeydata_len));
*(s++) = SSH_MSG_USERAUTH_REQUEST;
libssh2_htonu32(s, username_len); s += 4;
memcpy(s, username, username_len); s += username_len;
libssh2_htonu32(s, 14); s += 4;
memcpy(s, "ssh-connection", 14); s += 14;
libssh2_htonu32(s, 9); s += 4;
memcpy(s, "hostbased", 9); s += 9;
libssh2_htonu32(s, method_len); s += 4;
memcpy(s, method, method_len); s += method_len;
libssh2_htonu32(s, pubkeydata_len); s += 4;
memcpy(s, pubkeydata, pubkeydata_len); s += pubkeydata_len;
libssh2_htonu32(s, hostname_len); s += 4;
memcpy(s, hostname, hostname_len); s += hostname_len;
libssh2_htonu32(s, local_username_len); s += 4;
memcpy(s, local_username, local_username_len); s += local_username_len;
if (libssh2_file_read_privatekey(session, &privkeyobj, &abstract, method, method_len, privatekey, passphrase)) {
LIBSSH2_FREE(session, method);
LIBSSH2_FREE(session, packet);
return -1;
}
libssh2_htonu32(buf, session->session_id_len);
datavec[0].iov_base = buf;
datavec[0].iov_len = 4;
datavec[1].iov_base = session->session_id;
datavec[1].iov_len = session->session_id_len;
datavec[2].iov_base = packet;
datavec[2].iov_len = packet_len;
if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) {
LIBSSH2_FREE(session, method);
LIBSSH2_FREE(session, packet);
if (privkeyobj->dtor) {
privkeyobj->dtor(session, &abstract);
}
return -1;
}
if (privkeyobj->dtor) {
privkeyobj->dtor(session, &abstract);
}
if (sig_len > pubkeydata_len ) {
/* Should *NEVER* happen, but...well.. better safe than sorry */
packet = LIBSSH2_REALLOC(session, packet, packet_len + 4 + (4 + method_len) + (4 + sig_len)); /* PK sigblob */
if (!packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Failed allocating additional space for userauth-hostbased packet", 0);
LIBSSH2_FREE(session, method);
return -1;
}
}
s = packet + packet_len;
libssh2_htonu32(s, 4 + method_len + 4 + sig_len); s += 4;
libssh2_htonu32(s, method_len); s += 4;
memcpy(s, method, method_len); s += method_len;
LIBSSH2_FREE(session, method);
libssh2_htonu32(s, sig_len); s += 4;
memcpy(s, sig, sig_len); s += sig_len;
LIBSSH2_FREE(session, sig);
if (libssh2_packet_write(session, packet, s - packet)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-hostbased request", 0);
LIBSSH2_FREE(session, packet);
return -1;
}
LIBSSH2_FREE(session, packet);
while (1) {
unsigned char *data;
unsigned long data_len;
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_SUCCESS, &data, &data_len, 1) == 0) {
/* We are us and we've proved it. */
LIBSSH2_FREE(session, data);
session->state |= LIBSSH2_STATE_AUTHENTICATED;
return 0;
}
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_FAILURE, &data, &data_len, 0) == 0) {
/* This public key is not allowed for this user on this server */
LIBSSH2_FREE(session, data);
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, "Invalid signature for supplied public key, or bad username/public key combination", 0);
return -1;
}
/* TODO: Timeout? */
}
return 0;
}
/* }}} */
/* {{{ libssh2_userauth_publickey_fromfile_ex
* Authenticate using a keypair found in the named files
*/
@@ -389,7 +525,7 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
LIBSSH2_FREE(session, packet);
LIBSSH2_FREE(session, method);
LIBSSH2_FREE(session, pubkeydata);
session->authenticated = 1;
session->state |= LIBSSH2_STATE_AUTHENTICATED;
return 0;
}
@@ -485,7 +621,7 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_SUCCESS, &data, &data_len, 1) == 0) {
/* We are us and we've proved it. */
LIBSSH2_FREE(session, data);
session->authenticated = 1;
session->state |= LIBSSH2_STATE_AUTHENTICATED;
return 0;
}

View File

@@ -1,11 +1,17 @@
#include "libssh2.h"
#include <netinet/in.h>
#include <sys/socket.h>
#ifndef WIN32
# include <netinet/in.h>
# include <sys/socket.h>
# include <unistd.h>
#else
# include <winsock2.h>
#endif
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
int main(int argc, char *argv[]) {
@@ -14,16 +20,26 @@ int main(int argc, char *argv[]) {
char *fingerprint;
LIBSSH2_SESSION *session;
LIBSSH2_CHANNEL *channel;
#ifdef WIN32
WSADATA wsadata;
WSAStartup(WINSOCK_VERSION, &wsadata);
#endif
/* Ultra basic "connect to port 22 on localhost"
* Your code is responsible for creating the socket establishing the connection
*/
sock = socket(AF_INET, SOCK_STREAM, 0);
#ifndef WIN32
fcntl(sock, F_SETFL, 0);
#endif
sin.sin_family = AF_INET;
sin.sin_port = htons(22);
sin.sin_addr.s_addr = htonl(0x7F000001);
connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in));
if (connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) != 0) {
fprintf(stderr, "failed to connect!\n");
return -1;
}
/* Create a session instance and start it up
* This will trade welcome banners, exchange keys, and setup crypto, compression, and MAC layers
@@ -114,8 +130,13 @@ int main(int argc, char *argv[]) {
libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
libssh2_session_free(session);
#ifdef WIN32
Sleep(1000);
closesocket(sock);
#else
sleep(1);
close(sock);
#endif
printf("all done\n");
return 0;
}

19
test/Makefile Normal file
View File

@@ -0,0 +1,19 @@
LIBS = -L../src -lssh2
CFLAGS = -c -I../include
CC = gcc -Wall -g
OBJS = main.o util.o methods.o auth.o forward.o
all: libssh2-test
libssh2-test: $(OBJS)
$(CC) -o libssh2-test $(OBJS) $(LIBS)
main.o: main.c libssh2-test.h
util.o: util.c libssh2-test.h
methods.o: methods.c libssh2-test.h
auth.o: auth.c libssh2-test.h
forward.o: forward.c libssh2-test.h
clean:
rm -f $(OBJS) libssh2-test

58
test/README Normal file
View File

@@ -0,0 +1,58 @@
This directory contains some code meant to test libssh2's protocol compliance
against other implementations, as well as providing a body of example code.
The following tests are done:
* methods.c:
Tries a connection + authentication with every possible key exchange,
hostkey, encryption, mac and compression method (see
libssh2_session_method_pref()).
The first connection is done with methods that are required to be supported
by server implementations according to the standard: key exchange method
"diffie-hellman-group1-sha1", hostkey method "ssh-dss", encryption method
"3des-cbc", mac method "hmac-sha1" and no compression.
Then every method is tried in turn, with all the other methods set to these
"known good" methods. Hence, the test will report exactly which method of
which method type failed to initialize a connection. A total of 26 tests
is performed.
* auth.c:
This test tries to authenticate with username+pasword, and public/private
key + passphrase. In addition, the hostkey is retrieved in both MD5 and SHA1
formats, and sanity-checked.
* forward.c:
This test tries to make the remote host listen on a port, then requests a
tunnel through the remote host to that port, accepting the connection
locally. A block of data is then sent through the tunnel, and this data is
then compared to the original when received.
This is tried four times: one each for every combination of the remote
host's bind address provided or not, and bind port provided or not.
If you want to add a test, you will need to do the following:
* create a new source file, and add it to the Makefile
* call your main function (runtest_yourtest) from main() in main.c
* at the top of your source file, put:
#include <libssh2.h>
#include "libssh2-test.h"
extern struct authdefs auth;
* call init_test("description of your test", number_of_steps)
* use new_socket() to get a connected socket, and log_line() to log
errors if your test fails.
* before every step in your test, call increase_progress()
* after every step, if it was successful, call step_successful()
* after your test, print a "\n".

215
test/auth.c Normal file
View File

@@ -0,0 +1,215 @@
/*
* auth.c -- test authentication methods
*
* Copyright (C) 2005 Bert Vermeulen <bert@biot.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the copyright holder nor the names
* of any other contributors may be used to endorse or
* promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <libssh2.h>
#include "libssh2-test.h"
extern struct authdefs auth;
static int auth_publickey(LIBSSH2_SESSION *session)
{
if(libssh2_userauth_publickey_fromfile(session, auth.username,
auth.pubkey, auth.privkey, auth.passphrase))
{
log_line(ERROR, "Public key authentication failed\n");
return(0);
}
if(!libssh2_userauth_authenticated(session))
{
log_line(ERROR, "Public key authentication succeeded, but authentication not set\n");
return(0);
}
return(1);
}
static int auth_password(LIBSSH2_SESSION *session)
{
if(libssh2_userauth_password(session, auth.username, auth.password))
{
log_line(ERROR, "Password authentication failed\n");
return(0);
}
if(!libssh2_userauth_authenticated(session))
{
log_line(ERROR, "Password authentication succeeded, but authentication not set\n");
return(0);
}
return(1);
}
static void all_auth(void)
{
LIBSSH2_SESSION *session;
int sock, size, res, sum, i;
unsigned char *hash;
char *errmsg, *_authlist, *authlist, *authmethod, *sep;
authlist = NULL;
authmethod = "";
while(authmethod)
{
sock = new_socket();
if(sock == -1)
{
log_line(ERROR, "new_socket() failed\n");
return;
}
session = libssh2_session_init();
res = libssh2_session_startup(session, sock);
if(res)
{
libssh2_session_last_error(session, &errmsg, &size, 0);
log_line(ERROR, "session_startup() failed: %s\n", errmsg);
close(sock);
return;
}
if(!authlist)
{
_authlist = libssh2_userauth_list(session, auth.username, strlen(auth.username));
if(_authlist == NULL)
{
libssh2_session_last_error(session, &errmsg, &size, 0);
log_line(ERROR, "userauth_list() failed: %s\n", errmsg);
libssh2_session_disconnect(session, "All done.");
libssh2_session_free(session);
close(sock);
return;
}
authlist = strdup(_authlist);
authmethod = authlist;
/* only need to check hostkey hashes once... might as well do that here */
increase_progress();
hash = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
if(hash)
{
sum = 0;
for(i = 0; i < 16; i++)
sum += hash[i];
if(sum > 0)
step_successful();
else
log_line(ERROR, "MD5 hostkey hash invalid\n");
}
else
log_line(ERROR, "MD5 hostkey hash failed\n");
increase_progress();
hash = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
if(hash)
{
sum = 0;
for(i = 0; i < 20; i++)
sum += hash[i];
if(sum > 0)
step_successful();
else
log_line(ERROR, "SHA1 hostkey hash invalid\n");
}
else
log_line(ERROR, "SHA1 hostkey hash failed\n");
}
if( (sep = strchr(authmethod, ',')) )
*sep++ = '\0';
if(!strcasecmp(authmethod, "publickey"))
{
increase_progress();
if(auth_publickey(session))
step_successful();
}
else if(!strcasecmp(authmethod, "password"))
{
increase_progress();
if(auth_password(session))
step_successful();
}
else if(!strcasecmp(authmethod, "keyboard-interactive"))
{
/* no idea how to test this */
}
else
{
log_line(DEBUG, "Unknown authentication method %s\n", authmethod);
}
authmethod = sep;
libssh2_session_disconnect(session, "All done.");
libssh2_session_free(session);
close(sock);
}
free(authlist);
printf("\n");
}
void runtest_auth(void)
{
init_test("authentication", 4);
all_auth();
}

272
test/forward.c Normal file
View File

@@ -0,0 +1,272 @@
/*
* forward.c -- ssh2 port forwarding test
*
* Copyright (C) 2005 Bert Vermeulen <bert@biot.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the copyright holder nor the names
* of any other contributors may be used to endorse or
* promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <wordexp.h>
#include <libssh2.h>
#include "libssh2-test.h"
struct authdefs auth;
extern struct addrinfo *cur_ai;
#define LISTEN_PORT 22617
#define TESTBUF_SIZE 10
static int loopback(LIBSSH2_SESSION *session, int hostbind, int portbind)
{
LIBSSH2_CHANNEL *inbound, *outbound;
LIBSSH2_LISTENER *listener;
int listen_port, size, i, res;
char paramstr[64], ipstr[128], *errmsg, *host, *sendbuf, *recvbuf;
snprintf(paramstr, 64, "(%shost bind, %sport bind)", hostbind ? "" : "no ", portbind ? "" : "no ");
host = NULL;
if(hostbind)
{
if(getnameinfo(cur_ai->ai_addr, cur_ai->ai_addrlen, ipstr, sizeof(ipstr), NULL, 0, NI_NUMERICHOST))
{
log_line(ERROR, "getnameinfo() failed\n");
return(0);
}
host = ipstr;
}
listen_port = 0;
if(portbind)
listen_port = LISTEN_PORT;
listener = libssh2_channel_forward_listen_ex(session, host, listen_port, &listen_port, 2);
if(!listener)
{
libssh2_session_last_error(session, &errmsg, &size, 0);
log_line(ERROR, "Listen failed %s: %s\n", paramstr, errmsg);
return(0);
}
outbound = libssh2_channel_direct_tcpip(session, auth.hostname, listen_port);
if(!outbound)
{
libssh2_session_last_error(session, &errmsg, &size, 0);
log_line(ERROR, "Outbound channel setup failed %s: %s\n", paramstr, errmsg);
libssh2_channel_forward_cancel(listener);
return(0);
}
inbound = libssh2_channel_forward_accept(listener);
if(!inbound)
{
libssh2_session_last_error(session, &errmsg, &size, 0);
log_line(ERROR, "Forwarding channel accept failed %s: %s\n", paramstr, errmsg);
libssh2_channel_free(outbound);
libssh2_channel_forward_cancel(listener);
return(0);
}
sendbuf = malloc(TESTBUF_SIZE);
if(!sendbuf)
{
log_line(ERROR, "sendbuf malloc failed\n");
libssh2_channel_free(inbound);
libssh2_channel_free(outbound);
libssh2_channel_forward_cancel(listener);
return(0);
}
for(i = 0; i < TESTBUF_SIZE; i++)
sendbuf[i] = (char) random;
res = libssh2_channel_write(outbound, sendbuf, TESTBUF_SIZE);
if(res != TESTBUF_SIZE)
{
if(res == -1)
libssh2_session_last_error(session, &errmsg, &size, 0);
else
errmsg = NULL;
log_line(ERROR, "Unable to send %d bytes across tunnel %s%s%s\n",
TESTBUF_SIZE, paramstr, errmsg ? ": " : "", errmsg ? errmsg : "");
free(sendbuf);
libssh2_channel_free(inbound);
libssh2_channel_free(outbound);
libssh2_channel_forward_cancel(listener);
return(0);
}
recvbuf = malloc(TESTBUF_SIZE);
if(!recvbuf)
{
log_line(ERROR, "recvbuf malloc failed\n");
free(sendbuf);
libssh2_channel_free(inbound);
libssh2_channel_free(outbound);
libssh2_channel_forward_cancel(listener);
return(0);
}
res = libssh2_channel_read(inbound, recvbuf, TESTBUF_SIZE);
if(res != TESTBUF_SIZE)
{
if(res == -1)
libssh2_session_last_error(session, &errmsg, &size, 0);
else
errmsg = NULL;
log_line(ERROR, "Unable to receive %d bytes across tunnel %s%s%s\n",
TESTBUF_SIZE, paramstr, errmsg ? ": " : "", errmsg ? errmsg : "");
free(sendbuf);
free(recvbuf);
libssh2_channel_free(inbound);
libssh2_channel_free(outbound);
libssh2_channel_forward_cancel(listener);
return(0);
}
res = 1;
for(i = 0; i < TESTBUF_SIZE; i++)
{
if(recvbuf[i] != sendbuf[i])
{
log_line(ERROR, "Received data did not match sent data %s\n", paramstr);
res = 0;
break;
}
}
free(sendbuf);
free(recvbuf);
libssh2_channel_free(inbound);
libssh2_channel_free(outbound);
libssh2_channel_forward_cancel(listener);
return(res);
}
static void all_forward(void)
{
LIBSSH2_SESSION *session;
int sock, res, size;
char *errmsg;
sock = new_socket();
if(sock == -1)
{
log_line(ERROR, "Unable to open a socket\n");
return;
}
session = libssh2_session_init();
res = libssh2_session_startup(session, sock);
if(res)
{
libssh2_session_last_error(session, &errmsg, &size, 0);
log_line(ERROR, "Session startup failed: %s\n", errmsg);
close(sock);
return;
}
if(libssh2_userauth_password(session, auth.username, auth.password))
{
libssh2_session_last_error(session, &errmsg, &size, 0);
log_line(ERROR, "Authentication failed%s%s\n", errmsg[0] ? ": " : "", errmsg);
libssh2_session_disconnect(session, "All done.");
libssh2_session_free(session);
close(sock);
return;
}
increase_progress();
if(loopback(session, 1, 1))
step_successful();
increase_progress();
if(loopback(session, 1, 0))
step_successful();
increase_progress();
if(loopback(session, 0, 1))
step_successful();
increase_progress();
if(loopback(session, 0, 0))
step_successful();
libssh2_session_disconnect(session, "All done.");
libssh2_session_free(session);
close(sock);
printf("\n");
}
void runtest_forward(void)
{
init_test("TCP port forwarding/tunneling", 4);
all_forward();
}

102
test/libssh2-test.h Normal file
View File

@@ -0,0 +1,102 @@
/*
* prototest.h
*
* Copyright (C) 2005 Bert Vermeulen <bert@biot.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the copyright holder nor the names
* of any other contributors may be used to endorse or
* promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#ifndef LIBSSH2_TEST_H
#define LIBSSH2_TEST_H 1
#define MAX_LOGLINE_LEN 256
void log_line(int priority, char *format, ...);
void init_test(char *msg, int num_items);
void increase_progress(void);
void step_successful(void);
void output_testresults(void);
int new_socket(void);
void runtest_methods(void);
void runtest_auth(void);
void runtest_forward(void);
struct authdefs {
char *hostname;
char *port;
char *username;
char *password;
char *privkey;
char *pubkey;
char *passphrase;
};
struct methodlist {
int method_type;
char *description;
char **list;
int cursor;
int done;
};
struct logentry {
int priority;
char *logline;
struct logentry *next;
};
struct logresults {
char *description;
int num_steps;
int success_steps;
int progress;
struct logentry *log;
struct logresults *next;
};
enum {
ERROR,
WARNING,
NORMAL,
DEBUG
};
#endif

174
test/main.c Normal file
View File

@@ -0,0 +1,174 @@
/*
* main.c -- ssh2 protocol compliance tester for libssh2
*
* Copyright (C) 2005 Bert Vermeulen <bert@biot.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the copyright holder nor the names
* of any other contributors may be used to endorse or
* promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <wordexp.h>
#include <libssh2.h>
#include "libssh2-test.h"
struct authdefs auth;
char *progress_message;
int progress, progress_max;
struct addrinfo *hostai = NULL, *cur_ai = NULL;
extern struct logresults *testlogs;
extern struct logentry *logfile;
void cleanup(void)
{
struct logresults *test, *nexttest;
struct logentry *logfile, *nextlog;
if(hostai)
freeaddrinfo(hostai);
test = testlogs;
while(test)
{
logfile = test->log;
while(logfile)
{
nextlog = logfile->next;
free(logfile->logline);
free(logfile);
logfile = nextlog;
}
nexttest = test->next;
free(test);
test = nexttest;
}
free(auth.hostname);
free(auth.port);
free(auth.username);
free(auth.password);
free(auth.privkey);
free(auth.pubkey);
free(auth.passphrase);
}
char *get_interactive(char *prompt, int size, char *default_value)
{
char *str;
if( !(str = malloc(size)) )
{
log_line(ERROR, "unable to malloc %d bytes for %s\n", size, prompt);
return(NULL);
}
printf("%s [%s]: ", prompt, default_value);
fgets(str, size, stdin);
if(str[strlen(str)-1] == '\n')
str[strlen(str)-1] = 0;
if(!str[0])
strncpy(str, default_value, size);
return(str);
}
char *resolve_tilde(char *path)
{
wordexp_t we;
if( (wordexp(path, &we, 0)) == 0 && we.we_wordc == 1)
{
free(path);
path = strdup(we.we_wordv[0]);
wordfree(&we);
}
return(path);
}
void get_auth(void)
{
auth.hostname = get_interactive("hostname", 64, "localhost");
auth.port = get_interactive("port", 6, "22");
// auth.username = get_interactive("username", 20, getenv("USER"));
// auth.password = get_interactive("password", 20, "");
auth.username = get_interactive("username", 20, "bert2");
auth.password = get_interactive("password", 20, "blinko");
auth.privkey = resolve_tilde(get_interactive("private key filename", 128, "~/.ssh/id_dsa"));
auth.pubkey = resolve_tilde(get_interactive("public key filename", 128, "~/.ssh/id_dsa.pub"));
auth.passphrase = get_interactive("passphrase", 256, "");
}
int main(int argc, char **argv)
{
get_auth();
if(!strlen(auth.username) || !strlen(auth.password))
{
printf("Not enough authentication info to continue.\n");
return(1);
}
runtest_methods();
runtest_auth();
runtest_forward();
output_testresults();
cleanup();
return(0);
}

214
test/methods.c Normal file
View File

@@ -0,0 +1,214 @@
/*
* methods.c -- test all available key exchange, hostkey, encryption, mac
* and compression methods
*
* Copyright (C) 2005 Bert Vermeulen <bert@biot.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the copyright holder nor the names
* of any other contributors may be used to endorse or
* promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <unistd.h>
#include <libssh2.h>
#include "libssh2-test.h"
extern struct authdefs auth;
static char *kex_methods[] = {
"diffie-hellman-group1-sha1",
"diffie-hellman-group14-sha1",
"diffie-hellman-group-exchange-sha1",
NULL
};
static char *hostkey_methods[] = {
"ssh-dss",
"ssh-rsa",
NULL
};
static char *crypt_methods[] = {
"3des-cbc",
"aes256-cbc",
"aes192-cbc",
"aes128-cbc",
"blowfish-cbc",
"arcfour",
"cast128-cbc",
NULL
};
static char *mac_methods[] = {
"hmac-sha1",
"hmac-sha1-96",
"hmac-md5",
"hmac-md5-96",
"hmac-ripemd160",
NULL
};
static char *compression_methods[] = {
"none",
"zlib",
NULL
};
static struct methodlist methods[] = {
{ LIBSSH2_METHOD_KEX, "kex", kex_methods, 0, 0 },
{ LIBSSH2_METHOD_HOSTKEY, "hostkey", hostkey_methods, 0, 0 },
{ LIBSSH2_METHOD_CRYPT_CS, "crypt (cs)", crypt_methods, 0, 0 },
{ LIBSSH2_METHOD_CRYPT_SC, "crypt (sc)", crypt_methods, 0, 0 },
{ LIBSSH2_METHOD_MAC_CS, "MAC (cs)", mac_methods, 0, 0 },
{ LIBSSH2_METHOD_MAC_SC, "MAC (sc)", mac_methods, 0, 0 },
{ LIBSSH2_METHOD_COMP_CS, "compression (cs)", compression_methods, 0, 0 },
{ LIBSSH2_METHOD_COMP_SC, "compression (sc)", compression_methods, 0, 0 },
{ 0, NULL, NULL, 0, 0 }
};
/*
static void dump_methods(LIBSSH2_SESSION *session)
{
printf(" Key exchange methods: %s\n", libssh2_session_methods(session, LIBSSH2_METHOD_KEX));
printf(" Hostkey methods: %s\n", libssh2_session_methods(session, LIBSSH2_METHOD_HOSTKEY));
printf(" Crypt C->S methods: %s\n", libssh2_session_methods(session, LIBSSH2_METHOD_CRYPT_CS));
printf(" Crypt S->C methods: %s\n", libssh2_session_methods(session, LIBSSH2_METHOD_CRYPT_SC));
printf(" MAC C->S methods: %s\n", libssh2_session_methods(session, LIBSSH2_METHOD_MAC_CS));
printf(" MAC S->C methods: %s\n", libssh2_session_methods(session, LIBSSH2_METHOD_MAC_SC));
printf("Compression C->S methods: %s\n", libssh2_session_methods(session, LIBSSH2_METHOD_COMP_CS));
printf("Compression S->C methods: %s\n", libssh2_session_methods(session, LIBSSH2_METHOD_COMP_SC));
}
*/
static void cycle_methods(void)
{
LIBSSH2_SESSION *session;
int sock, size, res, method_type, method, i, methods_set;
char *errmsg;
method_type = 0;
method = 0;
while(methods[method_type].description)
{
while(methods[method_type].list[method])
{
increase_progress();
sock = new_socket();
if(sock == -1)
{
log_line(ERROR, "new_socket() failed");
return;
}
session = libssh2_session_init();
methods_set = 1;
for(i = 0; methods[i].description; i++)
{
res = libssh2_session_method_pref(session, methods[i].method_type,
methods[i].list[ i == method_type ? method : 0 ]);
if(res != 0)
{
libssh2_session_last_error(session, &errmsg, &size, 0);
log_line(ERROR, "%s method set to '%s' failed: %s\n",
methods[i].description,
methods[i].list[ i == method_type ? method : 0 ], errmsg);
methods_set = 0;
break;
}
i++;
}
if(methods_set)
{
res = libssh2_session_startup(session, sock);
if(res == 0)
{
if(libssh2_userauth_password(session, auth.username, auth.password))
{
log_line(ERROR, "Authentication failed\n");
}
else
step_successful();
}
else
{
libssh2_session_last_error(session, &errmsg, &size, 0);
log_line(ERROR, "Session startup for %s method %s failed: %s\n",
methods[method_type].description, methods[method_type].list[method], errmsg);
}
}
libssh2_session_disconnect(session, "All done.");
libssh2_session_free(session);
close(sock);
method++;
}
method_type++;
method = 1;
}
printf("\n");
}
void runtest_methods(void)
{
int i, j, num_steps;
num_steps = 0;
for(i = 0; methods[i].description; i++)
{
for(j = 0; methods[i].list[j]; j++)
;
num_steps += j - 1;
}
num_steps++;
init_test("kex/hostkey/crypt/mac/compression methods", num_steps);
cycle_methods();
}

222
test/util.c Normal file
View File

@@ -0,0 +1,222 @@
/*
* util.c
*
* Copyright (C) 2005 Bert Vermeulen <bert@biot.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the copyright holder nor the names
* of any other contributors may be used to endorse or
* promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdarg.h>
#include <errno.h>
#include <libssh2.h>
#include "libssh2-test.h"
extern struct addrinfo *hostai, *cur_ai;
struct logresults *testlogs = NULL, *cur_testlog;
struct logentry *logfile = NULL, *cur_logentry;
extern struct authdefs auth;
extern char *progress_message;
extern int progress, progress_max;
struct loglevel {
int priority;
char *descr;
} loglevels[] = {
{ ERROR, "ERROR" },
{ WARNING, "WARNING" },
{ NORMAL, "NORMAL" },
{ DEBUG, "DEBUG" }
};
void log_line(int priority, char *format, ...)
{
va_list args;
struct logentry *entry;
char line[MAX_LOGLINE_LEN];
va_start(args, format);
vsnprintf(line, MAX_LOGLINE_LEN, format, args);
va_end(args);
entry = malloc(sizeof(struct logentry));
entry->priority = priority;
entry->logline = malloc(strlen(line)+1);
strcpy(entry->logline, line);
entry->next = NULL;
if(!cur_testlog->log)
cur_testlog->log = entry;
else
cur_logentry->next = entry;
cur_logentry = entry;
}
void init_test(char *msg, int num_items)
{
struct logresults *newtest;
newtest = malloc(sizeof(struct logresults));
newtest->description = msg;
newtest->num_steps = num_items;
newtest->success_steps = 0;
newtest->progress = 0;
newtest->log = NULL;
newtest->next = NULL;
if(!testlogs)
testlogs = newtest;
else
cur_testlog->next = newtest;
cur_testlog = newtest;
}
void increase_progress(void)
{
cur_testlog->progress++;
printf("Testing %s... %3d/%d\r", cur_testlog->description, cur_testlog->progress, cur_testlog->num_steps);
fflush(stdout);
}
void step_successful(void)
{
cur_testlog->success_steps++;
}
void output_testresults(void)
{
struct logresults *test;
struct logentry *logfile;
int total_steps, total_success;
printf("\nTest results\n============\n");
total_steps = 0;
total_success = 0;
test = testlogs;
while(test)
{
total_steps += test->num_steps;
total_success += test->success_steps;
printf("Test: %s (%d/%d)\n", test->description, test->success_steps, test->num_steps);
logfile = test->log;
while(logfile)
{
printf(" %s", logfile->logline);
logfile = logfile->next;
}
test = test->next;
}
printf("%d/%d steps successful\n", total_success, total_steps);
}
int new_socket(void)
{
int sock, res;
struct addrinfo hints, *ai;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = PF_INET;
hints.ai_socktype = SOCK_STREAM;
if(!hostai)
{
res = getaddrinfo(auth.hostname, auth.port, &hints, &hostai);
if(res)
{
printf("unable to resolve %s: %s\n", auth.hostname, gai_strerror(res));
return(-1);
}
}
sock = 0;
ai = hostai;
while(ai)
{
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if(sock > 0)
{
res = connect(sock, ai->ai_addr, ai->ai_addrlen);
if(res == 0)
break;
close(sock);
sock = 0;
}
ai = ai->ai_next;
}
if(!sock)
{
printf("unable to connect: %s\n", strerror(errno));
close(sock);
sock = -1;
}
cur_ai = ai;
return(sock);
}

12
win32/.cvsignore Normal file
View File

@@ -0,0 +1,12 @@
*.lib
*.pdb
*.dll
*.exe
*.obj
.*.swp
Debug
Release
*.exp
*.ncb
*.opt
*.plg

29
win32/config.mk Normal file
View File

@@ -0,0 +1,29 @@
# Tweak these for your system
OPENSSLINC=..\libssh2_build\include
OPENSSLLIB=..\libssh2_build\lib
ZLIBINC=-DLIBSSH2_HAVE_ZLIB=1 /I..\libssh2_build\include
ZLIBLIB=..\libssh2_build\lib
!if "$(TARGET)" == ""
TARGET=Release
!endif
!if "$(TARGET)" == "Debug"
SUFFIX=_debug
CPPFLAGS=/Od /MDd
DLLFLAGS=/DEBUG /LDd
!else
CPPFLAGS=/Og /Oi /O2 /Oy /GF /Y- /MD /DNDEBUG
DLLFLAGS=/DEBUG /LD
!endif
CPPFLAGS=/nologo /GL /Zi /EHsc $(CPPFLAGS) /Iwin32 /Iinclude /I$(OPENSSLINC) $(ZLIBINC) -DLIBSSH2_WIN32
CFLAGS=$(CPPFLAGS)
DLLFLAGS=$(CFLAGS) $(DLLFLAGS)
LIBS=$(OPENSSLLIB)\libeay32.lib $(OPENSSLLIB)\ssleay32.lib ws2_32.lib $(ZLIBLIB)\zlib.lib
INTDIR=$(TARGET)\$(SUBDIR)

156
win32/libssh2.dsp Normal file
View File

@@ -0,0 +1,156 @@
# Microsoft Developer Studio Project File - Name="libssh2" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Static Library" 0x0104
CFG=libssh2 - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "libssh2.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "libssh2.mak" CFG="libssh2 - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "libssh2 - Win32 Release" (based on "Win32 (x86) Static Library")
!MESSAGE "libssh2 - Win32 Debug" (based on "Win32 (x86) Static Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "libssh2 - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "libssh2___Win32_Release"
# PROP BASE Intermediate_Dir "libssh2___Win32_Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "LIBSSH2_WIN32" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\include" /I "..\win32" /D "WIN32" /D "NDEBUG" /D "LIBSSH2_WIN32" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ELSEIF "$(CFG)" == "libssh2 - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "LIBSSH2_WIN32" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\include" /I "..\win32" /D "WIN32" /D "_DEBUG" /D "LIBSSH2_WIN32" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo /out:"Debug\libssh2d.lib"
!ENDIF
# Begin Target
# Name "libssh2 - Win32 Release"
# Name "libssh2 - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=..\src\channel.c
# End Source File
# Begin Source File
SOURCE=..\src\comp.c
# End Source File
# Begin Source File
SOURCE=..\src\crypt.c
# End Source File
# Begin Source File
SOURCE=..\src\hostkey.c
# End Source File
# Begin Source File
SOURCE=..\src\kex.c
# End Source File
# Begin Source File
SOURCE=..\src\mac.c
# End Source File
# Begin Source File
SOURCE=..\src\misc.c
# End Source File
# Begin Source File
SOURCE=..\src\packet.c
# End Source File
# Begin Source File
SOURCE=..\src\scp.c
# End Source File
# Begin Source File
SOURCE=..\src\session.c
# End Source File
# Begin Source File
SOURCE=..\src\sftp.c
# End Source File
# Begin Source File
SOURCE=..\src\userauth.c
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=..\include\libssh2.h
# End Source File
# Begin Source File
SOURCE=.\libssh2_config.h
# End Source File
# Begin Source File
SOURCE=..\include\libssh2_priv.h
# End Source File
# Begin Source File
SOURCE=..\include\libssh2_sftp.h
# End Source File
# End Group
# End Target
# End Project

41
win32/libssh2.dsw Normal file
View File

@@ -0,0 +1,41 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "libssh2"=.\libssh2.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "ssh2_sample"=.\ssh2_sample.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

38
win32/libssh2_config.h Normal file
View File

@@ -0,0 +1,38 @@
#ifndef WIN32
#define WIN32
#endif
#include <winsock2.h>
#include <mswsock.h>
#include <ws2tcpip.h>
/* same as WSABUF */
struct iovec {
u_long iov_len;
char *iov_base;
};
#define inline __inline
static inline int writev(int sock, struct iovec *iov, int nvecs)
{
DWORD ret;
if (WSASend(sock, (LPWSABUF)iov, nvecs, &ret, 0, NULL, NULL) == 0) {
return ret;
}
return -1;
}
/* not really usleep, but safe for the way we use it in this lib */
static inline int usleep(int udelay)
{
Sleep(udelay / 1000);
return 0;
}
#define snprintf _snprintf
/* Compile in zlib support */
#define LIBSSH2_HAVE_ZLIB 1
/* Enable newer diffie-hellman-group-exchange-sha1 syntax */
#define LIBSSH2_DH_GEX_NEW 1

15
win32/rules.mk Normal file
View File

@@ -0,0 +1,15 @@
all-sub: $(INTDIR) all
clean-sub: clean
$(INTDIR):
!if "$(SRCDIR)" == ""
@if not exist $(TARGET) mkdir $(TARGET)
!endif
@if not exist $(INTDIR) mkdir $(INTDIR)
{$(SUBDIR)}.c{$(INTDIR)}.obj::
$(CC) -c $(CFLAGS) /Fo"$(INTDIR)\\" $<

102
win32/ssh2_sample.dsp Normal file
View File

@@ -0,0 +1,102 @@
# Microsoft Developer Studio Project File - Name="ssh2_sample" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=ssh2_sample - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "ssh2_sample.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "ssh2_sample.mak" CFG="ssh2_sample - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "ssh2_sample - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "ssh2_sample - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "ssh2_sample - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "ssh2_sample___Win32_Release"
# PROP BASE Intermediate_Dir "ssh2_sample___Win32_Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "LIBSSH2_WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\include" /I "..\win32" /D "WIN32" /D "NDEBUG" /D "LIBSSH2_WIN32" /D "_CONSOLE" /D "_MBCS" /D "LIBSSH2_LIBRARY" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libeay32.lib ssleay32.lib ws2_32.lib zlib.lib libssh2.lib /nologo /subsystem:console /machine:I386 /libpath:"Release"
!ELSEIF "$(CFG)" == "ssh2_sample - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "ssh2_sample___Win32_Debug"
# PROP BASE Intermediate_Dir "ssh2_sample___Win32_Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "LIBSSH2_WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\include" /I "..\win32" /D "WIN32" /D "_DEBUG" /D "LIBSSH2_WIN32" /D "_CONSOLE" /D "_MBCS" /D "LIBSSH2_LIBRARY" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib libeay32.lib ssleay32.lib ws2_32.lib zlib.lib libssh2d.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /pdbtype:sept /libpath:"Debug"
!ENDIF
# Begin Target
# Name "ssh2_sample - Win32 Release"
# Name "ssh2_sample - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=..\ssh2_sample.c
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project