Compare commits

...

77 Commits

Author SHA1 Message Date
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
Sara Golemon
3f24fb005e Bump version for release and remove SFTP from TODO list 2004-12-23 15:15:44 +00:00
Sara Golemon
f11c657a10 Make libssh2_packet_read() use a static buffer to avoid unnecessary
alloc and free calls.

Since the cipher and mac layers aren't runtime extensible (yet)
and we know neither of these works in sizes greater than 32,
we can safely set aside a 64 byte block of data on the stack
for crypting and hashing.

This will make a big difference during quasi-non-blocking reads
where libssh2_packet_read() is polled repeatedly.
2004-12-23 00:42:20 +00:00
Sara Golemon
d4efdee802 Expose specific SFTP error codes to the calling program 2004-12-22 21:55:08 +00:00
Sara Golemon
aa8b8afe4f Update contact info with new domain 2004-12-22 20:56:06 +00:00
Sara Golemon
525a181037 Add SFTP support 2004-12-22 00:20:02 +00:00
Sara Golemon
9977cee99b Fix LIBSSH2_CHANNEL_CLOSE for the LAST TIME. 2004-12-20 22:42:02 +00:00
Sara Golemon
3a744117d6 Ooops, try that again... 2004-12-20 22:08:46 +00:00
Sara Golemon
d974137db9 Fixes: scp blocking modes, MacError abstract indirection
Additions: Channel Close callback
2004-12-20 21:52:35 +00:00
Sara Golemon
66f913e53a A broken decrypt (or false packet) could cause an unreasonably large
block of memory to be allocated leading to indeterminate results.

SSH-TRANS only requires implementations to handle about about 32k
compressed length per packet.  Allow 40k to be safe, but no more.
2004-12-18 07:14:51 +00:00
Sara Golemon
912e9ca713 Fixed polling error in libssh2_channel_read_ex() 2004-12-18 07:00:51 +00:00
Sara Golemon
6fdf9c9c06 Packet queueing mechanism allows data which immediately follows
open confirmation to get ignored.  Work around this by adding the channel
to the list before opening it.
2004-12-17 04:27:29 +00:00
Sara Golemon
26e7e66ecf Bump version for release 2004-12-17 01:33:17 +00:00
Sara Golemon
a0cd3ed3dc Fix return code in libssh2_channel_write_ex() 2004-12-16 23:04:11 +00:00
Sara Golemon
3614bdac21 Changed libssh2_session_disconnect_ex() to return an error code
on failed alloc.
2004-12-16 23:02:25 +00:00
Sara Golemon
14af2e3952 Correct comments for hostkey_hash 2004-12-16 22:58:02 +00:00
Sara Golemon
620a685af2 Add libssh2_session_last_error() 2004-12-16 22:44:28 +00:00
Sara Golemon
4ab2f2ab73 This initialization was based on an earlier concept 2004-12-10 14:44:08 +00:00
Sara Golemon
d2ca405d0f Added libssh2_session_abstract() 2004-12-09 23:27:14 +00:00
Sara Golemon
566bea77ea Add libssh2_session_method_pref() and libssh2_session_methods().
Specify methods to be used and retreive what methods were negotiated.
2004-12-09 22:10:07 +00:00
Sara Golemon
165837c085 Let the calling program know what methods we support 2004-12-09 19:09:03 +00:00
Sara Golemon
7035d475eb Added libssh2_session_callback_set() 2004-12-09 18:24:14 +00:00
Sara Golemon
794f01acc1 Add flush mechanism to the channel API 2004-12-08 18:54:25 +00:00
Sara Golemon
2b670d36ca Update changelog 2004-12-08 18:24:06 +00:00
Sara Golemon
7a153310f7 Change extended data ignore to allow merging extended data into the primary stream 2004-12-08 18:14:46 +00:00
45 changed files with 8044 additions and 310 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) * 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 * Run: make all install

View File

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

View File

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

100
README
View File

@@ -1,8 +1,104 @@
libssh2 - SSH2 library libssh2 - SSH2 library
====================== ======================
Version 0.1-dev 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
-----------
Fixed libssh2_channel_read_ex(). Packet loop initialized BEFORE transport polled for new packets (should have been after).
Fixed blocking issues in scp_send()/scp_recv().
Fixed degree of indirection in macerror callback.
Changed packet read mechanism to use a fixed buffer and avoid unnecessary alloc/free calls. (especially while non-block looping)
Added channel close callback.
Added SFTP support (Using its own header file: libssh2_sftp.h)
Version 0.2
-----------
Changed extended data ignorance mechanism:
libssh2_channel_ignore_extended_data() changed to libssh2_channel_handle_extended_data()
Macro introduced for backward compatability during beta phase.
*** THE LIBSSH2_CHANNEL_IGNORE_EXTENDED_DATA() MACRO WILL BE REMOVED PRIOR TO 1.0 RELEASE ***
libssh2_channel_handle_extended_data() may be passed one of three "ignore_mode" constants
LIBSSH2_CHANNEL_EXTENDED_DATA_NONE Default behavior, queue ED packets and return them with read_ex
LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE Equivalent to libssh2_channel_ignore_extended_data()
IGNORE will implicitly flush the extended data stream(s)
LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE Calls to channel_read() will check both the standard data stream
and the extended data stream(s) for the first available packet
Changed libssh2_session_disconnect_ex() to return an error code when alloc fails
Added libssh2_channel_flush_ex() and basic macros: ..._flush() ..._flush_stderr()
flush_ex accepts either the streamid (0 for standard data, 1 for stderr) or one of the two following constants:
LIBSSH2_CHANNEL_FLUSH_ALL Flush all streams
LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA Flush all streams EXCEPT the standard data stream
Added libssh2_session_callback_set() for setting ignore/debug/disconnect/macerror callbacks
Added libssh2_session_method_pref() to selectively set methods and method preferences.
Added libssh2_session_methods() to determine what methods were negotiated.
Added libssh2_session_abstract() for retreiving &session->abstract
Added libssh2_session_last_error() for retreiving error codes/messages
Version 0.1
-----------
Initial Release: Initial Release:
KEX methods: diffie-hellman-group14-sha1, diffie-hellman-group-exchange-sha1, diffie-hellman-group1-sha1 KEX methods: diffie-hellman-group14-sha1, diffie-hellman-group-exchange-sha1, diffie-hellman-group1-sha1

4
TODO
View File

@@ -1,4 +0,0 @@
* More Crypt Methods
* hmac-md5, hmac-md5-96
* SFTP support
* 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,21 @@
# AC_PREREQ(2.57) # AC_PREREQ(2.57)
AC_INIT(libssh2, 0.1 , pollita@php.net) AC_INIT(libssh2,0.6,sarag@libssh2.org)
AC_CONFIG_SRCDIR([src]) AC_CONFIG_SRCDIR([src])
AC_CONFIG_HEADER([include/libssh2_config.h]) AC_CONFIG_HEADER([include/libssh2_config.h])
SHLIB_SUFFIX_NAME="so" # Check for the OS.
SHLIB_LDFLAGS="-shared" AC_CANONICAL_HOST
case "$host" in
*-cygwin)
SHLIB_SUFFIX_NAME="dll"
SHLIB_LDFLAGS="-shared"
CFLAGS="$CFLAGS -DLIBSSH2_WIN32"
;;
*)
SHLIB_SUFFIX_NAME="so"
SHLIB_LDFLAGS="-shared"
;;
esac
AC_SUBST(SHLIB_SUFFIX_NAME) AC_SUBST(SHLIB_SUFFIX_NAME)
AC_SUBST(SHLIB_LDFLAGS) AC_SUBST(SHLIB_LDFLAGS)
@@ -138,6 +148,13 @@ AC_ARG_ENABLE(mac-none,
AC_HELP_STRING([--enable-mac-none],[Permit "none" MAC -- NOT RECOMMENDED]), AC_HELP_STRING([--enable-mac-none],[Permit "none" MAC -- NOT RECOMMENDED]),
[AC_DEFINE(LIBSSH2_MAC_NONE, 1, [Enable "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. # Checks for header files.
# AC_HEADER_STDC # 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])

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net> /* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@@ -42,7 +42,32 @@
#include <string.h> #include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#define LIBSSH2_VERSION "0.1" /* 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
# ifndef _MSC_VER
# include <sys/uio.h>
# endif
#else
# define LIBSSH2_API
#endif
#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.6"
#define LIBSSH2_APINO 200502091118
/* Part of every banner, user specified or not */ /* Part of every banner, user specified or not */
#define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION #define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION
@@ -51,9 +76,6 @@
#define LIBSSH2_SSH_DEFAULT_BANNER LIBSSH2_SSH_BANNER #define LIBSSH2_SSH_DEFAULT_BANNER LIBSSH2_SSH_BANNER
#define LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF LIBSSH2_SSH_DEFAULT_BANNER "\r\n" #define LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF LIBSSH2_SSH_DEFAULT_BANNER "\r\n"
/* 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 */ /* Default generate and safe prime sizes for diffie-hellman-group-exchange-sha1 */
#define LIBSSH2_DH_GEX_MINGROUP 1024 #define LIBSSH2_DH_GEX_MINGROUP 1024
#define LIBSSH2_DH_GEX_OPTGROUP 1536 #define LIBSSH2_DH_GEX_OPTGROUP 1536
@@ -71,10 +93,13 @@
#define LIBSSH2_SOCKET_POLL_MAXLOOPS 120 #define LIBSSH2_SOCKET_POLL_MAXLOOPS 120
/* Maximum size to allow a payload to compress to, plays it safe by falling short of spec limits */ /* Maximum size to allow a payload to compress to, plays it safe by falling short of spec limits */
#define LIBSSH2_PACKET_MAXCOMP 32000 #define LIBSSH2_PACKET_MAXCOMP 32000
/* Maximum size to allow a payload to deccompress to, plays it safe by allowing more than spec requires */ /* Maximum size to allow a payload to deccompress to, plays it safe by allowing more than spec requires */
#define LIBSSH2_PACKET_MAXDECOMP 40000 #define LIBSSH2_PACKET_MAXDECOMP 40000
/* Maximum size for an inbound compressed payload, plays it safe by overshooting spec limits */
#define LIBSSH2_PACKET_MAXPAYLOAD 40000
/* Malloc callbacks */ /* Malloc callbacks */
#define LIBSSH2_ALLOC_FUNC(name) void *name(size_t count, void **abstract) #define LIBSSH2_ALLOC_FUNC(name) void *name(size_t count, void **abstract)
@@ -87,15 +112,35 @@
#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_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_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_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)
/* libssh2_session_callback_set() constants */
#define LIBSSH2_CALLBACK_IGNORE 0
#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
#define LIBSSH2_METHOD_HOSTKEY 1
#define LIBSSH2_METHOD_CRYPT_CS 2
#define LIBSSH2_METHOD_CRYPT_SC 3
#define LIBSSH2_METHOD_MAC_CS 4
#define LIBSSH2_METHOD_MAC_SC 5
#define LIBSSH2_METHOD_COMP_CS 6
#define LIBSSH2_METHOD_COMP_SC 7
#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_SESSION LIBSSH2_SESSION;
typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL; 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
#define LIBSSH2_HOSTKEY_HASH_MD5 1 #define LIBSSH2_HOSTKEY_HASH_MD5 1
#define LIBSSH2_HOSTKEY_HASH_SHA1 2 #define LIBSSH2_HOSTKEY_HASH_SHA1 2
@@ -148,18 +193,32 @@ typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL;
#define LIBSSH2_ERROR_SCP_PROTOCOL -28 #define LIBSSH2_ERROR_SCP_PROTOCOL -28
#define LIBSSH2_ERROR_ZLIB -29 #define LIBSSH2_ERROR_ZLIB -29
#define LIBSSH2_ERROR_SOCKET_TIMEOUT -30 #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
/* Session API */ /* 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); 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);
#define libssh2_session_init() libssh2_session_init_ex(NULL, NULL, NULL, NULL) #define libssh2_session_init() libssh2_session_init_ex(NULL, NULL, NULL, NULL)
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_startup(LIBSSH2_SESSION *session, int socket);
LIBSSH2_API void libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, char *description, char *lang); LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, char *description, char *lang);
#define libssh2_session_disconnect(session, description) libssh2_session_disconnect_ex((session), SSH_DISCONNECT_BY_APPLICATION, (description), "") #define libssh2_session_disconnect(session, description) libssh2_session_disconnect_ex((session), SSH_DISCONNECT_BY_APPLICATION, (description), "")
LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session); LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session);
LIBSSH2_API char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type); 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 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 */ /* Userauth API */
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username, int username_len); LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username, int username_len);
LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session); LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session);
@@ -176,23 +235,40 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
#define LIBSSH2_CHANNEL_WINDOW_DEFAULT 65536 #define LIBSSH2_CHANNEL_WINDOW_DEFAULT 65536
#define LIBSSH2_CHANNEL_PACKET_DEFAULT 16384 #define LIBSSH2_CHANNEL_PACKET_DEFAULT 16384
/* Extended Data Handling */
#define LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL 0
#define LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE 1
#define LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE 2
#define SSH_EXTENDED_DATA_STDERR 1
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); 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) #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); 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) #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); 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)) #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); 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) #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); 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_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)) #define libssh2_channel_exec(channel, command) libssh2_channel_process_startup((channel), "exec", sizeof("exec") - 1, (command), strlen(command))
#define libssh2_channel_subsystem(channel, subsystem) libssh2_channel_process_startup((channel), "subsystem", sizeof("subsystem") - 1, (subsystem), strlen(subsystem)) #define libssh2_channel_subsystem(channel, subsystem) libssh2_channel_process_startup((channel), "subsystem", sizeof("subsystem") - 1, (subsystem), strlen(subsystem))
#define SSH_EXTENDED_DATA_STDERR 1
LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, char *buf, size_t buflen); LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, char *buf, size_t buflen);
#define libssh2_channel_read(channel, buf, buflen) libssh2_channel_read_ex((channel), 0, (buf), (buflen)) #define libssh2_channel_read(channel, buf, buflen) libssh2_channel_read_ex((channel), 0, (buf), (buflen))
#define libssh2_channel_read_stderr(channel, buf, buflen) libssh2_channel_read_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen)) #define libssh2_channel_read_stderr(channel, buf, buflen) libssh2_channel_read_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen))
@@ -202,7 +278,19 @@ LIBSSH2_API int libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id
#define libssh2_channel_write_stderr(channel, buf, buflen) libssh2_channel_write_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen)) #define libssh2_channel_write_stderr(channel, buf, buflen) libssh2_channel_write_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen))
LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int blocking); LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int blocking);
LIBSSH2_API void libssh2_channel_ignore_extended_data(LIBSSH2_CHANNEL *channel, int ignore); LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode);
/* libssh2_channel_ignore_extended_data() is defined below for BC with version 0.1
* Future uses should use libssh2_channel_handle_extended_data() directly
* if LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE is passed, extended data will be read (FIFO) from the standard data channel
*/
/* DEPRECATED */
#define libssh2_channel_ignore_extended_data(channel, ignore) libssh2_channel_handle_extended_data((channel), (ignore) ? LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE : LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL )
#define LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA -1
#define LIBSSH2_CHANNEL_FLUSH_ALL -2
LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int streamid);
#define libssh2_channel_flush(channel) libssh2_channel_flush_ex((channel), 0)
#define libssh2_channel_flush_stderr(channel) libssh2_channel_flush_ex((channel), SSH_EXTENDED_DATA_STDERR)
LIBSSH2_API int libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel); LIBSSH2_API int libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel);
LIBSSH2_API int libssh2_channel_eof(LIBSSH2_CHANNEL *channel); LIBSSH2_API int libssh2_channel_eof(LIBSSH2_CHANNEL *channel);

