Compare commits
145 Commits
start
...
RELEASE.0.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d6cfa7c6b9 | ||
![]() |
ae17fbcd2c | ||
![]() |
0c53895bc0 | ||
![]() |
dc446eff08 | ||
![]() |
aa6e9c6eca | ||
![]() |
2e097c7760 | ||
![]() |
77bd3c1215 | ||
![]() |
0e5eb4d9c5 | ||
![]() |
8ee79a5118 | ||
![]() |
0ad861d74c | ||
![]() |
b6d13ebe8a | ||
![]() |
06e1136ea0 | ||
![]() |
2a6c49a73a | ||
![]() |
da653774aa | ||
![]() |
9203a62789 | ||
![]() |
6de7ed8a7b | ||
![]() |
8937980044 | ||
![]() |
cc7703092f | ||
![]() |
7502920c7f | ||
![]() |
ff6f2dbe52 | ||
![]() |
e5ee4a5be3 | ||
![]() |
30bb7db0d1 | ||
![]() |
8d90bbfc28 | ||
![]() |
e9b0710b4b | ||
![]() |
379e510c87 | ||
![]() |
ebfbd22e59 | ||
![]() |
9a0ba35457 | ||
![]() |
023c54d95d | ||
![]() |
ba2f21eb85 | ||
![]() |
3ea661a574 | ||
![]() |
30755999c5 | ||
![]() |
8e0e6d81dd | ||
![]() |
cba673de6f | ||
![]() |
11b27e52c3 | ||
![]() |
f289bcdd54 | ||
![]() |
66e7462f01 | ||
![]() |
ed88c32368 | ||
![]() |
83b95eb13e | ||
![]() |
ba420fc7bf | ||
![]() |
ae9ad1ef6f | ||
![]() |
d3f854c21b | ||
![]() |
5d9c0d50f3 | ||
![]() |
35a3e7a6c0 | ||
![]() |
15b8489046 | ||
![]() |
dce388e9c5 | ||
![]() |
0138e36352 | ||
![]() |
d6039f39e4 | ||
![]() |
0e0ed2aff4 | ||
![]() |
7c64e21df6 | ||
![]() |
c67bb667aa | ||
![]() |
141ac5b856 | ||
![]() |
9f64f34dfe | ||
![]() |
a1b87a952c | ||
![]() |
7db9aeecf8 | ||
![]() |
99e5547442 | ||
![]() |
ef7496b29a | ||
![]() |
37c55becdc | ||
![]() |
47b96a9771 | ||
![]() |
0a9a5ffc22 | ||
![]() |
c6e5188fb4 | ||
![]() |
fe7ea0df58 | ||
![]() |
500169bf97 | ||
![]() |
10a0c20eae | ||
![]() |
2427c1b803 | ||
![]() |
159120f844 | ||
![]() |
fc1563a41d | ||
![]() |
c6bbe0d42f | ||
![]() |
a05bf84ecf | ||
![]() |
2c5c54e999 | ||
![]() |
5f2864c0b4 | ||
![]() |
4675d1242b | ||
![]() |
b59f2ccc1b | ||
![]() |
b25446d0a5 | ||
![]() |
064c6cde3a | ||
![]() |
2c5a8480b0 | ||
![]() |
87d61a39e8 | ||
![]() |
0e878271db | ||
![]() |
bc16411dd3 | ||
![]() |
096ef86627 | ||
![]() |
2b414db02e | ||
![]() |
5f7470700e | ||
![]() |
bfc2f5039e | ||
![]() |
a3735795dd | ||
![]() |
a891971a63 | ||
![]() |
d4677dba5b | ||
![]() |
d1ae5a501f | ||
![]() |
72c4c38e37 | ||
![]() |
fe2513a18b | ||
![]() |
ee03669517 | ||
![]() |
22c105332d | ||
![]() |
c9e8f3a1a0 | ||
![]() |
54b852dfc9 | ||
![]() |
308d59910f | ||
![]() |
ecd83df6a7 | ||
![]() |
4191a8c56c | ||
![]() |
c5acc8a901 | ||
![]() |
a119685410 | ||
![]() |
dc4bb1af96 | ||
![]() |
8fe47a609a | ||
![]() |
c070bdacc7 | ||
![]() |
a9af84c51d | ||
![]() |
dfb3b8f0fd | ||
![]() |
c006dd4350 | ||
![]() |
4324a1a1d1 | ||
![]() |
cf8ca63ea0 | ||
![]() |
d1b33840bf | ||
![]() |
eef99ca106 | ||
![]() |
d86bcab2d2 | ||
![]() |
2e02ad041a | ||
![]() |
596b62c027 | ||
![]() |
143c6bf97f | ||
![]() |
371f5de682 | ||
![]() |
d2d8f8ad0b | ||
![]() |
a1e649b507 | ||
![]() |
99795a165e | ||
![]() |
6f13a93be9 | ||
![]() |
3f24fb005e | ||
![]() |
f11c657a10 | ||
![]() |
d4efdee802 | ||
![]() |
aa8b8afe4f | ||
![]() |
525a181037 | ||
![]() |
9977cee99b | ||
![]() |
3a744117d6 | ||
![]() |
d974137db9 | ||
![]() |
66f913e53a | ||
![]() |
912e9ca713 | ||
![]() |
6fdf9c9c06 | ||
![]() |
26e7e66ecf | ||
![]() |
a0cd3ed3dc | ||
![]() |
3614bdac21 | ||
![]() |
14af2e3952 | ||
![]() |
620a685af2 | ||
![]() |
4ab2f2ab73 | ||
![]() |
d2ca405d0f | ||
![]() |
566bea77ea | ||
![]() |
165837c085 | ||
![]() |
7035d475eb | ||
![]() |
794f01acc1 | ||
![]() |
2b670d36ca | ||
![]() |
7a153310f7 | ||
![]() |
013f64698c | ||
![]() |
54290ae77d | ||
![]() |
433a94606a | ||
![]() |
82e9e2ba0f | ||
![]() |
2f41af6cdf |
9
.cvsignore
Normal file
9
.cvsignore
Normal file
@@ -0,0 +1,9 @@
|
||||
*.lib
|
||||
*.pdb
|
||||
*.dll
|
||||
*.exe
|
||||
*.obj
|
||||
.*.swp
|
||||
Debug
|
||||
Release
|
||||
*.exp
|
60
INSTALL
Normal file
60
INSTALL
Normal file
@@ -0,0 +1,60 @@
|
||||
Installing libssh2
|
||||
==================
|
||||
|
||||
* Untar this tarball (which, if you're reading this, you've already done)
|
||||
|
||||
* 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
|
||||
|
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
||||
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
|
32
Makefile.in
32
Makefile.in
@@ -10,7 +10,7 @@ CC = @CC@
|
||||
CFLAGS = -c @CFLAGS@ -Iinclude/ -Wall -g
|
||||
LIBS = -lssh2 -Lsrc/
|
||||
INSTALL = @INSTALL@
|
||||
VERSION=0.1-dev
|
||||
VERSION=@PACKAGE_VERSION@
|
||||
DISTLIB=libssh2-$(VERSION)
|
||||
|
||||
all:
|
||||
@@ -21,13 +21,14 @@ all:
|
||||
$(CC) -o ssh2_sample.o ssh2_sample.c $(CFLAGS)
|
||||
$(CC) -o ssh2_sample ssh2_sample.o $(LIBS)
|
||||
install:
|
||||
$(top_srcdir)/mkinstalldirs $(incldir)
|
||||
$(top_srcdir)/mkinstalldirs $(libdir)
|
||||
$(top_srcdir)/mkinstalldirs $(DESTDIR)$(incldir)
|
||||
$(top_srcdir)/mkinstalldirs $(DESTDIR)$(libdir)
|
||||
@for dir in ${subdirs}; do \
|
||||
(cd $$dir && $(MAKE) install) \
|
||||
|| case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
|
||||
done && test -z "$$fail"
|
||||
$(INSTALL) -m 644 include/libssh2.h $(incldir)/
|
||||
$(INSTALL) -m 644 include/libssh2.h $(DESTDIR)$(incldir)/
|
||||
$(INSTALL) -m 644 include/libssh2_sftp.h $(DESTDIR)$(incldir)/
|
||||
clean:
|
||||
@for dir in ${subdirs}; do \
|
||||
(cd $$dir && $(MAKE) clean) \
|
||||
@@ -40,9 +41,24 @@ dist:
|
||||
rm -f $(DISTLIB)
|
||||
ln -s . $(DISTLIB)
|
||||
tar -zcf $(DISTLIB).tar.gz \
|
||||
$(DISTLIB)/configure.in $(DISTLIB)/configure $(DISTLIB)/Makefile.in $(DISTLIB)/ssh2_sample.c \
|
||||
$(DISTLIB)/LICENSE $(DISTLIB)/README $(DISTLIB)/TODO \
|
||||
$(DISTLIB)/mkinstalldirs $(DISTLIB)/install-sh \
|
||||
$(DISTLIB)/configure $(DISTLIB)/Makefile.in $(DISTLIB)/ssh2_sample.c \
|
||||
$(DISTLIB)/LICENSE $(DISTLIB)/README $(DISTLIB)/INSTALL \
|
||||
$(DISTLIB)/mkinstalldirs $(DISTLIB)/install-sh $(DISTLIB)/config.sub $(DISTLIB)/config.guess \
|
||||
$(DISTLIB)/src/*.c $(DISTLIB)/src/Makefile.in \
|
||||
$(DISTLIB)/include/libssh2.h $(DISTLIB)/include/libssh2_priv.h $(DISTLIB)/include/libssh2_config.h.in
|
||||
$(DISTLIB)/include/libssh2.h $(DISTLIB)/include/libssh2_priv.h $(DISTLIB)/include/libssh2_sftp.h \
|
||||
$(DISTLIB)/include/libssh2_config.h.in \
|
||||
$(DISTLIB)/win32/config.mk $(DISTLIB)/win32/libssh2_config.h $(DISTLIB)/win32/rules.mk \
|
||||
$(DISTLIB)/win32/libssh2.dsp $(DISTLIB)/win32/libssh2.dsw $(DISTLIB)/win32/ssh2_sample.dsp
|
||||
rm -f $(DISTLIB)
|
||||
dist_nmake:
|
||||
autoheader
|
||||
autoconf
|
||||
rm -f $(DISTLIB)
|
||||
ln -s . $(DISTLIB)
|
||||
tar -zcf $(DISTLIB)-win32.tar.gz \
|
||||
$(DISTLIB)/NMakefile $(DISTLIB)/ssh2_sample.c $(DISTLIB)/src/*.c \
|
||||
$(DISTLIB)/LICENSE $(DISTLIB)/README $(DISTLIB)/TODO $(DISTLIB)/INSTALL \
|
||||
$(DISTLIB)/include/libssh2.h $(DISTLIB)/include/libssh2_priv.h $(DISTLIB)/include/libssh2_sftp.h \
|
||||
$(DISTLIB)/win32/config.mk $(DISTLIB)/win32/libssh2_config.h $(DISTLIB)/win32/rules.mk
|
||||
rm -f $(DISTLIB)
|
||||
|
||||
|
16
NMakefile
Normal file
16
NMakefile
Normal 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)
|
||||
|
||||
|
180
README
180
README
@@ -1,8 +1,184 @@
|
||||
libssh2 - SSH2 library
|
||||
======================
|
||||
|
||||
Version 0.1-dev
|
||||
---------------
|
||||
Version 0.11
|
||||
------------
|
||||
|
||||
Added libssh2_chnnale_get_exit_status() -- Mikhail
|
||||
|
||||
Added libssh2_channel_wait_closed() -- Mikhail
|
||||
|
||||
Added libssh2_userauth_keyboard_interactive_ex() -- Mikhail
|
||||
|
||||
Added libssh2_channel_receive_window_adjust() to be able to increase the size of the receive window.
|
||||
|
||||
Added queueing for small window_adjust packets to avoid unnecessary packet conversation.
|
||||
|
||||
Fixed libssh2_sftp_rename_ex() to only send flags parameter if version >= 5 negotiated
|
||||
(not currently possible, but will be and might as well keep the API consistent).
|
||||
|
||||
Version 0.10
|
||||
------------
|
||||
|
||||
Added developer debugging hooks. See --enable-debug-* options to ./configure
|
||||
|
||||
Ignore extended data in the SFTP layer. With no other mechanism to deal with that data it'd just fill up and get stuck.
|
||||
|
||||
(Re)Fixed channel_write() to provide an opportunity for window space to become available again.
|
||||
|
||||
(Re)Fixed SFTP INIT to send the correct SFTP packet length.
|
||||
|
||||
Fixed segfault when client and host can't agree on a hostkey/crypt/mac/comp method. (Thanks puudeli)
|
||||
|
||||
Fixed major issue with sftp packet buffering mechanism. Using wrong blocking semantics. (No puudeli, YOU the man)
|
||||
|
||||
Reduced busy-looping of libssh2_sftp_packet_requirev.
|
||||
|
||||
Version 0.9
|
||||
-----------
|
||||
|
||||
Changed blocking_read to only block as much as necessary and not an arbitrary length of time. (Thanks Felix)
|
||||
|
||||
Fixed SFTP INIT/VERSION to exclude request_id and send correct maximum version number.
|
||||
|
||||
Fixed SFTP to be properly BC with version 1 and 2 servers.
|
||||
|
||||
Fixed libssh2_poll() to recognized closed sessions/channels.
|
||||
|
||||
Fixed libssh2_channel_write_ex() to fully block when set to blocking mode. Return actual bytes written as well. (Thanks deadem)
|
||||
|
||||
Added tests for -lm and -lsocket and add them when necessary.
|
||||
|
||||
Added libssh2_channel_window_read_ex() and libssh2_channel_window_write_ex()
|
||||
for examining the ssh transport windowing states.
|
||||
|
||||
Version 0.8
|
||||
-----------
|
||||
|
||||
Fix potential segfault in compression/decompression.
|
||||
|
||||
Fix compatability with older versions of OpenSSL
|
||||
|
||||
Swapped order of none,zlib compression modes to prefer no compression by default.
|
||||
|
||||
Added sys/uio.h for platforms (FBSD) which need it in order to define struct iovec.
|
||||
|
||||
Added libssh2_poll() to check status of sockets/channels/listeners.
|
||||
|
||||
Removed unnecessary inclusion of stdio.h (holdover from debugging)
|
||||
|
||||
Version 0.7
|
||||
-----------
|
||||
|
||||
Added libssh2_userauth_hostbased_fromfile_ex() for authenticating from hostkey.
|
||||
|
||||
Added configure recognition for MacOSX (Darwin) (Thanks Gabe)
|
||||
|
||||
Fixed extended data identification in libssh2_channel_read().
|
||||
|
||||
Fixed window adjust code. Hadn't acknowledged adjustments correctly.
|
||||
|
||||
Removed initial_window_size requirement for sending window adjust packet.
|
||||
|
||||
|
||||
Version 0.6
|
||||
-----------
|
||||
|
||||
Added LIBSSH2_FLAG_SIGPIPE to enable/disable SIGPIPE generated by send()/recv() calls. Default off.
|
||||
|
||||
Added libssh2_session_flag() to set optional session flags.
|
||||
|
||||
Collapsed exchanging_keys/newkeys/authenticated flags into single state attribute.
|
||||
|
||||
Fix zlib compression issue when internal buffer state misses partial sync.
|
||||
|
||||
Fix segfault when libssh2_session_methods() is called prior to session_startup().
|
||||
|
||||
Fixed client to server channel windowing. Pervent send queue overruns.
|
||||
|
||||
Swapped banner send/receive order (send first, then wait for response).
|
||||
|
||||
Version 0.5
|
||||
-----------
|
||||
|
||||
*** BC Break ***
|
||||
Reimplemented libssh2_session_methods() to match libssh2_session_method_pref() style
|
||||
|
||||
Fixed libssh2_attr2bin() (effects any setstat style call).
|
||||
|
||||
Fixed authenticating with encrypted private key.
|
||||
|
||||
Fixed authenticating via ssh-dss public key.
|
||||
|
||||
Fixed KEX_INIT cookie and packet padding to use actual random data
|
||||
|
||||
Added DESTDIR support to makefiles (Adam Go<47><6F>biowski -- I hope that character set translates right)
|
||||
|
||||
Added libssh2_channel_forward_listen_ex(), libssh2_channel_forward_cancel(), and libssh2_channel_forward_accept().
|
||||
|
||||
Added ./configure option '--disable-gex-new' to allow using the older group-exchange format
|
||||
|
||||
Added MAC methods hmac-md5 and hmac-md5-96.
|
||||
|
||||
Version 0.4
|
||||
-----------
|
||||
|
||||
Fixed crash when trying to free sftp_dirhandle data from a filehandle struct.
|
||||
|
||||
Fixed leak in sftp_open_ex(), handle->handle not freed in handle_close().
|
||||
|
||||
Fixed leak in sftp_symlink_ex(), result for READLINK and REALPATH not freed unless there was an error.
|
||||
|
||||
Added libssh2_banner_set(), specify an arbitrary banner to send on introduction.
|
||||
|
||||
Version 0.3
|
||||
-----------
|
||||
|
||||
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:
|
||||
KEX methods: diffie-hellman-group14-sha1, diffie-hellman-group-exchange-sha1, diffie-hellman-group1-sha1
|
||||
|
4
TODO
4
TODO
@@ -1,4 +0,0 @@
|
||||
* More Crypt Methods
|
||||
* hmac-md5, hmac-md5-96
|
||||
* SFTP support
|
||||
* Review callbacks
|
1415
config.guess
vendored
Executable file
1415
config.guess
vendored
Executable file
File diff suppressed because it is too large
Load Diff
1510
config.sub
vendored
Executable file
1510
config.sub
vendored
Executable file
File diff suppressed because it is too large
Load Diff
78
configure.in
78
configure.in
@@ -1,13 +1,37 @@
|
||||
# AC_PREREQ(2.57)
|
||||
AC_INIT(libssh2, 0.1 , pollita@php.net)
|
||||
AC_INIT(libssh2,0.11,sarag@libssh2.org)
|
||||
AC_CONFIG_SRCDIR([src])
|
||||
AC_CONFIG_HEADER([include/libssh2_config.h])
|
||||
|
||||
SHLIB_SUFFIX_NAME="so"
|
||||
SHLIB_LDFLAGS="-shared"
|
||||
# Check for the OS.
|
||||
AC_CANONICAL_HOST
|
||||
case "$host" in
|
||||
*-cygwin)
|
||||
SHLIB_SUFFIX_NAME="dll"
|
||||
SHLIB_LDFLAGS="-shared"
|
||||
CFLAGS="$CFLAGS -DLIBSSH2_WIN32"
|
||||
;;
|
||||
*darwin*)
|
||||
SHLIB_SUFFIX_NAME="dylib"
|
||||
SHLIB_LDFLAGS="-dynamiclib -flat_namespace"
|
||||
CFLAGS="$CFLAGS -DLIBSSH2_DARWIN"
|
||||
;;
|
||||
*)
|
||||
SHLIB_SUFFIX_NAME="so"
|
||||
SHLIB_LDFLAGS="-shared"
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_CHECK_LIB(socket, socket, [
|
||||
SHLIB_LDFLAGS="$SHLIB_LDFLAGS -lsocket"
|
||||
LIBS="$LIBS -lsocket"
|
||||
])
|
||||
AC_CHECK_LIB(m, ceil, [ SHLIB_LDFLAGS="$SHLIB_LDFLAGS -lm" ])
|
||||
|
||||
|
||||
AC_SUBST(SHLIB_SUFFIX_NAME)
|
||||
AC_SUBST(SHLIB_LDFLAGS)
|
||||
AC_SUBST(LIBS)
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
@@ -138,9 +162,55 @@ AC_ARG_ENABLE(mac-none,
|
||||
AC_HELP_STRING([--enable-mac-none],[Permit "none" MAC -- NOT RECOMMENDED]),
|
||||
[AC_DEFINE(LIBSSH2_MAC_NONE, 1, [Enable "none" MAC -- NOT RECOMMENDED])])
|
||||
|
||||
AC_ARG_ENABLE(gex-new,
|
||||
AC_HELP_STRING([--disable-gex-new],[Disable "new" diffie-hellman-group-exchange-sha1 method]),
|
||||
[GEX_NEW=$enableval])
|
||||
if test "$GEX_NEW" != "no"; then
|
||||
AC_DEFINE(LIBSSH2_DH_GEX_NEW, 1, [Enable newer diffie-hellman-group-exchange-sha1 syntax])
|
||||
fi
|
||||
|
||||
#
|
||||
# Optional debugging -- Meant for developer maintenance only
|
||||
# When enabled, the relevant debugging information will be written on stderr
|
||||
#
|
||||
AC_ARG_ENABLE(debug-transport,
|
||||
AC_HELP_STRING([--enable-debug-transport],[Output transport layer debugging info to stderr]),
|
||||
[AC_DEFINE(LIBSSH2_DEBUG_TRANSPORT, 1, [Output transport layer debugging info to stderr])])
|
||||
AC_ARG_ENABLE(debug-kex,
|
||||
AC_HELP_STRING([--enable-debug-kex],[Output Key Exchange debugging info to stderr]),
|
||||
[AC_DEFINE(LIBSSH2_DEBUG_KEX, 1, [Output Key Exchange debugging info to stderr])])
|
||||
AC_ARG_ENABLE(debug-userauth,
|
||||
AC_HELP_STRING([--enable-debug-userauth],[Output userauth debugging info to stderr]),
|
||||
[AC_DEFINE(LIBSSH2_DEBUG_USERAUTH, 1, [Output userauth layer debugging info to stderr])])
|
||||
AC_ARG_ENABLE(debug-channel,
|
||||
AC_HELP_STRING([--enable-debug-connection],[Output connection layer debugging info to stderr]),
|
||||
[AC_DEFINE(LIBSSH2_DEBUG_CONNECTION, 1, [Output connection layer debugging info to stderr])])
|
||||
AC_ARG_ENABLE(debug-scp,
|
||||
AC_HELP_STRING([--enable-debug-scp],[Output scp subsystem debugging info to stderr]),
|
||||
[AC_DEFINE(LIBSSH2_DEBUG_SCP, 1, [Output scp subsystem debugging info to stderr])])
|
||||
AC_ARG_ENABLE(debug-sftp,
|
||||
AC_HELP_STRING([--enable-debug-sftp],[Output sftp subsystem debugging info to stderr]),
|
||||
[AC_DEFINE(LIBSSH2_DEBUG_SFTP, 1, [Output sftp subsystem debugging info to stderr])])
|
||||
AC_ARG_ENABLE(debug-errors,
|
||||
AC_HELP_STRING([--enable-debug-errors],[Output failure events to stderr]),
|
||||
[AC_DEFINE(LIBSSH2_DEBUG_ERRORS, 1, [Output failure events to stderr])])
|
||||
AC_ARG_ENABLE(debug-all,
|
||||
AC_HELP_STRING([--enable-debug-all],[Output debugging info for all layers to stderr]),
|
||||
[
|
||||
AC_DEFINE(LIBSSH2_DEBUG_TRANSPORT, 1, [Output transport layer debugging info to stderr])
|
||||
AC_DEFINE(LIBSSH2_DEBUG_KEX, 1, [Output Key Exchange debugging info to stderr])
|
||||
AC_DEFINE(LIBSSH2_DEBUG_USERAUTH, 1, [Output userauth layer debugging info to stderr])
|
||||
AC_DEFINE(LIBSSH2_DEBUG_CONNECTION, 1, [Output connection layer debugging info to stderr])
|
||||
AC_DEFINE(LIBSSH2_DEBUG_SCP, 1, [Output scp subsystem debugging info to stderr])
|
||||
AC_DEFINE(LIBSSH2_DEBUG_SFTP, 1, [Output sftp subsystem debugging info to stderr])
|
||||
AC_DEFINE(LIBSSH2_DEBUG_ERRORS, 1, [Output failure events to stderr])
|
||||
])
|
||||
|
||||
|
||||
# Checks for header files.
|
||||
# AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS([errno.h fcntl.h stdio.h stdlib.h unistd.h])
|
||||
AC_CHECK_HEADERS([errno.h fcntl.h stdio.h stdlib.h unistd.h sys/uio.h sys/select.h])
|
||||
AC_CHECK_FUNCS(poll gettimeofday select)
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
||||
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -38,11 +38,41 @@
|
||||
#ifndef LIBSSH2_H
|
||||
#define LIBSSH2_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define LIBSSH2_VERSION "0.1dev"
|
||||
/* Allow alternate API prefix from CFLAGS or calling app */
|
||||
#ifndef LIBSSH2_API
|
||||
# ifdef LIBSSH2_WIN32
|
||||
# ifdef LIBSSH2_LIBRARY
|
||||
# define LIBSSH2_API __declspec(dllexport)
|
||||
# else
|
||||
# define LIBSSH2_API __declspec(dllimport)
|
||||
# endif /* LIBSSH2_LIBRARY */
|
||||
# else /* !LIBSSH2_WIN32 */
|
||||
# define LIBSSH2_API
|
||||
# endif /* LIBSSH2_WIN32 */
|
||||
#endif /* LIBSSH2_API */
|
||||
|
||||
#if defined(LIBSSH2_DARWIN) || (defined(LIBSSH2_WIN32) && !defined(_MSC_VER))
|
||||
# include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#if defined(LIBSSH2_WIN32) && _MSC_VER < 1300
|
||||
typedef unsigned __int64 libssh2_uint64_t;
|
||||
typedef __int64 libssh2_int64_t;
|
||||
#else
|
||||
typedef unsigned long long libssh2_uint64_t;
|
||||
typedef long long libssh2_int64_t;
|
||||
#endif
|
||||
|
||||
#define LIBSSH2_VERSION "0.11"
|
||||
#define LIBSSH2_APINO 200507041839
|
||||
|
||||
/* Part of every banner, user specified or not */
|
||||
#define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION
|
||||
@@ -51,9 +81,6 @@
|
||||
#define LIBSSH2_SSH_DEFAULT_BANNER LIBSSH2_SSH_BANNER
|
||||
#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 */
|
||||
#define LIBSSH2_DH_GEX_MINGROUP 1024
|
||||
#define LIBSSH2_DH_GEX_OPTGROUP 1536
|
||||
@@ -71,32 +98,105 @@
|
||||
#define LIBSSH2_SOCKET_POLL_MAXLOOPS 120
|
||||
|
||||
/* 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 */
|
||||
#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 */
|
||||
#define LIBSSH2_ALLOC_FUNC(name) void *name(size_t count, void **abstract)
|
||||
#define LIBSSH2_REALLOC_FUNC(name) void *name(void *ptr, size_t count, void **abstract)
|
||||
#define LIBSSH2_FREE_FUNC(name) void name(void *ptr, void **abstract)
|
||||
|
||||
typedef struct _LIBSSH2_USERAUTH_KBDINT_PROMPT
|
||||
{
|
||||
char* text;
|
||||
unsigned int length;
|
||||
unsigned char echo;
|
||||
} LIBSSH2_USERAUTH_KBDINT_PROMPT;
|
||||
|
||||
typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE
|
||||
{
|
||||
char* text;
|
||||
unsigned int length;
|
||||
} LIBSSH2_USERAUTH_KBDINT_RESPONSE;
|
||||
|
||||
/* 'keyboard-interactive' authentication callback */
|
||||
#define LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC(name_) void name_(const char* name, int name_len, const char* instruction, int instruction_len, int num_prompts, const LIBSSH2_USERAUTH_KBDINT_PROMPT* prompts, LIBSSH2_USERAUTH_KBDINT_RESPONSE* responses, void **abstract)
|
||||
|
||||
/* Callbacks for special SSH packets */
|
||||
#define LIBSSH2_IGNORE_FUNC(name) void name(LIBSSH2_SESSION *session, const char *message, int message_len, void **abstract)
|
||||
#define LIBSSH2_DEBUG_FUNC(name) void name(LIBSSH2_SESSION *session, int always_display, 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_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_CHANNEL LIBSSH2_CHANNEL;
|
||||
typedef struct _LIBSSH2_LISTENER LIBSSH2_LISTENER;
|
||||
|
||||
#ifdef WIN_32
|
||||
#define LIBSSH2_API __declspec(dllexport)
|
||||
#else
|
||||
#define LIBSSH2_API
|
||||
#endif
|
||||
typedef struct _LIBSSH2_POLLFD {
|
||||
unsigned char type; /* LIBSSH2_POLLFD_* below */
|
||||
|
||||
union {
|
||||
int socket; /* File descriptors -- examined with system select() call */
|
||||
LIBSSH2_CHANNEL *channel; /* Examined by checking internal state */
|
||||
LIBSSH2_LISTENER *listener; /* Read polls only -- are inbound connections waiting to be accepted? */
|
||||
} fd;
|
||||
|
||||
unsigned long events; /* Requested Events */
|
||||
unsigned long revents; /* Returned Events */
|
||||
} LIBSSH2_POLLFD;
|
||||
|
||||
/* Poll FD Descriptor Types */
|
||||
#define LIBSSH2_POLLFD_SOCKET 1
|
||||
#define LIBSSH2_POLLFD_CHANNEL 2
|
||||
#define LIBSSH2_POLLFD_LISTENER 3
|
||||
|
||||
/* Note: Win32 Doesn't actually have a poll() implementation, so some of these values are faked with select() data */
|
||||
/* Poll FD events/revents -- Match sys/poll.h where possible */
|
||||
#define LIBSSH2_POLLFD_POLLIN 0x0001 /* Data available to be read or connection available -- All */
|
||||
#define LIBSSH2_POLLFD_POLLPRI 0x0002 /* Priority data available to be read -- Socket only */
|
||||
#define LIBSSH2_POLLFD_POLLEXT 0x0002 /* Extended data available to be read -- Channel only */
|
||||
#define LIBSSH2_POLLFD_POLLOUT 0x0004 /* Can may be written -- Socket/Channel */
|
||||
/* revents only */
|
||||
#define LIBSSH2_POLLFD_POLLERR 0x0008 /* Error Condition -- Socket */
|
||||
#define LIBSSH2_POLLFD_POLLHUP 0x0010 /* HangUp/EOF -- Socket */
|
||||
#define LIBSSH2_POLLFD_SESSION_CLOSED 0x0010 /* Session Disconnect */
|
||||
#define LIBSSH2_POLLFD_POLLNVAL 0x0020 /* Invalid request -- Socket Only */
|
||||
#define LIBSSH2_POLLFD_POLLEX 0x0040 /* Exception Condition -- Socket/Win32 */
|
||||
#define LIBSSH2_POLLFD_CHANNEL_CLOSED 0x0080 /* Channel Disconnect */
|
||||
#define LIBSSH2_POLLFD_LISTENER_CLOSED 0x0080 /* Listener Disconnect */
|
||||
|
||||
/* Hash Types */
|
||||
#define LIBSSH2_HOSTKEY_HASH_MD5 1
|
||||
#define LIBSSH2_HOSTKEY_HASH_SHA1 2
|
||||
|
||||
@@ -148,38 +248,89 @@ typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL;
|
||||
#define LIBSSH2_ERROR_SCP_PROTOCOL -28
|
||||
#define LIBSSH2_ERROR_ZLIB -29
|
||||
#define LIBSSH2_ERROR_SOCKET_TIMEOUT -30
|
||||
#define LIBSSH2_ERROR_SFTP_PROTOCOL -31
|
||||
#define LIBSSH2_ERROR_REQUEST_DENIED -32
|
||||
#define LIBSSH2_ERROR_METHOD_NOT_SUPPORTED -33
|
||||
#define LIBSSH2_ERROR_INVAL -34
|
||||
#define LIBSSH2_ERROR_INVALID_POLL_TYPE -35
|
||||
|
||||
/* Session API */
|
||||
LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)), LIBSSH2_FREE_FUNC((*my_free)), LIBSSH2_REALLOC_FUNC((*my_realloc)), void *abstract);
|
||||
#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, const char *banner);
|
||||
|
||||
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, const char *description, const char *lang);
|
||||
#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 char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type);
|
||||
LIBSSH2_API const char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type);
|
||||
|
||||
LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method_type, const char *prefs);
|
||||
LIBSSH2_API const char *libssh2_session_methods(LIBSSH2_SESSION *session, int method_type);
|
||||
LIBSSH2_API int libssh2_session_last_error(LIBSSH2_SESSION *session, char **errmsg, int *errmsg_len, int want_buf);
|
||||
|
||||
LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag, int value);
|
||||
|
||||
/* Userauth API */
|
||||
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username, int username_len);
|
||||
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, const char *username, int username_len);
|
||||
LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session);
|
||||
LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, char *username, int username_len, char *password, int password_len, LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)));
|
||||
LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *username, int username_len, const char *password, int password_len, LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)));
|
||||
#define libssh2_userauth_password(session, username, password) libssh2_userauth_password_ex((session), (username), strlen(username), (password), strlen(password), NULL)
|
||||
|
||||
LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, char *username, int username_len,
|
||||
char *publickey, char *privatekey,
|
||||
char *passphrase);
|
||||
LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, const char *username, int username_len,
|
||||
const char *publickey, const char *privatekey,
|
||||
const char *passphrase);
|
||||
#define libssh2_userauth_publickey_fromfile(session, username, publickey, privatekey, passphrase) \
|
||||
libssh2_userauth_publickey_fromfile_ex((session), (username), strlen(username), (publickey), (privatekey), (passphrase))
|
||||
LIBSSH2_API int libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, const char *username, int username_len,
|
||||
const char *publickey, const char *privatekey,
|
||||
const char *passphrase,
|
||||
const char *hostname, int hostname_len,
|
||||
const char *local_username, int local_username_len);
|
||||
#define libssh2_userauth_hostbased_fromfile(session, username, publickey, privatekey, passphrase, hostname) \
|
||||
libssh2_userauth_hostbased_fromfile_ex((session), (username), strlen(username), (publickey), (privatekey), (passphrase), (hostname), strlen(hostname), (username), strlen(username))
|
||||
|
||||
/*
|
||||
* response_callback is provided with filled by library prompts array,
|
||||
* but client must allocate and fill individual responses. Responses
|
||||
* array is already allocated. Responses data will be freed by libssh2
|
||||
* after callback return, but before subsequent callback invokation.
|
||||
*/
|
||||
LIBSSH2_API int libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION* session, const char *username, int username_len,
|
||||
LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)));
|
||||
#define libssh2_userauth_keyboard_interactive(session, username, response_callback) \
|
||||
libssh2_userauth_keyboard_interactive_ex((session), (username), strlen(username), (response_callback))
|
||||
|
||||
LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout);
|
||||
|
||||
/* Channel API */
|
||||
#define LIBSSH2_CHANNEL_WINDOW_DEFAULT 65536
|
||||
#define LIBSSH2_CHANNEL_PACKET_DEFAULT 16384
|
||||
#define LIBSSH2_CHANNEL_MINADJUST 1024
|
||||
|
||||
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);
|
||||
/* 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, const char *channel_type, int channel_type_len, int window_size, int packet_size, const char *message, int message_len);
|
||||
#define libssh2_channel_open_session(session) libssh2_channel_open_ex((session), "session", sizeof("session") - 1, LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0)
|
||||
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, char *host, int port, char *shost, int sport);
|
||||
#define libssh2_channel_direct_tcpip(session, host, port) libssh2_channel_direct_tcpip_ex((session), (host), (port), "127.0.0.1", 22)
|
||||
#define libssh2_channel_direct_tcpip(session, host, port) libssh2_channel_direct_tcpip_ex((session), (host), (port), "127.0.0.1", 22)
|
||||
|
||||
LIBSSH2_API LIBSSH2_LISTENER *libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session, char *host, int port, int *bound_port, int queue_maxsize);
|
||||
#define libssh2_channel_forward_listen(session, port) libssh2_channel_forward_listen_ex((session), NULL, (port), NULL, 16)
|
||||
|
||||
LIBSSH2_API int libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener);
|
||||
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener);
|
||||
|
||||
LIBSSH2_API int libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, char *varname, int varname_len, char *value, int value_len);
|
||||
#define libssh2_channel_setenv(channel, varname, value) libssh2_channel_setenv_ex((channel), (varname), strlen(varname), (value), strlen(value))
|
||||
@@ -187,31 +338,62 @@ LIBSSH2_API int libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, char *varnam
|
||||
LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, char *term, int term_len, char *modes, int modes_len, int width, int height, int width_px, int height_px);
|
||||
#define libssh2_channel_request_pty(channel, term) libssh2_channel_request_pty_ex((channel), (term), strlen(term), NULL, 0, LIBSSH2_TERM_WIDTH, LIBSSH2_TERM_HEIGHT, LIBSSH2_TERM_WIDTH_PX, LIBSSH2_TERM_HEIGHT_PX)
|
||||
|
||||
LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, char *request, int request_len, char *message, int message_len);
|
||||
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, const char *request, int request_len, const char *message, int message_len);
|
||||
#define libssh2_channel_shell(channel) libssh2_channel_process_startup((channel), "shell", sizeof("shell") - 1, NULL, 0)
|
||||
#define libssh2_channel_exec(channel, command) libssh2_channel_process_startup((channel), "exec", sizeof("exec") - 1, (command), strlen(command))
|
||||
#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);
|
||||
#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))
|
||||
|
||||
LIBSSH2_API int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended);
|
||||
|
||||
LIBSSH2_API unsigned long libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, unsigned long *read_avail, unsigned long *window_size_initial);
|
||||
#define libssh2_channel_window_read(channel) libssh2_channel_window_read_ex((channel), NULL, NULL)
|
||||
|
||||
LIBSSH2_API unsigned long libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, unsigned long adjustment, unsigned char force);
|
||||
|
||||
LIBSSH2_API int libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id, const char *buf, size_t buflen);
|
||||
#define libssh2_channel_write(channel, buf, buflen) libssh2_channel_write_ex((channel), 0, (buf), (buflen))
|
||||
#define libssh2_channel_write_stderr(channel, buf, buflen) libssh2_channel_write_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen))
|
||||
|
||||
LIBSSH2_API unsigned long libssh2_channel_window_write_ex(LIBSSH2_CHANNEL *channel, unsigned long *window_size_initial);
|
||||
#define libssh2_channel_window_write(channel) libssh2_channel_window_write_ex((channel), NULL)
|
||||
|
||||
LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int blocking);
|
||||
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_get_exit_status(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_close(LIBSSH2_CHANNEL *channel);
|
||||
LIBSSH2_API int libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel);
|
||||
LIBSSH2_API int libssh2_channel_free(LIBSSH2_CHANNEL *channel);
|
||||
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *path, struct stat *sb);
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char *path, int mode, size_t size, long mtime, long atime);
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat *sb);
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, const char *path, int mode, size_t size, long mtime, long atime);
|
||||
#define libssh2_scp_send(session, path, mode, size) libssh2_scp_send_ex((session), (path), (mode), (size), 0, 0)
|
||||
|
||||
LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **dest, int *dest_len, char *src, int src_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* LIBSSH2_H */
|
||||
|
@@ -6,12 +6,21 @@
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the `gettimeofday' function. */
|
||||
#undef HAVE_GETTIMEOFDAY
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `poll' function. */
|
||||
#undef HAVE_POLL
|
||||
|
||||
/* Define to 1 if you have the `select' function. */
|
||||
#undef HAVE_SELECT
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
@@ -27,18 +36,48 @@
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/select.h> header file. */
|
||||
#undef HAVE_SYS_SELECT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <sys/uio.h> header file. */
|
||||
#undef HAVE_SYS_UIO_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Enable "none" cipher -- NOT RECOMMENDED */
|
||||
#undef LIBSSH2_CRYPT_NONE
|
||||
|
||||
/* Output connection layer debugging info to stderr */
|
||||
#undef LIBSSH2_DEBUG_CONNECTION
|
||||
|
||||
/* Output failure events to stderr */
|
||||
#undef LIBSSH2_DEBUG_ERRORS
|
||||
|
||||
/* Output Key Exchange debugging info to stderr */
|
||||
#undef LIBSSH2_DEBUG_KEX
|
||||
|
||||
/* Output scp subsystem debugging info to stderr */
|
||||
#undef LIBSSH2_DEBUG_SCP
|
||||
|
||||
/* Output sftp subsystem debugging info to stderr */
|
||||
#undef LIBSSH2_DEBUG_SFTP
|
||||
|
||||
/* Output transport layer debugging info to stderr */
|
||||
#undef LIBSSH2_DEBUG_TRANSPORT
|
||||
|
||||
/* Output userauth layer debugging info to stderr */
|
||||
#undef LIBSSH2_DEBUG_USERAUTH
|
||||
|
||||
/* Enable newer diffie-hellman-group-exchange-sha1 syntax */
|
||||
#undef LIBSSH2_DH_GEX_NEW
|
||||
|
||||
/* Compile in zlib support */
|
||||
#undef LIBSSH2_HAVE_ZLIB
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
||||
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -38,11 +38,13 @@
|
||||
#ifndef LIBSSH2_PRIV_H
|
||||
#define LIBSSH2_PRIV_H 1
|
||||
|
||||
/* Definitions shared with the public */
|
||||
#define LIBSSH2_LIBRARY
|
||||
#include "libssh2_config.h"
|
||||
#include "libssh2.h"
|
||||
|
||||
#ifndef WIN32
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#define LIBSSH2_ALLOC(session, count) session->alloc((count), &(session)->abstract)
|
||||
@@ -55,7 +57,10 @@
|
||||
#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)
|
||||
|
||||
#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_HOSTKEY_METHOD LIBSSH2_HOSTKEY_METHOD;
|
||||
@@ -98,7 +103,7 @@ typedef struct _libssh2_channel_data {
|
||||
unsigned long window_size_initial, window_size, packet_size;
|
||||
|
||||
/* Set to 1 when CHANNEL_CLOSE / CHANNEL_EOF sent/received */
|
||||
int close, eof;
|
||||
char close, eof, extended_data_ignore_mode;
|
||||
} libssh2_channel_data;
|
||||
|
||||
struct _LIBSSH2_CHANNEL {
|
||||
@@ -107,17 +112,37 @@ struct _LIBSSH2_CHANNEL {
|
||||
|
||||
int blocking;
|
||||
|
||||
/* channel's program exit status */
|
||||
int exit_status;
|
||||
|
||||
libssh2_channel_data local, remote;
|
||||
unsigned long adjust_queue; /* Amount of bytes to be refunded to receive window (but not yet sent) */
|
||||
|
||||
LIBSSH2_SESSION *session;
|
||||
|
||||
LIBSSH2_CHANNEL *next, *prev;
|
||||
|
||||
void *abstract;
|
||||
LIBSSH2_CHANNEL_CLOSE_FUNC((*close_cb));
|
||||
};
|
||||
|
||||
struct _LIBSSH2_CHANNEL_BRIGADE {
|
||||
LIBSSH2_CHANNEL *head, *tail;
|
||||
};
|
||||
|
||||
struct _LIBSSH2_LISTENER {
|
||||
LIBSSH2_SESSION *session;
|
||||
|
||||
char *host;
|
||||
int port;
|
||||
|
||||
LIBSSH2_CHANNEL *queue;
|
||||
int queue_size;
|
||||
int queue_maxsize;
|
||||
|
||||
LIBSSH2_LISTENER *prev, *next;
|
||||
};
|
||||
|
||||
typedef struct _libssh2_endpoint_data {
|
||||
unsigned char *banner;
|
||||
|
||||
@@ -135,9 +160,10 @@ typedef struct _libssh2_endpoint_data {
|
||||
void *comp_abstract;
|
||||
|
||||
/* Method Preferences -- NULL yields "load order" */
|
||||
LIBSSH2_CRYPT_METHOD **crypt_prefs;
|
||||
LIBSSH2_MAC_METHOD **mac_prefs;
|
||||
LIBSSH2_COMP_METHOD **comp_prefs;
|
||||
char *crypt_prefs;
|
||||
char *mac_prefs;
|
||||
char *comp_prefs;
|
||||
char *lang_prefs;
|
||||
} libssh2_endpoint_data;
|
||||
|
||||
struct _LIBSSH2_SESSION {
|
||||
@@ -152,14 +178,14 @@ struct _LIBSSH2_SESSION {
|
||||
LIBSSH2_DEBUG_FUNC((*ssh_msg_debug));
|
||||
LIBSSH2_DISCONNECT_FUNC((*ssh_msg_disconnect));
|
||||
LIBSSH2_MACERROR_FUNC((*macerror));
|
||||
LIBSSH2_X11_OPEN_FUNC((*x11));
|
||||
|
||||
/* Method preferences -- NULL yields "load order" */
|
||||
LIBSSH2_KEX_METHOD **kex_prefs;
|
||||
LIBSSH2_HOSTKEY_METHOD **hostkey_prefs;
|
||||
char *kex_prefs;
|
||||
char *hostkey_prefs;
|
||||
|
||||
int exchanging_keys;
|
||||
int newkeys;
|
||||
int authenticated;
|
||||
int state;
|
||||
int flags;
|
||||
|
||||
/* Agreed Key Exchange Method */
|
||||
LIBSSH2_KEX_METHOD *kex;
|
||||
@@ -196,6 +222,8 @@ struct _LIBSSH2_SESSION {
|
||||
LIBSSH2_CHANNEL_BRIGADE channels;
|
||||
unsigned long next_channel;
|
||||
|
||||
LIBSSH2_LISTENER *listeners;
|
||||
|
||||
/* Actual I/O socket */
|
||||
int socket_fd;
|
||||
int socket_block;
|
||||
@@ -208,14 +236,26 @@ struct _LIBSSH2_SESSION {
|
||||
int err_code;
|
||||
};
|
||||
|
||||
/* session.state bits */
|
||||
#define LIBSSH2_STATE_EXCHANGING_KEYS 0x00000001
|
||||
#define LIBSSH2_STATE_NEWKEYS 0x00000002
|
||||
#define LIBSSH2_STATE_AUTHENTICATED 0x00000004
|
||||
|
||||
/* session.flag helpers */
|
||||
#ifdef MSG_NOSIGNAL
|
||||
#define LIBSSH2_SOCKET_SEND_FLAGS(session) (((session)->flags & LIBSSH2_FLAG_SIGPIPE) ? 0 : MSG_NOSIGNAL)
|
||||
#define LIBSSH2_SOCKET_RECV_FLAGS(session) (((session)->flags & LIBSSH2_FLAG_SIGPIPE) ? 0 : MSG_NOSIGNAL)
|
||||
#else
|
||||
/* If MSG_NOSIGNAL isn't defined we're SOL on blocking SIGPIPE */
|
||||
#define LIBSSH2_SOCKET_SEND_FLAGS(session) 0
|
||||
#define LIBSSH2_SOCKET_RECV_FLAGS(session) 0
|
||||
#endif
|
||||
|
||||
/* libssh2 extensible ssh api, ultimately I'd like to allow loading additional methods via .so/.dll */
|
||||
|
||||
struct _LIBSSH2_KEX_METHOD {
|
||||
char *name;
|
||||
|
||||
/* integrity key length */
|
||||
unsigned long key_len;
|
||||
|
||||
/* Key exchange, populates session->* and returns 0 on success, non-0 on error */
|
||||
int (*exchange_keys)(LIBSSH2_SESSION *session);
|
||||
|
||||
@@ -227,7 +267,7 @@ struct _LIBSSH2_HOSTKEY_METHOD {
|
||||
unsigned long hash_len;
|
||||
|
||||
int (*init)(LIBSSH2_SESSION *session, unsigned char *hostkey_data, unsigned long hostkey_data_len, void **abstract);
|
||||
int (*initPEM)(LIBSSH2_SESSION *session, unsigned char *privkeyfile, unsigned char *passphrase, void **abstract);
|
||||
int (*initPEM)(LIBSSH2_SESSION *session, unsigned const char *privkeyfile, unsigned const char *passphrase, void **abstract);
|
||||
int (*sig_verify)(LIBSSH2_SESSION *session, const unsigned char *sig, unsigned long sig_len, const unsigned char *m, unsigned long m_len, void **abstract);
|
||||
int (*sign)(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len, const unsigned char *data, unsigned long data_len, void **abstract);
|
||||
int (*signv)(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len, unsigned long veccount, const struct iovec datavec[], void **abstract);
|
||||
@@ -272,12 +312,46 @@ struct _LIBSSH2_MAC_METHOD {
|
||||
/* The length of a given MAC packet */
|
||||
int mac_len;
|
||||
|
||||
/* integrity key length */
|
||||
int key_len;
|
||||
|
||||
/* Message Authentication Code Hashing algo */
|
||||
int (*init)(LIBSSH2_SESSION *session, unsigned char *key, int *free_key, void **abstract);
|
||||
int (*hash)(LIBSSH2_SESSION *session, unsigned char *buf, unsigned long seqno, const unsigned char *packet, unsigned long packet_len, const unsigned char *addtl, unsigned long addtl_len, void **abstract);
|
||||
int (*dtor)(LIBSSH2_SESSION *session, void **abstract);
|
||||
};
|
||||
|
||||
#if defined(LIBSSH2_DEBUG_TRANSPORT) || defined(LIBSSH2_DEBUG_KEX) || defined(LIBSSH2_DEBUG_USERAUTH) || defined(LIBSSH2_DEBUG_CONNECTION) || defined(LIBSSH2_DEBUG_SCP) || defined(LIBSSH2_DEBUG_SFTP) || defined(LIBSSH2_DEBUG_ERRORS)
|
||||
#define LIBSSH2_DEBUG_ENABLED
|
||||
|
||||
/* Internal debugging contexts -- Used with --enable-debug-* */
|
||||
#define LIBSSH2_DBG_TRANS 1
|
||||
#define LIBSSH2_DBG_KEX 2
|
||||
#define LIBSSH2_DBG_AUTH 3
|
||||
#define LIBSSH2_DBG_CONN 4
|
||||
#define LIBSSH2_DBG_SCP 5
|
||||
#define LIBSSH2_DBG_SFTP 6
|
||||
#define LIBSSH2_DBG_ERROR 7
|
||||
|
||||
void _libssh2_debug(LIBSSH2_SESSION *session, int context, const char *format, ...);
|
||||
|
||||
#endif /* LIBSSH2_DEBUG_ENABLED */
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_ERRORS
|
||||
#define libssh2_error(session, errcode, errmsg, should_free) \
|
||||
{ \
|
||||
if (session->err_msg && session->err_should_free) { \
|
||||
LIBSSH2_FREE(session, session->err_msg); \
|
||||
} \
|
||||
session->err_msg = errmsg; \
|
||||
session->err_msglen = strlen(errmsg); \
|
||||
session->err_should_free = should_free; \
|
||||
session->err_code = errcode; \
|
||||
_libssh2_debug(session, LIBSSH2_DBG_ERROR, "%d - %s", session->err_code, session->err_msg); \
|
||||
}
|
||||
|
||||
#else /* ! LIBSSH2_DEBUG_ERRORS */
|
||||
|
||||
#define libssh2_error(session, errcode, errmsg, should_free) \
|
||||
{ \
|
||||
if (session->err_msg && session->err_should_free) { \
|
||||
@@ -289,6 +363,9 @@ struct _LIBSSH2_MAC_METHOD {
|
||||
session->err_code = errcode; \
|
||||
}
|
||||
|
||||
#endif /* LIBSSH2_DEBUG_ENABLED */
|
||||
|
||||
|
||||
#define LIBSSH2_SOCKET_UNKNOWN 1
|
||||
#define LIBSSH2_SOCKET_CONNECTED 0
|
||||
#define LIBSSH2_SOCKET_DISCONNECTED -1
|
||||
@@ -333,6 +410,9 @@ struct _LIBSSH2_MAC_METHOD {
|
||||
#define SSH_MSG_USERAUTH_PK_OK 60
|
||||
/* "password" method */
|
||||
#define SSH_MSG_USERAUTH_PASSWD_CHANGEREQ 60
|
||||
/* "keyboard-interactive" method */
|
||||
#define SSH_MSG_USERAUTH_INFO_REQUEST 60
|
||||
#define SSH_MSG_USERAUTH_INFO_RESPONSE 61
|
||||
|
||||
/* Channels */
|
||||
#define SSH_MSG_GLOBAL_REQUEST 80
|
||||
@@ -354,17 +434,26 @@ struct _LIBSSH2_MAC_METHOD {
|
||||
void libssh2_session_shutdown(LIBSSH2_SESSION *session);
|
||||
|
||||
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_htonu64(unsigned char *buf, libssh2_uint64_t val);
|
||||
|
||||
int libssh2_packet_read(LIBSSH2_SESSION *session, int block);
|
||||
int libssh2_packet_ask_ex(LIBSSH2_SESSION *session, unsigned char packet_type, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len, int poll_socket);
|
||||
#define libssh2_packet_ask(session, packet_type, data, data_len, poll_socket) \
|
||||
libssh2_packet_ask_ex((session), (packet_type), (data), (data_len), 0, NULL, 0, (poll_socket))
|
||||
int libssh2_packet_askv_ex(LIBSSH2_SESSION *session, unsigned char *packet_types, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len, int poll_socket);
|
||||
#define libssh2_packet_askv(session, packet_types, data, data_len, poll_socket) \
|
||||
libssh2_packet_askv_ex((session), (packet_types), (data), (data_len), 0, NULL, 0, (poll_socket))
|
||||
int libssh2_packet_require_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);
|
||||
#define libssh2_packet_require(session, packet_type, data, data_len) \
|
||||
libssh2_packet_require_ex((session), (packet_type), (data), (data_len), 0, NULL, 0)
|
||||
int libssh2_packet_requirev_ex(LIBSSH2_SESSION *session, unsigned char *packet_types, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len);
|
||||
#define libssh2_packet_requirev(session, packet_types, data, data_len) \
|
||||
libssh2_packet_requirev_ex((session), (packet_types), (data), (data_len), 0, NULL, 0)
|
||||
int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned long data_len);
|
||||
int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange);
|
||||
unsigned long libssh2_channel_nextid(LIBSSH2_SESSION *session);
|
||||
LIBSSH2_CHANNEL *libssh2_channel_locate(LIBSSH2_SESSION *session, unsigned long channel_id);
|
||||
|
||||
/* Let crypt.c/hostkey.c/comp.c/mac.c expose their method structs */
|
||||
|
190
include/libssh2_sftp.h
Normal file
190
include/libssh2_sftp.h
Normal file
@@ -0,0 +1,190 @@
|
||||
/* Copyright (c) 2004-2005, 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
9
src/.cvsignore
Normal file
@@ -0,0 +1,9 @@
|
||||
*.lib
|
||||
*.pdb
|
||||
*.dll
|
||||
*.exe
|
||||
*.obj
|
||||
.*.swp
|
||||
Debug
|
||||
Release
|
||||
*.exp
|
@@ -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@
|
||||
prefix = @prefix@
|
||||
@@ -42,6 +42,9 @@ scp.o: scp.c
|
||||
session.o: session.c
|
||||
$(CC) -o session.o session.c $(CFLAGS) $(LIBS)
|
||||
|
||||
sftp.o: sftp.c
|
||||
$(CC) -o sftp.o sftp.c $(CFLAGS) $(LIBS)
|
||||
|
||||
userauth.o: userauth.c
|
||||
$(CC) -o userauth.o userauth.c $(CFLAGS) $(LIBS)
|
||||
|
||||
@@ -54,7 +57,7 @@ libssh2.a: $(OBJECTS)
|
||||
ar q libssh2.a $(OBJECTS)
|
||||
@RANLIB@ libssh2.a
|
||||
install: all
|
||||
$(INSTALL) libssh2.@SHLIB_SUFFIX_NAME@ $(libdir)
|
||||
$(INSTALL) libssh2.@SHLIB_SUFFIX_NAME@ $(DESTDIR)$(libdir)
|
||||
clean:
|
||||
rm -f *~ libssh2.a libssh2.@SHLIB_SUFFIX_NAME@ *.o
|
||||
|
||||
|
18
src/NMakefile
Normal file
18
src/NMakefile
Normal 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"
|
||||
|
935
src/channel.c
935
src/channel.c
File diff suppressed because it is too large
Load Diff
54
src/comp.c
54
src/comp.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
||||
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -136,12 +136,12 @@ static int libssh2_comp_method_zlib_comp(LIBSSH2_SESSION *session, int compress,
|
||||
z_stream *strm = *abstract;
|
||||
/* A short-term alloc of a full data chunk is better than a series of reallocs */
|
||||
char *out;
|
||||
int out_maxlen = compress ? src_len : (2 * src_len);
|
||||
int out_maxlen = compress ? (src_len + 4) : (2 * src_len);
|
||||
int limiter = 0;
|
||||
|
||||
/* In practice they never come smaller than this */
|
||||
if (out_maxlen < 21) {
|
||||
out_maxlen = 21;
|
||||
if (out_maxlen < 25) {
|
||||
out_maxlen = 25;
|
||||
}
|
||||
|
||||
if (out_maxlen > payload_limit) {
|
||||
@@ -166,17 +166,17 @@ static int libssh2_comp_method_zlib_comp(LIBSSH2_SESSION *session, int compress,
|
||||
}
|
||||
if (status != Z_OK) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ZLIB, "compress/decompression failure", 0);
|
||||
LIBSSH2_FREE(session, strm->next_out);
|
||||
LIBSSH2_FREE(session, out);
|
||||
return -1;
|
||||
}
|
||||
if (strm->avail_in) {
|
||||
unsigned long out_ofs = out_maxlen - strm->avail_out;
|
||||
|
||||
out_maxlen += compress ? strm->avail_in : (2 * strm->avail_in);
|
||||
out_maxlen += compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
|
||||
|
||||
if ((out_maxlen > payload_limit) && !compress && limiter++) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ZLIB, "Excessive growth in decompression phase", 0);
|
||||
LIBSSH2_FREE(session, strm->next_out);
|
||||
LIBSSH2_FREE(session, out);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -186,7 +186,43 @@ static int libssh2_comp_method_zlib_comp(LIBSSH2_SESSION *session, int compress,
|
||||
return -1;
|
||||
}
|
||||
strm->next_out = out + out_ofs;
|
||||
strm->avail_out += compress ? strm->avail_in : (2 * strm->avail_in);
|
||||
strm->avail_out += compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
|
||||
} else while (!strm->avail_out) {
|
||||
/* Done with input, might be a byte or two in internal buffer during compress
|
||||
* Or potentially many bytes if it's a decompress
|
||||
*/
|
||||
int grow_size = compress ? 8 : 1024;
|
||||
|
||||
if (out_maxlen >= payload_limit) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ZLIB, "Excessive growth in decompression phase", 0);
|
||||
LIBSSH2_FREE(session, out);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (grow_size > (payload_limit - out_maxlen)) {
|
||||
grow_size = payload_limit - out_maxlen;
|
||||
}
|
||||
|
||||
out_maxlen += grow_size;
|
||||
strm->avail_out = grow_size;
|
||||
|
||||
out = LIBSSH2_REALLOC(session, out, out_maxlen);
|
||||
if (!out) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to expand final compress/decompress buffer", 0);
|
||||
return -1;
|
||||
}
|
||||
strm->next_out = out + out_maxlen - grow_size;
|
||||
|
||||
if (compress) {
|
||||
status = deflate(strm, Z_PARTIAL_FLUSH);
|
||||
} else {
|
||||
status = inflate(strm, Z_PARTIAL_FLUSH);
|
||||
}
|
||||
if (status != Z_OK) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ZLIB, "compress/decompression failure", 0);
|
||||
LIBSSH2_FREE(session, out);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,10 +272,10 @@ static LIBSSH2_COMP_METHOD libssh2_comp_method_zlib = {
|
||||
*********************** */
|
||||
|
||||
static LIBSSH2_COMP_METHOD *_libssh2_comp_methods[] = {
|
||||
&libssh2_comp_method_none,
|
||||
#ifdef LIBSSH2_HAVE_ZLIB
|
||||
&libssh2_comp_method_zlib,
|
||||
#endif /* LIBSSH2_HAVE_ZLIB */
|
||||
&libssh2_comp_method_none,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
||||
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
||||
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -38,6 +38,12 @@
|
||||
#include "libssh2_priv.h"
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
/* Needed for struct iovec on some platforms */
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_RSA
|
||||
/* ***********
|
||||
@@ -86,7 +92,8 @@ static int libssh2_hostkey_method_ssh_rsa_init(LIBSSH2_SESSION *session, unsigne
|
||||
/* {{{ libssh2_hostkey_method_ssh_rsa_passphrase_cb
|
||||
* TODO: Optionally call a passphrase callback specified by the calling program
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_rsadsa_passphrase_cb(char *buf, int size, int rwflag, char *passphrase){
|
||||
static int libssh2_hostkey_method_ssh_rsadsa_passphrase_cb(char *buf, int size, int rwflag, char *passphrase)
|
||||
{
|
||||
int passphrase_len = strlen(passphrase);
|
||||
|
||||
if (passphrase_len > (size - 1)) {
|
||||
@@ -102,7 +109,7 @@ static int libssh2_hostkey_method_ssh_rsadsa_passphrase_cb(char *buf, int size,
|
||||
/* {{{ libssh2_hostkey_method_ssh_rsa_initPEM
|
||||
* Load a Private Key from a PEM file
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION *session, unsigned char *privkeyfile, unsigned char *passphrase, void **abstract)
|
||||
static int libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION *session, unsigned const char *privkeyfile, unsigned const char *passphrase, void **abstract)
|
||||
{
|
||||
RSA *rsactx;
|
||||
FILE *fp;
|
||||
@@ -116,7 +123,15 @@ static int libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION *session, unsi
|
||||
if (!fp) {
|
||||
return -1;
|
||||
}
|
||||
rsactx = PEM_read_RSAPrivateKey(fp, NULL, (void*)libssh2_hostkey_method_ssh_rsadsa_passphrase_cb, passphrase);
|
||||
|
||||
if (!EVP_get_cipherbyname("des")) {
|
||||
/* If this cipher isn't loaded it's a pretty good indication that none are.
|
||||
* I have *NO DOUBT* that there's a better way to deal with this ($#&%#$(%$#(
|
||||
* Someone buy me an OpenSSL manual and I'll read up on it.
|
||||
*/
|
||||
OpenSSL_add_all_ciphers();
|
||||
}
|
||||
rsactx = PEM_read_RSAPrivateKey(fp, NULL, (void*)libssh2_hostkey_method_ssh_rsadsa_passphrase_cb, (void*)passphrase);
|
||||
if (!rsactx) {
|
||||
fclose(fp);
|
||||
return -1;
|
||||
@@ -308,7 +323,7 @@ static int libssh2_hostkey_method_ssh_dss_init(LIBSSH2_SESSION *session, unsigne
|
||||
/* {{{ libssh2_hostkey_method_ssh_dss_initPEM
|
||||
* Load a Private Key from a PEM file
|
||||
*/
|
||||
static int libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION *session, unsigned char *privkeyfile, unsigned char *passphrase, void **abstract)
|
||||
static int libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION *session, unsigned const char *privkeyfile, unsigned const char *passphrase, void **abstract)
|
||||
{
|
||||
DSA *dsactx;
|
||||
FILE *fp;
|
||||
@@ -322,7 +337,15 @@ static int libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION *session, unsi
|
||||
if (!fp) {
|
||||
return -1;
|
||||
}
|
||||
dsactx = PEM_read_DSAPrivateKey(fp, NULL, (void*)libssh2_hostkey_method_ssh_rsadsa_passphrase_cb, passphrase);
|
||||
|
||||
if (!EVP_get_cipherbyname("des")) {
|
||||
/* If this cipher isn't loaded it's a pretty good indication that none are.
|
||||
* I have *NO DOUBT* that there's a better way to deal with this ($#&%#$(%$#(
|
||||
* Someone buy me an OpenSSL manual and I'll read up on it.
|
||||
*/
|
||||
OpenSSL_add_all_ciphers();
|
||||
}
|
||||
dsactx = PEM_read_DSAPrivateKey(fp, NULL, (void*)libssh2_hostkey_method_ssh_rsadsa_passphrase_cb, (void*)passphrase);
|
||||
if (!dsactx) {
|
||||
fclose(fp);
|
||||
return -1;
|
||||
@@ -371,16 +394,14 @@ static int libssh2_hostkey_method_ssh_dss_sign(LIBSSH2_SESSION *session, unsigne
|
||||
const unsigned char *buf, unsigned long buf_len, void **abstract)
|
||||
{
|
||||
DSA *dsactx = (DSA*)(*abstract);
|
||||
int ret;
|
||||
DSA_SIG *sig;
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
SHA_CTX ctx;
|
||||
char *sig;
|
||||
int sig_len;
|
||||
|
||||
sig_len = DSA_size(dsactx);
|
||||
sig = LIBSSH2_ALLOC(session, sig_len);
|
||||
*signature = LIBSSH2_ALLOC(session, 2 * SHA_DIGEST_LENGTH);
|
||||
*signature_len = 2 * SHA_DIGEST_LENGTH;
|
||||
|
||||
if (!sig) {
|
||||
if (!(*signature)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -388,14 +409,16 @@ static int libssh2_hostkey_method_ssh_dss_sign(LIBSSH2_SESSION *session, unsigne
|
||||
SHA1_Update(&ctx, buf, buf_len);
|
||||
SHA1_Final(hash, &ctx);
|
||||
|
||||
ret = DSA_sign(NID_sha1, hash, SHA_DIGEST_LENGTH, sig, &sig_len, dsactx);
|
||||
if (!ret) {
|
||||
LIBSSH2_FREE(session, sig);
|
||||
sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx);
|
||||
if (!sig) {
|
||||
LIBSSH2_FREE(session, *signature);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*signature = sig;
|
||||
*signature_len = sig_len;
|
||||
BN_bn2bin(sig->r, *signature);
|
||||
BN_bn2bin(sig->s, *signature + SHA_DIGEST_LENGTH);
|
||||
|
||||
DSA_SIG_free(sig);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -408,16 +431,16 @@ static int libssh2_hostkey_method_ssh_dss_signv(LIBSSH2_SESSION *session, unsign
|
||||
unsigned long veccount, const struct iovec datavec[], void **abstract)
|
||||
{
|
||||
DSA *dsactx = (DSA*)(*abstract);
|
||||
int ret, i;
|
||||
DSA_SIG *sig;
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
SHA_CTX ctx;
|
||||
char *sig;
|
||||
int sig_len;
|
||||
int r_len, s_len, rs_pad, i;
|
||||
|
||||
sig_len = DSA_size(dsactx);
|
||||
sig = LIBSSH2_ALLOC(session, sig_len);
|
||||
*signature = LIBSSH2_ALLOC(session, 2 * SHA_DIGEST_LENGTH);
|
||||
*signature_len = 2 * SHA_DIGEST_LENGTH;
|
||||
memset(*signature, 0, 2 * SHA_DIGEST_LENGTH);
|
||||
|
||||
if (!sig) {
|
||||
if (!(*signature)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -427,15 +450,25 @@ static int libssh2_hostkey_method_ssh_dss_signv(LIBSSH2_SESSION *session, unsign
|
||||
}
|
||||
SHA1_Final(hash, &ctx);
|
||||
|
||||
ret = DSA_sign(NID_sha1, hash, SHA_DIGEST_LENGTH, sig, &sig_len, dsactx);
|
||||
|
||||
if (!ret) {
|
||||
LIBSSH2_FREE(session, sig);
|
||||
sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx);
|
||||
if (!sig) {
|
||||
LIBSSH2_FREE(session, *signature);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*signature = sig;
|
||||
*signature_len = sig_len;
|
||||
r_len = BN_num_bytes(sig->r);
|
||||
s_len = BN_num_bytes(sig->s);
|
||||
rs_pad = (2 * SHA_DIGEST_LENGTH) - (r_len + s_len);
|
||||
if (rs_pad < 0) {
|
||||
DSA_SIG_free(sig);
|
||||
LIBSSH2_FREE(session, *signature);
|
||||
return -1;
|
||||
}
|
||||
|
||||
BN_bn2bin(sig->r, *signature + rs_pad);
|
||||
BN_bn2bin(sig->s, *signature + rs_pad + r_len);
|
||||
|
||||
DSA_SIG_free(sig);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -485,9 +518,12 @@ LIBSSH2_HOSTKEY_METHOD **libssh2_hostkey_methods(void)
|
||||
}
|
||||
|
||||
/* {{{ 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 const char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type)
|
||||
{
|
||||
switch (hash_type) {
|
||||
#ifndef OPENSSL_NO_MD5
|
||||
|
438
src/kex.c
438
src/kex.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
||||
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
/* TODO: Switch this to an inline and handle alloc() failures */
|
||||
/* Helper macro called from libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange */
|
||||
@@ -108,6 +109,9 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
BN_bn2bin(e, e_packet + 6);
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending KEX packet %d", (int)packet_type_init);
|
||||
#endif
|
||||
if (libssh2_packet_write(session, e_packet, e_packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send KEX init message", 0);
|
||||
ret = -11;
|
||||
@@ -142,7 +146,18 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
MD5_Update(&fingerprint_ctx, session->server_hostkey, session->server_hostkey_len);
|
||||
MD5_Final(session->server_hostkey_md5, &fingerprint_ctx);
|
||||
}
|
||||
#endif
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
{
|
||||
char fingerprint[50], *fprint = fingerprint;
|
||||
int i;
|
||||
for(i = 0; i < 16; i++, fprint += 3) {
|
||||
snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]);
|
||||
}
|
||||
*(--fprint) = '\0';
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Server's MD5 Fingerprint: %s", fingerprint);
|
||||
}
|
||||
#endif /* LIBSSH2_DEBUG_KEX */
|
||||
#endif /* ! OPENSSL_NO_MD5 */
|
||||
|
||||
#ifndef OPENSSL_NO_SHA
|
||||
{
|
||||
@@ -152,7 +167,18 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
SHA1_Update(&fingerprint_ctx, session->server_hostkey, session->server_hostkey_len);
|
||||
SHA1_Final(session->server_hostkey_sha1, &fingerprint_ctx);
|
||||
}
|
||||
#endif
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
{
|
||||
char fingerprint[64], *fprint = fingerprint;
|
||||
int i;
|
||||
for(i = 0; i < 20; i++, fprint += 3) {
|
||||
snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]);
|
||||
}
|
||||
*(--fprint) = '\0';
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Server's SHA1 Fingerprint: %s", fingerprint);
|
||||
}
|
||||
#endif /* LIBSSH2_DEBUG_KEX */
|
||||
#endif /* ! OPENSSL_NO_SHA */
|
||||
|
||||
if (session->hostkey->init(session, session->server_hostkey, session->server_hostkey_len, &session->server_hostkey_abstract)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, "Unable to initialize hostkey importer", 0);
|
||||
@@ -160,7 +186,6 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
|
||||
f_value_len = libssh2_ntohu32(s); s += 4;
|
||||
f_value = s; s += f_value_len;
|
||||
BN_bin2bn(f_value, f_value_len, f);
|
||||
@@ -249,6 +274,9 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending NEWKEYS message");
|
||||
#endif
|
||||
c = SSH_MSG_NEWKEYS;
|
||||
if (libssh2_packet_write(session, &c, 1)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send NEWKEYS message", 0);
|
||||
@@ -262,7 +290,10 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
goto clean_exit;
|
||||
}
|
||||
/* The first key exchange has been performed, switch to active crypt/comp/mac mode */
|
||||
session->newkeys = 1;
|
||||
session->state |= LIBSSH2_STATE_NEWKEYS;
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Received NEWKEYS message");
|
||||
#endif
|
||||
|
||||
/* This will actually end up being just packet_type(1) for this packet type anyway */
|
||||
LIBSSH2_FREE(session, tmp);
|
||||
@@ -275,6 +306,9 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
}
|
||||
memcpy(session->session_id, h_sig_comp, SHA_DIGEST_LENGTH);
|
||||
session->session_id_len = SHA_DIGEST_LENGTH;
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "session_id calculated");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Calculate IV/Secret/Key for each direction */
|
||||
@@ -326,6 +360,9 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
LIBSSH2_FREE(session, secret);
|
||||
}
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Client to Server IV and Key calculated");
|
||||
#endif
|
||||
|
||||
if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
|
||||
if (session->remote.crypt_abstract) {
|
||||
@@ -375,6 +412,9 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
LIBSSH2_FREE(session, secret);
|
||||
}
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Server to Client IV and Key calculated");
|
||||
#endif
|
||||
|
||||
if (session->local.mac->dtor) {
|
||||
session->local.mac->dtor(session, &session->local.mac_abstract);
|
||||
@@ -384,14 +424,17 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
unsigned char *key = NULL;
|
||||
int free_key = 0;
|
||||
|
||||
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, session->kex->key_len, "E");
|
||||
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, session->local.mac->key_len, "E");
|
||||
session->local.mac->init(session, key, &free_key, &session->local.mac_abstract);
|
||||
|
||||
if (free_key) {
|
||||
memset(key, 0, session->kex->key_len);
|
||||
memset(key, 0, session->local.mac->key_len);
|
||||
LIBSSH2_FREE(session, key);
|
||||
}
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Client to Server HMAC Key calculated");
|
||||
#endif
|
||||
|
||||
if (session->remote.mac->dtor) {
|
||||
session->remote.mac->dtor(session, &session->remote.mac_abstract);
|
||||
@@ -401,14 +444,17 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
|
||||
unsigned char *key = NULL;
|
||||
int free_key = 0;
|
||||
|
||||
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, session->kex->key_len, "F");
|
||||
LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, session->remote.mac->key_len, "F");
|
||||
session->remote.mac->init(session, key, &free_key, &session->remote.mac_abstract);
|
||||
|
||||
if (free_key) {
|
||||
memset(key, 0, session->kex->key_len);
|
||||
memset(key, 0, session->remote.mac->key_len);
|
||||
LIBSSH2_FREE(session, key);
|
||||
}
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Server to Client HMAC Key calculated");
|
||||
#endif
|
||||
|
||||
clean_exit:
|
||||
BN_clear_free(x);
|
||||
@@ -469,6 +515,9 @@ static int libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange(LIBSSH2_SE
|
||||
BN_set_word(g, 2);
|
||||
BN_bin2bn(p_value, 128, p);
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Initiating Diffie-Hellman Group1 Key Exchange");
|
||||
#endif
|
||||
ret = libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session, g, p, SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, NULL, 0);
|
||||
|
||||
BN_clear_free(p);
|
||||
@@ -525,6 +574,9 @@ static int libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_S
|
||||
BN_set_word(g, 2);
|
||||
BN_bin2bn(p_value, 256, p);
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Initiating Diffie-Hellman Group14 Key Exchange");
|
||||
#endif
|
||||
ret = libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session, g, p, SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, NULL, 0);
|
||||
|
||||
BN_clear_free(p);
|
||||
@@ -553,10 +605,16 @@ static int libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange(LI
|
||||
libssh2_htonu32(request + 5, LIBSSH2_DH_GEX_OPTGROUP);
|
||||
libssh2_htonu32(request + 9, LIBSSH2_DH_GEX_MAXGROUP);
|
||||
request_len = 13;
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Initiating Diffie-Hellman Group-Exchange (New Method)");
|
||||
#endif
|
||||
#else
|
||||
request[0] = SSH_MSG_KEX_DH_GEX_REQUEST_OLD;
|
||||
libssh2_htonu32(request + 1, LIBSSH2_DH_GEX_OPTGROUP);
|
||||
request_len = 5;
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Initiating Diffie-Hellman Group-Exchange (Old Method)");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (libssh2_packet_write(session, request, request_len)) {
|
||||
@@ -595,21 +653,18 @@ static int libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange(LI
|
||||
|
||||
LIBSSH2_KEX_METHOD libssh2_kex_method_diffie_helman_group1_sha1 = {
|
||||
"diffie-hellman-group1-sha1",
|
||||
SHA_DIGEST_LENGTH,
|
||||
libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange,
|
||||
LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
|
||||
};
|
||||
|
||||
LIBSSH2_KEX_METHOD libssh2_kex_method_diffie_helman_group14_sha1 = {
|
||||
"diffie-hellman-group14-sha1",
|
||||
SHA_DIGEST_LENGTH,
|
||||
libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange,
|
||||
LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
|
||||
};
|
||||
|
||||
LIBSSH2_KEX_METHOD libssh2_kex_method_diffie_helman_group_exchange_sha1 = {
|
||||
"diffie-hellman-group-exchange-sha1",
|
||||
SHA_DIGEST_LENGTH,
|
||||
libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange,
|
||||
LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
|
||||
};
|
||||
@@ -671,16 +726,16 @@ static size_t libssh2_kex_method_list(unsigned char *buf, size_t list_strlen, LI
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
#define LIBSSH2_METHOD_PREFS \
|
||||
LIBSSH2_KEX_METHOD **kex_prefs = session->kex_prefs ? session->kex_prefs : libssh2_kex_methods; \
|
||||
LIBSSH2_HOSTKEY_METHOD **hostkey_prefs = session->hostkey_prefs ? session->hostkey_prefs : libssh2_hostkey_methods(); \
|
||||
LIBSSH2_CRYPT_METHOD **crypt_cs_prefs = session->local.crypt_prefs ? session->local.crypt_prefs : libssh2_crypt_methods(); \
|
||||
LIBSSH2_CRYPT_METHOD **crypt_sc_prefs = session->remote.crypt_prefs ? session->remote.crypt_prefs : libssh2_crypt_methods(); \
|
||||
LIBSSH2_COMP_METHOD **comp_cs_prefs = session->local.comp_prefs ? session->local.comp_prefs : libssh2_comp_methods(); \
|
||||
LIBSSH2_COMP_METHOD **comp_sc_prefs = session->remote.comp_prefs ? session->remote.comp_prefs : libssh2_comp_methods(); \
|
||||
LIBSSH2_MAC_METHOD **mac_cs_prefs = session->local.mac_prefs ? session->local.mac_prefs : libssh2_mac_methods(); \
|
||||
LIBSSH2_MAC_METHOD **mac_sc_prefs = session->remote.mac_prefs ? session->remote.mac_prefs : libssh2_mac_methods();
|
||||
|
||||
#define LIBSSH2_METHOD_PREFS_LEN(prefvar, defaultvar) ((prefvar) ? strlen(prefvar) : libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)(defaultvar)))
|
||||
#define LIBSSH2_METHOD_PREFS_STR(buf, prefvarlen, prefvar, defaultvar) \
|
||||
if (prefvar) { \
|
||||
libssh2_htonu32((buf), (prefvarlen)); \
|
||||
buf += 4; \
|
||||
memcpy((buf), (prefvar), (prefvarlen)); \
|
||||
buf += (prefvarlen); \
|
||||
} else { \
|
||||
buf += libssh2_kex_method_list((buf), (prefvarlen), (LIBSSH2_COMMON_METHOD**)(defaultvar)); \
|
||||
}
|
||||
|
||||
/* {{{ libssh2_kexinit
|
||||
* Send SSH_MSG_KEXINIT packet
|
||||
@@ -694,18 +749,17 @@ static int libssh2_kexinit(LIBSSH2_SESSION *session)
|
||||
size_t mac_cs_len, mac_sc_len;
|
||||
size_t lang_cs_len, lang_sc_len;
|
||||
unsigned char *data, *s;
|
||||
LIBSSH2_METHOD_PREFS
|
||||
|
||||
kex_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)kex_prefs);
|
||||
hostkey_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)hostkey_prefs);
|
||||
crypt_cs_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)crypt_cs_prefs);
|
||||
crypt_sc_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)crypt_sc_prefs);
|
||||
mac_cs_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)mac_cs_prefs);
|
||||
mac_sc_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)mac_sc_prefs);
|
||||
comp_cs_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)comp_cs_prefs);
|
||||
comp_sc_len = libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)comp_sc_prefs);
|
||||
lang_cs_len = 0; /* No langs in this version */
|
||||
lang_sc_len = 0; /* No langs in this version */
|
||||
kex_len = LIBSSH2_METHOD_PREFS_LEN(session->kex_prefs, libssh2_kex_methods);
|
||||
hostkey_len = LIBSSH2_METHOD_PREFS_LEN(session->hostkey_prefs, libssh2_hostkey_methods());
|
||||
crypt_cs_len = LIBSSH2_METHOD_PREFS_LEN(session->local.crypt_prefs, libssh2_crypt_methods());
|
||||
crypt_sc_len = LIBSSH2_METHOD_PREFS_LEN(session->remote.crypt_prefs, libssh2_crypt_methods());
|
||||
mac_cs_len = LIBSSH2_METHOD_PREFS_LEN(session->local.mac_prefs, libssh2_mac_methods());
|
||||
mac_sc_len = LIBSSH2_METHOD_PREFS_LEN(session->remote.mac_prefs, libssh2_mac_methods());
|
||||
comp_cs_len = LIBSSH2_METHOD_PREFS_LEN(session->local.comp_prefs, libssh2_comp_methods());
|
||||
comp_sc_len = LIBSSH2_METHOD_PREFS_LEN(session->remote.comp_prefs, libssh2_comp_methods());
|
||||
lang_cs_len = LIBSSH2_METHOD_PREFS_LEN(session->local.lang_prefs, NULL);
|
||||
lang_sc_len = LIBSSH2_METHOD_PREFS_LEN(session->remote.lang_prefs, NULL);
|
||||
|
||||
data_len += kex_len + hostkey_len + \
|
||||
crypt_cs_len + crypt_sc_len + \
|
||||
@@ -721,21 +775,20 @@ static int libssh2_kexinit(LIBSSH2_SESSION *session)
|
||||
|
||||
*(s++) = SSH_MSG_KEXINIT;
|
||||
|
||||
/* TODO: Build a better cookie (and the mice will beat a path to my door...) */
|
||||
memcpy(s, "mysecretMYSECRET", 16);
|
||||
RAND_bytes(s, 16);
|
||||
s += 16;
|
||||
|
||||
/* Ennumerating through these lists twice is probably (certainly?) inefficient from a CPU standpoint, but it saves multiple malloc/realloc calls */
|
||||
s += libssh2_kex_method_list(s, kex_len, (LIBSSH2_COMMON_METHOD**)kex_prefs);
|
||||
s += libssh2_kex_method_list(s, hostkey_len, (LIBSSH2_COMMON_METHOD**)hostkey_prefs);
|
||||
s += libssh2_kex_method_list(s, crypt_cs_len, (LIBSSH2_COMMON_METHOD**)crypt_cs_prefs);
|
||||
s += libssh2_kex_method_list(s, crypt_sc_len, (LIBSSH2_COMMON_METHOD**)crypt_sc_prefs);
|
||||
s += libssh2_kex_method_list(s, mac_cs_len, (LIBSSH2_COMMON_METHOD**)mac_cs_prefs);
|
||||
s += libssh2_kex_method_list(s, mac_sc_len, (LIBSSH2_COMMON_METHOD**)mac_sc_prefs);
|
||||
s += libssh2_kex_method_list(s, comp_cs_len, (LIBSSH2_COMMON_METHOD**)comp_cs_prefs);
|
||||
s += libssh2_kex_method_list(s, comp_sc_len, (LIBSSH2_COMMON_METHOD**)comp_sc_prefs);
|
||||
s += libssh2_kex_method_list(s, lang_cs_len, NULL);
|
||||
s += libssh2_kex_method_list(s, lang_sc_len, NULL);
|
||||
LIBSSH2_METHOD_PREFS_STR(s, kex_len, session->kex_prefs, libssh2_kex_methods);
|
||||
LIBSSH2_METHOD_PREFS_STR(s, hostkey_len, session->hostkey_prefs, libssh2_hostkey_methods());
|
||||
LIBSSH2_METHOD_PREFS_STR(s, crypt_cs_len, session->local.crypt_prefs, libssh2_crypt_methods());
|
||||
LIBSSH2_METHOD_PREFS_STR(s, crypt_sc_len, session->remote.crypt_prefs, libssh2_crypt_methods());
|
||||
LIBSSH2_METHOD_PREFS_STR(s, mac_cs_len, session->local.mac_prefs, libssh2_mac_methods());
|
||||
LIBSSH2_METHOD_PREFS_STR(s, mac_sc_len, session->remote.mac_prefs, libssh2_mac_methods());
|
||||
LIBSSH2_METHOD_PREFS_STR(s, comp_cs_len, session->local.comp_prefs, libssh2_comp_methods());
|
||||
LIBSSH2_METHOD_PREFS_STR(s, comp_sc_len, session->remote.comp_prefs, libssh2_comp_methods());
|
||||
LIBSSH2_METHOD_PREFS_STR(s, lang_cs_len, session->local.lang_prefs, NULL);
|
||||
LIBSSH2_METHOD_PREFS_STR(s, lang_sc_len, session->remote.lang_prefs, NULL);
|
||||
|
||||
/* No optimistic KEX packet follows */
|
||||
/* Deal with optimistic packets
|
||||
@@ -750,6 +803,23 @@ static int libssh2_kexinit(LIBSSH2_SESSION *session)
|
||||
*(s++) = 0;
|
||||
*(s++) = 0;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
{
|
||||
/* Funnily enough, they'll all "appear" to be '\0' terminated */
|
||||
char *p = data + 21; /* type(1) + cookie(16) + len(4) */
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent KEX: %s", p); p += kex_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent HOSTKEY: %s", p); p += hostkey_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent CRYPT_CS: %s", p); p += crypt_cs_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent CRYPT_SC: %s", p); p += crypt_sc_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent MAC_CS: %s", p); p += mac_cs_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent MAC_SC: %s", p); p += mac_sc_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent COMP_CS: %s", p); p += comp_cs_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent COMP_SC: %s", p); p += comp_sc_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent LANG_CS: %s", p); p += lang_cs_len + 4;
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent LANG_SC: %s", p); p += lang_sc_len + 4;
|
||||
}
|
||||
#endif /* LIBSSH2_DEBUG_KEX */
|
||||
if (libssh2_packet_write(session, data, data_len)) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send KEXINIT packet to remote host", 0);
|
||||
@@ -803,15 +873,62 @@ 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
|
||||
* 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)
|
||||
{
|
||||
LIBSSH2_HOSTKEY_METHOD **hostkeyp = session->hostkey_prefs ? session->hostkey_prefs : libssh2_hostkey_methods();
|
||||
LIBSSH2_HOSTKEY_METHOD **hostkeyp = libssh2_hostkey_methods();
|
||||
unsigned char *s;
|
||||
|
||||
while ((*hostkeyp)->name) {
|
||||
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 && (*hostkeyp)->name) {
|
||||
s = libssh2_kex_agree_instr(hostkey, hostkey_len, (*hostkeyp)->name, strlen((*hostkeyp)->name));
|
||||
if (s) {
|
||||
/* So far so good, but does it suit our purposes? (Encrypting vs Signing) */
|
||||
@@ -839,9 +956,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,
|
||||
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;
|
||||
|
||||
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) {
|
||||
s = libssh2_kex_agree_instr(kex, kex_len, (*kexp)->name, strlen((*kexp)->name));
|
||||
if (s) {
|
||||
@@ -864,10 +1009,34 @@ 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)
|
||||
{
|
||||
LIBSSH2_CRYPT_METHOD **cryptp = endpoint->crypt_prefs ? endpoint->crypt_prefs : libssh2_crypt_methods();
|
||||
LIBSSH2_CRYPT_METHOD **cryptp = libssh2_crypt_methods();
|
||||
unsigned char *s;
|
||||
|
||||
while ((*cryptp)->name) {
|
||||
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 && (*cryptp)->name) {
|
||||
s = libssh2_kex_agree_instr(crypt, crypt_len, (*cryptp)->name, strlen((*cryptp)->name));
|
||||
if (s) {
|
||||
endpoint->crypt = *cryptp;
|
||||
@@ -885,10 +1054,34 @@ 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)
|
||||
{
|
||||
LIBSSH2_MAC_METHOD **macp = endpoint->mac_prefs ? endpoint->mac_prefs : libssh2_mac_methods();
|
||||
LIBSSH2_MAC_METHOD **macp = libssh2_mac_methods();
|
||||
unsigned char *s;
|
||||
|
||||
while ((*macp)->name) {
|
||||
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 && (*macp)->name) {
|
||||
s = libssh2_kex_agree_instr(mac, mac_len, (*macp)->name, strlen((*macp)->name));
|
||||
if (s) {
|
||||
endpoint->mac = *macp;
|
||||
@@ -906,10 +1099,34 @@ 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)
|
||||
{
|
||||
LIBSSH2_COMP_METHOD **compp = endpoint->comp_prefs ? endpoint->comp_prefs : libssh2_comp_methods();
|
||||
LIBSSH2_COMP_METHOD **compp = libssh2_comp_methods();
|
||||
unsigned char *s;
|
||||
|
||||
while ((*compp)->name) {
|
||||
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 && (*compp)->name) {
|
||||
s = libssh2_kex_agree_instr(comp, comp_len, (*compp)->name, strlen((*compp)->name));
|
||||
if (s) {
|
||||
endpoint->comp = *compp;
|
||||
@@ -977,6 +1194,19 @@ static int libssh2_kex_agree_methods(LIBSSH2_SESSION *session, unsigned char *da
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_KEX
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on KEX method: %s", session->kex->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on HOSTKEY method: %s", session->hostkey->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on CRYPT_CS method: %s", session->local.crypt->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on CRYPT_SC method: %s", session->remote.crypt->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on MAC_CS method: %s", session->local.mac->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on MAC_SC method: %s", session->remote.mac->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on COMP_CS method: %s", session->local.comp->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on COMP_SC method: %s", session->remote.comp->name);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on LANG_CS method:"); /* None yet */
|
||||
_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on LANG_SC method:"); /* None yet */
|
||||
#endif
|
||||
|
||||
/* Initialize compression layer */
|
||||
if (session->local.comp && session->local.comp->init &&
|
||||
session->local.comp->init(session, 1, &session->local.comp_abstract)) {
|
||||
@@ -1002,7 +1232,7 @@ int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange) /* session->f
|
||||
unsigned long data_len;
|
||||
|
||||
/* Prevent loop in packet_add() */
|
||||
session->exchanging_keys = 1;
|
||||
session->state |= LIBSSH2_STATE_EXCHANGING_KEYS;
|
||||
|
||||
if (reexchange) {
|
||||
session->kex = NULL;
|
||||
@@ -1048,9 +1278,105 @@ int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange) /* session->f
|
||||
session->remote.kexinit = NULL;
|
||||
}
|
||||
|
||||
session->exchanging_keys = 0;
|
||||
session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_session_method_pref
|
||||
* Set preferred method
|
||||
*/
|
||||
LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method_type, const 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;
|
||||
}
|
||||
/* }}} */
|
||||
|
35
src/mac.c
35
src/mac.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
||||
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -54,6 +54,7 @@ static int libssh2_mac_none_MAC(LIBSSH2_SESSION *session, unsigned char *buf, un
|
||||
static LIBSSH2_MAC_METHOD libssh2_mac_method_none = {
|
||||
"none",
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
libssh2_mac_none_MAC,
|
||||
NULL
|
||||
@@ -98,7 +99,7 @@ static int libssh2_mac_method_hmac_sha1_hash(LIBSSH2_SESSION *session, unsigned
|
||||
|
||||
libssh2_htonu32(seqno_buf, seqno);
|
||||
|
||||
HMAC_Init(&ctx, *abstract, session->kex->key_len, EVP_sha1());
|
||||
HMAC_Init(&ctx, *abstract, 20, EVP_sha1());
|
||||
HMAC_Update(&ctx, seqno_buf, 4);
|
||||
HMAC_Update(&ctx, packet, packet_len);
|
||||
if (addtl && addtl_len) {
|
||||
@@ -113,7 +114,8 @@ static int libssh2_mac_method_hmac_sha1_hash(LIBSSH2_SESSION *session, unsigned
|
||||
|
||||
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_sha1 = {
|
||||
"hmac-sha1",
|
||||
SHA_DIGEST_LENGTH,
|
||||
20,
|
||||
20,
|
||||
libssh2_mac_method_common_init,
|
||||
libssh2_mac_method_hmac_sha1_hash,
|
||||
libssh2_mac_method_common_dtor,
|
||||
@@ -137,13 +139,13 @@ static int libssh2_mac_method_hmac_sha1_96_hash(LIBSSH2_SESSION *session, unsign
|
||||
|
||||
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_sha1_96 = {
|
||||
"hmac-sha1-96",
|
||||
96 / 8,
|
||||
12,
|
||||
20,
|
||||
libssh2_mac_method_common_init,
|
||||
libssh2_mac_method_hmac_sha1_96_hash,
|
||||
libssh2_mac_method_common_dtor,
|
||||
};
|
||||
|
||||
#ifdef WHY_DOESNT_MD5_WORK
|
||||
/* {{{ libssh2_mac_method_hmac_md5_hash
|
||||
* Calculate hash using full md5 value
|
||||
*/
|
||||
@@ -156,7 +158,7 @@ static int libssh2_mac_method_hmac_md5_hash(LIBSSH2_SESSION *session, unsigned c
|
||||
|
||||
libssh2_htonu32(seqno_buf, seqno);
|
||||
|
||||
HMAC_Init(&ctx, *abstract, session->kex->key_len, EVP_md5());
|
||||
HMAC_Init(&ctx, *abstract, 16, EVP_md5());
|
||||
HMAC_Update(&ctx, seqno_buf, 4);
|
||||
HMAC_Update(&ctx, packet, packet_len);
|
||||
if (addtl && addtl_len) {
|
||||
@@ -171,7 +173,8 @@ static int libssh2_mac_method_hmac_md5_hash(LIBSSH2_SESSION *session, unsigned c
|
||||
|
||||
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_md5 = {
|
||||
"hmac-md5",
|
||||
MD5_DIGEST_LENGTH,
|
||||
16,
|
||||
16,
|
||||
libssh2_mac_method_common_init,
|
||||
libssh2_mac_method_hmac_md5_hash,
|
||||
libssh2_mac_method_common_dtor,
|
||||
@@ -180,8 +183,8 @@ static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_md5 = {
|
||||
/* {{{ libssh2_mac_method_hmac_md5_96_hash
|
||||
* Calculate hash using first 96 bits of md5 value
|
||||
*/
|
||||
static int libssh2_mac_method_hmac_md5_96_hash(LIBSSH2_SESSION *session, unsigned char *buf, unsigned seqno,
|
||||
const unsigned char *packet, unsigned packet_len,
|
||||
static int libssh2_mac_method_hmac_md5_96_hash(LIBSSH2_SESSION *session, unsigned char *buf, unsigned long seqno,
|
||||
const unsigned char *packet, unsigned long packet_len,
|
||||
const unsigned char *addtl, unsigned long addtl_len, void **abstract)
|
||||
{
|
||||
char temp[MD5_DIGEST_LENGTH];
|
||||
@@ -195,12 +198,12 @@ static int libssh2_mac_method_hmac_md5_96_hash(LIBSSH2_SESSION *session, unsigne
|
||||
|
||||
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_md5_96 = {
|
||||
"hmac-md5-96",
|
||||
96 / 8,
|
||||
12,
|
||||
16,
|
||||
libssh2_mac_method_common_init,
|
||||
libssh2_mac_method_hmac_md5_96_hash,
|
||||
libssh2_mac_method_common_dtor,
|
||||
};
|
||||
#endif /* WHY_DOESNT_MD5_WORK */
|
||||
|
||||
#ifndef OPENSSL_NO_RIPEMD
|
||||
/* {{{ libssh2_mac_method_hmac_ripemd160_hash
|
||||
@@ -215,7 +218,7 @@ static int libssh2_mac_method_hmac_ripemd160_hash(LIBSSH2_SESSION *session, unsi
|
||||
|
||||
libssh2_htonu32(seqno_buf, seqno);
|
||||
|
||||
HMAC_Init(&ctx, *abstract, session->kex->key_len, EVP_ripemd160());
|
||||
HMAC_Init(&ctx, *abstract, 20, EVP_ripemd160());
|
||||
HMAC_Update(&ctx, seqno_buf, 4);
|
||||
HMAC_Update(&ctx, packet, packet_len);
|
||||
if (addtl && addtl_len) {
|
||||
@@ -230,7 +233,8 @@ static int libssh2_mac_method_hmac_ripemd160_hash(LIBSSH2_SESSION *session, unsi
|
||||
|
||||
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160 = {
|
||||
"hmac-ripemd160",
|
||||
160 / 8,
|
||||
20,
|
||||
20,
|
||||
libssh2_mac_method_common_init,
|
||||
libssh2_mac_method_hmac_ripemd160_hash,
|
||||
libssh2_mac_method_common_dtor,
|
||||
@@ -238,7 +242,8 @@ static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160 = {
|
||||
|
||||
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160_openssh_com = {
|
||||
"hmac-ripemd160@openssh.com",
|
||||
160 / 8,
|
||||
20,
|
||||
20,
|
||||
libssh2_mac_method_common_init,
|
||||
libssh2_mac_method_hmac_ripemd160_hash,
|
||||
libssh2_mac_method_common_dtor,
|
||||
@@ -248,10 +253,8 @@ static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160_openssh_com = {
|
||||
static LIBSSH2_MAC_METHOD *_libssh2_mac_methods[] = {
|
||||
&libssh2_mac_method_hmac_sha1,
|
||||
&libssh2_mac_method_hmac_sha1_96,
|
||||
#ifdef WHY_DOESNT_MD5_WORK
|
||||
&libssh2_mac_method_hmac_md5,
|
||||
&libssh2_mac_method_hmac_md5_96,
|
||||
#endif /* WHY_DOESNT_MD5_WORK */
|
||||
#ifndef OPENSSL_NO_RIPEMD
|
||||
&libssh2_mac_method_hmac_ripemd160,
|
||||
&libssh2_mac_method_hmac_ripemd160_openssh_com,
|
||||
|
61
src/misc.c
61
src/misc.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
||||
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
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 */
|
||||
|
||||
/* {{{ */
|
||||
@@ -136,3 +169,29 @@ LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **data, int
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_ENABLED
|
||||
/* {{{ _libssh2_debug
|
||||
* Internal debug logging facility
|
||||
* Just writes to stderr until a good reason comes up to support anything else
|
||||
*/
|
||||
void _libssh2_debug(LIBSSH2_SESSION *session, int context, const char *format, ...)
|
||||
{
|
||||
char buffer[1536];
|
||||
int len;
|
||||
va_list vargs;
|
||||
char *contexts[8] = { "Unknown", "Transport", "Key Exhange", "Userauth", "Connection", "scp", "SFTP", "Failure Event" };
|
||||
|
||||
if (context < 1 || context > 6) {
|
||||
context = 0;
|
||||
}
|
||||
|
||||
len = snprintf(buffer, 1535, "[libssh2] %s: ", contexts[context]);
|
||||
|
||||
va_start(vargs, format);
|
||||
len += vsnprintf(buffer + len, 1535 - len, format, vargs);
|
||||
buffer[len] = '\n';
|
||||
va_end(vargs);
|
||||
write(2, buffer, len + 1);
|
||||
}
|
||||
/* }}} */
|
||||
#endif
|
||||
|
587
src/packet.c
587
src/packet.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
||||
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -38,8 +38,275 @@
|
||||
#include "libssh2_priv.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
/* Needed for struct iovec on some platforms */
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POLL
|
||||
# include <sys/poll.h>
|
||||
#else
|
||||
# ifdef HAVE_SELECT
|
||||
# ifdef HAVE_SYS_SELECT_H
|
||||
# include <sys/select.h>
|
||||
# else
|
||||
# include <sys/time.h>
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* {{{ libssh2_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;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Remote received connection from %s:%ld to %s:%ld", shost, sport, host, port);
|
||||
#endif
|
||||
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 */
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Listener queue full, ignoring");
|
||||
#endif
|
||||
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;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Connection queued: channel %lu/%lu win %lu/%lu packet %lu/%lu",
|
||||
channel->local.id, channel->remote.id,
|
||||
channel->local.window_size, channel->remote.window_size,
|
||||
channel->local.packet_size, channel->remote.packet_size);
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "X11 Connection Received from %s:%ld on channel %lu", shost, sport, sender_channel);
|
||||
#endif
|
||||
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;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "X11 Connection established: channel %lu/%lu win %lu/%lu packet %lu/%lu",
|
||||
channel->local.id, channel->remote.id,
|
||||
channel->local.window_size, channel->remote.window_size,
|
||||
channel->local.packet_size, channel->remote.packet_size);
|
||||
#endif
|
||||
p = packet;
|
||||
*(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
|
||||
libssh2_htonu32(p, channel->remote.id); p += 4;
|
||||
libssh2_htonu32(p, channel->local.id); p += 4;
|
||||
libssh2_htonu32(p, channel->remote.window_size_initial); p += 4;
|
||||
libssh2_htonu32(p, channel->remote.packet_size); p += 4;
|
||||
|
||||
if (libssh2_packet_write(session, packet, 17)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel open confirmation", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Link the channel into the session */
|
||||
if (session->channels.tail) {
|
||||
session->channels.tail->next = channel;
|
||||
channel->prev = session->channels.tail;
|
||||
} else {
|
||||
session->channels.head = channel;
|
||||
channel->prev = NULL;
|
||||
}
|
||||
channel->next = NULL;
|
||||
session->channels.tail = channel;
|
||||
|
||||
/* Pass control to the callback, they may turn right around and free the channel, or actually use it */
|
||||
LIBSSH2_X11_OPEN(channel, shost, sport);
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
|
||||
}
|
||||
|
||||
x11_exit:
|
||||
p = packet;
|
||||
*(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
|
||||
libssh2_htonu32(p, sender_channel); p += 4;
|
||||
libssh2_htonu32(p, failure_code); p += 4;
|
||||
libssh2_htonu32(p, sizeof("X11 Forward Unavailable") - 1); p += 4;
|
||||
memcpy(s, "X11 Forward Unavailable", sizeof("X11 Forward Unavailable") - 1); p += sizeof("X11 Forward Unavailable") - 1;
|
||||
libssh2_htonu32(p, 0);
|
||||
|
||||
if (libssh2_packet_write(session, packet, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send open failure", 0);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_packet_new
|
||||
* Create a new packet and attach it to the brigade
|
||||
@@ -49,6 +316,9 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
LIBSSH2_PACKET *packet;
|
||||
unsigned long data_head = 0;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Packet type %d received, length=%d", (int)data[0], (int)datalen);
|
||||
#endif
|
||||
if (macstate == LIBSSH2_MAC_INVALID) {
|
||||
if (session->macerror) {
|
||||
if (LIBSSH2_MACERROR(session, data, datalen) == 0) {
|
||||
@@ -97,6 +367,9 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
if (session->ssh_msg_disconnect) {
|
||||
LIBSSH2_DISCONNECT(session, reason, message, message_len, language, language_len);
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Disconnect(%d): %s(%s)", reason, message, language);
|
||||
#endif
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
|
||||
return -1;
|
||||
@@ -137,6 +410,10 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
if (session->ssh_msg_debug) {
|
||||
LIBSSH2_DEBUG(session, always_display, message, message_len, language, language_len);
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
/* _libssh2_debug will actually truncate this for us so that it's not an inordinate about of data */
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Debug Packet: %s", message);
|
||||
#endif
|
||||
LIBSSH2_FREE(session, data);
|
||||
return 0;
|
||||
}
|
||||
@@ -153,6 +430,29 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
LIBSSH2_FREE(session, data);
|
||||
return 0;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
{
|
||||
unsigned long stream_id = 0;
|
||||
|
||||
if (data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) {
|
||||
stream_id = libssh2_ntohu32(data + 5);
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "%d bytes received for channel %lu/%lu stream #%lu", (int)(datalen - data_head), channel->local.id, channel->remote.id, stream_id);
|
||||
}
|
||||
#endif
|
||||
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 */
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Ignoring extended data and refunding %d bytes", (int)(datalen - 13));
|
||||
#endif
|
||||
/* Adjust the window based on the block we just freed */
|
||||
libssh2_channel_receive_window_adjust(channel, datalen - 13, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* REMEMBER! remote means remote as source of data, NOT remote window! */
|
||||
if (channel->remote.packet_size < (datalen - data_head)) {
|
||||
@@ -160,7 +460,7 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED, "Packet contains more data than we offered to receive, truncating", 0);
|
||||
datalen = channel->remote.packet_size + data_head;
|
||||
}
|
||||
if (channel->remote.window_size_initial && (channel->remote.window_size <= 0)) {
|
||||
if (channel->remote.window_size <= 0) {
|
||||
/* Spec says we MAY ignore bytes sent beyond window_size */
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED, "The current receive window is full, data ignored", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
@@ -169,7 +469,7 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
/* Reset EOF status */
|
||||
channel->remote.eof = 0;
|
||||
|
||||
if (channel->remote.window_size_initial && ((datalen - data_head) > channel->remote.window_size)) {
|
||||
if ((datalen - data_head) > channel->remote.window_size) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED, "Remote sent more data than current window allows, truncating", 0);
|
||||
datalen = channel->remote.window_size + data_head;
|
||||
} else {
|
||||
@@ -188,12 +488,35 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "EOF received for channel %lu/%lu", channel->local.id, channel->remote.id);
|
||||
#endif
|
||||
channel->remote.eof = 1;
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case SSH_MSG_CHANNEL_REQUEST:
|
||||
{
|
||||
if (libssh2_ntohu32(data+5) == sizeof("exit-status") - 1
|
||||
&& !memcmp("exit-status", data + 9, sizeof("exit-status") - 1)) {
|
||||
|
||||
/* we've got "exit-status" packet. Set the session value */
|
||||
LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data+1));
|
||||
|
||||
if (channel) {
|
||||
channel->exit_status = libssh2_ntohu32(data + 9 + sizeof("exit-status"));
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Exit status %lu received for channel %lu/%lu", channel->exit_status, channel->local.id, channel->remote.id);
|
||||
#endif
|
||||
}
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SSH_MSG_CHANNEL_CLOSE:
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1));
|
||||
@@ -203,6 +526,9 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
LIBSSH2_FREE(session, data);
|
||||
return 0;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Close received for channel %lu/%lu", channel->local.id, channel->remote.id);
|
||||
#endif
|
||||
|
||||
channel->remote.close = 1;
|
||||
/* TODO: Add a callback for this */
|
||||
@@ -211,6 +537,40 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case SSH_MSG_CHANNEL_OPEN:
|
||||
if ((datalen >= (sizeof("forwarded-tcpip") + 4)) &&
|
||||
((sizeof("forwarded-tcpip")-1) == libssh2_ntohu32(data + 1)) &&
|
||||
(memcmp(data + 5, "forwarded-tcpip", sizeof("forwarded-tcpip") - 1) == 0)) {
|
||||
int retval = libssh2_packet_queue_listener(session, data, datalen);
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
return retval;
|
||||
}
|
||||
if ((datalen >= (sizeof("x11") + 4)) &&
|
||||
((sizeof("x11")-1) == libssh2_ntohu32(data + 1)) &&
|
||||
(memcmp(data + 5, "x11", sizeof("x11") - 1) == 0)) {
|
||||
int retval = libssh2_packet_x11_open(session, data, datalen);
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
return retval;
|
||||
}
|
||||
break;
|
||||
case SSH_MSG_CHANNEL_WINDOW_ADJUST:
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1));
|
||||
unsigned long bytestoadd = libssh2_ntohu32(data + 5);
|
||||
|
||||
if (channel && bytestoadd) {
|
||||
channel->local.window_size += bytestoadd;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_CONNECTION
|
||||
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Window adjust received for channel %lu/%lu, adding %lu bytes, new window_size=%lu", channel->local.id, channel->remote.id, bytestoadd, channel->local.window_size);
|
||||
#endif
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
packet = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
|
||||
@@ -233,11 +593,14 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
packet->prev = NULL;
|
||||
}
|
||||
|
||||
if (data[0] == SSH_MSG_KEXINIT && !session->exchanging_keys) {
|
||||
if (data[0] == SSH_MSG_KEXINIT && !(session->state & LIBSSH2_STATE_EXCHANGING_KEYS)) {
|
||||
/* Remote wants new keys
|
||||
* Well, it's already in the brigade,
|
||||
* let's just call back into ourselves
|
||||
*/
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Renegotiating Keys");
|
||||
#endif
|
||||
libssh2_kex_exchange(session, 1);
|
||||
/* If there was a key reexchange failure, let's just hope we didn't send NEWKEYS yet, otherwise remote will drop us like a rock */
|
||||
}
|
||||
@@ -252,18 +615,66 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz
|
||||
static int libssh2_blocking_read(LIBSSH2_SESSION *session, unsigned char *buf, size_t count)
|
||||
{
|
||||
size_t bytes_read = 0;
|
||||
#if !defined(HAVE_POLL) && !defined(HAVE_SELECT)
|
||||
int polls = 0;
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
fcntl(session->socket_fd, F_SETFL, 0);
|
||||
#else
|
||||
{
|
||||
u_long block = FALSE;
|
||||
ioctlsocket(session->socket_fd, FIONBIO, &block);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Blocking read: %d bytes", (int)count);
|
||||
#endif
|
||||
|
||||
while (bytes_read < count) {
|
||||
int ret;
|
||||
|
||||
ret = read(session->socket_fd, buf + bytes_read, count - bytes_read);
|
||||
ret = recv(session->socket_fd, buf + bytes_read, count - bytes_read, LIBSSH2_SOCKET_RECV_FLAGS(session));
|
||||
if (ret < 0) {
|
||||
#ifdef WIN32
|
||||
switch (WSAGetLastError()) {
|
||||
case WSAEWOULDBLOCK: errno = EAGAIN; break;
|
||||
case WSAENOTCONN:
|
||||
case WSAENOTSOCK:
|
||||
case WSAECONNABORTED: errno = EBADF; break;
|
||||
case WSAEINTR: errno = EINTR; break;
|
||||
}
|
||||
#endif
|
||||
if (errno == EAGAIN) {
|
||||
#ifdef HAVE_POLL
|
||||
struct pollfd read_socket;
|
||||
|
||||
read_socket.fd = session->socket_fd;
|
||||
read_socket.events = POLLIN;
|
||||
|
||||
if (poll(&read_socket, 1, 30000) <= 0) {
|
||||
return -1;
|
||||
}
|
||||
#elif defined(HAVE_SELECT)
|
||||
fd_set read_socket;
|
||||
struct timeval timeout;
|
||||
|
||||
FD_ZERO(&read_socket);
|
||||
FD_SET(session->socket_fd, &read_socket);
|
||||
|
||||
timeout.tv_sec = 30;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
if (select(session->socket_fd + 1, &read_socket, NULL, NULL, &timeout) <= 0) {
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
if (polls++ > LIBSSH2_SOCKET_POLL_MAXLOOPS) {
|
||||
return -1;
|
||||
}
|
||||
usleep(LIBSSH2_SOCKET_POLL_UDELAY);
|
||||
#endif /* POLL/SELECT/SLEEP */
|
||||
continue;
|
||||
}
|
||||
if (errno == EINTR) {
|
||||
@@ -279,6 +690,10 @@ static int libssh2_blocking_read(LIBSSH2_SESSION *session, unsigned char *buf, s
|
||||
bytes_read += ret;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Blocking read: %d bytes actually read", (int)bytes_read);
|
||||
#endif
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -297,9 +712,23 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
fcntl(session->socket_fd, F_SETFL, O_NONBLOCK);
|
||||
if (session->newkeys) {
|
||||
unsigned char *block, *payload, *s, tmp[6];
|
||||
#else
|
||||
{
|
||||
u_long non_block = TRUE;
|
||||
ioctlsocket(session->socket_fd, FIONBIO, &non_block);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Checking for packet: will%s block", should_block ? "" : " not");
|
||||
#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;
|
||||
unsigned long blocksize = session->remote.crypt->blocksize;
|
||||
unsigned long packet_len, payload_len;
|
||||
@@ -309,24 +738,19 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
||||
/* Safely ignored in CUSTOM cipher mode */
|
||||
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
|
||||
* For now, all blocksize sizes are 8+
|
||||
*/
|
||||
if (should_block) {
|
||||
read_len = libssh2_blocking_read(session, block, blocksize);
|
||||
} else {
|
||||
read_len = read(session->socket_fd, block, 1);
|
||||
read_len = recv(session->socket_fd, block, 1, LIBSSH2_SOCKET_RECV_FLAGS(session));
|
||||
if (read_len <= 0) {
|
||||
LIBSSH2_FREE(session, block);
|
||||
return 0;
|
||||
}
|
||||
read_len += libssh2_blocking_read(session, block + read_len, blocksize - read_len);
|
||||
}
|
||||
if (read_len < blocksize) {
|
||||
LIBSSH2_FREE(session, block);
|
||||
return (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) ? 0 : -1;
|
||||
}
|
||||
|
||||
@@ -336,16 +760,27 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
||||
} else {
|
||||
if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0);
|
||||
LIBSSH2_FREE(session, block);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
packet_len = libssh2_ntohu32(block);
|
||||
padding_len = block[4];
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Processing packet %lu bytes long (with %lu bytes padding)", packet_len, padding_len);
|
||||
#endif
|
||||
memcpy(tmp, block, 5); /* Use this for MAC later */
|
||||
|
||||
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);
|
||||
memcpy(s, block + 5, blocksize - 5);
|
||||
s += blocksize - 5;
|
||||
@@ -353,7 +788,6 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
||||
while ((s - payload) < payload_len) {
|
||||
read_len = libssh2_blocking_read(session, block, blocksize);
|
||||
if (read_len < blocksize) {
|
||||
LIBSSH2_FREE(session, block);
|
||||
LIBSSH2_FREE(session, payload);
|
||||
return -1;
|
||||
}
|
||||
@@ -363,7 +797,6 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
||||
} else {
|
||||
if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0);
|
||||
LIBSSH2_FREE(session, block);
|
||||
LIBSSH2_FREE(session, payload);
|
||||
return -1;
|
||||
}
|
||||
@@ -375,7 +808,6 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
|
||||
|
||||
read_len = libssh2_blocking_read(session, block, session->remote.mac->mac_len);
|
||||
if (read_len < session->remote.mac->mac_len) {
|
||||
LIBSSH2_FREE(session, block);
|
||||
LIBSSH2_FREE(session, payload);
|
||||
return -1;
|
||||
}
|
||||
@@ -384,13 +816,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);
|
||||
|
||||
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++;
|
||||
|
||||
LIBSSH2_FREE(session, block);
|
||||
|
||||
/* Ignore padding */
|
||||
payload_len -= padding_len;
|
||||
|
||||
@@ -404,6 +832,9 @@ if (macstate == LIBSSH2_MAC_INVALID) libssh2_error(session, -255, "EEEK an error
|
||||
LIBSSH2_FREE(session, payload);
|
||||
return -1;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Payload decompressed: %lu bytes(compressed) to %lu bytes(uncompressed)", data_len, payload_len);
|
||||
#endif
|
||||
if (free_payload) {
|
||||
LIBSSH2_FREE(session, payload);
|
||||
payload = data;
|
||||
@@ -423,7 +854,6 @@ if (macstate == LIBSSH2_MAC_INVALID) libssh2_error(session, -255, "EEEK an error
|
||||
payload = LIBSSH2_ALLOC(session, data_len);
|
||||
if (!payload) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for copy of uncompressed data", 0);
|
||||
LIBSSH2_FREE(session, block);
|
||||
return -1;
|
||||
}
|
||||
memcpy(payload, data, data_len);
|
||||
@@ -445,7 +875,7 @@ if (macstate == LIBSSH2_MAC_INVALID) libssh2_error(session, -255, "EEEK an error
|
||||
if (should_block) {
|
||||
buf_len = libssh2_blocking_read(session, buf, 5);
|
||||
} else {
|
||||
buf_len = read(session->socket_fd, buf, 1);
|
||||
buf_len = recv(session->socket_fd, buf, 1, LIBSSH2_SOCKET_RECV_FLAGS(session));
|
||||
if (buf_len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -457,6 +887,9 @@ if (macstate == LIBSSH2_MAC_INVALID) libssh2_error(session, -255, "EEEK an error
|
||||
}
|
||||
packet_length = libssh2_ntohu32(buf);
|
||||
padding_length = buf[4];
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Processing plaintext packet %lu bytes long (with %lu bytes padding)", packet_length, padding_length);
|
||||
#endif
|
||||
|
||||
payload_len = packet_length - padding_length - 1; /* padding_length(1) */
|
||||
payload = LIBSSH2_ALLOC(session, payload_len);
|
||||
@@ -465,8 +898,13 @@ if (macstate == LIBSSH2_MAC_INVALID) libssh2_error(session, -255, "EEEK an error
|
||||
return (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) ? 0 : -1;
|
||||
}
|
||||
while (padding_length) {
|
||||
int l;
|
||||
/* Flush padding */
|
||||
padding_length -= libssh2_blocking_read(session, buf, padding_length);
|
||||
l = libssh2_blocking_read(session, buf, padding_length);
|
||||
if (l > 0)
|
||||
padding_length -= l;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* MACs don't exist in non-encrypted mode */
|
||||
@@ -482,7 +920,7 @@ if (macstate == LIBSSH2_MAC_INVALID) libssh2_error(session, -255, "EEEK an error
|
||||
/* {{{ libssh2_packet_ask
|
||||
* Scan the brigade for a matching packet type, optionally poll the socket for a packet first
|
||||
*/
|
||||
int libssh2_packet_ask_ex(LIBSSH2_SESSION *session, unsigned char packet_type, unsigned char **data, unsigned long *data_len,
|
||||
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)
|
||||
{
|
||||
LIBSSH2_PACKET *packet = session->packets.head;
|
||||
@@ -492,6 +930,9 @@ int libssh2_packet_ask_ex(LIBSSH2_SESSION *session, unsigned char packet_type, u
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Looking for packet of type: %d", (int)packet_type);
|
||||
#endif
|
||||
while (packet) {
|
||||
if (packet->data[0] == packet_type &&
|
||||
(packet->data_len >= (match_ofs + match_len)) &&
|
||||
@@ -521,9 +962,27 @@ int libssh2_packet_ask_ex(LIBSSH2_SESSION *session, unsigned char packet_type, u
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_packet_askv
|
||||
* Scan for any of a list of packet types in the brigade, optionally poll the socket for a packet first
|
||||
*/
|
||||
int libssh2_packet_askv_ex(LIBSSH2_SESSION *session, unsigned char *packet_types, unsigned char **data, unsigned long *data_len,
|
||||
unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len, int poll_socket)
|
||||
{
|
||||
int i, packet_types_len = strlen(packet_types);
|
||||
|
||||
for(i = 0; i < packet_types_len; i++) {
|
||||
if (0 == libssh2_packet_ask_ex(session, packet_types[i], data, data_len, match_ofs, match_buf, match_len, i ? 0 : poll_socket)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_packet_require
|
||||
* Loops libssh2_packet_read() until the packet requested is available
|
||||
* SSH_DISCONNECT will cause a bailout though
|
||||
* SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout
|
||||
*/
|
||||
int libssh2_packet_require_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)
|
||||
@@ -533,6 +992,9 @@ int libssh2_packet_require_ex(LIBSSH2_SESSION *session, unsigned char packet_typ
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Blocking until packet of type %d becomes available", (int)packet_type);
|
||||
#endif
|
||||
while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
|
||||
int ret = libssh2_packet_read(session, 1);
|
||||
if (ret < 0) {
|
||||
@@ -551,6 +1013,39 @@ int libssh2_packet_require_ex(LIBSSH2_SESSION *session, unsigned char packet_typ
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_packet_requirev
|
||||
* Loops libssh2_packet_read() until one of a list of packet types requested is available
|
||||
* SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout
|
||||
* packet_types is a null terminated list of packet_type numbers
|
||||
*/
|
||||
int libssh2_packet_requirev_ex(LIBSSH2_SESSION *session, unsigned char *packet_types, unsigned char **data, unsigned long *data_len,
|
||||
unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len)
|
||||
{
|
||||
if (libssh2_packet_askv_ex(session, packet_types, data, data_len, match_ofs, match_buf, match_len, 0) == 0) {
|
||||
/* One of the packets listed was available in the packet brigade */
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) {
|
||||
int ret = libssh2_packet_read(session, 1);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (ret == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strchr(packet_types, ret)) {
|
||||
/* Be lazy, let packet_ask pull it out of the brigade */
|
||||
return libssh2_packet_askv_ex(session, packet_types, data, data_len, match_ofs, match_buf, match_len, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Only reached if the socket died */
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_packet_write
|
||||
* Send a packet, encrypting it and adding a MAC code if necessary
|
||||
* Returns 0 on success, non-zero on failure
|
||||
@@ -558,22 +1053,42 @@ int libssh2_packet_require_ex(LIBSSH2_SESSION *session, unsigned char packet_typ
|
||||
int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned long data_len)
|
||||
{
|
||||
unsigned long packet_length = data_len + 1;
|
||||
unsigned long block_size = (session->newkeys) ? session->local.crypt->blocksize : 8;
|
||||
unsigned long block_size = (session->state & LIBSSH2_STATE_NEWKEYS) ? session->local.crypt->blocksize : 8;
|
||||
/* At this point packet_length doesn't include the packet_len field itself */
|
||||
unsigned long padding_length;
|
||||
int free_data = 0;
|
||||
unsigned char buf[246]; /* 6 byte header plus max padding size(240) */
|
||||
int i;
|
||||
|
||||
if (session->newkeys &&
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
{
|
||||
/* Show a hint of what's being sent */
|
||||
char excerpt[32];
|
||||
int ex_len = 0, db_ofs = 0;
|
||||
|
||||
for (; ex_len < 24 && db_ofs < data_len; ex_len += 3, db_ofs++) snprintf(excerpt + ex_len, 4, "%02X ", data[db_ofs]);
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Sending packet type %d, length=%lu, %s", (int)data[0], data_len, excerpt);
|
||||
}
|
||||
#endif
|
||||
if ((session->state & LIBSSH2_STATE_NEWKEYS) &&
|
||||
strcmp(session->local.comp->name, "none")) {
|
||||
|
||||
if (session->local.comp->comp(session, 1, &data, &data_len, LIBSSH2_PACKET_MAXCOMP, &free_data, data, data_len, &session->local.comp_abstract)) {
|
||||
return -1;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Compressed payload to %lu bytes", data_len);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
fcntl(session->socket_fd, F_SETFL, 0);
|
||||
#else
|
||||
{
|
||||
u_long non_block = FALSE;
|
||||
ioctlsocket(session->socket_fd, FIONBIO, &non_block);
|
||||
}
|
||||
#endif
|
||||
|
||||
packet_length = data_len + 1; /* padding_length(1) -- MAC doesn't count -- Padding to be added soon */
|
||||
padding_length = block_size - ((packet_length + 4) % block_size);
|
||||
if (padding_length < 4) {
|
||||
@@ -584,13 +1099,11 @@ int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned
|
||||
packet_length += padding_length;
|
||||
libssh2_htonu32(buf, packet_length);
|
||||
buf[4] = padding_length;
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Sending packet with total length %lu (%lu bytes padding)", packet_length, padding_length);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < padding_length; i++) {
|
||||
/* Make random */
|
||||
buf[5 + i] = '\0';
|
||||
}
|
||||
|
||||
if (session->newkeys) {
|
||||
if (session->state & LIBSSH2_STATE_NEWKEYS) {
|
||||
/* Encryption is in effect */
|
||||
unsigned char *encbuf, *s;
|
||||
int ret;
|
||||
@@ -611,7 +1124,7 @@ int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned
|
||||
/* Copy packet to encoding buffer */
|
||||
memcpy(encbuf, buf, 5);
|
||||
memcpy(encbuf + 5, data, data_len);
|
||||
memcpy(encbuf + 5 + data_len, buf + 5, padding_length);
|
||||
RAND_bytes(encbuf + 5 + data_len, padding_length);
|
||||
if (free_data) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
}
|
||||
@@ -632,7 +1145,7 @@ int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned
|
||||
session->local.seqno++;
|
||||
|
||||
/* Send It */
|
||||
ret = ((4 + packet_length + session->local.mac->mac_len) == write(session->socket_fd, encbuf, 4 + packet_length + session->local.mac->mac_len)) ? 0 : -1;
|
||||
ret = ((4 + packet_length + session->local.mac->mac_len) == send(session->socket_fd, encbuf, 4 + packet_length + session->local.mac->mac_len, LIBSSH2_SOCKET_SEND_FLAGS(session))) ? 0 : -1;
|
||||
|
||||
/* Cleanup environment */
|
||||
LIBSSH2_FREE(session, encbuf);
|
||||
|
43
src/scp.c
43
src/scp.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
||||
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -37,7 +37,6 @@
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define LIBSSH2_SCP_RESPONSE_BUFLEN 256
|
||||
@@ -45,7 +44,7 @@
|
||||
/* {{{ libssh2_scp_recv
|
||||
* Open a channel and request a remote file via SCP
|
||||
*/
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *path, struct stat *sb)
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat *sb)
|
||||
{
|
||||
int path_len = strlen(path);
|
||||
unsigned char *command, response[LIBSSH2_SCP_RESPONSE_BUFLEN];
|
||||
@@ -71,11 +70,16 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *pa
|
||||
}
|
||||
command[command_len - 1] = '\0';
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SCP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Opening channel for SCP receive");
|
||||
#endif
|
||||
/* Allocate a channel */
|
||||
if ((channel = libssh2_channel_open_session(session)) == NULL) {
|
||||
LIBSSH2_FREE(session, command);
|
||||
return NULL;
|
||||
}
|
||||
/* Use blocking I/O for negotiation phase */
|
||||
libssh2_channel_set_blocking(channel, 1);
|
||||
|
||||
/* Request SCP for the desired file */
|
||||
if (libssh2_channel_process_startup(channel, "exec", sizeof("exec") - 1, command, command_len)) {
|
||||
@@ -85,6 +89,9 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *pa
|
||||
}
|
||||
LIBSSH2_FREE(session, command);
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SCP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sending initial wakeup");
|
||||
#endif
|
||||
/* SCP ACK */
|
||||
response[0] = '\0';
|
||||
if (libssh2_channel_write(channel, response, 1) != 1) {
|
||||
@@ -196,6 +203,9 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *pa
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_SCP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "mtime = %ld, atime = %ld", mtime, atime);
|
||||
#endif
|
||||
|
||||
/* We *should* check that atime.usec is valid, but why let that stop use? */
|
||||
break;
|
||||
@@ -294,6 +304,9 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *pa
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_SCP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "mod = 0%lo size = %ld", mode, size);
|
||||
#endif
|
||||
|
||||
/* We *should* check that basename is valid, but why let that stop us? */
|
||||
break;
|
||||
@@ -307,7 +320,8 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *pa
|
||||
sb->st_size = size;
|
||||
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;
|
||||
}
|
||||
@@ -316,11 +330,12 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, char *pa
|
||||
/* {{{ libssh2_scp_send_ex
|
||||
* Send a file using SCP
|
||||
*/
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char *path, int mode, size_t size, long mtime, long atime)
|
||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, const char *path, int mode, size_t size, long mtime, long atime)
|
||||
{
|
||||
int path_len = strlen(path);
|
||||
unsigned char *command, *base, response[LIBSSH2_SCP_RESPONSE_BUFLEN];
|
||||
unsigned char *command, response[LIBSSH2_SCP_RESPONSE_BUFLEN];
|
||||
unsigned long response_len, command_len = path_len + sizeof("scp -t ");
|
||||
unsigned const char *base;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
|
||||
if (mtime || atime) {
|
||||
@@ -342,14 +357,21 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char
|
||||
}
|
||||
command[command_len - 1] = '\0';
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_SCP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Opening channel for SCP send");
|
||||
#endif
|
||||
/* Allocate a channel */
|
||||
if ((channel = libssh2_channel_open_session(session)) == NULL) {
|
||||
/* previous call set libssh2_session_last_error(), pass it through */
|
||||
LIBSSH2_FREE(session, command);
|
||||
return NULL;
|
||||
}
|
||||
/* Use blocking I/O for negotiation phase */
|
||||
libssh2_channel_set_blocking(channel, 1);
|
||||
|
||||
/* Request SCP for the desired file */
|
||||
if (libssh2_channel_process_startup(channel, "exec", sizeof("exec") - 1, command, command_len)) {
|
||||
/* previous call set libssh2_session_last_error(), pass it through */
|
||||
LIBSSH2_FREE(session, command);
|
||||
libssh2_channel_free(channel);
|
||||
return NULL;
|
||||
@@ -366,6 +388,9 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char
|
||||
/* Send mtime and atime to be used for file */
|
||||
if (mtime || atime) {
|
||||
response_len = snprintf(response, LIBSSH2_SCP_RESPONSE_BUFLEN, "T%ld 0 %ld 0\n", mtime, atime);
|
||||
#ifdef LIBSSH2_DEBUG_SCP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s", response);
|
||||
#endif
|
||||
if (libssh2_channel_write(channel, response, response_len) != response_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send time data for SCP file", 0);
|
||||
libssh2_channel_free(channel);
|
||||
@@ -388,6 +413,9 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char
|
||||
}
|
||||
|
||||
response_len = snprintf(response, LIBSSH2_SCP_RESPONSE_BUFLEN, "C0%o %lu %s\n", mode, (unsigned long)size, base);
|
||||
#ifdef LIBSSH2_DEBUG_SCP
|
||||
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s", response);
|
||||
#endif
|
||||
if (libssh2_channel_write(channel, response, response_len) != response_len) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send core file data for SCP file", 0);
|
||||
libssh2_channel_free(channel);
|
||||
@@ -400,7 +428,8 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, char
|
||||
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;
|
||||
}
|
||||
|
670
src/session.c
670
src/session.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
||||
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -37,9 +37,31 @@
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include <errno.h>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
#include <sys/time.h>
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POLL
|
||||
# include <sys/poll.h>
|
||||
#else
|
||||
# ifdef HAVE_SELECT
|
||||
# ifdef HAVE_SYS_SELECT_H
|
||||
# include <sys/select.h>
|
||||
# else
|
||||
# include <sys/time.h>
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* {{{ libssh2_default_alloc
|
||||
*/
|
||||
static LIBSSH2_ALLOC_FUNC(libssh2_default_alloc)
|
||||
@@ -79,7 +101,7 @@ static int libssh2_banner_receive(LIBSSH2_SESSION *session)
|
||||
char c = '\0';
|
||||
int ret;
|
||||
|
||||
ret = read(session->socket_fd, &c, 1);
|
||||
ret = recv(session->socket_fd, &c, 1, LIBSSH2_SOCKET_RECV_FLAGS(session));
|
||||
|
||||
if ((ret < 0) && (ret != EAGAIN)) {
|
||||
/* Some kinda error, but don't break for non-blocking issues */
|
||||
@@ -106,6 +128,9 @@ static int libssh2_banner_receive(LIBSSH2_SESSION *session)
|
||||
session->remote.banner = LIBSSH2_ALLOC(session, banner_len + 1);
|
||||
memcpy(session->remote.banner, banner, banner_len);
|
||||
session->remote.banner[banner_len] = '\0';
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Received Banner: %s", session->remote.banner);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -123,8 +148,59 @@ static int libssh2_banner_send(LIBSSH2_SESSION *session)
|
||||
banner_len = strlen(session->local.banner);
|
||||
banner = session->local.banner;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
{
|
||||
/* Hack and slash to avoid sending CRLF in debug output */
|
||||
char banner_dup[256];
|
||||
|
||||
return (write(session->socket_fd, banner, banner_len) == banner_len) ? 0 : 1;
|
||||
if (banner_len < 256) {
|
||||
memcpy(banner_dup, banner, banner_len - 2);
|
||||
banner_dup[banner_len - 2] = '\0';
|
||||
} else {
|
||||
memcpy(banner_dup, banner, 255);
|
||||
banner[255] = '\0';
|
||||
}
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Sending Banner: %s", banner_dup);
|
||||
}
|
||||
#endif
|
||||
|
||||
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, const 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);
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
session->local.banner[banner_len] = '\0';
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Setting local Banner: %s", session->local.banner);
|
||||
#endif
|
||||
session->local.banner[banner_len++] = '\r';
|
||||
session->local.banner[banner_len++] = '\n';
|
||||
session->local.banner[banner_len++] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -155,11 +231,57 @@ LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(
|
||||
session->free = local_free;
|
||||
session->realloc = local_realloc;
|
||||
session->abstract = abstract;
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "New session resource allocated");
|
||||
#endif
|
||||
|
||||
return session;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ 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;
|
||||
}
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Setting Callback %d", cbtype);
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto libssh2_session_startup
|
||||
* session: LIBSSH2_SESSION struct allocated and owned by the calling program
|
||||
* Returns: 0 on success, or non-zero on failure
|
||||
@@ -173,6 +295,9 @@ LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket)
|
||||
unsigned char service[sizeof("ssh-userauth") + 5 - 1];
|
||||
unsigned long service_length;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "session_startup for socket %d", socket);
|
||||
#endif
|
||||
if (socket <= 0) {
|
||||
/* Did we forget something? */
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_NONE, "No socket provided", 0);
|
||||
@@ -181,6 +306,11 @@ LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket)
|
||||
session->socket_fd = socket;
|
||||
|
||||
/* TODO: Liveness check */
|
||||
if (libssh2_banner_send(session)) {
|
||||
/* Unable to send banner? */
|
||||
libssh2_error(session, LIBSSH2_ERROR_BANNER_SEND, "Error sending banner to remote host", 0);
|
||||
return LIBSSH2_ERROR_BANNER_SEND;
|
||||
}
|
||||
|
||||
if (libssh2_banner_receive(session)) {
|
||||
/* Unable to receive banner from remote */
|
||||
@@ -188,17 +318,14 @@ LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket)
|
||||
return LIBSSH2_ERROR_BANNER_NONE;
|
||||
}
|
||||
|
||||
if (libssh2_banner_send(session)) {
|
||||
/* Unable to send banner? */
|
||||
libssh2_error(session, LIBSSH2_ERROR_BANNER_SEND, "Error sending banner to remote host", 0);
|
||||
return LIBSSH2_ERROR_BANNER_SEND;
|
||||
}
|
||||
|
||||
if (libssh2_kex_exchange(session, 0)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE, "Unable to exchange encryption keys", 0);
|
||||
return LIBSSH2_ERROR_KEX_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Requesting userauth service");
|
||||
#endif
|
||||
/* Request the userauth service */
|
||||
service[0] = SSH_MSG_SERVICE_REQUEST;
|
||||
libssh2_htonu32(service + 1, sizeof("ssh-userauth") - 1);
|
||||
@@ -231,6 +358,9 @@ LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket)
|
||||
*/
|
||||
LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
|
||||
{
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Freeing session resource", session->remote.banner);
|
||||
#endif
|
||||
while (session->channels.head) {
|
||||
LIBSSH2_CHANNEL *tmp = session->channels.head;
|
||||
|
||||
@@ -249,7 +379,11 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
|
||||
}
|
||||
}
|
||||
|
||||
if (session->newkeys) {
|
||||
while (session->listeners) {
|
||||
libssh2_channel_forward_cancel(session->listeners);
|
||||
}
|
||||
|
||||
if (session->state & LIBSSH2_STATE_NEWKEYS) {
|
||||
/* hostkey */
|
||||
if (session->hostkey && session->hostkey->dtor) {
|
||||
session->hostkey->dtor(session, &session->server_hostkey_abstract);
|
||||
@@ -303,6 +437,7 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
|
||||
}
|
||||
}
|
||||
|
||||
/* Free banner(s) */
|
||||
if (session->remote.banner) {
|
||||
LIBSSH2_FREE(session, session->remote.banner);
|
||||
}
|
||||
@@ -310,6 +445,40 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
|
||||
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 */
|
||||
while (session->packets.head) {
|
||||
LIBSSH2_PACKET *tmp = session->packets.head;
|
||||
@@ -322,21 +491,20 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
|
||||
LIBSSH2_FREE(session, tmp);
|
||||
}
|
||||
|
||||
if (session->local.banner) {
|
||||
LIBSSH2_FREE(session, session->local.banner);
|
||||
}
|
||||
|
||||
LIBSSH2_FREE(session, session);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ 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, const char *description, const char *lang)
|
||||
{
|
||||
unsigned char *data;
|
||||
unsigned char *s, *data;
|
||||
unsigned long data_len, descr_len = 0, lang_len = 0;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_TRANSPORT
|
||||
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Disconnecting: reason=%d, desc=%s, lang=%s", reason, description, lang);
|
||||
#endif
|
||||
if (description) {
|
||||
descr_len = strlen(description);
|
||||
}
|
||||
@@ -345,28 +513,454 @@ 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 = LIBSSH2_ALLOC(session, data_len);
|
||||
if (data) {
|
||||
unsigned char *s = 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);
|
||||
s = data = LIBSSH2_ALLOC(session, data_len);
|
||||
if (!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);
|
||||
|
||||
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 const 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;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_poll_channel_read
|
||||
* Returns 0 if no data is waiting on channel,
|
||||
* non-0 if data is available
|
||||
*/
|
||||
LIBSSH2_API int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended)
|
||||
{
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
LIBSSH2_PACKET *packet = session->packets.head;
|
||||
|
||||
while (packet) {
|
||||
if (((packet->data[0] == SSH_MSG_CHANNEL_DATA) && (extended == 0) && (channel->local.id == libssh2_ntohu32(packet->data + 1))) ||
|
||||
((packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) && (extended != 0) && (channel->local.id == libssh2_ntohu32(packet->data + 1)))) {
|
||||
/* Found data waiting to be read */
|
||||
return 1;
|
||||
}
|
||||
packet = packet->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_poll_channel_write
|
||||
* Returns 0 if writing to channel would block,
|
||||
* non-0 if data can be written without blocking
|
||||
*/
|
||||
inline int libssh2_poll_channel_write(LIBSSH2_CHANNEL *channel)
|
||||
{
|
||||
return channel->local.window_size ? 1 : 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_poll_listener_queued
|
||||
* Returns 0 if no connections are waiting to be accepted
|
||||
* non-0 if one or more connections are available
|
||||
*/
|
||||
inline int libssh2_poll_listener_queued(LIBSSH2_LISTENER *listener)
|
||||
{
|
||||
return listener->queue ? 1 : 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_poll
|
||||
* Poll sockets, channels, and listeners for activity
|
||||
*/
|
||||
LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout)
|
||||
{
|
||||
long timeout_remaining;
|
||||
int i, active_fds;
|
||||
#ifdef HAVE_POLL
|
||||
LIBSSH2_SESSION *session = NULL;
|
||||
struct pollfd sockets[nfds];
|
||||
|
||||
/* Setup sockets for polling */
|
||||
for(i = 0; i < nfds; i++) {
|
||||
fds[i].revents = 0;
|
||||
switch (fds[i].type) {
|
||||
case LIBSSH2_POLLFD_SOCKET:
|
||||
sockets[i].fd = fds[i].fd.socket;
|
||||
sockets[i].events = fds[i].events;
|
||||
sockets[i].revents = 0;
|
||||
break;
|
||||
case LIBSSH2_POLLFD_CHANNEL:
|
||||
sockets[i].fd = fds[i].fd.channel->session->socket_fd;
|
||||
sockets[i].events = POLLIN;
|
||||
sockets[i].revents = 0;
|
||||
if (!session) session = fds[i].fd.channel->session;
|
||||
break;
|
||||
case LIBSSH2_POLLFD_LISTENER:
|
||||
sockets[i].fd = fds[i].fd.listener->session->socket_fd;
|
||||
sockets[i].events = POLLIN;
|
||||
sockets[i].revents = 0;
|
||||
if (!session) session = fds[i].fd.listener->session;
|
||||
break;
|
||||
default:
|
||||
if (session) libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE, "Invalid descriptor passed to libssh2_poll()", 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#elif defined(HAVE_SELECT)
|
||||
LIBSSH2_SESSION *session = NULL;
|
||||
int maxfd = 0;
|
||||
fd_set rfds,wfds;
|
||||
struct timeval tv;
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&wfds);
|
||||
for(i = 0; i < nfds; i++) {
|
||||
fds[i].revents = 0;
|
||||
switch (fds[i].type) {
|
||||
case LIBSSH2_POLLFD_SOCKET:
|
||||
if (fds[i].events & LIBSSH2_POLLFD_POLLIN) {
|
||||
FD_SET(fds[i].fd.socket, &rfds);
|
||||
if (fds[i].fd.socket > maxfd) maxfd = fds[i].fd.socket;
|
||||
}
|
||||
if (fds[i].events & LIBSSH2_POLLFD_POLLOUT) {
|
||||
FD_SET(fds[i].fd.socket, &wfds);
|
||||
if (fds[i].fd.socket > maxfd) maxfd = fds[i].fd.socket;
|
||||
}
|
||||
break;
|
||||
case LIBSSH2_POLLFD_CHANNEL:
|
||||
FD_SET(fds[i].fd.channel->session->socket_fd, &rfds);
|
||||
if (fds[i].fd.channel->session->socket_fd > maxfd) maxfd = fds[i].fd.channel->session->socket_fd;
|
||||
if (!session) session = fds[i].fd.channel->session;
|
||||
break;
|
||||
case LIBSSH2_POLLFD_LISTENER:
|
||||
FD_SET(fds[i].fd.listener->session->socket_fd, &rfds);
|
||||
if (fds[i].fd.listener->session->socket_fd > maxfd) maxfd = fds[i].fd.listener->session->socket_fd;
|
||||
if (!session) session = fds[i].fd.listener->session;
|
||||
break;
|
||||
default:
|
||||
if (session) libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE, "Invalid descriptor passed to libssh2_poll()", 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* No select() or poll()
|
||||
* no sockets sturcture to setup
|
||||
*/
|
||||
|
||||
timeout = 0;
|
||||
#endif /* HAVE_POLL or HAVE_SELECT */
|
||||
|
||||
timeout_remaining = timeout;
|
||||
do {
|
||||
#if defined(HAVE_POLL) || defined(HAVE_SELECT)
|
||||
int sysret;
|
||||
#endif
|
||||
|
||||
active_fds = 0;
|
||||
|
||||
for (i = 0; i < nfds; i++) {
|
||||
if (fds[i].events != fds[i].revents) {
|
||||
switch (fds[i].type) {
|
||||
case LIBSSH2_POLLFD_CHANNEL:
|
||||
if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) && /* Want to be ready for read */
|
||||
((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) { /* Not yet known to be ready for read */
|
||||
fds[i].revents |= libssh2_poll_channel_read(fds[i].fd.channel, 0) ? LIBSSH2_POLLFD_POLLIN : 0;
|
||||
}
|
||||
if ((fds[i].events & LIBSSH2_POLLFD_POLLEXT) && /* Want to be ready for extended read */
|
||||
((fds[i].revents & LIBSSH2_POLLFD_POLLEXT) == 0)) { /* Not yet known to be ready for extended read */
|
||||
fds[i].revents |= libssh2_poll_channel_read(fds[i].fd.channel, 1) ? LIBSSH2_POLLFD_POLLEXT : 0;
|
||||
}
|
||||
if ((fds[i].events & LIBSSH2_POLLFD_POLLOUT) && /* Want to be ready for write */
|
||||
((fds[i].revents & LIBSSH2_POLLFD_POLLOUT) == 0)) { /* Not yet known to be ready for write */
|
||||
fds[i].revents |= libssh2_poll_channel_write(fds[i].fd.channel) ? LIBSSH2_POLLFD_POLLOUT : 0;
|
||||
}
|
||||
if (fds[i].fd.channel->remote.close || fds[i].fd.channel->local.close) {
|
||||
fds[i].revents |= LIBSSH2_POLLFD_CHANNEL_CLOSED;
|
||||
}
|
||||
if (fds[i].fd.channel->session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
|
||||
fds[i].revents |= LIBSSH2_POLLFD_CHANNEL_CLOSED | LIBSSH2_POLLFD_SESSION_CLOSED;
|
||||
}
|
||||
break;
|
||||
case LIBSSH2_POLLFD_LISTENER:
|
||||
if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) && /* Want a connection */
|
||||
((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) { /* No connections known of yet */
|
||||
fds[i].revents |= libssh2_poll_listener_queued(fds[i].fd.listener) ? LIBSSH2_POLLFD_POLLIN : 0;
|
||||
}
|
||||
if (fds[i].fd.listener->session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
|
||||
fds[i].revents |= LIBSSH2_POLLFD_LISTENER_CLOSED | LIBSSH2_POLLFD_SESSION_CLOSED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fds[i].revents) {
|
||||
active_fds++;
|
||||
}
|
||||
}
|
||||
|
||||
if (active_fds) {
|
||||
/* Don't block on the sockets if we have channels/listeners which are ready */
|
||||
timeout_remaining = 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_POLL
|
||||
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
{
|
||||
struct timeval tv_begin, tv_end;
|
||||
|
||||
gettimeofday((struct timeval *)&tv_begin, NULL);
|
||||
sysret = poll(sockets, nfds, timeout_remaining);
|
||||
gettimeofday((struct timeval *)&tv_end, NULL);
|
||||
timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
|
||||
timeout_remaining -= ceil((tv_end.tv_usec - tv_begin.tv_usec) / 1000);
|
||||
}
|
||||
#else
|
||||
/* If the platform doesn't support gettimeofday,
|
||||
* then just make the call non-blocking and walk away
|
||||
*/
|
||||
sysret = poll(sockets, nfds, timeout_remaining);
|
||||
timeout_remaining = 0;
|
||||
#endif /* HAVE_GETTIMEOFDAY */
|
||||
|
||||
if (sysret > 0) {
|
||||
for (i = 0; i < nfds; i++) {
|
||||
switch (fds[i].type) {
|
||||
case LIBSSH2_POLLFD_SOCKET:
|
||||
fds[i].revents = sockets[i].revents;
|
||||
sockets[i].revents = 0; /* In case we loop again, be nice */
|
||||
if (fds[i].revents) {
|
||||
active_fds++;
|
||||
}
|
||||
break;
|
||||
case LIBSSH2_POLLFD_CHANNEL:
|
||||
if (sockets[i].events & POLLIN) {
|
||||
/* Spin session until no data available */
|
||||
while (libssh2_packet_read(fds[i].fd.channel->session, 0) > 0);
|
||||
}
|
||||
if (sockets[i].revents & POLLHUP) {
|
||||
fds[i].revents |= LIBSSH2_POLLFD_CHANNEL_CLOSED | LIBSSH2_POLLFD_SESSION_CLOSED;
|
||||
}
|
||||
sockets[i].revents = 0;
|
||||
break;
|
||||
case LIBSSH2_POLLFD_LISTENER:
|
||||
if (sockets[i].events & POLLIN) {
|
||||
/* Spin session until no data available */
|
||||
while (libssh2_packet_read(fds[i].fd.listener->session, 0) > 0);
|
||||
}
|
||||
if (sockets[i].revents & POLLHUP) {
|
||||
fds[i].revents |= LIBSSH2_POLLFD_LISTENER_CLOSED | LIBSSH2_POLLFD_SESSION_CLOSED;
|
||||
}
|
||||
sockets[i].revents = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined(HAVE_SELECT)
|
||||
tv.tv_sec = timeout_remaining / 1000;
|
||||
tv.tv_usec = (timeout_remaining % 1000) * 1000;
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
{
|
||||
struct timeval tv_begin, tv_end;
|
||||
|
||||
gettimeofday((struct timeval *)&tv_begin, NULL);
|
||||
sysret = select(maxfd, &rfds, &wfds, NULL, &tv);
|
||||
gettimeofday((struct timeval *)&tv_end, NULL);
|
||||
|
||||
timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
|
||||
timeout_remaining -= ceil((tv_end.tv_usec - tv_begin.tv_usec) / 1000);
|
||||
}
|
||||
#else
|
||||
/* If the platform doesn't support gettimeofday,
|
||||
* then just make the call non-blocking and walk away
|
||||
*/
|
||||
sysret = select(maxfd, &rfds, &wfds, NULL, &tv);
|
||||
timeout_remaining = 0;
|
||||
#endif
|
||||
|
||||
if (sysret > 0) {
|
||||
for (i = 0; i < nfds; i++) {
|
||||
switch (fds[i].type) {
|
||||
case LIBSSH2_POLLFD_SOCKET:
|
||||
if (FD_ISSET(fds[i].fd.socket, &rfds)) {
|
||||
fds[i].revents |= LIBSSH2_POLLFD_POLLIN;
|
||||
}
|
||||
if (FD_ISSET(fds[i].fd.socket, &wfds)) {
|
||||
fds[i].revents |= LIBSSH2_POLLFD_POLLOUT;
|
||||
}
|
||||
if (fds[i].revents) {
|
||||
active_fds++;
|
||||
}
|
||||
break;
|
||||
case LIBSSH2_POLLFD_CHANNEL:
|
||||
if (FD_ISSET(fds[i].fd.channel->session->socket_fd, &rfds)) {
|
||||
/* Spin session until no data available */
|
||||
while (libssh2_packet_read(fds[i].fd.channel->session, 0) > 0);
|
||||
}
|
||||
break;
|
||||
case LIBSSH2_POLLFD_LISTENER:
|
||||
if (FD_ISSET(fds[i].fd.listener->session->socket_fd, &rfds)) {
|
||||
/* Spin session until no data available */
|
||||
while (libssh2_packet_read(fds[i].fd.listener->session, 0) > 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* else no select() or poll() -- timeout (and by extension timeout_remaining) will be equal to 0 */
|
||||
} while ((timeout_remaining > 0) && !active_fds);
|
||||
|
||||
return active_fds;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
1471
src/sftp.c
Normal file
1471
src/sftp.c
Normal file
File diff suppressed because it is too large
Load Diff
640
src/userauth.c
640
src/userauth.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2004, Sara Golemon <sarag@users.sourceforge.net>
|
||||
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -36,7 +36,12 @@
|
||||
*/
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include <stdio.h>
|
||||
|
||||
/* Needed for struct iovec on some platforms */
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* {{{ proto libssh2_userauth_list
|
||||
* List authentication methods
|
||||
@@ -44,8 +49,9 @@
|
||||
* Not a common configuration for any SSH server though
|
||||
* username should be NULL, or a null terminated string
|
||||
*/
|
||||
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username, int username_len)
|
||||
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, const char *username, int username_len)
|
||||
{
|
||||
unsigned char reply_codes[3] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
|
||||
unsigned long data_len = username_len + 31; /* packet_type(1) + username_len(4) + service_len(4) + service(14)"ssh-connection" +
|
||||
method_len(4) + method(4)"none" */
|
||||
unsigned long methods_len;
|
||||
@@ -76,25 +82,23 @@ LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username
|
||||
}
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
while (1) {
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_SUCCESS, &data, &data_len, 1) == 0) {
|
||||
/* Wow, who'dve thought... */
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->authenticated = 1;
|
||||
return NULL;
|
||||
}
|
||||
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_FAILURE, &data, &data_len, 0) == 0) {
|
||||
/* What we *actually* wanted to happen */
|
||||
break;
|
||||
}
|
||||
/* TODO: Timeout? */
|
||||
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
/* Wow, who'dve thought... */
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
methods_len = libssh2_ntohu32(data + 1);
|
||||
memcpy(data, data + 5, methods_len);
|
||||
data[methods_len] = '\0';
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Permitted auth methods: %s", data);
|
||||
#endif
|
||||
return data;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -105,18 +109,18 @@ LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, char *username
|
||||
*/
|
||||
LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session)
|
||||
{
|
||||
return session->authenticated;
|
||||
return session->state & LIBSSH2_STATE_AUTHENTICATED;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_userauth_password
|
||||
* Plain ol' login
|
||||
*/
|
||||
LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, char *username, int username_len,
|
||||
char *password, int password_len,
|
||||
LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *username, int username_len,
|
||||
const char *password, int password_len,
|
||||
LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)))
|
||||
{
|
||||
unsigned char *data, *s;
|
||||
unsigned char *data, *s, reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 0 };
|
||||
unsigned long data_len = username_len + password_len + 40; /* packet_type(1) + username_len(4) + service_len(4) + service(14)"ssh-connection" +
|
||||
method_len(4) + method(8)"password" + chgpwdbool(1) + password_len(4) */
|
||||
|
||||
@@ -141,6 +145,9 @@ LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, char *use
|
||||
libssh2_htonu32(s, password_len); s += 4;
|
||||
memcpy(s, password, password_len); s += password_len;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting to login using password authentication");
|
||||
#endif
|
||||
if (libssh2_packet_write(session, data, data_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-password request", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
@@ -148,71 +155,78 @@ LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, char *use
|
||||
}
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
while (1) {
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_SUCCESS, &data, &data_len, 1) == 0) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->authenticated = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_FAILURE, &data, &data_len, 0) == 0) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, &data, &data_len, 0) == 0) {
|
||||
char *newpw = NULL;
|
||||
int newpw_len = 0;
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
if (passwd_change_cb) {
|
||||
passwd_change_cb(session, &newpw, &newpw_len, &session->abstract);
|
||||
if (!newpw) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED, "Password expired, and callback failed", 0);
|
||||
return -1;
|
||||
}
|
||||
data_len = username_len + password_len + 44 + newpw_len; /* basic data_len + newpw_len(4) */
|
||||
s = data = LIBSSH2_ALLOC(session, data_len);
|
||||
if (!data) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for userauth-password-change request", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*(s++) = SSH_MSG_USERAUTH_REQUEST;
|
||||
libssh2_htonu32(s, username_len); s += 4;
|
||||
memcpy(s, username, username_len); s += username_len;
|
||||
|
||||
libssh2_htonu32(s, sizeof("ssh-connection") - 1); s += 4;
|
||||
memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1); s += sizeof("ssh-connection") - 1;
|
||||
|
||||
libssh2_htonu32(s, sizeof("password") - 1); s += 4;
|
||||
memcpy(s, "password", sizeof("password") - 1); s += sizeof("password") - 1;
|
||||
|
||||
*s = 0xFF; s++;
|
||||
|
||||
libssh2_htonu32(s, password_len); s += 4;
|
||||
memcpy(s, password, password_len); s += password_len;
|
||||
|
||||
libssh2_htonu32(s, newpw_len); s += 4;
|
||||
memcpy(s, newpw, newpw_len); s += newpw_len;
|
||||
|
||||
if (libssh2_packet_write(session, data, data_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-password-change request", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, data);
|
||||
LIBSSH2_FREE(session, newpw);
|
||||
/* TODO: Reset timeout? */
|
||||
} else {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED, "Password Expired, and no callback specified", 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* TODO: Timeout? */
|
||||
password_response:
|
||||
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Password authentication successful");
|
||||
#endif
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data[0] == SSH_MSG_USERAUTH_PASSWD_CHANGEREQ) {
|
||||
char *newpw = NULL;
|
||||
int newpw_len = 0;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Password change required");
|
||||
#endif
|
||||
LIBSSH2_FREE(session, data);
|
||||
if (passwd_change_cb) {
|
||||
passwd_change_cb(session, &newpw, &newpw_len, &session->abstract);
|
||||
if (!newpw) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED, "Password expired, and callback failed", 0);
|
||||
return -1;
|
||||
}
|
||||
data_len = username_len + password_len + 44 + newpw_len; /* basic data_len + newpw_len(4) */
|
||||
s = data = LIBSSH2_ALLOC(session, data_len);
|
||||
if (!data) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for userauth-password-change request", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*(s++) = SSH_MSG_USERAUTH_REQUEST;
|
||||
libssh2_htonu32(s, username_len); s += 4;
|
||||
memcpy(s, username, username_len); s += username_len;
|
||||
|
||||
libssh2_htonu32(s, sizeof("ssh-connection") - 1); s += 4;
|
||||
memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1); s += sizeof("ssh-connection") - 1;
|
||||
|
||||
libssh2_htonu32(s, sizeof("password") - 1); s += 4;
|
||||
memcpy(s, "password", sizeof("password") - 1); s += sizeof("password") - 1;
|
||||
|
||||
*s = 0xFF; s++;
|
||||
|
||||
libssh2_htonu32(s, password_len); s += 4;
|
||||
memcpy(s, password, password_len); s += password_len;
|
||||
|
||||
libssh2_htonu32(s, newpw_len); s += 4;
|
||||
memcpy(s, newpw, newpw_len); s += newpw_len;
|
||||
|
||||
if (libssh2_packet_write(session, data, data_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-password-change request", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, data);
|
||||
LIBSSH2_FREE(session, newpw);
|
||||
|
||||
/* Ugliest use of goto ever. Blame it on the askN => requirev migration. */
|
||||
goto password_response;
|
||||
} else {
|
||||
libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED, "Password Expired, and no callback specified", 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* FAILURE */
|
||||
LIBSSH2_FREE(session, data);
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -221,12 +235,15 @@ LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, char *use
|
||||
*/
|
||||
static int libssh2_file_read_publickey(LIBSSH2_SESSION *session, unsigned char **method, unsigned long *method_len,
|
||||
unsigned char **pubkeydata, unsigned long *pubkeydata_len,
|
||||
char *pubkeyfile)
|
||||
const char *pubkeyfile)
|
||||
{
|
||||
FILE *fd;
|
||||
char *pubkey = NULL, c, *sp1, *sp2, *tmp;
|
||||
int pubkey_len = 0, tmp_len;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Loading public key file: %s", pubkeyfile);
|
||||
#endif
|
||||
/* Read Public Key */
|
||||
fd = fopen(pubkeyfile, "r");
|
||||
if (!fd) {
|
||||
@@ -293,15 +310,18 @@ static int libssh2_file_read_publickey(LIBSSH2_SESSION *session, unsigned char *
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_file_read_publickey
|
||||
/* {{{ libssh2_file_read_privatekey
|
||||
* Read a PEM encoded private key from an id_??? style file
|
||||
*/
|
||||
static int libssh2_file_read_privatekey(LIBSSH2_SESSION *session, LIBSSH2_HOSTKEY_METHOD **hostkey_method, void **hostkey_abstract,
|
||||
char *method, int method_len,
|
||||
char *privkeyfile, char *passphrase)
|
||||
const char *method, int method_len,
|
||||
const char *privkeyfile, const 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();
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Loading private key file: %s", privkeyfile);
|
||||
#endif
|
||||
*hostkey_method = NULL;
|
||||
*hostkey_abstract = NULL;
|
||||
while (*hostkey_methods_avail && (*hostkey_methods_avail)->name) {
|
||||
@@ -326,19 +346,151 @@ static int libssh2_file_read_privatekey(LIBSSH2_SESSION *session, LIBSSH2_HOSTKE
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_userauth_publickey_fromfile_ex
|
||||
/* {{{ libssh2_userauth_hostbased_fromfile_ex
|
||||
* Authenticate using a keypair found in the named files
|
||||
*/
|
||||
LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, char *username, int username_len,
|
||||
char *publickey, char *privatekey,
|
||||
char *passphrase)
|
||||
LIBSSH2_API int libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, const char *username, int username_len,
|
||||
const char *publickey, const char *privatekey,
|
||||
const char *passphrase,
|
||||
const char *hostname, int hostname_len,
|
||||
const char *local_username, int local_username_len)
|
||||
{
|
||||
LIBSSH2_HOSTKEY_METHOD *privkeyobj;
|
||||
void *abstract;
|
||||
unsigned char buf[5];
|
||||
struct iovec datavec[4];
|
||||
unsigned char *method, *pubkeydata, *packet, *s, *b, *sig;
|
||||
unsigned long method_len, pubkeydata_len, packet_len, sig_len;
|
||||
unsigned char *method, *pubkeydata, *packet, *s, *sig, *data, reply_codes[3] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
|
||||
unsigned long method_len, pubkeydata_len, packet_len, sig_len, data_len;
|
||||
|
||||
if (libssh2_file_read_publickey(session, &method, &method_len, &pubkeydata, &pubkeydata_len, publickey)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
packet_len = username_len + method_len + hostname_len + local_username_len + pubkeydata_len + 48;
|
||||
/* packet_type(1) + username_len(4) + servicename_len(4) + service_name(14)"ssh-connection" +
|
||||
* authmethod_len(4) + authmethod(9)"hostbased" + method_len(4) + pubkeydata_len(4) +
|
||||
* local_username_len(4)
|
||||
*/
|
||||
/* Preallocate space for an overall length, method name again,
|
||||
* and the signature, which won't be any larger than the size of the publickeydata itself */
|
||||
s = packet = LIBSSH2_ALLOC(session, packet_len + 4 + (4 + method_len) + (4 + pubkeydata_len));
|
||||
|
||||
*(s++) = SSH_MSG_USERAUTH_REQUEST;
|
||||
libssh2_htonu32(s, username_len); s += 4;
|
||||
memcpy(s, username, username_len); s += username_len;
|
||||
|
||||
libssh2_htonu32(s, 14); s += 4;
|
||||
memcpy(s, "ssh-connection", 14); s += 14;
|
||||
|
||||
libssh2_htonu32(s, 9); s += 4;
|
||||
memcpy(s, "hostbased", 9); s += 9;
|
||||
|
||||
libssh2_htonu32(s, method_len); s += 4;
|
||||
memcpy(s, method, method_len); s += method_len;
|
||||
|
||||
libssh2_htonu32(s, pubkeydata_len); s += 4;
|
||||
memcpy(s, pubkeydata, pubkeydata_len); s += pubkeydata_len;
|
||||
|
||||
libssh2_htonu32(s, hostname_len); s += 4;
|
||||
memcpy(s, hostname, hostname_len); s += hostname_len;
|
||||
|
||||
libssh2_htonu32(s, local_username_len); s += 4;
|
||||
memcpy(s, local_username, local_username_len); s += local_username_len;
|
||||
|
||||
if (libssh2_file_read_privatekey(session, &privkeyobj, &abstract, method, method_len, privatekey, passphrase)) {
|
||||
LIBSSH2_FREE(session, method);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
|
||||
libssh2_htonu32(buf, session->session_id_len);
|
||||
datavec[0].iov_base = buf;
|
||||
datavec[0].iov_len = 4;
|
||||
datavec[1].iov_base = session->session_id;
|
||||
datavec[1].iov_len = session->session_id_len;
|
||||
datavec[2].iov_base = packet;
|
||||
datavec[2].iov_len = packet_len;
|
||||
|
||||
if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) {
|
||||
LIBSSH2_FREE(session, method);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
if (privkeyobj->dtor) {
|
||||
privkeyobj->dtor(session, &abstract);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (privkeyobj->dtor) {
|
||||
privkeyobj->dtor(session, &abstract);
|
||||
}
|
||||
|
||||
if (sig_len > pubkeydata_len ) {
|
||||
/* Should *NEVER* happen, but...well.. better safe than sorry */
|
||||
packet = LIBSSH2_REALLOC(session, packet, packet_len + 4 + (4 + method_len) + (4 + sig_len)); /* PK sigblob */
|
||||
if (!packet) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Failed allocating additional space for userauth-hostbased packet", 0);
|
||||
LIBSSH2_FREE(session, method);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
s = packet + packet_len;
|
||||
|
||||
libssh2_htonu32(s, 4 + method_len + 4 + sig_len); s += 4;
|
||||
|
||||
libssh2_htonu32(s, method_len); s += 4;
|
||||
memcpy(s, method, method_len); s += method_len;
|
||||
LIBSSH2_FREE(session, method);
|
||||
|
||||
libssh2_htonu32(s, sig_len); s += 4;
|
||||
memcpy(s, sig, sig_len); s += sig_len;
|
||||
LIBSSH2_FREE(session, sig);
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting hostbased authentication");
|
||||
#endif
|
||||
if (libssh2_packet_write(session, packet, s - packet)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-hostbased request", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Hostbased authentication successful");
|
||||
#endif
|
||||
/* We are us and we've proved it. */
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This public key is not allowed for this user on this server */
|
||||
LIBSSH2_FREE(session, data);
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, "Invalid signature for supplied public key, or bad username/public key combination", 0);
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_userauth_publickey_fromfile_ex
|
||||
* Authenticate using a keypair found in the named files
|
||||
*/
|
||||
LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, const char *username, int username_len,
|
||||
const char *publickey, const char *privatekey,
|
||||
const char *passphrase)
|
||||
{
|
||||
LIBSSH2_HOSTKEY_METHOD *privkeyobj;
|
||||
void *abstract;
|
||||
unsigned char buf[5];
|
||||
struct iovec datavec[4];
|
||||
unsigned char *method, *pubkeydata, *packet, *s, *b, *sig, *data;
|
||||
unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_PK_OK, 0 };
|
||||
unsigned long method_len, pubkeydata_len, packet_len, sig_len, data_len;
|
||||
|
||||
if (libssh2_file_read_publickey(session, &method, &method_len, &pubkeydata, &pubkeydata_len, publickey)) {
|
||||
return -1;
|
||||
@@ -371,6 +523,9 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
libssh2_htonu32(s, pubkeydata_len); s += 4;
|
||||
memcpy(s, pubkeydata, pubkeydata_len); s += pubkeydata_len;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting publickey authentication");
|
||||
#endif
|
||||
if (libssh2_packet_write(session, packet, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-publickey request", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
@@ -379,45 +534,38 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
unsigned char *data;
|
||||
unsigned long data_len;
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_SUCCESS, &data, &data_len, 1) == 0) {
|
||||
/* God help any SSH server that allows an UNVERIFIED public key to validate the user */
|
||||
LIBSSH2_FREE(session, data);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
LIBSSH2_FREE(session, method);
|
||||
LIBSSH2_FREE(session, pubkeydata);
|
||||
session->authenticated = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_FAILURE, &data, &data_len, 0) == 0) {
|
||||
/* This public key is not allowed for this user on this server */
|
||||
LIBSSH2_FREE(session, data);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
LIBSSH2_FREE(session, method);
|
||||
LIBSSH2_FREE(session, pubkeydata);
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED, "Username/PublicKey combination invalid", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_PK_OK, &data, &data_len, 0) == 0) {
|
||||
/* Semi-Success! */
|
||||
if ((libssh2_ntohu32(data + 1) != method_len) ||
|
||||
strncmp(data + 5, method, method_len) ||
|
||||
(libssh2_ntohu32(data + 5 + method_len) != pubkeydata_len) ||
|
||||
strncmp(data + 5 + method_len + 4, pubkeydata, pubkeydata_len)) {
|
||||
/* Unlikely but possible, the server has responded to a different userauth public key request */
|
||||
LIBSSH2_FREE(session, data);
|
||||
continue;
|
||||
}
|
||||
LIBSSH2_FREE(session, data);
|
||||
break;
|
||||
}
|
||||
/* TODO: Timeout? */
|
||||
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
|
||||
LIBSSH2_FREE(session, packet);
|
||||
LIBSSH2_FREE(session, method);
|
||||
LIBSSH2_FREE(session, pubkeydata);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Pubkey authentication prematurely successful");
|
||||
#endif
|
||||
/* God help any SSH server that allows an UNVERIFIED public key to validate the user */
|
||||
LIBSSH2_FREE(session, data);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
LIBSSH2_FREE(session, method);
|
||||
LIBSSH2_FREE(session, pubkeydata);
|
||||
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data[0] == SSH_MSG_USERAUTH_FAILURE) {
|
||||
/* This public key is not allowed for this user on this server */
|
||||
LIBSSH2_FREE(session, data);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
LIBSSH2_FREE(session, method);
|
||||
LIBSSH2_FREE(session, pubkeydata);
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED, "Username/PublicKey combination invalid", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Semi-Success! */
|
||||
LIBSSH2_FREE(session, data);
|
||||
LIBSSH2_FREE(session, pubkeydata);
|
||||
|
||||
if (libssh2_file_read_privatekey(session, &privkeyobj, &abstract, method, method_len, privatekey, passphrase)) {
|
||||
@@ -471,6 +619,9 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
memcpy(s, sig, sig_len); s += sig_len;
|
||||
LIBSSH2_FREE(session, sig);
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting publickey authentication -- phase 2");
|
||||
#endif
|
||||
if (libssh2_packet_write(session, packet, s - packet)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-publickey request", 0);
|
||||
LIBSSH2_FREE(session, packet);
|
||||
@@ -478,26 +629,227 @@ LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
}
|
||||
LIBSSH2_FREE(session, packet);
|
||||
|
||||
while (1) {
|
||||
unsigned char *data;
|
||||
unsigned long data_len;
|
||||
/* PK_OK is no longer valid */
|
||||
reply_codes[2] = 0;
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_SUCCESS, &data, &data_len, 1) == 0) {
|
||||
/* We are us and we've proved it. */
|
||||
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Publickey authentication successful");
|
||||
#endif
|
||||
/* We are us and we've proved it. */
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This public key is not allowed for this user on this server */
|
||||
LIBSSH2_FREE(session, data);
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, "Invalid signature for supplied public key, or bad username/public key combination", 0);
|
||||
return -1;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ libssh2_userauth_keyboard_interactive
|
||||
* Authenticate using a challenge-response authentication
|
||||
*/
|
||||
LIBSSH2_API int libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION *session, const char *username, int username_len,
|
||||
LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)))
|
||||
{
|
||||
unsigned char *s, *data; /* packet */
|
||||
unsigned long packet_len;
|
||||
|
||||
packet_len = 1 /* byte SSH_MSG_USERAUTH_REQUEST */
|
||||
+ 4 + username_len /* string user name (ISO-10646 UTF-8, as defined in [RFC-3629]) */
|
||||
+ 4 + 14 /* string service name (US-ASCII) */
|
||||
+ 4 + 20 /* string "keyboard-interactive" (US-ASCII) */
|
||||
+ 4 + 0 /* string language tag (as defined in [RFC-3066]) */
|
||||
+ 4 + 0 /* string submethods (ISO-10646 UTF-8) */
|
||||
;
|
||||
|
||||
if (!(data = s = LIBSSH2_ALLOC(session, packet_len))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive authentication", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*s++ = SSH_MSG_USERAUTH_REQUEST;
|
||||
|
||||
/* user name */
|
||||
libssh2_htonu32(s, username_len); s += 4;
|
||||
memcpy(s, username, username_len); s += username_len;
|
||||
|
||||
/* service name */
|
||||
libssh2_htonu32(s, sizeof("ssh-connection") - 1); s += 4;
|
||||
memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1); s += sizeof("ssh-connection") - 1;
|
||||
|
||||
/* "keyboard-interactive" */
|
||||
libssh2_htonu32(s, sizeof("keyboard-interactive") - 1); s += 4;
|
||||
memcpy(s, "keyboard-interactive", sizeof("keyboard-interactive") - 1); s += sizeof("keyboard-interactive") - 1;
|
||||
|
||||
/* language tag */
|
||||
libssh2_htonu32(s, 0); s += 4;
|
||||
|
||||
/* submethods */
|
||||
libssh2_htonu32(s, 0); s += 4;
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting keyboard-interactive authentication");
|
||||
#endif
|
||||
if (libssh2_packet_write(session, data, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send keyboard-interactive request", 0);
|
||||
LIBSSH2_FREE(session, data);
|
||||
return -1;
|
||||
}
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
for (;;) {
|
||||
unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0 };
|
||||
unsigned int auth_name_len;
|
||||
char* auth_name = NULL;
|
||||
unsigned auth_instruction_len;
|
||||
char* auth_instruction = NULL;
|
||||
unsigned int language_tag_len;
|
||||
unsigned long data_len;
|
||||
unsigned int num_prompts = 0;
|
||||
unsigned int i;
|
||||
int auth_failure = 1;
|
||||
LIBSSH2_USERAUTH_KBDINT_PROMPT* prompts = NULL;
|
||||
LIBSSH2_USERAUTH_KBDINT_RESPONSE* responses = NULL;
|
||||
|
||||
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Keyboard-interactive authentication successful");
|
||||
#endif
|
||||
LIBSSH2_FREE(session, data);
|
||||
session->authenticated = 1;
|
||||
session->state |= LIBSSH2_STATE_AUTHENTICATED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (libssh2_packet_ask(session, SSH_MSG_USERAUTH_FAILURE, &data, &data_len, 0) == 0) {
|
||||
/* This public key is not allowed for this user on this server */
|
||||
if (data[0] == SSH_MSG_USERAUTH_FAILURE) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, "Invalid signature for supplied public key, or bad username/public key combination", 0);
|
||||
return -1;
|
||||
}
|
||||
/* TODO: Timeout? */
|
||||
|
||||
/* server requested PAM-like conversation */
|
||||
|
||||
s = data + 1;
|
||||
|
||||
/* string name (ISO-10646 UTF-8) */
|
||||
auth_name_len = libssh2_ntohu32(s); s += 4;
|
||||
if (!(auth_name = LIBSSH2_ALLOC(session, auth_name_len))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive 'name' request field", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
memcpy(auth_name, s, auth_name_len); s += auth_name_len;
|
||||
|
||||
/* string instruction (ISO-10646 UTF-8) */
|
||||
auth_instruction_len = libssh2_ntohu32(s); s += 4;
|
||||
if (!(auth_instruction = LIBSSH2_ALLOC(session, auth_instruction_len))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive 'instruction' request field", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
memcpy(auth_instruction, s, auth_instruction_len); s += auth_instruction_len;
|
||||
|
||||
/* string language tag (as defined in [RFC-3066]) */
|
||||
language_tag_len = libssh2_ntohu32(s); s += 4;
|
||||
/* ignoring this field as deprecated */ s += language_tag_len;
|
||||
|
||||
/* int num-prompts */
|
||||
num_prompts = libssh2_ntohu32(s); s += 4;
|
||||
|
||||
prompts = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * num_prompts);
|
||||
if (!prompts) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive prompts array", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
memset(prompts, 0, sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * num_prompts);
|
||||
|
||||
responses = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * num_prompts);
|
||||
if (!responses) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive responses array", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
memset(responses, 0, sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * num_prompts);
|
||||
|
||||
for(i = 0; i != num_prompts; ++i) {
|
||||
/* string prompt[1] (ISO-10646 UTF-8) */
|
||||
prompts[i].length = libssh2_ntohu32(s); s += 4;
|
||||
if (!(prompts[i].text = LIBSSH2_ALLOC(session, prompts[i].length))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive prompt message", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
memcpy(prompts[i].text, s, prompts[i].length); s += prompts[i].length;
|
||||
|
||||
/* boolean echo[1] */
|
||||
prompts[i].echo = *s++;
|
||||
}
|
||||
|
||||
response_callback(auth_name, auth_name_len, auth_instruction, auth_instruction_len, num_prompts, prompts, responses, &session->abstract);
|
||||
|
||||
#ifdef LIBSSH2_DEBUG_USERAUTH
|
||||
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Keyboard-interactive response callback function invoked");
|
||||
#endif
|
||||
|
||||
packet_len = 1 /* byte SSH_MSG_USERAUTH_INFO_RESPONSE */
|
||||
+ 4 /* int num-responses */
|
||||
;
|
||||
|
||||
for (i = 0; i != num_prompts; ++i) {
|
||||
packet_len += 4 + responses[i].length; /* string response[1] (ISO-10646 UTF-8) */
|
||||
}
|
||||
|
||||
if (!(data = s = LIBSSH2_ALLOC(session, packet_len))) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive response packet", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
*s = SSH_MSG_USERAUTH_INFO_RESPONSE; s++;
|
||||
libssh2_htonu32(s, num_prompts); s += 4;
|
||||
|
||||
for (i = 0; i != num_prompts; ++i) {
|
||||
libssh2_htonu32(s, responses[i].length); s += 4;
|
||||
memcpy(s, responses[i].text, responses[i].length); s += responses[i].length;
|
||||
}
|
||||
|
||||
if (libssh2_packet_write(session, data, packet_len)) {
|
||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-keyboard-interactive request", 0);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
auth_failure = 0;
|
||||
|
||||
cleanup:
|
||||
/* It's safe to clean all the data here, because unallocated pointers
|
||||
* are filled by zeroes
|
||||
*/
|
||||
|
||||
LIBSSH2_FREE(session, data);
|
||||
|
||||
if (prompts) {
|
||||
for (i = 0; i != num_prompts; ++i) {
|
||||
LIBSSH2_FREE(session, prompts[i].text);
|
||||
}
|
||||
}
|
||||
|
||||
if (responses) {
|
||||
for (i = 0; i != num_prompts; ++i) {
|
||||
LIBSSH2_FREE(session, responses[i].text);
|
||||
}
|
||||
}
|
||||
|
||||
LIBSSH2_FREE(session, prompts);
|
||||
LIBSSH2_FREE(session, responses);
|
||||
|
||||
if (auth_failure) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
@@ -1,29 +1,45 @@
|
||||
#include "libssh2.h"
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#ifndef WIN32
|
||||
# include <netinet/in.h>
|
||||
# include <sys/socket.h>
|
||||
# include <unistd.h>
|
||||
#else
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int sock, i, auth_pw = 1;
|
||||
struct sockaddr_in sin;
|
||||
char *fingerprint;
|
||||
const char *fingerprint;
|
||||
LIBSSH2_SESSION *session;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
|
||||
WSAStartup(WINSOCK_VERSION, &wsadata);
|
||||
#endif
|
||||
|
||||
/* Ultra basic "connect to port 22 on localhost"
|
||||
* Your code is responsible for creating the socket establishing the connection
|
||||
*/
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
#ifndef WIN32
|
||||
fcntl(sock, F_SETFL, 0);
|
||||
#endif
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(22);
|
||||
sin.sin_addr.s_addr = htonl(0x7F000001);
|
||||
connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in));
|
||||
if (connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "failed to connect!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create a session instance and start it up
|
||||
* This will trade welcome banners, exchange keys, and setup crypto, compression, and MAC layers
|
||||
@@ -114,8 +130,13 @@ int main(int argc, char *argv[]) {
|
||||
libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
|
||||
libssh2_session_free(session);
|
||||
|
||||
#ifdef WIN32
|
||||
Sleep(1000);
|
||||
closesocket(sock);
|
||||
#else
|
||||
sleep(1);
|
||||
close(sock);
|
||||
|
||||
#endif
|
||||
printf("all done\n");
|
||||
return 0;
|
||||
}
|
||||
|
12
win32/.cvsignore
Normal file
12
win32/.cvsignore
Normal file
@@ -0,0 +1,12 @@
|
||||
*.lib
|
||||
*.pdb
|
||||
*.dll
|
||||
*.exe
|
||||
*.obj
|
||||
.*.swp
|
||||
Debug
|
||||
Release
|
||||
*.exp
|
||||
*.ncb
|
||||
*.opt
|
||||
*.plg
|
29
win32/config.mk
Normal file
29
win32/config.mk
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
# Tweak these for your system
|
||||
OPENSSLINC=..\libssh2_build\include
|
||||
OPENSSLLIB=..\libssh2_build\lib
|
||||
|
||||
ZLIBINC=-DLIBSSH2_HAVE_ZLIB=1 /I..\libssh2_build\include
|
||||
ZLIBLIB=..\libssh2_build\lib
|
||||
|
||||
!if "$(TARGET)" == ""
|
||||
TARGET=Release
|
||||
!endif
|
||||
|
||||
!if "$(TARGET)" == "Debug"
|
||||
SUFFIX=_debug
|
||||
CPPFLAGS=/Od /MDd
|
||||
DLLFLAGS=/DEBUG /LDd
|
||||
!else
|
||||
CPPFLAGS=/Og /Oi /O2 /Oy /GF /Y- /MD /DNDEBUG
|
||||
DLLFLAGS=/DEBUG /LD
|
||||
!endif
|
||||
|
||||
CPPFLAGS=/nologo /GL /Zi /EHsc $(CPPFLAGS) /Iwin32 /Iinclude /I$(OPENSSLINC) $(ZLIBINC) -DLIBSSH2_WIN32
|
||||
CFLAGS=$(CPPFLAGS)
|
||||
DLLFLAGS=$(CFLAGS) $(DLLFLAGS)
|
||||
LIBS=$(OPENSSLLIB)\libeay32.lib $(OPENSSLLIB)\ssleay32.lib ws2_32.lib $(ZLIBLIB)\zlib.lib
|
||||
|
||||
INTDIR=$(TARGET)\$(SUBDIR)
|
||||
|
||||
|
156
win32/libssh2.dsp
Normal file
156
win32/libssh2.dsp
Normal 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
41
win32/libssh2.dsw
Normal 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
38
win32/libssh2_config.h
Normal 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
15
win32/rules.mk
Normal 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
102
win32/ssh2_sample.dsp
Normal 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
|
Reference in New Issue
Block a user