Compare commits
146 Commits
libssh2-1.
...
libssh2-1.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5633bb4a3b | ||
![]() |
fabf1a45ee | ||
![]() |
2e352d3085 | ||
![]() |
8c9571b7ba | ||
![]() |
527c1b2def | ||
![]() |
ec934f6dab | ||
![]() |
516fa7fdd9 | ||
![]() |
3ce2628140 | ||
![]() |
ad88325b3f | ||
![]() |
2db4863e6e | ||
![]() |
691cabc048 | ||
![]() |
90b4b4073f | ||
![]() |
8ce9a66ccf | ||
![]() |
7015488150 | ||
![]() |
164838c7dd | ||
![]() |
f9b1b95059 | ||
![]() |
59207291fc | ||
![]() |
0da37e0924 | ||
![]() |
4552c73cd5 | ||
![]() |
306929ee80 | ||
![]() |
326f741a52 | ||
![]() |
aa4f861643 | ||
![]() |
fd691deb17 | ||
![]() |
20da09932e | ||
![]() |
3ab7af095a | ||
![]() |
5b1a7ec2f1 | ||
![]() |
5ee38702a0 | ||
![]() |
2165ceacd3 | ||
![]() |
121237ce2f | ||
![]() |
b3e832172b | ||
![]() |
3faa8bc940 | ||
![]() |
2f0c0cef76 | ||
![]() |
75909e05a9 | ||
![]() |
47b4e62780 | ||
![]() |
1b1ff333e4 | ||
![]() |
c1683ae92c | ||
![]() |
1b65c6ae26 | ||
![]() |
92ea3bda60 | ||
![]() |
811cce09b5 | ||
![]() |
6875285b71 | ||
![]() |
0cc14be09d | ||
![]() |
499b989d46 | ||
![]() |
fa07d9fefc | ||
![]() |
b0c32a85fc | ||
![]() |
7ed7dad3b4 | ||
![]() |
b215ec0af5 | ||
![]() |
ac6d0fb706 | ||
![]() |
e87293d480 | ||
![]() |
a3ce1073c4 | ||
![]() |
97a1881749 | ||
![]() |
80f7508d55 | ||
![]() |
e8c44e789f | ||
![]() |
ca2e81eb1f | ||
![]() |
aff9c825c8 | ||
![]() |
7899d28ecb | ||
![]() |
2f5a2ff8e6 | ||
![]() |
160453cee4 | ||
![]() |
82fa5d2167 | ||
![]() |
1c3e1c4d25 | ||
![]() |
1d2a5b8456 | ||
![]() |
1d11d02aa9 | ||
![]() |
f4ad3e0120 | ||
![]() |
772564650d | ||
![]() |
05ba8db8aa | ||
![]() |
1964ccb557 | ||
![]() |
bef0ce5392 | ||
![]() |
fb6afd01a1 | ||
![]() |
a302428335 | ||
![]() |
7ad152a6b2 | ||
![]() |
075ff19574 | ||
![]() |
16f46c1cfc | ||
![]() |
aa2fdb3e7e | ||
![]() |
8f10da89c5 | ||
![]() |
2dfa5d38cb | ||
![]() |
095e9e7b3e | ||
![]() |
588c8946fc | ||
![]() |
a6fc9aeec9 | ||
![]() |
7603c0f854 | ||
![]() |
8974dc05ae | ||
![]() |
6395a738fd | ||
![]() |
73be9fab04 | ||
![]() |
753e55ef23 | ||
![]() |
4760e4d051 | ||
![]() |
57af0da9f7 | ||
![]() |
024b5d29f5 | ||
![]() |
a0dd0c5992 | ||
![]() |
92d308c157 | ||
![]() |
4ae71b4838 | ||
![]() |
ba190d34c6 | ||
![]() |
b84f69c960 | ||
![]() |
a7aee34522 | ||
![]() |
1dc366109d | ||
![]() |
e1ea2eb7c2 | ||
![]() |
610a8ab919 | ||
![]() |
8ec21e0afe | ||
![]() |
8e0983347b | ||
![]() |
95db6cc62c | ||
![]() |
727043074a | ||
![]() |
5b4ed2717b | ||
![]() |
59f74de157 | ||
![]() |
d87562976a | ||
![]() |
a94886f157 | ||
![]() |
dec0ea9e70 | ||
![]() |
030b2d9b60 | ||
![]() |
c48840ba88 | ||
![]() |
d9cdd8c0a7 | ||
![]() |
c49061e708 | ||
![]() |
d674b1a09a | ||
![]() |
5ede32a826 | ||
![]() |
3a391f6cf2 | ||
![]() |
64063d5f0b | ||
![]() |
784db8e987 | ||
![]() |
84efbf788f | ||
![]() |
f805c2db2a | ||
![]() |
08ce6425f6 | ||
![]() |
fac9412a74 | ||
![]() |
4d15e0c9d1 | ||
![]() |
6140ec2de3 | ||
![]() |
70d6bd6c6f | ||
![]() |
98e38c4f3a | ||
![]() |
cd6d41b806 | ||
![]() |
c36f379b88 | ||
![]() |
77a9335515 | ||
![]() |
59636cc11e | ||
![]() |
0d58af6aec | ||
![]() |
c34e1d8735 | ||
![]() |
861fc75fa3 | ||
![]() |
f4d302fdfe | ||
![]() |
4faf67d3e9 | ||
![]() |
76a30f2c6f | ||
![]() |
bcd7eee1d2 | ||
![]() |
046ad88d88 | ||
![]() |
9887c01103 | ||
![]() |
822f9e8689 | ||
![]() |
3ee2aabd7a | ||
![]() |
7c49c8be58 | ||
![]() |
665d9ee885 | ||
![]() |
b3d6c6567d | ||
![]() |
7dd574c353 | ||
![]() |
018602cb34 | ||
![]() |
eec7f2fb63 | ||
![]() |
c32b0d164e | ||
![]() |
835c03e076 | ||
![]() |
6c6c43f92c | ||
![]() |
5af87e8c80 | ||
![]() |
10a65fda01 |
@@ -29,7 +29,8 @@ vms/readme.vms vms/libssh2_config.h
|
||||
WIN32FILES = win32/Makefile.win32 win32/libssh2.dsw \
|
||||
win32/config.mk win32/Makefile win32/test/Makefile.win32 \
|
||||
win32/libssh2_config.h win32/tests.dsp win32/rules.mk $(DSP) \
|
||||
win32/msvcproj.head win32/msvcproj.foot
|
||||
win32/msvcproj.head win32/msvcproj.foot win32/libssh2.rc \
|
||||
win32/Makefile.Watcom
|
||||
|
||||
EXTRA_DIST = $(WIN32FILES) buildconf $(NETWAREFILES) get_ver.awk HACKING \
|
||||
maketgz NMakefile TODO RELEASE-NOTES libssh2.pc.in $(VMSFILES)
|
||||
|
@@ -4,4 +4,4 @@ CSOURCES = channel.c comp.c crypt.c hostkey.c kex.c mac.c misc.c \
|
||||
global.c
|
||||
|
||||
HHEADERS = libssh2_priv.h openssl.h libgcrypt.h transport.h channel.h \
|
||||
comp.h mac.h misc.h packet.h userauth.h session.h
|
||||
comp.h mac.h misc.h packet.h userauth.h session.h sftp.h crypto.h
|
||||
|
787
NEWS
787
NEWS
@@ -1,786 +1,3 @@
|
||||
libssh2 1.2.7 (August 17, 2010)
|
||||
The old NEWS file.
|
||||
|
||||
This release includes the following changes:
|
||||
|
||||
o Added Watcom makefile
|
||||
|
||||
This release includes the following bugfixes:
|
||||
|
||||
o Better handling of invalid key files
|
||||
o inputchecks: make lots of API functions check for NULL pointers
|
||||
o libssh2_session_callback_set: extended the man page
|
||||
o SFTP: limit write() to not produce overly large packets
|
||||
o agent: make libssh2_agent_userauth() work blocking properly
|
||||
o _libssh2_userauth_publickey: reject method names longer than the data
|
||||
o channel_free: ignore problems with channel_close()
|
||||
o typedef: make ssize_t get typedef without LIBSSH2_WIN32
|
||||
o _libssh2_wait_socket: poll needs milliseconds
|
||||
o libssh2_wait_socket: reset error code to "leak" EAGAIN less
|
||||
o Added include for sys/select.h to get fd.set on some platforms
|
||||
o session_free: free more data to avoid memory leaks
|
||||
o openssl: make use of the EVP interface
|
||||
o Fix underscore typo for 64-bit printf format specifiers on Windows
|
||||
o Make libssh2_debug() create a correctly terminated string
|
||||
o userauth_hostbased_fromfile: packet length too short
|
||||
o handshake: Compression enabled at the wrong time
|
||||
o Don't overflow MD5 server hostkey
|
||||
|
||||
libssh2 1.2.6 (June 10, 2010)
|
||||
|
||||
This release includes the following changes:
|
||||
|
||||
o Added libssh2_sftp_statvfs() and libssh2_sftp_fstatvfs()
|
||||
o Added libssh2_knownhost_checkp()
|
||||
o Added libssh2_scp_send64()
|
||||
|
||||
This release includes the following bugfixes:
|
||||
|
||||
o wait_socket: make c89 compliant and use two fd_sets for select()
|
||||
o OpenSSL AES-128-CTR detection
|
||||
o proper keyboard-interactive user dialog in the sftp.c example
|
||||
o build procedure for VMS
|
||||
o fixed libssh2.dsw to use the generated libssh2.dsp
|
||||
o several Windows-related build fixes
|
||||
o fail to init SFTP if session isn't already authenticated
|
||||
o many tiny fixes that address clang-analyzer warnings
|
||||
o sftp_open: deal with short channel_write calls
|
||||
o libssh2_publickey_init: fixed to work better non-blocking
|
||||
o sftp_close_handle: add precation to not access NULL pointer
|
||||
o sftp_readdir: simplified and bugfixed
|
||||
o channel_write: if data has been sent, don't return EAGAIN
|
||||
|
||||
Version 1.2.5 (April 13, 2010)
|
||||
|
||||
This release includes the following changes:
|
||||
|
||||
o Added Add keep-alive support: libssh2_keepalive_config() and
|
||||
libssh2_keepalive_send()
|
||||
o Added libssh2_knownhost_addc(), libssh2_init() and libssh2_exit()
|
||||
o Added LIBSSH2_SFTP_S_IS***() macros
|
||||
|
||||
This release includes the following bugfixes:
|
||||
|
||||
o fix memory leak in libssh2_session_startup()
|
||||
o added missing error codes - shown as hangs in blocking mode
|
||||
o fix memory leak in userauth_keyboard_interactive()
|
||||
o libssh2_knownhost_del: fix write to freed memory
|
||||
o Send and receive channel EOF before sending SSH_MSG_CHANNEL_CLOSE
|
||||
o Use AES-CTR from OpenSSL when available
|
||||
o Fixed gettimeofday to compile with Visual C++ 6
|
||||
o NULL dereference when window adjusting a non-existing channel
|
||||
o avoid using poll on interix and mac os x systems
|
||||
o fix scp memory leak
|
||||
o Correctly clear blocking flag after sending multipart packet
|
||||
o Reduce used window sizes by factor 10
|
||||
o libssh2_userauth_publickey_fromfile_ex() handles a NULL password
|
||||
o sftp_init() deal with _libssh2_channel_write() short returns
|
||||
|
||||
o Use poll instead of select when available. By Paul Querna.
|
||||
|
||||
o Add APIs to have libssh2 automatically send keep-alive requests.
|
||||
The APIs are libssh2_keepalive_config, and libssh2_keepalive_send.
|
||||
By Simon Josefsson.
|
||||
|
||||
o Add global init/exit points, to do crypto initialization in one place.
|
||||
The APIs are libssh2_init and libssh2_exit. By Lars Nordin.
|
||||
|
||||
* (February 15 2010) Daniel Stenberg:
|
||||
- Added 46 new man pages for public convenience macros. The man pages are
|
||||
just short redirects to the actual underlying function. The were all
|
||||
initially created by a script.
|
||||
|
||||
- Committed the patch by Yoichi Iwaki in bug #2929647, which fixed a memory
|
||||
leak when an 'outbuf' was still allocated when a session was freed.
|
||||
|
||||
Version 1.2.4 (February 13, 2010)
|
||||
|
||||
o Resolve compile issues on Solaris x64 and UltraSPARC
|
||||
o Allow compiling with OpenSSL when AES isn't available
|
||||
o Fix Tru64 socklen_t compile issue with example/direct_tcpip.c
|
||||
|
||||
Version 1.2.3 (February 3, 2010)
|
||||
|
||||
o Added libssh2_trace_sethandler()
|
||||
o Added the direct_tcpip.c example
|
||||
o Fixed memory leak in userauth_publickey
|
||||
o Added support for authentication via SSH-Agent. By Daiki Ueno.
|
||||
|
||||
o Respond to unknown SSH_MSG_GLOBAL_REQUEST/SSH_MSG_CHANNEL_REQUEST
|
||||
with SSH_MSG_REQUEST_FAILURE/SSH_MSG_CHANNEL_FAILURE in order to
|
||||
make (at least) OpenSSH server keepalive work. Before OpenSSH
|
||||
servers (configured with a positive ClientAliveInterval) would
|
||||
terminate connections against libssh2 clients because libssh2 did
|
||||
not respond properly to the request. By Simon Josefsson.
|
||||
|
||||
Version 1.2.2 (November 16, 2009)
|
||||
|
||||
* This release includes the following changes:
|
||||
|
||||
o Fix crash when server sends an invalid SSH_MSG_IGNORE message.
|
||||
Reported by Bob Alexander <balexander@expressor-software.com> in
|
||||
<http://thread.gmane.org/gmane.network.ssh.libssh2.devel/2530>.
|
||||
By Simon Josefsson.
|
||||
|
||||
o Support for the "aes128-ctr", "aes192-ctr", "aes256-ctr" ciphers
|
||||
as per RFC 4344 for libgcrypt and OpenSSL. They are now the
|
||||
preferred ciphers. By Simon Josefsson.
|
||||
|
||||
o Support for the "arcfour128" cipher as per RFC 4345 for libgcrypt
|
||||
and OpenSSL. It is preferred over the normal "arcfour" cipher
|
||||
which is somewhat broken. By Simon Josefsson.
|
||||
|
||||
o Add support for GCC visibility features. By Cristian Rodr<64>guez.
|
||||
|
||||
o Fix libssh2_channel_forward_accept. By Juzna.
|
||||
|
||||
o Generate Win32 files correctly. By Peter Stuge.
|
||||
|
||||
o Fix permission issue in ssh2 self test. By Dan Fandrich.
|
||||
|
||||
o Use memmove instead of memcpy in one place which copies
|
||||
overlapping memory areas.
|
||||
|
||||
o Cleanup hard coding of cipher modes in libgcrypt backend. By Simon.
|
||||
|
||||
o Added man page for libssh2_knownhost_free. By Daniel.
|
||||
|
||||
Version 1.2.1 (September 28, 2009)
|
||||
|
||||
* This release includes the following changes:
|
||||
|
||||
o generate and install libssh2.pc
|
||||
|
||||
... and the following bugfixes:
|
||||
|
||||
o proper return codes returned from several functions
|
||||
o return EAGAIN internal cleanup
|
||||
o added knownhost.c to windows makefiles
|
||||
o pass private-key to OpenSSL as a filename with BIO_new_file().
|
||||
o make libssh2_scp_send/recv do blocking mode correctly
|
||||
o libssh2_channel_wait_closed() could hang
|
||||
o libssh2_channel_read_ex() must return 0 when closed
|
||||
o added gettimeofday() function for win32 for the debug trace outputs
|
||||
o transport layer bug causing invalid -39 (LIBSSH2_ERROR_BAD_USE) errors
|
||||
o scp examples now loop correctly over libssh2_channel_write()
|
||||
|
||||
* (August 29 2009) Daniel Stenberg:
|
||||
|
||||
- I fixed all code to use the recently added dedicated linked list functions
|
||||
instead of doing the same stuff spread out all over.
|
||||
|
||||
- I also fixed a few cases where local variables where used to keep memory
|
||||
but was used to keep state for re-invokes due to non-blocking situations
|
||||
which would lead to segfaults.
|
||||
|
||||
Version 1.2 (August 10, 2009)
|
||||
-----------------------------
|
||||
|
||||
* (August 02 2009) Alexander Lamaison:
|
||||
|
||||
- changed _libssh2_rsa_new_private and _libssh2_rsa_new_private so that they
|
||||
no longer use the OpenSSL functions that take a FILE* argument. Passing
|
||||
CRT-created objects across a DLL boundary causes crashes on Windows of the
|
||||
DLL and the client aren't linked to the exact same verison of the CRT. Now
|
||||
we pass the keys as strings to avoid this issue.
|
||||
|
||||
* (May 29 2009) Daniel Stenberg:
|
||||
|
||||
- Updated the knownhost API and there are now 9 functions, and all of them
|
||||
have man pages. The libssh2.h now defines HAVE_LIBSSH2_KNOWNHOST_API to
|
||||
ease things for applications to check for the correct release before trying
|
||||
to use it.
|
||||
|
||||
* (May 23 2009) Daniel Stenberg:
|
||||
|
||||
- Anonymous bug report #2795816 revealed that doing subsequent
|
||||
libssh2_sftp_init() calls on the same session failed.
|
||||
|
||||
* (May 20 2009) Daniel Stenberg:
|
||||
|
||||
- made libssh2_sftp_write() properly deal with huge/any sized input buffers.
|
||||
|
||||
- fixed libssh2_channel_write_ex() to return the correct return code, and
|
||||
deal with sending off huge buffers better
|
||||
|
||||
* (May 7 2009) Daniel Stenberg:
|
||||
|
||||
- linked list code. I got a bit tired of the fact that we don't have any
|
||||
generic linked-list functions within libssh2 so I wrote up the first embryo
|
||||
for one that I use for this new functionality. The plan would then be to
|
||||
move all existing code that uses linked lists to use this new set.
|
||||
|
||||
- base64 encode. I had to add a base64 encoding function which was missing
|
||||
in the code base so it helps to "bloat" my patch.
|
||||
|
||||
- The knownhost API is currently:
|
||||
|
||||
_init() - init a bundle of known hosts
|
||||
_add() - add a known host
|
||||
_del() - delete a known host
|
||||
_free() - free an entire bundle of known hosts
|
||||
_check() - check if a host+key is present in the bundle
|
||||
|
||||
The convenience function:
|
||||
|
||||
_parsefile() - reads a ~/.ssh/known_hosts file and add all entries to the
|
||||
given bundle
|
||||
|
||||
- there's no docs other than some comments in the code/headers yet
|
||||
|
||||
- the patch includes changes to example/simple/ssh2_exec.c that makes use of
|
||||
a few of these functions. Using that I've verified that the functions in
|
||||
fact can verify my localhost's key agains my ~/.ssh/known_hosts file
|
||||
|
||||
* (Apr 30 2009) Daniel Stenberg:
|
||||
|
||||
Markus posted a bug report about a bad 0-return from libssh2_channel_read:
|
||||
http://libssh2.haxx.se/mail/libssh2-devel-archive-2009-04/0076.shtml
|
||||
|
||||
And it was indeed a bad loop that terminated too early due to a receveived
|
||||
close packet.
|
||||
|
||||
* (Apr 14 2009) Daniel Stenberg:
|
||||
|
||||
libssh2_poll() and libssh2_poll_channel_read() are now considered and
|
||||
documented deprecated and they will be removed at next soname bump. It also
|
||||
saves us from fixing some rather quirky bugs in libssh2_poll()...
|
||||
|
||||
|
||||
Version 1.1 (April 2, 2009)
|
||||
---------------------------
|
||||
|
||||
- (Mar 28 2009) Daniel Stenberg:
|
||||
|
||||
Jean-Louis Charton found a memory leak in
|
||||
libssh2_userauth_hostbased_fromfile_ex()
|
||||
|
||||
- (Mar 25 2009) Daniel Stenberg:
|
||||
|
||||
* Renamed the functions in src/transport.c to be _libssh2_transport_ prefixed
|
||||
and introduced a transport.h header.
|
||||
|
||||
* Fixed the blocking mode to only change behavior not the actual underlying
|
||||
socket mode so we now always work with non-blocking sockets. This also
|
||||
introduces a new rule of thumb in libssh2 code: we don't call the
|
||||
external function calls internally. We use the internal (non-blocking)
|
||||
ones!
|
||||
|
||||
* libssh2_channel_receive_window_adjust2 was added and
|
||||
libssh2_channel_receive_window_adjust is now deprecated
|
||||
|
||||
* Introduced "local" header files with prototypes etc for different parts
|
||||
instead of cramming everything into libssh2_priv.h. channel.h is the
|
||||
first.
|
||||
|
||||
- (Mar 19 2009) Daniel Stenberg: based on a patch by "E L" we now use errno
|
||||
properly after recv() and send() calls (that internally are now known as
|
||||
_libssh2_recv() and _libssh2_send()) so that the API and more works fine on
|
||||
windows too!
|
||||
|
||||
- (Mar 17 2009) Simon Josefsson:
|
||||
|
||||
Added a Libtool -export-symbols-regex flag to reduce the number of
|
||||
exported symbols in shared libraries. Reported by Mikhail Gusarov.
|
||||
|
||||
- (Mar 16 2009) Daniel Stenberg:
|
||||
|
||||
I renamed a few man pages to match the exact name of the functions they
|
||||
describe. I also added template versions for the 13 functions that
|
||||
previously lacked man pages. While these don't contain any docs just yet, it
|
||||
will now be easier to add the info as the foundation is there!
|
||||
|
||||
- (Mar 15 2009) Daniel Stenberg:
|
||||
|
||||
* libssh2_channel_read_ex() was simplified and enhanced. It now adjusts the
|
||||
window less frequent and uses much larger window that now allows MUCH
|
||||
faster transfers.
|
||||
|
||||
* SCP send/recv now allow file names with whitespaces etc, thanks to a patch
|
||||
by Heiner Steven
|
||||
|
||||
- (Mar 13 2009) Daniel Stenberg: Cleanups, that do seem to have boosted SFTP
|
||||
download performance up to 300% in some tests:
|
||||
|
||||
* cut off "_ex" from several internal function names
|
||||
|
||||
* corrected some log outputs
|
||||
|
||||
* simplified libssh2_channel_read_ex() and made it much faster in the process
|
||||
|
||||
* cut out {{{ and }}} comments that were incorrect anyway
|
||||
|
||||
* fixed sftp_packet_ask() to return the correct packet by using memcmp() and
|
||||
not strncmp()
|
||||
|
||||
* fixed mkdir()'s wait for packet to use the correct request_id - it
|
||||
semi-worked previously because strncmp() in sftp_packet_ask() made it
|
||||
match far too easily.
|
||||
|
||||
* took away the polling functionality from sftp_packet_ask() since it wasn't
|
||||
used
|
||||
|
||||
- (Mar 7 2009) Olivier Hervieu pointed out a flaw in the
|
||||
libssh2_channel_x11_req_ex() function that made it produce a crappy random
|
||||
chunk of data. Peter Stuge improved the fix to not do out-of-boundary
|
||||
writes. I (Daniel Stenberg) replaced the snprintf() with a plain sprintf()
|
||||
since the size argument wasn't adding anything anyway.
|
||||
|
||||
- (Feb 23 2009) Added libssh2_version()
|
||||
|
||||
- (Feb 20 2009) libssh2_channel_direct_tcpip_ex() bug #1902169 fixed, which
|
||||
caused it to fail when called a second time.
|
||||
|
||||
- (Feb 12 2009) Romain Bondue extended Markus Moeller fix from Feb 8, based on
|
||||
a previous (uncommitted) patch by Erik Brossler. It improves
|
||||
libssh2_channel_write_ex in blocking situations when the socket is set non-
|
||||
blocking.
|
||||
|
||||
- (Feb 8 2009) Markus Moeller fixed a flaw in libssh2_channel_write_ex() that
|
||||
would occur on EAGAIN situations.
|
||||
|
||||
Version 1.0 (December 26 2008)
|
||||
------------------------------
|
||||
|
||||
- (Dec 20 2008) Based on Alexander Lamaison's patch, there's now a new
|
||||
function called libssh2_sftp_tell64() that returns the 64 bit file offset,
|
||||
as the existing libssh2_sftp_tell() only returns a size_t.
|
||||
|
||||
- (Dec 18 2008) Markus Moeller fixed the issue also reported by Alexander
|
||||
Lamaison which caused SFTP reads with large buffers to fail.
|
||||
|
||||
- Several flaws were fixed that prevented at least SFTP to work reliably
|
||||
|
||||
- Vlad Grachov brought the new function called
|
||||
libssh2_session_block_directions() which returns a bitmask for what
|
||||
directions the connection blocks. It is to be used applications that use
|
||||
non-blocking sockets and when a libssh2 function returns
|
||||
LIBSSH2_ERROR_EAGAIN this function can be used to figure out in which
|
||||
direction the socket would block and thus it can wait for the socket to
|
||||
again be ready for communication in that direction before it calls libssh2
|
||||
again.
|
||||
|
||||
- Vincent Jaulin brought the new libssh2_channel_request_pty_size_ex()
|
||||
function.
|
||||
|
||||
- Carlo Bramini fixed the build for msys+mingw. Bug #1943976.
|
||||
|
||||
- Neil Gierman provided improved Visual Studio 2008 code in bug #1946268
|
||||
|
||||
- Bug #1862727 fixed libssh2_poll() to work on windows (by defining
|
||||
HAVE_SELECT).
|
||||
|
||||
- Based on bug #1815692, we introduce libssh2_sftp_seek64() that allows
|
||||
seeking beyond the 2GB margin even on 32bit machines.
|
||||
|
||||
- Based on a patch in bug #1878059 by Steven Ayre libssh2 now parses >2GB file
|
||||
sizes when downloading SCP files.
|
||||
|
||||
- Bug #2064371 pointed out that the SSH2 banner may not use dash
|
||||
('-'). Reported by Bjorn Stenborg.
|
||||
|
||||
- Sean Peterson fixed a key re-exchange bug:
|
||||
http://daniel.haxx.se/projects/libssh2/mail/libssh2-devel-archive-2008-06/0002.shtml
|
||||
|
||||
- Mike Protts filed the bug report #1908724 that identified and fixed a problem
|
||||
with SFTP stat on files >4GB in size. Previously it used 32bit math only.
|
||||
|
||||
- Removed a stderr debug message that was accidentally left in (bug #1863153)
|
||||
|
||||
- OpenSSL and libz detection changed to make cross-compiling to Mingw
|
||||
work. See README for parameters to use if the auto-detection does
|
||||
not work for you. From Simon Josefsson.
|
||||
|
||||
- Simon Josefsson added a self-test that uses libssh2 to connect to a
|
||||
local sshd (only enabled if if OpenSSH is installed).
|
||||
|
||||
Version 0.18 (November 11 2007)
|
||||
-------------------------------
|
||||
|
||||
- Various changes that improve non-blocking operations and prevent stalls.
|
||||
Especially noticable on Windows since libssh2 just didn't work properly
|
||||
non-blocking on Windows before.
|
||||
|
||||
- Peter O'Gorman reported how a SCP transfer would hang for him, and it was
|
||||
fairly easy reproducable. One bug was in the transport layer, ignoring to
|
||||
read more data while there was data left even though it couldn't decrypt the
|
||||
data that was left due to it being too little... The other bug was in the
|
||||
channel layer, where the libssh2_channel_receive_window_adjust() function
|
||||
missed to set the state variables at times and thus this function would
|
||||
misbehave on repeated invokes.
|
||||
|
||||
- Changed the signature of libssh2_channel_setenv_ex to add const to the
|
||||
"varname" parameter (Dan Fandrich)
|
||||
|
||||
- Satish Mittal and David J Sullivan fixed an infinit recv() loop in
|
||||
libssh2_banner_receive()
|
||||
|
||||
Version 0.17 (August 6 2007)
|
||||
----------------------------
|
||||
Changes since previous version include:
|
||||
|
||||
o Re-indented the source code with this GNU indent setup:
|
||||
|
||||
--braces-on-if-line
|
||||
--braces-after-struct-decl-line
|
||||
--space-after-cast
|
||||
--line-length 79
|
||||
--comment-line-length 79
|
||||
--cuddle-else
|
||||
--no-tabs
|
||||
--tab-size 8
|
||||
--indent-level 4
|
||||
--no-space-after-for
|
||||
--space-after-if
|
||||
--space-after-while
|
||||
--no-space-after-function-call-names
|
||||
|
||||
Version 0.16 (August 6 2007)
|
||||
----------------------------
|
||||
Changes since previous version include:
|
||||
|
||||
o CRLF stripping fix for PEM reading
|
||||
o libssh2_scp_recv() error message fix
|
||||
o added HACKING as an initial attempt to describe our source code format
|
||||
o new public defines in include/libssh2.h to allow applictions to figure out
|
||||
version number etc
|
||||
o new script (maketgz) to build releases with
|
||||
o updated files for building with MSVC and mingw
|
||||
o keyboard-interactive would always fail due to claimed memory problem
|
||||
o a few minor memory leaks fixed
|
||||
o libssh2_poll() no longer relies on C99 features
|
||||
o AIX 4 and 5 now supports non-blocking sockets
|
||||
o large file magic checks in configure
|
||||
o LIBSSH2_APINO was removed from the public header file
|
||||
|
||||
This release would not have been possible without these friendly contributors:
|
||||
|
||||
James Housley, Simon Josefsson, Dan Fandrich, Guenter Knauf and I too did
|
||||
some poking. (Sorry if I forgot anyone I should've mentioned here.)
|
||||
|
||||
Of course we would have nothing without the great work by Sara Golemon that
|
||||
we're extending and building upon.
|
||||
|
||||
Version 0.15 (June 15 2007)
|
||||
---------------------------
|
||||
Added libssh2_sftp_readdir_ex() and updated LIBSSH2_APINO to
|
||||
200706151200 (James Housley)
|
||||
|
||||
Converted all of the libssh2 code to be able to work in non-blocking
|
||||
mode. This included some public API changes, listed below (James Housley)
|
||||
Changed function return values:
|
||||
int libssh2_session_free()
|
||||
int libssh2_publickey_shutdown()
|
||||
ssize_t libssh2_channel_read_ex()
|
||||
ssize_t libssh2_channel_write_ex()
|
||||
|
||||
Added functions:
|
||||
libssh2_session_last_errno(), libssh2_channel_handle_extended_data2(),
|
||||
libssh2_channel_wait_closed(), libssh2_channel_wait_eof(),
|
||||
libssh2_session_set_blocking()
|
||||
|
||||
Removed functions:
|
||||
libssh2_channel_readnb_ex(), libssh2_channel_writenb_ex(),
|
||||
libssh2_sftp_readnb(), libssh2_sftp_writenb(),
|
||||
libssh2_sftp_mkdirnb_ex()
|
||||
|
||||
Added the following functions for non-blocking operations: (Daniel Stenberg)
|
||||
libssh2_channel_readnb_ex()
|
||||
libssh2_channel_writenb_ex()
|
||||
libssh2_sftp_readnb()
|
||||
libssh2_sftp_writenb()
|
||||
|
||||
Size parameter changed from 'int' to 'unsigned int' in several
|
||||
public APIs.
|
||||
|
||||
Added (a few) man pages in docs/. (Daniel Stenberg)
|
||||
|
||||
Maximum SSH packet size is now some 35000 bytes.
|
||||
|
||||
Private include files are now in src/ and only public headers are in
|
||||
include/. (Daniel Stenberg)
|
||||
|
||||
Automake and libtool are being used (increased portability). (Daniel
|
||||
Stenberg)
|
||||
|
||||
Fixed OpenSSL detection using pkg-config. (Daniel Stenberg)
|
||||
|
||||
Simple self test added to tests/. (Simon Josefsson)
|
||||
|
||||
Libgcrypt can now be used instead of OpenSSL if you specify
|
||||
--with-libgcrypt. (Simon Josefsson)
|
||||
|
||||
Fixed a memory leak in the packet handling, and better handle out of
|
||||
memory situations. (Dan Fandrich)
|
||||
|
||||
Made libssh2 build with OpenSSL 0.9.6. (Dan Fandrich)
|
||||
|
||||
Improved portability to Solaris related to -lsocket and
|
||||
-lnsl. (Simon Josefsson)
|
||||
|
||||
Clean up of README, INSTALL, NEWS, added ChangeLog. (Simon
|
||||
Josefsson)
|
||||
|
||||
Improve debugging code. Avoids many #ifdef's.
|
||||
|
||||
Improved session closing to avoid potentially truncated files on
|
||||
OpenSSH servers (Dan Fandrich)
|
||||
|
||||
Made some function parameters in the API const (Dan Fandrich)
|
||||
|
||||
Version 0.14
|
||||
------------
|
||||
|
||||
Plug leaks in EVP cipher init/shutdown. (Selcuk Gueney)
|
||||
|
||||
Allow socket_fd == 0 in libssh2_session_startup(). (puudeli)
|
||||
|
||||
Swap ordering of packet_add/packet-inspection to avoid inspect after
|
||||
free. (Selcuk)
|
||||
|
||||
Swap KEX_INIT ordering, send our KEX_INIT first.
|
||||
|
||||
Add check for oportunistic KEX_INIT packets. Burn bad guess if necessary.
|
||||
|
||||
Fix OpenSSL detection using pkg-config. (Dan Casey)
|
||||
|
||||
Version 0.13
|
||||
------------
|
||||
|
||||
Fixed channel not being marked closed when CHANNEL_CLOSE package cannot be
|
||||
sent. (David Robins)
|
||||
|
||||
Fixed payload packet allocation bug when invalid packet length
|
||||
received. (David Robins)
|
||||
|
||||
Fixed `make install' target for MacOSX.
|
||||
|
||||
Add terminating NULL character to readlink()/realpath() results.
|
||||
|
||||
BugFix#1436593: Apply build options for HPUX targets.
|
||||
|
||||
Version 0.12
|
||||
------------
|
||||
|
||||
Added support for publickey subsytem (not the same as publickey auth).
|
||||
|
||||
Fix x11_req. Multiple packet_len issues and error handling logic.
|
||||
(Thanks Simon Hart)
|
||||
|
||||
Fix generation of 'e' portion of Diffie-Hellman keyset.
|
||||
|
||||
Use appropriate order for BN_rand() rather than fixed group1-specific value.
|
||||
|
||||
Re-fixed libssh2_sftp_rename_ex()
|
||||
|
||||
Transport had right packet_len, but sftp layer still had extra 4 bytes.
|
||||
|
||||
Fixed build with newer OpenSSL headers.
|
||||
|
||||
Added extern "C" declarations to libssh2_sftp.h for C++ compatability.
|
||||
|
||||
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
|
||||
Hostkey methods: ssh-rsa, ssh-dss
|
||||
Cipher methods: aes256-cbc, rijndael-cbc@lysator.liu.se, aes192-cbc, aes128-cbc, blowfish-cbc, arcfour, cast128-cbc, 3des-cbc, none*
|
||||
Compression methods: zlib, none
|
||||
MAC methods: hmac-sha1, hmac-sha1-96, hmac-ripemd160, hmac-ripemd160@openssh.com none*
|
||||
*Cipher/MAC "none" is disabled by default for security purposes,
|
||||
Use --enable-crypt-none and/or --enable-mac-none with ./configure to enable
|
||||
NEWS is now generated from git and put into the release tarballs.
|
||||
|
@@ -1,34 +1,44 @@
|
||||
libssh2 1.2.7
|
||||
libssh2 1.2.8
|
||||
|
||||
This release includes the following changes:
|
||||
|
||||
o Added Watcom makefile
|
||||
o added libssh2_free, libssh2_channel_get_exit_signal and
|
||||
libssh2_session_handshake
|
||||
o SFTP read/write remade and now MUCH faster, especially on high latency
|
||||
connections
|
||||
o added new examples: ssh2_echo.c, sftp_append.c and sftp_write_sliding.c
|
||||
o userauth: derive publickey from private
|
||||
o NEWS: now generated from git
|
||||
|
||||
This release includes the following bugfixes:
|
||||
|
||||
o Better handling of invalid key files
|
||||
o inputchecks: make lots of API functions check for NULL pointers
|
||||
o libssh2_session_callback_set: extended the man page
|
||||
o SFTP: limit write() to not produce overly large packets
|
||||
o agent: make libssh2_agent_userauth() work blocking properly
|
||||
o _libssh2_userauth_publickey: reject method names longer than the data
|
||||
o channel_free: ignore problems with channel_close()
|
||||
o typedef: make ssize_t get typedef without LIBSSH2_WIN32
|
||||
o _libssh2_wait_socket: poll needs milliseconds
|
||||
o libssh2_wait_socket: reset error code to "leak" EAGAIN less
|
||||
o Added include for sys/select.h to get fd.set on some platforms
|
||||
o session_free: free more data to avoid memory leaks
|
||||
o openssl: make use of the EVP interface
|
||||
o Fix underscore typo for 64-bit printf format specifiers on Windows
|
||||
o Make libssh2_debug() create a correctly terminated string
|
||||
o userauth_hostbased_fromfile: packet length too short
|
||||
o handshake: Compression enabled at the wrong time
|
||||
o Don't overflow MD5 server hostkey
|
||||
o Support unlimited number of host names in a single line of the
|
||||
known_hosts file.
|
||||
o fix memory leak in userauth_keyboard_interactive()
|
||||
o fix memory leaks (two times cipher_data) for each sftp session
|
||||
o session_startup: manage server data before server identification
|
||||
o SCP: allow file names with bytes > 126
|
||||
o scp_recv: improved treatment of channel_read() returning zero
|
||||
o libssh2_userauth_authenticated: make it work as documented
|
||||
o variable size cleanup: match internal variable sizes better with the sizes
|
||||
of the fields used on the wire
|
||||
o channel_request_pty_size: fix reqPTY_state
|
||||
o sftp_symlink: return error if receive buffer too small
|
||||
o sftp_readdir: return error if buffer is too small
|
||||
o libssh2_knownhost_readfile.3: clarify return value
|
||||
o configure: stop using the deprecated AM_INIT_AUTOMAKE syntax
|
||||
o Fixed Win32 makefile which was now broken at resource build
|
||||
o kex_agree_hostkey: fix NULL pointer derefence
|
||||
o _libssh2_ntohu64: fix conversion from network bytes to uint64
|
||||
o ssize_t: proper typedef with MSVC compilers
|
||||
o zlib: Add debug tracing of zlib errors
|
||||
o decomp: increase decompression buffer sizes
|
||||
|
||||
This release would not have looked like this without help, code, reports and
|
||||
advice from friends like these:
|
||||
|
||||
Alexander Lamaison, Guenter Knauf, Peter Stuge, Simon Josefsson, Lars Nordin,
|
||||
John Little, Daniel Stenberg, TJ Saunders, Tor Arntsen
|
||||
Alexander Lamaison, Alfred Gebert, Guenter Knauf, Dan Fandrich,
|
||||
Daniel Stenberg, Jasmeet Bagga, Joey Degges, Mark Smith, Peter Stuge,
|
||||
Pierre Joye, Simon Josefsson, TJ Saunders, Tommy Lindgren
|
||||
|
||||
Thanks! (and sorry if I forgot to mention someone)
|
||||
|
127
TODO
127
TODO
@@ -1,6 +1,9 @@
|
||||
Things TODO
|
||||
===========
|
||||
|
||||
* Fix the numerous malloc+copy operations for sending data, see "Buffering
|
||||
Improvements" below for details
|
||||
|
||||
* make sure the windowing code adapts better to slow situations so that it
|
||||
doesn't then use as much memory as today. Possibly by an app-controllable
|
||||
"Window mode"?
|
||||
@@ -11,9 +14,11 @@ Things TODO
|
||||
|
||||
* Add more info to the man pages.
|
||||
|
||||
* Decrease the number of mallocs. Everywhere.
|
||||
* Decrease the number of mallocs. Everywhere. Will get easier once the
|
||||
buffering improvements have been done.
|
||||
|
||||
* Use SO_NOSIGPIPE for Mac OS/BSD systems where MSG_NOSIGNAL doesn't exist/work
|
||||
* Use SO_NOSIGPIPE for Mac OS/BSD systems where MSG_NOSIGNAL doesn't
|
||||
exist/work
|
||||
|
||||
* Extend the test suite to actually test lots of aspects of libssh2
|
||||
|
||||
@@ -21,6 +26,13 @@ Things TODO
|
||||
|
||||
* Expose error messages sent by the server
|
||||
|
||||
* Make SFTP transfers ask for and send several packages at once so that it
|
||||
doesn't have to send-waitforack-send-waitforack as much. This will be
|
||||
easier/smoother if we implement the "New SFTP API" described below.
|
||||
|
||||
* select() is troublesome with libssh2 when using multiple channels over
|
||||
the same session. See "New Transport API" below for more details.
|
||||
|
||||
At next SONAME bump
|
||||
===================
|
||||
|
||||
@@ -38,6 +50,7 @@ At next SONAME bump
|
||||
libssh2_channel_receive_window_adjust()
|
||||
libssh2_poll()
|
||||
libssh2_poll_channel_read()
|
||||
libssh2_session_startup() (libssh2_session_handshake() is the replacement)
|
||||
|
||||
* Rename a few function:
|
||||
|
||||
@@ -58,3 +71,113 @@ At next SONAME bump
|
||||
|
||||
* remove the existing libssh2_knownhost_check() functin and rename
|
||||
libssh2_knownhost_checkp() to become the new libssh2_knownhost_check instead
|
||||
|
||||
Buffering Improvements
|
||||
======================
|
||||
|
||||
transport_write
|
||||
|
||||
- If this function gets called with a total packet size that is larger than
|
||||
32K, it should create more than one SSH packet so that it keeps the largest
|
||||
one below 32K
|
||||
|
||||
sftp_write
|
||||
|
||||
- should not copy/allocate anything for the data, only create a header chunk
|
||||
and pass on the payload data to channel_write "pointed to"
|
||||
|
||||
New Transport API
|
||||
=================
|
||||
|
||||
THE PROBLEM
|
||||
|
||||
The problem in a nutshell is that when an application opens up multiple
|
||||
channels over a single session, those are all using the same socket. If the
|
||||
application is then using select() to wait for traffic (like any sensible app
|
||||
does) and wants to act on the data when select() tells there is something to
|
||||
for example read, what does an application do?
|
||||
|
||||
With our current API, you have to loop over all the channels and read from
|
||||
them to see if they have data. This effectively makes blocking reads
|
||||
impossible. If the app has many channels in a setup like this, it even becomes
|
||||
slow. (The original API had the libssh2_poll_channel_read() and libssh2_poll()
|
||||
to somewhat overcome this hurdle, but they too have pretty much the same
|
||||
problems plus a few others.)
|
||||
|
||||
Traffic in the other direction is similarly limited: the app has to try
|
||||
sending to all channels, even though some of them may very well not accept any
|
||||
data at that point.
|
||||
|
||||
A SOLUTION
|
||||
|
||||
I suggest we introduce two new helper functions:
|
||||
|
||||
libssh2_transport_read()
|
||||
|
||||
- Read "a bunch" of data from the given socket and returns information to the
|
||||
app about what channels that are now readable (ie they will not block when
|
||||
read from). The function can be called over and over and it will repeatedly
|
||||
return info about what channels that are readable at that moment.
|
||||
|
||||
libssh2_transport_write()
|
||||
|
||||
- Returns information about what channels that are writable, in the sense
|
||||
that they have windows set from the remote side that allows data to get
|
||||
sent. Writing to one of those channels will not block. Of course, the
|
||||
underlying socket may only accept a certain amount of data, so at the first
|
||||
short return, nothing more should be attempted to get sent until select()
|
||||
(or equivalent) has been used on the master socket again.
|
||||
|
||||
I haven't yet figured out a sensible API for how these functions should return
|
||||
that info, but if we agree on the general principles I guess we can work that
|
||||
out.
|
||||
|
||||
VOLUNTARY
|
||||
|
||||
I wanted to mention that these two helper functions would not be mandatory
|
||||
in any way. They would just be there for those who want them, and existing
|
||||
programs can remain using the old functions only if they prefer to.
|
||||
|
||||
New SFTP API
|
||||
============
|
||||
|
||||
PURPOSE
|
||||
|
||||
Provide API functions that explicitly tells at once that a (full) SFTP file
|
||||
transfer is wanted, to allow libssh2 to leverage on that knowledge to speed
|
||||
up things internally. It can for example do read ahead, buffer writes (merge
|
||||
small writes into larger chunks), better tune the SSH window and more. This
|
||||
sort of API is already provided for SCP transfers.
|
||||
|
||||
API
|
||||
|
||||
New functions:
|
||||
|
||||
LIBSSH2_SFTP_HANDLE *libssh2_sftp_send(SFTP_SESSION *sftp,
|
||||
uint64_t filesize,
|
||||
char *remote_path,
|
||||
size_t remote_path_len,
|
||||
long mode);
|
||||
|
||||
Tell libssh2 that a local file with a given size is about to get sent to
|
||||
the SFTP server.
|
||||
|
||||
LIBSSH2_SFTP_HANDLE *libssh2_sftp_recv();
|
||||
|
||||
Tell libssh2 that a remote file is requested to get downloaded from the SFTP
|
||||
server.
|
||||
|
||||
Only the setup of the file transfer is different from an application's point
|
||||
of view. Depending on direction of the transfer(s), the following already
|
||||
existing functions should then be used until the transfer is complete:
|
||||
|
||||
libssh2_sftp_read()
|
||||
libssh2_sftp_write()
|
||||
|
||||
HOW TO USE
|
||||
|
||||
1. Setup the transfer using one of the two new functions.
|
||||
|
||||
2. Loop through the reading or writing of data.
|
||||
|
||||
3. Cleanup the transfer
|
||||
|
@@ -16,7 +16,7 @@ fi
|
||||
|
||||
dnl figure out the libssh2 version
|
||||
VERSION=`$SED -ne 's/^#define LIBSSH2_VERSION *"\(.*\)"/\1/p' ${srcdir}/include/libssh2.h`
|
||||
AM_INIT_AUTOMAKE(libssh2,$VERSION)
|
||||
AM_INIT_AUTOMAKE
|
||||
AC_MSG_CHECKING([libssh2 version])
|
||||
AC_MSG_RESULT($VERSION)
|
||||
|
||||
|
@@ -26,6 +26,7 @@ dist_man_MANS = \
|
||||
libssh2_channel_forward_listen_ex.3 \
|
||||
libssh2_channel_free.3 \
|
||||
libssh2_channel_get_exit_status.3 \
|
||||
libssh2_channel_get_exit_signal.3 \
|
||||
libssh2_channel_handle_extended_data.3 \
|
||||
libssh2_channel_handle_extended_data2.3 \
|
||||
libssh2_channel_ignore_extended_data.3 \
|
||||
@@ -59,6 +60,7 @@ dist_man_MANS = \
|
||||
libssh2_channel_x11_req.3 \
|
||||
libssh2_channel_x11_req_ex.3 \
|
||||
libssh2_exit.3 \
|
||||
libssh2_free.3 \
|
||||
libssh2_free_host_entry.3 \
|
||||
libssh2_host_entry_match.3 \
|
||||
libssh2_hostkey_hash.3 \
|
||||
@@ -133,6 +135,7 @@ dist_man_MANS = \
|
||||
libssh2_sftp_rmdir.3 \
|
||||
libssh2_sftp_rmdir_ex.3 \
|
||||
libssh2_sftp_seek.3 \
|
||||
libssh2_sftp_seek64.3 \
|
||||
libssh2_sftp_setstat.3 \
|
||||
libssh2_sftp_shutdown.3 \
|
||||
libssh2_sftp_stat.3 \
|
||||
@@ -155,6 +158,7 @@ dist_man_MANS = \
|
||||
libssh2_userauth_list.3 \
|
||||
libssh2_userauth_password.3 \
|
||||
libssh2_userauth_password_ex.3 \
|
||||
libssh2_userauth_publickey.3 \
|
||||
libssh2_userauth_publickey_fromfile.3 \
|
||||
libssh2_userauth_publickey_fromfile_ex.3 \
|
||||
libssh2_version.3
|
||||
|
36
docs/libssh2_channel_get_exit_signal.3
Normal file
36
docs/libssh2_channel_get_exit_signal.3
Normal file
@@ -0,0 +1,36 @@
|
||||
.\" $Id$
|
||||
.\"
|
||||
.TH libssh2_channel_get_exit_signal 3 "4 Oct 2010" "libssh2 1.2.8" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_channel_get_exit_signal - get the remote exit signal
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
int
|
||||
libssh2_channel_get_exit_signal(LIBSSH2_CHANNEL *channel, char **exitsignal, size_t *exitsignal_len, char **errmsg, size_t *errmsg_len, char **langtag, size_t *langtag_len);
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fIchannel\fP - Closed channel stream to retrieve exit signal from.
|
||||
|
||||
\fIexitsignal\fP - If not NULL, is populated by reference with the exit signal
|
||||
(without leading "SIG"). Note that the string is stored in a newly allocated
|
||||
buffer. If the remote program exited cleanly, the referenced string pointer
|
||||
will be set to NULL.
|
||||
|
||||
\fIexitsignal_len\fP - If not NULL, is populated by reference with the length
|
||||
of exitsignal.
|
||||
|
||||
\fIerrmsg\fP - If not NULL, is populated by reference with the error message
|
||||
(if provided by remote server, if not it will be set to NULL). Note that the
|
||||
string is stored in a newly allocated buffer.
|
||||
|
||||
\fIerrmsg_len\fP - If not NULL, is populated by reference with the length of errmsg.
|
||||
|
||||
\fIlangtag\fP - If not NULL, is populated by reference with the language tag
|
||||
(if provided by remote server, if not it will be set to NULL). Note that the
|
||||
string is stored in a newly allocated buffer.
|
||||
|
||||
\fIlangtag_len\fP - If not NULL, is populated by reference with the length of langtag.
|
||||
|
||||
.SH RETURN VALUE
|
||||
Numeric error code corresponding to the the Error Code constants.
|
19
docs/libssh2_free.3
Normal file
19
docs/libssh2_free.3
Normal file
@@ -0,0 +1,19 @@
|
||||
.TH libssh2_exit 3 "13 Oct 2010" "libssh2 1.2.8" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_free - deallocate libssh2 memory
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
void
|
||||
libssh2_free(LIBSSH2_SESSION *session, void *ptr);
|
||||
.SH DESCRIPTION
|
||||
Deallocate memory allocated by earlier call to libssh2 functions. It
|
||||
uses the memory allocation callbacks provided by the application, if
|
||||
any. Otherwise, this will just call free().
|
||||
|
||||
This function is mostly useful under Windows when libssh2 is linked to
|
||||
one run-time library and the application to another.
|
||||
.SH AVAILABILITY
|
||||
Added in libssh2 1.2.8
|
||||
.SH SEE ALSO
|
||||
.BR libssh2_session_init_ex(3)
|
@@ -1,5 +1,5 @@
|
||||
.\"
|
||||
.\" Copyright (c) 2009 by Daniel Stenberg
|
||||
.\" Copyright (c) 2009-2011 by Daniel Stenberg
|
||||
.\"
|
||||
.TH libssh2_knownhost_readfile 3 "28 May 2009" "libssh2 1.2" "libssh2 manual"
|
||||
.SH NAME
|
||||
@@ -19,8 +19,8 @@ collection of known hosts.
|
||||
\fILIBSSH2_KNOWNHOST_FILE_OPENSSH\fP is the only currently supported
|
||||
format. This file is normally found named ~/.ssh/known_hosts
|
||||
.SH RETURN VALUE
|
||||
Returns a regular libssh2 error code, where negative values are error codes
|
||||
and 0 indicates success.
|
||||
Returns a negative value, a regular libssh2 error code for errors, or a
|
||||
positive number as number of parsed known hosts in the file.
|
||||
.SH AVAILABILITY
|
||||
Added in libssh2 1.2
|
||||
.SH SEE ALSO
|
||||
|
@@ -29,7 +29,8 @@ Called when a SSH_MSG_DEBUG message is received
|
||||
.IP LIBSSH2_CALLBACK_DISCONNECT
|
||||
Called when a SSH_MSG_DISCONNECT message is received
|
||||
.IP LIBSSH2_CALLBACK_MACERROR
|
||||
Called when a mismatched MAC has been detected in the transport layer
|
||||
Called when a mismatched MAC has been detected in the transport layer. If the
|
||||
function returns 0, the packet will be accepted nonetheless.
|
||||
.IP LIBSSH2_CALLBACK_X11
|
||||
Called when an X11 connection has been accepted
|
||||
.SH RETURN VALUE
|
||||
|
@@ -5,11 +5,21 @@
|
||||
libssh2_session_flag - TODO
|
||||
.SH SYNOPSIS
|
||||
int
|
||||
libssh2_session_flag(LIBSSH2_SESSION * session, int flag, int value);
|
||||
libssh2_session_flag(LIBSSH2_SESSION *session, int flag, int value);
|
||||
.SH DESCRIPTION
|
||||
This function has no purpose and no documented flags can be set nor read.
|
||||
Set options for the created session. \fIflag\fP is the option to set, while
|
||||
\fIvalue\fP is typically set to 1 or 0 to enable or disable the option.
|
||||
.SH FLAGS
|
||||
.IP LIBSSH2_FLAG_SIGPIPE
|
||||
If set, libssh2 will not attempt to block SIGPIPEs but will let them trigger
|
||||
from the underlying socket layer.
|
||||
.IP LIBSSH2_FLAG_COMPRESS
|
||||
If set - before the connection negotiation is performed - libssh2 will try to
|
||||
negotiate compression enabling for this connection. By default libssh2 will
|
||||
not attempt to use compression.
|
||||
.SH RETURN VALUE
|
||||
0
|
||||
.SH ERRORS
|
||||
Its mere existence is an error
|
||||
Returns regular libssh2 error code.
|
||||
.SH AVAILABILITY
|
||||
This function has existed since the age of dawn. LIBSSH2_FLAG_COMPRESS was
|
||||
added in version 1.2.8.
|
||||
.SH SEE ALSO
|
||||
|
42
docs/libssh2_session_handshake.3
Normal file
42
docs/libssh2_session_handshake.3
Normal file
@@ -0,0 +1,42 @@
|
||||
.\" $Id: libssh2_session_handshake.3,v 1.7 2009/03/16 23:25:14 bagder Exp $
|
||||
.\"
|
||||
.TH libssh2_session_handshake 3 "7 Oct 2010" "libssh2 1.2.8" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_session_handshake - perform the SSH handshake
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
int
|
||||
libssh2_session_handshake(LIBSSH2_SESSION *session, libssh2_socket_t socket);
|
||||
.SH DESCRIPTION
|
||||
\fIsession\fP - Session instance as returned by
|
||||
.BR libssh2_session_init_ex(3)
|
||||
|
||||
\fIsocket\fP - Connected socket descriptor. Typically a TCP connection
|
||||
though the protocol allows for any reliable transport and the library will
|
||||
attempt to use any berkeley socket.
|
||||
|
||||
Begin transport layer protocol negotiation with the connected host.
|
||||
.SH RETURN VALUE
|
||||
Returns 0 on success, negative on failure.
|
||||
.SH ERRORS
|
||||
\fILIBSSH2_ERROR_SOCKET_NONE\fP - The socket is invalid.
|
||||
|
||||
\fILIBSSH2_ERROR_BANNER_SEND\fP - Unable to send banner to remote host.
|
||||
|
||||
\fILIBSSH2_ERROR_KEX_FAILURE\fP - >Encryption key exchange with the remote
|
||||
host failed.
|
||||
|
||||
\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
|
||||
|
||||
\fILIBSSH2_ERROR_SOCKET_DISCONNECT\fP - The socket was disconnected.
|
||||
|
||||
\fILIBSSH2_ERROR_PROTO\fP - An invalid SSH protocol response was received on
|
||||
the socket.
|
||||
|
||||
\fILIBSSH2_ERROR_EAGAIN\fP - Marked for non-blocking I/O but the call would block.
|
||||
.SH AVAILABILITY
|
||||
Added in 1.2.8
|
||||
.SH SEE ALSO
|
||||
.BR libssh2_session_free(3)
|
||||
.BR libssh2_session_init_ex(3)
|
@@ -13,17 +13,17 @@ libssh2_session_methods(LIBSSH2_SESSION *session, int method_type);
|
||||
\fIsession\fP - Session instance as returned by
|
||||
.BR libssh2_session_init_ex(3)
|
||||
|
||||
\fImethod_type\fP - One of the Method Type constants.
|
||||
|
||||
Return the actual method negotiated for a particular transport parameter.
|
||||
\fImethod_type\fP - one of the method type constants: LIBSSH2_METHOD_KEX,
|
||||
LIBSSH2_METHOD_HOSTKEY, LIBSSH2_METHOD_CRYPT_CS, LIBSSH2_METHOD_CRYPT_SC,
|
||||
LIBSSH2_METHOD_MAC_CS, LIBSSH2_METHOD_MAC_SC, LIBSSH2_METHOD_COMP_CS,
|
||||
LIBSSH2_METHOD_COMP_SC, LIBSSH2_METHOD_LANG_CS, LIBSSH2_METHOD_LANG_SC.
|
||||
|
||||
Returns the actual method negotiated for a particular transport parameter.
|
||||
.SH RETURN VALUE
|
||||
Negotiated method or NULL if the session has not yet been started.
|
||||
|
||||
.SH ERRORS
|
||||
\fILIBSSH2_ERROR_INVAL\fP - The requested method type was invalid.
|
||||
|
||||
\fILIBSSH2_ERROR_METHOD_NONE\fP -
|
||||
|
||||
\fILIBSSH2_ERROR_METHOD_NONE\fP - no method has been set
|
||||
.SH SEE ALSO
|
||||
.BR libssh2_session_init_ex(3)
|
||||
|
@@ -8,8 +8,10 @@ libssh2_session_startup - begin transport layer
|
||||
|
||||
int
|
||||
libssh2_session_startup(LIBSSH2_SESSION *session, int socket);
|
||||
|
||||
.SH DESCRIPTION
|
||||
Starting in libssh2 version 1.2.8 this function is considered deprecated. Use
|
||||
\fIlibssh2_session_handshake(3)\fP instead.
|
||||
|
||||
\fIsession\fP - Session instance as returned by
|
||||
.BR libssh2_session_init_ex(3)
|
||||
|
||||
|
@@ -4,31 +4,45 @@
|
||||
.SH NAME
|
||||
libssh2_sftp_open - open filehandle for file on SFTP.
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
#include <libssh2.h>
|
||||
#include <libssh2_sftp.h>
|
||||
|
||||
LIBSSH2_SFTP_HANDLE *
|
||||
libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, const char *filename, unsigned int filename_len, unsigned long flags, long mode, int open_type);
|
||||
|
||||
LIBSSH2_SFTP_HANDLE *
|
||||
libssh2_sftp_open(LIBSSH2_SFTP *sftp, const char *filename, unsigned long flags, long mode);
|
||||
|
||||
LIBSSH2_SFTP_HANDLE *
|
||||
libssh2_sftp_opendir(LIBSSH2_SFTP *sftp, const char *path);
|
||||
|
||||
libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, const char *filename,
|
||||
unsigned int filename_len, unsigned long flags,
|
||||
long mode, int open_type);
|
||||
.SH DESCRIPTION
|
||||
\fIsftp\fP - SFTP instance as returned by
|
||||
.BR libssh2_sftp_init(3)
|
||||
\fIsftp\fP - SFTP instance as returned by \fIlibssh2_sftp_init(3)\fP
|
||||
|
||||
\fIfilename\fP - Remote file/directory resource to open
|
||||
|
||||
\fIfilename_len\fP - Length of filename
|
||||
|
||||
\fIflags\fP - Any (reasonable) combination of the LIBSSH2_FXF_* constants
|
||||
corresponding fopen modes.
|
||||
\fIflags\fP - Any reasonable combination of the LIBSSH2_FXF_* constants:
|
||||
.RS
|
||||
.IP LIBSSH2_FXF_READ
|
||||
Open the file for reading.
|
||||
.IP LIBSSH2_FXF_WRITE
|
||||
Open the file for writing. If both this and LIBSSH2_FXF_READ are specified,
|
||||
the file is opened for both reading and writing.
|
||||
.IP LIBSSH2_FXF_APPEND
|
||||
Force all writes to append data at the end of the file.
|
||||
.IP LIBSSH2_FXF_CREAT,
|
||||
If this flag is specified, then a new file will be created if one does not
|
||||
already exist (if LIBSSH2_FXF_TRUNC is specified, the new file will be
|
||||
truncated to zero length if it previously exists)
|
||||
.IP LIBSSH2_FXF_TRUNC
|
||||
Forces an existing file with the same name to be truncated to zero length when
|
||||
creating a file by specifying LIBSSH2_FXF_CREAT. LIBSSH2_FXF_CREAT MUST also
|
||||
be specified if this flag is used.
|
||||
.IP LIBSSH2_FXF_EXCL
|
||||
Causes the request to fail if the named file already exists.
|
||||
LIBSSH2_FXF_CREAT MUST also be specified if this flag is used.
|
||||
|
||||
.RE
|
||||
\fImode\fP - POSIX file permissions to assign if the file is being newly
|
||||
created.
|
||||
created. See the LIBSSH2_SFTP_S_* convenience defines in <libssh2_sftp.h>
|
||||
|
||||
\fIopen_type\fP - Either of LIBSSH2_SFTP_OPENFILE (to open a file) or
|
||||
LIBSSH2_SFTP_OPENDIR (to open a directory).
|
||||
|
@@ -13,9 +13,6 @@ libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *handle,
|
||||
char *buffer, size_t buffer_maxlen,
|
||||
char *longentry, size_t longentry_maxlen,
|
||||
LIBSSH2_SFTP_ATTRIBUTES *attrs);
|
||||
|
||||
#define libssh2_sftp_readdir(h, b, bl, a) \\
|
||||
libssh2_sftp_readdir_ex((h), (b), (bl), NULL, 0, (a))
|
||||
.SH DESCRIPTION
|
||||
Reads a block of data from a LIBSSH2_SFTP_HANDLE and returns file entry
|
||||
information for the next entry, if any.
|
||||
@@ -47,6 +44,10 @@ Number of bytes actually populated into buffer (not counting the terminating
|
||||
zero), or negative on failure. It returns LIBSSH2_ERROR_EAGAIN when it would
|
||||
otherwise block. While LIBSSH2_ERROR_EAGAIN is a negative number, it isn't
|
||||
really a failure per se.
|
||||
.SH BUG
|
||||
Passing in a too small buffer for 'buffer' or 'longentry' when receiving data
|
||||
only results in libssh2 1.2.7 or earlier to not copy the entire data amount,
|
||||
and it is not possible for the application to tell when it happens!
|
||||
.SH ERRORS
|
||||
\fILIBSSH2_ERROR_ALLOC\fP - An internal memory allocation call failed.
|
||||
|
||||
@@ -57,6 +58,10 @@ really a failure per se.
|
||||
\fILIBSSH2_ERROR_SFTP_PROTOCOL\fP - An invalid SFTP protocol response was
|
||||
received on the socket, or an SFTP operation caused an errorcode to be
|
||||
returned by the server.
|
||||
|
||||
From 1.2.8, LIBSSH2_ERROR_BUFFER_TOO_SMALL is returned if any of the
|
||||
given 'buffer' or 'longentry' buffers are too small to fit the requested
|
||||
object name.
|
||||
.SH SEE ALSO
|
||||
.BR libssh2_sftp_open_ex(3),
|
||||
.BR libssh2_sftp_close_handle(3)
|
||||
|
@@ -4,16 +4,14 @@
|
||||
.SH NAME
|
||||
libssh2_sftp_seek - set the read/write position indicator within a file
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
#include <libssh2.h>
|
||||
#include <libssh2_sftp.h>
|
||||
|
||||
void
|
||||
libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE *handle, size_t offset);
|
||||
|
||||
void
|
||||
libssh2_sftp_seek64(LIBSSH2_SFTP_HANDLE *handle, libssh2_uint64_t offset);
|
||||
|
||||
void libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE *handle, size_t offset);
|
||||
.SH DESCRIPTION
|
||||
Deprecated function. Use \fIlibssh2_sftp_seek64(3)\fP instead!
|
||||
|
||||
\fIhandle\fP - SFTP File Handle as returned by
|
||||
.BR libssh2_sftp_open_ex(3)
|
||||
|
||||
@@ -24,7 +22,6 @@ Note that libssh2 implements file pointers as a localized concept to make
|
||||
file access appear more POSIX like. No packets are exchanged with the server
|
||||
during a seek operation. The localized file pointer is simply used as a
|
||||
convenience offset during read/write operations.
|
||||
.SH AVAILABILITY
|
||||
libssh2_sftp_seek64(3) was added in 1.0
|
||||
.SH SEE ALSO
|
||||
.BR libssh2_sftp_open_ex(3)
|
||||
.BR libssh2_sftp_open_ex(3),
|
||||
.BR libssh2_sftp_seek64(3)
|
||||
|
31
docs/libssh2_sftp_seek64.3
Normal file
31
docs/libssh2_sftp_seek64.3
Normal file
@@ -0,0 +1,31 @@
|
||||
.\" $Id: libssh2_sftp_seek.3,v 1.5 2009/03/17 10:34:27 bagder Exp $
|
||||
.\"
|
||||
.TH libssh2_sftp_seek64 3 "22 Dec 2008" "libssh2 1.0" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_sftp_seek64 - set the read/write position within a file
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
#include <libssh2.h>
|
||||
#include <libssh2_sftp.h>
|
||||
|
||||
void libssh2_sftp_seek64(LIBSSH2_SFTP_HANDLE *handle,
|
||||
libssh2_uint64_t offset);
|
||||
.SH DESCRIPTION
|
||||
\fIhandle\fP - SFTP File Handle as returned by
|
||||
.BR libssh2_sftp_open_ex(3)
|
||||
|
||||
\fIoffset\fP - Number of bytes from the beginning of file to seek to.
|
||||
|
||||
Move the file handle's internal pointer to an arbitrary location. libssh2
|
||||
implements file pointers as a localized concept to make file access appear
|
||||
more POSIX like. No packets are exchanged with the server during a seek
|
||||
operation. The localized file pointer is simply used as a convenience offset
|
||||
during read/write operations.
|
||||
|
||||
You MUST NOT seek during writing or reading a file with SFTP, as the internals
|
||||
use outstanding packets and changing the "file position" during transit will
|
||||
results in badness.
|
||||
.SH AVAILABILITY
|
||||
Added in 1.0
|
||||
.SH SEE ALSO
|
||||
.BR libssh2_sftp_open_ex(3)
|
@@ -4,21 +4,13 @@
|
||||
.SH NAME
|
||||
libssh2_sftp_stat_ex - get status about an SFTP file
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
#include <libssh2.h>
|
||||
#include <libssh2_sftp.h>
|
||||
|
||||
int
|
||||
libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len, int stat_type, LIBSSH2_SFTP_ATTRIBUTES *attrs);
|
||||
|
||||
int
|
||||
libssh2_sftp_stat(LIBSSH2_SFTP *sftp, const char *path, LIBSSH2_SFTP_ATTRIBUTES *attrs);
|
||||
|
||||
int
|
||||
libssh2_sftp_lstat(LIBSSH2_SFTP *sftp, const char *path, LIBSSH2_SFTP_ATTRIBUTES *attrs);
|
||||
|
||||
int
|
||||
libssh2_sftp_setstat(LIBSSH2_SFTP *sftp, const char *path, LIBSSH2_SFTP_ATTRIBUTES *attrs);
|
||||
|
||||
int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, const char *path,
|
||||
unsigned int path_len, int stat_type,
|
||||
LIBSSH2_SFTP_ATTRIBUTES *attrs);
|
||||
.SH DESCRIPTION
|
||||
\fIsftp\fP - SFTP instance as returned by
|
||||
.BR libssh2_sftp_init(3)
|
||||
@@ -29,24 +21,47 @@ libssh2_sftp_setstat(LIBSSH2_SFTP *sftp, const char *path, LIBSSH2_SFTP_ATTRIBUT
|
||||
to stat/lstat/setstat.
|
||||
|
||||
\fIstat_type\fP - One of the three constants specifying the type of
|
||||
stat operation to perform.
|
||||
stat operation to perform:
|
||||
|
||||
\fIattrs\fP - Pointer to attribute structure to set file metadata
|
||||
from or into depending on the value of stat_type.
|
||||
.br
|
||||
\fBLIBSSH2_SFTP_STAT\fP: performs stat(2) operation
|
||||
.br
|
||||
\fBLIBSSH2_SFTP_LSTAT\fP: performs lstat(2) operation
|
||||
.br
|
||||
\fBLIBSSH2_SFTP_SETSTAT\fP: performs operation to set stat info on file
|
||||
|
||||
Get or Set statbuf type data on a remote filesystem object. When
|
||||
getting statbuf data,
|
||||
\fIattrs\fP - Pointer to a \fBLIBSSH2_SFTP_ATTRIBUTES\fP structure to set file
|
||||
metadata from or into depending on the value of stat_type.
|
||||
|
||||
Get or Set statbuf type data on a remote filesystem object. When getting
|
||||
statbuf data,
|
||||
.BR libssh2_sftp_stat(3)
|
||||
will follow all symlinks, while
|
||||
.BR libssh2_sftp_lstat(3)
|
||||
will return data about the object encountered, even if that object
|
||||
happens to be a symlink.
|
||||
|
||||
.SH RETURN VALUE
|
||||
Return 0 on success or negative on failure. It returns
|
||||
LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
|
||||
LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
|
||||
The LIBSSH2_SFTP_ATTRIBUTES struct looks like this:
|
||||
|
||||
.nf
|
||||
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;
|
||||
unsigned long gid;
|
||||
unsigned long permissions;
|
||||
unsigned long atime;
|
||||
unsigned long mtime;
|
||||
};
|
||||
.fi
|
||||
.SH RETURN VALUE
|
||||
Returns 0 on success or negative on failure. It returns LIBSSH2_ERROR_EAGAIN
|
||||
when it would otherwise block. While LIBSSH2_ERROR_EAGAIN is a negative
|
||||
number, it isn't really a failure per se.
|
||||
.SH ERRORS
|
||||
\fILIBSSH2_ERROR_ALLOC\fP - An internal memory allocation call failed.
|
||||
|
||||
@@ -57,6 +72,5 @@ LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
|
||||
\fILIBSSH2_ERROR_SFTP_PROTOCOL\fP - An invalid SFTP protocol response was
|
||||
received on the socket, or an SFTP operation caused an errorcode to
|
||||
be returned by the server.
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR libssh2_sftp_init(3)
|
||||
|
@@ -12,9 +12,6 @@ int
|
||||
libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path,
|
||||
unsigned int path_len, char *target,
|
||||
unsigned int target_len, int link_type);
|
||||
int
|
||||
libssh2_sftp_realpath(LIBSSH2_SFTP *sftp, const char *path, char *target,
|
||||
unsigned int target_len);
|
||||
.SH DESCRIPTION
|
||||
Create a symlink or read out symlink information from the remote side.
|
||||
|
||||
@@ -62,6 +59,13 @@ zero) or negative on failure.
|
||||
|
||||
It returns LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
|
||||
LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
|
||||
|
||||
From 1.2.8, LIBSSH2_ERROR_BUFFER_TOO_SMALL is returned if the given 'target'
|
||||
buffer is too small to fit the requested object name.
|
||||
.SH BUG
|
||||
Passing in a too small buffer when receiving data only results in libssh2
|
||||
1.2.7 or earlier to not copy the entire data amount, and it is not possible
|
||||
for the application to tell when it happens!
|
||||
.SH ERRORS
|
||||
\fILIBSSH2_ERROR_ALLOC\fP - An internal memory allocation call failed.
|
||||
|
||||
|
@@ -27,6 +27,28 @@ possible to write all bytes as requested.
|
||||
put it into a single SFTP protocol packet. This means that to get maximum
|
||||
performance when sending larger files, you should try to always pass in at
|
||||
least 32K of data to this function.
|
||||
|
||||
.SH WRITE AHEAD
|
||||
Starting in libssh2 version 1.2.8, the default behavior of libssh2 is to
|
||||
create several smaller outgoing packets for all data you pass to this function
|
||||
and it will return a positive number as soon as the first packet is
|
||||
acknowledged from the server.
|
||||
|
||||
This has the effect that sometimes more data has been sent off but isn't acked
|
||||
yet when this function returns, and when this function is subsequently called
|
||||
again to write more data, libssh2 will immediately figure out that the data is
|
||||
already received remotely.
|
||||
|
||||
In most normal situation this should not cause any problems, but it should be
|
||||
noted that if you've once called libssh2_sftp_write() with data and it returns
|
||||
short, you MUST still assume that the rest of the data might've been cached so
|
||||
you need to make sure you don't alter that data and think that the version you
|
||||
have in your next function invoke will be detected or used.
|
||||
|
||||
The reason for this funny behavior is that SFTP can only send 32K data in each
|
||||
packet and it gets all packets acked individually. This means we cannot use a
|
||||
simple serial approach if we want to reach high performance even on high
|
||||
latency connections. And we want that.
|
||||
.SH RETURN VALUE
|
||||
Actual number of bytes written or negative on failure.
|
||||
|
||||
|
@@ -2,42 +2,40 @@
|
||||
.\"
|
||||
.TH libssh2_userauth_list 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_userauth_list - list the authentication methods supported by a server
|
||||
libssh2_userauth_list - list supported authentication methods
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
#include <libssh2.h>
|
||||
|
||||
char *
|
||||
libssh2_userauth_list(LIBSSH2_SESSION *session, const char *username, unsigned int username_len);
|
||||
|
||||
libssh2_userauth_list(LIBSSH2_SESSION *session, const char *username,
|
||||
unsigned int username_len);
|
||||
.SH DESCRIPTION
|
||||
\fIsession\fP - Session instance as returned by
|
||||
.BR libssh2_session_init_ex(3)
|
||||
|
||||
\fIusername\fP - Username which will be used while authenticating. Note
|
||||
that most server implementations do not permit attempting authentication
|
||||
with different usernames between requests. Therefore this must be the
|
||||
same username you will use on later userauth calls.
|
||||
\fIusername\fP - Username which will be used while authenticating. Note that
|
||||
most server implementations do not permit attempting authentication with
|
||||
different usernames between requests. Therefore this must be the same username
|
||||
you will use on later userauth calls.
|
||||
|
||||
\fIusername_len\fP - Length of username parameter.
|
||||
|
||||
Send a \fBSSH_USERAUTH_NONE\fP request to the remote host. Unless the
|
||||
remote host is configured to accept none as a viable authentication
|
||||
scheme (unlikely), it will return \fBSSH_USERAUTH_FAILURE\fB along with a
|
||||
listing of what authentication schemes it does support. In the unlikely
|
||||
event that none authentication succeeds, this method with return NULL. This
|
||||
case may be distinguished from faily by examining
|
||||
.BR libssh2_userauth_authenticated(3)
|
||||
|
||||
Send a \fBSSH_USERAUTH_NONE\fP request to the remote host. Unless the remote
|
||||
host is configured to accept none as a viable authentication scheme
|
||||
(unlikely), it will return \fBSSH_USERAUTH_FAILURE\fP along with a listing of
|
||||
what authentication schemes it does support. In the unlikely event that none
|
||||
authentication succeeds, this method with return NULL. This case may be
|
||||
distinguished from a failing case by examining
|
||||
\fIlibssh2_userauth_authenticated(3)\fP.
|
||||
.SH RETURN VALUE
|
||||
On success a comma delimited list of supported authentication schemes. This list is
|
||||
internally managed by libssh2. On failure ruturns NULL.
|
||||
|
||||
On success a comma delimited list of supported authentication schemes. This
|
||||
list is internally managed by libssh2. On failure ruturns NULL.
|
||||
.SH ERRORS
|
||||
\fILIBSSH2_ERROR_ALLOC\fP - An internal memory allocation call failed.
|
||||
|
||||
\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
|
||||
|
||||
\fILIBSSH2_ERROR_EAGAIN\fP - Marked for non-blocking I/O but the call
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR libssh2_session_init_ex(3)
|
||||
|
29
docs/libssh2_userauth_publickey.3
Normal file
29
docs/libssh2_userauth_publickey.3
Normal file
@@ -0,0 +1,29 @@
|
||||
.\" $Id: template.3,v 1.4 2007/06/13 16:41:33 jehousley Exp $
|
||||
.\"
|
||||
.TH libssh2_userauth_publickey 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
|
||||
.SH NAME
|
||||
libssh2_userauth_publickey - authenticate using a callback function
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
.NF
|
||||
int libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
||||
const char *user,
|
||||
const unsigned char *pubkeydata,
|
||||
size_t pubkeydata_len,
|
||||
sign_callback,
|
||||
void **abstract);
|
||||
.SH DESCRIPTION
|
||||
Authenticate with the \fIsign_callback\fP callback that matches the prototype
|
||||
below
|
||||
.SH CALLBACK
|
||||
.nf
|
||||
int name(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
|
||||
const unsigned char *data, size_t data_len, void **abstract);
|
||||
.fi
|
||||
|
||||
This function gets called...
|
||||
.SH RETURN VALUE
|
||||
Return 0 on success or negative on failure.
|
||||
.SH SEE ALSO
|
||||
.BR libssh2_userauth_publickey_fromfile_ex(3)
|
@@ -6,12 +6,12 @@ libssh2_userauth_publickey_fromfile - authenticate a session with a public key,
|
||||
.SH SYNOPSIS
|
||||
#include <libssh2.h>
|
||||
|
||||
int
|
||||
libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len, const char *publickey, const char *privatekey, const char *passphrase);
|
||||
|
||||
int
|
||||
libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, const char *username, const char *publickey, const char *privatekey, const char *passphrase);
|
||||
|
||||
.nf
|
||||
int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
|
||||
const char *username,
|
||||
const char *publickey,
|
||||
const char *privatekey,
|
||||
const char *passphrase);
|
||||
.SH DESCRIPTION
|
||||
\fIsession\fP - Session instance as returned by
|
||||
.BR libssh2_session_init_ex(3)
|
||||
|
@@ -3,14 +3,10 @@ AUTOMAKE_OPTIONS = foreign nostdinc
|
||||
EXTRA_DIST = libssh2_config.h.in
|
||||
|
||||
# samples
|
||||
noinst_PROGRAMS = direct_tcpip ssh2 \
|
||||
scp scp_nonblock \
|
||||
scp_write scp_write_nonblock \
|
||||
sftp sftp_nonblock \
|
||||
sftp_write sftp_write_nonblock \
|
||||
sftp_mkdir sftp_mkdir_nonblock \
|
||||
sftp_RW_nonblock \
|
||||
sftpdir sftpdir_nonblock ssh2_exec ssh2_agent
|
||||
noinst_PROGRAMS = direct_tcpip ssh2 scp scp_nonblock scp_write \
|
||||
scp_write_nonblock sftp sftp_nonblock sftp_write sftp_write_nonblock \
|
||||
sftp_mkdir sftp_mkdir_nonblock sftp_RW_nonblock sftpdir \
|
||||
sftpdir_nonblock ssh2_exec ssh2_agent ssh2_echo sftp_append
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/example
|
||||
LDADD = $(top_builddir)/src/libssh2.la
|
||||
|
@@ -137,7 +137,8 @@ int main(int argc, char *argv[])
|
||||
channel = libssh2_scp_recv(session, scppath, &fileinfo);
|
||||
|
||||
if (!channel) {
|
||||
fprintf(stderr, "Unable to open a session\n");
|
||||
fprintf(stderr, "Unable to open a session: %d\n",
|
||||
libssh2_session_last_errno(session));
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
|
@@ -34,6 +34,36 @@
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
|
||||
static int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
|
||||
{
|
||||
struct timeval timeout;
|
||||
int rc;
|
||||
fd_set fd;
|
||||
fd_set *writefd = NULL;
|
||||
fd_set *readfd = NULL;
|
||||
int dir;
|
||||
|
||||
timeout.tv_sec = 10;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
FD_ZERO(&fd);
|
||||
|
||||
FD_SET(socket_fd, &fd);
|
||||
|
||||
/* now make sure we wait in the correct direction */
|
||||
dir = libssh2_session_block_directions(session);
|
||||
|
||||
if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
|
||||
readfd = &fd;
|
||||
|
||||
if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
|
||||
writefd = &fd;
|
||||
|
||||
rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned long hostaddr;
|
||||
@@ -58,6 +88,7 @@ int main(int argc, char *argv[])
|
||||
time_t start;
|
||||
long total = 0;
|
||||
int duration;
|
||||
size_t prev;
|
||||
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
@@ -190,15 +221,23 @@ int main(int argc, char *argv[])
|
||||
|
||||
total += nread;
|
||||
|
||||
prev = 0;
|
||||
do {
|
||||
/* write the same data over and over, until error or completion */
|
||||
rc = libssh2_channel_write(channel, ptr, nread);
|
||||
if (LIBSSH2_ERROR_EAGAIN == rc) { /* must loop around */
|
||||
continue;
|
||||
} else if (rc < 0) {
|
||||
fprintf(stderr, "ERROR %d\n", rc);
|
||||
while ((rc = libssh2_channel_write(channel, ptr, nread)) ==
|
||||
LIBSSH2_ERROR_EAGAIN) {
|
||||
waitsocket(sock, session);
|
||||
prev = 0;
|
||||
}
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "ERROR %d total %ld / %d prev %d\n", rc,
|
||||
total, (int)nread, (int)prev);
|
||||
break;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
prev = nread;
|
||||
if(rc > nread) {
|
||||
fprintf(stderr, "MOO %d > %d\n", (int)rc, (int)nread);
|
||||
}
|
||||
/* rc indicates how many bytes were written this time */
|
||||
nread -= rc;
|
||||
ptr += rc;
|
||||
|
@@ -245,7 +245,8 @@ int main(int argc, char *argv[])
|
||||
libssh2_sftp_open(sftp_session, sftppath, LIBSSH2_FXF_READ, 0);
|
||||
|
||||
if (!sftp_handle) {
|
||||
fprintf(stderr, "Unable to open file with SFTP\n");
|
||||
fprintf(stderr, "Unable to open file with SFTP: %ld\n",
|
||||
libssh2_sftp_last_error(sftp_session));
|
||||
goto shutdown;
|
||||
}
|
||||
fprintf(stderr, "libssh2_sftp_open() is done, now receive data!\n");
|
||||
|
232
example/sftp_append.c
Normal file
232
example/sftp_append.c
Normal file
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* $Id: sftp_write.c,v 1.11 2009/04/28 10:35:30 bagder Exp $
|
||||
*
|
||||
* Sample showing how to do SFTP append of a local file onto a remote one.
|
||||
*
|
||||
* The sample code has default values for host name, user name, password
|
||||
* and path to copy, but you can specify them on the command line like:
|
||||
*
|
||||
* sftp_append 192.168.0.1 user password localfile /tmp/remotefile
|
||||
*/
|
||||
|
||||
#include "libssh2_config.h"
|
||||
#include <libssh2.h>
|
||||
#include <libssh2_sftp.h>
|
||||
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned long hostaddr;
|
||||
int sock, i, auth_pw = 1;
|
||||
struct sockaddr_in sin;
|
||||
const char *fingerprint;
|
||||
LIBSSH2_SESSION *session;
|
||||
const char *username="username";
|
||||
const char *password="password";
|
||||
const char *loclfile="sftp_write.c";
|
||||
const char *sftppath="/tmp/TEST";
|
||||
int rc;
|
||||
FILE *local;
|
||||
LIBSSH2_SFTP *sftp_session;
|
||||
LIBSSH2_SFTP_HANDLE *sftp_handle;
|
||||
LIBSSH2_SFTP_ATTRIBUTES attrs;
|
||||
char mem[1024*100];
|
||||
size_t nread;
|
||||
char *ptr;
|
||||
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
|
||||
WSAStartup(MAKEWORD(2,0), &wsadata);
|
||||
#endif
|
||||
|
||||
if (argc > 1) {
|
||||
hostaddr = inet_addr(argv[1]);
|
||||
} else {
|
||||
hostaddr = htonl(0x7F000001);
|
||||
}
|
||||
|
||||
if(argc > 2) {
|
||||
username = argv[2];
|
||||
}
|
||||
if(argc > 3) {
|
||||
password = argv[3];
|
||||
}
|
||||
if(argc > 4) {
|
||||
loclfile = argv[4];
|
||||
}
|
||||
if(argc > 5) {
|
||||
sftppath = argv[5];
|
||||
}
|
||||
|
||||
rc = libssh2_init (0);
|
||||
if (rc != 0) {
|
||||
fprintf (stderr, "libssh2 initialization failed (%d)\n", rc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
local = fopen(loclfile, "rb");
|
||||
if (!local) {
|
||||
printf("Can't local file %s\n", loclfile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The application code is responsible for creating the socket
|
||||
* and establishing the connection
|
||||
*/
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(22);
|
||||
sin.sin_addr.s_addr = hostaddr;
|
||||
if (connect(sock, (struct sockaddr*)(&sin),
|
||||
sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "failed to connect!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create a session instance
|
||||
*/
|
||||
session = libssh2_session_init();
|
||||
if(!session)
|
||||
return -1;
|
||||
|
||||
/* Since we have set non-blocking, tell libssh2 we are blocking */
|
||||
libssh2_session_set_blocking(session, 1);
|
||||
|
||||
/* ... start it up. This will trade welcome banners, exchange keys,
|
||||
* and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
rc = libssh2_session_startup(session, sock);
|
||||
if(rc) {
|
||||
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* At this point we havn't yet authenticated. The first thing to do
|
||||
* is check the hostkey's fingerprint against our known hosts Your app
|
||||
* may have it hard coded, may go to a file, may present it to the
|
||||
* user, that's your call
|
||||
*/
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 20; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if (auth_pw) {
|
||||
/* We could authenticate via password */
|
||||
if (libssh2_userauth_password(session, username, password)) {
|
||||
printf("Authentication by password failed.\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} else {
|
||||
/* Or by public key */
|
||||
if (libssh2_userauth_publickey_fromfile(session, username,
|
||||
"/home/username/.ssh/id_rsa.pub",
|
||||
"/home/username/.ssh/id_rsa",
|
||||
password)) {
|
||||
printf("\tAuthentication by public key failed\n");
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "libssh2_sftp_init()!\n");
|
||||
sftp_session = libssh2_sftp_init(session);
|
||||
|
||||
if (!sftp_session) {
|
||||
fprintf(stderr, "Unable to init SFTP session\n");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
fprintf(stderr, "libssh2_sftp_open() for READ and WRITE!\n");
|
||||
/* Request a file via SFTP */
|
||||
|
||||
sftp_handle =
|
||||
libssh2_sftp_open(sftp_session, sftppath,
|
||||
LIBSSH2_FXF_WRITE|LIBSSH2_FXF_READ,
|
||||
LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR|
|
||||
LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH);
|
||||
if (!sftp_handle) {
|
||||
fprintf(stderr, "Unable to open file with SFTP\n");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
if(libssh2_sftp_fstat_ex(sftp_handle, &attrs, 0) < 0) {
|
||||
printf("libssh2_sftp_fstat_ex failed\n");
|
||||
goto shutdown;
|
||||
}
|
||||
else
|
||||
libssh2_sftp_seek64(sftp_handle, attrs.filesize);
|
||||
printf("Did a seek to position %ld\n", (long) attrs.filesize);
|
||||
|
||||
fprintf(stderr, "libssh2_sftp_open() a handle for APPEND\n");
|
||||
|
||||
if (!sftp_handle) {
|
||||
fprintf(stderr, "Unable to open file with SFTP\n");
|
||||
goto shutdown;
|
||||
}
|
||||
fprintf(stderr, "libssh2_sftp_open() is done, now send data!\n");
|
||||
do {
|
||||
nread = fread(mem, 1, sizeof(mem), local);
|
||||
if (nread <= 0) {
|
||||
/* end of file */
|
||||
break;
|
||||
}
|
||||
ptr = mem;
|
||||
|
||||
do {
|
||||
/* write data in a loop until we block */
|
||||
rc = libssh2_sftp_write(sftp_handle, ptr, nread);
|
||||
if(rc < 0)
|
||||
break;
|
||||
ptr += rc;
|
||||
nread -= rc;
|
||||
} while (nread);
|
||||
|
||||
} while (rc > 0);
|
||||
|
||||
libssh2_sftp_close(sftp_handle);
|
||||
libssh2_sftp_shutdown(sftp_session);
|
||||
|
||||
shutdown:
|
||||
libssh2_session_disconnect(session,
|
||||
"Normal Shutdown, Thank you for playing");
|
||||
libssh2_session_free(session);
|
||||
|
||||
#ifdef WIN32
|
||||
closesocket(sock);
|
||||
#else
|
||||
close(sock);
|
||||
#endif
|
||||
if (local)
|
||||
fclose(local);
|
||||
printf("all done\n");
|
||||
|
||||
libssh2_exit();
|
||||
|
||||
return 0;
|
||||
}
|
@@ -50,7 +50,7 @@ int main(int argc, char *argv[])
|
||||
FILE *local;
|
||||
LIBSSH2_SFTP *sftp_session;
|
||||
LIBSSH2_SFTP_HANDLE *sftp_handle;
|
||||
char mem[1024];
|
||||
char mem[1024*100];
|
||||
size_t nread;
|
||||
char *ptr;
|
||||
|
||||
|
@@ -31,6 +31,9 @@
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
|
290
example/sftp_write_sliding.c
Normal file
290
example/sftp_write_sliding.c
Normal file
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* $Id: sftp_write_nonblock.c,v 1.14 2009/04/28 10:35:30 bagder Exp $
|
||||
*
|
||||
* Sample showing how to do SFTP non-blocking write transfers.
|
||||
*
|
||||
* The sample code has default values for host name, user name, password
|
||||
* and path to copy, but you can specify them on the command line like:
|
||||
*
|
||||
* "sftp 192.168.0.1 user password sftp_write_nonblock.c /tmp/sftp_write_nonblock.c"
|
||||
*/
|
||||
|
||||
#include "libssh2_config.h"
|
||||
#include <libssh2.h>
|
||||
#include <libssh2_sftp.h>
|
||||
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
# include <sys/select.h>
|
||||
#endif
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
|
||||
static int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
|
||||
{
|
||||
struct timeval timeout;
|
||||
int rc;
|
||||
fd_set fd;
|
||||
fd_set *writefd = NULL;
|
||||
fd_set *readfd = NULL;
|
||||
int dir;
|
||||
|
||||
timeout.tv_sec = 10;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
FD_ZERO(&fd);
|
||||
|
||||
FD_SET(socket_fd, &fd);
|
||||
|
||||
/* now make sure we wait in the correct direction */
|
||||
dir = libssh2_session_block_directions(session);
|
||||
|
||||
if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
|
||||
readfd = &fd;
|
||||
|
||||
if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
|
||||
writefd = &fd;
|
||||
|
||||
rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned long hostaddr;
|
||||
int sock, i, auth_pw = 1;
|
||||
struct sockaddr_in sin;
|
||||
const char *fingerprint;
|
||||
LIBSSH2_SESSION *session;
|
||||
const char *username="username";
|
||||
const char *password="password";
|
||||
const char *loclfile="sftp_write_nonblock.c";
|
||||
const char *sftppath="/tmp/sftp_write_nonblock.c";
|
||||
int rc;
|
||||
#if defined(HAVE_IOCTLSOCKET)
|
||||
long flag = 1;
|
||||
#endif
|
||||
FILE *local;
|
||||
LIBSSH2_SFTP *sftp_session;
|
||||
LIBSSH2_SFTP_HANDLE *sftp_handle;
|
||||
char mem[1024 * 1000];
|
||||
size_t nread;
|
||||
size_t memuse;
|
||||
time_t start;
|
||||
long total = 0;
|
||||
int duration;
|
||||
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
|
||||
WSAStartup(MAKEWORD(2,0), &wsadata);
|
||||
#endif
|
||||
|
||||
if (argc > 1) {
|
||||
hostaddr = inet_addr(argv[1]);
|
||||
} else {
|
||||
hostaddr = htonl(0x7F000001);
|
||||
}
|
||||
|
||||
if (argc > 2) {
|
||||
username = argv[2];
|
||||
}
|
||||
if (argc > 3) {
|
||||
password = argv[3];
|
||||
}
|
||||
if (argc > 4) {
|
||||
loclfile = argv[4];
|
||||
}
|
||||
if (argc > 5) {
|
||||
sftppath = argv[5];
|
||||
}
|
||||
|
||||
rc = libssh2_init (0);
|
||||
if (rc != 0) {
|
||||
fprintf (stderr, "libssh2 initialization failed (%d)\n", rc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
local = fopen(loclfile, "rb");
|
||||
if (!local) {
|
||||
printf("Can't local file %s\n", loclfile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The application code is responsible for creating the socket
|
||||
* and establishing the connection
|
||||
*/
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(22);
|
||||
sin.sin_addr.s_addr = hostaddr;
|
||||
if (connect(sock, (struct sockaddr*)(&sin),
|
||||
sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "failed to connect!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create a session instance
|
||||
*/
|
||||
session = libssh2_session_init();
|
||||
if (!session)
|
||||
return -1;
|
||||
|
||||
/* Since we have set non-blocking, tell libssh2 we are non-blocking */
|
||||
libssh2_session_set_blocking(session, 0);
|
||||
|
||||
/* ... start it up. This will trade welcome banners, exchange keys,
|
||||
* and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
while ((rc = libssh2_session_startup(session, sock))
|
||||
== LIBSSH2_ERROR_EAGAIN);
|
||||
if (rc) {
|
||||
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* At this point we havn't yet authenticated. The first thing to do is
|
||||
* check the hostkey's fingerprint against our known hosts Your app may
|
||||
* have it hard coded, may go to a file, may present it to the user,
|
||||
* that's your call
|
||||
*/
|
||||
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
|
||||
printf("Fingerprint: ");
|
||||
for(i = 0; i < 20; i++) {
|
||||
printf("%02X ", (unsigned char)fingerprint[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if (auth_pw) {
|
||||
/* We could authenticate via password */
|
||||
while ((rc = libssh2_userauth_password(session, username, password)) ==
|
||||
LIBSSH2_ERROR_EAGAIN);
|
||||
if (rc) {
|
||||
printf("Authentication by password failed.\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} else {
|
||||
/* Or by public key */
|
||||
while ((rc = libssh2_userauth_publickey_fromfile(session, username,
|
||||
"/home/username/.ssh/id_rsa.pub",
|
||||
"/home/username/.ssh/id_rsa",
|
||||
password)) ==
|
||||
LIBSSH2_ERROR_EAGAIN);
|
||||
if (rc) {
|
||||
printf("\tAuthentication by public key failed\n");
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "libssh2_sftp_init()!\n");
|
||||
do {
|
||||
sftp_session = libssh2_sftp_init(session);
|
||||
|
||||
if (!sftp_session &&
|
||||
(libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN)) {
|
||||
fprintf(stderr, "Unable to init SFTP session\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} while (!sftp_session);
|
||||
|
||||
fprintf(stderr, "libssh2_sftp_open()!\n");
|
||||
/* Request a file via SFTP */
|
||||
do {
|
||||
sftp_handle =
|
||||
libssh2_sftp_open(sftp_session, sftppath,
|
||||
LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
|
||||
LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR|
|
||||
LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH);
|
||||
|
||||
if (!sftp_handle &&
|
||||
(libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN)) {
|
||||
fprintf(stderr, "Unable to open file with SFTP\n");
|
||||
goto shutdown;
|
||||
}
|
||||
} while (!sftp_handle);
|
||||
|
||||
fprintf(stderr, "libssh2_sftp_open() is done, now send data!\n");
|
||||
|
||||
start = time(NULL);
|
||||
|
||||
memuse = 0; /* it starts blank */
|
||||
do {
|
||||
nread = fread(&mem[memuse], 1, sizeof(mem)-memuse, local);
|
||||
if (nread <= 0) {
|
||||
/* end of file */
|
||||
break;
|
||||
}
|
||||
memuse += nread;
|
||||
total += nread;
|
||||
|
||||
/* write data in a loop until we block */
|
||||
while ((rc = libssh2_sftp_write(sftp_handle, mem, memuse)) ==
|
||||
LIBSSH2_ERROR_EAGAIN) {
|
||||
waitsocket(sock, session);
|
||||
}
|
||||
if(rc < 0)
|
||||
break;
|
||||
|
||||
if(memuse - rc) {
|
||||
/* make room for more data at the end of the buffer */
|
||||
memmove(&mem[0], &mem[rc], memuse - rc);
|
||||
memuse -= rc;
|
||||
}
|
||||
else
|
||||
/* 'mem' was consumed fully */
|
||||
memuse = 0;
|
||||
|
||||
} while (rc > 0);
|
||||
|
||||
duration = (int)(time(NULL)-start);
|
||||
|
||||
printf("%ld bytes in %d seconds makes %.1f bytes/sec\n",
|
||||
total, duration, total/(double)duration);
|
||||
|
||||
|
||||
fclose(local);
|
||||
libssh2_sftp_close(sftp_handle);
|
||||
libssh2_sftp_shutdown(sftp_session);
|
||||
|
||||
shutdown:
|
||||
|
||||
while (libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing")
|
||||
== LIBSSH2_ERROR_EAGAIN);
|
||||
libssh2_session_free(session);
|
||||
|
||||
#ifdef WIN32
|
||||
closesocket(sock);
|
||||
#else
|
||||
close(sock);
|
||||
#endif
|
||||
printf("all done\n");
|
||||
|
||||
libssh2_exit();
|
||||
|
||||
return 0;
|
||||
}
|
@@ -144,7 +144,7 @@ int main(int argc, char *argv[])
|
||||
username, identity->comment);
|
||||
break;
|
||||
}
|
||||
prev_identity = identity;
|
||||
prev_identity = identity;
|
||||
}
|
||||
if (rc) {
|
||||
fprintf(stderr, "Couldn't continue authentication\n");
|
||||
|
361
example/ssh2_echo.c
Normal file
361
example/ssh2_echo.c
Normal file
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* $Id: ssh2_exec.c,v 1.4 2009/05/07 20:30:22 bagder Exp $
|
||||
*
|
||||
* Run it like this:
|
||||
*
|
||||
* $ ./ssh2_echo 127.0.0.1 user password
|
||||
*
|
||||
* The code sends a 'cat' command, and then writes a lot of data to it only to
|
||||
* check that reading the returned data sums up to the same amount.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "libssh2_config.h"
|
||||
#include <libssh2.h>
|
||||
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
# include <sys/select.h>
|
||||
#endif
|
||||
# ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
static int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
|
||||
{
|
||||
struct timeval timeout;
|
||||
int rc;
|
||||
fd_set fd;
|
||||
fd_set *writefd = NULL;
|
||||
fd_set *readfd = NULL;
|
||||
int dir;
|
||||
|
||||
timeout.tv_sec = 10;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
FD_ZERO(&fd);
|
||||
|
||||
FD_SET(socket_fd, &fd);
|
||||
|
||||
/* now make sure we wait in the correct direction */
|
||||
dir = libssh2_session_block_directions(session);
|
||||
|
||||
if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
|
||||
readfd = &fd;
|
||||
|
||||
if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
|
||||
writefd = &fd;
|
||||
|
||||
rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define BUFSIZE 32000
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const char *hostname = "127.0.0.1";
|
||||
const char *commandline = "cat";
|
||||
const char *username = "user";
|
||||
const char *password = "password";
|
||||
unsigned long hostaddr;
|
||||
int sock;
|
||||
struct sockaddr_in sin;
|
||||
const char *fingerprint;
|
||||
LIBSSH2_SESSION *session;
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
int rc;
|
||||
int exitcode = 0;
|
||||
char *exitsignal=(char *)"none";
|
||||
size_t len;
|
||||
LIBSSH2_KNOWNHOSTS *nh;
|
||||
int type;
|
||||
|
||||
#ifdef WIN32
|
||||
WSADATA wsadata;
|
||||
WSAStartup(MAKEWORD(2,0), &wsadata);
|
||||
#endif
|
||||
if (argc > 1)
|
||||
/* must be ip address only */
|
||||
hostname = argv[1];
|
||||
|
||||
if (argc > 2) {
|
||||
username = argv[2];
|
||||
}
|
||||
if (argc > 3) {
|
||||
password = argv[3];
|
||||
}
|
||||
|
||||
rc = libssh2_init (0);
|
||||
if (rc != 0) {
|
||||
fprintf (stderr, "libssh2 initialization failed (%d)\n", rc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
hostaddr = inet_addr(hostname);
|
||||
|
||||
/* 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);
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(22);
|
||||
sin.sin_addr.s_addr = hostaddr;
|
||||
if (connect(sock, (struct sockaddr*)(&sin),
|
||||
sizeof(struct sockaddr_in)) != 0) {
|
||||
fprintf(stderr, "failed to connect!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create a session instance */
|
||||
session = libssh2_session_init();
|
||||
if (!session)
|
||||
return -1;
|
||||
|
||||
/* tell libssh2 we want it all done non-blocking */
|
||||
libssh2_session_set_blocking(session, 0);
|
||||
|
||||
/* ... start it up. This will trade welcome banners, exchange keys,
|
||||
* and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
while ((rc = libssh2_session_startup(session, sock)) ==
|
||||
LIBSSH2_ERROR_EAGAIN);
|
||||
if (rc) {
|
||||
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
nh = libssh2_knownhost_init(session);
|
||||
if(!nh) {
|
||||
/* eeek, do cleanup here */
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* read all hosts from here */
|
||||
libssh2_knownhost_readfile(nh, "known_hosts",
|
||||
LIBSSH2_KNOWNHOST_FILE_OPENSSH);
|
||||
|
||||
/* store all known hosts to here */
|
||||
libssh2_knownhost_writefile(nh, "dumpfile",
|
||||
LIBSSH2_KNOWNHOST_FILE_OPENSSH);
|
||||
|
||||
fingerprint = libssh2_session_hostkey(session, &len, &type);
|
||||
if(fingerprint) {
|
||||
struct libssh2_knownhost *host;
|
||||
int check = libssh2_knownhost_checkp(nh, hostname, 22,
|
||||
fingerprint, len,
|
||||
LIBSSH2_KNOWNHOST_TYPE_PLAIN|
|
||||
LIBSSH2_KNOWNHOST_KEYENC_RAW,
|
||||
&host);
|
||||
|
||||
fprintf(stderr, "Host check: %d, key: %s\n", check,
|
||||
(check <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)?
|
||||
host->key:"<none>");
|
||||
|
||||
/*****
|
||||
* At this point, we could verify that 'check' tells us the key is
|
||||
* fine or bail out.
|
||||
*****/
|
||||
}
|
||||
else {
|
||||
/* eeek, do cleanup here */
|
||||
return 3;
|
||||
}
|
||||
libssh2_knownhost_free(nh);
|
||||
|
||||
if ( strlen(password) != 0 ) {
|
||||
/* We could authenticate via password */
|
||||
while ((rc = libssh2_userauth_password(session, username, password)) ==
|
||||
LIBSSH2_ERROR_EAGAIN);
|
||||
if (rc) {
|
||||
fprintf(stderr, "Authentication by password failed.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
libssh2_trace(session, LIBSSH2_TRACE_SOCKET);
|
||||
|
||||
/* Exec non-blocking on the remove host */
|
||||
while( (channel = libssh2_channel_open_session(session)) == NULL &&
|
||||
libssh2_session_last_error(session,NULL,NULL,0) ==
|
||||
LIBSSH2_ERROR_EAGAIN ) {
|
||||
waitsocket(sock, session);
|
||||
}
|
||||
if( channel == NULL ) {
|
||||
fprintf(stderr,"Error\n");
|
||||
exit( 1 );
|
||||
}
|
||||
while( (rc = libssh2_channel_exec(channel, commandline)) ==
|
||||
LIBSSH2_ERROR_EAGAIN )
|
||||
waitsocket(sock, session);
|
||||
|
||||
if( rc != 0 ) {
|
||||
fprintf(stderr, "exec error\n");
|
||||
exit( 1 );
|
||||
}
|
||||
else {
|
||||
LIBSSH2_POLLFD *fds = NULL;
|
||||
int running = 1;
|
||||
int bufsize = BUFSIZE;
|
||||
char buffer[BUFSIZE];
|
||||
int totsize = 1500000;
|
||||
int totwritten = 0;
|
||||
int totread = 0;
|
||||
int partials = 0;
|
||||
int rereads = 0;
|
||||
int rewrites = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BUFSIZE; i++)
|
||||
buffer[i] = 'A';
|
||||
|
||||
if ((fds = malloc (sizeof (LIBSSH2_POLLFD))) == NULL) {
|
||||
fprintf(stderr, "malloc failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fds[0].type = LIBSSH2_POLLFD_CHANNEL;
|
||||
fds[0].fd.channel = channel;
|
||||
fds[0].events = LIBSSH2_POLLFD_POLLIN | LIBSSH2_POLLFD_POLLOUT;
|
||||
|
||||
do {
|
||||
int rc = (libssh2_poll(fds, 1, 10));
|
||||
int act = 0;
|
||||
|
||||
if (rc < 1)
|
||||
continue;
|
||||
|
||||
if (fds[0].revents & LIBSSH2_POLLFD_POLLIN) {
|
||||
int n = libssh2_channel_read(channel, buffer, sizeof(buffer));
|
||||
act++;
|
||||
|
||||
if (n == LIBSSH2_ERROR_EAGAIN) {
|
||||
rereads++;
|
||||
fprintf(stderr, "will read again\n");
|
||||
}
|
||||
else if (n < 0) {
|
||||
fprintf(stderr, "read failed\n");
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
totread += n;
|
||||
fprintf(stderr, "read %d bytes (%d in total)\n",
|
||||
n, totread);
|
||||
}
|
||||
}
|
||||
|
||||
if (fds[0].revents & LIBSSH2_POLLFD_POLLOUT) {
|
||||
act++;
|
||||
|
||||
if (totwritten < totsize) {
|
||||
/* we have not written all data yet */
|
||||
int left = totsize - totwritten;
|
||||
int size = (left < bufsize) ? left : bufsize;
|
||||
int n = libssh2_channel_write_ex(channel, 0, buffer, size);
|
||||
|
||||
if (n == LIBSSH2_ERROR_EAGAIN) {
|
||||
rewrites++;
|
||||
fprintf(stderr, "will write again\n");
|
||||
}
|
||||
else if (n < 0) {
|
||||
fprintf(stderr, "write failed\n");
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
totwritten += n;
|
||||
fprintf(stderr, "wrote %d bytes (%d in total)",
|
||||
n, totwritten);
|
||||
if (left >= bufsize && n != bufsize) {
|
||||
partials++;
|
||||
fprintf(stderr, " PARTIAL");
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
} else {
|
||||
/* all data written, send EOF */
|
||||
rc = libssh2_channel_send_eof(channel);
|
||||
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
fprintf(stderr, "will send eof again\n");
|
||||
}
|
||||
else if (rc < 0) {
|
||||
fprintf(stderr, "send eof failed\n");
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "sent eof\n");
|
||||
/* we're done writing, stop listening for OUT events */
|
||||
fds[0].events &= ~LIBSSH2_POLLFD_POLLOUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fds[0].revents & LIBSSH2_POLLFD_CHANNEL_CLOSED) {
|
||||
if (!act) /* don't leave loop until we have read all data */
|
||||
running = 0;
|
||||
}
|
||||
} while(running);
|
||||
|
||||
exitcode = 127;
|
||||
while( (rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN )
|
||||
waitsocket(sock, session);
|
||||
|
||||
if( rc == 0 ) {
|
||||
exitcode = libssh2_channel_get_exit_status( channel );
|
||||
libssh2_channel_get_exit_signal(channel, &exitsignal,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
if (exitsignal)
|
||||
printf("\nGot signal: %s\n", exitsignal);
|
||||
|
||||
libssh2_channel_free(channel);
|
||||
channel = NULL;
|
||||
|
||||
fprintf(stderr, "\nrereads: %d rewrites: %d totwritten %d\n",
|
||||
rereads, rewrites, totwritten);
|
||||
|
||||
if (totwritten != totread) {
|
||||
fprintf(stderr, "\n*** FAIL bytes written: %d bytes "
|
||||
"read: %d ***\n", totwritten, totread);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
libssh2_session_disconnect(session,
|
||||
"Normal Shutdown, Thank you for playing");
|
||||
libssh2_session_free(session);
|
||||
|
||||
#ifdef WIN32
|
||||
closesocket(sock);
|
||||
#else
|
||||
close(sock);
|
||||
#endif
|
||||
fprintf(stderr, "all done\n");
|
||||
|
||||
libssh2_exit();
|
||||
|
||||
return exitcode;
|
||||
}
|
@@ -86,6 +86,7 @@ int main(int argc, char *argv[])
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
int rc;
|
||||
int exitcode;
|
||||
char *exitsignal=(char *)"none";
|
||||
int bytecount = 0;
|
||||
size_t len;
|
||||
LIBSSH2_KNOWNHOSTS *nh;
|
||||
@@ -286,8 +287,14 @@ int main(int argc, char *argv[])
|
||||
if( rc == 0 )
|
||||
{
|
||||
exitcode = libssh2_channel_get_exit_status( channel );
|
||||
libssh2_channel_get_exit_signal(channel, &exitsignal,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
printf("\nEXIT: %d bytecount: %d\n", exitcode, bytecount);
|
||||
|
||||
if (exitsignal)
|
||||
printf("\nGot signal: %s\n", exitsignal);
|
||||
else
|
||||
printf("\nEXIT: %d bytecount: %d\n", exitcode, bytecount);
|
||||
|
||||
libssh2_channel_free(channel);
|
||||
channel = NULL;
|
||||
|
76
git2news.pl
Executable file
76
git2news.pl
Executable file
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# git log --pretty=fuller --no-color --date=short --decorate=full
|
||||
|
||||
my @mname = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
|
||||
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' );
|
||||
|
||||
sub nicedate {
|
||||
my ($date)=$_;
|
||||
|
||||
if($date =~ /(\d\d\d\d)-(\d\d)-(\d\d)/) {
|
||||
return sprintf("%d %s %4d", $3, $mname[$2-1], $1);
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
|
||||
print
|
||||
' Changelog for the libssh2 project. Generated with git2news.pl
|
||||
';
|
||||
|
||||
my $line;
|
||||
my $tag;
|
||||
while(<STDIN>) {
|
||||
my $l = $_;
|
||||
|
||||
if($l =~/^commit ([[:xdigit:]]*) ?(.*)/) {
|
||||
$co = $1;
|
||||
my $ref = $2;
|
||||
if ($ref =~ /refs\/tags\/(libssh2-|VERSION\.)([0-9._]*)/) {
|
||||
$tag = $2;
|
||||
} else {
|
||||
$tag = '';
|
||||
}
|
||||
}
|
||||
elsif($l =~ /^Author: *(.*) +</) {
|
||||
$a = $1;
|
||||
}
|
||||
elsif($l =~ /^Commit: *(.*) +</) {
|
||||
$c = $1;
|
||||
}
|
||||
elsif($l =~ /^CommitDate: (.*)/) {
|
||||
$date = nicedate($1);
|
||||
}
|
||||
elsif($l =~ /^( )(.*)/) {
|
||||
my $extra;
|
||||
if ($tag) {
|
||||
# Version entries have a special format
|
||||
print "\nVersion " . $tag." ($date)\n";
|
||||
$oldc = "";
|
||||
$tag = "";
|
||||
}
|
||||
if($a ne $c) {
|
||||
$extra=sprintf("\n- [%s brought this change]\n\n ", $a);
|
||||
}
|
||||
else {
|
||||
$extra="\n- ";
|
||||
}
|
||||
if($co ne $oldco) {
|
||||
if($c ne $oldc) {
|
||||
print "\n$c ($date)$extra";
|
||||
}
|
||||
else {
|
||||
print "$extra";
|
||||
}
|
||||
$line =0;
|
||||
}
|
||||
|
||||
$oldco = $co;
|
||||
$oldc = $c;
|
||||
$olddate = $date;
|
||||
if($line++) {
|
||||
print " ";
|
||||
}
|
||||
print $2."\n";
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/* Copyright (c) 2004-2009, Sara Golemon <sarag@libssh2.org>
|
||||
* Copyright (c) 2009 by Daniel Stenberg
|
||||
* Copyright (c) 2009-2010 Daniel Stenberg
|
||||
* Copyright (c) 2010 Simon Josefsson <simon@josefsson.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -46,13 +46,13 @@
|
||||
to make the BANNER define (used by src/session.c) be a valid SSH
|
||||
banner. Release versions have no appended strings and may of course not
|
||||
have dashes either. */
|
||||
#define LIBSSH2_VERSION "1.2.7_DEV"
|
||||
#define LIBSSH2_VERSION "1.2.8_DEV"
|
||||
|
||||
/* The numeric version number is also available "in parts" by using these
|
||||
defines: */
|
||||
#define LIBSSH2_VERSION_MAJOR 1
|
||||
#define LIBSSH2_VERSION_MINOR 2
|
||||
#define LIBSSH2_VERSION_PATCH 7
|
||||
#define LIBSSH2_VERSION_PATCH 8
|
||||
|
||||
/* This is the numeric version of the libssh2 version number, meant for easier
|
||||
parsing and comparions by programs. The LIBSSH2_VERSION_NUM define will
|
||||
@@ -69,7 +69,7 @@
|
||||
and it is always a greater number in a more recent release. It makes
|
||||
comparisons with greater than and less than work.
|
||||
*/
|
||||
#define LIBSSH2_VERSION_NUM 0x010207
|
||||
#define LIBSSH2_VERSION_NUM 0x010208
|
||||
|
||||
/*
|
||||
* This is the date and time when the full source package was created. The
|
||||
@@ -87,6 +87,10 @@
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
# include <BaseTsd.h>
|
||||
# include <WinSock2.h>
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
@@ -106,8 +110,7 @@ extern "C" {
|
||||
# endif /* LIBSSH2_WIN32 */
|
||||
#endif /* LIBSSH2_API */
|
||||
|
||||
#if defined(LIBSSH2_DARWIN) || (defined(LIBSSH2_WIN32) && \
|
||||
!defined(_MSC_VER) && !defined(__MINGW32__))
|
||||
#if defined(LIBSSH2_DARWIN)
|
||||
# include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
@@ -122,15 +125,21 @@ typedef unsigned char uint8_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned __int64 libssh2_uint64_t;
|
||||
typedef __int64 libssh2_int64_t;
|
||||
# ifndef _SSIZE_T_DEFINED
|
||||
typedef int ssize_t;
|
||||
# define _SSIZE_T_DEFINED
|
||||
#ifndef ssize_t
|
||||
typedef SSIZE_T ssize_t;
|
||||
#endif
|
||||
#else
|
||||
typedef unsigned long long libssh2_uint64_t;
|
||||
typedef long long libssh2_int64_t;
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
typedef SOCKET libssh2_socket_t;
|
||||
#else /* !WIN32 */
|
||||
typedef int libssh2_socket_t;
|
||||
#define INVALID_SOCKET -1
|
||||
#endif /* WIN32 */
|
||||
|
||||
/* Part of every banner, user specified or not */
|
||||
#define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION
|
||||
|
||||
@@ -247,8 +256,9 @@ typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE
|
||||
#define LIBSSH2_METHOD_LANG_CS 8
|
||||
#define LIBSSH2_METHOD_LANG_SC 9
|
||||
|
||||
/* session.flags bits */
|
||||
#define LIBSSH2_FLAG_SIGPIPE 0x00000001
|
||||
/* flags */
|
||||
#define LIBSSH2_FLAG_SIGPIPE 1
|
||||
#define LIBSSH2_FLAG_COMPRESS 2
|
||||
|
||||
typedef struct _LIBSSH2_SESSION LIBSSH2_SESSION;
|
||||
typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL;
|
||||
@@ -331,8 +341,15 @@ typedef struct _LIBSSH2_POLLFD {
|
||||
|
||||
/* Error Codes (defined by libssh2) */
|
||||
#define LIBSSH2_ERROR_NONE 0
|
||||
|
||||
/* The library once used -1 as a generic error return value on numerous places
|
||||
through the code, which subsequently was converted to
|
||||
LIBSSH2_ERROR_SOCKET_NONE uses over time. As this is a generic error code,
|
||||
the goal is to never ever return this code but instead make sure that a
|
||||
more accurate and descriptive error code is used. */
|
||||
#define LIBSSH2_ERROR_SOCKET_NONE -1
|
||||
#define LIBSSH2_ERROR_BANNER_NONE -2
|
||||
|
||||
#define LIBSSH2_ERROR_BANNER_RECV -2
|
||||
#define LIBSSH2_ERROR_BANNER_SEND -3
|
||||
#define LIBSSH2_ERROR_INVALID_MAC -4
|
||||
#define LIBSSH2_ERROR_KEX_FAILURE -5
|
||||
@@ -374,6 +391,12 @@ typedef struct _LIBSSH2_POLLFD {
|
||||
#define LIBSSH2_ERROR_COMPRESS -40
|
||||
#define LIBSSH2_ERROR_OUT_OF_BOUNDARY -41
|
||||
#define LIBSSH2_ERROR_AGENT_PROTOCOL -42
|
||||
#define LIBSSH2_ERROR_SOCKET_RECV -43
|
||||
#define LIBSSH2_ERROR_ENCRYPT -44
|
||||
#define LIBSSH2_ERROR_BAD_SOCKET -45
|
||||
|
||||
/* this is a define to provide the old (<= 1.2.7) name */
|
||||
#define LIBSSH2_ERROR_BANNER_NONE LIBSSH2_ERROR_BANNER_RECV
|
||||
|
||||
/* Global API */
|
||||
#define LIBSSH2_INIT_NO_CRYPTO 0x0001
|
||||
@@ -401,6 +424,13 @@ LIBSSH2_API int libssh2_init(int flags);
|
||||
*/
|
||||
LIBSSH2_API void libssh2_exit(void);
|
||||
|
||||
/*
|
||||
* libssh2_free()
|
||||
*
|
||||
* Deallocate memory allocated by earlier call to libssh2 functions.
|
||||
*/
|
||||
LIBSSH2_API void libssh2_free(LIBSSH2_SESSION *session, void *ptr);
|
||||
|
||||
/* Session API */
|
||||
LIBSSH2_API LIBSSH2_SESSION *
|
||||
libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)),
|
||||
@@ -416,6 +446,8 @@ LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session,
|
||||
const char *banner);
|
||||
|
||||
LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int sock);
|
||||
LIBSSH2_API int libssh2_session_handshake(LIBSSH2_SESSION *session,
|
||||
libssh2_socket_t sock);
|
||||
LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session,
|
||||
int reason,
|
||||
const char *description,
|
||||
@@ -702,6 +734,13 @@ LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *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_get_exit_signal(LIBSSH2_CHANNEL* channel,
|
||||
char **exitsignal,
|
||||
size_t *exitsignal_len,
|
||||
char **errmsg,
|
||||
size_t *errmsg_len,
|
||||
char **langtag,
|
||||
size_t *langtag_len);
|
||||
LIBSSH2_API int libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel);
|
||||
LIBSSH2_API int libssh2_channel_eof(LIBSSH2_CHANNEL *channel);
|
||||
LIBSSH2_API int libssh2_channel_wait_eof(LIBSSH2_CHANNEL *channel);
|
||||
|
7
maketgz
7
maketgz
@@ -63,6 +63,13 @@ else
|
||||
automake --include-deps Makefile >/dev/null
|
||||
fi
|
||||
|
||||
#######################################################################
|
||||
#
|
||||
# Generate the changelog
|
||||
#
|
||||
echo "generate NEWS"
|
||||
git log --pretty=fuller --no-color --date=short --decorate=full -1000 | ./log2changes.pl > NEWS.dist
|
||||
|
||||
############################################################################
|
||||
#
|
||||
# Now run make dist to generate a tar.gz archive
|
||||
|
@@ -19,7 +19,7 @@ endif
|
||||
|
||||
# Edit the path below to point to the base of your OpenSSL package.
|
||||
ifndef OPENSSL_PATH
|
||||
OPENSSL_PATH = ../../openssl-0.9.8o
|
||||
OPENSSL_PATH = ../../openssl-0.9.8q
|
||||
endif
|
||||
|
||||
# Edit the path below to point to your Distribution folder.
|
||||
|
@@ -19,7 +19,7 @@ endif
|
||||
|
||||
# Edit the path below to point to the base of your OpenSSL package.
|
||||
ifndef OPENSSL_PATH
|
||||
OPENSSL_PATH = ../../../openssl-0.9.8o
|
||||
OPENSSL_PATH = ../../../openssl-0.9.8q
|
||||
endif
|
||||
|
||||
# Edit the var below to enable static linking of libssh2 and libz
|
||||
|
48
src/agent.c
48
src/agent.c
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2009 by Daiki Ueno
|
||||
* Copyright (C) 2010 by Daniel Stenberg
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -153,15 +154,15 @@ agent_connect_unix(LIBSSH2_AGENT *agent)
|
||||
|
||||
agent->fd = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (agent->fd < 0)
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_NONE,
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_BAD_SOCKET,
|
||||
"failed creating socket");
|
||||
|
||||
s_un.sun_family = AF_UNIX;
|
||||
strncpy (s_un.sun_path, path, sizeof s_un.sun_path);
|
||||
if (connect(agent->fd, (struct sockaddr*)(&s_un), sizeof s_un) != 0) {
|
||||
close (agent->fd);
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_NONE,
|
||||
"failed connecting");
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
|
||||
"failed connecting with agent");
|
||||
}
|
||||
|
||||
return LIBSSH2_ERROR_NONE;
|
||||
@@ -176,36 +177,34 @@ agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
|
||||
/* Send the length of the request */
|
||||
if (transctx->state == agent_NB_state_request_created) {
|
||||
_libssh2_htonu32(buf, transctx->request_len);
|
||||
rc = send(agent->fd, buf, sizeof buf, 0);
|
||||
if (rc < 0) {
|
||||
if (errno == EAGAIN)
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
rc = _libssh2_send(agent->fd, buf, sizeof buf, 0);
|
||||
if (rc == -EAGAIN)
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
else if (rc < 0)
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"agent send failed");
|
||||
}
|
||||
transctx->state = agent_NB_state_request_length_sent;
|
||||
}
|
||||
|
||||
/* Send the request body */
|
||||
if (transctx->state == agent_NB_state_request_length_sent) {
|
||||
rc = send(agent->fd, transctx->request,
|
||||
transctx->request_len, 0);
|
||||
if (rc < 0) {
|
||||
if (errno == EAGAIN)
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
rc = _libssh2_send(agent->fd, transctx->request,
|
||||
transctx->request_len, 0);
|
||||
if (rc == -EAGAIN)
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
else if (rc < 0)
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"agent send failed");
|
||||
}
|
||||
transctx->state = agent_NB_state_request_sent;
|
||||
}
|
||||
|
||||
/* Receive the length of a response */
|
||||
if (transctx->state == agent_NB_state_request_sent) {
|
||||
rc = recv(agent->fd, buf, sizeof buf, 0);
|
||||
rc = _libssh2_recv(agent->fd, buf, sizeof buf, 0);
|
||||
if (rc < 0) {
|
||||
if (errno == EAGAIN)
|
||||
if (rc == -EAGAIN)
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_NONE,
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_RECV,
|
||||
"agent recv failed");
|
||||
}
|
||||
transctx->response_len = _libssh2_ntohu32(buf);
|
||||
@@ -219,9 +218,10 @@ agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
|
||||
|
||||
/* Receive the response body */
|
||||
if (transctx->state == agent_NB_state_response_length_received) {
|
||||
rc = recv(agent->fd, transctx->response, transctx->response_len, 0);
|
||||
rc = _libssh2_recv(agent->fd, transctx->response,
|
||||
transctx->response_len, 0);
|
||||
if (rc < 0) {
|
||||
if (errno == EAGAIN)
|
||||
if (rc == -EAGAIN)
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"agent recv failed");
|
||||
@@ -268,7 +268,7 @@ agent_connect_pageant(LIBSSH2_AGENT *agent)
|
||||
HWND hwnd;
|
||||
hwnd = FindWindow("Pageant", "Pageant");
|
||||
if (!hwnd)
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_NONE,
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
|
||||
"failed connecting agent");
|
||||
agent->fd = 0; /* Mark as the connection has been established */
|
||||
return LIBSSH2_ERROR_NONE;
|
||||
@@ -296,7 +296,7 @@ agent_transact_pageant(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
|
||||
|
||||
sprintf(mapname, "PageantRequest%08x", (unsigned)GetCurrentThreadId());
|
||||
filemap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
|
||||
0, PAGEANT_MAX_MSGLEN, mapname);
|
||||
0, PAGEANT_MAX_MSGLEN, mapname);
|
||||
|
||||
if (filemap == NULL || filemap == INVALID_HANDLE_VALUE)
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
|
||||
@@ -312,16 +312,16 @@ agent_transact_pageant(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
|
||||
|
||||
id = SendMessage(hwnd, WM_COPYDATA, (WPARAM) NULL, (LPARAM) &cds);
|
||||
if (id > 0) {
|
||||
transctx->response_len = _libssh2_ntohu32(p);
|
||||
transctx->response_len = _libssh2_ntohu32(p);
|
||||
if (transctx->response_len > PAGEANT_MAX_MSGLEN) {
|
||||
UnmapViewOfFile(p);
|
||||
CloseHandle(filemap);
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
|
||||
"agent setup fail");
|
||||
}
|
||||
transctx->response = LIBSSH2_ALLOC(agent->session,
|
||||
transctx->response = LIBSSH2_ALLOC(agent->session,
|
||||
transctx->response_len);
|
||||
if (!transctx->response) {
|
||||
if (!transctx->response) {
|
||||
UnmapViewOfFile(p);
|
||||
CloseHandle(filemap);
|
||||
return _libssh2_error(agent->session, LIBSSH2_ERROR_ALLOC,
|
||||
|
457
src/channel.c
457
src/channel.c
@@ -1,6 +1,6 @@
|
||||
/* Copyright (c) 2004-2007 Sara Golemon <sarag@libssh2.org>
|
||||
* Copyright (c) 2005 Mikhail Gusarov <dottedmag@dottedmag.net>
|
||||
* Copyright (c) 2008-2010 by Daniel Stenberg
|
||||
* Copyright (c) 2008-2011 by Daniel Stenberg
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -130,7 +130,8 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type,
|
||||
uint32_t channel_type_len,
|
||||
uint32_t window_size,
|
||||
uint32_t packet_size,
|
||||
const char *message, unsigned int message_len)
|
||||
const unsigned char *message,
|
||||
size_t message_len)
|
||||
{
|
||||
static const unsigned char reply_codes[3] = {
|
||||
SSH_MSG_CHANNEL_OPEN_CONFIRMATION,
|
||||
@@ -146,7 +147,7 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type,
|
||||
session->open_data = NULL;
|
||||
/* 17 = packet_type(1) + channel_type_len(4) + sender_channel(4) +
|
||||
* window_size(4) + packet_size(4) */
|
||||
session->open_packet_len = channel_type_len + message_len + 17;
|
||||
session->open_packet_len = channel_type_len + 17;
|
||||
session->open_local_channel = _libssh2_channel_nextid(session);
|
||||
|
||||
/* Zero the whole thing out */
|
||||
@@ -201,23 +202,23 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type,
|
||||
_libssh2_store_u32(&s, window_size);
|
||||
_libssh2_store_u32(&s, packet_size);
|
||||
|
||||
if (message && message_len) {
|
||||
memcpy(s, message, message_len);
|
||||
s += message_len;
|
||||
}
|
||||
/* Do not copy the message */
|
||||
|
||||
session->open_state = libssh2_NB_state_created;
|
||||
}
|
||||
|
||||
if (session->open_state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_transport_write(session, session->open_packet,
|
||||
session->open_packet_len);
|
||||
rc = _libssh2_transport_send(session,
|
||||
session->open_packet,
|
||||
session->open_packet_len,
|
||||
message, message_len);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
_libssh2_error(session, rc,
|
||||
"Would block sending channel-open request");
|
||||
return NULL;
|
||||
} else if (rc) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
}
|
||||
else if (rc) {
|
||||
_libssh2_error(session, rc,
|
||||
"Unable to send channel-open request");
|
||||
goto channel_error;
|
||||
}
|
||||
@@ -303,12 +304,6 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type,
|
||||
session->open_data = NULL;
|
||||
}
|
||||
|
||||
/* Free any state variables still holding data */
|
||||
if (session->open_channel->write_packet) {
|
||||
LIBSSH2_FREE(session, session->open_channel->write_packet);
|
||||
session->open_channel->write_packet = NULL;
|
||||
}
|
||||
|
||||
LIBSSH2_FREE(session, session->open_channel);
|
||||
session->open_channel = NULL;
|
||||
}
|
||||
@@ -336,7 +331,8 @@ libssh2_channel_open_ex(LIBSSH2_SESSION *session, const char *type,
|
||||
BLOCK_ADJUST_ERRNO(ptr, session,
|
||||
_libssh2_channel_open(session, type, type_len,
|
||||
window_size, packet_size,
|
||||
msg, msg_len));
|
||||
(unsigned char *)msg,
|
||||
msg_len));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@@ -381,7 +377,7 @@ channel_direct_tcpip(LIBSSH2_SESSION * session, const char *host,
|
||||
sizeof("direct-tcpip") - 1,
|
||||
LIBSSH2_CHANNEL_WINDOW_DEFAULT,
|
||||
LIBSSH2_CHANNEL_PACKET_DEFAULT,
|
||||
(char *) session->direct_message,
|
||||
session->direct_message,
|
||||
session->direct_message_len);
|
||||
|
||||
if (!channel &&
|
||||
@@ -433,9 +429,11 @@ channel_forward_listen(LIBSSH2_SESSION * session, const char *host,
|
||||
{ SSH_MSG_REQUEST_SUCCESS, SSH_MSG_REQUEST_FAILURE, 0 };
|
||||
int rc;
|
||||
|
||||
if(!host)
|
||||
host = "0.0.0.0";
|
||||
|
||||
if (session->fwdLstn_state == libssh2_NB_state_idle) {
|
||||
session->fwdLstn_host_len =
|
||||
(host ? strlen(host) : (sizeof("0.0.0.0") - 1));
|
||||
session->fwdLstn_host_len = strlen(host);
|
||||
/* 14 = packet_type(1) + request_len(4) + want_replay(1) + host_len(4)
|
||||
+ port(4) */
|
||||
session->fwdLstn_packet_len =
|
||||
@@ -461,22 +459,24 @@ channel_forward_listen(LIBSSH2_SESSION * session, const char *host,
|
||||
_libssh2_store_str(&s, "tcpip-forward", sizeof("tcpip-forward") - 1);
|
||||
*(s++) = 0x01; /* want_reply */
|
||||
|
||||
_libssh2_store_str(&s, host ? host : "0.0.0.0",
|
||||
session->fwdLstn_host_len);
|
||||
_libssh2_store_str(&s, host, session->fwdLstn_host_len);
|
||||
_libssh2_store_u32(&s, port);
|
||||
|
||||
session->fwdLstn_state = libssh2_NB_state_created;
|
||||
}
|
||||
|
||||
if (session->fwdLstn_state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_transport_write(session, session->fwdLstn_packet,
|
||||
session->fwdLstn_packet_len);
|
||||
rc = _libssh2_transport_send(session,
|
||||
session->fwdLstn_packet,
|
||||
session->fwdLstn_packet_len,
|
||||
NULL, 0);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block sending global-request packet for "
|
||||
"forward listen request");
|
||||
return NULL;
|
||||
} else if (rc) {
|
||||
}
|
||||
else if (rc) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send global-request packet for forward "
|
||||
"listen request");
|
||||
@@ -633,8 +633,10 @@ int _libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener)
|
||||
}
|
||||
|
||||
if (listener->chanFwdCncl_state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_transport_write(session, packet, packet_len);
|
||||
rc = _libssh2_transport_send(session, packet, packet_len, NULL, 0);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
_libssh2_error(session, rc,
|
||||
"Would block sending forward request");
|
||||
listener->chanFwdCncl_data = packet;
|
||||
return rc;
|
||||
}
|
||||
@@ -800,9 +802,13 @@ static int channel_setenv(LIBSSH2_CHANNEL *channel,
|
||||
}
|
||||
|
||||
if (channel->setenv_state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_transport_write(session, channel->setenv_packet,
|
||||
channel->setenv_packet_len);
|
||||
rc = _libssh2_transport_send(session,
|
||||
channel->setenv_packet,
|
||||
channel->setenv_packet_len,
|
||||
NULL, 0);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
_libssh2_error(session, rc,
|
||||
"Would block sending setenv request");
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
LIBSSH2_FREE(session, channel->setenv_packet);
|
||||
@@ -888,6 +894,11 @@ static int channel_request_pty(LIBSSH2_CHANNEL *channel,
|
||||
/* 41 = packet_type(1) + channel(4) + pty_req_len(4) + "pty_req"(7) +
|
||||
* want_reply(1) + term_len(4) + width(4) + height(4) + width_px(4) +
|
||||
* height_px(4) + modes_len(4) */
|
||||
if(term_len + modes_len > 256) {
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_INVAL,
|
||||
"term + mode lengths too large");
|
||||
}
|
||||
|
||||
channel->reqPTY_packet_len = term_len + modes_len + 41;
|
||||
|
||||
/* Zero the whole thing out */
|
||||
@@ -898,12 +909,7 @@ static int channel_request_pty(LIBSSH2_CHANNEL *channel,
|
||||
"Allocating tty on channel %lu/%lu", channel->local.id,
|
||||
channel->remote.id);
|
||||
|
||||
s = channel->reqPTY_packet =
|
||||
LIBSSH2_ALLOC(session, channel->reqPTY_packet_len);
|
||||
if (!channel->reqPTY_packet) {
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for pty-request");
|
||||
}
|
||||
s = channel->reqPTY_packet;
|
||||
|
||||
*(s++) = SSH_MSG_CHANNEL_REQUEST;
|
||||
_libssh2_store_u32(&s, channel->remote.id);
|
||||
@@ -922,20 +928,18 @@ static int channel_request_pty(LIBSSH2_CHANNEL *channel,
|
||||
}
|
||||
|
||||
if (channel->reqPTY_state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_transport_write(session, channel->reqPTY_packet,
|
||||
channel->reqPTY_packet_len);
|
||||
rc = _libssh2_transport_send(session, channel->reqPTY_packet,
|
||||
channel->reqPTY_packet_len,
|
||||
NULL, 0);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
_libssh2_error(session, rc,
|
||||
"Would block sending pty request");
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
LIBSSH2_FREE(session, channel->reqPTY_packet);
|
||||
channel->reqPTY_packet = NULL;
|
||||
channel->reqPTY_state = libssh2_NB_state_idle;
|
||||
return _libssh2_error(session, rc,
|
||||
"Unable to send pty-request packet");
|
||||
}
|
||||
LIBSSH2_FREE(session, channel->reqPTY_packet);
|
||||
channel->reqPTY_packet = NULL;
|
||||
|
||||
_libssh2_htonu32(channel->reqPTY_local_channel, channel->local.id);
|
||||
|
||||
channel->reqPTY_state = libssh2_NB_state_sent;
|
||||
@@ -952,7 +956,8 @@ static int channel_request_pty(LIBSSH2_CHANNEL *channel,
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
channel->reqPTY_state = libssh2_NB_state_idle;
|
||||
return -1;
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||
"Failed to require the PTY package");
|
||||
}
|
||||
|
||||
code = data[0];
|
||||
@@ -997,6 +1002,7 @@ channel_request_pty_size(LIBSSH2_CHANNEL * channel, int width,
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
unsigned char *s;
|
||||
int rc;
|
||||
int retcode = LIBSSH2_ERROR_PROTO;
|
||||
|
||||
if (channel->reqPTY_state == libssh2_NB_state_idle) {
|
||||
channel->reqPTY_packet_len = 39;
|
||||
@@ -1010,12 +1016,7 @@ channel_request_pty_size(LIBSSH2_CHANNEL * channel, int width,
|
||||
channel->local.id,
|
||||
channel->remote.id);
|
||||
|
||||
s = channel->reqPTY_packet =
|
||||
LIBSSH2_ALLOC(session, channel->reqPTY_packet_len);
|
||||
|
||||
if (!channel->reqPTY_packet)
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for pty-request");
|
||||
s = channel->reqPTY_packet;
|
||||
|
||||
*(s++) = SSH_MSG_CHANNEL_REQUEST;
|
||||
_libssh2_store_u32(&s, channel->remote.id);
|
||||
@@ -1031,27 +1032,24 @@ channel_request_pty_size(LIBSSH2_CHANNEL * channel, int width,
|
||||
}
|
||||
|
||||
if (channel->reqPTY_state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_transport_write(session, channel->reqPTY_packet,
|
||||
channel->reqPTY_packet_len);
|
||||
rc = _libssh2_transport_send(session, channel->reqPTY_packet,
|
||||
channel->reqPTY_packet_len,
|
||||
NULL, 0);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
_libssh2_error(session, rc,
|
||||
"Would block sending window-change request");
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
LIBSSH2_FREE(session, channel->reqPTY_packet);
|
||||
channel->reqPTY_packet = NULL;
|
||||
channel->reqPTY_state = libssh2_NB_state_idle;
|
||||
return _libssh2_error(session, rc,
|
||||
"Unable to send window-change packet");
|
||||
}
|
||||
LIBSSH2_FREE(session, channel->reqPTY_packet);
|
||||
channel->reqPTY_packet = NULL;
|
||||
_libssh2_htonu32(channel->reqPTY_local_channel, channel->local.id);
|
||||
channel->reqPTY_state = libssh2_NB_state_sent;
|
||||
|
||||
return 0;
|
||||
retcode = LIBSSH2_ERROR_NONE;
|
||||
}
|
||||
|
||||
channel->reqPTY_state = libssh2_NB_state_idle;
|
||||
return -1;
|
||||
return retcode;
|
||||
}
|
||||
|
||||
LIBSSH2_API int
|
||||
@@ -1149,9 +1147,12 @@ channel_x11_req(LIBSSH2_CHANNEL *channel, int single_connection,
|
||||
}
|
||||
|
||||
if (channel->reqX11_state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_transport_write(session, channel->reqX11_packet,
|
||||
channel->reqX11_packet_len);
|
||||
rc = _libssh2_transport_send(session, channel->reqX11_packet,
|
||||
channel->reqX11_packet_len,
|
||||
NULL, 0);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
_libssh2_error(session, rc,
|
||||
"Would block sending X11-req packet");
|
||||
return rc;
|
||||
}
|
||||
if (rc) {
|
||||
@@ -1225,8 +1226,8 @@ libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_connection,
|
||||
*/
|
||||
int
|
||||
_libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel,
|
||||
const char *request, unsigned int request_len,
|
||||
const char *message, unsigned int message_len)
|
||||
const char *request, size_t request_len,
|
||||
const char *message, size_t message_len)
|
||||
{
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
unsigned char *s;
|
||||
@@ -1243,7 +1244,7 @@ _libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel,
|
||||
sizeof(channel->process_packet_requirev_state));
|
||||
|
||||
if (message)
|
||||
channel->process_packet_len += message_len + 4;
|
||||
channel->process_packet_len += + 4;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
||||
"starting request(%s) on channel %lu/%lu, message=%s",
|
||||
@@ -1262,15 +1263,19 @@ _libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel,
|
||||
*(s++) = 0x01;
|
||||
|
||||
if (message)
|
||||
_libssh2_store_str(&s, message, message_len);
|
||||
_libssh2_store_u32(&s, message_len);
|
||||
|
||||
channel->process_state = libssh2_NB_state_created;
|
||||
}
|
||||
|
||||
if (channel->process_state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_transport_write(session, channel->process_packet,
|
||||
channel->process_packet_len);
|
||||
rc = _libssh2_transport_send(session,
|
||||
channel->process_packet,
|
||||
channel->process_packet_len,
|
||||
(unsigned char *)message, message_len);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
_libssh2_error(session, rc,
|
||||
"Would block sending channel request");
|
||||
return rc;
|
||||
}
|
||||
else if (rc) {
|
||||
@@ -1459,6 +1464,67 @@ libssh2_channel_get_exit_status(LIBSSH2_CHANNEL *channel)
|
||||
return channel->exit_status;
|
||||
}
|
||||
|
||||
/*
|
||||
* libssh2_channel_get_exit_signal
|
||||
*
|
||||
* Get exit signal (without leading "SIG"), error message, and language
|
||||
* tag into newly allocated buffers of indicated length. Caller can
|
||||
* use NULL pointers to indicate that the value should not be set. The
|
||||
* *_len variables are set if they are non-NULL even if the
|
||||
* corresponding string parameter is NULL. Returns LIBSSH2_ERROR_NONE
|
||||
* on success, or an API error code.
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_channel_get_exit_signal(LIBSSH2_CHANNEL *channel,
|
||||
char **exitsignal,
|
||||
size_t *exitsignal_len,
|
||||
char **errmsg,
|
||||
size_t *errmsg_len,
|
||||
char **langtag,
|
||||
size_t *langtag_len)
|
||||
{
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
size_t namelen = 0;
|
||||
|
||||
if (channel) {
|
||||
if (channel->exit_signal) {
|
||||
namelen = strlen(channel->exit_signal);
|
||||
if (exitsignal) {
|
||||
*exitsignal = LIBSSH2_ALLOC(session, namelen + 1);
|
||||
if (!*exitsignal) {
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for signal name");
|
||||
}
|
||||
memcpy(*exitsignal, channel->exit_signal, namelen);
|
||||
(*exitsignal)[namelen] = '\0';
|
||||
}
|
||||
if (exitsignal_len)
|
||||
*exitsignal_len = namelen;
|
||||
} else {
|
||||
if (exitsignal)
|
||||
*exitsignal = NULL;
|
||||
if (exitsignal_len)
|
||||
*exitsignal_len = 0;
|
||||
}
|
||||
|
||||
/* TODO: set error message and language tag */
|
||||
|
||||
if (errmsg)
|
||||
*errmsg = NULL;
|
||||
|
||||
if (errmsg_len)
|
||||
*errmsg_len = 0;
|
||||
|
||||
if (langtag)
|
||||
*langtag = NULL;
|
||||
|
||||
if (langtag_len)
|
||||
*langtag_len = 0;
|
||||
}
|
||||
|
||||
return LIBSSH2_ERROR_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* _libssh2_channel_receive_window_adjust
|
||||
*
|
||||
@@ -1466,10 +1532,11 @@ libssh2_channel_get_exit_status(LIBSSH2_CHANNEL *channel)
|
||||
* to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and force is 0 the
|
||||
* adjustment amount will be queued for a later packet.
|
||||
*
|
||||
* Calls _libssh2_error() !
|
||||
*/
|
||||
int
|
||||
_libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel,
|
||||
unsigned long adjustment,
|
||||
uint32_t adjustment,
|
||||
unsigned char force,
|
||||
unsigned int *store)
|
||||
{
|
||||
@@ -1510,8 +1577,11 @@ _libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel,
|
||||
channel->adjust_state = libssh2_NB_state_created;
|
||||
}
|
||||
|
||||
rc = _libssh2_transport_write(channel->session, channel->adjust_adjust, 9);
|
||||
rc = _libssh2_transport_send(channel->session, channel->adjust_adjust, 9,
|
||||
NULL, 0);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
_libssh2_error(channel->session, rc,
|
||||
"Would block sending window adjust");
|
||||
return rc;
|
||||
}
|
||||
else if (rc) {
|
||||
@@ -1789,9 +1859,11 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
|
||||
return code. */
|
||||
if(channel->remote.eof || channel->remote.close)
|
||||
return 0;
|
||||
else
|
||||
/* if the transport layer said EAGAIN then we say so as well */
|
||||
return (rc == LIBSSH2_ERROR_EAGAIN)?rc:0;
|
||||
else if(rc != LIBSSH2_ERROR_EAGAIN)
|
||||
return 0;
|
||||
|
||||
/* if the transport layer said EAGAIN then we say so as well */
|
||||
return _libssh2_error(session, rc, "would block");
|
||||
}
|
||||
else
|
||||
/* make sure we remain in the created state to focus on emptying the
|
||||
@@ -1899,160 +1971,132 @@ _libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id)
|
||||
/*
|
||||
* _libssh2_channel_write
|
||||
*
|
||||
* Send data to a channel. Note that if this returns EAGAIN or simply didn't
|
||||
* send the entire packet, the caller must call this function again with the
|
||||
* SAME input arguments.
|
||||
* Send data to a channel. Note that if this returns EAGAIN, the caller must
|
||||
* call this function again with the SAME input arguments.
|
||||
*
|
||||
* Returns: number of bytes sent, or if it returns a negative number, that is
|
||||
* the error code!
|
||||
*/
|
||||
ssize_t
|
||||
_libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id,
|
||||
const char *buf, size_t buflen)
|
||||
const unsigned char *buf, size_t buflen)
|
||||
{
|
||||
int rc = 0;
|
||||
LIBSSH2_SESSION *session = channel->session;
|
||||
int rc;
|
||||
ssize_t wrote = 0; /* counter for this specific this call */
|
||||
|
||||
/* In theory we could split larger buffers into several smaller packets,
|
||||
* but for now we instead only deal with the first 32K in this call and
|
||||
* assume the app will call it again with the rest! The 32K is a
|
||||
* conservative limit based on the text in RFC4253 section 6.1.
|
||||
/* In theory we could split larger buffers into several smaller packets
|
||||
* but it turns out to be really hard and nasty to do while still offering
|
||||
* the API/prototype.
|
||||
*
|
||||
* Instead we only deal with the first 32K in this call and for the parent
|
||||
* function to call it again with the remainder! 32K is a conservative
|
||||
* limit based on the text in RFC4253 section 6.1.
|
||||
*/
|
||||
if(buflen > 32768)
|
||||
buflen = 32768;
|
||||
if(buflen > 32700)
|
||||
buflen = 32700;
|
||||
|
||||
if (channel->write_state == libssh2_NB_state_idle) {
|
||||
channel->write_bufwrote = 0;
|
||||
unsigned char *s = channel->write_packet;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
||||
_libssh2_debug(channel->session, LIBSSH2_TRACE_CONN,
|
||||
"Writing %d bytes on channel %lu/%lu, stream #%d",
|
||||
(int) buflen, channel->local.id, channel->remote.id,
|
||||
stream_id);
|
||||
|
||||
if (channel->local.close) {
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_CLOSED,
|
||||
if (channel->local.close)
|
||||
return _libssh2_error(channel->session,
|
||||
LIBSSH2_ERROR_CHANNEL_CLOSED,
|
||||
"We've already closed this channel");
|
||||
}
|
||||
|
||||
if (channel->local.eof) {
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_EOF_SENT,
|
||||
else if (channel->local.eof)
|
||||
return _libssh2_error(channel->session,
|
||||
LIBSSH2_ERROR_CHANNEL_EOF_SENT,
|
||||
"EOF has already been received, "
|
||||
"data might be ignored");
|
||||
}
|
||||
|
||||
/* [13] 9 = packet_type(1) + channelno(4) [ + streamid(4) ] +
|
||||
buflen(4) */
|
||||
channel->write_packet_len = buflen + (stream_id ? 13 : 9);
|
||||
channel->write_packet =
|
||||
LIBSSH2_ALLOC(session, channel->write_packet_len);
|
||||
if (!channel->write_packet) {
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocte space "
|
||||
"for data transmission packet");
|
||||
}
|
||||
/* drain the incoming flow first, mostly to make sure we get all
|
||||
* pending window adjust packets */
|
||||
do
|
||||
rc = _libssh2_transport_read(session);
|
||||
while (rc > 0);
|
||||
|
||||
channel->write_state = libssh2_NB_state_allocated;
|
||||
}
|
||||
if(channel->local.window_size <= 0)
|
||||
/* there's no room for data so we stop */
|
||||
return 0;
|
||||
|
||||
/* Deduct the amount that has already been sent, and set buf accordingly. */
|
||||
buflen -= channel->write_bufwrote;
|
||||
buf += channel->write_bufwrote;
|
||||
channel->write_bufwrite = buflen;
|
||||
|
||||
while (buflen > 0) {
|
||||
if (channel->write_state == libssh2_NB_state_allocated) {
|
||||
|
||||
/* drain the incoming flow first */
|
||||
do
|
||||
rc = _libssh2_transport_read(session);
|
||||
while (rc > 0);
|
||||
|
||||
if(channel->local.window_size <= 0) {
|
||||
/* there's no more room for data so we stop sending now */
|
||||
break;
|
||||
}
|
||||
|
||||
channel->write_bufwrite = buflen;
|
||||
channel->write_s = channel->write_packet;
|
||||
|
||||
*(channel->write_s++) =
|
||||
stream_id ? SSH_MSG_CHANNEL_EXTENDED_DATA :
|
||||
SSH_MSG_CHANNEL_DATA;
|
||||
_libssh2_store_u32(&channel->write_s, channel->remote.id);
|
||||
if (stream_id)
|
||||
_libssh2_store_u32(&channel->write_s, stream_id);
|
||||
|
||||
/* Don't exceed the remote end's limits */
|
||||
/* REMEMBER local means local as the SOURCE of the data */
|
||||
if (channel->write_bufwrite > channel->local.window_size) {
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
||||
"Splitting write block due to %lu byte "
|
||||
"window_size on %lu/%lu/%d",
|
||||
channel->local.window_size, channel->local.id,
|
||||
channel->remote.id, stream_id);
|
||||
channel->write_bufwrite = channel->local.window_size;
|
||||
}
|
||||
if (channel->write_bufwrite > channel->local.packet_size) {
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
||||
"Splitting write block due to %lu byte "
|
||||
"packet_size on %lu/%lu/%d",
|
||||
channel->local.packet_size, channel->local.id,
|
||||
channel->remote.id, stream_id);
|
||||
channel->write_bufwrite = channel->local.packet_size;
|
||||
}
|
||||
_libssh2_store_str(&channel->write_s, buf, channel->write_bufwrite);
|
||||
*(s++) = stream_id ? SSH_MSG_CHANNEL_EXTENDED_DATA :
|
||||
SSH_MSG_CHANNEL_DATA;
|
||||
_libssh2_store_u32(&s, channel->remote.id);
|
||||
if (stream_id)
|
||||
_libssh2_store_u32(&s, stream_id);
|
||||
|
||||
/* Don't exceed the remote end's limits */
|
||||
/* REMEMBER local means local as the SOURCE of the data */
|
||||
if (channel->write_bufwrite > channel->local.window_size) {
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
||||
"Sending %d bytes on channel %lu/%lu, stream_id=%d",
|
||||
(int) channel->write_bufwrite, channel->local.id,
|
||||
"Splitting write block due to %lu byte "
|
||||
"window_size on %lu/%lu/%d",
|
||||
channel->local.window_size, channel->local.id,
|
||||
channel->remote.id, stream_id);
|
||||
|
||||
channel->write_state = libssh2_NB_state_created;
|
||||
channel->write_bufwrite = channel->local.window_size;
|
||||
}
|
||||
|
||||
if (channel->write_state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_transport_write(session, channel->write_packet,
|
||||
channel->write_s -
|
||||
channel->write_packet);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
if(wrote) {
|
||||
/* some pieces of data was sent before the EAGAIN so we
|
||||
return that amount! As we ignore EAGAIN, we must drain
|
||||
the outgoing transport buffer. */
|
||||
_libssh2_transport_drain(session);
|
||||
goto _channel_write_done;
|
||||
}
|
||||
return _libssh2_error(session, rc,
|
||||
"Unable to send channel data");
|
||||
}
|
||||
else if (rc) {
|
||||
LIBSSH2_FREE(session, channel->write_packet);
|
||||
channel->write_packet = NULL;
|
||||
channel->write_state = libssh2_NB_state_idle;
|
||||
return _libssh2_error(session, rc,
|
||||
"Unable to send channel data");
|
||||
}
|
||||
/* Shrink local window size */
|
||||
channel->local.window_size -= channel->write_bufwrite;
|
||||
|
||||
/* Adjust buf for next iteration */
|
||||
buflen -= channel->write_bufwrite;
|
||||
buf += channel->write_bufwrite;
|
||||
channel->write_bufwrote += channel->write_bufwrite;
|
||||
wrote += channel->write_bufwrite;
|
||||
|
||||
channel->write_state = libssh2_NB_state_allocated;
|
||||
if (channel->write_bufwrite > channel->local.packet_size) {
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
||||
"Splitting write block due to %lu byte "
|
||||
"packet_size on %lu/%lu/%d",
|
||||
channel->local.packet_size, channel->local.id,
|
||||
channel->remote.id, stream_id);
|
||||
channel->write_bufwrite = channel->local.packet_size;
|
||||
}
|
||||
/* store the size here only, the buffer is passed in as-is to
|
||||
_libssh2_transport_send() */
|
||||
_libssh2_store_u32(&s, channel->write_bufwrite);
|
||||
channel->write_packet_len = s - channel->write_packet;
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
||||
"Sending %d bytes on channel %lu/%lu, stream_id=%d",
|
||||
(int) channel->write_bufwrite, channel->local.id,
|
||||
channel->remote.id, stream_id);
|
||||
|
||||
channel->write_state = libssh2_NB_state_created;
|
||||
}
|
||||
|
||||
_channel_write_done:
|
||||
if (channel->write_state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_transport_send(session, channel->write_packet,
|
||||
channel->write_packet_len,
|
||||
buf, channel->write_bufwrite);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
return _libssh2_error(session, rc,
|
||||
"Unable to send channel data");
|
||||
}
|
||||
else if (rc) {
|
||||
channel->write_state = libssh2_NB_state_idle;
|
||||
return _libssh2_error(session, rc,
|
||||
"Unable to send channel data");
|
||||
}
|
||||
/* Shrink local window size */
|
||||
channel->local.window_size -= channel->write_bufwrite;
|
||||
|
||||
LIBSSH2_FREE(session, channel->write_packet);
|
||||
channel->write_packet = NULL;
|
||||
wrote += channel->write_bufwrite;
|
||||
|
||||
channel->write_state = libssh2_NB_state_idle;
|
||||
/* Since _libssh2_transport_write() succeeded, we must return
|
||||
now to allow the caller to provide the next chunk of data.
|
||||
|
||||
return wrote;
|
||||
We cannot move on to send the next piece of data that may
|
||||
already have been provided in this same function call, as we
|
||||
risk getting EAGAIN for that and we can't return information
|
||||
both about sent data as well as EAGAIN. So, by returning short
|
||||
now, the caller will call this function again with new data to
|
||||
send */
|
||||
|
||||
channel->write_state = libssh2_NB_state_idle;
|
||||
|
||||
return wrote;
|
||||
}
|
||||
|
||||
return LIBSSH2_ERROR_INVAL; /* reaching this point is really bad */
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2070,7 +2114,8 @@ libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id,
|
||||
return LIBSSH2_ERROR_BAD_USE;
|
||||
|
||||
BLOCK_ADJUST(rc, channel->session,
|
||||
_libssh2_channel_write(channel, stream_id, buf, buflen));
|
||||
_libssh2_channel_write(channel, stream_id,
|
||||
(unsigned char *)buf, buflen));
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -2089,8 +2134,10 @@ static int channel_send_eof(LIBSSH2_CHANNEL *channel)
|
||||
channel->local.id, channel->remote.id);
|
||||
packet[0] = SSH_MSG_CHANNEL_EOF;
|
||||
_libssh2_htonu32(packet + 1, channel->remote.id);
|
||||
rc = _libssh2_transport_write(session, packet, 5);
|
||||
rc = _libssh2_transport_send(session, packet, 5, NULL, 0);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
_libssh2_error(session, rc,
|
||||
"Would block sending EOF");
|
||||
return rc;
|
||||
}
|
||||
else if (rc) {
|
||||
@@ -2181,7 +2228,8 @@ static int channel_wait_eof(LIBSSH2_CHANNEL *channel)
|
||||
}
|
||||
else if (rc < 0) {
|
||||
channel->wait_eof_state = libssh2_NB_state_idle;
|
||||
return -1;
|
||||
return _libssh2_error(session, rc,
|
||||
"_libssh2_transport_read() bailed out!");
|
||||
}
|
||||
} while (1);
|
||||
|
||||
@@ -2238,8 +2286,11 @@ int _libssh2_channel_close(LIBSSH2_CHANNEL * channel)
|
||||
}
|
||||
|
||||
if (channel->close_state == libssh2_NB_state_created) {
|
||||
retcode = _libssh2_transport_write(session, channel->close_packet, 5);
|
||||
retcode = _libssh2_transport_send(session, channel->close_packet, 5,
|
||||
NULL, 0);
|
||||
if (retcode == LIBSSH2_ERROR_EAGAIN) {
|
||||
_libssh2_error(session, rc,
|
||||
"Would block sending close-channel");
|
||||
return retcode;
|
||||
} else if (retcode) {
|
||||
channel->close_state = libssh2_NB_state_idle;
|
||||
@@ -2253,9 +2304,9 @@ int _libssh2_channel_close(LIBSSH2_CHANNEL * channel)
|
||||
if (channel->close_state == libssh2_NB_state_sent) {
|
||||
/* We must wait for the remote SSH_MSG_CHANNEL_CLOSE message */
|
||||
|
||||
while (!channel->remote.close && !rc) {
|
||||
while (!channel->remote.close && !rc &&
|
||||
(session->socket_state != LIBSSH2_SOCKET_DISCONNECTED))
|
||||
rc = _libssh2_transport_read(session);
|
||||
}
|
||||
}
|
||||
|
||||
if(rc != LIBSSH2_ERROR_EAGAIN) {
|
||||
@@ -2394,6 +2445,10 @@ int _libssh2_channel_free(LIBSSH2_CHANNEL *channel)
|
||||
|
||||
channel->free_state = libssh2_NB_state_idle;
|
||||
|
||||
if (channel->exit_signal) {
|
||||
LIBSSH2_FREE(session, channel->exit_signal);
|
||||
}
|
||||
|
||||
/*
|
||||
* channel->remote.close *might* not be set yet, Well...
|
||||
* We've sent the close packet, what more do you want?
|
||||
@@ -2424,18 +2479,12 @@ int _libssh2_channel_free(LIBSSH2_CHANNEL *channel)
|
||||
if (channel->setenv_packet) {
|
||||
LIBSSH2_FREE(session, channel->setenv_packet);
|
||||
}
|
||||
if (channel->reqPTY_packet) {
|
||||
LIBSSH2_FREE(session, channel->reqPTY_packet);
|
||||
}
|
||||
if (channel->reqX11_packet) {
|
||||
LIBSSH2_FREE(session, channel->reqX11_packet);
|
||||
}
|
||||
if (channel->process_packet) {
|
||||
LIBSSH2_FREE(session, channel->process_packet);
|
||||
}
|
||||
if (channel->write_packet) {
|
||||
LIBSSH2_FREE(session, channel->write_packet);
|
||||
}
|
||||
|
||||
LIBSSH2_FREE(session, channel);
|
||||
|
||||
|
@@ -48,7 +48,7 @@
|
||||
* Always non-blocking.
|
||||
*/
|
||||
int _libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel,
|
||||
unsigned long adjustment,
|
||||
uint32_t adjustment,
|
||||
unsigned char force,
|
||||
unsigned int *store);
|
||||
|
||||
@@ -80,7 +80,7 @@ _libssh2_channel_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode);
|
||||
*/
|
||||
ssize_t
|
||||
_libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id,
|
||||
const char *buf, size_t buflen);
|
||||
const unsigned char *buf, size_t buflen);
|
||||
|
||||
/*
|
||||
* _libssh2_channel_open
|
||||
@@ -92,7 +92,7 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type,
|
||||
uint32_t channel_type_len,
|
||||
uint32_t window_size,
|
||||
uint32_t packet_size,
|
||||
const char *message, unsigned int message_len);
|
||||
const unsigned char *message, size_t message_len);
|
||||
|
||||
|
||||
/*
|
||||
@@ -102,9 +102,8 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type,
|
||||
*/
|
||||
int
|
||||
_libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel,
|
||||
const char *request, unsigned int request_len,
|
||||
const char *message, unsigned int message_len);
|
||||
|
||||
const char *request, size_t request_len,
|
||||
const char *message, size_t message_len);
|
||||
|
||||
/*
|
||||
* _libssh2_channel_read
|
||||
|
205
src/comp.c
205
src/comp.c
@@ -1,4 +1,5 @@
|
||||
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
|
||||
* Copyright (c) 2010, Daniel Stenberg <daniel@haxx.se>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -52,24 +53,41 @@
|
||||
* Minimalist compression: Absolutely none
|
||||
*/
|
||||
static int
|
||||
comp_method_none_comp(LIBSSH2_SESSION * session,
|
||||
int compress,
|
||||
unsigned char **dest,
|
||||
comp_method_none_comp(LIBSSH2_SESSION *session,
|
||||
unsigned char *dest,
|
||||
size_t *dest_len,
|
||||
size_t payload_limit,
|
||||
int *free_dest,
|
||||
const unsigned char *src,
|
||||
size_t src_len, void **abstract)
|
||||
size_t src_len,
|
||||
void **abstract)
|
||||
{
|
||||
(void) session;
|
||||
(void) abstract;
|
||||
(void) dest;
|
||||
(void) dest_len;
|
||||
(void) src;
|
||||
(void) src_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* comp_method_none_decomp
|
||||
*
|
||||
* Minimalist decompression: Absolutely none
|
||||
*/
|
||||
static int
|
||||
comp_method_none_decomp(LIBSSH2_SESSION * session,
|
||||
unsigned char **dest,
|
||||
size_t *dest_len,
|
||||
size_t payload_limit,
|
||||
const unsigned char *src,
|
||||
size_t src_len, void **abstract)
|
||||
{
|
||||
(void) session;
|
||||
(void) compress;
|
||||
(void) payload_limit;
|
||||
(void) abstract;
|
||||
*dest = (unsigned char *) src;
|
||||
*dest_len = src_len;
|
||||
|
||||
*free_dest = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -77,8 +95,10 @@ comp_method_none_comp(LIBSSH2_SESSION * session,
|
||||
|
||||
static const LIBSSH2_COMP_METHOD comp_method_none = {
|
||||
"none",
|
||||
0, /* not really compressing */
|
||||
NULL,
|
||||
comp_method_none_comp,
|
||||
comp_method_none_decomp,
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -114,7 +134,7 @@ comp_method_zlib_free(voidpf opaque, voidpf address)
|
||||
* All your bandwidth are belong to us (so save some)
|
||||
*/
|
||||
static int
|
||||
comp_method_zlib_init(LIBSSH2_SESSION * session, int compress,
|
||||
comp_method_zlib_init(LIBSSH2_SESSION * session, int compr,
|
||||
void **abstract)
|
||||
{
|
||||
z_stream *strm;
|
||||
@@ -131,7 +151,7 @@ comp_method_zlib_init(LIBSSH2_SESSION * session, int compress,
|
||||
strm->opaque = (voidpf) session;
|
||||
strm->zalloc = (alloc_func) comp_method_zlib_alloc;
|
||||
strm->zfree = (free_func) comp_method_zlib_free;
|
||||
if (compress) {
|
||||
if (compr) {
|
||||
/* deflate */
|
||||
status = deflateInit(strm, Z_DEFAULT_COMPRESSION);
|
||||
} else {
|
||||
@@ -141,84 +161,112 @@ comp_method_zlib_init(LIBSSH2_SESSION * session, int compress,
|
||||
|
||||
if (status != Z_OK) {
|
||||
LIBSSH2_FREE(session, strm);
|
||||
return -1;
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS,
|
||||
"unhandled zlib error %d", status);
|
||||
return LIBSSH2_ERROR_COMPRESS;
|
||||
}
|
||||
*abstract = strm;
|
||||
|
||||
return LIBSSH2_ERROR_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* libssh2_comp_method_zlib_comp
|
||||
*
|
||||
* Compresses source to destination. Without allocation.
|
||||
*/
|
||||
static int
|
||||
comp_method_zlib_comp(LIBSSH2_SESSION *session,
|
||||
unsigned char *dest,
|
||||
|
||||
/* dest_len is a pointer to allow this function to
|
||||
update it with the final actual size used */
|
||||
size_t *dest_len,
|
||||
const unsigned char *src,
|
||||
size_t src_len,
|
||||
void **abstract)
|
||||
{
|
||||
z_stream *strm = *abstract;
|
||||
int out_maxlen = *dest_len;
|
||||
int status;
|
||||
|
||||
strm->next_in = (unsigned char *) src;
|
||||
strm->avail_in = src_len;
|
||||
strm->next_out = dest;
|
||||
strm->avail_out = out_maxlen;
|
||||
|
||||
status = deflate(strm, Z_PARTIAL_FLUSH);
|
||||
|
||||
if (status != Z_OK) {
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS,
|
||||
"unhandled zlib compression error %d", status);
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_ZLIB,
|
||||
"compression failure");
|
||||
}
|
||||
|
||||
*dest_len = out_maxlen - strm->avail_out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* libssh2_comp_method_zlib_comp
|
||||
* zlib, a compression standard for all occasions
|
||||
/*
|
||||
* libssh2_comp_method_zlib_decomp
|
||||
*
|
||||
* Decompresses source to destination. Allocates the output memory.
|
||||
*/
|
||||
static int
|
||||
comp_method_zlib_comp(LIBSSH2_SESSION * session,
|
||||
int compress,
|
||||
unsigned char **dest,
|
||||
size_t *dest_len,
|
||||
size_t payload_limit,
|
||||
int *free_dest,
|
||||
const unsigned char *src,
|
||||
size_t src_len, void **abstract)
|
||||
comp_method_zlib_decomp(LIBSSH2_SESSION * session,
|
||||
unsigned char **dest,
|
||||
size_t *dest_len,
|
||||
size_t payload_limit,
|
||||
const unsigned char *src,
|
||||
size_t src_len, void **abstract)
|
||||
{
|
||||
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 + 4) : (2 * src_len);
|
||||
int out_maxlen = 8 * src_len;
|
||||
int limiter = 0;
|
||||
|
||||
/* If strm is null, then we have not yet been initialized. */
|
||||
if (strm == NULL) {
|
||||
*dest = (unsigned char *) src;
|
||||
*dest_len = src_len;
|
||||
|
||||
*free_dest = 0;
|
||||
return 0;
|
||||
}
|
||||
if (strm == NULL)
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_COMPRESS,
|
||||
"decompression unitilized");;
|
||||
|
||||
/* In practice they never come smaller than this */
|
||||
if (out_maxlen < 25) {
|
||||
if (out_maxlen < 25)
|
||||
out_maxlen = 25;
|
||||
}
|
||||
|
||||
if (out_maxlen > (int) payload_limit) {
|
||||
if (out_maxlen > (int) payload_limit)
|
||||
out_maxlen = payload_limit;
|
||||
}
|
||||
|
||||
strm->next_in = (unsigned char *) src;
|
||||
strm->avail_in = src_len;
|
||||
strm->next_out = (unsigned char *) LIBSSH2_ALLOC(session, out_maxlen);
|
||||
out = (char *) strm->next_out;
|
||||
strm->avail_out = out_maxlen;
|
||||
if (!strm->next_out) {
|
||||
if (!strm->next_out)
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate compression/decompression "
|
||||
"buffer");
|
||||
}
|
||||
"Unable to allocate decompression buffer");
|
||||
while (strm->avail_in) {
|
||||
int status;
|
||||
|
||||
if (compress) {
|
||||
status = deflate(strm, Z_PARTIAL_FLUSH);
|
||||
} else {
|
||||
status = inflate(strm, Z_PARTIAL_FLUSH);
|
||||
}
|
||||
status = inflate(strm, Z_PARTIAL_FLUSH);
|
||||
|
||||
if (status != Z_OK) {
|
||||
LIBSSH2_FREE(session, out);
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS,
|
||||
"unhandled zlib error %d", status);
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_ZLIB,
|
||||
"compress/decompression failure");
|
||||
"decompression failure");
|
||||
}
|
||||
if (strm->avail_in) {
|
||||
size_t out_ofs = out_maxlen - strm->avail_out;
|
||||
char *newout;
|
||||
|
||||
out_maxlen +=
|
||||
compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
|
||||
out_maxlen += 8 * strm->avail_in;
|
||||
|
||||
if ((out_maxlen > (int) payload_limit) && !compress && limiter++) {
|
||||
if ((out_maxlen > (int) payload_limit) && limiter++) {
|
||||
LIBSSH2_FREE(session, out);
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_ZLIB,
|
||||
"Excessive growth in decompression phase");
|
||||
@@ -228,20 +276,18 @@ comp_method_zlib_comp(LIBSSH2_SESSION * session,
|
||||
if (!newout) {
|
||||
LIBSSH2_FREE(session, out);
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to expand compress/"
|
||||
"decompression buffer");
|
||||
"Unable to expand decompression buffer");
|
||||
}
|
||||
out = newout;
|
||||
strm->next_out = (unsigned char *) out + out_ofs;
|
||||
strm->avail_out +=
|
||||
compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
|
||||
strm->avail_out += 8 * 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;
|
||||
int grow_size = 2048;
|
||||
char *newout;
|
||||
|
||||
if (out_maxlen >= (int) payload_limit) {
|
||||
@@ -262,29 +308,27 @@ comp_method_zlib_comp(LIBSSH2_SESSION * session,
|
||||
if (!newout) {
|
||||
LIBSSH2_FREE(session, out);
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to expand final compress/"
|
||||
"Unable to expand final "
|
||||
"decompress buffer");
|
||||
}
|
||||
out = newout;
|
||||
strm->next_out = (unsigned char *) out + out_maxlen -
|
||||
grow_size;
|
||||
|
||||
if (compress) {
|
||||
status = deflate(strm, Z_PARTIAL_FLUSH);
|
||||
} else {
|
||||
status = inflate(strm, Z_PARTIAL_FLUSH);
|
||||
}
|
||||
status = inflate(strm, Z_PARTIAL_FLUSH);
|
||||
|
||||
if (status != Z_OK) {
|
||||
LIBSSH2_FREE(session, out);
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS,
|
||||
"unhandled zlib error %d", status);
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_ZLIB,
|
||||
"compress/decompression failure");
|
||||
"decompression failure");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*dest = (unsigned char *) out;
|
||||
*dest_len = out_maxlen - strm->avail_out;
|
||||
*free_dest = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -294,50 +338,53 @@ comp_method_zlib_comp(LIBSSH2_SESSION * session,
|
||||
* All done, no more compression for you
|
||||
*/
|
||||
static int
|
||||
comp_method_zlib_dtor(LIBSSH2_SESSION * session, int compress,
|
||||
void **abstract)
|
||||
comp_method_zlib_dtor(LIBSSH2_SESSION *session, int compr, void **abstract)
|
||||
{
|
||||
z_stream *strm = *abstract;
|
||||
|
||||
if (strm) {
|
||||
if (compress) {
|
||||
/* deflate */
|
||||
if (compr)
|
||||
deflateEnd(strm);
|
||||
} else {
|
||||
/* inflate */
|
||||
else
|
||||
inflateEnd(strm);
|
||||
}
|
||||
|
||||
LIBSSH2_FREE(session, strm);
|
||||
}
|
||||
|
||||
*abstract = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const LIBSSH2_COMP_METHOD comp_method_zlib = {
|
||||
"zlib",
|
||||
1, /* yes, this compresses */
|
||||
comp_method_zlib_init,
|
||||
comp_method_zlib_comp,
|
||||
comp_method_zlib_decomp,
|
||||
comp_method_zlib_dtor,
|
||||
};
|
||||
#endif /* LIBSSH2_HAVE_ZLIB */
|
||||
|
||||
/* ***********************
|
||||
* Compression Methods *
|
||||
*********************** */
|
||||
|
||||
/* If compression is enabled by the API, then this array is used which then
|
||||
may allow compression if zlib is available at build time */
|
||||
static const LIBSSH2_COMP_METHOD *comp_methods[] = {
|
||||
&comp_method_none,
|
||||
#ifdef LIBSSH2_HAVE_ZLIB
|
||||
&comp_method_zlib,
|
||||
#endif /* LIBSSH2_HAVE_ZLIB */
|
||||
&comp_method_none,
|
||||
NULL
|
||||
};
|
||||
|
||||
/* If compression is disabled by the API, then this array is used */
|
||||
static const LIBSSH2_COMP_METHOD *no_comp_methods[] = {
|
||||
&comp_method_none,
|
||||
NULL
|
||||
};
|
||||
|
||||
const LIBSSH2_COMP_METHOD **
|
||||
_libssh2_comp_methods(void)
|
||||
_libssh2_comp_methods(LIBSSH2_SESSION *session)
|
||||
{
|
||||
return comp_methods;
|
||||
if(session->flag.compress)
|
||||
return comp_methods;
|
||||
else
|
||||
return no_comp_methods;
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#ifndef __LIBSSH2_COMP_H
|
||||
#define __LIBSSH2_COMP_H
|
||||
|
||||
/* Copyright (C) 2009 by Daniel Stenberg
|
||||
/* Copyright (C) 2009-2010 by Daniel Stenberg
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
@@ -40,6 +40,6 @@
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
|
||||
const LIBSSH2_COMP_METHOD **_libssh2_comp_methods(void);
|
||||
const LIBSSH2_COMP_METHOD **_libssh2_comp_methods(LIBSSH2_SESSION *session);
|
||||
|
||||
#endif /* __LIBSSH2_COMP_H */
|
||||
|
20
src/crypt.c
20
src/crypt.c
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2009 Simon Josefsson <simon@josefsson.org>
|
||||
/* Copyright (c) 2009, 2010 Simon Josefsson <simon@josefsson.org>
|
||||
* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -79,9 +79,9 @@ crypt_init(LIBSSH2_SESSION * session,
|
||||
{
|
||||
struct crypt_ctx *ctx = LIBSSH2_ALLOC(session,
|
||||
sizeof(struct crypt_ctx));
|
||||
if (!ctx) {
|
||||
return -1;
|
||||
}
|
||||
if (!ctx)
|
||||
return LIBSSH2_ERROR_ALLOC;
|
||||
|
||||
ctx->encrypt = encrypt;
|
||||
ctx->algo = method->algo;
|
||||
if (_libssh2_cipher_init(&ctx->h, ctx->algo, iv, secret, encrypt)) {
|
||||
@@ -242,13 +242,13 @@ crypt_init_arcfour128(LIBSSH2_SESSION * session,
|
||||
int rc;
|
||||
|
||||
rc = crypt_init (session, method, iv, free_iv, secret, free_secret,
|
||||
encrypt, abstract);
|
||||
encrypt, abstract);
|
||||
if (rc == 0) {
|
||||
struct crypt_ctx *cctx = *(struct crypt_ctx **) abstract;
|
||||
unsigned char block[8];
|
||||
size_t discard = 1536;
|
||||
for (; discard; discard -= 8)
|
||||
_libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, block);
|
||||
struct crypt_ctx *cctx = *(struct crypt_ctx **) abstract;
|
||||
unsigned char block[8];
|
||||
size_t discard = 1536;
|
||||
for (; discard; discard -= 8)
|
||||
_libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, block);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
116
src/crypto.h
Normal file
116
src/crypto.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/* Copyright (C) 2009, 2010 Simon Josefsson
|
||||
* Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved.
|
||||
* Copyright (C) 2010 Daniel Stenberg
|
||||
*
|
||||
* 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_CRYPTO_H
|
||||
#define LIBSSH2_CRYPTO_H
|
||||
|
||||
#ifdef LIBSSH2_LIBGCRYPT
|
||||
#include "libgcrypt.h"
|
||||
#else
|
||||
#include "openssl.h"
|
||||
#endif
|
||||
|
||||
int _libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
|
||||
const unsigned char *edata,
|
||||
unsigned long elen,
|
||||
const unsigned char *ndata,
|
||||
unsigned long nlen,
|
||||
const unsigned char *ddata,
|
||||
unsigned long dlen,
|
||||
const unsigned char *pdata,
|
||||
unsigned long plen,
|
||||
const unsigned char *qdata,
|
||||
unsigned long qlen,
|
||||
const unsigned char *e1data,
|
||||
unsigned long e1len,
|
||||
const unsigned char *e2data,
|
||||
unsigned long e2len,
|
||||
const unsigned char *coeffdata, unsigned long coefflen);
|
||||
int _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
|
||||
LIBSSH2_SESSION * session,
|
||||
const char *filename,
|
||||
unsigned const char *passphrase);
|
||||
int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa,
|
||||
const unsigned char *sig,
|
||||
unsigned long sig_len,
|
||||
const unsigned char *m, unsigned long m_len);
|
||||
int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
|
||||
libssh2_rsa_ctx * rsactx,
|
||||
const unsigned char *hash,
|
||||
size_t hash_len,
|
||||
unsigned char **signature,
|
||||
size_t *signature_len);
|
||||
|
||||
int _libssh2_dsa_new(libssh2_dsa_ctx ** dsa,
|
||||
const unsigned char *pdata,
|
||||
unsigned long plen,
|
||||
const unsigned char *qdata,
|
||||
unsigned long qlen,
|
||||
const unsigned char *gdata,
|
||||
unsigned long glen,
|
||||
const unsigned char *ydata,
|
||||
unsigned long ylen,
|
||||
const unsigned char *x, unsigned long x_len);
|
||||
int _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
|
||||
LIBSSH2_SESSION * session,
|
||||
const char *filename,
|
||||
unsigned const char *passphrase);
|
||||
int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,
|
||||
const unsigned char *sig,
|
||||
const unsigned char *m, unsigned long m_len);
|
||||
int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
|
||||
const unsigned char *hash,
|
||||
unsigned long hash_len, unsigned char *sig);
|
||||
|
||||
int _libssh2_cipher_init(_libssh2_cipher_ctx * h,
|
||||
_libssh2_cipher_type(algo),
|
||||
unsigned char *iv,
|
||||
unsigned char *secret, int encrypt);
|
||||
|
||||
int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
|
||||
_libssh2_cipher_type(algo),
|
||||
int encrypt, unsigned char *block);
|
||||
|
||||
int _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
|
||||
unsigned char **method,
|
||||
size_t *method_len,
|
||||
unsigned char **pubkeydata,
|
||||
size_t *pubkeydata_len,
|
||||
const char *privatekey,
|
||||
const char *passphrase);
|
||||
|
||||
#endif
|
@@ -68,7 +68,8 @@ libssh2_keepalive_send (LIBSSH2_SESSION *session,
|
||||
now = time (NULL);
|
||||
|
||||
if (session->keepalive_last_sent + session->keepalive_interval <= now) {
|
||||
/* Format is "SSH_MSG_GLOBAL_REQUEST || 4-byte len || str || want-reply". */
|
||||
/* Format is
|
||||
"SSH_MSG_GLOBAL_REQUEST || 4-byte len || str || want-reply". */
|
||||
unsigned char keepalive_data[]
|
||||
= "\x50\x00\x00\x00\x15keepalive@libssh2.orgW";
|
||||
size_t len = sizeof (keepalive_data) - 1;
|
||||
@@ -76,9 +77,9 @@ libssh2_keepalive_send (LIBSSH2_SESSION *session,
|
||||
|
||||
keepalive_data[len - 1] = session->keepalive_want_reply;
|
||||
|
||||
rc = _libssh2_transport_write(session, keepalive_data, len);
|
||||
/* Silently ignore PACKET_EAGAIN here: if the write buffer is
|
||||
already full, sending another keepalive is not useful. */
|
||||
rc = _libssh2_transport_send(session, keepalive_data, len, NULL, 0);
|
||||
/* Silently ignore PACKET_EAGAIN here: if the write buffer is
|
||||
already full, sending another keepalive is not useful. */
|
||||
if (rc && rc != LIBSSH2_ERROR_EAGAIN) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
||||
"Unable to send keepalive message");
|
||||
|
38
src/kex.c
38
src/kex.c
@@ -1,4 +1,5 @@
|
||||
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
|
||||
* Copyright (c) 2010, Daniel Stenberg <daniel@haxx.se>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -140,8 +141,9 @@ static int diffie_hellman_sha1(LIBSSH2_SESSION *session,
|
||||
}
|
||||
|
||||
if (exchange_state->state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_transport_write(session, exchange_state->e_packet,
|
||||
exchange_state->e_packet_len);
|
||||
rc = _libssh2_transport_send(session, exchange_state->e_packet,
|
||||
exchange_state->e_packet_len,
|
||||
NULL, 0);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
@@ -410,7 +412,7 @@ static int diffie_hellman_sha1(LIBSSH2_SESSION *session,
|
||||
}
|
||||
|
||||
if (exchange_state->state == libssh2_NB_state_sent2) {
|
||||
rc = _libssh2_transport_write(session, &exchange_state->c, 1);
|
||||
rc = _libssh2_transport_send(session, &exchange_state->c, 1, NULL, 0);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
@@ -843,8 +845,8 @@ kex_method_diffie_hellman_group_exchange_sha1_key_exchange
|
||||
}
|
||||
|
||||
if (key_state->state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_transport_write(session, key_state->request,
|
||||
key_state->request_len);
|
||||
rc = _libssh2_transport_send(session, key_state->request,
|
||||
key_state->request_len, NULL, 0);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
return rc;
|
||||
} else if (rc) {
|
||||
@@ -1043,10 +1045,10 @@ static int kexinit(LIBSSH2_SESSION * session)
|
||||
_libssh2_mac_methods());
|
||||
comp_cs_len =
|
||||
LIBSSH2_METHOD_PREFS_LEN(session->local.comp_prefs,
|
||||
_libssh2_comp_methods());
|
||||
_libssh2_comp_methods(session));
|
||||
comp_sc_len =
|
||||
LIBSSH2_METHOD_PREFS_LEN(session->remote.comp_prefs,
|
||||
_libssh2_comp_methods());
|
||||
_libssh2_comp_methods(session));
|
||||
lang_cs_len =
|
||||
LIBSSH2_METHOD_PREFS_LEN(session->local.lang_prefs, NULL);
|
||||
lang_sc_len =
|
||||
@@ -1083,9 +1085,9 @@ static int kexinit(LIBSSH2_SESSION * session)
|
||||
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_comp_methods(session));
|
||||
LIBSSH2_METHOD_PREFS_STR(s, comp_sc_len, session->remote.comp_prefs,
|
||||
_libssh2_comp_methods());
|
||||
_libssh2_comp_methods(session));
|
||||
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,
|
||||
@@ -1133,12 +1135,12 @@ static int kexinit(LIBSSH2_SESSION * session)
|
||||
} else {
|
||||
data = session->kexinit_data;
|
||||
data_len = session->kexinit_data_len;
|
||||
/* zap the variables to ensure there is NOT a double free later */
|
||||
/* zap the variables to ensure there is NOT a double free later */
|
||||
session->kexinit_data = NULL;
|
||||
session->kexinit_data_len = 0;
|
||||
}
|
||||
|
||||
rc = _libssh2_transport_write(session, data, data_len);
|
||||
rc = _libssh2_transport_send(session, data, data_len, NULL, 0);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
session->kexinit_data = data;
|
||||
session->kexinit_data_len = data_len;
|
||||
@@ -1271,7 +1273,7 @@ static int kex_agree_hostkey(LIBSSH2_SESSION * session,
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (hostkeyp && (*hostkeyp)->name) {
|
||||
while (hostkeyp && (*hostkeyp) && (*hostkeyp)->name) {
|
||||
s = kex_agree_instr(hostkey, hostkey_len,
|
||||
(unsigned char *) (*hostkeyp)->name,
|
||||
strlen((*hostkeyp)->name));
|
||||
@@ -1487,11 +1489,11 @@ static int kex_agree_mac(LIBSSH2_SESSION * session,
|
||||
/* kex_agree_comp
|
||||
* Agree on a compression scheme
|
||||
*/
|
||||
static int kex_agree_comp(LIBSSH2_SESSION * session,
|
||||
libssh2_endpoint_data * endpoint, unsigned char *comp,
|
||||
static int kex_agree_comp(LIBSSH2_SESSION *session,
|
||||
libssh2_endpoint_data *endpoint, unsigned char *comp,
|
||||
unsigned long comp_len)
|
||||
{
|
||||
const LIBSSH2_COMP_METHOD **compp = _libssh2_comp_methods();
|
||||
const LIBSSH2_COMP_METHOD **compp = _libssh2_comp_methods(session);
|
||||
unsigned char *s;
|
||||
(void) session;
|
||||
|
||||
@@ -1827,12 +1829,14 @@ libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type,
|
||||
|
||||
case LIBSSH2_METHOD_COMP_CS:
|
||||
prefvar = &session->local.comp_prefs;
|
||||
mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_comp_methods();
|
||||
mlist = (const LIBSSH2_COMMON_METHOD **)
|
||||
_libssh2_comp_methods(session);
|
||||
break;
|
||||
|
||||
case LIBSSH2_METHOD_COMP_SC:
|
||||
prefvar = &session->remote.comp_prefs;
|
||||
mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_comp_methods();
|
||||
mlist = (const LIBSSH2_COMMON_METHOD **)
|
||||
_libssh2_comp_methods(session);
|
||||
break;
|
||||
|
||||
case LIBSSH2_METHOD_LANG_CS:
|
||||
|
232
src/knownhost.c
232
src/knownhost.c
@@ -566,6 +566,120 @@ libssh2_knownhost_free(LIBSSH2_KNOWNHOSTS *hosts)
|
||||
LIBSSH2_FREE(hosts->session, hosts);
|
||||
}
|
||||
|
||||
|
||||
/* old style plain text: [name]([,][name])*
|
||||
|
||||
for the sake of simplicity, we add them as separate hosts with the same
|
||||
key
|
||||
*/
|
||||
static int oldstyle_hostline(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
const char *host, size_t hostlen,
|
||||
const char *key, size_t keylen, int key_type,
|
||||
const char *comment, size_t commentlen)
|
||||
{
|
||||
int rc = 0;
|
||||
size_t namelen = 0;
|
||||
const char *name = host + hostlen;
|
||||
|
||||
if(hostlen < 1)
|
||||
return _libssh2_error(hosts->session,
|
||||
LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
|
||||
"Failed to parse known_hosts line "
|
||||
"(no host names)");
|
||||
|
||||
while(name > host) {
|
||||
--name;
|
||||
++namelen;
|
||||
|
||||
/* when we get the the start or see a comma coming up, add the host
|
||||
name to the collection */
|
||||
if((name == host) || (*(name-1) == ',')) {
|
||||
|
||||
char hostbuf[256];
|
||||
|
||||
/* make sure we don't overflow the buffer */
|
||||
if(namelen >= sizeof(hostbuf)-1)
|
||||
return _libssh2_error(hosts->session,
|
||||
LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
|
||||
"Failed to parse known_hosts line "
|
||||
"(unexpected length)");
|
||||
|
||||
/* copy host name to the temp buffer and zero terminate */
|
||||
memcpy(hostbuf, name, namelen);
|
||||
hostbuf[namelen]=0;
|
||||
|
||||
rc = knownhost_add(hosts, hostbuf, NULL, key, keylen,
|
||||
comment, commentlen,
|
||||
key_type | LIBSSH2_KNOWNHOST_TYPE_PLAIN |
|
||||
LIBSSH2_KNOWNHOST_KEYENC_BASE64, NULL);
|
||||
if(rc)
|
||||
return rc;
|
||||
|
||||
if(name > host) {
|
||||
namelen = 0;
|
||||
--name; // skip comma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* |1|[salt]|[hash] */
|
||||
static int hashed_hostline(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
const char *host, size_t hostlen,
|
||||
const char *key, size_t keylen, int key_type,
|
||||
const char *comment, size_t commentlen)
|
||||
{
|
||||
const char *p;
|
||||
char saltbuf[32];
|
||||
char hostbuf[256];
|
||||
|
||||
const char *salt = &host[3]; /* skip the magic marker */
|
||||
hostlen -= 3; /* deduct the marker */
|
||||
|
||||
/* this is where the salt starts, find the end of it */
|
||||
for(p = salt; *p && (*p != '|'); p++)
|
||||
;
|
||||
|
||||
if(*p=='|') {
|
||||
const char *hash = NULL;
|
||||
size_t saltlen = p - salt;
|
||||
if(saltlen >= (sizeof(saltbuf)-1)) /* weird length */
|
||||
return _libssh2_error(hosts->session,
|
||||
LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
|
||||
"Failed to parse known_hosts line "
|
||||
"(unexpectedly long salt)");
|
||||
|
||||
memcpy(saltbuf, salt, saltlen);
|
||||
saltbuf[saltlen] = 0; /* zero terminate */
|
||||
salt = saltbuf; /* point to the stack based buffer */
|
||||
|
||||
hash = p+1; /* the host hash is after the separator */
|
||||
|
||||
/* now make the host point to the hash */
|
||||
host = hash;
|
||||
hostlen -= saltlen+1; /* deduct the salt and separator */
|
||||
|
||||
/* check that the lengths seem sensible */
|
||||
if(hostlen >= sizeof(hostbuf)-1)
|
||||
return _libssh2_error(hosts->session,
|
||||
LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
|
||||
"Failed to parse known_hosts line "
|
||||
"(unexpected length)");
|
||||
|
||||
memcpy(hostbuf, host, hostlen);
|
||||
hostbuf[hostlen]=0;
|
||||
|
||||
return knownhost_add(hosts, hostbuf, salt, key, keylen, comment,
|
||||
commentlen,
|
||||
key_type | LIBSSH2_KNOWNHOST_TYPE_SHA1 |
|
||||
LIBSSH2_KNOWNHOST_KEYENC_BASE64, NULL);
|
||||
}
|
||||
else
|
||||
return 0; /* XXX: This should be an error, shouldn't it? */
|
||||
}
|
||||
|
||||
/*
|
||||
* hostline()
|
||||
*
|
||||
@@ -580,88 +694,21 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
const char *host, size_t hostlen,
|
||||
const char *key, size_t keylen)
|
||||
{
|
||||
const char *p;
|
||||
const char *orig = host;
|
||||
const char *salt = NULL;
|
||||
const char *comment = NULL;
|
||||
size_t commentlen = 0;
|
||||
int rc;
|
||||
int type = LIBSSH2_KNOWNHOST_TYPE_PLAIN;
|
||||
const char *sep = NULL;
|
||||
size_t seplen = 0;
|
||||
char saltbuf[32];
|
||||
char hostbuf[256];
|
||||
|
||||
/* Figure out host format */
|
||||
if((hostlen >2) && memcmp(host, "|1|", 3)) {
|
||||
/* old style plain text: [name][,][ip-address]
|
||||
|
||||
for the sake of simplicity, we add them as two hosts with the same
|
||||
key
|
||||
*/
|
||||
size_t scan = hostlen;
|
||||
|
||||
while(scan && (*host != ',')) {
|
||||
host++;
|
||||
scan--;
|
||||
}
|
||||
|
||||
if(scan) {
|
||||
sep = host+1;
|
||||
seplen = scan-1;
|
||||
hostlen -= scan; /* deduct what's left to scan from the first
|
||||
host name */
|
||||
}
|
||||
else
|
||||
host = orig;
|
||||
}
|
||||
else {
|
||||
/* |1|[salt]|[hash] */
|
||||
type = LIBSSH2_KNOWNHOST_TYPE_SHA1;
|
||||
|
||||
salt = &host[3]; /* skip the magic marker */
|
||||
hostlen -= 3; /* deduct the marker */
|
||||
|
||||
/* this is where the salt starts, find the end of it */
|
||||
for(p = salt; *p && (*p != '|'); p++)
|
||||
;
|
||||
|
||||
if(*p=='|') {
|
||||
const char *hash = NULL;
|
||||
size_t saltlen = p - salt;
|
||||
if(saltlen >= (sizeof(saltbuf)-1)) /* weird length */
|
||||
return _libssh2_error(hosts->session,
|
||||
LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
|
||||
"Failed to parse known_hosts line "
|
||||
"(unexpectedly long salt)");
|
||||
|
||||
memcpy(saltbuf, salt, saltlen);
|
||||
saltbuf[saltlen] = 0; /* zero terminate */
|
||||
salt = saltbuf; /* point to the stack based buffer */
|
||||
|
||||
hash = p+1; /* the host hash is after the separator */
|
||||
|
||||
/* now make the host point to the hash */
|
||||
host = hash;
|
||||
hostlen -= saltlen+1; /* deduct the salt and separator */
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
int key_type;
|
||||
|
||||
/* make some checks that the lengths seem sensible */
|
||||
if((keylen < 20) ||
|
||||
(seplen >= sizeof(hostbuf)-1) ||
|
||||
(hostlen >= sizeof(hostbuf)-1))
|
||||
if(keylen < 20)
|
||||
return _libssh2_error(hosts->session,
|
||||
LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
|
||||
"Failed to parse known_hosts line "
|
||||
"(unexpected length)");
|
||||
|
||||
"(key too short)");
|
||||
|
||||
switch(key[0]) {
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
type |= LIBSSH2_KNOWNHOST_KEY_RSA1;
|
||||
key_type = LIBSSH2_KNOWNHOST_KEY_RSA1;
|
||||
|
||||
/* Note that the old-style keys (RSA1) aren't truly base64, but we
|
||||
* claim it is for now since we can get away with strcmp()ing the
|
||||
@@ -672,9 +719,9 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
|
||||
case 's': /* ssh-dss or ssh-rsa */
|
||||
if(!strncmp(key, "ssh-dss", 7))
|
||||
type |= LIBSSH2_KNOWNHOST_KEY_SSHDSS;
|
||||
key_type = LIBSSH2_KNOWNHOST_KEY_SSHDSS;
|
||||
else if(!strncmp(key, "ssh-rsa", 7))
|
||||
type |= LIBSSH2_KNOWNHOST_KEY_SSHRSA;
|
||||
key_type = LIBSSH2_KNOWNHOST_KEY_SSHRSA;
|
||||
else
|
||||
/* unknown key type */
|
||||
return _libssh2_error(hosts->session,
|
||||
@@ -721,30 +768,21 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
"Unknown key format");
|
||||
}
|
||||
|
||||
if(sep) {
|
||||
/* The second host after the comma, add this first. Copy it to the
|
||||
temp buffer and zero terminate */
|
||||
memcpy(hostbuf, sep, seplen);
|
||||
hostbuf[seplen]=0;
|
||||
/* Figure out host format */
|
||||
if((hostlen >2) && memcmp(host, "|1|", 3)) {
|
||||
/* old style plain text: [name]([,][name])*
|
||||
|
||||
rc = knownhost_add(hosts, hostbuf, salt, key, keylen,
|
||||
comment, commentlen,
|
||||
type | LIBSSH2_KNOWNHOST_KEYENC_BASE64,
|
||||
NULL);
|
||||
if(rc)
|
||||
return rc;
|
||||
for the sake of simplicity, we add them as separate hosts with the
|
||||
same key
|
||||
*/
|
||||
return oldstyle_hostline(hosts, host, hostlen, key, keylen, key_type,
|
||||
comment, commentlen);
|
||||
}
|
||||
else {
|
||||
/* |1|[salt]|[hash] */
|
||||
return hashed_hostline(hosts, host, hostlen, key, keylen, key_type,
|
||||
comment, commentlen);
|
||||
}
|
||||
|
||||
if (!salt)
|
||||
host = orig;
|
||||
memcpy(hostbuf, host, hostlen);
|
||||
hostbuf[hostlen]=0;
|
||||
|
||||
rc = knownhost_add(hosts, hostbuf, salt, key, keylen, comment,
|
||||
commentlen,
|
||||
type | LIBSSH2_KNOWNHOST_KEYENC_BASE64,
|
||||
NULL);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -764,7 +802,7 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts,
|
||||
* <name> or <hash>
|
||||
*
|
||||
* <name> consists of
|
||||
* [name,address] or just [name] or just [address]
|
||||
* [name] optionally followed by [,name] one or more times
|
||||
*
|
||||
* <hash> consists of
|
||||
* |1|<salt>|hash
|
||||
|
@@ -537,11 +537,11 @@ _libssh2_cipher_init(_libssh2_cipher_ctx * h,
|
||||
|
||||
if (mode != GCRY_CIPHER_MODE_STREAM) {
|
||||
int blklen = gcry_cipher_get_algo_blklen(cipher);
|
||||
if (mode == GCRY_CIPHER_MODE_CTR)
|
||||
ret = gcry_cipher_setctr(*h, iv, blklen);
|
||||
else
|
||||
ret = gcry_cipher_setiv(*h, iv, blklen);
|
||||
if (ret) {
|
||||
if (mode == GCRY_CIPHER_MODE_CTR)
|
||||
ret = gcry_cipher_setctr(*h, iv, blklen);
|
||||
else
|
||||
ret = gcry_cipher_setiv(*h, iv, blklen);
|
||||
if (ret) {
|
||||
gcry_cipher_close(*h);
|
||||
return -1;
|
||||
}
|
||||
@@ -572,4 +572,17 @@ _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
_libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
|
||||
unsigned char **method,
|
||||
size_t *method_len,
|
||||
unsigned char **pubkeydata,
|
||||
size_t *pubkeydata_len,
|
||||
const char *privatekey,
|
||||
const char *passphrase)
|
||||
{
|
||||
return -1; /* not yet supported; interpreted by userauth.c to call
|
||||
libssh2_error */
|
||||
}
|
||||
|
||||
#endif /* LIBSSH2_LIBGCRYPT */
|
||||
|
@@ -97,62 +97,10 @@
|
||||
|
||||
#define libssh2_rsa_ctx struct gcry_sexp
|
||||
|
||||
int _libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
|
||||
const unsigned char *edata,
|
||||
unsigned long elen,
|
||||
const unsigned char *ndata,
|
||||
unsigned long nlen,
|
||||
const unsigned char *ddata,
|
||||
unsigned long dlen,
|
||||
const unsigned char *pdata,
|
||||
unsigned long plen,
|
||||
const unsigned char *qdata,
|
||||
unsigned long qlen,
|
||||
const unsigned char *e1data,
|
||||
unsigned long e1len,
|
||||
const unsigned char *e2data,
|
||||
unsigned long e2len,
|
||||
const unsigned char *coeffdata, unsigned long coefflen);
|
||||
int _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
|
||||
LIBSSH2_SESSION * session,
|
||||
const char *filename,
|
||||
unsigned const char *passphrase);
|
||||
int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa,
|
||||
const unsigned char *sig,
|
||||
unsigned long sig_len,
|
||||
const unsigned char *m, unsigned long m_len);
|
||||
int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
|
||||
libssh2_rsa_ctx * rsactx,
|
||||
const unsigned char *hash,
|
||||
size_t hash_len,
|
||||
unsigned char **signature,
|
||||
size_t *signature_len);
|
||||
|
||||
#define _libssh2_rsa_free(rsactx) gcry_sexp_release (rsactx)
|
||||
|
||||
#define libssh2_dsa_ctx struct gcry_sexp
|
||||
|
||||
int _libssh2_dsa_new(libssh2_dsa_ctx ** dsa,
|
||||
const unsigned char *pdata,
|
||||
unsigned long plen,
|
||||
const unsigned char *qdata,
|
||||
unsigned long qlen,
|
||||
const unsigned char *gdata,
|
||||
unsigned long glen,
|
||||
const unsigned char *ydata,
|
||||
unsigned long ylen,
|
||||
const unsigned char *x, unsigned long x_len);
|
||||
int _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
|
||||
LIBSSH2_SESSION * session,
|
||||
const char *filename,
|
||||
unsigned const char *passphrase);
|
||||
int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsa,
|
||||
const unsigned char *sig,
|
||||
const unsigned char *m, unsigned long m_len);
|
||||
int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
|
||||
const unsigned char *hash,
|
||||
unsigned long hash_len, unsigned char *sig);
|
||||
|
||||
#define _libssh2_dsa_free(dsactx) gcry_sexp_release (dsactx)
|
||||
|
||||
#define _libssh2_cipher_type(name) int name
|
||||
@@ -162,35 +110,27 @@ int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
|
||||
#define _libssh2_gcry_cipher(c) (c >> 8)
|
||||
#define _libssh2_gcry_mode(m) (m & 0xFF)
|
||||
|
||||
#define _libssh2_cipher_aes256ctr \
|
||||
#define _libssh2_cipher_aes256ctr \
|
||||
_libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CTR)
|
||||
#define _libssh2_cipher_aes192ctr \
|
||||
#define _libssh2_cipher_aes192ctr \
|
||||
_libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CTR)
|
||||
#define _libssh2_cipher_aes128ctr \
|
||||
#define _libssh2_cipher_aes128ctr \
|
||||
_libssh2_gcry_ciphermode(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR)
|
||||
#define _libssh2_cipher_aes256 \
|
||||
#define _libssh2_cipher_aes256 \
|
||||
_libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC)
|
||||
#define _libssh2_cipher_aes192 \
|
||||
#define _libssh2_cipher_aes192 \
|
||||
_libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC)
|
||||
#define _libssh2_cipher_aes128 \
|
||||
#define _libssh2_cipher_aes128 \
|
||||
_libssh2_gcry_ciphermode(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC)
|
||||
#define _libssh2_cipher_blowfish \
|
||||
#define _libssh2_cipher_blowfish \
|
||||
_libssh2_gcry_ciphermode(GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC)
|
||||
#define _libssh2_cipher_arcfour \
|
||||
#define _libssh2_cipher_arcfour \
|
||||
_libssh2_gcry_ciphermode(GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM)
|
||||
#define _libssh2_cipher_cast5 \
|
||||
#define _libssh2_cipher_cast5 \
|
||||
_libssh2_gcry_ciphermode(GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC)
|
||||
#define _libssh2_cipher_3des \
|
||||
#define _libssh2_cipher_3des \
|
||||
_libssh2_gcry_ciphermode(GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC)
|
||||
|
||||
int _libssh2_cipher_init(_libssh2_cipher_ctx * h,
|
||||
_libssh2_cipher_type(algo),
|
||||
unsigned char *iv,
|
||||
unsigned char *secret, int encrypt);
|
||||
|
||||
int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
|
||||
_libssh2_cipher_type(algo),
|
||||
int encrypt, unsigned char *block);
|
||||
|
||||
#define _libssh2_cipher_dtor(ctx) gcry_cipher_close(*(ctx))
|
||||
|
||||
@@ -207,3 +147,4 @@ int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
|
||||
#define _libssh2_bn_bytes(bn) (gcry_mpi_get_nbits (bn) / 8 + ((gcry_mpi_get_nbits (bn) % 8 == 0) ? 0 : 1))
|
||||
#define _libssh2_bn_bits(bn) gcry_mpi_get_nbits (bn)
|
||||
#define _libssh2_bn_free(bn) gcry_mpi_release(bn)
|
||||
|
||||
|
@@ -125,12 +125,7 @@ static inline int writev(int sock, struct iovec *iov, int nvecs)
|
||||
|
||||
#endif /* WIN32 */
|
||||
|
||||
|
||||
#ifdef LIBSSH2_LIBGCRYPT
|
||||
#include "libgcrypt.h"
|
||||
#else
|
||||
#include "openssl.h"
|
||||
#endif
|
||||
#include "crypto.h"
|
||||
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
|
||||
@@ -145,13 +140,6 @@ static inline int writev(int sock, struct iovec *iov, int nvecs)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
typedef SOCKET libssh2_socket_t;
|
||||
#else /* !WIN32 */
|
||||
typedef int libssh2_socket_t;
|
||||
#define INVALID_SOCKET -1
|
||||
#endif /* WIN32 */
|
||||
|
||||
/* RFC4253 section 6.1 Maximum Packet Length says:
|
||||
*
|
||||
* "All implementations MUST be able to process packets with
|
||||
@@ -185,7 +173,6 @@ typedef int libssh2_socket_t;
|
||||
|
||||
typedef struct _LIBSSH2_KEX_METHOD LIBSSH2_KEX_METHOD;
|
||||
typedef struct _LIBSSH2_HOSTKEY_METHOD LIBSSH2_HOSTKEY_METHOD;
|
||||
typedef struct _LIBSSH2_MAC_METHOD LIBSSH2_MAC_METHOD;
|
||||
typedef struct _LIBSSH2_CRYPT_METHOD LIBSSH2_CRYPT_METHOD;
|
||||
typedef struct _LIBSSH2_COMP_METHOD LIBSSH2_COMP_METHOD;
|
||||
|
||||
@@ -311,18 +298,13 @@ struct _LIBSSH2_PACKET
|
||||
{
|
||||
struct list_node node; /* linked list header */
|
||||
|
||||
unsigned char type;
|
||||
|
||||
/* Unencrypted Payload (no type byte, no padding, just the facts ma'am) */
|
||||
/* the raw unencrypted payload */
|
||||
unsigned char *data;
|
||||
size_t data_len;
|
||||
|
||||
/* Where to start reading data from,
|
||||
* used for channel data that's been partially consumed */
|
||||
unsigned long data_head;
|
||||
|
||||
/* Can the message be confirmed? */
|
||||
int mac;
|
||||
size_t data_head;
|
||||
};
|
||||
|
||||
typedef struct _libssh2_channel_data
|
||||
@@ -331,7 +313,7 @@ typedef struct _libssh2_channel_data
|
||||
uint32_t id;
|
||||
|
||||
/* Limits and restrictions */
|
||||
unsigned long window_size_initial, window_size, packet_size;
|
||||
uint32_t window_size_initial, window_size, packet_size;
|
||||
|
||||
/* Set to 1 when CHANNEL_CLOSE / CHANNEL_EOF sent/received */
|
||||
char close, eof, extended_data_ignore_mode;
|
||||
@@ -347,9 +329,12 @@ struct _LIBSSH2_CHANNEL
|
||||
/* channel's program exit status */
|
||||
int exit_status;
|
||||
|
||||
/* channel's program exit signal (without the SIG prefix) */
|
||||
char *exit_signal;
|
||||
|
||||
libssh2_channel_data local, remote;
|
||||
/* Amount of bytes to be refunded to receive window (but not yet sent) */
|
||||
unsigned long adjust_queue;
|
||||
uint32_t adjust_queue;
|
||||
|
||||
LIBSSH2_SESSION *session;
|
||||
|
||||
@@ -363,9 +348,10 @@ struct _LIBSSH2_CHANNEL
|
||||
unsigned char setenv_local_channel[4];
|
||||
packet_requirev_state_t setenv_packet_requirev_state;
|
||||
|
||||
/* State variables used in libssh2_channel_request_pty_ex() */
|
||||
/* State variables used in libssh2_channel_request_pty_ex()
|
||||
libssh2_channel_request_pty_size_ex() */
|
||||
libssh2_nonblocking_states reqPTY_state;
|
||||
unsigned char *reqPTY_packet;
|
||||
unsigned char reqPTY_packet[41 + 256];
|
||||
size_t reqPTY_packet_len;
|
||||
unsigned char reqPTY_local_channel[4];
|
||||
packet_requirev_state_t reqPTY_packet_requirev_state;
|
||||
@@ -400,10 +386,8 @@ struct _LIBSSH2_CHANNEL
|
||||
|
||||
/* State variables used in libssh2_channel_write_ex() */
|
||||
libssh2_nonblocking_states write_state;
|
||||
unsigned char *write_packet;
|
||||
unsigned char *write_s;
|
||||
unsigned char write_packet[13];
|
||||
size_t write_packet_len;
|
||||
size_t write_bufwrote;
|
||||
size_t write_bufwrite;
|
||||
|
||||
/* State variables used in libssh2_channel_close() */
|
||||
@@ -421,6 +405,7 @@ struct _LIBSSH2_CHANNEL
|
||||
|
||||
/* State variables used in libssh2_channel_handle_extended_data2() */
|
||||
libssh2_nonblocking_states extData2_state;
|
||||
|
||||
};
|
||||
|
||||
struct _LIBSSH2_LISTENER
|
||||
@@ -454,8 +439,8 @@ typedef struct _libssh2_endpoint_data
|
||||
const LIBSSH2_CRYPT_METHOD *crypt;
|
||||
void *crypt_abstract;
|
||||
|
||||
const LIBSSH2_MAC_METHOD *mac;
|
||||
unsigned long seqno;
|
||||
const struct _LIBSSH2_MAC_METHOD *mac;
|
||||
uint32_t seqno;
|
||||
void *mac_abstract;
|
||||
|
||||
const LIBSSH2_COMP_METHOD *comp;
|
||||
@@ -476,17 +461,17 @@ struct transportpacket
|
||||
unsigned char buf[PACKETBUFSIZE];
|
||||
unsigned char init[5]; /* first 5 bytes of the incoming data stream,
|
||||
still encrypted */
|
||||
int writeidx; /* at what array index we do the next write into
|
||||
size_t writeidx; /* at what array index we do the next write into
|
||||
the buffer */
|
||||
int readidx; /* at what array index we do the next read from
|
||||
size_t readidx; /* at what array index we do the next read from
|
||||
the buffer */
|
||||
uint32_t packet_length; /* the most recent packet_length as read from the
|
||||
network data */
|
||||
uint8_t padding_length; /* the most recent padding_length as read from the
|
||||
network data */
|
||||
int data_num; /* How much of the total package that has been read
|
||||
size_t data_num; /* How much of the total package that has been read
|
||||
so far. */
|
||||
int total_num; /* How much a total package is supposed to be, in
|
||||
size_t total_num; /* How much a total package is supposed to be, in
|
||||
number of bytes. A full package is
|
||||
packet_length + padding_length + 4 +
|
||||
mac_length. */
|
||||
@@ -496,11 +481,10 @@ struct transportpacket
|
||||
are currently writing decrypted data */
|
||||
|
||||
/* ------------- for outgoing data --------------- */
|
||||
unsigned char *outbuf; /* pointer to a LIBSSH2_ALLOC() area for the
|
||||
outgoing data */
|
||||
unsigned char outbuf[MAX_SSH_PACKET_LEN]; /* area for the outgoing data */
|
||||
|
||||
int ototal_num; /* size of outbuf in number of bytes */
|
||||
unsigned char *odata; /* original pointer to the data we stored in
|
||||
outbuf */
|
||||
const unsigned char *odata; /* original pointer to the data */
|
||||
size_t olen; /* original size of the data we stored in
|
||||
outbuf */
|
||||
size_t osent; /* number of bytes already sent */
|
||||
@@ -509,7 +493,7 @@ struct transportpacket
|
||||
struct _LIBSSH2_PUBLICKEY
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
unsigned long version;
|
||||
uint32_t version;
|
||||
|
||||
/* State variables used in libssh2_publickey_packet_receive() */
|
||||
libssh2_nonblocking_states receive_state;
|
||||
@@ -534,137 +518,13 @@ struct _LIBSSH2_PUBLICKEY
|
||||
size_t listFetch_data_len;
|
||||
};
|
||||
|
||||
#define SFTP_HANDLE_MAXLEN 256 /* according to spec! */
|
||||
|
||||
struct _LIBSSH2_SFTP_HANDLE
|
||||
{
|
||||
struct list_node node;
|
||||
|
||||
LIBSSH2_SFTP *sftp;
|
||||
|
||||
/* This is a pre-allocated buffer used for sending SFTP requests as the
|
||||
whole thing might not get sent in one go. This buffer is used for read,
|
||||
write, close and MUST thus be big enough to suit all these. */
|
||||
unsigned char request_packet[SFTP_HANDLE_MAXLEN + 25];
|
||||
|
||||
char handle[SFTP_HANDLE_MAXLEN];
|
||||
size_t handle_len;
|
||||
|
||||
char handle_type;
|
||||
|
||||
union _libssh2_sftp_handle_data
|
||||
{
|
||||
struct _libssh2_sftp_handle_file_data
|
||||
{
|
||||
libssh2_uint64_t offset;
|
||||
} file;
|
||||
struct _libssh2_sftp_handle_dir_data
|
||||
{
|
||||
unsigned long names_left;
|
||||
void *names_packet;
|
||||
char *next_name;
|
||||
} dir;
|
||||
} u;
|
||||
|
||||
/* State variables used in libssh2_sftp_close_handle() */
|
||||
libssh2_nonblocking_states close_state;
|
||||
unsigned long close_request_id;
|
||||
unsigned char *close_packet;
|
||||
};
|
||||
|
||||
struct _LIBSSH2_SFTP
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
|
||||
unsigned long request_id, version;
|
||||
|
||||
struct list_head packets;
|
||||
|
||||
/* a list of _LIBSSH2_SFTP_HANDLE structs */
|
||||
struct list_head sftp_handles;
|
||||
|
||||
uint32_t last_errno;
|
||||
|
||||
/* Holder for partial packet, use in libssh2_sftp_packet_read() */
|
||||
unsigned char *partial_packet; /* The data */
|
||||
size_t partial_len; /* Desired number of bytes */
|
||||
size_t partial_received; /* Bytes received so far */
|
||||
|
||||
/* Time that libssh2_sftp_packet_requirev() started reading */
|
||||
time_t requirev_start;
|
||||
|
||||
/* State variables used in libssh2_sftp_open_ex() */
|
||||
libssh2_nonblocking_states open_state;
|
||||
unsigned char *open_packet;
|
||||
size_t open_packet_len;
|
||||
size_t open_packet_sent;
|
||||
uint32_t open_request_id;
|
||||
|
||||
/* State variables used in libssh2_sftp_read() */
|
||||
libssh2_nonblocking_states read_state;
|
||||
unsigned char *read_packet;
|
||||
uint32_t read_request_id;
|
||||
size_t read_total_read;
|
||||
|
||||
/* State variables used in libssh2_sftp_readdir() */
|
||||
libssh2_nonblocking_states readdir_state;
|
||||
unsigned char *readdir_packet;
|
||||
uint32_t readdir_request_id;
|
||||
|
||||
/* State variables used in libssh2_sftp_write() */
|
||||
libssh2_nonblocking_states write_state;
|
||||
unsigned char *write_packet;
|
||||
uint32_t write_request_id;
|
||||
|
||||
/* State variables used in libssh2_sftp_fstat_ex() */
|
||||
libssh2_nonblocking_states fstat_state;
|
||||
unsigned char *fstat_packet;
|
||||
uint32_t fstat_request_id;
|
||||
|
||||
/* State variables used in libssh2_sftp_unlink_ex() */
|
||||
libssh2_nonblocking_states unlink_state;
|
||||
unsigned char *unlink_packet;
|
||||
uint32_t unlink_request_id;
|
||||
|
||||
/* State variables used in libssh2_sftp_rename_ex() */
|
||||
libssh2_nonblocking_states rename_state;
|
||||
unsigned char *rename_packet;
|
||||
unsigned char *rename_s;
|
||||
uint32_t rename_request_id;
|
||||
|
||||
/* State variables used in libssh2_sftp_fstatvfs() */
|
||||
libssh2_nonblocking_states fstatvfs_state;
|
||||
unsigned char *fstatvfs_packet;
|
||||
uint32_t fstatvfs_request_id;
|
||||
|
||||
/* State variables used in libssh2_sftp_statvfs() */
|
||||
libssh2_nonblocking_states statvfs_state;
|
||||
unsigned char *statvfs_packet;
|
||||
uint32_t statvfs_request_id;
|
||||
|
||||
/* State variables used in libssh2_sftp_mkdir() */
|
||||
libssh2_nonblocking_states mkdir_state;
|
||||
unsigned char *mkdir_packet;
|
||||
uint32_t mkdir_request_id;
|
||||
|
||||
/* State variables used in libssh2_sftp_rmdir() */
|
||||
libssh2_nonblocking_states rmdir_state;
|
||||
unsigned char *rmdir_packet;
|
||||
uint32_t rmdir_request_id;
|
||||
|
||||
/* State variables used in libssh2_sftp_stat() */
|
||||
libssh2_nonblocking_states stat_state;
|
||||
unsigned char *stat_packet;
|
||||
uint32_t stat_request_id;
|
||||
|
||||
/* State variables used in libssh2_sftp_symlink() */
|
||||
libssh2_nonblocking_states symlink_state;
|
||||
unsigned char *symlink_packet;
|
||||
uint32_t symlink_request_id;
|
||||
};
|
||||
|
||||
#define LIBSSH2_SCP_RESPONSE_BUFLEN 256
|
||||
|
||||
struct flags {
|
||||
int sigpipe; /* LIBSSH2_FLAG_SIGPIPE */
|
||||
int compress; /* LIBSSH2_FLAG_COMPRESS */
|
||||
};
|
||||
|
||||
struct _LIBSSH2_SESSION
|
||||
{
|
||||
/* Memory management callbacks */
|
||||
@@ -685,14 +545,16 @@ struct _LIBSSH2_SESSION
|
||||
char *hostkey_prefs;
|
||||
|
||||
int state;
|
||||
int flags;
|
||||
|
||||
/* Flag options */
|
||||
struct flags flag;
|
||||
|
||||
/* Agreed Key Exchange Method */
|
||||
const LIBSSH2_KEX_METHOD *kex;
|
||||
int burn_optimistic_kexinit:1;
|
||||
|
||||
unsigned char *session_id;
|
||||
unsigned long session_id_len;
|
||||
uint32_t session_id_len;
|
||||
|
||||
/* this is set to TRUE if a blocking API behavior is requested */
|
||||
int api_block_mode;
|
||||
@@ -705,7 +567,7 @@ struct _LIBSSH2_SESSION
|
||||
* Or read from server in (eg) KEXDH_INIT (for client mode)
|
||||
*/
|
||||
unsigned char *server_hostkey;
|
||||
unsigned long server_hostkey_len;
|
||||
uint32_t server_hostkey_len;
|
||||
#if LIBSSH2_MD5
|
||||
unsigned char server_hostkey_md5[MD5_DIGEST_LENGTH];
|
||||
#endif /* ! LIBSSH2_MD5 */
|
||||
@@ -724,7 +586,7 @@ struct _LIBSSH2_SESSION
|
||||
/* Active connection channels */
|
||||
struct list_head channels;
|
||||
|
||||
unsigned long next_channel;
|
||||
uint32_t next_channel;
|
||||
|
||||
struct list_head listeners; /* list of LIBSSH2_LISTENER structs */
|
||||
|
||||
@@ -771,7 +633,7 @@ struct _LIBSSH2_SESSION
|
||||
|
||||
/* State variables used in libssh2_session_disconnect_ex() */
|
||||
libssh2_nonblocking_states disconnect_state;
|
||||
unsigned char *disconnect_data;
|
||||
unsigned char disconnect_data[256 + 13];
|
||||
size_t disconnect_data_len;
|
||||
|
||||
/* State variables used in libssh2_packet_read() */
|
||||
@@ -852,8 +714,8 @@ struct _LIBSSH2_SESSION
|
||||
/* State variables used in libssh2_channel_forward_listen_ex() */
|
||||
libssh2_nonblocking_states fwdLstn_state;
|
||||
unsigned char *fwdLstn_packet;
|
||||
unsigned long fwdLstn_host_len;
|
||||
unsigned long fwdLstn_packet_len;
|
||||
uint32_t fwdLstn_host_len;
|
||||
uint32_t fwdLstn_packet_len;
|
||||
packet_requirev_state_t fwdLstn_packet_requirev_state;
|
||||
|
||||
/* State variables used in libssh2_publickey_init() */
|
||||
@@ -868,16 +730,15 @@ struct _LIBSSH2_SESSION
|
||||
|
||||
/* State variables used in libssh2_packet_add() */
|
||||
libssh2_nonblocking_states packAdd_state;
|
||||
LIBSSH2_CHANNEL *packAdd_channel;
|
||||
unsigned long packAdd_data_head;
|
||||
key_exchange_state_t packAdd_key_state;
|
||||
LIBSSH2_CHANNEL *packAdd_channelp; /* keeper of the channel during EAGAIN
|
||||
states */
|
||||
packet_queue_listener_state_t packAdd_Qlstn_state;
|
||||
packet_x11_open_state_t packAdd_x11open_state;
|
||||
|
||||
/* State variables used in fullpacket() */
|
||||
libssh2_nonblocking_states fullpacket_state;
|
||||
int fullpacket_macstate;
|
||||
int fullpacket_payload_len;
|
||||
size_t fullpacket_payload_len;
|
||||
int fullpacket_packet_type;
|
||||
|
||||
/* State variables used in libssh2_sftp_init() */
|
||||
@@ -892,9 +753,9 @@ struct _LIBSSH2_SESSION
|
||||
/* State variables used in libssh2_scp_recv() */
|
||||
libssh2_nonblocking_states scpRecv_state;
|
||||
unsigned char *scpRecv_command;
|
||||
unsigned long scpRecv_command_len;
|
||||
size_t scpRecv_command_len;
|
||||
unsigned char scpRecv_response[LIBSSH2_SCP_RESPONSE_BUFLEN];
|
||||
unsigned long scpRecv_response_len;
|
||||
size_t scpRecv_response_len;
|
||||
long scpRecv_mode;
|
||||
#if defined(HAVE_LONGLONG) && defined(HAVE_STRTOLL)
|
||||
/* we have the type and we can parse such numbers */
|
||||
@@ -906,18 +767,14 @@ struct _LIBSSH2_SESSION
|
||||
#endif
|
||||
long scpRecv_mtime;
|
||||
long scpRecv_atime;
|
||||
char *scpRecv_err_msg;
|
||||
long scpRecv_err_len;
|
||||
LIBSSH2_CHANNEL *scpRecv_channel;
|
||||
|
||||
/* State variables used in libssh2_scp_send_ex() */
|
||||
libssh2_nonblocking_states scpSend_state;
|
||||
unsigned char *scpSend_command;
|
||||
unsigned long scpSend_command_len;
|
||||
size_t scpSend_command_len;
|
||||
unsigned char scpSend_response[LIBSSH2_SCP_RESPONSE_BUFLEN];
|
||||
unsigned long scpSend_response_len;
|
||||
char *scpSend_err_msg;
|
||||
long scpSend_err_len;
|
||||
size_t scpSend_response_len;
|
||||
LIBSSH2_CHANNEL *scpSend_channel;
|
||||
|
||||
/* Keepalive variables used by keepalive.c. */
|
||||
@@ -934,8 +791,8 @@ struct _LIBSSH2_SESSION
|
||||
|
||||
/* 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)
|
||||
#define LIBSSH2_SOCKET_SEND_FLAGS(session) (((session)->flag.sigpipe) ? 0 : MSG_NOSIGNAL)
|
||||
#define LIBSSH2_SOCKET_RECV_FLAGS(session) (((session)->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
|
||||
@@ -1005,33 +862,22 @@ struct _LIBSSH2_CRYPT_METHOD
|
||||
struct _LIBSSH2_COMP_METHOD
|
||||
{
|
||||
const char *name;
|
||||
|
||||
int (*init) (LIBSSH2_SESSION * session, int compress, void **abstract);
|
||||
int (*comp) (LIBSSH2_SESSION * session, int compress, unsigned char **dest,
|
||||
size_t *dest_len, size_t payload_limit,
|
||||
int *free_dest, const unsigned char *src,
|
||||
size_t src_len, void **abstract);
|
||||
int (*dtor) (LIBSSH2_SESSION * session, int compress, void **abstract);
|
||||
};
|
||||
|
||||
struct _LIBSSH2_MAC_METHOD
|
||||
{
|
||||
const char *name;
|
||||
|
||||
/* 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,
|
||||
int compress; /* 1 if it does compress, 0 if it doesn't */
|
||||
int (*init) (LIBSSH2_SESSION *session, int compress, void **abstract);
|
||||
int (*comp) (LIBSSH2_SESSION *session,
|
||||
unsigned char *dest,
|
||||
size_t *dest_len,
|
||||
const unsigned char *src,
|
||||
size_t src_len,
|
||||
void **abstract);
|
||||
int (*hash) (LIBSSH2_SESSION * session, unsigned char *buf,
|
||||
unsigned long seqno, const unsigned char *packet,
|
||||
unsigned long packet_len, const unsigned char *addtl,
|
||||
unsigned long addtl_len, void **abstract);
|
||||
int (*dtor) (LIBSSH2_SESSION * session, void **abstract);
|
||||
int (*decomp) (LIBSSH2_SESSION *session,
|
||||
unsigned char **dest,
|
||||
size_t *dest_len,
|
||||
size_t payload_limit,
|
||||
const unsigned char *src,
|
||||
size_t src_len,
|
||||
void **abstract);
|
||||
int (*dtor) (LIBSSH2_SESSION * session, int compress, void **abstract);
|
||||
};
|
||||
|
||||
#ifdef LIBSSH2DEBUG
|
||||
@@ -1115,13 +961,17 @@ _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...)
|
||||
#define SSH_MSG_CHANNEL_SUCCESS 99
|
||||
#define SSH_MSG_CHANNEL_FAILURE 100
|
||||
|
||||
#if defined( WIN32 ) || defined( __VMS )
|
||||
ssize_t _libssh2_recv(libssh2_socket_t socket, void *buffer, size_t length, int flags);
|
||||
ssize_t _libssh2_send(libssh2_socket_t socket, const void *buffer, size_t length, int flags);
|
||||
#else
|
||||
#define _libssh2_recv(a,b,c,d) recv(a,b,c,d)
|
||||
#define _libssh2_send(a,b,c,d) send(a,b,c,d)
|
||||
#endif
|
||||
/* Error codes returned in SSH_MSG_CHANNEL_OPEN_FAILURE message
|
||||
(see RFC4254) */
|
||||
#define SSH_OPEN_ADMINISTRATIVELY_PROHIBITED 1
|
||||
#define SSH_OPEN_CONNECT_FAILED 2
|
||||
#define SSH_OPEN_UNKNOWN_CHANNELTYPE 3
|
||||
#define SSH_OPEN_RESOURCE_SHORTAGE 4
|
||||
|
||||
ssize_t _libssh2_recv(libssh2_socket_t socket, void *buffer,
|
||||
size_t length, int flags);
|
||||
ssize_t _libssh2_send(libssh2_socket_t socket, const void *buffer,
|
||||
size_t length, int flags);
|
||||
|
||||
#define LIBSSH2_READ_TIMEOUT 60 /* generic timeout in seconds used when
|
||||
waiting for more data to arrive */
|
||||
|
36
src/mac.c
36
src/mac.c
@@ -44,9 +44,9 @@
|
||||
*/
|
||||
static int
|
||||
mac_none_MAC(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)
|
||||
uint32_t seqno, const unsigned char *packet,
|
||||
uint32_t packet_len, const unsigned char *addtl,
|
||||
uint32_t addtl_len, void **abstract)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -101,11 +101,11 @@ mac_method_common_dtor(LIBSSH2_SESSION * session, void **abstract)
|
||||
*/
|
||||
static int
|
||||
mac_method_hmac_sha1_hash(LIBSSH2_SESSION * session,
|
||||
unsigned char *buf, unsigned long seqno,
|
||||
unsigned char *buf, uint32_t seqno,
|
||||
const unsigned char *packet,
|
||||
unsigned long packet_len,
|
||||
uint32_t packet_len,
|
||||
const unsigned char *addtl,
|
||||
unsigned long addtl_len, void **abstract)
|
||||
uint32_t addtl_len, void **abstract)
|
||||
{
|
||||
libssh2_hmac_ctx ctx;
|
||||
unsigned char seqno_buf[4];
|
||||
@@ -141,11 +141,11 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_sha1 = {
|
||||
*/
|
||||
static int
|
||||
mac_method_hmac_sha1_96_hash(LIBSSH2_SESSION * session,
|
||||
unsigned char *buf, unsigned long seqno,
|
||||
unsigned char *buf, uint32_t seqno,
|
||||
const unsigned char *packet,
|
||||
unsigned long packet_len,
|
||||
uint32_t packet_len,
|
||||
const unsigned char *addtl,
|
||||
unsigned long addtl_len, void **abstract)
|
||||
uint32_t addtl_len, void **abstract)
|
||||
{
|
||||
unsigned char temp[SHA_DIGEST_LENGTH];
|
||||
|
||||
@@ -173,11 +173,11 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_sha1_96 = {
|
||||
*/
|
||||
static int
|
||||
mac_method_hmac_md5_hash(LIBSSH2_SESSION * session, unsigned char *buf,
|
||||
unsigned long seqno,
|
||||
uint32_t seqno,
|
||||
const unsigned char *packet,
|
||||
unsigned long packet_len,
|
||||
uint32_t packet_len,
|
||||
const unsigned char *addtl,
|
||||
unsigned long addtl_len, void **abstract)
|
||||
uint32_t addtl_len, void **abstract)
|
||||
{
|
||||
libssh2_hmac_ctx ctx;
|
||||
unsigned char seqno_buf[4];
|
||||
@@ -213,11 +213,11 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_md5 = {
|
||||
*/
|
||||
static int
|
||||
mac_method_hmac_md5_96_hash(LIBSSH2_SESSION * session,
|
||||
unsigned char *buf, unsigned long seqno,
|
||||
unsigned char *buf, uint32_t seqno,
|
||||
const unsigned char *packet,
|
||||
unsigned long packet_len,
|
||||
uint32_t packet_len,
|
||||
const unsigned char *addtl,
|
||||
unsigned long addtl_len, void **abstract)
|
||||
uint32_t addtl_len, void **abstract)
|
||||
{
|
||||
unsigned char temp[MD5_DIGEST_LENGTH];
|
||||
mac_method_hmac_md5_hash(session, temp, seqno, packet, packet_len,
|
||||
@@ -244,11 +244,11 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_md5_96 = {
|
||||
*/
|
||||
static int
|
||||
mac_method_hmac_ripemd160_hash(LIBSSH2_SESSION * session,
|
||||
unsigned char *buf, unsigned long seqno,
|
||||
unsigned char *buf, uint32_t seqno,
|
||||
const unsigned char *packet,
|
||||
unsigned long packet_len,
|
||||
uint32_t packet_len,
|
||||
const unsigned char *addtl,
|
||||
unsigned long addtl_len,
|
||||
uint32_t addtl_len,
|
||||
void **abstract)
|
||||
{
|
||||
libssh2_hmac_ctx ctx;
|
||||
|
24
src/mac.h
24
src/mac.h
@@ -1,7 +1,7 @@
|
||||
#ifndef __LIBSSH2_MAC_H
|
||||
#define __LIBSSH2_MAC_H
|
||||
|
||||
/* Copyright (C) 2009 by Daniel Stenberg
|
||||
/* Copyright (C) 2009-2010 by Daniel Stenberg
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
@@ -40,6 +40,28 @@
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
|
||||
struct _LIBSSH2_MAC_METHOD
|
||||
{
|
||||
const char *name;
|
||||
|
||||
/* 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,
|
||||
uint32_t seqno, const unsigned char *packet,
|
||||
uint32_t packet_len, const unsigned char *addtl,
|
||||
uint32_t addtl_len, void **abstract);
|
||||
int (*dtor) (LIBSSH2_SESSION * session, void **abstract);
|
||||
};
|
||||
|
||||
typedef struct _LIBSSH2_MAC_METHOD LIBSSH2_MAC_METHOD;
|
||||
|
||||
const LIBSSH2_MAC_METHOD **_libssh2_mac_methods(void);
|
||||
|
||||
#endif /* __LIBSSH2_MAC_H */
|
||||
|
66
src/misc.c
66
src/misc.c
@@ -1,5 +1,6 @@
|
||||
/* Copyright (c) 2004-2007 Sara Golemon <sarag@libssh2.org>
|
||||
* Copyright (c) 2009 by Daniel Stenberg
|
||||
* Copyright (c) 2009-2010 by Daniel Stenberg
|
||||
* Copyright (c) 2010 Simon Josefsson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -55,6 +56,10 @@ int _libssh2_error(LIBSSH2_SESSION* session, int errcode, const char* errmsg)
|
||||
session->err_msg = errmsg;
|
||||
session->err_code = errcode;
|
||||
#ifdef LIBSSH2DEBUG
|
||||
if((errcode == LIBSSH2_ERROR_EAGAIN) && !session->api_block_mode)
|
||||
/* if this is EAGAIN and we're in non-blocking mode, don't generate
|
||||
a debug output for this */
|
||||
return errcode;
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_ERROR, "%d - %s", session->err_code,
|
||||
session->err_msg);
|
||||
#endif
|
||||
@@ -84,53 +89,56 @@ static int wsa2errno(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef _libssh2_recv
|
||||
/* _libssh2_recv
|
||||
*
|
||||
* Wrapper around standard recv to allow WIN32 systems
|
||||
* to set errno
|
||||
* Replacement for the standard recv, return -errno on failure.
|
||||
*/
|
||||
ssize_t
|
||||
_libssh2_recv(libssh2_socket_t socket, void *buffer, size_t length, int flags)
|
||||
_libssh2_recv(libssh2_socket_t sock, void *buffer, size_t length, int flags)
|
||||
{
|
||||
ssize_t rc = recv(socket, buffer, length, flags);
|
||||
ssize_t rc = recv(sock, buffer, length, flags);
|
||||
#ifdef WIN32
|
||||
if (rc < 0 )
|
||||
errno = wsa2errno();
|
||||
#endif
|
||||
#ifdef __VMS
|
||||
return -wsa2errno();
|
||||
#elif defined(__VMS)
|
||||
if (rc < 0 ){
|
||||
if ( errno == EWOULDBLOCK ) errno = EAGAIN;
|
||||
if ( errno == EWOULDBLOCK )
|
||||
return -EAGAIN;
|
||||
else
|
||||
return -errno;
|
||||
}
|
||||
#else
|
||||
if (rc < 0 )
|
||||
return -errno;
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
#endif /* _libssh2_recv */
|
||||
|
||||
#ifndef _libssh2_send
|
||||
|
||||
/* _libssh2_send
|
||||
*
|
||||
* Wrapper around standard send to allow WIN32 systems
|
||||
* to set errno
|
||||
* Replacement for the standard send, return -errno on failure.
|
||||
*/
|
||||
ssize_t
|
||||
_libssh2_send(libssh2_socket_t socket, const void *buffer, size_t length,
|
||||
_libssh2_send(libssh2_socket_t sock, const void *buffer, size_t length,
|
||||
int flags)
|
||||
{
|
||||
ssize_t rc = send(socket, buffer, length, flags);
|
||||
ssize_t rc = send(sock, buffer, length, flags);
|
||||
#ifdef WIN32
|
||||
if (rc < 0 )
|
||||
errno = wsa2errno();
|
||||
#endif
|
||||
#ifdef VMS
|
||||
if (rc < 0 ){
|
||||
if ( errno == EWOULDBLOCK ) errno = EAGAIN;
|
||||
return -wsa2errno();
|
||||
#elif defined(__VMS)
|
||||
if (rc < 0 ) {
|
||||
if ( errno == EWOULDBLOCK )
|
||||
return -EAGAIN;
|
||||
else
|
||||
return -errno;
|
||||
}
|
||||
#else
|
||||
if (rc < 0 )
|
||||
return -errno;
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
#endif /* _libssh2_recv */
|
||||
|
||||
/* libssh2_ntohu32
|
||||
*/
|
||||
@@ -148,8 +156,10 @@ _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];
|
||||
msl = ((libssh2_uint64_t)buf[0] << 24) | ((libssh2_uint64_t)buf[1] << 16)
|
||||
| ((libssh2_uint64_t)buf[2] << 8) | (libssh2_uint64_t)buf[3];
|
||||
lsl = ((libssh2_uint64_t)buf[4] << 24) | ((libssh2_uint64_t)buf[5] << 16)
|
||||
| ((libssh2_uint64_t)buf[6] << 8) | (libssh2_uint64_t)buf[7];
|
||||
|
||||
return ((libssh2_uint64_t)msl <<32) | lsl;
|
||||
}
|
||||
@@ -348,6 +358,12 @@ size_t _libssh2_base64_encode(LIBSSH2_SESSION *session,
|
||||
}
|
||||
/* ---- End of Base64 Encoding ---- */
|
||||
|
||||
LIBSSH2_API void
|
||||
libssh2_free(LIBSSH2_SESSION *session, void *ptr)
|
||||
{
|
||||
LIBSSH2_FREE(session, ptr);
|
||||
}
|
||||
|
||||
#ifdef LIBSSH2DEBUG
|
||||
LIBSSH2_API int
|
||||
libssh2_trace(LIBSSH2_SESSION * session, int bitmask)
|
||||
|
313
src/openssl.c
313
src/openssl.c
@@ -215,31 +215,31 @@ typedef struct
|
||||
|
||||
static int
|
||||
aes_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc) /* init key */
|
||||
const unsigned char *iv, int enc) /* init key */
|
||||
{
|
||||
aes_ctr_ctx *c = malloc(sizeof(*c));
|
||||
const EVP_CIPHER *aes_cipher;
|
||||
(void) enc;
|
||||
|
||||
if (c == NULL)
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
switch (ctx->key_len) {
|
||||
case 16:
|
||||
aes_cipher = EVP_aes_128_ecb();
|
||||
break;
|
||||
case 24:
|
||||
aes_cipher = EVP_aes_192_ecb();
|
||||
break;
|
||||
case 32:
|
||||
aes_cipher = EVP_aes_256_ecb();
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
case 16:
|
||||
aes_cipher = EVP_aes_128_ecb();
|
||||
break;
|
||||
case 24:
|
||||
aes_cipher = EVP_aes_192_ecb();
|
||||
break;
|
||||
case 32:
|
||||
aes_cipher = EVP_aes_256_ecb();
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
c->aes_ctx = malloc(sizeof(EVP_CIPHER_CTX));
|
||||
if (c->aes_ctx == NULL)
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
if (EVP_EncryptInit(c->aes_ctx, aes_cipher, key, NULL) != 1) {
|
||||
return 0;
|
||||
@@ -256,8 +256,8 @@ aes_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
|
||||
|
||||
static int
|
||||
aes_ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
const unsigned char *in,
|
||||
unsigned int inl) /* encrypt/decrypt data */
|
||||
const unsigned char *in,
|
||||
unsigned int inl) /* encrypt/decrypt data */
|
||||
{
|
||||
aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx);
|
||||
unsigned char b1[AES_BLOCK_SIZE];
|
||||
@@ -265,7 +265,7 @@ aes_ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
int outlen = 0;
|
||||
|
||||
if (inl != 16) /* libssh2 only ever encrypt one block */
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
if (c == NULL) {
|
||||
return 0;
|
||||
@@ -283,13 +283,13 @@ aes_ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
*out++ = *in++ ^ b1[i];
|
||||
*out++ = *in++ ^ b1[i];
|
||||
|
||||
i = 15;
|
||||
while (c->ctr[i]++ == 0xFF) {
|
||||
if (i == 0)
|
||||
break;
|
||||
i--;
|
||||
if (i == 0)
|
||||
break;
|
||||
i--;
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -305,6 +305,7 @@ aes_ctr_cleanup(EVP_CIPHER_CTX *ctx) /* cleanup ctx */
|
||||
}
|
||||
|
||||
if (c->aes_ctx != NULL) {
|
||||
_libssh2_cipher_dtor(c->aes_ctx);
|
||||
free(c->aes_ctx);
|
||||
}
|
||||
|
||||
@@ -514,4 +515,274 @@ libssh2_md5(const unsigned char *message, unsigned long len,
|
||||
EVP_DigestFinal(&ctx, out, NULL);
|
||||
}
|
||||
|
||||
static unsigned char *
|
||||
write_bn(unsigned char *buf, const BIGNUM *bn, int bn_bytes)
|
||||
{
|
||||
unsigned char *p = buf;
|
||||
|
||||
/* Left space for bn size which will be written below. */
|
||||
p += 4;
|
||||
|
||||
*p = 0;
|
||||
BN_bn2bin(bn, p + 1);
|
||||
if (!(*(p + 1) & 0x80)) {
|
||||
memmove(p, p + 1, --bn_bytes);
|
||||
}
|
||||
_libssh2_htonu32(p - 4, bn_bytes); /* Post write bn size. */
|
||||
|
||||
return p + bn_bytes;
|
||||
}
|
||||
|
||||
static unsigned char *
|
||||
gen_publickey_from_rsa(LIBSSH2_SESSION *session, RSA *rsa,
|
||||
size_t *key_len)
|
||||
{
|
||||
int e_bytes, n_bytes;
|
||||
unsigned long len;
|
||||
unsigned char* key;
|
||||
unsigned char* p;
|
||||
|
||||
e_bytes = BN_num_bytes(rsa->e) + 1;
|
||||
n_bytes = BN_num_bytes(rsa->n) + 1;
|
||||
|
||||
/* Key form is "ssh-rsa" + e + n. */
|
||||
len = 4 + 7 + 4 + e_bytes + 4 + n_bytes;
|
||||
|
||||
key = LIBSSH2_ALLOC(session, len);
|
||||
if (key == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Process key encoding. */
|
||||
p = key;
|
||||
|
||||
_libssh2_htonu32(p, 7); /* Key type. */
|
||||
p += 4;
|
||||
memcpy(p, "ssh-rsa", 7);
|
||||
p += 7;
|
||||
|
||||
p = write_bn(p, rsa->e, e_bytes);
|
||||
p = write_bn(p, rsa->n, n_bytes);
|
||||
|
||||
*key_len = (size_t)(p - key);
|
||||
return key;
|
||||
}
|
||||
|
||||
static unsigned char *
|
||||
gen_publickey_from_dsa(LIBSSH2_SESSION* session, DSA *dsa,
|
||||
size_t *key_len)
|
||||
{
|
||||
int p_bytes, q_bytes, g_bytes, k_bytes;
|
||||
unsigned long len;
|
||||
unsigned char* key;
|
||||
unsigned char* p;
|
||||
|
||||
p_bytes = BN_num_bytes(dsa->p) + 1;
|
||||
q_bytes = BN_num_bytes(dsa->q) + 1;
|
||||
g_bytes = BN_num_bytes(dsa->g) + 1;
|
||||
k_bytes = BN_num_bytes(dsa->pub_key) + 1;
|
||||
|
||||
/* Key form is "ssh-dss" + p + q + g + pub_key. */
|
||||
len = 4 + 7 + 4 + p_bytes + 4 + q_bytes + 4 + g_bytes + 4 + k_bytes;
|
||||
|
||||
key = LIBSSH2_ALLOC(session, len);
|
||||
if (key == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Process key encoding. */
|
||||
p = key;
|
||||
|
||||
_libssh2_htonu32(p, 7); /* Key type. */
|
||||
p += 4;
|
||||
memcpy(p, "ssh-dss", 7);
|
||||
p += 7;
|
||||
|
||||
p = write_bn(p, dsa->p, p_bytes);
|
||||
p = write_bn(p, dsa->q, q_bytes);
|
||||
p = write_bn(p, dsa->g, g_bytes);
|
||||
p = write_bn(p, dsa->pub_key, k_bytes);
|
||||
|
||||
*key_len = (size_t)(p - key);
|
||||
return key;
|
||||
}
|
||||
|
||||
static int
|
||||
gen_publickey_from_rsa_evp(LIBSSH2_SESSION *session,
|
||||
unsigned char **method,
|
||||
size_t *method_len,
|
||||
unsigned char **pubkeydata,
|
||||
size_t *pubkeydata_len,
|
||||
EVP_PKEY *pk)
|
||||
{
|
||||
RSA* rsa = NULL;
|
||||
unsigned char* key;
|
||||
unsigned char* method_buf = NULL;
|
||||
size_t key_len;
|
||||
|
||||
_libssh2_debug(session,
|
||||
LIBSSH2_TRACE_AUTH,
|
||||
"Computing public key from RSA private key envelop");
|
||||
|
||||
rsa = EVP_PKEY_get1_RSA(pk);
|
||||
if (rsa == NULL) {
|
||||
/* Assume memory allocation error... what else could it be ? */
|
||||
goto __alloc_error;
|
||||
}
|
||||
|
||||
method_buf = LIBSSH2_ALLOC(session, 7); /* ssh-rsa. */
|
||||
if (method_buf == NULL) {
|
||||
goto __alloc_error;
|
||||
}
|
||||
|
||||
key = gen_publickey_from_rsa(session, rsa, &key_len);
|
||||
if (key == NULL) {
|
||||
goto __alloc_error;
|
||||
}
|
||||
RSA_free(rsa);
|
||||
|
||||
memcpy(method_buf, "ssh-rsa", 7);
|
||||
*method = method_buf;
|
||||
*method_len = 7;
|
||||
*pubkeydata = key;
|
||||
*pubkeydata_len = key_len;
|
||||
return 0;
|
||||
|
||||
__alloc_error:
|
||||
if (rsa != NULL) {
|
||||
RSA_free(rsa);
|
||||
}
|
||||
if (method_buf != NULL) {
|
||||
LIBSSH2_FREE(session, method_buf);
|
||||
}
|
||||
|
||||
_libssh2_error(session,
|
||||
LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for private key data");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
gen_publickey_from_dsa_evp(LIBSSH2_SESSION *session,
|
||||
unsigned char **method,
|
||||
size_t *method_len,
|
||||
unsigned char **pubkeydata,
|
||||
size_t *pubkeydata_len,
|
||||
EVP_PKEY *pk)
|
||||
{
|
||||
DSA* dsa = NULL;
|
||||
unsigned char* key;
|
||||
unsigned char* method_buf = NULL;
|
||||
size_t key_len;
|
||||
|
||||
_libssh2_debug(session,
|
||||
LIBSSH2_TRACE_AUTH,
|
||||
"Computing public key from DSA private key envelop");
|
||||
|
||||
dsa = EVP_PKEY_get1_DSA(pk);
|
||||
if (dsa == NULL) {
|
||||
/* Assume memory allocation error... what else could it be ? */
|
||||
goto __alloc_error;
|
||||
}
|
||||
|
||||
method_buf = LIBSSH2_ALLOC(session, 7); /* ssh-dss. */
|
||||
if (method_buf == NULL) {
|
||||
goto __alloc_error;
|
||||
}
|
||||
|
||||
key = gen_publickey_from_dsa(session, dsa, &key_len);
|
||||
if (key == NULL) {
|
||||
goto __alloc_error;
|
||||
}
|
||||
DSA_free(dsa);
|
||||
|
||||
memcpy(method_buf, "ssh-dss", 7);
|
||||
*method = method_buf;
|
||||
*method_len = 7;
|
||||
*pubkeydata = key;
|
||||
*pubkeydata_len = key_len;
|
||||
return 0;
|
||||
|
||||
__alloc_error:
|
||||
if (dsa != NULL) {
|
||||
DSA_free(dsa);
|
||||
}
|
||||
if (method_buf != NULL) {
|
||||
LIBSSH2_FREE(session, method_buf);
|
||||
}
|
||||
|
||||
_libssh2_error(session,
|
||||
LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for private key data");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
_libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
|
||||
unsigned char **method,
|
||||
size_t *method_len,
|
||||
unsigned char **pubkeydata,
|
||||
size_t *pubkeydata_len,
|
||||
const char *privatekey,
|
||||
const char *passphrase)
|
||||
{
|
||||
int st;
|
||||
BIO* bp;
|
||||
EVP_PKEY* pk;
|
||||
|
||||
_libssh2_debug(session,
|
||||
LIBSSH2_TRACE_AUTH,
|
||||
"Computing public key from private key file: %s",
|
||||
privatekey);
|
||||
|
||||
bp = BIO_new_file(privatekey, "r");
|
||||
if (bp == NULL) {
|
||||
_libssh2_error(session,
|
||||
LIBSSH2_ERROR_FILE,
|
||||
"Unable to open private key file");
|
||||
return -1;
|
||||
}
|
||||
if (!EVP_get_cipherbyname("des")) {
|
||||
/* If this cipher isn't loaded it's a pretty good indication that none
|
||||
* are. I have *NO DOUBT* that there's a better way to deal with this
|
||||
* ($#&%#$(%$#( Someone buy me an OpenSSL manual and I'll read up on
|
||||
* it.
|
||||
*/
|
||||
OpenSSL_add_all_ciphers();
|
||||
}
|
||||
BIO_reset(bp);
|
||||
pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void*)passphrase);
|
||||
BIO_free(bp);
|
||||
|
||||
if (pk == NULL) {
|
||||
_libssh2_error(session,
|
||||
LIBSSH2_ERROR_FILE,
|
||||
"Wrong passphrase or invalid/unrecognized "
|
||||
"private key file format");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (pk->type) {
|
||||
case EVP_PKEY_RSA :
|
||||
st = gen_publickey_from_rsa_evp(
|
||||
session, method, method_len, pubkeydata, pubkeydata_len, pk);
|
||||
break;
|
||||
|
||||
case EVP_PKEY_DSA :
|
||||
st = gen_publickey_from_dsa_evp(
|
||||
session, method, method_len, pubkeydata, pubkeydata_len, pk);
|
||||
break;
|
||||
|
||||
default :
|
||||
st = -1;
|
||||
_libssh2_error(session,
|
||||
LIBSSH2_ERROR_FILE,
|
||||
"Unsupported private key file format");
|
||||
break;
|
||||
}
|
||||
|
||||
EVP_PKEY_free(pk);
|
||||
return st;
|
||||
}
|
||||
|
||||
#endif /* !LIBSSH2_LIBGCRYPT */
|
||||
|
@@ -135,61 +135,10 @@ void libssh2_md5(const unsigned char *message, unsigned long len, unsigned char
|
||||
|
||||
#define libssh2_rsa_ctx RSA
|
||||
|
||||
int _libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
|
||||
const unsigned char *edata,
|
||||
unsigned long elen,
|
||||
const unsigned char *ndata,
|
||||
unsigned long nlen,
|
||||
const unsigned char *ddata,
|
||||
unsigned long dlen,
|
||||
const unsigned char *pdata,
|
||||
unsigned long plen,
|
||||
const unsigned char *qdata,
|
||||
unsigned long qlen,
|
||||
const unsigned char *e1data,
|
||||
unsigned long e1len,
|
||||
const unsigned char *e2data,
|
||||
unsigned long e2len,
|
||||
const unsigned char *coeffdata, unsigned long coefflen);
|
||||
int _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
|
||||
LIBSSH2_SESSION * session,
|
||||
const char *filename,
|
||||
unsigned const char *passphrase);
|
||||
int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa,
|
||||
const unsigned char *sig,
|
||||
unsigned long sig_len,
|
||||
const unsigned char *m, unsigned long m_len);
|
||||
int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
|
||||
libssh2_rsa_ctx * rsactx,
|
||||
const unsigned char *hash,
|
||||
size_t hash_len,
|
||||
unsigned char **signature,
|
||||
size_t *signature_len);
|
||||
|
||||
#define _libssh2_rsa_free(rsactx) RSA_free(rsactx)
|
||||
|
||||
#define libssh2_dsa_ctx DSA
|
||||
|
||||
int _libssh2_dsa_new(libssh2_dsa_ctx ** dsa,
|
||||
const unsigned char *pdata,
|
||||
unsigned long plen,
|
||||
const unsigned char *qdata,
|
||||
unsigned long qlen,
|
||||
const unsigned char *gdata,
|
||||
unsigned long glen,
|
||||
const unsigned char *ydata,
|
||||
unsigned long ylen,
|
||||
const unsigned char *x, unsigned long x_len);
|
||||
int _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
|
||||
LIBSSH2_SESSION * session,
|
||||
const char *filename,
|
||||
unsigned const char *passphrase);
|
||||
int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,
|
||||
const unsigned char *sig,
|
||||
const unsigned char *m, unsigned long m_len);
|
||||
int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
|
||||
const unsigned char *hash,
|
||||
unsigned long hash_len, unsigned char *sig);
|
||||
|
||||
#define _libssh2_dsa_free(dsactx) DSA_free(dsactx)
|
||||
|
||||
@@ -213,15 +162,6 @@ int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
|
||||
#define _libssh2_cipher_cast5 EVP_cast5_cbc
|
||||
#define _libssh2_cipher_3des EVP_des_ede3_cbc
|
||||
|
||||
int _libssh2_cipher_init(_libssh2_cipher_ctx * h,
|
||||
_libssh2_cipher_type(algo),
|
||||
unsigned char *iv,
|
||||
unsigned char *secret, int encrypt);
|
||||
|
||||
int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
|
||||
_libssh2_cipher_type(algo),
|
||||
int encrypt, unsigned char *block);
|
||||
|
||||
#define _libssh2_cipher_dtor(ctx) EVP_CIPHER_CTX_cleanup(ctx)
|
||||
|
||||
#define _libssh2_bn BIGNUM
|
||||
@@ -241,3 +181,4 @@ int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
|
||||
const EVP_CIPHER *_libssh2_EVP_aes_128_ctr(void);
|
||||
const EVP_CIPHER *_libssh2_EVP_aes_192_ctr(void);
|
||||
const EVP_CIPHER *_libssh2_EVP_aes_256_ctr(void);
|
||||
|
||||
|
718
src/packet.c
718
src/packet.c
File diff suppressed because it is too large
Load Diff
@@ -378,7 +378,7 @@ static LIBSSH2_PUBLICKEY *publickey_init(LIBSSH2_SESSION *session)
|
||||
|
||||
if (session->pkeyInit_state == libssh2_NB_state_sent2) {
|
||||
rc = _libssh2_channel_write(session->pkeyInit_channel, 0,
|
||||
(char *)session->pkeyInit_buffer,
|
||||
session->pkeyInit_buffer,
|
||||
19 - session->pkeyInit_buffer_sent);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
@@ -644,7 +644,7 @@ libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name,
|
||||
}
|
||||
|
||||
if (pkey->add_state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_channel_write(channel, 0, (char *) pkey->add_packet,
|
||||
rc = _libssh2_channel_write(channel, 0, pkey->add_packet,
|
||||
(pkey->add_s - pkey->add_packet));
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
return rc;
|
||||
@@ -727,7 +727,7 @@ libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY * pkey,
|
||||
}
|
||||
|
||||
if (pkey->remove_state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_channel_write(channel, 0, (char *) pkey->remove_packet,
|
||||
rc = _libssh2_channel_write(channel, 0, pkey->remove_packet,
|
||||
(pkey->remove_s - pkey->remove_packet));
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
return rc;
|
||||
@@ -794,7 +794,7 @@ libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY * pkey, unsigned long *num_keys,
|
||||
|
||||
if (pkey->listFetch_state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_channel_write(channel, 0,
|
||||
(char *) pkey->listFetch_buffer,
|
||||
pkey->listFetch_buffer,
|
||||
(pkey->listFetch_s -
|
||||
pkey->listFetch_buffer));
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
|
215
src/scp.c
215
src/scp.c
@@ -360,7 +360,7 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
|
||||
if (session->scpRecv_state == libssh2_NB_state_sent1) {
|
||||
rc = _libssh2_channel_write(session->scpRecv_channel, 0,
|
||||
(char *) session->scpRecv_response, 1);
|
||||
session->scpRecv_response, 1);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block sending initial wakeup");
|
||||
@@ -390,56 +390,53 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
_libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block waiting for SCP response");
|
||||
return NULL;
|
||||
} else if (rc <= 0) {
|
||||
/* Timeout, give up */
|
||||
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
||||
"Timed out waiting for SCP response");
|
||||
}
|
||||
else if (rc < 0) {
|
||||
/* error, give up */
|
||||
_libssh2_error(session, rc, "Failed reading SCP response");
|
||||
goto scp_recv_error;
|
||||
}
|
||||
else if(rc == 0)
|
||||
goto scp_recv_empty_channel;
|
||||
|
||||
session->scpRecv_response_len++;
|
||||
|
||||
if (session->scpRecv_response[0] != 'T') {
|
||||
/*
|
||||
* Set this as the default error for here, if
|
||||
* we are successful it will be replaced
|
||||
*/
|
||||
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
||||
"Invalid data in SCP response, missing Time data");
|
||||
size_t err_len;
|
||||
char *err_msg;
|
||||
|
||||
session->scpRecv_err_len =
|
||||
/* there can be
|
||||
01 for warnings
|
||||
02 for errors
|
||||
|
||||
The following string MUST be newline terminated
|
||||
*/
|
||||
err_len =
|
||||
_libssh2_channel_packet_data_len(session->
|
||||
scpRecv_channel, 0);
|
||||
session->scpRecv_err_msg =
|
||||
LIBSSH2_ALLOC(session, session->scpRecv_err_len + 1);
|
||||
if (!session->scpRecv_err_msg) {
|
||||
err_msg = LIBSSH2_ALLOC(session, err_len + 1);
|
||||
if (!err_msg) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Failed to get memory ");
|
||||
goto scp_recv_error;
|
||||
}
|
||||
memset(session->scpRecv_err_msg, 0,
|
||||
session->scpRecv_err_len + 1);
|
||||
|
||||
/* Read the remote error message */
|
||||
rc = _libssh2_channel_read(session->scpRecv_channel, 0,
|
||||
session->scpRecv_err_msg,
|
||||
session->scpRecv_err_len);
|
||||
if (rc <= 0) {
|
||||
/*
|
||||
* Since we have alread started reading this packet,
|
||||
* it is already in the systems so it can't return
|
||||
* LIBSSH2_ERROR_EAGAIN
|
||||
*/
|
||||
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
||||
"Unknown error" );
|
||||
}
|
||||
else
|
||||
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
||||
"SCP protocol error");
|
||||
(void)_libssh2_channel_read(session->scpRecv_channel, 0,
|
||||
err_msg, err_len);
|
||||
/* If it failed for any reason, we ignore it anyway. */
|
||||
|
||||
/* TODO: for debugging purposes, the
|
||||
session->scpRecv_err_msg should be displayed here
|
||||
when available */
|
||||
/* zero terminate the error */
|
||||
err_msg[err_len]=0;
|
||||
|
||||
LIBSSH2_FREE(session, session->scpRecv_err_msg);
|
||||
session->scpRecv_err_msg = NULL;
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SCP,
|
||||
"got %02x %s", session->scpRecv_response[0],
|
||||
err_msg);
|
||||
|
||||
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
||||
"Failed to recv file");
|
||||
|
||||
LIBSSH2_FREE(session, err_msg);
|
||||
goto scp_recv_error;
|
||||
}
|
||||
|
||||
@@ -513,13 +510,8 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
|
||||
*(p++) = '\0';
|
||||
/* Make sure we don't get fooled by leftover values */
|
||||
errno = 0;
|
||||
session->scpRecv_mtime = strtol((char *) s, NULL, 10);
|
||||
if (errno) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
||||
"Invalid response from SCP server, invalid mtime");
|
||||
goto scp_recv_error;
|
||||
}
|
||||
|
||||
s = (unsigned char *) strchr((char *) p, ' ');
|
||||
if (!s || ((s - p) <= 0)) {
|
||||
/* No spaces or space in the wrong spot */
|
||||
@@ -540,13 +532,7 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
|
||||
*p = '\0';
|
||||
/* Make sure we don't get fooled by leftover values */
|
||||
errno = 0;
|
||||
session->scpRecv_atime = strtol((char *) s, NULL, 10);
|
||||
if (errno) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
||||
"Invalid response from SCP server, invalid atime");
|
||||
goto scp_recv_error;
|
||||
}
|
||||
|
||||
/* SCP ACK */
|
||||
session->scpRecv_response[0] = '\0';
|
||||
@@ -556,8 +542,7 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
|
||||
if (session->scpRecv_state == libssh2_NB_state_sent3) {
|
||||
rc = _libssh2_channel_write(session->scpRecv_channel, 0,
|
||||
(char *) session->
|
||||
scpRecv_response, 1);
|
||||
session->scpRecv_response, 1);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block waiting to send SCP ACK");
|
||||
@@ -599,12 +584,15 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
_libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block waiting for SCP response");
|
||||
return NULL;
|
||||
} else if (rc <= 0) {
|
||||
/* Timeout, give up */
|
||||
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
||||
"Timed out waiting for SCP response");
|
||||
}
|
||||
else if (rc < 0) {
|
||||
/* error, bail out*/
|
||||
_libssh2_error(session, rc, "Failed reading SCP response");
|
||||
goto scp_recv_error;
|
||||
}
|
||||
else if(rc == 0)
|
||||
goto scp_recv_empty_channel;
|
||||
|
||||
session->scpRecv_response_len++;
|
||||
|
||||
if (session->scpRecv_response[0] != 'C') {
|
||||
@@ -621,11 +609,9 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
scpRecv_response[session->scpRecv_response_len - 1] !=
|
||||
'\n')
|
||||
&&
|
||||
((session->
|
||||
scpRecv_response[session->scpRecv_response_len - 1] < 32)
|
||||
|| (session->
|
||||
scpRecv_response[session->scpRecv_response_len - 1] >
|
||||
126))) {
|
||||
(session->
|
||||
scpRecv_response[session->scpRecv_response_len - 1]
|
||||
< 32)) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
||||
"Invalid data in SCP response");
|
||||
goto scp_recv_error;
|
||||
@@ -679,9 +665,9 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
|
||||
*(p++) = '\0';
|
||||
/* Make sure we don't get fooled by leftover values */
|
||||
errno = 0;
|
||||
|
||||
session->scpRecv_mode = strtol(s, &e, 8);
|
||||
if ((e && *e) || errno) {
|
||||
if (e && *e) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
||||
"Invalid response from SCP server, invalid mode");
|
||||
goto scp_recv_error;
|
||||
@@ -697,9 +683,8 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
|
||||
*s = '\0';
|
||||
/* Make sure we don't get fooled by leftover values */
|
||||
errno = 0;
|
||||
session->scpRecv_size = scpsize_strtol(p, &e, 10);
|
||||
if ((e && *e) || errno) {
|
||||
if (e && *e) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
||||
"Invalid response from SCP server, invalid size");
|
||||
goto scp_recv_error;
|
||||
@@ -713,8 +698,7 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
|
||||
if (session->scpRecv_state == libssh2_NB_state_sent6) {
|
||||
rc = _libssh2_channel_write(session->scpRecv_channel, 0,
|
||||
(char *) session->
|
||||
scpRecv_response, 1);
|
||||
session->scpRecv_response, 1);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block sending SCP ACK");
|
||||
@@ -747,8 +731,18 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return session->scpRecv_channel;
|
||||
|
||||
scp_recv_empty_channel:
|
||||
/* the code only jumps here as a result of a zero read from channel_read()
|
||||
so we check EOF status to avoid getting stuck in a loop */
|
||||
if(libssh2_channel_eof(session->scpRecv_channel))
|
||||
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
||||
"Unexpected channel close");
|
||||
else
|
||||
return session->scpRecv_channel;
|
||||
/* fall-through */
|
||||
scp_recv_error:
|
||||
while (libssh2_channel_free(session->scpRecv_channel) == LIBSSH2_ERROR_EAGAIN);
|
||||
while (libssh2_channel_free(session->scpRecv_channel) ==
|
||||
LIBSSH2_ERROR_EAGAIN);
|
||||
session->scpRecv_channel = NULL;
|
||||
session->scpRecv_state = libssh2_NB_state_idle;
|
||||
return NULL;
|
||||
@@ -869,12 +863,19 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode,
|
||||
_libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block waiting for response from remote");
|
||||
return NULL;
|
||||
} else if ((rc <= 0) || (session->scpSend_response[0] != 0)) {
|
||||
}
|
||||
else if (rc < 0) {
|
||||
_libssh2_error(session, rc, "SCP failure");
|
||||
goto scp_send_error;
|
||||
}
|
||||
else if(!rc)
|
||||
/* remain in the same state */
|
||||
goto scp_send_empty_channel;
|
||||
else if (session->scpSend_response[0] != 0) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
||||
"Invalid ACK response from remote");
|
||||
goto scp_send_error;
|
||||
}
|
||||
|
||||
if (mtime || atime) {
|
||||
/* Send mtime and atime to be used for file */
|
||||
session->scpSend_response_len =
|
||||
@@ -892,7 +893,7 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode,
|
||||
if (mtime || atime) {
|
||||
if (session->scpSend_state == libssh2_NB_state_sent2) {
|
||||
rc = _libssh2_channel_write(session->scpSend_channel, 0,
|
||||
(char *) session->scpSend_response,
|
||||
session->scpSend_response,
|
||||
session->scpSend_response_len);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
@@ -915,9 +916,17 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode,
|
||||
_libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block waiting for response");
|
||||
return NULL;
|
||||
} else if ((rc <= 0) || (session->scpSend_response[0] != 0)) {
|
||||
}
|
||||
else if (rc < 0) {
|
||||
_libssh2_error(session, rc, "SCP failure");
|
||||
goto scp_send_error;
|
||||
}
|
||||
else if(!rc)
|
||||
/* remain in the same state */
|
||||
goto scp_send_empty_channel;
|
||||
else if (session->scpSend_response[0] != 0) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
||||
"Invalid ACK response from remote");
|
||||
"Invalid SCP ACK response");
|
||||
goto scp_send_error;
|
||||
}
|
||||
|
||||
@@ -950,7 +959,7 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode,
|
||||
|
||||
if (session->scpSend_state == libssh2_NB_state_sent5) {
|
||||
rc = _libssh2_channel_write(session->scpSend_channel, 0,
|
||||
(char *) session->scpSend_response,
|
||||
session->scpSend_response,
|
||||
session->scpSend_response_len);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
@@ -973,51 +982,57 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode,
|
||||
_libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block waiting for response");
|
||||
return NULL;
|
||||
} else if (rc <= 0) {
|
||||
}
|
||||
else if (rc < 0) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
||||
"Invalid ACK response from remote");
|
||||
goto scp_send_error;
|
||||
} else if (session->scpSend_response[0] != 0) {
|
||||
/*
|
||||
* Set this as the default error for here, if
|
||||
* we are successful it will be replaced
|
||||
*/
|
||||
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
||||
"Invalid ACK response from remote");
|
||||
}
|
||||
else if (rc == 0)
|
||||
goto scp_send_empty_channel;
|
||||
|
||||
session->scpSend_err_len =
|
||||
else if (session->scpSend_response[0] != 0) {
|
||||
size_t err_len;
|
||||
char *err_msg;
|
||||
|
||||
err_len =
|
||||
_libssh2_channel_packet_data_len(session->scpSend_channel, 0);
|
||||
session->scpSend_err_msg =
|
||||
LIBSSH2_ALLOC(session, session->scpSend_err_len + 1);
|
||||
if (!session->scpSend_err_msg) {
|
||||
err_msg = LIBSSH2_ALLOC(session, err_len + 1);
|
||||
if (!err_msg) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"failed to get memory");
|
||||
goto scp_send_error;
|
||||
}
|
||||
memset(session->scpSend_err_msg, 0, session->scpSend_err_len + 1);
|
||||
|
||||
/* Read the remote error message */
|
||||
rc = _libssh2_channel_read(session->scpSend_channel, 0,
|
||||
session->scpSend_err_msg,
|
||||
session->scpSend_err_len);
|
||||
if (rc <= 0) {
|
||||
/*
|
||||
* Since we have alread started reading this packet, it is
|
||||
* already in the systems so it can't return
|
||||
* LIBSSH2_ERROR_EAGAIN
|
||||
*/
|
||||
LIBSSH2_FREE(session, session->scpSend_err_msg);
|
||||
session->scpSend_err_msg = NULL;
|
||||
err_msg, err_len);
|
||||
if (rc > 0) {
|
||||
err_msg[err_len]=0;
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SCP,
|
||||
"got %02x %s", session->scpSend_response[0],
|
||||
err_msg);
|
||||
}
|
||||
else
|
||||
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
||||
"failed waiting for ACK");
|
||||
LIBSSH2_FREE(session, err_msg);
|
||||
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
||||
"failed to send file");
|
||||
goto scp_send_error;
|
||||
}
|
||||
}
|
||||
|
||||
session->scpSend_state = libssh2_NB_state_idle;
|
||||
|
||||
return session->scpSend_channel;
|
||||
|
||||
scp_send_empty_channel:
|
||||
/* the code only jumps here as a result of a zero read from channel_read()
|
||||
so we check EOF status to avoid getting stuck in a loop */
|
||||
if(libssh2_channel_eof(session->scpSend_channel)) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
|
||||
"Unexpected channel close");
|
||||
}
|
||||
else
|
||||
return session->scpSend_channel;
|
||||
/* fall-through */
|
||||
scp_send_error:
|
||||
while (libssh2_channel_free(session->scpSend_channel) ==
|
||||
LIBSSH2_ERROR_EAGAIN);
|
||||
|
178
src/session.c
178
src/session.c
@@ -1,5 +1,5 @@
|
||||
/* Copyright (c) 2004-2007 Sara Golemon <sarag@libssh2.org>
|
||||
* Copyright (c) 2009-2010 by Daniel Stenberg
|
||||
* Copyright (c) 2009-2011 by Daniel Stenberg
|
||||
* Copyright (c) 2010 Simon Josefsson <simon@josefsson.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -55,6 +55,7 @@
|
||||
#include "transport.h"
|
||||
#include "session.h"
|
||||
#include "channel.h"
|
||||
#include "mac.h"
|
||||
|
||||
/* libssh2_default_alloc
|
||||
*/
|
||||
@@ -88,7 +89,8 @@ LIBSSH2_REALLOC_FUNC(libssh2_default_realloc)
|
||||
*
|
||||
* Wait for a hello from the remote host
|
||||
* Allocate a buffer and store the banner in session->remote.banner
|
||||
* Returns: 0 on success, LIBSSH2_ERROR_EAGAIN if read would block, negative on failure
|
||||
* Returns: 0 on success, LIBSSH2_ERROR_EAGAIN if read would block, negative
|
||||
* on failure
|
||||
*/
|
||||
static int
|
||||
banner_receive(LIBSSH2_SESSION * session)
|
||||
@@ -114,15 +116,18 @@ banner_receive(LIBSSH2_SESSION * session)
|
||||
|
||||
ret = _libssh2_recv(session->socket_fd, &c, 1,
|
||||
LIBSSH2_SOCKET_RECV_FLAGS(session));
|
||||
if (ret < 0)
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||
"Error recving %d bytes to %p: %d", 1, &c, errno);
|
||||
if (ret < 0) {
|
||||
if(session->api_block_mode || (ret != -EAGAIN))
|
||||
/* ignore EAGAIN when non-blocking */
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||
"Error recving %d bytes: %d", 1, -ret);
|
||||
}
|
||||
else
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||
"Recved %d bytes to %p", ret, &c);
|
||||
"Recved %d bytes banner", ret);
|
||||
|
||||
if (ret < 0) {
|
||||
if (errno == EAGAIN) {
|
||||
if (ret == -EAGAIN) {
|
||||
session->socket_block_directions =
|
||||
LIBSSH2_SESSION_BLOCK_INBOUND;
|
||||
session->banner_TxRx_total_send = banner_len;
|
||||
@@ -132,19 +137,19 @@ banner_receive(LIBSSH2_SESSION * session)
|
||||
/* Some kinda error */
|
||||
session->banner_TxRx_state = libssh2_NB_state_idle;
|
||||
session->banner_TxRx_total_send = 0;
|
||||
return -1;
|
||||
return LIBSSH2_ERROR_SOCKET_RECV;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
|
||||
return LIBSSH2_ERROR_SOCKET_NONE;
|
||||
return LIBSSH2_ERROR_SOCKET_RECV;
|
||||
}
|
||||
|
||||
if (c == '\0') {
|
||||
/* NULLs are not allowed in SSH banners */
|
||||
session->banner_TxRx_state = libssh2_NB_state_idle;
|
||||
session->banner_TxRx_total_send = 0;
|
||||
return -1;
|
||||
return LIBSSH2_ERROR_BANNER_RECV;
|
||||
}
|
||||
|
||||
session->banner_TxRx_banner[banner_len++] = c;
|
||||
@@ -161,7 +166,7 @@ banner_receive(LIBSSH2_SESSION * session)
|
||||
session->banner_TxRx_total_send = 0;
|
||||
|
||||
if (!banner_len)
|
||||
return -1;
|
||||
return LIBSSH2_ERROR_BANNER_RECV;
|
||||
|
||||
session->remote.banner = LIBSSH2_ALLOC(session, banner_len + 1);
|
||||
if (!session->remote.banner) {
|
||||
@@ -172,7 +177,7 @@ banner_receive(LIBSSH2_SESSION * session)
|
||||
session->remote.banner[banner_len] = '\0';
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Received Banner: %s",
|
||||
session->remote.banner);
|
||||
return 0;
|
||||
return LIBSSH2_ERROR_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -180,9 +185,9 @@ banner_receive(LIBSSH2_SESSION * session)
|
||||
*
|
||||
* Send the default banner, or the one set via libssh2_setopt_string
|
||||
*
|
||||
* Returns LIBSSH2_ERROR_EAGAIN if it would block - and if it does so, you should
|
||||
* call this function again as soon as it is likely that more data can be
|
||||
* sent, and this function should then be called with the same argument set
|
||||
* Returns LIBSSH2_ERROR_EAGAIN if it would block - and if it does so, you
|
||||
* should call this function again as soon as it is likely that more data can
|
||||
* be sent, and this function should then be called with the same argument set
|
||||
* (same data pointer and same data_len) until zero or failure is returned.
|
||||
*/
|
||||
static int
|
||||
@@ -228,7 +233,7 @@ banner_send(LIBSSH2_SESSION * session)
|
||||
if (ret < 0)
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||
"Error sending %d bytes: %d",
|
||||
banner_len - session->banner_TxRx_total_send, errno);
|
||||
banner_len - session->banner_TxRx_total_send, -ret);
|
||||
else
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||
"Sent %d/%d bytes at %p+%d", ret,
|
||||
@@ -236,16 +241,17 @@ banner_send(LIBSSH2_SESSION * session)
|
||||
banner, session->banner_TxRx_total_send);
|
||||
|
||||
if (ret != (banner_len - session->banner_TxRx_total_send)) {
|
||||
if ((ret > 0) || ((ret == -1) && (errno == EAGAIN))) {
|
||||
if (ret >= 0 || ret == -EAGAIN) {
|
||||
/* the whole packet could not be sent, save the what was */
|
||||
session->socket_block_directions =
|
||||
LIBSSH2_SESSION_BLOCK_OUTBOUND;
|
||||
session->banner_TxRx_total_send += ret;
|
||||
if (ret > 0)
|
||||
session->banner_TxRx_total_send += ret;
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
}
|
||||
session->banner_TxRx_state = libssh2_NB_state_idle;
|
||||
session->banner_TxRx_total_send = 0;
|
||||
return LIBSSH2_ERROR_SOCKET_NONE;
|
||||
return LIBSSH2_ERROR_SOCKET_RECV;
|
||||
}
|
||||
|
||||
/* Set the state back to idle */
|
||||
@@ -410,16 +416,15 @@ get_socket_nonblocking(int sockfd)
|
||||
LIBSSH2_API int
|
||||
libssh2_banner_set(LIBSSH2_SESSION * session, const char *banner)
|
||||
{
|
||||
int banner_len = banner ? strlen(banner) : 0;
|
||||
size_t banner_len = banner ? strlen(banner) : 0;
|
||||
|
||||
if (session->local.banner) {
|
||||
LIBSSH2_FREE(session, session->local.banner);
|
||||
session->local.banner = NULL;
|
||||
}
|
||||
|
||||
if (!banner_len) {
|
||||
if (!banner_len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
session->local.banner = LIBSSH2_ALLOC(session, banner_len + 3);
|
||||
if (!session->local.banner) {
|
||||
@@ -556,6 +561,14 @@ int _libssh2_wait_socket(LIBSSH2_SESSION *session)
|
||||
/* figure out what to wait for */
|
||||
dir = libssh2_session_block_directions(session);
|
||||
|
||||
if(!dir) {
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||
"Nothing to wait for in wait_socket");
|
||||
/* To avoid that we hang below just because there's nothing set to
|
||||
wait for, we timeout on 1 second to also avoid busy-looping
|
||||
during this condition */
|
||||
seconds_to_next = 1;
|
||||
}
|
||||
{
|
||||
#ifdef HAVE_POLL
|
||||
struct pollfd sockets[1];
|
||||
@@ -621,7 +634,7 @@ session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock)
|
||||
"session_startup for socket %d", sock);
|
||||
if (INVALID_SOCKET == sock) {
|
||||
/* Did we forget something? */
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_NONE,
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_BAD_SOCKET,
|
||||
"Bad socket provided");
|
||||
}
|
||||
session->socket_fd = sock;
|
||||
@@ -647,11 +660,14 @@ session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock)
|
||||
}
|
||||
|
||||
if (session->startup_state == libssh2_NB_state_sent) {
|
||||
rc = banner_receive(session);
|
||||
if (rc) {
|
||||
return _libssh2_error(session, rc,
|
||||
"Failed getting banner");
|
||||
}
|
||||
do {
|
||||
session->banner_TxRx_state = libssh2_NB_state_idle;
|
||||
|
||||
rc = banner_receive(session);
|
||||
if (rc)
|
||||
return _libssh2_error(session, rc,
|
||||
"Failed getting banner");
|
||||
} while(strncmp("SSH-", (char *)session->remote.banner, 4));
|
||||
|
||||
session->startup_state = libssh2_NB_state_sent1;
|
||||
}
|
||||
@@ -680,8 +696,9 @@ session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock)
|
||||
}
|
||||
|
||||
if (session->startup_state == libssh2_NB_state_sent3) {
|
||||
rc = _libssh2_transport_write(session, session->startup_service,
|
||||
sizeof("ssh-userauth") + 5 - 1);
|
||||
rc = _libssh2_transport_send(session, session->startup_service,
|
||||
sizeof("ssh-userauth") + 5 - 1,
|
||||
NULL, 0);
|
||||
if (rc) {
|
||||
return _libssh2_error(session, rc,
|
||||
"Unable to ask for ssh-userauth service");
|
||||
@@ -722,16 +739,15 @@ session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock)
|
||||
}
|
||||
|
||||
/*
|
||||
* proto libssh2_session_startup
|
||||
* libssh2_session_handshake()
|
||||
*
|
||||
* session: LIBSSH2_SESSION struct allocated and owned by the calling program
|
||||
* sock: *must* be populated with an opened and connected socket.
|
||||
*
|
||||
* Returns: 0 on success, or non-zero on failure
|
||||
* Any memory allocated by libssh2 will use alloc/realloc/free
|
||||
* callbacks in session.
|
||||
* The 'sock' socket *must* be populated with an opened and connected socket.
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_session_startup(LIBSSH2_SESSION *session, int sock)
|
||||
libssh2_session_handshake(LIBSSH2_SESSION *session, libssh2_socket_t sock)
|
||||
{
|
||||
int rc;
|
||||
|
||||
@@ -740,6 +756,23 @@ libssh2_session_startup(LIBSSH2_SESSION *session, int sock)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* libssh2_session_startup()
|
||||
*
|
||||
* DEPRECATED. Use libssh2_session_handshake() instead! This function is not
|
||||
* portable enough.
|
||||
*
|
||||
* session: LIBSSH2_SESSION struct allocated and owned by the calling program
|
||||
* sock: *must* be populated with an opened and connected socket.
|
||||
*
|
||||
* Returns: 0 on success, or non-zero on failure
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_session_startup(LIBSSH2_SESSION *session, int sock)
|
||||
{
|
||||
return libssh2_session_handshake(session, (libssh2_socket_t) sock);
|
||||
}
|
||||
|
||||
/*
|
||||
* libssh2_session_free
|
||||
*
|
||||
@@ -753,7 +786,6 @@ session_free(LIBSSH2_SESSION *session)
|
||||
LIBSSH2_PACKET *pkg;
|
||||
LIBSSH2_CHANNEL *ch;
|
||||
LIBSSH2_LISTENER *l;
|
||||
struct transportpacket *p = &session->packet;
|
||||
|
||||
if (session->free_state == libssh2_NB_state_idle) {
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Freeing session resource",
|
||||
@@ -884,9 +916,6 @@ session_free(LIBSSH2_SESSION *session)
|
||||
if (session->startup_data) {
|
||||
LIBSSH2_FREE(session, session->startup_data);
|
||||
}
|
||||
if (session->disconnect_data) {
|
||||
LIBSSH2_FREE(session, session->disconnect_data);
|
||||
}
|
||||
if (session->userauth_list_data) {
|
||||
LIBSSH2_FREE(session, session->userauth_list_data);
|
||||
}
|
||||
@@ -944,12 +973,6 @@ session_free(LIBSSH2_SESSION *session)
|
||||
if (session->scpSend_command) {
|
||||
LIBSSH2_FREE(session, session->scpSend_command);
|
||||
}
|
||||
if (session->scpRecv_err_msg) {
|
||||
LIBSSH2_FREE(session, session->scpRecv_err_msg);
|
||||
}
|
||||
if (session->scpSend_err_msg) {
|
||||
LIBSSH2_FREE(session, session->scpSend_err_msg);
|
||||
}
|
||||
|
||||
/* Cleanup all remaining packets */
|
||||
while ((pkg = _libssh2_list_first(&session->packets))) {
|
||||
@@ -961,11 +984,6 @@ session_free(LIBSSH2_SESSION *session)
|
||||
LIBSSH2_FREE(session, pkg);
|
||||
}
|
||||
|
||||
/* Cleanup remaining outgoing packet buffer */
|
||||
if (p->outbuf) {
|
||||
LIBSSH2_FREE(session, p->outbuf);
|
||||
}
|
||||
|
||||
if(session->socket_prev_blockstate)
|
||||
/* if the socket was previously blocking, put it back so */
|
||||
session_nonblock(session->socket_fd, 0);
|
||||
@@ -1000,7 +1018,8 @@ libssh2_session_free(LIBSSH2_SESSION * session)
|
||||
*/
|
||||
static int
|
||||
session_disconnect(LIBSSH2_SESSION *session, int reason,
|
||||
const char *description, const char *lang)
|
||||
const char *description,
|
||||
const char *lang)
|
||||
{
|
||||
unsigned char *s;
|
||||
unsigned long descr_len = 0, lang_len = 0;
|
||||
@@ -1010,40 +1029,36 @@ session_disconnect(LIBSSH2_SESSION *session, int reason,
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_TRANS,
|
||||
"Disconnecting: reason=%d, desc=%s, lang=%s", reason,
|
||||
description, lang);
|
||||
if (description) {
|
||||
if (description)
|
||||
descr_len = strlen(description);
|
||||
}
|
||||
if (lang) {
|
||||
|
||||
if (lang)
|
||||
lang_len = strlen(lang);
|
||||
}
|
||||
|
||||
if(descr_len > 256)
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_INVAL,
|
||||
"too long description");
|
||||
|
||||
/* 13 = packet_type(1) + reason code(4) + descr_len(4) + lang_len(4) */
|
||||
session->disconnect_data_len = descr_len + lang_len + 13;
|
||||
|
||||
s = session->disconnect_data =
|
||||
LIBSSH2_ALLOC(session, session->disconnect_data_len);
|
||||
if (!session->disconnect_data) {
|
||||
session->disconnect_state = libssh2_NB_state_idle;
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||
"Unable to allocate memory for "
|
||||
"disconnect packet");
|
||||
}
|
||||
s = session->disconnect_data;
|
||||
|
||||
*(s++) = SSH_MSG_DISCONNECT;
|
||||
_libssh2_store_u32(&s, reason);
|
||||
_libssh2_store_str(&s, description, descr_len);
|
||||
_libssh2_store_str(&s, lang, lang_len);
|
||||
/* store length only, lang is sent separately */
|
||||
_libssh2_store_u32(&s, lang_len);
|
||||
|
||||
session->disconnect_state = libssh2_NB_state_created;
|
||||
}
|
||||
|
||||
rc = _libssh2_transport_write(session, session->disconnect_data,
|
||||
session->disconnect_data_len);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
rc = _libssh2_transport_send(session, session->disconnect_data,
|
||||
session->disconnect_data_len,
|
||||
(unsigned char *)lang, lang_len);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN)
|
||||
return rc;
|
||||
}
|
||||
|
||||
LIBSSH2_FREE(session, session->disconnect_data);
|
||||
session->disconnect_data = NULL;
|
||||
session->disconnect_state = libssh2_NB_state_idle;
|
||||
|
||||
return 0;
|
||||
@@ -1208,19 +1223,24 @@ libssh2_session_last_errno(LIBSSH2_SESSION * session)
|
||||
*
|
||||
* Set/Get session flags
|
||||
*
|
||||
* Passing flag==0 will avoid changing session->flags while still returning
|
||||
* its current value
|
||||
* Return error code.
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_session_flag(LIBSSH2_SESSION * session, int flag, int value)
|
||||
{
|
||||
if (value) {
|
||||
session->flags |= flag;
|
||||
} else {
|
||||
session->flags &= ~flag;
|
||||
switch(flag) {
|
||||
case LIBSSH2_FLAG_SIGPIPE:
|
||||
session->flag.sigpipe = value;
|
||||
break;
|
||||
case LIBSSH2_FLAG_COMPRESS:
|
||||
session->flag.compress = value;
|
||||
break;
|
||||
default:
|
||||
/* unknown flag */
|
||||
return LIBSSH2_ERROR_INVAL;
|
||||
}
|
||||
|
||||
return session->flags;
|
||||
return LIBSSH2_ERROR_NONE;
|
||||
}
|
||||
|
||||
/* _libssh2_session_set_blocking
|
||||
@@ -1338,8 +1358,8 @@ libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout)
|
||||
struct pollfd sockets[256];
|
||||
|
||||
if (nfds > 256)
|
||||
/* systems without alloca use a fixed-size array, this can be fixed
|
||||
if we really want to, at least if the compiler is a C99 capable one */
|
||||
/* systems without alloca use a fixed-size array, this can be fixed if
|
||||
we really want to, at least if the compiler is a C99 capable one */
|
||||
return -1;
|
||||
#endif
|
||||
/* Setup sockets for polling */
|
||||
|
1004
src/sftp.c
1004
src/sftp.c
File diff suppressed because it is too large
Load Diff
219
src/sftp.h
Normal file
219
src/sftp.h
Normal file
@@ -0,0 +1,219 @@
|
||||
#ifndef _LIBSSH2_SFP_H
|
||||
#define _LIBSSH2_SFTP_H
|
||||
/*
|
||||
* Copyright (C) 2010 by Daniel Stenberg
|
||||
* Author: Daniel Stenberg <daniel@haxx.se>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* MAX_SFTP_OUTGOING_SIZE MUST not be larger than 32500 or so. This is the
|
||||
* amount of data sent in each FXP_WRITE packet
|
||||
*/
|
||||
#define MAX_SFTP_OUTGOING_SIZE 30000
|
||||
|
||||
/* MAX_SFTP_READ_SIZE is how much data is asked for at max in each FXP_READ
|
||||
* packets.
|
||||
*/
|
||||
#define MAX_SFTP_READ_SIZE 2000
|
||||
|
||||
struct sftp_pipeline_chunk {
|
||||
struct list_node node;
|
||||
size_t len; /* WRITE: size of the data to write
|
||||
READ: how many bytes that was asked for */
|
||||
size_t sent;
|
||||
ssize_t lefttosend; /* if 0, the entire packet has been sent off */
|
||||
uint32_t request_id;
|
||||
unsigned char packet[1]; /* data */
|
||||
};
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(x,y) ((x)<(y)?(x):(y))
|
||||
#endif
|
||||
|
||||
struct _LIBSSH2_SFTP_PACKET
|
||||
{
|
||||
struct list_node node; /* linked list header */
|
||||
uint32_t request_id;
|
||||
unsigned char *data;
|
||||
size_t data_len; /* payload size */
|
||||
};
|
||||
|
||||
typedef struct _LIBSSH2_SFTP_PACKET LIBSSH2_SFTP_PACKET;
|
||||
|
||||
#define SFTP_HANDLE_MAXLEN 256 /* according to spec! */
|
||||
|
||||
struct _LIBSSH2_SFTP_HANDLE
|
||||
{
|
||||
struct list_node node;
|
||||
|
||||
LIBSSH2_SFTP *sftp;
|
||||
|
||||
char handle[SFTP_HANDLE_MAXLEN];
|
||||
size_t handle_len;
|
||||
|
||||
enum {
|
||||
LIBSSH2_SFTP_HANDLE_FILE,
|
||||
LIBSSH2_SFTP_HANDLE_DIR
|
||||
} handle_type;
|
||||
|
||||
union _libssh2_sftp_handle_data
|
||||
{
|
||||
struct _libssh2_sftp_handle_file_data
|
||||
{
|
||||
libssh2_uint64_t offset;
|
||||
libssh2_uint64_t offset_sent;
|
||||
size_t acked; /* container for acked data that hasn't been
|
||||
returned to caller yet, used for sftp_write */
|
||||
|
||||
/* 'data' is used by sftp_read() and is allocated data that has
|
||||
been received already from the server but wasn't returned to
|
||||
the caller yet. It is of size 'data_len' and 'data_left is the
|
||||
number of bytes not yet returned, counted from the end of the
|
||||
buffer. */
|
||||
unsigned char *data;
|
||||
size_t data_len;
|
||||
size_t data_left;
|
||||
|
||||
char eof; /* we have read to the end */
|
||||
} file;
|
||||
struct _libssh2_sftp_handle_dir_data
|
||||
{
|
||||
uint32_t names_left;
|
||||
void *names_packet;
|
||||
char *next_name;
|
||||
} dir;
|
||||
} u;
|
||||
|
||||
/* State variables used in libssh2_sftp_close_handle() */
|
||||
libssh2_nonblocking_states close_state;
|
||||
uint32_t close_request_id;
|
||||
unsigned char *close_packet;
|
||||
|
||||
/* list of outstanding packets sent to server */
|
||||
struct list_head packet_list;
|
||||
|
||||
};
|
||||
|
||||
struct _LIBSSH2_SFTP
|
||||
{
|
||||
LIBSSH2_CHANNEL *channel;
|
||||
|
||||
uint32_t request_id, version;
|
||||
|
||||
struct list_head packets;
|
||||
|
||||
/* a list of _LIBSSH2_SFTP_HANDLE structs */
|
||||
struct list_head sftp_handles;
|
||||
|
||||
uint32_t last_errno;
|
||||
|
||||
/* Holder for partial packet, use in libssh2_sftp_packet_read() */
|
||||
unsigned char partial_size[4]; /* buffer for size field */
|
||||
size_t partial_size_len; /* size field length */
|
||||
unsigned char *partial_packet; /* The data */
|
||||
uint32_t partial_len; /* Desired number of bytes */
|
||||
size_t partial_received; /* Bytes received so far */
|
||||
|
||||
/* Time that libssh2_sftp_packet_requirev() started reading */
|
||||
time_t requirev_start;
|
||||
|
||||
/* State variables used in libssh2_sftp_open_ex() */
|
||||
libssh2_nonblocking_states open_state;
|
||||
unsigned char *open_packet;
|
||||
uint32_t open_packet_len; /* 32 bit on the wire */
|
||||
size_t open_packet_sent;
|
||||
uint32_t open_request_id;
|
||||
|
||||
/* State variables used in libssh2_sftp_read() */
|
||||
libssh2_nonblocking_states read_state;
|
||||
unsigned char *read_packet;
|
||||
uint32_t read_request_id;
|
||||
size_t read_total_read;
|
||||
|
||||
/* State variables used in libssh2_sftp_readdir() */
|
||||
libssh2_nonblocking_states readdir_state;
|
||||
unsigned char *readdir_packet;
|
||||
uint32_t readdir_request_id;
|
||||
|
||||
/* State variables used in libssh2_sftp_fstat_ex() */
|
||||
libssh2_nonblocking_states fstat_state;
|
||||
unsigned char *fstat_packet;
|
||||
uint32_t fstat_request_id;
|
||||
|
||||
/* State variables used in libssh2_sftp_unlink_ex() */
|
||||
libssh2_nonblocking_states unlink_state;
|
||||
unsigned char *unlink_packet;
|
||||
uint32_t unlink_request_id;
|
||||
|
||||
/* State variables used in libssh2_sftp_rename_ex() */
|
||||
libssh2_nonblocking_states rename_state;
|
||||
unsigned char *rename_packet;
|
||||
unsigned char *rename_s;
|
||||
uint32_t rename_request_id;
|
||||
|
||||
/* State variables used in libssh2_sftp_fstatvfs() */
|
||||
libssh2_nonblocking_states fstatvfs_state;
|
||||
unsigned char *fstatvfs_packet;
|
||||
uint32_t fstatvfs_request_id;
|
||||
|
||||
/* State variables used in libssh2_sftp_statvfs() */
|
||||
libssh2_nonblocking_states statvfs_state;
|
||||
unsigned char *statvfs_packet;
|
||||
uint32_t statvfs_request_id;
|
||||
|
||||
/* State variables used in libssh2_sftp_mkdir() */
|
||||
libssh2_nonblocking_states mkdir_state;
|
||||
unsigned char *mkdir_packet;
|
||||
uint32_t mkdir_request_id;
|
||||
|
||||
/* State variables used in libssh2_sftp_rmdir() */
|
||||
libssh2_nonblocking_states rmdir_state;
|
||||
unsigned char *rmdir_packet;
|
||||
uint32_t rmdir_request_id;
|
||||
|
||||
/* State variables used in libssh2_sftp_stat() */
|
||||
libssh2_nonblocking_states stat_state;
|
||||
unsigned char *stat_packet;
|
||||
uint32_t stat_request_id;
|
||||
|
||||
/* State variables used in libssh2_sftp_symlink() */
|
||||
libssh2_nonblocking_states symlink_state;
|
||||
unsigned char *symlink_packet;
|
||||
uint32_t symlink_request_id;
|
||||
};
|
||||
|
||||
#endif
|
268
src/transport.c
268
src/transport.c
@@ -42,10 +42,14 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
#ifdef LIBSSH2DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "transport.h"
|
||||
#include "mac.h"
|
||||
|
||||
#define MAX_BLOCKSIZE 32 /* MUST fit biggest crypto block size we use/get */
|
||||
#define MAX_MACSIZE 20 /* MUST fit biggest MAC length we support */
|
||||
@@ -54,7 +58,7 @@
|
||||
#define UNPRINTABLE_CHAR '.'
|
||||
static void
|
||||
debugdump(LIBSSH2_SESSION * session,
|
||||
const char *desc, unsigned char *ptr, size_t size)
|
||||
const char *desc, const unsigned char *ptr, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
size_t c;
|
||||
@@ -74,7 +78,7 @@ debugdump(LIBSSH2_SESSION * session,
|
||||
(session->tracehandler)(session, session->tracehandler_context,
|
||||
buffer, used);
|
||||
else
|
||||
write(2 /* stderr */, buffer, used);
|
||||
fprintf(stderr, "%s", buffer);
|
||||
|
||||
for(i = 0; i < size; i += width) {
|
||||
|
||||
@@ -110,7 +114,7 @@ debugdump(LIBSSH2_SESSION * session,
|
||||
(session->tracehandler)(session, session->tracehandler_context,
|
||||
buffer, used);
|
||||
else
|
||||
write(2, buffer, used);
|
||||
fprintf(stderr, "%s", buffer);
|
||||
}
|
||||
}
|
||||
#else
|
||||
@@ -138,7 +142,7 @@ decrypt(LIBSSH2_SESSION * session, unsigned char *source,
|
||||
if (session->remote.crypt->crypt(session, source,
|
||||
&session->remote.crypt_abstract)) {
|
||||
LIBSSH2_FREE(session, p->payload);
|
||||
return LIBSSH2_ERROR_SOCKET_NONE;
|
||||
return LIBSSH2_ERROR_DECRYPT;
|
||||
}
|
||||
|
||||
/* if the crypt() function would write to a given address it
|
||||
@@ -196,49 +200,28 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
|
||||
|
||||
/* Check for and deal with decompression */
|
||||
if (session->remote.comp &&
|
||||
strcmp(session->remote.comp->name, "none")) {
|
||||
session->remote.comp->compress &&
|
||||
session->remote.comp_abstract) {
|
||||
/*
|
||||
* The buffer for the decompression (remote.comp_abstract) is
|
||||
* initialised in time when it is needed so as long it is NULL we
|
||||
* cannot decompress.
|
||||
*/
|
||||
|
||||
unsigned char *data;
|
||||
size_t data_len;
|
||||
int free_payload = 1;
|
||||
rc = session->remote.comp->decomp(session,
|
||||
&data, &data_len,
|
||||
LIBSSH2_PACKET_MAXDECOMP,
|
||||
p->payload,
|
||||
session->fullpacket_payload_len,
|
||||
&session->remote.comp_abstract);
|
||||
LIBSSH2_FREE(session, p->payload);
|
||||
if(rc)
|
||||
return rc;
|
||||
|
||||
if (session->remote.comp->comp(session, 0,
|
||||
&data, &data_len,
|
||||
LIBSSH2_PACKET_MAXDECOMP,
|
||||
&free_payload,
|
||||
p->payload,
|
||||
session->fullpacket_payload_len,
|
||||
&session->remote.comp_abstract)) {
|
||||
LIBSSH2_FREE(session, p->payload);
|
||||
return LIBSSH2_ERROR_SOCKET_NONE;
|
||||
}
|
||||
|
||||
if (free_payload) {
|
||||
LIBSSH2_FREE(session, p->payload);
|
||||
p->payload = data;
|
||||
session->fullpacket_payload_len = data_len;
|
||||
} else {
|
||||
if (data == p->payload) {
|
||||
/* It's not to be freed, because the
|
||||
* compression layer reused payload, So let's
|
||||
* do the same!
|
||||
*/
|
||||
session->fullpacket_payload_len = data_len;
|
||||
} else {
|
||||
/* No comp_method actually lets this happen,
|
||||
* but let's prepare for the future */
|
||||
|
||||
LIBSSH2_FREE(session, p->payload);
|
||||
|
||||
/* We need a freeable struct otherwise the
|
||||
* brigade won't know what to do with it */
|
||||
p->payload = LIBSSH2_ALLOC(session, data_len);
|
||||
if (!p->payload)
|
||||
return LIBSSH2_ERROR_ALLOC;
|
||||
|
||||
memcpy(p->payload, data, data_len);
|
||||
session->fullpacket_payload_len = data_len;
|
||||
}
|
||||
}
|
||||
p->payload = data;
|
||||
session->fullpacket_payload_len = data_len;
|
||||
}
|
||||
|
||||
session->fullpacket_packet_type = p->payload[0];
|
||||
@@ -280,7 +263,7 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
|
||||
*/
|
||||
int _libssh2_transport_read(LIBSSH2_SESSION * session)
|
||||
{
|
||||
int rc = LIBSSH2_ERROR_SOCKET_NONE;
|
||||
int rc;
|
||||
struct transportpacket *p = &session->packet;
|
||||
int remainbuf;
|
||||
int remainpack;
|
||||
@@ -289,6 +272,7 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session)
|
||||
unsigned char block[MAX_BLOCKSIZE];
|
||||
int blocksize;
|
||||
int encrypted = 1;
|
||||
size_t total_num;
|
||||
|
||||
/* default clear the bit */
|
||||
session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_INBOUND;
|
||||
@@ -376,25 +360,22 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session)
|
||||
_libssh2_recv(session->socket_fd, &p->buf[remainbuf],
|
||||
PACKETBUFSIZE - remainbuf,
|
||||
LIBSSH2_SOCKET_RECV_FLAGS(session));
|
||||
if (nread < 0)
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||
"Error recving %d bytes to %p+%d: %d",
|
||||
PACKETBUFSIZE - remainbuf, p->buf, remainbuf,
|
||||
errno);
|
||||
else
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||
"Recved %d/%d bytes to %p+%d", nread,
|
||||
PACKETBUFSIZE - remainbuf, p->buf, remainbuf);
|
||||
if (nread <= 0) {
|
||||
/* check if this is due to EAGAIN and return the special
|
||||
return code if so, error out normally otherwise */
|
||||
if ((nread < 0) && (errno == EAGAIN)) {
|
||||
if ((nread < 0) && (nread == -EAGAIN)) {
|
||||
session->socket_block_directions |=
|
||||
LIBSSH2_SESSION_BLOCK_INBOUND;
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
}
|
||||
return LIBSSH2_ERROR_SOCKET_NONE;
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||
"Error recving %d bytes (got %d)",
|
||||
PACKETBUFSIZE - remainbuf, -nread);
|
||||
return LIBSSH2_ERROR_SOCKET_RECV;
|
||||
}
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||
"Recved %d/%d bytes to %p+%d", nread,
|
||||
PACKETBUFSIZE - remainbuf, p->buf, remainbuf);
|
||||
|
||||
debugdump(session, "libssh2_transport_read() raw",
|
||||
&p->buf[remainbuf], nread);
|
||||
@@ -445,13 +426,13 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session)
|
||||
*/
|
||||
p->packet_length = _libssh2_ntohu32(block);
|
||||
if (p->packet_length < 1)
|
||||
return LIBSSH2_ERROR_SOCKET_NONE;
|
||||
return LIBSSH2_ERROR_DECRYPT;
|
||||
|
||||
p->padding_length = block[4];
|
||||
|
||||
/* total_num is the number of bytes following the initial
|
||||
(5 bytes) packet length and padding length fields */
|
||||
p->total_num =
|
||||
total_num =
|
||||
p->packet_length - 1 +
|
||||
(encrypted ? session->remote.mac->mac_len : 0);
|
||||
|
||||
@@ -463,16 +444,17 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session)
|
||||
* or less (including length, padding length, payload,
|
||||
* padding, and MAC.)."
|
||||
*/
|
||||
if (p->total_num > LIBSSH2_PACKET_MAXPAYLOAD) {
|
||||
if (total_num > LIBSSH2_PACKET_MAXPAYLOAD) {
|
||||
return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
|
||||
}
|
||||
|
||||
/* Get a packet handle put data into. We get one to
|
||||
hold all data, including padding and MAC. */
|
||||
p->payload = LIBSSH2_ALLOC(session, p->total_num);
|
||||
p->payload = LIBSSH2_ALLOC(session, total_num);
|
||||
if (!p->payload) {
|
||||
return LIBSSH2_ERROR_ALLOC;
|
||||
}
|
||||
p->total_num = total_num;
|
||||
/* init write pointer to start of payload buffer */
|
||||
p->wptr = p->payload;
|
||||
|
||||
@@ -597,32 +579,18 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session)
|
||||
}
|
||||
} while (1); /* loop */
|
||||
|
||||
return LIBSSH2_ERROR_SOCKET_NONE; /* we never reach this point */
|
||||
}
|
||||
|
||||
/*
|
||||
* _libssh2_transport_drain() empties the outgoing send buffer if there
|
||||
* is any.
|
||||
*/
|
||||
void _libssh2_transport_drain(LIBSSH2_SESSION * session)
|
||||
{
|
||||
struct transportpacket *p = &session->packet;
|
||||
if(p->outbuf) {
|
||||
LIBSSH2_FREE(session, p->outbuf);
|
||||
p->outbuf = NULL;
|
||||
p->ototal_num = 0;
|
||||
}
|
||||
return LIBSSH2_ERROR_SOCKET_RECV; /* we never reach this point */
|
||||
}
|
||||
|
||||
static int
|
||||
send_existing(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
size_t data_len, ssize_t * ret)
|
||||
send_existing(LIBSSH2_SESSION *session, const unsigned char *data,
|
||||
size_t data_len, ssize_t *ret)
|
||||
{
|
||||
ssize_t rc;
|
||||
ssize_t length;
|
||||
struct transportpacket *p = &session->packet;
|
||||
|
||||
if (!p->outbuf) {
|
||||
if (!p->olen) {
|
||||
*ret = 0;
|
||||
return LIBSSH2_ERROR_NONE;
|
||||
}
|
||||
@@ -646,29 +614,31 @@ send_existing(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
LIBSSH2_SOCKET_SEND_FLAGS(session));
|
||||
if (rc < 0)
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||
"Error sending %d bytes: %d", length, errno);
|
||||
else
|
||||
"Error sending %d bytes: %d", length, -rc);
|
||||
else {
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||
"Sent %d/%d bytes at %p+%d", rc, length, p->outbuf,
|
||||
p->osent);
|
||||
|
||||
if(rc > 0) {
|
||||
debugdump(session, "libssh2_transport_write send()",
|
||||
&p->outbuf[p->osent], rc);
|
||||
}
|
||||
|
||||
if (rc == length) {
|
||||
/* the remainder of the package was sent */
|
||||
LIBSSH2_FREE(session, p->outbuf);
|
||||
p->outbuf = NULL;
|
||||
p->ototal_num = 0;
|
||||
p->olen = 0;
|
||||
/* we leave *ret set so that the parent returns as we MUST return back
|
||||
a send success now, so that we don't risk sending EAGAIN later
|
||||
which then would confuse the parent function */
|
||||
return LIBSSH2_ERROR_NONE;
|
||||
|
||||
}
|
||||
else if (rc < 0) {
|
||||
/* nothing was sent */
|
||||
if (errno != EAGAIN) {
|
||||
if (rc != -EAGAIN)
|
||||
/* send failure! */
|
||||
return LIBSSH2_ERROR_SOCKET_NONE;
|
||||
}
|
||||
return LIBSSH2_ERROR_SOCKET_SEND;
|
||||
|
||||
session->socket_block_directions |= LIBSSH2_SESSION_BLOCK_OUTBOUND;
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
}
|
||||
@@ -679,48 +649,50 @@ send_existing(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
}
|
||||
|
||||
/*
|
||||
* libssh2_transport_write
|
||||
* libssh2_transport_send
|
||||
*
|
||||
* Send a packet, encrypting it and adding a MAC code if necessary
|
||||
* Returns 0 on success, non-zero on failure.
|
||||
*
|
||||
* Returns LIBSSH2_ERROR_EAGAIN if it would block - and if it does so, you should
|
||||
* call this function again as soon as it is likely that more data can be
|
||||
* sent, and this function should then be called with the same argument set
|
||||
* (same data pointer and same data_len) until zero or failure is returned.
|
||||
* The data is provided as _two_ data areas that are combined by this
|
||||
* function. The 'data' part is sent immediately before 'data2'. 'data2' may
|
||||
* be set to NULL to only use a single part.
|
||||
*
|
||||
* NOTE: this function does not verify that 'data_len' is less than ~35000
|
||||
* which is what all implementations should support at least as packet size.
|
||||
* (RFC4253 section 6.1)
|
||||
* Returns LIBSSH2_ERROR_EAGAIN if it would block or if the whole packet was
|
||||
* not sent yet. If it does so, the caller should call this function again as
|
||||
* soon as it is likely that more data can be sent, and this function MUST
|
||||
* then be called with the same argument set (same data pointer and same
|
||||
* data_len) until ERROR_NONE or failure is returned.
|
||||
*
|
||||
* This function DOES not call _libssh2_error() on any errors.
|
||||
* This function DOES NOT call _libssh2_error() on any errors.
|
||||
*/
|
||||
int
|
||||
_libssh2_transport_write(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
size_t data_len)
|
||||
int _libssh2_transport_send(LIBSSH2_SESSION *session,
|
||||
const unsigned char *data, size_t data_len,
|
||||
const unsigned char *data2, size_t data2_len)
|
||||
{
|
||||
int blocksize =
|
||||
(session->state & LIBSSH2_STATE_NEWKEYS) ? session->local.crypt->
|
||||
blocksize : 8;
|
||||
(session->state & LIBSSH2_STATE_NEWKEYS) ?
|
||||
session->local.crypt->blocksize : 8;
|
||||
int padding_length;
|
||||
int packet_length;
|
||||
size_t packet_length;
|
||||
int total_length;
|
||||
int free_data = 0;
|
||||
#ifdef RANDOM_PADDING
|
||||
int rand_max;
|
||||
int seed = data[0]; /* FIXME: make this random */
|
||||
#endif
|
||||
struct transportpacket *p = &session->packet;
|
||||
int encrypted;
|
||||
int i;
|
||||
ssize_t ret;
|
||||
int rc;
|
||||
unsigned char *orgdata = data;
|
||||
const unsigned char *orgdata = data;
|
||||
size_t orgdata_len = data_len;
|
||||
|
||||
debugdump(session, "libssh2_transport_write plain", data, data_len);
|
||||
if(data2)
|
||||
debugdump(session, "libssh2_transport_write plain2", data2, data2_len);
|
||||
|
||||
/* FIRST, check if we have a pending write to complete */
|
||||
/* FIRST, check if we have a pending write to complete. send_existing
|
||||
only sanity-check data and data_len and not data2 and data2_len!! */
|
||||
rc = send_existing(session, data, data_len, &ret);
|
||||
if (rc)
|
||||
return rc;
|
||||
@@ -728,19 +700,56 @@ _libssh2_transport_write(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_OUTBOUND;
|
||||
|
||||
if (ret)
|
||||
/* set by send_existing if data was sent */
|
||||
return rc;
|
||||
|
||||
encrypted = (session->state & LIBSSH2_STATE_NEWKEYS) ? 1 : 0;
|
||||
|
||||
/* check if we should compress */
|
||||
if (encrypted && 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 LIBSSH2_ERROR_COMPRESS; /* compression failure */
|
||||
if (encrypted && session->local.comp->compress) {
|
||||
/* the idea here is that these function must fail if the output gets
|
||||
larger than what fits in the assigned buffer so thus they don't
|
||||
check the input size as we don't know how much it compresses */
|
||||
size_t dest_len = MAX_SSH_PACKET_LEN-5-256;
|
||||
size_t dest2_len = dest_len;
|
||||
|
||||
/* compress directly to the target buffer */
|
||||
rc = session->local.comp->comp(session,
|
||||
&p->outbuf[5], &dest_len,
|
||||
data, data_len,
|
||||
&session->local.comp_abstract);
|
||||
if(rc)
|
||||
return rc; /* compression failure */
|
||||
|
||||
if(data2 && data2_len) {
|
||||
/* compress directly to the target buffer right after where the
|
||||
previous call put data */
|
||||
dest2_len -= dest_len;
|
||||
|
||||
rc = session->local.comp->comp(session,
|
||||
&p->outbuf[5+dest_len], &dest2_len,
|
||||
data2, data2_len,
|
||||
&session->local.comp_abstract);
|
||||
}
|
||||
else
|
||||
dest2_len = 0;
|
||||
if(rc)
|
||||
return rc; /* compression failure */
|
||||
|
||||
data_len = dest_len + dest2_len; /* use the combined length */
|
||||
}
|
||||
else {
|
||||
if((data_len + data2_len) >= (MAX_SSH_PACKET_LEN-0x100))
|
||||
/* too large packet, return error for this until we make this
|
||||
function split it up and send multiple SSH packets */
|
||||
return LIBSSH2_ERROR_INVAL;
|
||||
|
||||
/* copy the payload data */
|
||||
memcpy(&p->outbuf[5], data, data_len);
|
||||
if(data2 && data2_len)
|
||||
memcpy(&p->outbuf[5+data_len], data2, data2_len);
|
||||
data_len += data2_len; /* use the combined length */
|
||||
}
|
||||
|
||||
|
||||
/* RFC4253 says: Note that the length of the concatenation of
|
||||
'packet_length', 'padding_length', 'payload', and 'random padding'
|
||||
@@ -781,28 +790,18 @@ _libssh2_transport_write(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
total_length =
|
||||
packet_length + (encrypted ? session->local.mac->mac_len : 0);
|
||||
|
||||
/* allocate memory to store the outgoing packet in, in case we can't
|
||||
send the whole one and thus need to keep it after this function
|
||||
returns. */
|
||||
p->outbuf = LIBSSH2_ALLOC(session, total_length);
|
||||
if (!p->outbuf) {
|
||||
return LIBSSH2_ERROR_ALLOC;
|
||||
}
|
||||
|
||||
/* store packet_length, which is the size of the whole packet except
|
||||
the MAC and the packet_length field itself */
|
||||
_libssh2_htonu32(p->outbuf, packet_length - 4);
|
||||
/* store padding_length */
|
||||
p->outbuf[4] = padding_length;
|
||||
/* copy the payload data */
|
||||
memcpy(p->outbuf + 5, data, data_len);
|
||||
|
||||
/* fill the padding area with random junk */
|
||||
_libssh2_random(p->outbuf + 5 + data_len, padding_length);
|
||||
if (free_data) {
|
||||
LIBSSH2_FREE(session, data);
|
||||
}
|
||||
|
||||
if (encrypted) {
|
||||
size_t i;
|
||||
|
||||
/* Calculate MAC hash. Put the output at index packet_length,
|
||||
since that size includes the whole packet. The MAC is
|
||||
calculated on the entire unencrypted packet, including all
|
||||
@@ -818,7 +817,7 @@ _libssh2_transport_write(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
unsigned char *ptr = &p->outbuf[i];
|
||||
if (session->local.crypt->crypt(session, ptr,
|
||||
&session->local.crypt_abstract))
|
||||
return LIBSSH2_ERROR_SOCKET_NONE; /* encryption failure */
|
||||
return LIBSSH2_ERROR_ENCRYPT; /* encryption failure */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -828,32 +827,29 @@ _libssh2_transport_write(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
LIBSSH2_SOCKET_SEND_FLAGS(session));
|
||||
if (ret < 0)
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
|
||||
"Error sending %d bytes: %d", total_length, errno);
|
||||
else
|
||||
"Error sending %d bytes: %d", total_length, -ret);
|
||||
else {
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_SOCKET, "Sent %d/%d bytes at %p",
|
||||
ret, total_length, p->outbuf);
|
||||
|
||||
if (ret != -1) {
|
||||
debugdump(session, "libssh2_transport_write send()", p->outbuf, ret);
|
||||
}
|
||||
|
||||
if (ret != total_length) {
|
||||
if ((ret > 0) || ((ret == -1) && (errno == EAGAIN))) {
|
||||
if (ret >= 0 || ret == -EAGAIN) {
|
||||
/* the whole packet could not be sent, save the rest */
|
||||
session->socket_block_directions |= LIBSSH2_SESSION_BLOCK_OUTBOUND;
|
||||
p->odata = orgdata;
|
||||
p->olen = orgdata_len;
|
||||
p->osent = (ret == -1) ? 0 : ret;
|
||||
p->osent = ret <= 0 ? 0 : ret;
|
||||
p->ototal_num = total_length;
|
||||
return LIBSSH2_ERROR_EAGAIN;
|
||||
}
|
||||
return LIBSSH2_ERROR_SOCKET_NONE;
|
||||
return LIBSSH2_ERROR_SOCKET_SEND;
|
||||
}
|
||||
|
||||
/* the whole thing got sent away */
|
||||
p->odata = NULL;
|
||||
p->olen = 0;
|
||||
LIBSSH2_FREE(session, p->outbuf);
|
||||
p->outbuf = NULL;
|
||||
|
||||
return LIBSSH2_ERROR_NONE; /* all is good */
|
||||
}
|
||||
|
@@ -44,23 +44,29 @@
|
||||
#include "libssh2_priv.h"
|
||||
#include "packet.h"
|
||||
|
||||
|
||||
/*
|
||||
* libssh2_transport_write
|
||||
* libssh2_transport_send
|
||||
*
|
||||
* Send a packet, encrypting it and adding a MAC code if necessary
|
||||
* Returns 0 on success, non-zero on failure.
|
||||
*
|
||||
* Returns PACKET_EAGAIN if it would block - and if it does so, you should
|
||||
* call this function again as soon as it is likely that more data can be
|
||||
* sent, and this function should then be called with the same argument set
|
||||
* (same data pointer and same data_len) until zero or failure is returned.
|
||||
* The data is provided as _two_ data areas that are combined by this
|
||||
* function. The 'data' part is sent immediately before 'data2'. 'data2' can
|
||||
* be set to NULL (or data2_len to 0) to only use a single part.
|
||||
*
|
||||
* NOTE: this function does not verify that 'data_len' is less than ~35000
|
||||
* which is what all implementations should support at least as packet size.
|
||||
* (RFC4253 section 6.1)
|
||||
* Returns LIBSSH2_ERROR_EAGAIN if it would block or if the whole packet was
|
||||
* not sent yet. If it does so, the caller should call this function again as
|
||||
* soon as it is likely that more data can be sent, and this function MUST
|
||||
* then be called with the same argument set (same data pointer and same
|
||||
* data_len) until ERROR_NONE or failure is returned.
|
||||
*
|
||||
* This function DOES NOT call _libssh2_error() on any errors.
|
||||
*/
|
||||
int _libssh2_transport_write(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
size_t data_len);
|
||||
int _libssh2_transport_send(LIBSSH2_SESSION *session,
|
||||
const unsigned char *data, size_t data_len,
|
||||
const unsigned char *data2, size_t data2_len);
|
||||
|
||||
/*
|
||||
* _libssh2_transport_read
|
||||
*
|
||||
@@ -78,10 +84,4 @@ int _libssh2_transport_write(LIBSSH2_SESSION * session, unsigned char *data,
|
||||
*/
|
||||
int _libssh2_transport_read(LIBSSH2_SESSION * session);
|
||||
|
||||
/*
|
||||
* _libssh2_transport_drain() empties the outgoing send buffer if there
|
||||
* is any.
|
||||
*/
|
||||
void _libssh2_transport_drain(LIBSSH2_SESSION *session);
|
||||
|
||||
#endif /* __LIBSSH2_TRANSPORT_H */
|
||||
|
159
src/userauth.c
159
src/userauth.c
@@ -1,6 +1,6 @@
|
||||
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
|
||||
* Copyright (c) 2005 Mikhail Gusarov <dottedmag@dottedmag.net>
|
||||
* Copyright (c) 2009 by Daniel Stenberg
|
||||
* Copyright (c) 2009-2010 by Daniel Stenberg
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
@@ -66,7 +66,7 @@ static char *userauth_list(LIBSSH2_SESSION *session, const char *username,
|
||||
static const unsigned char reply_codes[3] =
|
||||
{ SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
|
||||
/* packet_type(1) + username_len(4) + service_len(4) +
|
||||
service(14)"ssh-connection" + method_len(4) + method(4)"none" */
|
||||
service(14)"ssh-connection" + method_len(4) = 27 */
|
||||
unsigned long methods_len;
|
||||
unsigned char *s;
|
||||
int rc;
|
||||
@@ -76,7 +76,7 @@ static char *userauth_list(LIBSSH2_SESSION *session, const char *username,
|
||||
memset(&session->userauth_list_packet_requirev_state, 0,
|
||||
sizeof(session->userauth_list_packet_requirev_state));
|
||||
|
||||
session->userauth_list_data_len = username_len + 31;
|
||||
session->userauth_list_data_len = username_len + 27;
|
||||
|
||||
s = session->userauth_list_data =
|
||||
LIBSSH2_ALLOC(session, session->userauth_list_data_len);
|
||||
@@ -89,14 +89,15 @@ static char *userauth_list(LIBSSH2_SESSION *session, const char *username,
|
||||
*(s++) = SSH_MSG_USERAUTH_REQUEST;
|
||||
_libssh2_store_str(&s, username, username_len);
|
||||
_libssh2_store_str(&s, "ssh-connection", 14);
|
||||
_libssh2_store_str(&s, "none", 4);
|
||||
_libssh2_store_u32(&s, 4); /* send "none" separately */
|
||||
|
||||
session->userauth_list_state = libssh2_NB_state_created;
|
||||
}
|
||||
|
||||
if (session->userauth_list_state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_transport_write(session, session->userauth_list_data,
|
||||
session->userauth_list_data_len);
|
||||
rc = _libssh2_transport_send(session, session->userauth_list_data,
|
||||
session->userauth_list_data_len,
|
||||
(unsigned char *)"none", 4);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
_libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block requesting userauth list");
|
||||
@@ -178,12 +179,12 @@ libssh2_userauth_list(LIBSSH2_SESSION * session, const char *user,
|
||||
* libssh2_userauth_authenticated
|
||||
*
|
||||
* Returns: 0 if not yet authenticated
|
||||
* non-zero is already authenticated
|
||||
* 1 if already authenticated
|
||||
*/
|
||||
LIBSSH2_API int
|
||||
libssh2_userauth_authenticated(LIBSSH2_SESSION * session)
|
||||
{
|
||||
return session->state & LIBSSH2_STATE_AUTHENTICATED;
|
||||
return (session->state & LIBSSH2_STATE_AUTHENTICATED)?1:0;
|
||||
}
|
||||
|
||||
|
||||
@@ -192,9 +193,9 @@ libssh2_userauth_authenticated(LIBSSH2_SESSION * session)
|
||||
* Plain ol' login
|
||||
*/
|
||||
static int
|
||||
userauth_password(LIBSSH2_SESSION *session, const char *username,
|
||||
unsigned int username_len, const char *password,
|
||||
unsigned int password_len,
|
||||
userauth_password(LIBSSH2_SESSION *session,
|
||||
const char *username, unsigned int username_len,
|
||||
const unsigned char *password, unsigned int password_len,
|
||||
LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)))
|
||||
{
|
||||
unsigned char *s;
|
||||
@@ -213,10 +214,12 @@ userauth_password(LIBSSH2_SESSION *session, const char *username,
|
||||
* 40 = acket_type(1) + username_len(4) + service_len(4) +
|
||||
* service(14)"ssh-connection" + method_len(4) + method(8)"password" +
|
||||
* chgpwdbool(1) + password_len(4) */
|
||||
session->userauth_pswd_data_len = username_len + password_len + 40;
|
||||
session->userauth_pswd_data_len = username_len + 40;
|
||||
|
||||
session->userauth_pswd_data0 = ~SSH_MSG_USERAUTH_PASSWD_CHANGEREQ;
|
||||
|
||||
/* TODO: remove this alloc with a fixed buffer in the session
|
||||
struct */
|
||||
s = session->userauth_pswd_data =
|
||||
LIBSSH2_ALLOC(session, session->userauth_pswd_data_len);
|
||||
if (!session->userauth_pswd_data) {
|
||||
@@ -230,7 +233,8 @@ userauth_password(LIBSSH2_SESSION *session, const char *username,
|
||||
_libssh2_store_str(&s, "ssh-connection", sizeof("ssh-connection") - 1);
|
||||
_libssh2_store_str(&s, "password", sizeof("password") - 1);
|
||||
*s++ = '\0';
|
||||
_libssh2_store_str(&s, password, password_len);
|
||||
_libssh2_store_u32(&s, password_len);
|
||||
/* 'password' is sent separately */
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
|
||||
"Attempting to login using password authentication");
|
||||
@@ -239,8 +243,9 @@ userauth_password(LIBSSH2_SESSION *session, const char *username,
|
||||
}
|
||||
|
||||
if (session->userauth_pswd_state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_transport_write(session, session->userauth_pswd_data,
|
||||
session->userauth_pswd_data_len);
|
||||
rc = _libssh2_transport_send(session, session->userauth_pswd_data,
|
||||
session->userauth_pswd_data_len,
|
||||
password, password_len);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block writing password request");
|
||||
@@ -335,8 +340,7 @@ userauth_password(LIBSSH2_SESSION *session, const char *username,
|
||||
|
||||
/* basic data_len + newpw_len(4) */
|
||||
session->userauth_pswd_data_len =
|
||||
username_len + password_len + 44 +
|
||||
session->userauth_pswd_newpw_len;
|
||||
username_len + password_len + 44;
|
||||
|
||||
s = session->userauth_pswd_data =
|
||||
LIBSSH2_ALLOC(session,
|
||||
@@ -358,18 +362,21 @@ userauth_password(LIBSSH2_SESSION *session, const char *username,
|
||||
_libssh2_store_str(&s, "password",
|
||||
sizeof("password") - 1);
|
||||
*s++ = 0x01;
|
||||
_libssh2_store_str(&s, password, password_len);
|
||||
_libssh2_store_str(&s, session->userauth_pswd_newpw,
|
||||
_libssh2_store_str(&s, (char *)password, password_len);
|
||||
_libssh2_store_u32(&s,
|
||||
session->userauth_pswd_newpw_len);
|
||||
/* send session->userauth_pswd_newpw separately */
|
||||
|
||||
session->userauth_pswd_state = libssh2_NB_state_sent2;
|
||||
}
|
||||
|
||||
if (session->userauth_pswd_state == libssh2_NB_state_sent2) {
|
||||
rc = _libssh2_transport_write(session,
|
||||
session->userauth_pswd_data,
|
||||
session->
|
||||
userauth_pswd_data_len);
|
||||
rc = _libssh2_transport_send(session,
|
||||
session->userauth_pswd_data,
|
||||
session->userauth_pswd_data_len,
|
||||
(unsigned char *)
|
||||
session->userauth_pswd_newpw,
|
||||
session->userauth_pswd_newpw_len);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block waiting");
|
||||
@@ -429,7 +436,7 @@ libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *username,
|
||||
int rc;
|
||||
BLOCK_ADJUST(rc, session,
|
||||
userauth_password(session, username, username_len,
|
||||
password, password_len,
|
||||
(unsigned char *)password, password_len,
|
||||
passwd_change_cb));
|
||||
return rc;
|
||||
}
|
||||
@@ -648,13 +655,25 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session,
|
||||
memset(&session->userauth_host_packet_requirev_state, 0,
|
||||
sizeof(session->userauth_host_packet_requirev_state));
|
||||
|
||||
rc = file_read_publickey(session, &session->userauth_host_method,
|
||||
&session->userauth_host_method_len,
|
||||
&pubkeydata, &pubkeydata_len,
|
||||
publickey);
|
||||
if(rc)
|
||||
/* Note: file_read_publickey() calls _libssh2_error() */
|
||||
return rc;
|
||||
if (publickey) {
|
||||
rc = file_read_publickey(session, &session->userauth_host_method,
|
||||
&session->userauth_host_method_len,
|
||||
&pubkeydata, &pubkeydata_len, publickey);
|
||||
if(rc)
|
||||
/* Note: file_read_publickey() calls _libssh2_error() */
|
||||
return rc;
|
||||
}
|
||||
else {
|
||||
/* Compute public key from private key. */
|
||||
if (_libssh2_pub_priv_keyfile(session,
|
||||
&session->userauth_host_method,
|
||||
&session->userauth_host_method_len,
|
||||
&pubkeydata, &pubkeydata_len,
|
||||
privatekey, passphrase))
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_FILE,
|
||||
"Unable to extract public key "
|
||||
"from private key file");
|
||||
}
|
||||
|
||||
/*
|
||||
* 52 = packet_type(1) + username_len(4) + servicename_len(4) +
|
||||
@@ -776,9 +795,10 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session,
|
||||
}
|
||||
|
||||
if (session->userauth_host_state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_transport_write(session, session->userauth_host_packet,
|
||||
session->userauth_host_s -
|
||||
session->userauth_host_packet);
|
||||
rc = _libssh2_transport_send(session, session->userauth_host_packet,
|
||||
session->userauth_host_s -
|
||||
session->userauth_host_packet,
|
||||
NULL, 0);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block");
|
||||
}
|
||||
@@ -924,7 +944,7 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
||||
else if (session->userauth_pblc_method_len !=
|
||||
_libssh2_ntohu32(pubkeydata))
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
|
||||
"Invalid public key");
|
||||
"Invalid public key");
|
||||
|
||||
/*
|
||||
* 45 = packet_type(1) + username_len(4) + servicename_len(4) +
|
||||
@@ -937,9 +957,13 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
||||
45;
|
||||
|
||||
/*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* Note that the 'pubkeydata_len' extra bytes allocated here will not
|
||||
* be used in this first send, but will be used in the later one where
|
||||
* this same allocation is re-used.
|
||||
*/
|
||||
s = session->userauth_pblc_packet =
|
||||
LIBSSH2_ALLOC(session,
|
||||
@@ -965,6 +989,7 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
||||
_libssh2_store_str(&s, (const char *)session->userauth_pblc_method,
|
||||
session->userauth_pblc_method_len);
|
||||
_libssh2_store_str(&s, (const char *)pubkeydata, pubkeydata_len);
|
||||
|
||||
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
|
||||
"Attempting publickey authentication");
|
||||
|
||||
@@ -972,8 +997,9 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
||||
}
|
||||
|
||||
if (session->userauth_pblc_state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_transport_write(session, session->userauth_pblc_packet,
|
||||
session->userauth_pblc_packet_len);
|
||||
rc = _libssh2_transport_send(session, session->userauth_pblc_packet,
|
||||
session->userauth_pblc_packet_len,
|
||||
NULL, 0);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN)
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block");
|
||||
else if (rc) {
|
||||
@@ -1006,7 +1032,7 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
||||
session->userauth_pblc_method = NULL;
|
||||
session->userauth_pblc_state = libssh2_NB_state_idle;
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
|
||||
"Failed waiting");
|
||||
"Waiting for USERAUTH response");
|
||||
}
|
||||
|
||||
if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
@@ -1049,7 +1075,7 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
||||
}
|
||||
|
||||
if (session->userauth_pblc_state == libssh2_NB_state_sent1) {
|
||||
unsigned char *buf, *s;
|
||||
unsigned char *buf;
|
||||
unsigned char *sig;
|
||||
size_t sig_len;
|
||||
|
||||
@@ -1130,9 +1156,10 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
||||
}
|
||||
|
||||
if (session->userauth_pblc_state == libssh2_NB_state_sent2) {
|
||||
rc = _libssh2_transport_write(session, session->userauth_pblc_packet,
|
||||
session->userauth_pblc_s -
|
||||
session->userauth_pblc_packet);
|
||||
rc = _libssh2_transport_send(session, session->userauth_pblc_packet,
|
||||
session->userauth_pblc_s -
|
||||
session->userauth_pblc_packet,
|
||||
NULL, 0);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block");
|
||||
} else if (rc) {
|
||||
@@ -1161,7 +1188,7 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
|
||||
} else if (rc) {
|
||||
session->userauth_pblc_state = libssh2_NB_state_idle;
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
|
||||
"Failed waiting");
|
||||
"Waiting for publickey USERAUTH response");
|
||||
}
|
||||
|
||||
if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
@@ -1206,11 +1233,24 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session,
|
||||
privkey_file.passphrase = passphrase;
|
||||
|
||||
if (session->userauth_pblc_state == libssh2_NB_state_idle) {
|
||||
rc = file_read_publickey(session, &session->userauth_pblc_method,
|
||||
&session->userauth_pblc_method_len,
|
||||
&pubkeydata, &pubkeydata_len, publickey);
|
||||
if(rc)
|
||||
return rc;
|
||||
if (publickey) {
|
||||
rc = file_read_publickey(session, &session->userauth_pblc_method,
|
||||
&session->userauth_pblc_method_len,
|
||||
&pubkeydata, &pubkeydata_len,publickey);
|
||||
if(rc)
|
||||
return rc;
|
||||
}
|
||||
else {
|
||||
/* Compute public key from private key. */
|
||||
if (_libssh2_pub_priv_keyfile(session,
|
||||
&session->userauth_pblc_method,
|
||||
&session->userauth_pblc_method_len,
|
||||
&pubkeydata, &pubkeydata_len,
|
||||
privatekey, passphrase))
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_FILE,
|
||||
"Unable to extract public key "
|
||||
"from private key file");
|
||||
}
|
||||
}
|
||||
|
||||
rc = _libssh2_userauth_publickey(session, username, username_len,
|
||||
@@ -1348,8 +1388,9 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
|
||||
}
|
||||
|
||||
if (session->userauth_kybd_state == libssh2_NB_state_created) {
|
||||
rc = _libssh2_transport_write(session, session->userauth_kybd_data,
|
||||
session->userauth_kybd_packet_len);
|
||||
rc = _libssh2_transport_send(session, session->userauth_kybd_data,
|
||||
session->userauth_kybd_packet_len,
|
||||
NULL, 0);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block");
|
||||
} else if (rc) {
|
||||
@@ -1380,7 +1421,7 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
|
||||
session->userauth_kybd_state = libssh2_NB_state_idle;
|
||||
return _libssh2_error(session,
|
||||
LIBSSH2_ERROR_AUTHENTICATION_FAILED,
|
||||
"Failed waiting");
|
||||
"Waiting for keyboard USERAUTH response");
|
||||
}
|
||||
|
||||
if (session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
|
||||
@@ -1551,8 +1592,9 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
|
||||
}
|
||||
|
||||
if (session->userauth_kybd_state == libssh2_NB_state_sent1) {
|
||||
rc = _libssh2_transport_write(session, session->userauth_kybd_data,
|
||||
session->userauth_kybd_packet_len);
|
||||
rc = _libssh2_transport_send(session, session->userauth_kybd_data,
|
||||
session->userauth_kybd_packet_len,
|
||||
NULL, 0);
|
||||
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
||||
return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
||||
"Would block");
|
||||
@@ -1595,6 +1637,10 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
|
||||
session->userauth_kybd_prompts = NULL;
|
||||
LIBSSH2_FREE(session, session->userauth_kybd_responses);
|
||||
session->userauth_kybd_responses = NULL;
|
||||
LIBSSH2_FREE(session, session->userauth_kybd_auth_name);
|
||||
session->userauth_kybd_auth_name = NULL;
|
||||
LIBSSH2_FREE(session, session->userauth_kybd_auth_instruction);
|
||||
session->userauth_kybd_auth_instruction = NULL;
|
||||
|
||||
if (session->userauth_kybd_auth_failure) {
|
||||
session->userauth_kybd_state = libssh2_NB_state_idle;
|
||||
@@ -1622,4 +1668,3 @@ libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION *session,
|
||||
response_callback));
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@@ -35,12 +35,12 @@ RC = wrc
|
||||
!endif
|
||||
|
||||
!if $(__VERSION__) < 1250
|
||||
RM = del /q /f >NUL 2>&1
|
||||
RM = del /q /f 2>NUL
|
||||
!else
|
||||
RM = rm -f
|
||||
!endif
|
||||
MD = mkdir
|
||||
RD = rmdir /q /s >NUL 2>&1
|
||||
RD = rmdir /q /s 2>NUL
|
||||
CP = copy
|
||||
|
||||
CFLAGS = -3r -mf -hc -zff -zgf -zq -zm -zc -s -fr=nul -w2 -fpi -oilrtfm &
|
||||
@@ -70,7 +70,7 @@ ZLIB_ROOT = ..\..\zlib-1.2.5
|
||||
!ifdef %openssl_root
|
||||
OPENSSL_ROOT = $(%openssl_root)
|
||||
!else
|
||||
OPENSSL_ROOT = ..\..\openssl-0.9.8o
|
||||
OPENSSL_ROOT = ..\..\openssl-0.9.8q
|
||||
!endif
|
||||
|
||||
#!ifdef %use_zlib
|
||||
|
@@ -16,7 +16,7 @@ WITH_ZLIB = 1
|
||||
|
||||
# Edit the path below to point to the base of your OpenSSL package.
|
||||
ifndef OPENSSL_PATH
|
||||
OPENSSL_PATH = ../../openssl-0.9.8o
|
||||
OPENSSL_PATH = ../../openssl-0.9.8q
|
||||
endif
|
||||
|
||||
# Edit the path below to point to your Distribution folder.
|
||||
@@ -65,6 +65,7 @@ else
|
||||
endif
|
||||
CP = cp -afv
|
||||
# RM = rm -f
|
||||
MD = mkdir
|
||||
# Here you can find a native Win32 binary of the original awk:
|
||||
# http://www.gknw.net/development/prgtools/awk-20070501.zip
|
||||
AWK = awk
|
||||
@@ -98,7 +99,7 @@ LIBEXT = a
|
||||
RANLIB = $(CROSSPREFIX)ranlib
|
||||
#LDLIBS += -lwsock32
|
||||
LDLIBS += -lws2_32
|
||||
RCFLAGS = -O coff -i
|
||||
RCFLAGS = -DLIBSSH2_VERSION_ONLY -I. -I ../include -O coff -i
|
||||
CFLAGS += -fno-strict-aliasing
|
||||
CFLAGS += -Wall # -pedantic
|
||||
endif
|
||||
@@ -123,7 +124,8 @@ ifeq ($(findstring /sh,$(SHELL)),/sh)
|
||||
DL = '
|
||||
DS = /
|
||||
else
|
||||
DS = \\
|
||||
XX =
|
||||
DS = $(XX)\$(XX)
|
||||
endif
|
||||
|
||||
vpath %.c . ../src
|
||||
@@ -198,13 +200,13 @@ clean:
|
||||
-$(RM) -r $(OBJDIR)
|
||||
|
||||
$(OBJDIR):
|
||||
@mkdir $@
|
||||
@$(MD) $@
|
||||
|
||||
$(DISTDIR):
|
||||
@mkdir $@
|
||||
@$(MD) $@
|
||||
|
||||
$(DEVLDIR):
|
||||
@mkdir $@
|
||||
@$(MD) $@
|
||||
|
||||
$(TARGET).$(LIBEXT): $(OBJS)
|
||||
@echo Creating $@
|
||||
@@ -222,7 +224,7 @@ $(TARGET).dll $(TARGET)dll.a: $(OBJL)
|
||||
|
||||
$(OBJDIR)/%.res: %.rc
|
||||
@echo Creating $@
|
||||
@$(RC) $(RCFLAGS) -DLIBSSH2_VERSION_ONLY -I. -I ../include $< -o $@
|
||||
@$(RC) $(RCFLAGS) $< -o $@
|
||||
|
||||
|
||||
$(DISTDIR)/readme.txt: Makefile.win32
|
||||
|
@@ -1,7 +1,7 @@
|
||||
|
||||
# Tweak these for your system
|
||||
OPENSSLINC=..\openssl-0.9.8o\inc32
|
||||
OPENSSLLIB=..\openssl-0.9.8o\out32dll
|
||||
OPENSSLINC=..\openssl-0.9.8q\inc32
|
||||
OPENSSLLIB=..\openssl-0.9.8q\out32dll
|
||||
|
||||
ZLIBINC=-DLIBSSH2_HAVE_ZLIB=1 /I..\zlib-1.2.5
|
||||
ZLIBLIB=..\zlib-1.2.5
|
||||
|
@@ -14,7 +14,7 @@ endif
|
||||
|
||||
# Edit the path below to point to the base of your OpenSSL package.
|
||||
ifndef OPENSSL_PATH
|
||||
OPENSSL_PATH = ../../../openssl-0.9.8o
|
||||
OPENSSL_PATH = ../../../openssl-0.9.8q
|
||||
endif
|
||||
|
||||
# Edit the var below to enable static linking of libssh2 and libz
|
||||
|
Reference in New Issue
Block a user