View File

@@ -39,6 +39,9 @@
/* Enable "none" cipher -- NOT RECOMMENDED */ /* Enable "none" cipher -- NOT RECOMMENDED */
#undef LIBSSH2_CRYPT_NONE #undef LIBSSH2_CRYPT_NONE
/* Enable newer diffie-hellman-group-exchange-sha1 syntax */
#undef LIBSSH2_DH_GEX_NEW
/* Compile in zlib support */ /* Compile in zlib support */
#undef LIBSSH2_HAVE_ZLIB #undef LIBSSH2_HAVE_ZLIB

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net> /* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@@ -38,11 +38,13 @@
#ifndef LIBSSH2_PRIV_H #ifndef LIBSSH2_PRIV_H
#define LIBSSH2_PRIV_H 1 #define LIBSSH2_PRIV_H 1
/* Definitions shared with the public */ #define LIBSSH2_LIBRARY
#include "libssh2_config.h" #include "libssh2_config.h"
#include "libssh2.h" #include "libssh2.h"
#ifndef WIN32
#include <sys/socket.h> #include <sys/socket.h>
#endif
#include <openssl/evp.h> #include <openssl/evp.h>
#define LIBSSH2_ALLOC(session, count) session->alloc((count), &(session)->abstract) #define LIBSSH2_ALLOC(session, count) session->alloc((count), &(session)->abstract)
@@ -55,7 +57,10 @@
#define LIBSSH2_DISCONNECT(session, reason, message, message_len, language, language_len) \ #define LIBSSH2_DISCONNECT(session, reason, message, message_len, language, language_len) \
session->ssh_msg_disconnect((session), (reason), (message), (message_len), (language), (language_len), &(session)->abstract) 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_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)
typedef struct _LIBSSH2_KEX_METHOD LIBSSH2_KEX_METHOD; typedef struct _LIBSSH2_KEX_METHOD LIBSSH2_KEX_METHOD;
typedef struct _LIBSSH2_HOSTKEY_METHOD LIBSSH2_HOSTKEY_METHOD; typedef struct _LIBSSH2_HOSTKEY_METHOD LIBSSH2_HOSTKEY_METHOD;
@@ -98,7 +103,7 @@ typedef struct _libssh2_channel_data {
unsigned long window_size_initial, window_size, packet_size; unsigned long window_size_initial, window_size, packet_size;
/* Set to 1 when CHANNEL_CLOSE / CHANNEL_EOF sent/received */ /* Set to 1 when CHANNEL_CLOSE / CHANNEL_EOF sent/received */
char close, eof, ignore_extended_data; char close, eof, extended_data_ignore_mode;
} libssh2_channel_data; } libssh2_channel_data;
struct _LIBSSH2_CHANNEL { struct _LIBSSH2_CHANNEL {
@@ -112,12 +117,28 @@ struct _LIBSSH2_CHANNEL {
LIBSSH2_SESSION *session; LIBSSH2_SESSION *session;
LIBSSH2_CHANNEL *next, *prev; LIBSSH2_CHANNEL *next, *prev;
void *abstract;
LIBSSH2_CHANNEL_CLOSE_FUNC((*close_cb));
}; };
struct _LIBSSH2_CHANNEL_BRIGADE { struct _LIBSSH2_CHANNEL_BRIGADE {
LIBSSH2_CHANNEL *head, *tail; 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 { typedef struct _libssh2_endpoint_data {
unsigned char *banner; unsigned char *banner;
@@ -135,9 +156,10 @@ typedef struct _libssh2_endpoint_data {
void *comp_abstract; void *comp_abstract;
/* Method Preferences -- NULL yields "load order" */ /* Method Preferences -- NULL yields "load order" */
LIBSSH2_CRYPT_METHOD **crypt_prefs; char *crypt_prefs;
LIBSSH2_MAC_METHOD **mac_prefs; char *mac_prefs;
LIBSSH2_COMP_METHOD **comp_prefs; char *comp_prefs;
char *lang_prefs;
} libssh2_endpoint_data; } libssh2_endpoint_data;
struct _LIBSSH2_SESSION { struct _LIBSSH2_SESSION {
@@ -152,14 +174,14 @@ struct _LIBSSH2_SESSION {
LIBSSH2_DEBUG_FUNC((*ssh_msg_debug)); LIBSSH2_DEBUG_FUNC((*ssh_msg_debug));
LIBSSH2_DISCONNECT_FUNC((*ssh_msg_disconnect)); LIBSSH2_DISCONNECT_FUNC((*ssh_msg_disconnect));
LIBSSH2_MACERROR_FUNC((*macerror)); LIBSSH2_MACERROR_FUNC((*macerror));
LIBSSH2_X11_OPEN_FUNC((*x11));
/* Method preferences -- NULL yields "load order" */ /* Method preferences -- NULL yields "load order" */
LIBSSH2_KEX_METHOD **kex_prefs; char *kex_prefs;
LIBSSH2_HOSTKEY_METHOD **hostkey_prefs; char *hostkey_prefs;
int exchanging_keys; int state;
int newkeys; int flags;
int authenticated;
/* Agreed Key Exchange Method */ /* Agreed Key Exchange Method */
LIBSSH2_KEX_METHOD *kex; LIBSSH2_KEX_METHOD *kex;
@@ -196,6 +218,8 @@ struct _LIBSSH2_SESSION {
LIBSSH2_CHANNEL_BRIGADE channels; LIBSSH2_CHANNEL_BRIGADE channels;
unsigned long next_channel; unsigned long next_channel;
LIBSSH2_LISTENER *listeners;
/* Actual I/O socket */ /* Actual I/O socket */
int socket_fd; int socket_fd;
int socket_block; int socket_block;
@@ -208,14 +232,26 @@ struct _LIBSSH2_SESSION {
int err_code; 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 */ /* libssh2 extensible ssh api, ultimately I'd like to allow loading additional methods via .so/.dll */
struct _LIBSSH2_KEX_METHOD { struct _LIBSSH2_KEX_METHOD {
char *name; char *name;
/* integrity key length */
unsigned long key_len;
/* Key exchange, populates session->* and returns 0 on success, non-0 on error */ /* Key exchange, populates session->* and returns 0 on success, non-0 on error */
int (*exchange_keys)(LIBSSH2_SESSION *session); int (*exchange_keys)(LIBSSH2_SESSION *session);
@@ -272,6 +308,9 @@ struct _LIBSSH2_MAC_METHOD {
/* The length of a given MAC packet */ /* The length of a given MAC packet */
int mac_len; int mac_len;
/* integrity key length */
int key_len;
/* Message Authentication Code Hashing algo */ /* Message Authentication Code Hashing algo */
int (*init)(LIBSSH2_SESSION *session, unsigned char *key, int *free_key, void **abstract); 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); 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);
@@ -354,7 +393,9 @@ struct _LIBSSH2_MAC_METHOD {
void libssh2_session_shutdown(LIBSSH2_SESSION *session); void libssh2_session_shutdown(LIBSSH2_SESSION *session);
unsigned long libssh2_ntohu32(const unsigned char *buf); unsigned long libssh2_ntohu32(const unsigned char *buf);
libssh2_uint64_t libssh2_ntohu64(const unsigned char *buf);
void libssh2_htonu32(unsigned char *buf, unsigned long val); void libssh2_htonu32(unsigned char *buf, unsigned long val);
void libssh2_htonu64(unsigned char *buf, libssh2_uint64_t val);
int libssh2_packet_read(LIBSSH2_SESSION *session, int block); 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); 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);
@@ -365,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) 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_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned long data_len);
int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange); 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); 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 */ /* Let crypt.c/hostkey.c/comp.c/mac.c expose their method structs */

190
include/libssh2_sftp.h Normal file
View File

@@ -0,0 +1,190 @@
/* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
* 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_SFTP_H
#define LIBSSH2_SFTP_H 1
/* Note: Version 6 was documented at the time of writing
* However it was marked as "DO NOT IMPLEMENT" due to pending changes
*
* Let's start with Version 3 (The version found in OpenSSH) and go from there
*/
#define LIBSSH2_SFTP_VERSION 3
#define LIBSSH2_SFTP_PACKET_MAXLEN 40000
typedef struct _LIBSSH2_SFTP LIBSSH2_SFTP;
typedef struct _LIBSSH2_SFTP_HANDLE LIBSSH2_SFTP_HANDLE;
typedef struct _LIBSSH2_SFTP_ATTRIBUTES LIBSSH2_SFTP_ATTRIBUTES;
/* Flags for open_ex() */
#define LIBSSH2_SFTP_OPENFILE 0
#define LIBSSH2_SFTP_OPENDIR 1
/* Flags for rename_ex() */
#define LIBSSH2_SFTP_RENAME_OVERWRITE 0x00000001
#define LIBSSH2_SFTP_RENAME_ATOMIC 0x00000002
#define LIBSSH2_SFTP_RENAME_NATIVE 0x00000004
/* Flags for stat_ex() */
#define LIBSSH2_SFTP_STAT 0
#define LIBSSH2_SFTP_LSTAT 1
#define LIBSSH2_SFTP_SETSTAT 2
/* Flags for symlink_ex() */
#define LIBSSH2_SFTP_SYMLINK 0
#define LIBSSH2_SFTP_READLINK 1
#define LIBSSH2_SFTP_REALPATH 2
/* SFTP attribute flag bits */
#define LIBSSH2_SFTP_ATTR_SIZE 0x00000001
#define LIBSSH2_SFTP_ATTR_UIDGID 0x00000002
#define LIBSSH2_SFTP_ATTR_PERMISSIONS 0x00000004
#define LIBSSH2_SFTP_ATTR_ACMODTIME 0x00000008
#define LIBSSH2_SFTP_ATTR_EXTENDED 0x80000000
struct _LIBSSH2_SFTP_ATTRIBUTES {
/* If flags & ATTR_* bit is set, then the value in this struct will be meaningful
* Otherwise it should be ignored
*/
unsigned long flags;
libssh2_uint64_t filesize;
unsigned long uid, gid;
unsigned long permissions;
unsigned long atime, mtime;
};
/* SFTP filetypes */
#define LIBSSH2_SFTP_TYPE_REGULAR 1
#define LIBSSH2_SFTP_TYPE_DIRECTORY 2
#define LIBSSH2_SFTP_TYPE_SYMLINK 3
#define LIBSSH2_SFTP_TYPE_SPECIAL 4
#define LIBSSH2_SFTP_TYPE_UNKNOWN 5
#define LIBSSH2_SFTP_TYPE_SOCKET 6
#define LIBSSH2_SFTP_TYPE_CHAR_DEVICE 7
#define LIBSSH2_SFTP_TYPE_BLOCK_DEVICE 8
#define LIBSSH2_SFTP_TYPE_FIFO 9
/* SFTP File Transfer Flags -- (e.g. flags parameter to sftp_open())
* Danger will robinson... APPEND doesn't have any effect on OpenSSH servers */
#define LIBSSH2_FXF_READ 0x00000001
#define LIBSSH2_FXF_WRITE 0x00000002
#define LIBSSH2_FXF_APPEND 0x00000004
#define LIBSSH2_FXF_CREAT 0x00000008
#define LIBSSH2_FXF_TRUNC 0x00000010
#define LIBSSH2_FXF_EXCL 0x00000020
/* SFTP Status Codes (returned by libssh2_sftp_last_error() ) */
#define LIBSSH2_FX_OK 0
#define LIBSSH2_FX_EOF 1
#define LIBSSH2_FX_NO_SUCH_FILE 2
#define LIBSSH2_FX_PERMISSION_DENIED 3
#define LIBSSH2_FX_FAILURE 4
#define LIBSSH2_FX_BAD_MESSAGE 5
#define LIBSSH2_FX_NO_CONNECTION 6
#define LIBSSH2_FX_CONNECTION_LOST 7
#define LIBSSH2_FX_OP_UNSUPPORTED 8
#define LIBSSH2_FX_INVALID_HANDLE 9
#define LIBSSH2_FX_NO_SUCH_PATH 10
#define LIBSSH2_FX_FILE_ALREADY_EXISTS 11
#define LIBSSH2_FX_WRITE_PROTECT 12
#define LIBSSH2_FX_NO_MEDIA 13
#define LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM 14
#define LIBSSH2_FX_QUOTA_EXCEEDED 15
#define LIBSSH2_FX_UNKNOWN_PRINCIPLE 16
#define LIBSSH2_FX_LOCK_CONFlICT 17
#define LIBSSH2_FX_DIR_NOT_EMPTY 18
#define LIBSSH2_FX_NOT_A_DIRECTORY 19
#define LIBSSH2_FX_INVALID_FILENAME 20
#define LIBSSH2_FX_LINK_LOOP 21
/* SFTP API */
LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session);
LIBSSH2_API int libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp);
LIBSSH2_API unsigned long libssh2_sftp_last_error(LIBSSH2_SFTP *sftp);
/* File / Directory Ops */
LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, char *filename, int filename_len, unsigned long flags, long mode, int open_type);
#define libssh2_sftp_open(sftp, filename, flags, mode) libssh2_sftp_open_ex((sftp), (filename), strlen(filename), (flags), (mode), LIBSSH2_SFTP_OPENFILE)
#define libssh2_sftp_opendir(sftp, path) libssh2_sftp_open_ex((sftp), (path), strlen(path), 0, 0, LIBSSH2_SFTP_OPENDIR)
LIBSSH2_API size_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen);
LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen, LIBSSH2_SFTP_ATTRIBUTES *attrs);
LIBSSH2_API size_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, size_t count);
LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle);
#define libssh2_sftp_close(handle) libssh2_sftp_close_handle(handle)
#define libssh2_sftp_closedir(handle) libssh2_sftp_close_handle(handle)
LIBSSH2_API void libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE *handle, size_t offset);
#define libssh2_sftp_rewind(handle) libssh2_sftp_seek((handle), 0)
LIBSSH2_API size_t libssh2_sftp_tell(LIBSSH2_SFTP_HANDLE *handle);
LIBSSH2_API int libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_ATTRIBUTES *attrs, int setstat);
#define libssh2_sftp_fstat(handle, attrs) libssh2_sftp_fstat_ex((handle), (attrs), 0)
#define libssh2_sftp_fsetstat(handle, attrs) libssh2_sftp_fstat_ex((handle), (attrs), 1)
/* Miscellaneous Ops */
LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, char *source_filename, int srouce_filename_len,
char *dest_filename, int dest_filename_len,
long flags);
#define libssh2_sftp_rename(sftp, sourcefile, destfile) libssh2_sftp_rename_ex((sftp), (sourcefile), strlen(sourcefile), (destfile), strlen(destfile), \
LIBSSH2_SFTP_RENAME_OVERWRITE | LIBSSH2_SFTP_RENAME_ATOMIC | LIBSSH2_SFTP_RENAME_NATIVE)
LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, char *filename, int filename_len);
#define libssh2_sftp_unlink(sftp, filename) libssh2_sftp_unlink_ex((sftp), (filename), strlen(filename))
LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_len, long mode);
#define libssh2_sftp_mkdir(sftp, path, mode) libssh2_sftp_mkdir_ex((sftp), (path), strlen(path), (mode))
LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_len);
#define libssh2_sftp_rmdir(sftp, path) libssh2_sftp_rmdir_ex((sftp), (path), strlen(path))
LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, char *path, int path_len, int stat_type, LIBSSH2_SFTP_ATTRIBUTES *attrs);
#define libssh2_sftp_stat(sftp, path, attrs) libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_STAT, (attrs))
#define libssh2_sftp_lstat(sftp, path, attrs) libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_LSTAT, (attrs))
#define libssh2_sftp_setstat(sftp, path, attrs) libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_SETSTAT, (attrs))
LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, int path_len, char *target, int target_len, int link_type);
#define libssh2_sftp_symlink(sftp, orig, linkpath) libssh2_sftp_symlink_ex((sftp), (orig), strlen(orig), (linkpath), strlen(linkpath), LIBSSH2_SFTP_SYMLINK)
#define libssh2_sftp_readlink(sftp, path, target, maxlen) libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), LIBSSH2_SFTP_READLINK)
#define libssh2_sftp_realpath(sftp, path, target, maxlen) libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), LIBSSH2_SFTP_REALPATH)
#endif /* LIBSSH2_SFTP_H */

9
src/.cvsignore Normal file
View File

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

View File

@@ -1,4 +1,4 @@
OBJECTS = channel.o comp.o crypt.o hostkey.o kex.o mac.o misc.o packet.o scp.o session.o userauth.o OBJECTS = channel.o comp.o crypt.o hostkey.o kex.o mac.o misc.o packet.o scp.o session.o sftp.o userauth.o
top_srcdir = @top_srcdir@ top_srcdir = @top_srcdir@
prefix = @prefix@ prefix = @prefix@
@@ -42,6 +42,9 @@ scp.o: scp.c
session.o: session.c session.o: session.c
$(CC) -o session.o session.c $(CFLAGS) $(LIBS) $(CC) -o session.o session.c $(CFLAGS) $(LIBS)
sftp.o: sftp.c
$(CC) -o sftp.o sftp.c $(CFLAGS) $(LIBS)
userauth.o: userauth.c userauth.o: userauth.c
$(CC) -o userauth.o userauth.c $(CFLAGS) $(LIBS) $(CC) -o userauth.o userauth.c $(CFLAGS) $(LIBS)
@@ -54,7 +57,7 @@ libssh2.a: $(OBJECTS)
ar q libssh2.a $(OBJECTS) ar q libssh2.a $(OBJECTS)
@RANLIB@ libssh2.a @RANLIB@ libssh2.a
install: all install: all
$(INSTALL) libssh2.@SHLIB_SUFFIX_NAME@ $(libdir) $(INSTALL) libssh2.@SHLIB_SUFFIX_NAME@ $(DESTDIR)$(libdir)
clean: clean:
rm -f *~ libssh2.a libssh2.@SHLIB_SUFFIX_NAME@ *.o 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@users.sourceforge.net> /* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@@ -36,12 +36,15 @@
*/ */
#include "libssh2_priv.h" #include "libssh2_priv.h"
#include <openssl/rand.h>
#ifndef WIN32
#include <unistd.h> #include <unistd.h>
#endif
/* {{{ libssh2_channel_nextid /* {{{ libssh2_channel_nextid
* Determine the next channel ID we can use at our end * 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; unsigned long id = session->next_channel;
LIBSSH2_CHANNEL *channel; LIBSSH2_CHANNEL *channel;
@@ -72,7 +75,6 @@ static unsigned long libssh2_channel_nextid(LIBSSH2_SESSION *session)
LIBSSH2_CHANNEL *libssh2_channel_locate(LIBSSH2_SESSION *session, unsigned long channel_id) LIBSSH2_CHANNEL *libssh2_channel_locate(LIBSSH2_SESSION *session, unsigned long channel_id)
{ {
LIBSSH2_CHANNEL *channel = session->channels.head; LIBSSH2_CHANNEL *channel = session->channels.head;
while (channel) { while (channel) {
if (channel->local.id == channel_id) { if (channel->local.id == channel_id) {
return channel; return channel;
@@ -104,15 +106,39 @@ LIBSSH2_CHANNEL *libssh2_channel_locate(LIBSSH2_SESSION *session, unsigned long
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, char *channel_type, int channel_type_len, int window_size, int packet_size, 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) char *message, int message_len)
{ {
LIBSSH2_CHANNEL *channel; LIBSSH2_CHANNEL *channel = NULL;
unsigned long local_channel = libssh2_channel_nextid(session); unsigned long local_channel = libssh2_channel_nextid(session);
unsigned char *s, *packet; unsigned char *s, *packet = NULL;
unsigned long packet_len = channel_type_len + message_len + 17; /* packet_type(1) + channel_type_len(4) + sender_channel(4) + unsigned long packet_len = channel_type_len + message_len + 17; /* packet_type(1) + channel_type_len(4) + sender_channel(4) +
window_size(4) + packet_size(4) */ window_size(4) + packet_size(4) */
unsigned char *data; unsigned char *data = NULL;
unsigned long data_len; unsigned long data_len;
int polls = 0; int polls = 0;
channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
if (!channel) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate space for channel data", 0);
return NULL;
}
memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
channel->channel_type_len = channel_type_len;
channel->channel_type = LIBSSH2_ALLOC(session, channel_type_len);
if (!channel->channel_type) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Failed allocating memory for channel type name", 0);
LIBSSH2_FREE(session, channel);
return NULL;
}
memcpy(channel->channel_type, channel_type, channel_type_len);
/* REMEMBER: local as in locally sourced */
channel->local.id = local_channel;
channel->remote.window_size = window_size;
channel->remote.window_size_initial = window_size;
channel->remote.packet_size = packet_size;
libssh2_channel_add(session, channel);
s = packet = LIBSSH2_ALLOC(session, packet_len); s = packet = LIBSSH2_ALLOC(session, packet_len);
if (!packet) { if (!packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate temporary space for packet", 0); libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate temporary space for packet", 0);
@@ -132,8 +158,7 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, c
if (libssh2_packet_write(session, packet, packet_len)) { if (libssh2_packet_write(session, packet, packet_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel-open request", 0); libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel-open request", 0);
LIBSSH2_FREE(session, packet); goto channel_error;
return NULL;
} }
while (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) { while (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) {
@@ -146,62 +171,62 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, c
/* TODO: provide reason code and description */ /* TODO: provide reason code and description */
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Channel open failure", 0); libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Channel open failure", 0);
LIBSSH2_FREE(session, data); goto channel_error;
LIBSSH2_FREE(session, packet);
return NULL;
} }
usleep(LIBSSH2_SOCKET_POLL_UDELAY); usleep(LIBSSH2_SOCKET_POLL_UDELAY);
if (polls++ > LIBSSH2_SOCKET_POLL_MAXLOOPS) { if (polls++ > LIBSSH2_SOCKET_POLL_MAXLOOPS) {
/* Give up waiting */ /* Give up waiting */
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timed out waiting for response", 0); libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timed out waiting for response", 0);
LIBSSH2_FREE(session, packet); goto channel_error;
return NULL;
} }
} }
LIBSSH2_FREE(session, packet);
channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL)); channel->remote.id = libssh2_ntohu32(data + 5);
if (!channel) {
/* Play nice and close that channel that we're not going to use after all */
data[3] = SSH_MSG_CHANNEL_CLOSE;
libssh2_packet_write(session, data + 3, 5);
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate space for channel data", 0);
LIBSSH2_FREE(session, data);
return NULL;
}
memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
channel->channel_type_len = channel_type_len;
channel->channel_type = LIBSSH2_ALLOC(session, channel_type_len);
if (!channel->channel_type) {
/* Play nice and close that channel that we're not going to use after all */
data[4] = SSH_MSG_CHANNEL_CLOSE;
libssh2_packet_write(session, data + 4, 5);
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Failed allocating memory for channel type name", 0);
LIBSSH2_FREE(session, channel);
return NULL;
}
memcpy(channel->channel_type, channel_type, channel_type_len);
/* REMEMBER: local as in locally sourced */
channel->local.id = local_channel;
channel->local.window_size = libssh2_ntohu32(data + 9); channel->local.window_size = libssh2_ntohu32(data + 9);
channel->local.window_size_initial = libssh2_ntohu32(data + 9); channel->local.window_size_initial = libssh2_ntohu32(data + 9);
channel->local.packet_size = libssh2_ntohu32(data + 13); channel->local.packet_size = libssh2_ntohu32(data + 13);
channel->remote.id = libssh2_ntohu32(data + 5); LIBSSH2_FREE(session, packet);
channel->remote.window_size = window_size;
channel->remote.window_size_initial = window_size;
channel->remote.packet_size = packet_size;
LIBSSH2_FREE(session, data); LIBSSH2_FREE(session, data);
libssh2_channel_add(session, channel);
return channel; return channel;
channel_error:
if (data) {
LIBSSH2_FREE(session, data);
}
if (packet) {
LIBSSH2_FREE(session, packet);
}
if (channel) {
unsigned char channel_id[4];
LIBSSH2_FREE(session, channel->channel_type);
if (channel->next) {
channel->next->prev = channel->prev;
}
if (channel->prev) {
channel->prev->next = channel->next;
}
if (session->channels.head == channel) {
session->channels.head = channel->next;
}
if (session->channels.tail == channel) {
session->channels.tail = channel->prev;
}
/* Clear out packets meant for this channel */
libssh2_htonu32(channel_id, channel->local.id);
while ((libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_DATA, &data, &data_len, 1, channel_id, 4, 1) >= 0) ||
(libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_EXTENDED_DATA, &data, &data_len, 1, channel_id, 4, 1) >= 0)) {
LIBSSH2_FREE(session, data);
}
LIBSSH2_FREE(session, channel);
}
return NULL;
} }
/* }}} */ /* }}} */
@@ -210,6 +235,7 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, c
*/ */
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, char *host, int port, char *shost, int sport) LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, char *host, int port, char *shost, int sport)
{ {
LIBSSH2_CHANNEL *channel;
unsigned char *message, *s; unsigned char *message, *s;
unsigned long host_len = strlen(host), shost_len = strlen(shost); unsigned long host_len = strlen(host), shost_len = strlen(shost);
unsigned long message_len = host_len + shost_len + 16; /* host_len(4) + port(4) + shost_len(4) + sport(4) */ unsigned long message_len = host_len + shost_len + 16; /* host_len(4) + port(4) + shost_len(4) + sport(4) */
@@ -227,7 +253,195 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *se
memcpy(s, shost, shost_len); s += shost_len; memcpy(s, shost, shost_len); s += shost_len;
libssh2_htonu32(s, sport); s += 4; libssh2_htonu32(s, sport); s += 4;
return libssh2_channel_open_ex(session, "direct-tcpip", sizeof("direct-tcpip") - 1, LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT, message, message_len); channel = libssh2_channel_open_ex(session, "direct-tcpip", sizeof("direct-tcpip") - 1, LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT, message, message_len);
LIBSSH2_FREE(session, message);
return channel;
}
/* }}} */
/* {{{ 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;
} }
/* }}} */ /* }}} */
@@ -363,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 /* {{{ libssh2_channel_process_startup
* Primitive for libssh2_channel_(shell|exec|subsystem) * Primitive for libssh2_channel_(shell|exec|subsystem)
*/ */
@@ -434,23 +727,30 @@ LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int bloc
} }
/* }}} */ /* }}} */
/* {{{ libssh2_channel_ignore_extended_data /* {{{ libssh2_channel_flush_ex
* Ignore (or stop ignoring) extended data * Flush data from one (or all) stream
* Returns number of bytes flushed, or -1 on failure
*/ */
LIBSSH2_API void libssh2_channel_ignore_extended_data(LIBSSH2_CHANNEL *channel, int ignore) LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int streamid)
{ {
channel->remote.ignore_extended_data = ignore; LIBSSH2_PACKET *packet = channel->session->packets.head;
unsigned long refund_bytes = 0, flush_bytes = 0;
if (ignore) { while (packet) {
/* Flush queued extended data */ LIBSSH2_PACKET *next = packet->next;
LIBSSH2_PACKET *packet = channel->session->packets.head; unsigned char packet_type = packet->data[0];
unsigned long refund_bytes = 0;
while (packet) { if (((packet_type == SSH_MSG_CHANNEL_DATA) || (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA)) &&
LIBSSH2_PACKET *next = packet->next; (libssh2_ntohu32(packet->data + 1) == channel->local.id)) {
/* It's our channel at least */
if ((streamid == LIBSSH2_CHANNEL_FLUSH_ALL) ||
((packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA) && ((streamid == LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA) || (streamid = libssh2_ntohu32(packet->data + 5)))) ||
((packet_type == SSH_MSG_CHANNEL_DATA) && (streamid == 0))) {
if ((packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) && (libssh2_ntohu32(packet->data + 1) == channel->local.id)) { /* It's one of the streams we wanted to flush */
refund_bytes += packet->data_len - 13; refund_bytes += packet->data_len - 13;
flush_bytes += packet->data_len - packet->data_head;
LIBSSH2_FREE(channel->session, packet->data); LIBSSH2_FREE(channel->session, packet->data);
if (packet->prev) { if (packet->prev) {
packet->prev->next = packet->next; packet->prev->next = packet->next;
@@ -464,23 +764,43 @@ LIBSSH2_API void libssh2_channel_ignore_extended_data(LIBSSH2_CHANNEL *channel,
} }
LIBSSH2_FREE(channel->session, packet); LIBSSH2_FREE(channel->session, packet);
} }
packet = next;
} }
if (refund_bytes && channel->remote.window_size_initial) { packet = next;
unsigned char adjust[9]; /* packet_type(1) + channel(4) + adjustment(4) */ }
/* Adjust the window based on the block we just freed */ if (refund_bytes && channel->remote.window_size_initial) {
adjust[0] = SSH_MSG_CHANNEL_WINDOW_ADJUST; unsigned char adjust[9]; /* packet_type(1) + channel(4) + adjustment(4) */
libssh2_htonu32(adjust + 1, channel->remote.id);
libssh2_htonu32(adjust + 5, refund_bytes);
if (libssh2_packet_write(channel->session, adjust, 9)) { /* Adjust the window based on the block we just freed */
libssh2_error(channel->session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send transfer-window adjustment packet", 0); adjust[0] = SSH_MSG_CHANNEL_WINDOW_ADJUST;
} else { libssh2_htonu32(adjust + 1, channel->remote.id);
channel->remote.window_size += refund_bytes; libssh2_htonu32(adjust + 5, refund_bytes);
}
if (libssh2_packet_write(channel->session, adjust, 9)) {
libssh2_error(channel->session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send transfer-window adjustment packet", 0);
return -1;
} else {
channel->remote.window_size += refund_bytes;
} }
} }
return flush_bytes;
}
/* }}} */
/* {{{ libssh2_channel_handle_extended_data
* How should extended data look to the calling app?
* Keep it in separate channels[_read() _read_stdder()]? (NORMAL)
* Merge the extended data to the standard data? [everything via _read()]? (MERGE)
* Ignore it entirely [toss out packets as they come in]? (IGNORE)
*/
LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode)
{
channel->remote.extended_data_ignore_mode = ignore_mode;
if (ignore_mode == LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE) {
libssh2_channel_flush_ex(channel, LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA);
}
} }
/* }}} */ /* }}} */
@@ -493,17 +813,23 @@ LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id,
int bytes_read = 0, blocking_read = 0; int bytes_read = 0, blocking_read = 0;
do { do {
LIBSSH2_PACKET *packet = session->packets.head; LIBSSH2_PACKET *packet;
/* Process any waiting packets */ /* Process any waiting packets */
while (libssh2_packet_read(session, blocking_read) > 0) blocking_read = 0; while (libssh2_packet_read(session, blocking_read) > 0) blocking_read = 0;
packet = session->packets.head;
while (packet && (bytes_read < buflen)) { while (packet && (bytes_read < buflen)) {
/* In case packet gets destroyed during this iteration */ /* In case packet gets destroyed during this iteration */
LIBSSH2_PACKET *next = packet->next; LIBSSH2_PACKET *next = packet->next;
/* Either we asked for a specific extended data stream (and data was available),
* 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 && (packet->data[0] == SSH_MSG_CHANNEL_DATA) && (channel->local.id == libssh2_ntohu32(packet->data + 1)))) { (!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; int want = buflen - bytes_read;
int unlink_packet = 0; int unlink_packet = 0;
@@ -576,11 +902,11 @@ 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); 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 */ /* twiddle our thumbs until there's window space available */
if (libssh2_packet_read(session, 1) < 0) { if (libssh2_packet_read(session, 1) < 0) {
/* Error occured, disconnect? */ /* Error occured, disconnect? */
return 0; return -1;
} }
} }
@@ -599,7 +925,7 @@ LIBSSH2_API int libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id
/* Don't exceed the remote end's limits */ /* Don't exceed the remote end's limits */
/* REMEMBER local means local as the SOURCE of the data */ /* 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; buflen = channel->local.window_size;
} }
if (buflen > channel->local.packet_size) { if (buflen > channel->local.packet_size) {
@@ -675,6 +1001,10 @@ LIBSSH2_API int libssh2_channel_close(LIBSSH2_CHANNEL *channel)
return 0; return 0;
} }
if (channel->close_cb) {
LIBSSH2_CHANNEL_CLOSE(session, channel);
}
packet[0] = SSH_MSG_CHANNEL_CLOSE; packet[0] = SSH_MSG_CHANNEL_CLOSE;
libssh2_htonu32(packet + 1, channel->remote.id); libssh2_htonu32(packet + 1, channel->remote.id);
if (libssh2_packet_write(session, packet, 5)) { if (libssh2_packet_write(session, packet, 5)) {

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net> /* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * 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; z_stream *strm = *abstract;
/* A short-term alloc of a full data chunk is better than a series of reallocs */ /* A short-term alloc of a full data chunk is better than a series of reallocs */
char *out; char *out;
int out_maxlen = compress ? src_len : (2 * src_len); int out_maxlen = compress ? (src_len + 4) : (2 * src_len);
int limiter = 0; int limiter = 0;
/* In practice they never come smaller than this */ /* In practice they never come smaller than this */
if (out_maxlen < 21) { if (out_maxlen < 25) {
out_maxlen = 21; out_maxlen = 25;
} }
if (out_maxlen > payload_limit) { if (out_maxlen > payload_limit) {
@@ -172,11 +172,11 @@ static int libssh2_comp_method_zlib_comp(LIBSSH2_SESSION *session, int compress,
if (strm->avail_in) { if (strm->avail_in) {
unsigned long out_ofs = out_maxlen - strm->avail_out; 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++) { if ((out_maxlen > payload_limit) && !compress && limiter++) {
libssh2_error(session, LIBSSH2_ERROR_ZLIB, "Excessive growth in decompression phase", 0); libssh2_error(session, LIBSSH2_ERROR_ZLIB, "Excessive growth in decompression phase", 0);
LIBSSH2_FREE(session, strm->next_out); LIBSSH2_FREE(session, out);
return -1; return -1;
} }
@@ -186,7 +186,43 @@ static int libssh2_comp_method_zlib_comp(LIBSSH2_SESSION *session, int compress,
return -1; return -1;
} }
strm->next_out = out + out_ofs; 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, strm->next_out);
return -1;
}
} }
} }

View File

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

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net> /* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@@ -38,6 +38,7 @@
#include "libssh2_priv.h" #include "libssh2_priv.h"
#include <openssl/bn.h> #include <openssl/bn.h>
#include <openssl/pem.h> #include <openssl/pem.h>
#include <openssl/evp.h>
#ifndef OPENSSL_NO_RSA #ifndef OPENSSL_NO_RSA
/* *********** /* ***********
@@ -86,7 +87,8 @@ static int libssh2_hostkey_method_ssh_rsa_init(LIBSSH2_SESSION *session, unsigne
/* {{{ libssh2_hostkey_method_ssh_rsa_passphrase_cb /* {{{ libssh2_hostkey_method_ssh_rsa_passphrase_cb
* TODO: Optionally call a passphrase callback specified by the calling program * 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); int passphrase_len = strlen(passphrase);
if (passphrase_len > (size - 1)) { if (passphrase_len > (size - 1)) {
@@ -116,6 +118,14 @@ static int libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION *session, unsi
if (!fp) { if (!fp) {
return -1; 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_algorithms_noconf();
}
rsactx = PEM_read_RSAPrivateKey(fp, NULL, (void*)libssh2_hostkey_method_ssh_rsadsa_passphrase_cb, passphrase); rsactx = PEM_read_RSAPrivateKey(fp, NULL, (void*)libssh2_hostkey_method_ssh_rsadsa_passphrase_cb, passphrase);
if (!rsactx) { if (!rsactx) {
fclose(fp); fclose(fp);
@@ -322,6 +332,14 @@ static int libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION *session, unsi
if (!fp) { if (!fp) {
return -1; 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_algorithms_noconf();
}
dsactx = PEM_read_DSAPrivateKey(fp, NULL, (void*)libssh2_hostkey_method_ssh_rsadsa_passphrase_cb, passphrase); dsactx = PEM_read_DSAPrivateKey(fp, NULL, (void*)libssh2_hostkey_method_ssh_rsadsa_passphrase_cb, passphrase);
if (!dsactx) { if (!dsactx) {
fclose(fp); fclose(fp);
@@ -371,16 +389,14 @@ static int libssh2_hostkey_method_ssh_dss_sign(LIBSSH2_SESSION *session, unsigne
const unsigned char *buf, unsigned long buf_len, void **abstract) const unsigned char *buf, unsigned long buf_len, void **abstract)
{ {
DSA *dsactx = (DSA*)(*abstract); DSA *dsactx = (DSA*)(*abstract);
int ret; DSA_SIG *sig;
unsigned char hash[SHA_DIGEST_LENGTH]; unsigned char hash[SHA_DIGEST_LENGTH];
SHA_CTX ctx; SHA_CTX ctx;
char *sig;
int sig_len;
sig_len = DSA_size(dsactx); *signature = LIBSSH2_ALLOC(session, 2 * SHA_DIGEST_LENGTH);
sig = LIBSSH2_ALLOC(session, sig_len); *signature_len = 2 * SHA_DIGEST_LENGTH;
if (!sig) { if (!(*signature)) {
return -1; return -1;
} }
@@ -388,14 +404,16 @@ static int libssh2_hostkey_method_ssh_dss_sign(LIBSSH2_SESSION *session, unsigne
SHA1_Update(&ctx, buf, buf_len); SHA1_Update(&ctx, buf, buf_len);
SHA1_Final(hash, &ctx); SHA1_Final(hash, &ctx);
ret = DSA_sign(NID_sha1, hash, SHA_DIGEST_LENGTH, sig, &sig_len, dsactx); sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx);
if (!ret) { if (!sig) {
LIBSSH2_FREE(session, sig); LIBSSH2_FREE(session, *signature);
return -1; return -1;
} }
*signature = sig; BN_bn2bin(sig->r, *signature);
*signature_len = sig_len; BN_bn2bin(sig->s, *signature + SHA_DIGEST_LENGTH);
DSA_SIG_free(sig);
return 0; return 0;
} }
@@ -408,16 +426,16 @@ static int libssh2_hostkey_method_ssh_dss_signv(LIBSSH2_SESSION *session, unsign
unsigned long veccount, const struct iovec datavec[], void **abstract) unsigned long veccount, const struct iovec datavec[], void **abstract)
{ {
DSA *dsactx = (DSA*)(*abstract); DSA *dsactx = (DSA*)(*abstract);
int ret, i; DSA_SIG *sig;
unsigned char hash[SHA_DIGEST_LENGTH]; unsigned char hash[SHA_DIGEST_LENGTH];
SHA_CTX ctx; SHA_CTX ctx;
char *sig; int r_len, s_len, rs_pad, i;
int sig_len;
sig_len = DSA_size(dsactx); *signature = LIBSSH2_ALLOC(session, 2 * SHA_DIGEST_LENGTH);
sig = LIBSSH2_ALLOC(session, sig_len); *signature_len = 2 * SHA_DIGEST_LENGTH;
memset(*signature, 0, 2 * SHA_DIGEST_LENGTH);
if (!sig) { if (!(*signature)) {
return -1; return -1;
} }
@@ -427,15 +445,25 @@ static int libssh2_hostkey_method_ssh_dss_signv(LIBSSH2_SESSION *session, unsign
} }
SHA1_Final(hash, &ctx); SHA1_Final(hash, &ctx);
ret = DSA_sign(NID_sha1, hash, SHA_DIGEST_LENGTH, sig, &sig_len, dsactx); sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx);
if (!sig) {
if (!ret) { LIBSSH2_FREE(session, *signature);
LIBSSH2_FREE(session, sig);
return -1; return -1;
} }
*signature = sig; r_len = BN_num_bytes(sig->r);
*signature_len = sig_len; 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; return 0;
} }
@@ -485,7 +513,10 @@ LIBSSH2_HOSTKEY_METHOD **libssh2_hostkey_methods(void)
} }
/* {{{ libssh2_hostkey_hash /* {{{ libssh2_hostkey_hash
* Returns NULL terminated hash signature * Returns hash signature
* Returned buffer should NOT be freed
* Length of buffer is determined by hash type
* i.e. MD5 == 16, SHA1 == 20
*/ */
LIBSSH2_API char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type) LIBSSH2_API char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type)
{ {

337
src/kex.c
View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net> /* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@@ -39,6 +39,7 @@
#include <openssl/bn.h> #include <openssl/bn.h>
#include <openssl/sha.h> #include <openssl/sha.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/rand.h>
/* TODO: Switch this to an inline and handle alloc() failures */ /* TODO: Switch this to an inline and handle alloc() failures */
/* Helper macro called from libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange */ /* 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; goto clean_exit;
} }
/* The first key exchange has been performed, switch to active crypt/comp/mac mode */ /* 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 */ /* This will actually end up being just packet_type(1) for this packet type anyway */
LIBSSH2_FREE(session, tmp); 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; unsigned char *key = NULL;
int free_key = 0; 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); session->local.mac->init(session, key, &free_key, &session->local.mac_abstract);
if (free_key) { if (free_key) {
memset(key, 0, session->kex->key_len); memset(key, 0, session->local.mac->key_len);
LIBSSH2_FREE(session, key); 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; unsigned char *key = NULL;
int free_key = 0; 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); session->remote.mac->init(session, key, &free_key, &session->remote.mac_abstract);
if (free_key) { if (free_key) {
memset(key, 0, session->kex->key_len); memset(key, 0, session->remote.mac->key_len);
LIBSSH2_FREE(session, key); 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 = { LIBSSH2_KEX_METHOD libssh2_kex_method_diffie_helman_group1_sha1 = {
"diffie-hellman-group1-sha1", "diffie-hellman-group1-sha1",
SHA_DIGEST_LENGTH,
libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange, libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange,
LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
}; };
LIBSSH2_KEX_METHOD libssh2_kex_method_diffie_helman_group14_sha1 = { LIBSSH2_KEX_METHOD libssh2_kex_method_diffie_helman_group14_sha1 = {
"diffie-hellman-group14-sha1", "diffie-hellman-group14-sha1",
SHA_DIGEST_LENGTH,
libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange, libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange,
LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
}; };
LIBSSH2_KEX_METHOD libssh2_kex_method_diffie_helman_group_exchange_sha1 = { LIBSSH2_KEX_METHOD libssh2_kex_method_diffie_helman_group_exchange_sha1 = {
"diffie-hellman-group-exchange-sha1", "diffie-hellman-group-exchange-sha1",
SHA_DIGEST_LENGTH,
libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange, libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange,
LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
}; };
@@ -671,16 +669,16 @@ static size_t libssh2_kex_method_list(unsigned char *buf, size_t list_strlen, LI
} }
/* }}} */ /* }}} */
#define LIBSSH2_METHOD_PREFS \ #define LIBSSH2_METHOD_PREFS_LEN(prefvar, defaultvar) ((prefvar) ? strlen(prefvar) : libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)(defaultvar)))
LIBSSH2_KEX_METHOD **kex_prefs = session->kex_prefs ? session->kex_prefs : libssh2_kex_methods; \ #define LIBSSH2_METHOD_PREFS_STR(buf, prefvarlen, prefvar, defaultvar) \
LIBSSH2_HOSTKEY_METHOD **hostkey_prefs = session->hostkey_prefs ? session->hostkey_prefs : libssh2_hostkey_methods(); \ if (prefvar) { \
LIBSSH2_CRYPT_METHOD **crypt_cs_prefs = session->local.crypt_prefs ? session->local.crypt_prefs : libssh2_crypt_methods(); \ libssh2_htonu32((buf), (prefvarlen)); \
LIBSSH2_CRYPT_METHOD **crypt_sc_prefs = session->remote.crypt_prefs ? session->remote.crypt_prefs : libssh2_crypt_methods(); \ buf += 4; \
LIBSSH2_COMP_METHOD **comp_cs_prefs = session->local.comp_prefs ? session->local.comp_prefs : libssh2_comp_methods(); \ memcpy((buf), (prefvar), (prefvarlen)); \
LIBSSH2_COMP_METHOD **comp_sc_prefs = session->remote.comp_prefs ? session->remote.comp_prefs : libssh2_comp_methods(); \ buf += (prefvarlen); \
LIBSSH2_MAC_METHOD **mac_cs_prefs = session->local.mac_prefs ? session->local.mac_prefs : libssh2_mac_methods(); \ } else { \
LIBSSH2_MAC_METHOD **mac_sc_prefs = session->remote.mac_prefs ? session->remote.mac_prefs : libssh2_mac_methods(); buf += libssh2_kex_method_list((buf), (prefvarlen), (LIBSSH2_COMMON_METHOD**)(defaultvar)); \
}
/* {{{ libssh2_kexinit /* {{{ libssh2_kexinit
* Send SSH_MSG_KEXINIT packet * Send SSH_MSG_KEXINIT packet
@@ -694,18 +692,17 @@ static int libssh2_kexinit(LIBSSH2_SESSION *session)
size_t mac_cs_len, mac_sc_len; size_t mac_cs_len, mac_sc_len;
size_t lang_cs_len, lang_sc_len; size_t lang_cs_len, lang_sc_len;
unsigned char *data, *s; unsigned char *data, *s;
LIBSSH2_METHOD_PREFS
kex_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)kex_prefs); kex_len = LIBSSH2_METHOD_PREFS_LEN(session->kex_prefs, libssh2_kex_methods);
hostkey_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)hostkey_prefs); hostkey_len = LIBSSH2_METHOD_PREFS_LEN(session->hostkey_prefs, libssh2_hostkey_methods());
crypt_cs_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)crypt_cs_prefs); crypt_cs_len = LIBSSH2_METHOD_PREFS_LEN(session->local.crypt_prefs, libssh2_crypt_methods());
crypt_sc_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)crypt_sc_prefs); crypt_sc_len = LIBSSH2_METHOD_PREFS_LEN(session->remote.crypt_prefs, libssh2_crypt_methods());
mac_cs_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)mac_cs_prefs); mac_cs_len = LIBSSH2_METHOD_PREFS_LEN(session->local.mac_prefs, libssh2_mac_methods());
mac_sc_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)mac_sc_prefs); mac_sc_len = LIBSSH2_METHOD_PREFS_LEN(session->remote.mac_prefs, libssh2_mac_methods());
comp_cs_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)comp_cs_prefs); comp_cs_len = LIBSSH2_METHOD_PREFS_LEN(session->local.comp_prefs, libssh2_comp_methods());
comp_sc_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)comp_sc_prefs); comp_sc_len = LIBSSH2_METHOD_PREFS_LEN(session->remote.comp_prefs, libssh2_comp_methods());
lang_cs_len = 0; /* No langs in this version */ lang_cs_len = LIBSSH2_METHOD_PREFS_LEN(session->local.lang_prefs, NULL);
lang_sc_len = 0; /* No langs in this version */ lang_sc_len = LIBSSH2_METHOD_PREFS_LEN(session->remote.lang_prefs, NULL);
data_len += kex_len + hostkey_len + \ data_len += kex_len + hostkey_len + \
crypt_cs_len + crypt_sc_len + \ crypt_cs_len + crypt_sc_len + \
@@ -721,21 +718,20 @@ static int libssh2_kexinit(LIBSSH2_SESSION *session)
*(s++) = SSH_MSG_KEXINIT; *(s++) = SSH_MSG_KEXINIT;
/* TODO: Build a better cookie (and the mice will beat a path to my door...) */ RAND_bytes(s, 16);
memcpy(s, "mysecretMYSECRET", 16);
s += 16; s += 16;
/* Ennumerating through these lists twice is probably (certainly?) inefficient from a CPU standpoint, but it saves multiple malloc/realloc calls */ /* Ennumerating through these lists twice is probably (certainly?) inefficient from a CPU standpoint, but it saves multiple malloc/realloc calls */
s += libssh2_kex_method_list(s, kex_len, (LIBSSH2_COMMON_METHOD**)kex_prefs); LIBSSH2_METHOD_PREFS_STR(s, kex_len, session->kex_prefs, libssh2_kex_methods);
s += libssh2_kex_method_list(s, hostkey_len, (LIBSSH2_COMMON_METHOD**)hostkey_prefs); LIBSSH2_METHOD_PREFS_STR(s, hostkey_len, session->hostkey_prefs, libssh2_hostkey_methods());
s += libssh2_kex_method_list(s, crypt_cs_len, (LIBSSH2_COMMON_METHOD**)crypt_cs_prefs); LIBSSH2_METHOD_PREFS_STR(s, crypt_cs_len, session->local.crypt_prefs, libssh2_crypt_methods());
s += libssh2_kex_method_list(s, crypt_sc_len, (LIBSSH2_COMMON_METHOD**)crypt_sc_prefs); LIBSSH2_METHOD_PREFS_STR(s, crypt_sc_len, session->remote.crypt_prefs, libssh2_crypt_methods());
s += libssh2_kex_method_list(s, mac_cs_len, (LIBSSH2_COMMON_METHOD**)mac_cs_prefs); LIBSSH2_METHOD_PREFS_STR(s, mac_cs_len, session->local.mac_prefs, libssh2_mac_methods());
s += libssh2_kex_method_list(s, mac_sc_len, (LIBSSH2_COMMON_METHOD**)mac_sc_prefs); LIBSSH2_METHOD_PREFS_STR(s, mac_sc_len, session->remote.mac_prefs, libssh2_mac_methods());
s += libssh2_kex_method_list(s, comp_cs_len, (LIBSSH2_COMMON_METHOD**)comp_cs_prefs); LIBSSH2_METHOD_PREFS_STR(s, comp_cs_len, session->local.comp_prefs, libssh2_comp_methods());
s += libssh2_kex_method_list(s, comp_sc_len, (LIBSSH2_COMMON_METHOD**)comp_sc_prefs); LIBSSH2_METHOD_PREFS_STR(s, comp_sc_len, session->remote.comp_prefs, libssh2_comp_methods());
s += libssh2_kex_method_list(s, lang_cs_len, NULL); LIBSSH2_METHOD_PREFS_STR(s, lang_cs_len, session->local.lang_prefs, NULL);
s += libssh2_kex_method_list(s, lang_sc_len, NULL); LIBSSH2_METHOD_PREFS_STR(s, lang_sc_len, session->remote.lang_prefs, NULL);
/* No optimistic KEX packet follows */ /* No optimistic KEX packet follows */
/* Deal with optimistic packets /* Deal with optimistic packets
@@ -803,14 +799,61 @@ static unsigned char *libssh2_kex_agree_instr(unsigned char *haystack, unsigned
} }
/* }}} */ /* }}} */
/* {{{ libssh2_get_method_by_name
*/
static LIBSSH2_COMMON_METHOD *libssh2_get_method_by_name(char *name, int name_len, LIBSSH2_COMMON_METHOD **methodlist)
{
while (*methodlist) {
if ((strlen((*methodlist)->name) == name_len) &&
(strncmp((*methodlist)->name, name, name_len) == 0)) {
return *methodlist;
}
methodlist++;
}
return NULL;
}
/* }}} */
/* {{{ libssh2_kex_agree_hostkey /* {{{ libssh2_kex_agree_hostkey
* Agree on a Hostkey which works with this kex * Agree on a Hostkey which works with this kex
*/ */
static int libssh2_kex_agree_hostkey(LIBSSH2_SESSION *session, unsigned long kex_flags, unsigned char *hostkey, unsigned long hostkey_len) static int libssh2_kex_agree_hostkey(LIBSSH2_SESSION *session, unsigned long kex_flags, unsigned char *hostkey, unsigned long hostkey_len)
{ {
LIBSSH2_HOSTKEY_METHOD **hostkeyp = session->hostkey_prefs ? session->hostkey_prefs : libssh2_hostkey_methods(); LIBSSH2_HOSTKEY_METHOD **hostkeyp = libssh2_hostkey_methods();
unsigned char *s; unsigned char *s;
if (session->hostkey_prefs) {
s = session->hostkey_prefs;
while (s && *s) {
unsigned char *p = strchr(s, ',');
int method_len = (p ? (p - s) : strlen(s));
if (libssh2_kex_agree_instr(hostkey, hostkey_len, s, method_len)) {
LIBSSH2_HOSTKEY_METHOD *method = (LIBSSH2_HOSTKEY_METHOD*)libssh2_get_method_by_name(s, method_len, (LIBSSH2_COMMON_METHOD**)hostkeyp);
if (!method) {
/* Invalid method -- Should never be reached */
return -1;
}
/* So far so good, but does it suit our purposes? (Encrypting vs Signing) */
if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY) == 0) ||
(method->encrypt)) {
/* Either this hostkey can do encryption or this kex just doesn't require it */
if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY) == 0) ||
(method->sig_verify)) {
/* Either this hostkey can do signing or this kex just doesn't require it */
session->hostkey = method;
return 0;
}
}
}
s = p ? p + 1 : NULL;
}
return -1;
}
while ((*hostkeyp)->name) { while ((*hostkeyp)->name) {
s = libssh2_kex_agree_instr(hostkey, hostkey_len, (*hostkeyp)->name, strlen((*hostkeyp)->name)); s = libssh2_kex_agree_instr(hostkey, hostkey_len, (*hostkeyp)->name, strlen((*hostkeyp)->name));
if (s) { if (s) {
@@ -839,9 +882,37 @@ static int libssh2_kex_agree_hostkey(LIBSSH2_SESSION *session, unsigned long kex
static int libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION *session, unsigned char *kex, unsigned long kex_len, static int libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION *session, unsigned char *kex, unsigned long kex_len,
unsigned char *hostkey, unsigned long hostkey_len) unsigned char *hostkey, unsigned long hostkey_len)
{ {
LIBSSH2_KEX_METHOD **kexp = session->kex_prefs ? session->kex_prefs : libssh2_kex_methods; LIBSSH2_KEX_METHOD **kexp = libssh2_kex_methods;
unsigned char *s; unsigned char *s;
if (session->kex_prefs) {
s = session->kex_prefs;
while (s && *s) {
unsigned char *p = strchr(s, ',');
int method_len = (p ? (p - s) : strlen(s));
if (libssh2_kex_agree_instr(kex, kex_len, s, method_len)) {
LIBSSH2_KEX_METHOD *method = (LIBSSH2_KEX_METHOD*)libssh2_get_method_by_name(s, method_len, (LIBSSH2_COMMON_METHOD**)kexp);
if (!method) {
/* Invalid method -- Should never be reached */
return -1;
}
/* We've agreed on a key exchange method,
* Can we agree on a hostkey that works with this kex?
*/
if (libssh2_kex_agree_hostkey(session, method->flags, hostkey, hostkey_len) == 0) {
session->kex = method;
return 0;
}
}
s = p ? p + 1 : NULL;
}
return -1;
}
while (*kexp && (*kexp)->name) { while (*kexp && (*kexp)->name) {
s = libssh2_kex_agree_instr(kex, kex_len, (*kexp)->name, strlen((*kexp)->name)); s = libssh2_kex_agree_instr(kex, kex_len, (*kexp)->name, strlen((*kexp)->name));
if (s) { if (s) {
@@ -864,9 +935,33 @@ static int libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION *session, unsigned char
*/ */
static int libssh2_kex_agree_crypt(LIBSSH2_SESSION *session, libssh2_endpoint_data *endpoint, unsigned char *crypt, unsigned long crypt_len) static int libssh2_kex_agree_crypt(LIBSSH2_SESSION *session, libssh2_endpoint_data *endpoint, unsigned char *crypt, unsigned long crypt_len)
{ {
LIBSSH2_CRYPT_METHOD **cryptp = endpoint->crypt_prefs ? endpoint->crypt_prefs : libssh2_crypt_methods(); LIBSSH2_CRYPT_METHOD **cryptp = libssh2_crypt_methods();
unsigned char *s; unsigned char *s;
if (endpoint->crypt_prefs) {
s = endpoint->crypt_prefs;
while (s && *s) {
unsigned char *p = strchr(s, ',');
int method_len = (p ? (p - s) : strlen(s));
if (libssh2_kex_agree_instr(crypt, crypt_len, s, method_len)) {
LIBSSH2_CRYPT_METHOD *method = (LIBSSH2_CRYPT_METHOD*)libssh2_get_method_by_name(s, method_len, (LIBSSH2_COMMON_METHOD**)cryptp);
if (!method) {
/* Invalid method -- Should never be reached */
return -1;
}
endpoint->crypt = method;
return 0;
}
s = p ? p + 1 : NULL;
}
return -1;
}
while ((*cryptp)->name) { while ((*cryptp)->name) {
s = libssh2_kex_agree_instr(crypt, crypt_len, (*cryptp)->name, strlen((*cryptp)->name)); s = libssh2_kex_agree_instr(crypt, crypt_len, (*cryptp)->name, strlen((*cryptp)->name));
if (s) { if (s) {
@@ -885,9 +980,33 @@ static int libssh2_kex_agree_crypt(LIBSSH2_SESSION *session, libssh2_endpoint_da
*/ */
static int libssh2_kex_agree_mac(LIBSSH2_SESSION *session, libssh2_endpoint_data *endpoint, unsigned char *mac, unsigned long mac_len) static int libssh2_kex_agree_mac(LIBSSH2_SESSION *session, libssh2_endpoint_data *endpoint, unsigned char *mac, unsigned long mac_len)
{ {
LIBSSH2_MAC_METHOD **macp = endpoint->mac_prefs ? endpoint->mac_prefs : libssh2_mac_methods(); LIBSSH2_MAC_METHOD **macp = libssh2_mac_methods();
unsigned char *s; unsigned char *s;
if (endpoint->mac_prefs) {
s = endpoint->mac_prefs;
while (s && *s) {
unsigned char *p = strchr(s, ',');
int method_len = (p ? (p - s) : strlen(s));
if (libssh2_kex_agree_instr(mac, mac_len, s, method_len)) {
LIBSSH2_MAC_METHOD *method = (LIBSSH2_MAC_METHOD*)libssh2_get_method_by_name(s, method_len, (LIBSSH2_COMMON_METHOD**)macp);
if (!method) {
/* Invalid method -- Should never be reached */
return -1;
}
endpoint->mac = method;
return 0;
}
s = p ? p + 1 : NULL;
}
return -1;
}
while ((*macp)->name) { while ((*macp)->name) {
s = libssh2_kex_agree_instr(mac, mac_len, (*macp)->name, strlen((*macp)->name)); s = libssh2_kex_agree_instr(mac, mac_len, (*macp)->name, strlen((*macp)->name));
if (s) { if (s) {
@@ -906,9 +1025,33 @@ static int libssh2_kex_agree_mac(LIBSSH2_SESSION *session, libssh2_endpoint_data
*/ */
static int libssh2_kex_agree_comp(LIBSSH2_SESSION *session, libssh2_endpoint_data *endpoint, unsigned char *comp, unsigned long comp_len) static int libssh2_kex_agree_comp(LIBSSH2_SESSION *session, libssh2_endpoint_data *endpoint, unsigned char *comp, unsigned long comp_len)
{ {
LIBSSH2_COMP_METHOD **compp = endpoint->comp_prefs ? endpoint->comp_prefs : libssh2_comp_methods(); LIBSSH2_COMP_METHOD **compp = libssh2_comp_methods();
unsigned char *s; unsigned char *s;
if (endpoint->comp_prefs) {
s = endpoint->comp_prefs;
while (s && *s) {
unsigned char *p = strchr(s, ',');
int method_len = (p ? (p - s) : strlen(s));
if (libssh2_kex_agree_instr(comp, comp_len, s, method_len)) {
LIBSSH2_COMP_METHOD *method = (LIBSSH2_COMP_METHOD*)libssh2_get_method_by_name(s, method_len, (LIBSSH2_COMMON_METHOD**)compp);
if (!method) {
/* Invalid method -- Should never be reached */
return -1;
}
endpoint->comp = method;
return 0;
}
s = p ? p + 1 : NULL;
}
return -1;
}
while ((*compp)->name) { while ((*compp)->name) {
s = libssh2_kex_agree_instr(comp, comp_len, (*compp)->name, strlen((*compp)->name)); s = libssh2_kex_agree_instr(comp, comp_len, (*compp)->name, strlen((*compp)->name));
if (s) { if (s) {
@@ -1002,7 +1145,7 @@ int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange) /* session->f
unsigned long data_len; unsigned long data_len;
/* Prevent loop in packet_add() */ /* Prevent loop in packet_add() */
session->exchanging_keys = 1; session->state |= LIBSSH2_STATE_EXCHANGING_KEYS;
if (reexchange) { if (reexchange) {
session->kex = NULL; session->kex = NULL;
@@ -1048,9 +1191,105 @@ int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange) /* session->f
session->remote.kexinit = NULL; session->remote.kexinit = NULL;
} }
session->exchanging_keys = 0; session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
return 0; return 0;
} }
/* }}} */ /* }}} */
/* {{{ libssh2_session_method_pref
* Set preferred method
*/
LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method_type, char *prefs)
{
char **prefvar, *s, *newprefs;
int prefs_len = strlen(prefs);
LIBSSH2_COMMON_METHOD **mlist;
switch (method_type) {
case LIBSSH2_METHOD_KEX:
prefvar = &session->kex_prefs;
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_kex_methods;
break;
case LIBSSH2_METHOD_HOSTKEY:
prefvar = &session->hostkey_prefs;
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_hostkey_methods();
break;
case LIBSSH2_METHOD_CRYPT_CS:
prefvar = &session->local.crypt_prefs;
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_crypt_methods();
break;
case LIBSSH2_METHOD_CRYPT_SC:
prefvar = &session->remote.crypt_prefs;
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_crypt_methods();
break;
case LIBSSH2_METHOD_MAC_CS:
prefvar = &session->local.mac_prefs;
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_mac_methods();
break;
case LIBSSH2_METHOD_MAC_SC:
prefvar = &session->remote.mac_prefs;
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_mac_methods();
break;
case LIBSSH2_METHOD_COMP_CS:
prefvar = &session->local.comp_prefs;
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_comp_methods();
break;
case LIBSSH2_METHOD_COMP_SC:
prefvar = &session->remote.comp_prefs;
mlist = (LIBSSH2_COMMON_METHOD**)libssh2_comp_methods();
break;
case LIBSSH2_METHOD_LANG_CS:
prefvar = &session->local.lang_prefs;
mlist = NULL;
break;
case LIBSSH2_METHOD_LANG_SC:
prefvar = &session->remote.lang_prefs;
mlist = NULL;
break;
default:
libssh2_error(session, LIBSSH2_ERROR_INVAL, "Invalid parameter specified for method_type", 0);
return -1;
}
s = newprefs = LIBSSH2_ALLOC(session, prefs_len + 1);
if (!newprefs) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Error allocated space for method preferences", 0);
return -1;
}
memcpy(s, prefs, prefs_len + 1);
while (s && *s) {
char *p = strchr(s, ',');
int method_len = p ? (p - s) : strlen(s);
if (!libssh2_get_method_by_name(s, method_len, mlist)) {
/* Strip out unsupported method */
if (p) {
memcpy(s, p + 1, strlen(s) - method_len);
} else {
if (s > newprefs) {
*(--s) = '\0';
} else {
*s = '\0';
}
}
}
s = p ? (p + 1) : NULL;
}
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;
}
if (*prefvar) {
LIBSSH2_FREE(session, *prefvar);
}
*prefvar = newprefs;
return 0;
}
/* }}} */

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net> /* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * 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 = { static LIBSSH2_MAC_METHOD libssh2_mac_method_none = {
"none", "none",
0, 0,
0,
NULL, NULL,
libssh2_mac_none_MAC, libssh2_mac_none_MAC,
NULL NULL
@@ -98,7 +99,7 @@ static int libssh2_mac_method_hmac_sha1_hash(LIBSSH2_SESSION *session, unsigned
libssh2_htonu32(seqno_buf, seqno); 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, seqno_buf, 4);
HMAC_Update(&ctx, packet, packet_len); HMAC_Update(&ctx, packet, packet_len);
if (addtl && addtl_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 = { static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_sha1 = {
"hmac-sha1", "hmac-sha1",
SHA_DIGEST_LENGTH, 20,
20,
libssh2_mac_method_common_init, libssh2_mac_method_common_init,
libssh2_mac_method_hmac_sha1_hash, libssh2_mac_method_hmac_sha1_hash,
libssh2_mac_method_common_dtor, 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 = { static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_sha1_96 = {
"hmac-sha1-96", "hmac-sha1-96",
96 / 8, 12,
20,
libssh2_mac_method_common_init, libssh2_mac_method_common_init,
libssh2_mac_method_hmac_sha1_96_hash, libssh2_mac_method_hmac_sha1_96_hash,
libssh2_mac_method_common_dtor, libssh2_mac_method_common_dtor,
}; };
#ifdef WHY_DOESNT_MD5_WORK
/* {{{ libssh2_mac_method_hmac_md5_hash /* {{{ libssh2_mac_method_hmac_md5_hash
* Calculate hash using full md5 value * 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); 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, seqno_buf, 4);
HMAC_Update(&ctx, packet, packet_len); HMAC_Update(&ctx, packet, packet_len);
if (addtl && addtl_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 = { static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_md5 = {
"hmac-md5", "hmac-md5",
MD5_DIGEST_LENGTH, 16,
16,
libssh2_mac_method_common_init, libssh2_mac_method_common_init,
libssh2_mac_method_hmac_md5_hash, libssh2_mac_method_hmac_md5_hash,
libssh2_mac_method_common_dtor, 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 /* {{{ libssh2_mac_method_hmac_md5_96_hash
* Calculate hash using first 96 bits of md5 value * 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, static int libssh2_mac_method_hmac_md5_96_hash(LIBSSH2_SESSION *session, unsigned char *buf, unsigned long seqno,
const unsigned char *packet, unsigned packet_len, const unsigned char *packet, unsigned long packet_len,
const unsigned char *addtl, unsigned long addtl_len, void **abstract) const unsigned char *addtl, unsigned long addtl_len, void **abstract)
{ {
char temp[MD5_DIGEST_LENGTH]; 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 = { static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_md5_96 = {
"hmac-md5-96", "hmac-md5-96",
96 / 8, 12,
16,
libssh2_mac_method_common_init, libssh2_mac_method_common_init,
libssh2_mac_method_hmac_md5_96_hash, libssh2_mac_method_hmac_md5_96_hash,
libssh2_mac_method_common_dtor, libssh2_mac_method_common_dtor,
}; };
#endif /* WHY_DOESNT_MD5_WORK */
#ifndef OPENSSL_NO_RIPEMD #ifndef OPENSSL_NO_RIPEMD
/* {{{ libssh2_mac_method_hmac_ripemd160_hash /* {{{ 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); 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, seqno_buf, 4);
HMAC_Update(&ctx, packet, packet_len); HMAC_Update(&ctx, packet, packet_len);
if (addtl && addtl_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 = { static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160 = {
"hmac-ripemd160", "hmac-ripemd160",
160 / 8, 20,
20,
libssh2_mac_method_common_init, libssh2_mac_method_common_init,
libssh2_mac_method_hmac_ripemd160_hash, libssh2_mac_method_hmac_ripemd160_hash,
libssh2_mac_method_common_dtor, 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 = { static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160_openssh_com = {
"hmac-ripemd160@openssh.com", "hmac-ripemd160@openssh.com",
160 / 8, 20,
20,
libssh2_mac_method_common_init, libssh2_mac_method_common_init,
libssh2_mac_method_hmac_ripemd160_hash, libssh2_mac_method_hmac_ripemd160_hash,
libssh2_mac_method_common_dtor, 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[] = { static LIBSSH2_MAC_METHOD *_libssh2_mac_methods[] = {
&libssh2_mac_method_hmac_sha1, &libssh2_mac_method_hmac_sha1,
&libssh2_mac_method_hmac_sha1_96, &libssh2_mac_method_hmac_sha1_96,
#ifdef WHY_DOESNT_MD5_WORK
&libssh2_mac_method_hmac_md5, &libssh2_mac_method_hmac_md5,
&libssh2_mac_method_hmac_md5_96, &libssh2_mac_method_hmac_md5_96,
#endif /* WHY_DOESNT_MD5_WORK */
#ifndef OPENSSL_NO_RIPEMD #ifndef OPENSSL_NO_RIPEMD
&libssh2_mac_method_hmac_ripemd160, &libssh2_mac_method_hmac_ripemd160,
&libssh2_mac_method_hmac_ripemd160_openssh_com, &libssh2_mac_method_hmac_ripemd160_openssh_com,

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net> /* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@@ -45,6 +45,21 @@ unsigned long libssh2_ntohu32(const unsigned char *buf)
} }
/* }}} */ /* }}} */
/* {{{ libssh2_ntohu64
* 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
*/
libssh2_uint64_t libssh2_ntohu64(const unsigned char *buf)
{
unsigned long msl, lsl;
msl = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
lsl = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
return ((msl * 65536) * 65536) + lsl;
}
/* }}} */
/* {{{ libssh2_htonu32 /* {{{ libssh2_htonu32
*/ */
void libssh2_htonu32(unsigned char *buf, unsigned long value) void libssh2_htonu32(unsigned char *buf, unsigned long value)
@@ -56,6 +71,24 @@ void libssh2_htonu32(unsigned char *buf, unsigned long value)
} }
/* }}} */ /* }}} */
/* {{{ libssh2_htonu64
*/
void libssh2_htonu64(unsigned char *buf, libssh2_uint64_t value)
{
unsigned long msl = (value / 65536) / 65536;
buf[0] = (msl >> 24) & 0xFF;
buf[1] = (msl >> 16) & 0xFF;
buf[2] = (msl >> 8) & 0xFF;
buf[3] = msl & 0xFF;
buf[4] = (value >> 24) & 0xFF;
buf[5] = (value >> 16) & 0xFF;
buf[6] = (value >> 8) & 0xFF;
buf[7] = value & 0xFF;
}
/* }}} */
/* Base64 Conversion */ /* Base64 Conversion */
/* {{{ */ /* {{{ */

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net> /* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@@ -38,8 +38,236 @@
#include "libssh2_priv.h" #include "libssh2_priv.h"
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#ifndef WIN32
#include <unistd.h> #include <unistd.h>
#endif
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/rand.h>
/* {{{ 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 /* {{{ libssh2_packet_new
* Create a new packet and attach it to the brigade * Create a new packet and attach it to the brigade
@@ -153,7 +381,7 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
LIBSSH2_FREE(session, data); LIBSSH2_FREE(session, data);
return 0; return 0;
} }
if (channel->remote.ignore_extended_data && (data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)) { if ((channel->remote.extended_data_ignore_mode == LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE) && (data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)) {
/* Pretend we didn't receive this */ /* Pretend we didn't receive this */
LIBSSH2_FREE(session, data); LIBSSH2_FREE(session, data);
@@ -229,6 +457,37 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
return 0; return 0;
} }
break; 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)); packet = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
@@ -251,7 +510,7 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
packet->prev = NULL; 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 /* Remote wants new keys
* Well, it's already in the brigade, * Well, it's already in the brigade,
* let's just call back into ourselves * let's just call back into ourselves
@@ -275,8 +534,17 @@ static int libssh2_blocking_read(LIBSSH2_SESSION *session, unsigned char *buf, s
while (bytes_read < count) { while (bytes_read < count) {
int ret; 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) { 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 (errno == EAGAIN) {
if (polls++ > LIBSSH2_SOCKET_POLL_MAXLOOPS) { if (polls++ > LIBSSH2_SOCKET_POLL_MAXLOOPS) {
return -1; return -1;
@@ -315,9 +583,19 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
return 0; return 0;
} }
#ifndef WIN32
fcntl(session->socket_fd, F_SETFL, O_NONBLOCK); fcntl(session->socket_fd, F_SETFL, O_NONBLOCK);
if (session->newkeys) { #else
unsigned char *block, *payload, *s, tmp[6]; {
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
*/
unsigned char block[2 * 32], *payload, *s, tmp[6];
long read_len; long read_len;
unsigned long blocksize = session->remote.crypt->blocksize; unsigned long blocksize = session->remote.crypt->blocksize;
unsigned long packet_len, payload_len; unsigned long packet_len, payload_len;
@@ -327,24 +605,19 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
/* Safely ignored in CUSTOM cipher mode */ /* Safely ignored in CUSTOM cipher mode */
EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)session->remote.crypt_abstract; EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)session->remote.crypt_abstract;
/* Temporary Buffer */
block = LIBSSH2_ALLOC(session, 2 * (blocksize > session->remote.mac->mac_len ? blocksize : session->remote.mac->mac_len));
/* Note: If we add any cipher with a blocksize less than 6 we'll need to get more creative with this /* Note: If we add any cipher with a blocksize less than 6 we'll need to get more creative with this
* For now, all blocksize sizes are 8+ * For now, all blocksize sizes are 8+
*/ */
if (should_block) { if (should_block) {
read_len = libssh2_blocking_read(session, block, blocksize); read_len = libssh2_blocking_read(session, block, blocksize);
} else { } 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) { if (read_len <= 0) {
LIBSSH2_FREE(session, block);
return 0; return 0;
} }
read_len += libssh2_blocking_read(session, block + read_len, blocksize - read_len); read_len += libssh2_blocking_read(session, block + read_len, blocksize - read_len);
} }
if (read_len < blocksize) { if (read_len < blocksize) {
LIBSSH2_FREE(session, block);
return (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) ? 0 : -1; return (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) ? 0 : -1;
} }
@@ -354,7 +627,6 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
} else { } else {
if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) { if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) {
libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0); libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0);
LIBSSH2_FREE(session, block);
return -1; return -1;
} }
} }
@@ -364,6 +636,15 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
memcpy(tmp, block, 5); /* Use this for MAC later */ memcpy(tmp, block, 5); /* Use this for MAC later */
payload_len = packet_len - 1; /* padding_len(1) */ payload_len = packet_len - 1; /* padding_len(1) */
/* Sanity Check */
if ((payload_len > LIBSSH2_PACKET_MAXPAYLOAD) ||
((packet_len + 4) % blocksize)) {
/* If something goes horribly wrong during the decryption phase, just bailout and die gracefully */
session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
libssh2_error(session, LIBSSH2_ERROR_PROTO, "Fatal protocol error, invalid payload size", 0);
return -1;
}
s = payload = LIBSSH2_ALLOC(session, payload_len); s = payload = LIBSSH2_ALLOC(session, payload_len);
memcpy(s, block + 5, blocksize - 5); memcpy(s, block + 5, blocksize - 5);
s += blocksize - 5; s += blocksize - 5;
@@ -371,7 +652,6 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
while ((s - payload) < payload_len) { while ((s - payload) < payload_len) {
read_len = libssh2_blocking_read(session, block, blocksize); read_len = libssh2_blocking_read(session, block, blocksize);
if (read_len < blocksize) { if (read_len < blocksize) {
LIBSSH2_FREE(session, block);
LIBSSH2_FREE(session, payload); LIBSSH2_FREE(session, payload);
return -1; return -1;
} }
@@ -381,7 +661,6 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
} else { } else {
if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) { if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) {
libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0); libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0);
LIBSSH2_FREE(session, block);
LIBSSH2_FREE(session, payload); LIBSSH2_FREE(session, payload);
return -1; return -1;
} }
@@ -393,7 +672,6 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
read_len = libssh2_blocking_read(session, block, session->remote.mac->mac_len); read_len = libssh2_blocking_read(session, block, session->remote.mac->mac_len);
if (read_len < session->remote.mac->mac_len) { if (read_len < session->remote.mac->mac_len) {
LIBSSH2_FREE(session, block);
LIBSSH2_FREE(session, payload); LIBSSH2_FREE(session, payload);
return -1; return -1;
} }
@@ -402,13 +680,9 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
session->remote.mac->hash(session, block + session->remote.mac->mac_len, session->remote.seqno, tmp, 5, payload, payload_len, &session->remote.mac_abstract); session->remote.mac->hash(session, block + session->remote.mac->mac_len, session->remote.seqno, tmp, 5, payload, payload_len, &session->remote.mac_abstract);
macstate = (strncmp(block, block + session->remote.mac->mac_len, session->remote.mac->mac_len) == 0) ? LIBSSH2_MAC_CONFIRMED : LIBSSH2_MAC_INVALID; macstate = (strncmp(block, block + session->remote.mac->mac_len, session->remote.mac->mac_len) == 0) ? LIBSSH2_MAC_CONFIRMED : LIBSSH2_MAC_INVALID;
/* SMG */
if (macstate == LIBSSH2_MAC_INVALID) libssh2_error(session, -255, "EEEK an error!", 0);
session->remote.seqno++; session->remote.seqno++;
LIBSSH2_FREE(session, block);
/* Ignore padding */ /* Ignore padding */
payload_len -= padding_len; payload_len -= padding_len;
@@ -441,7 +715,6 @@ if (macstate == LIBSSH2_MAC_INVALID) libssh2_error(session, -255, "EEEK an error
payload = LIBSSH2_ALLOC(session, data_len); payload = LIBSSH2_ALLOC(session, data_len);
if (!payload) { if (!payload) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for copy of uncompressed data", 0); libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for copy of uncompressed data", 0);
LIBSSH2_FREE(session, block);
return -1; return -1;
} }
memcpy(payload, data, data_len); memcpy(payload, data, data_len);
@@ -463,7 +736,7 @@ if (macstate == LIBSSH2_MAC_INVALID) libssh2_error(session, -255, "EEEK an error
if (should_block) { if (should_block) {
buf_len = libssh2_blocking_read(session, buf, 5); buf_len = libssh2_blocking_read(session, buf, 5);
} else { } 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) { if (buf_len <= 0) {
return 0; return 0;
} }
@@ -483,8 +756,13 @@ if (macstate == LIBSSH2_MAC_INVALID) libssh2_error(session, -255, "EEEK an error
return (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) ? 0 : -1; return (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) ? 0 : -1;
} }
while (padding_length) { while (padding_length) {
int l;
/* Flush padding */ /* 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 */ /* MACs don't exist in non-encrypted mode */
@@ -576,14 +854,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) int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned long data_len)
{ {
unsigned long packet_length = data_len + 1; 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 */ /* At this point packet_length doesn't include the packet_len field itself */
unsigned long padding_length; unsigned long padding_length;
int free_data = 0; int free_data = 0;
unsigned char buf[246]; /* 6 byte header plus max padding size(240) */ unsigned char buf[246]; /* 6 byte header plus max padding size(240) */
int i; int i;
if (session->newkeys && if ((session->state & LIBSSH2_STATE_NEWKEYS) &&
strcmp(session->local.comp->name, "none")) { 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)) { if (session->local.comp->comp(session, 1, &data, &data_len, LIBSSH2_PACKET_MAXCOMP, &free_data, data, data_len, &session->local.comp_abstract)) {
@@ -591,7 +869,15 @@ int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned
} }
} }
#ifndef WIN32
fcntl(session->socket_fd, F_SETFL, 0); 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 */ 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); padding_length = block_size - ((packet_length + 4) % block_size);
if (padding_length < 4) { if (padding_length < 4) {
@@ -608,7 +894,7 @@ int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned
buf[5 + i] = '\0'; buf[5 + i] = '\0';
} }
if (session->newkeys) { if (session->state & LIBSSH2_STATE_NEWKEYS) {
/* Encryption is in effect */ /* Encryption is in effect */
unsigned char *encbuf, *s; unsigned char *encbuf, *s;
int ret; int ret;
@@ -629,7 +915,7 @@ int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned
/* Copy packet to encoding buffer */ /* Copy packet to encoding buffer */
memcpy(encbuf, buf, 5); memcpy(encbuf, buf, 5);
memcpy(encbuf + 5, data, data_len); 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) { if (free_data) {
LIBSSH2_FREE(session, data); LIBSSH2_FREE(session, data);
} }
@@ -650,7 +936,7 @@ int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned
session->local.seqno++; session->local.seqno++;
/* Send It */ /* 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 */ /* Cleanup environment */
LIBSSH2_FREE(session, encbuf); LIBSSH2_FREE(session, encbuf);

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net> /* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@@ -76,6 +76,8 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *pa
LIBSSH2_FREE(session, command); LIBSSH2_FREE(session, command);
return NULL; return NULL;
} }
/* Use blocking I/O for negotiation phase */
libssh2_channel_set_blocking(channel, 1);
/* Request SCP for the desired file */ /* Request SCP for the desired file */
if (libssh2_channel_process_startup(channel, "exec", sizeof("exec") - 1, command, command_len)) { if (libssh2_channel_process_startup(channel, "exec", sizeof("exec") - 1, command, command_len)) {
@@ -307,7 +309,8 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *pa
sb->st_size = size; sb->st_size = size;
sb->st_mode = mode; sb->st_mode = mode;
} }
/* Let the data BEGIN! */ /* Revert to non-blocking and let the data BEGIN! */
libssh2_channel_set_blocking(channel, 0);
return channel; return channel;
} }
@@ -344,12 +347,16 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char
/* Allocate a channel */ /* Allocate a channel */
if ((channel = libssh2_channel_open_session(session)) == NULL) { if ((channel = libssh2_channel_open_session(session)) == NULL) {
/* previous call set libssh2_session_last_error(), pass it through */
LIBSSH2_FREE(session, command); LIBSSH2_FREE(session, command);
return NULL; return NULL;
} }
/* Use blocking I/O for negotiation phase */
libssh2_channel_set_blocking(channel, 1);
/* Request SCP for the desired file */ /* Request SCP for the desired file */
if (libssh2_channel_process_startup(channel, "exec", sizeof("exec") - 1, command, command_len)) { 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_FREE(session, command);
libssh2_channel_free(channel); libssh2_channel_free(channel);
return NULL; return NULL;
@@ -400,7 +407,8 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char
return NULL; return NULL;
} }
/* Ready to send file */ /* Ready to start, switch to non-blocking and let calling app send file */
libssh2_channel_set_blocking(channel, 0);
return channel; return channel;
} }

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net> /* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@@ -37,7 +37,9 @@
#include "libssh2_priv.h" #include "libssh2_priv.h"
#include <errno.h> #include <errno.h>
#ifndef WIN32
#include <unistd.h> #include <unistd.h>
#endif
#include <stdlib.h> #include <stdlib.h>
/* {{{ libssh2_default_alloc /* {{{ libssh2_default_alloc
@@ -79,7 +81,7 @@ static int libssh2_banner_receive(LIBSSH2_SESSION *session)
char c = '\0'; char c = '\0';
int ret; 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)) { if ((ret < 0) && (ret != EAGAIN)) {
/* Some kinda error, but don't break for non-blocking issues */ /* Some kinda error, but don't break for non-blocking issues */
@@ -124,7 +126,38 @@ static int libssh2_banner_send(LIBSSH2_SESSION *session)
banner = session->local.banner; 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;
} }
/* }}} */ /* }}} */
@@ -160,6 +193,46 @@ LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(
} }
/* }}} */ /* }}} */
/* {{{ libssh2_session_callback_set
* Set (or reset) a callback function
* Returns the prior address
*/
LIBSSH2_API void* libssh2_session_callback_set(LIBSSH2_SESSION *session, int cbtype, void *callback)
{
void *oldcb;
switch (cbtype) {
case LIBSSH2_CALLBACK_IGNORE:
oldcb = session->ssh_msg_ignore;
session->ssh_msg_ignore = callback;
return oldcb;
break;
case LIBSSH2_CALLBACK_DEBUG:
oldcb = session->ssh_msg_debug;
session->ssh_msg_debug = callback;
return oldcb;
break;
case LIBSSH2_CALLBACK_DISCONNECT:
oldcb = session->ssh_msg_disconnect;
session->ssh_msg_disconnect = callback;
return oldcb;
break;
case LIBSSH2_CALLBACK_MACERROR:
oldcb = session->macerror;
session->macerror = callback;
return oldcb;
break;
case LIBSSH2_CALLBACK_X11:
oldcb = session->x11;
session->x11 = callback;
return oldcb;
break;
}
return NULL;
}
/* }}} */
/* {{{ proto libssh2_session_startup /* {{{ proto libssh2_session_startup
* session: LIBSSH2_SESSION struct allocated and owned by the calling program * session: LIBSSH2_SESSION struct allocated and owned by the calling program
* Returns: 0 on success, or non-zero on failure * Returns: 0 on success, or non-zero on failure
@@ -181,6 +254,11 @@ LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket)
session->socket_fd = socket; session->socket_fd = socket;
/* TODO: Liveness check */ /* 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)) { if (libssh2_banner_receive(session)) {
/* Unable to receive banner from remote */ /* Unable to receive banner from remote */
@@ -188,12 +266,6 @@ LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket)
return LIBSSH2_ERROR_BANNER_NONE; 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)) { if (libssh2_kex_exchange(session, 0)) {
libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE, "Unable to exchange encryption keys", 0); libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE, "Unable to exchange encryption keys", 0);
return LIBSSH2_ERROR_KEX_FAILURE; return LIBSSH2_ERROR_KEX_FAILURE;
@@ -249,7 +321,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 */ /* hostkey */
if (session->hostkey && session->hostkey->dtor) { if (session->hostkey && session->hostkey->dtor) {
session->hostkey->dtor(session, &session->server_hostkey_abstract); session->hostkey->dtor(session, &session->server_hostkey_abstract);
@@ -303,6 +379,7 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
} }
} }
/* Free banner(s) */
if (session->remote.banner) { if (session->remote.banner) {
LIBSSH2_FREE(session, session->remote.banner); LIBSSH2_FREE(session, session->remote.banner);
} }
@@ -310,6 +387,40 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
LIBSSH2_FREE(session, session->local.banner); LIBSSH2_FREE(session, session->local.banner);
} }
/* Free preference(s) */
if (session->kex_prefs) {
LIBSSH2_FREE(session, session->kex_prefs);
}
if (session->hostkey_prefs) {
LIBSSH2_FREE(session, session->hostkey_prefs);
}
if (session->local.crypt_prefs) {
LIBSSH2_FREE(session, session->local.crypt_prefs);
}
if (session->local.mac_prefs) {
LIBSSH2_FREE(session, session->local.mac_prefs);
}
if (session->local.comp_prefs) {
LIBSSH2_FREE(session, session->local.comp_prefs);
}
if (session->local.lang_prefs) {
LIBSSH2_FREE(session, session->local.lang_prefs);
}
if (session->remote.crypt_prefs) {
LIBSSH2_FREE(session, session->remote.crypt_prefs);
}
if (session->remote.mac_prefs) {
LIBSSH2_FREE(session, session->remote.mac_prefs);
}
if (session->remote.comp_prefs) {
LIBSSH2_FREE(session, session->remote.comp_prefs);
}
if (session->remote.lang_prefs) {
LIBSSH2_FREE(session, session->remote.lang_prefs);
}
/* Cleanup any remaining packets */ /* Cleanup any remaining packets */
while (session->packets.head) { while (session->packets.head) {
LIBSSH2_PACKET *tmp = session->packets.head; LIBSSH2_PACKET *tmp = session->packets.head;
@@ -322,19 +433,15 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
LIBSSH2_FREE(session, tmp); LIBSSH2_FREE(session, tmp);
} }
if (session->local.banner) {
LIBSSH2_FREE(session, session->local.banner);
}
LIBSSH2_FREE(session, session); LIBSSH2_FREE(session, session);
} }
/* }}} */ /* }}} */
/* {{{ libssh2_session_disconnect_ex /* {{{ libssh2_session_disconnect_ex
*/ */
LIBSSH2_API void libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, char *description, char *lang) LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, char *description, char *lang)
{ {
unsigned char *data; unsigned char *s, *data;
unsigned long data_len, descr_len = 0, lang_len = 0; unsigned long data_len, descr_len = 0, lang_len = 0;
if (description) { if (description) {
@@ -345,28 +452,167 @@ LIBSSH2_API void libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int rea
} }
data_len = descr_len + lang_len + 13; /* packet_type(1) + reason code(4) + descr_len(4) + lang_len(4) */ data_len = descr_len + lang_len + 13; /* packet_type(1) + reason code(4) + descr_len(4) + lang_len(4) */
data = LIBSSH2_ALLOC(session, data_len); s = data = LIBSSH2_ALLOC(session, data_len);
if (data) { if (!data) {
unsigned char *s = data; libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for disconnect packet", 0);
return -1;
*(s++) = SSH_MSG_DISCONNECT;
libssh2_htonu32(s, reason); s += 4;
libssh2_htonu32(s, descr_len); s += 4;
if (description) {
memcpy(s, description, descr_len);
s += descr_len;
}
libssh2_htonu32(s, lang_len); s += 4;
if (lang) {
memcpy(s, lang, lang_len);
s += lang_len;
}
libssh2_packet_write(session, data, data_len);
LIBSSH2_FREE(session, data);
} }
*(s++) = SSH_MSG_DISCONNECT;
libssh2_htonu32(s, reason); s += 4;
libssh2_htonu32(s, descr_len); s += 4;
if (description) {
memcpy(s, description, descr_len);
s += descr_len;
}
libssh2_htonu32(s, lang_len); s += 4;
if (lang) {
memcpy(s, lang, lang_len);
s += lang_len;
}
libssh2_packet_write(session, data, data_len);
LIBSSH2_FREE(session, data);
return 0;
}
/* }}} */
/* {{{ libssh2_session_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 char *libssh2_session_methods(LIBSSH2_SESSION *session, int method_type)
{
/* 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 (!method) {
libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE, "No method negotiated", 0);
return NULL;
}
return method->name;
}
/* }}} */
/* {{{ libssh2_session_abstract
* Retrieve a pointer to the abstract property
*/
LIBSSH2_API void **libssh2_session_abstract(LIBSSH2_SESSION *session)
{
return &session->abstract;
}
/* }}} */
/* {{{ libssh2_session_last_error
* Returns error code and populates an error string into errmsg
* If want_buf is non-zero then the string placed into errmsg must be freed by the calling program
* Otherwise it is assumed to be owned by libssh2
*/
LIBSSH2_API int libssh2_session_last_error(LIBSSH2_SESSION *session, char **errmsg, int *errmsg_len, int want_buf)
{
/* No error to report */
if (!session->err_code) {
if (errmsg) {
if (want_buf) {
*errmsg = LIBSSH2_ALLOC(session, 1);
if (*errmsg) {
**errmsg = 0;
}
} else {
*errmsg = "";
}
}
if (errmsg_len) {
*errmsg_len = 0;
}
return 0;
}
if (errmsg) {
char *serrmsg = session->err_msg ? session->err_msg : "";
int ownbuf = session->err_msg ? session->err_should_free : 0;
if (want_buf) {
if (ownbuf) {
/* Just give the calling program the buffer */
*errmsg = serrmsg;
session->err_should_free = 0;
} else {
/* Make a copy so the calling program can own it */
*errmsg = LIBSSH2_ALLOC(session, session->err_msglen + 1);
if (*errmsg) {
memcpy(*errmsg, session->err_msg, session->err_msglen);
(*errmsg)[session->err_msglen] = 0;
}
}
} else {
*errmsg = serrmsg;
}
}
if (errmsg_len) {
*errmsg_len = session->err_msglen;
}
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;
} }
/* }}} */ /* }}} */

1355
src/sftp.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net> /* Copyright (c) 2004, Sara Golemon <sarag@libssh2.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, * Redistribution and use in source and binary forms,
@@ -80,7 +80,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) { if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_SUCCESS, &data, &data_len, 1) == 0) {
/* Wow, who'dve thought... */ /* Wow, who'dve thought... */
LIBSSH2_FREE(session, data); LIBSSH2_FREE(session, data);
session->authenticated = 1; session->state |= LIBSSH2_STATE_AUTHENTICATED;
return NULL; return NULL;
} }
@@ -105,7 +105,7 @@ LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username
*/ */
LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session) LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session)
{ {
return session->authenticated; return session->state & LIBSSH2_STATE_AUTHENTICATED;
} }
/* }}} */ /* }}} */
@@ -151,7 +151,7 @@ LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, char *use
while (1) { while (1) {
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_SUCCESS, &data, &data_len, 1) == 0) { if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_SUCCESS, &data, &data_len, 1) == 0) {
LIBSSH2_FREE(session, data); LIBSSH2_FREE(session, data);
session->authenticated = 1; session->state |= LIBSSH2_STATE_AUTHENTICATED;
return 0; return 0;
} }
@@ -300,7 +300,7 @@ static int libssh2_file_read_privatekey(LIBSSH2_SESSION *session, LIBSSH2_HOSTKE
char *method, int method_len, char *method, int method_len,
char *privkeyfile, char *passphrase) char *privkeyfile, char *passphrase)
{ {
LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail = session->hostkey_prefs ? session->hostkey_prefs : libssh2_hostkey_methods(); LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail = libssh2_hostkey_methods();
*hostkey_method = NULL; *hostkey_method = NULL;
*hostkey_abstract = NULL; *hostkey_abstract = NULL;
@@ -389,7 +389,7 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
LIBSSH2_FREE(session, packet); LIBSSH2_FREE(session, packet);
LIBSSH2_FREE(session, method); LIBSSH2_FREE(session, method);
LIBSSH2_FREE(session, pubkeydata); LIBSSH2_FREE(session, pubkeydata);
session->authenticated = 1; session->state |= LIBSSH2_STATE_AUTHENTICATED;
return 0; return 0;
} }
@@ -485,7 +485,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) { if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_SUCCESS, &data, &data_len, 1) == 0) {
/* We are us and we've proved it. */ /* We are us and we've proved it. */
LIBSSH2_FREE(session, data); LIBSSH2_FREE(session, data);
session->authenticated = 1; session->state |= LIBSSH2_STATE_AUTHENTICATED;
return 0; return 0;
} }

View File

@@ -1,11 +1,17 @@
#include "libssh2.h" #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 <sys/types.h>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h>
#include <ctype.h> #include <ctype.h>
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
@@ -14,16 +20,26 @@ int main(int argc, char *argv[]) {
char *fingerprint; char *fingerprint;
LIBSSH2_SESSION *session; LIBSSH2_SESSION *session;
LIBSSH2_CHANNEL *channel; LIBSSH2_CHANNEL *channel;
#ifdef WIN32
WSADATA wsadata;
WSAStartup(WINSOCK_VERSION, &wsadata);
#endif
/* Ultra basic "connect to port 22 on localhost" /* Ultra basic "connect to port 22 on localhost"
* Your code is responsible for creating the socket establishing the connection * Your code is responsible for creating the socket establishing the connection
*/ */
sock = socket(AF_INET, SOCK_STREAM, 0); sock = socket(AF_INET, SOCK_STREAM, 0);
#ifndef WIN32
fcntl(sock, F_SETFL, 0); fcntl(sock, F_SETFL, 0);
#endif
sin.sin_family = AF_INET; sin.sin_family = AF_INET;
sin.sin_port = htons(22); sin.sin_port = htons(22);
sin.sin_addr.s_addr = htonl(0x7F000001); 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 /* Create a session instance and start it up
* This will trade welcome banners, exchange keys, and setup crypto, compression, and MAC layers * 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_disconnect(session, "Normal Shutdown, Thank you for playing");
libssh2_session_free(session); libssh2_session_free(session);
#ifdef WIN32
Sleep(1000);
closesocket(sock);
#else
sleep(1); sleep(1);
close(sock); close(sock);
#endif
printf("all done\n");
return 0; 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=\local\php\php_build\include
OPENSSLLIB=\local\php\php_build\lib
ZLIBINC=-DLIBSSH2_HAVE_ZLIB=1 /I\local\php\php_build\include
ZLIBLIB=\local\php\php_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