Compare commits

..

93 Commits

Author SHA1 Message Date
Andreas Schneider
f17788adc2 Update ChangeLog. 2013-07-26 08:42:26 +02:00
Andreas Schneider
23e0053a41 BUG 103: Disable proxy command if set to 'none'.
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
2013-07-26 08:42:26 +02:00
Andreas Schneider
b6788f369e client: Fix possible NULL pointer dereference. 2013-07-26 08:42:26 +02:00
Andreas Schneider
4cc4236182 kex: Fix a double free. 2013-07-26 08:42:26 +02:00
milo
21a1c51eef Check for NULL pointers in channels.c 2013-07-26 08:42:26 +02:00
Andreas Schneider
d796de288e cmake: Set application version as package version. 2013-07-26 08:42:26 +02:00
Andreas Schneider
7ba381116d BUG 103: Fix ProxyCommand parsing. 2013-06-02 19:33:57 +02:00
Andreas Schneider
6f59c0534d config: Rename ssh_config_get_str(). 2013-06-02 19:33:57 +02:00
Andreas Schneider
494fb26b01 opts: Fix segfault in option parser. 2013-06-02 19:33:57 +02:00
Andreas Schneider
d0f9320602 cmake: Fix setting -D_FORTIFY_SOURCE=2. 2013-06-02 19:33:56 +02:00
Aris Adamantiadis
5826cb6ab2 poll: return error on poll() when pollset is empty
(cherry picked from commit 222a0d78ca)
2013-02-27 08:07:44 +01:00
Andreas Schneider
bbdef245a1 Update version number to 0.5.5. 2013-02-12 14:30:22 +01:00
Laurent Bigonville
a0d894dd2a server: Fix typo in dh_handshake_server().
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-02-05 21:16:04 +01:00
Andreas Schneider
05d8421290 Update to version 0.5.4. 2013-01-22 11:52:36 +01:00
Andreas Schneider
55b09f4264 CVE-2013-0176: Fix a remote DoS if the client doesn't send a matching kex.
Thanks to Yong Chuan Koh, X-Force Research <kohyc@sg.ibm.com>
2013-01-14 14:38:55 +01:00
Andreas Schneider
f128338132 options: Fix a free crash bug if we parse unknown options.
Thanks to Yong Chuan Koh, X-Force Research <kohyc@sg.ibm.com>
2013-01-11 08:52:27 +01:00
Andreas Schneider
ba231d0844 channels1: Fix severa possible null pointer dereferences.
(cherry picked from commit b811b89f57)
2013-01-10 13:55:12 +01:00
Andreas Schneider
6da817aa47 Update ChangeLog. 2012-11-14 17:56:48 +01:00
Andreas Schneider
05ed61848f cmake: Bump version number. 2012-11-14 17:11:03 +01:00
Andreas Schneider
d63f19c300 CVE-2012-4561: Fix possible free's on invalid pointers. 2012-11-14 17:11:03 +01:00
Andreas Schneider
455da60846 CVE-2012-4561: Fix error handling of try_publickey_from_file(). 2012-11-14 17:11:03 +01:00
Andreas Schneider
46b2eb3c14 CVE-2012-4559: Make sure we don't free name and longname twice on error. 2012-11-14 17:11:03 +01:00
Andreas Schneider
6236001ff4 CVE-2012-4559: Ensure that we don't free req twice. 2012-11-14 17:11:03 +01:00
Andreas Schneider
1471f2c67a CVE-2012-4559: Ensure we don't free blob or request twice. 2012-11-14 17:11:03 +01:00
Andreas Schneider
b485463197 CVE-2012-4560: Fix a write one past the end of 'buf'. 2012-11-14 17:11:03 +01:00
Andreas Schneider
64fca8a7ed CVE-2012-4560: Fix a write one past the end of the 'u' buffer. 2012-11-14 17:11:03 +01:00
Xi Wang
e3d9501b31 CVE-2012-4562: Fix possible string related integer overflows. 2012-11-14 17:11:00 +01:00
Andreas Schneider
1699adfa03 CVE-2012-4562: Fix a possible infinite loop in buffer_reinit().
If needed is bigger than the highest power of two or a which fits in an
integer we will loop forever.
2012-11-14 17:10:57 +01:00
Xi Wang
db81310d71 CVE-2012-4562: Fix multiple integer overflows in buffer-related functions. 2012-11-14 17:10:53 +01:00
Xi Wang
8489521c0d CVE-2012-4562: Fix possible integer overflow in ssh_get_hexa().
No exploit known, but it is better to check the string length.
2012-11-14 17:10:47 +01:00
Andreas Schneider
2ee6282fdd channels: Fix a possible infinite loop if the connection dropped.
This fixes bug #85.
2012-10-22 18:13:53 +02:00
Andreas Schneider
ae218d0d15 channels1: Add missing request_state and set it to accepted.
This fixes bug #88.
2012-10-22 18:06:12 +02:00
Andreas Schneider
26579b2231 auth1: Reset error state to no error.
This fixes bug #89.
2012-10-22 18:06:09 +02:00
Andreas Schneider
04f1d950b9 session: Fix a possible use after free in ssh_free().
We need to cleanup the channels first cause we call ssh_channel_close()
on the channels which still require a working socket and poll context.

Thanks to sh4rm4!
2012-10-22 17:37:50 +02:00
Andreas Schneider
191c0ae2bb doc: Update copyright policy. 2012-10-14 19:58:26 +02:00
Andreas Schneider
5b32f31a31 channel: Fix a possible null pointer dereference.
(cherry picked from commit ceb8072b34)
2012-10-05 11:48:34 +02:00
Andreas Schneider
3eac8e1c18 channels: Fix a possible null pointer dereference.
(cherry picked from commit 656fd60110)
2012-10-05 11:47:35 +02:00
Andreas Schneider
dc8f0cddee getpass: Fix a memory leak in ssh_gets() on error.
(cherry picked from commit 6092596199)
2012-10-05 11:45:47 +02:00
Andreas Schneider
97b263aee9 sftp: Harden sftp_extension_supported() against null pointers.
(cherry picked from commit 22f607649d)
2012-10-05 11:45:28 +02:00
Andreas Schneider
cb53c4f0e1 sftp: Fix a memory on error in sftp_opendir().
(cherry picked from commit b5c4b090da)
2012-10-05 11:45:12 +02:00
Andreas Schneider
0d029e7038 misc: Don't leak memory on ssh_path_expand_escape() on error.
(cherry picked from commit 61d032fc03)
2012-10-05 11:44:50 +02:00
Andreas Schneider
aae725a44c session: Fix a memory leak in ssh_new() on error.
(cherry picked from commit 280ce3fe93)
2012-10-05 11:44:12 +02:00
Werner Koch
0e833d75e6 Fix regression in pre-connected socket setting.
* src/socket.c (ssh_socket_pollcallback): Factor some code out to ...
(ssh_socket_set_connecting): New.
* include/libssh/socket.h (ssh_socket_set_connecting): Add prototype.
* src/client.c (ssh_connect): Use new function for a socket set by
SSH_OPTIONS_FD.

Signed-off-by: Werner Koch <wk@gnupg.org>
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
2012-09-21 09:41:47 +02:00
Andreas Schneider
ae83f77511 build: Fix missing struct in_addr warning.
(cherry picked from commit 782b2e37c6)
2012-07-17 18:17:05 +02:00
Andreas Schneider
4d8420f328 sftp: Fix bug in sftp_mkdir not returning on error.
resolves: #84
(cherry picked from commit a92c97b2e1)
2012-07-17 18:13:03 +02:00
Andreas Schneider
d8f2a793d3 connect: Fix a build warning.
(cherry picked from commit 8b8d9dc83a)
2012-07-17 17:34:50 +02:00
rofl0r
558b53a856 session: Cleanup timeout functions and fix packets termination.
It is possible that we get unrelated packets while waiting for
termination, thus waiting indefinitely. As a workaround we have to
check the user-supplied timeout.
Also cleaned up ssh_blocking_flush, which was using the timeout in a
bogus manner (resetting the timeout after each check).
2012-01-02 12:42:47 +01:00
Andreas Schneider
0764adc82f message: Fix compiler warning.
(cherry picked from commit 2f861a858b)
2012-01-02 09:31:59 +01:00
rofl0r
87fd7d617e message: Handle all unknown global messages.
Reply to unknown global messages as required by the RFC. Therefore
keepalive@openssh.com style messages should get treated in a sane way.
2012-01-01 20:54:09 +01:00
Andreas Schneider
3e83af5f5e keyfiles: Fix build errors with callbacks.
Introduced with the last commit.
2011-09-17 22:59:13 +02:00
Aris Adamantiadis
0dc57fdcf1 Fixes the ssh_log issue on ssh_bind handles.
(cherry picked from commit da954c2c5e)

Conflicts:

	src/keyfiles.c
2011-09-17 22:01:43 +02:00
Andreas Schneider
3799670d01 doc: Fix threading documentation.
(cherry picked from commit 2cc95e1e08)
2011-09-17 21:32:43 +02:00
Aris Adamantiadis
d6390d50bf Fix documentation bug about threading
(cherry picked from commit c84380bad5)
2011-09-17 21:22:20 +02:00
Andreas Schneider
e27b31c9c4 build: Increase version number. 2011-09-16 21:56:19 +02:00
Andreas Schneider
684b7f6a57 build: Updated changelog. 2011-09-16 21:54:39 +02:00
Aris Adamantiadis
b0b2fd768c SSH1: handle exit-status message (channels would not close) 2011-09-15 11:25:11 +02:00
Aris Adamantiadis
9180bfffcd channels: don't send SSH2 packets on SSH1 ! 2011-09-15 11:25:00 +02:00
Aris Adamantiadis
058bb0f4ea SSH1: fix build
(cherry picked from commit 3eece8ac0b)

Conflicts:

	src/channels.c
	src/channels1.c
2011-09-02 23:02:27 +02:00
Aris Adamantiadis
64b125700e channels: replaced bugged lists with ssh_list
(cherry picked from commit 6d8bb956c5)

Conflicts:

	src/channels.c
	src/session.c
2011-09-02 22:59:44 +02:00
Aris Adamantiadis
6f650a61ca poll: resolve use-after-free + inconsistent callbacks call
This code was weird in the first place. I suspect my change will break something else
(probably the appcode that needed it). ssh_poll_ctx_free is not a good
place to send exception callbacks imho.
(cherry picked from commit b5351f2809)
2011-09-02 22:49:22 +02:00
Aris Adamantiadis
d4e95f4653 Channels: increase window size x10
Provides me a 3x performance boost for async sftp, 5x for sync sftp
(on localhost)
(cherry picked from commit 17ae216340)
2011-09-02 22:45:54 +02:00
Andreas Schneider
26be91fb8e channels: Fix bug #52.
(cherry picked from commit a2c94abb92)

Conflicts:
    src/channels.c
2011-09-02 22:45:50 +02:00
Aris Adamantiadis
43a3becf08 unittests:make sftp_dir pass on my laptop
(cherry picked from commit 7363b29427)
2011-09-02 22:25:26 +02:00
Aris Adamantiadis
d127d68b9f scp: Fixed documentation bug #9
(cherry picked from commit 99e6fde751)
2011-09-02 22:24:47 +02:00
rofl0r
730da3e3c2 channels: Fix possible infinite loop in channel_read().
(cherry picked from commit 66188f1af8)
2011-08-29 21:48:09 +02:00
Jonas Jonsson
661722753b sftp: Handle short reads of sftp_async_read().
sftp_async_read() and sftp_async_read_begin() assume that the whole read
will be successful but when this is not the case, the offset will be
wrong.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit d1df255df4)
2011-08-29 10:07:22 +02:00
Andreas Schneider
ac445a1e18 auth: Handle request service timeout in blocking mode.
(cherry picked from commit e5e673bafe)
2011-08-27 00:00:28 +02:00
Andreas Schneider
b7a3d41baf auth: Fix ssh_auth_list() documentation.
The server will not return SSH_AUTH_METHOD_NONE.
(cherry picked from commit 9c376dd913)
2011-08-22 15:04:09 +02:00
Andreas Schneider
096475b356 channels: Fix incorrect return values in ssh_channel_write().
(cherry picked from commit 13227714f2)
2011-08-10 18:37:58 +02:00
rofl0r
d08554dabd session: Fix an infinite loop in the termination callback.
This happened due to the use of the buggy and obsolete timeout
funtions.
(cherry picked from commit 7949f2cdc6)
2011-08-10 18:37:14 +02:00
Andreas Schneider
cbe8f8b760 channels: Handle SSH_AGAIN in channel_open().
(cherry picked from commit 2f87873642)
2011-08-09 23:08:39 +02:00
Mark Riordan
8987bc53e0 Fix "status -5 inflating zlib packet"
Signed-off-by: Mark Riordan <mriordan@ipswitch.com>
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 6c45d6dc01)
2011-08-09 20:13:41 +02:00
Andreas Schneider
39802b31fe build: Set libssh version to 0.5.1. 2011-08-09 14:47:33 +02:00
Andreas Schneider
e5a2aef1bf build: Updated ChangeLog. 2011-08-09 14:46:26 +02:00
Einar Floystad Dorum
edb03bd224 Fixed ssh_scp_write so it works when doing recursive copy
There where two issues with ssh_scp_write:
1) It did not write a status message after the last write and OpenSSH
   would then give up after the write finished.
2) OpenSSH would sometimes write a status message, after near ends write.
   If scp_write didn't handle it, and subsequent status message. The remote
   window would shrink to zero and ssh_channel_write would start returning 0.

Signed-off-by: Einar Floystad Dorum <einarfd@mailthief.com>
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 01c4b713dc)
2011-08-08 15:28:08 +02:00
rofl0r
1204f43ea9 client: Fix another source of endless wait.
(cherry picked from commit 35686b4822)
2011-08-07 12:47:23 +02:00
rofl0r
b542bc9e4e channels: Fix an endless loop in case of a channel_open error.
(cherry picked from commit 7ccd9c31b3)
2011-08-07 12:47:17 +02:00
rofl0r
61a97ccede session: Fix timeout handling.
-2 now means to use the timeout specified in options. It wasn't used
earlier and poll only knows -1 and 0 anyway for special meanings.
(cherry picked from commit af85337f5f)
2011-08-07 12:47:09 +02:00
rofl0r
a1ef27c0b8 channels: Fix checking for fatal errors.
We need this that we don't end up in and infinite poll loop.
(cherry picked from commit 563fbe4de8)

Conflicts:

	src/poll.c
2011-08-07 12:46:47 +02:00
rofl0r
fb8f2cd11b channels: Fix ssh_channel_from_local()
It only worked if the first channel in the list was equivalent to we
were looking for.
(cherry picked from commit 39f962c91e)
2011-08-07 12:46:06 +02:00
rofl0r
1d8a9ddf84 misc: Fix ssh_timeout_update().
(cherry picked from commit c31cac93f3)
2011-08-07 12:45:54 +02:00
Andreas Schneider
bea66b6476 examples: Fix permissions of the file we copy.
Thanks to Baptiste Marchand.
(cherry picked from commit 15ebbad146)
2011-08-03 22:23:51 +02:00
Andreas Schneider
a8111934d5 channels: Set the max packet size to 32768.
(cherry picked from commit 790b62bca5)
2011-08-03 22:20:52 +02:00
Aris Adamantiadis
f201e983b0 Workaround ssh_get_user_home_dir on LDAP users 2011-07-13 12:04:04 +02:00
Andreas Schneider
81332e1e27 build: Fix libssh_threads pkg-config.
(cherry picked from commit 269c9fed354f3a8adbc54fccba6287d5b1f166e3)
2011-06-15 18:26:33 +02:00
Andreas Schneider
ea84f50603 cmake: Added pkg-config support for libssh_treads.
(cherry picked from commit 583a7f933a)
2011-06-14 13:47:51 +02:00
Andreas Schneider
ccc94e7ab6 packet: Don't (de)compress empty buffers.
This fixes bug #50.
(cherry picked from commit fb0f125351)
2011-06-11 13:16:21 +02:00
Aris Adamantiadis
4c05be0c1b Fix compilation without server and sftp modes
(cherry picked from commit 809b3adeba)
2011-06-09 12:16:07 +02:00
Andreas Schneider
a493a90c59 build: Check for ntohll().
This function is available on AIX.
(cherry picked from commit 640e3830f2)
2011-06-06 18:57:50 +02:00
Andreas Schneider
4a18df8574 string: Added missing include.
(cherry picked from commit 3fa801a929)
2011-06-06 18:57:11 +02:00
Andreas Schneider
cfa74c1dc6 string: Added missing errno.
(cherry picked from commit d536cc4f39)
2011-06-06 18:51:12 +02:00
milo
de706de8c3 Check for NULL pointers in string.c
(cherry picked from commit 4230509e80)
2011-06-06 18:50:11 +02:00
Andreas Schneider
71fa0dc6bb cmake: Fix static .lib overwriting on Windows.
(cherry picked from commit 1880ef54d2)
2011-06-01 14:53:29 +02:00
57 changed files with 1185 additions and 455 deletions

View File

@@ -8,7 +8,7 @@ set(APPLICATION_NAME ${PROJECT_NAME})
set(APPLICATION_VERSION_MAJOR "0")
set(APPLICATION_VERSION_MINOR "5")
set(APPLICATION_VERSION_PATCH "0")
set(APPLICATION_VERSION_PATCH "5")
set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}")
@@ -19,7 +19,7 @@ set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINO
# Increment AGE. Set REVISION to 0
# If the source code was changed, but there were no interface changes:
# Increment REVISION.
set(LIBRARY_VERSION "4.2.0")
set(LIBRARY_VERSION "4.2.5")
set(LIBRARY_SOVERSION "4")
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
@@ -78,9 +78,11 @@ add_subdirectory(src)
# pkg-config file
configure_file(libssh.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libssh.pc)
configure_file(libssh_threads.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libssh_threads.pc)
install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/libssh.pc
${CMAKE_CURRENT_BINARY_DIR}/libssh_threads.pc
DESTINATION
${LIB_INSTALL_DIR}/pkgconfig
COMPONENT

View File

@@ -11,9 +11,9 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING")
### versions
set(CPACK_PACKAGE_VERSION_MAJOR "0")
set(CPACK_PACKAGE_VERSION_MINOR "5")
set(CPACK_PACKAGE_VERSION_PATCH "0")
set(CPACK_PACKAGE_VERSION_MAJOR "${APPLICATION_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${APPLICATION_VERSION_MINOR}")
set(CPACK_PACKAGE_VERSION_PATCH "${APPLICATION_VERSION_PATCH}")
set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")

View File

@@ -1,6 +1,63 @@
ChangeLog
==========
version 0.5.5 (released 2013-07-26)
* BUG 103: Fix ProxyCommand parsing.
* Fix setting -D_FORTIFY_SOURCE=2.
* Fix pollset error return if emtpy.
* Fix NULL pointer checks in channel functions.
* Several bugfixes.
version 0.5.4 (released 2013-01-22)
* CVE-2013-0176 - NULL dereference leads to denial of service
* Fixed several NULL pointer dereferences in SSHv1.
* Fixed a free crash bug in options parsing.
version 0.5.3 (released 2012-11-20)
* CVE-2012-4559 Fixed multiple double free() flaws.
* CVE-2012-4560 Fixed multiple buffer overflow flaws.
* CVE-2012-4561 Fixed multiple invalid free() flaws.
* BUG #84 - Fix bug in sftp_mkdir not returning on error.
* BUG #85 - Fixed a possible channel infinite loop if the connection dropped.
* BUG #88 - Added missing channel request_state and set it to accepted.
* BUG #89 - Reset error state to no error on successful SSHv1 authentiction.
* Fixed a possible use after free in ssh_free().
* Fixed multiple possible NULL pointer dereferences.
* Fixed multiple memory leaks in error paths.
* Fixed timeout handling.
* Fixed regression in pre-connected socket setting.
* Handle all unknown global messages.
version 0.5.2 (released 2011-09-17)
* Increased window size x10.
* Fixed SSHv1.
* Fixed bugged lists.
* Fixed use-after-free + inconsistent callbacks call in poll.
* Fixed scp documentation.
* Fixed possible infinite loop in channel_read().
* Fixed handling of short reads of sftp_async_read().
* Fixed handling request service timeout in blocking mode.
* Fixed ssh_auth_list() documentation.
* Fixed incorrect return values in ssh_channel_write().
* Fixed an infinite loop in the termination callback.
* Fixed handling of SSH_AGAIN in channel_open().
* Fixed "status -5 inflating zlib packet"
version 0.5.1 (released 2011-08-09)
* Added checks for NULL pointers in string.c.
* Set the channel max packet size to 32768.
* Don't (de)compress empty buffers.
* Fixed ssh_scp_write so it works when doing recursive copy.
* Fixed another source of endless wait.
* Fixed an endless loop in case of a channel_open error.
* Fixed session timeout handling.
* Fixed ssh_channel_from_local() loop.
* Fixed permissions of scp example when we copy a file.
* Workaround ssh_get_user_home_dir on LDAP users.
* Added pkg-config support for libssh_threads.
* Fixed compilation without server and sftp modes.
* Fix static .lib overwriting on Windows.
version 0.5.0 (released 2011-06-01)
* Added ssh_ prefix to all functions.
* Added complete Windows support.

View File

@@ -119,6 +119,7 @@ if (UNIX)
check_function_exists(select HAVE_SELECT)
check_function_exists(cfmakeraw HAVE_CFMAKERAW)
check_function_exists(regcomp HAVE_REGCOMP)
check_function_exists(ntohll HAVE_NTOHLL)
endif (UNIX)
set(LIBSSH_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} CACHE INTERNAL "libssh required system libraries")

109
README
View File

@@ -55,17 +55,102 @@ ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
5* Copyright policy
-_-_-_-_-_-_-_-_-_-_
The developers of libssh have a policy of asking for contributions to be made
under the personal copyright of the contributor, instead of a corporate
copyright.
libssh is a project with distributed copyright ownership, which means we prefer
the copyright on parts of libssh to be held by individuals rather than
corporations if possible. There are historical legal reasons for this, but one
of the best ways to explain it is that its much easier to work with
individuals who have ownership than corporate legal departments if we ever need
to make reasonable compromises with people using and working with libssh.
There are some reasons for the establishment of this policy:
We track the ownership of every part of libssh via git, our source code control
system, so we know the provenance of every piece of code that is committed to
libssh.
* Individual copyrights make copyright registration in the US a simpler
process.
* If libssh is copyrighted by individuals rather than corporations,
decisions regarding enforcement and protection of copyright will, more
likely, be made in the interests of the project, and not in the interests
of any corporations shareholders.
* If we ever need to relicense a portion of the code contacting individuals
for permission to do so is much easier than contacting a company.
So if possible, if youre doing libssh changes on behalf of a company who
normally owns all the work you do please get them to assign personal copyright
ownership of your changes to you as an individual, that makes things very easy
for us to work with and avoids bringing corporate legal departments into the
picture.
If you cant do this we can still accept patches from you owned by your
employer under a standard employment contract with corporate copyright
ownership. It just requires a simple set-up process first.
We use a process very similar to the way things are done in the Linux Kernel
community, so it should be very easy to get a sign off from your corporate
legal department. The only changes weve made are to accommodate the license we
use, which is LGPLv2 (or later) whereas the Linux kernel uses GPLv2.
The process is called signing.
How to sign your work
----------------------
Once you have permission to contribute to libssh from your employer, simply
email a copy of the following text from your corporate email address to:
contributing@libssh.org
--------------------------------------------------------------------------
libssh Developer's Certificate of Origin. Version 1.0
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the appropriate
version of the GNU General Public License; or
(b) The contribution is based upon previous work that, to the best of
my knowledge, is covered under an appropriate open source license
and I have the right under that license to submit that work with
modifications, whether created in whole or in part by me, under
the GNU General Public License, in the appropriate version; or
(c) The contribution was provided directly to me by some other
person who certified (a) or (b) and I have not modified it.
(d) I understand and agree that this project and the contribution are
public and that a record of the contribution (including all
metadata and personal information I submit with it, including my
sign-off) is maintained indefinitely and may be redistributed
consistent with the libssh Team's policies and the requirements of
the GNU GPL where they are relevant.
(e) I am granting this work to this project under the terms of the
GNU Lesser General Public License as published by the
Free Software Foundation; either version 2.1 of
the License, or (at the option of the project) any later version.
http://www.gnu.org/licenses/lgpl-2.1.html
--------------------------------------------------------------------------
We will maintain a copy of that email as a record that you have the rights to
contribute code to libssh under the required licenses whilst working for the
company where the email came from.
Then when sending in a patch via the normal mechanisms described above, add a
line that states:
Signed-off-by: Random J Developer <random@developer.example.org>
using your real name and the email address you sent the original email you used
to send the libssh Developers Certificate of Origin to us (sorry, no
pseudonyms or anonymous contributions.)
Thats it! Such code can then quite happily contain changes that have copyright
messages such as:
(c) Example Corporation.
and can be merged into the libssh codebase in the same way as patches from any
other individual. You dont need to send in a copy of the libssh Developers
Certificate of Origin for each patch, or inside each patch. Just the sign-off
message is all that is required once weve received the initial email.
Have fun and happy libssh hacking!
The libssh Team

View File

@@ -25,10 +25,15 @@ if (UNIX AND NOT WIN32)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector")
endif (WITH_STACK_PROTECTOR)
check_c_compiler_flag("-D_FORTIFY_SOURCE=2" WITH_FORTIFY_SOURCE)
if (WITH_FORTIFY_SOURCE)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FORTIFY_SOURCE=2")
endif (WITH_FORTIFY_SOURCE)
if (CMAKE_BUILD_TYPE)
string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWER)
if (NOT CMAKE_BUILD_TYPE_LOWER MATCHES debug)
check_c_compiler_flag("-D_FORTIFY_SOURCE=2" WITH_FORTIFY_SOURCE)
if (WITH_FORTIFY_SOURCE)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FORTIFY_SOURCE=2")
endif (WITH_FORTIFY_SOURCE)
endif()
endif()
endif (${CMAKE_C_COMPILER_ID} MATCHES GNU)
#

View File

@@ -80,6 +80,9 @@
/* Define to 1 if you have the `clock_gettime' function. */
#cmakedefine HAVE_CLOCK_GETTIME 1
/* Define to 1 if you have the `ntohll' function. */
#cmakedefine HAVE_NTOHLL 1
/*************************** LIBRARIES ***************************/
/* Define to 1 if you have the `crypto' library (-lcrypto). */

View File

@@ -40,20 +40,105 @@ The libssh library provides:
@section main-copyright Copyright Policy
The developers of libssh have a policy of asking for contributions to be made
under the personal copyright of the contributor, instead of a corporate
copyright.
libssh is a project with distributed copyright ownership, which means we prefer
the copyright on parts of libssh to be held by individuals rather than
corporations if possible. There are historical legal reasons for this, but one
of the best ways to explain it is that its much easier to work with
individuals who have ownership than corporate legal departments if we ever need
to make reasonable compromises with people using and working with libssh.
There are some reasons for the establishment of this policy:
We track the ownership of every part of libssh via git, our source code control
system, so we know the provenance of every piece of code that is committed to
libssh.
@li Individual copyrights make copyright registration in the US a simpler
process.
@li If libssh is copyrighted by individuals rather than corporations,
decisions regarding enforcement and protection of copyright will, more
likely, be made in the interests of the project, and not in the interests
of any corporations shareholders.
@li If we ever need to relicense a portion of the code contacting individuals
for permission to do so is much easier than contacting a company.
So if possible, if youre doing libssh changes on behalf of a company who
normally owns all the work you do please get them to assign personal copyright
ownership of your changes to you as an individual, that makes things very easy
for us to work with and avoids bringing corporate legal departments into the
picture.
If you cant do this we can still accept patches from you owned by your
employer under a standard employment contract with corporate copyright
ownership. It just requires a simple set-up process first.
We use a process very similar to the way things are done in the Linux Kernel
community, so it should be very easy to get a sign off from your corporate
legal department. The only changes weve made are to accommodate the license we
use, which is LGPLv2 (or later) whereas the Linux kernel uses GPLv2.
The process is called signing.
How to sign your work
----------------------
Once you have permission to contribute to libssh from your employer, simply
email a copy of the following text from your corporate email address to:
contributing@libssh.org
@verbatim
libssh Developer's Certificate of Origin. Version 1.0
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the appropriate
version of the GNU General Public License; or
(b) The contribution is based upon previous work that, to the best of
my knowledge, is covered under an appropriate open source license
and I have the right under that license to submit that work with
modifications, whether created in whole or in part by me, under
the GNU General Public License, in the appropriate version; or
(c) The contribution was provided directly to me by some other
person who certified (a) or (b) and I have not modified it.
(d) I understand and agree that this project and the contribution are
public and that a record of the contribution (including all
metadata and personal information I submit with it, including my
sign-off) is maintained indefinitely and may be redistributed
consistent with the libssh Team's policies and the requirements of
the GNU GPL where they are relevant.
(e) I am granting this work to this project under the terms of the
GNU Lesser General Public License as published by the
Free Software Foundation; either version 2.1 of
the License, or (at the option of the project) any later version.
http://www.gnu.org/licenses/lgpl-2.1.html
@endverbatim
We will maintain a copy of that email as a record that you have the rights to
contribute code to libssh under the required licenses whilst working for the
company where the email came from.
Then when sending in a patch via the normal mechanisms described above, add a
line that states:
@verbatim
Signed-off-by: Random J Developer <random@developer.example.org>
@endverbatim
using your real name and the email address you sent the original email you used
to send the libssh Developers Certificate of Origin to us (sorry, no
pseudonyms or anonymous contributions.)
Thats it! Such code can then quite happily contain changes that have copyright
messages such as:
@verbatim
(c) Example Corporation.
@endverbatim
and can be merged into the libssh codebase in the same way as patches from any
other individual. You dont need to send in a copy of the libssh Developers
Certificate of Origin for each patch, or inside each patch. Just the sign-off
message is all that is required once weve received the initial email.
Have fun and happy libssh hacking!
The libssh Team
@section main-rfc Internet standard

View File

@@ -6,16 +6,16 @@ libssh may be used in multithreaded applications, but under several conditions :
- Threading must be initialized during the initialization of libssh. This
initialization must be done outside of any threading context.
- If pthreads is being used by your application (or your framework's backend),
you must link with libssh_threads_pthread dynamic library and initialize
you must link with libssh_threads dynamic library and initialize
threading with the ssh_threads_pthreads threading object.
- If an other threading library is being used by your application, you must
implement all the methods of the ssh_threads_callbacks_struct structure
and initialize libssh with it.
- At all times, you may use different sessions inside threads, make parallel
connections, read/write on different sessions and so on. You can use a
single session in several channels at the same time. This will lead to
internal state corruption. This limitation is being worked out and will
maybe disappear later.
connections, read/write on different sessions and so on. You *cannot* use a
single session (or channels for a single session) in several threads at the same
time. This will most likely lead to internal state corruption. This limitation is
being worked out and will maybe disappear later.
@subsection threads_init Initialization of threads
@@ -25,7 +25,7 @@ use, using ssh_threads_set_callbacks(), then call ssh_init().
@code
#include <libssh/callbacks.h>
...
ssh_threads_set_callbacks(ssh_threads_noop);
ssh_threads_set_callbacks(ssh_threads_get_noop());
ssh_init();
@endcode
@@ -40,14 +40,14 @@ threading backend:
@code
#include <libssh/callbacks.h>
...
ssh_threads_set_callbacks(ssh_threads_pthread);
ssh_threads_set_callbacks(ssh_threads_get_pthread());
ssh_init();
@endcode
However, you must be sure to link with the library ssh_threads_pthread. If
However, you must be sure to link with the library ssh_threads. If
you're using gcc, you must use the commandline
@code
gcc -o output input.c -lssh -lssh_threads_pthread
gcc -o output input.c -lssh -lssh_threads
@endcode

View File

@@ -182,7 +182,7 @@ static int do_copy(struct location *src, struct location *dest, int recursive){
fd=fileno(src->file);
fstat(fd,&s);
size=s.st_size;
mode = s.st_mode & S_IFMT;
mode = s.st_mode & ~S_IFMT;
filename=ssh_basename(src->path);
} else {
size=0;

View File

@@ -23,11 +23,10 @@
#define BIND_H_
#include "libssh/priv.h"
#include "libssh/session.h"
struct ssh_bind_struct {
struct error_struct error;
ssh_callbacks callbacks; /* Callbacks to user functions */
struct ssh_common_struct common; /* stuff common to ssh_bind and ssh_session */
struct ssh_bind_callbacks_struct *bind_callbacks;
void *bind_callbacks_userdata;
@@ -40,8 +39,6 @@ struct ssh_bind_struct {
char *bindaddr;
socket_t bindfd;
unsigned int bindport;
unsigned int log_verbosity;
int blocking;
int toaccept;
};

View File

@@ -48,8 +48,6 @@ enum ssh_channel_state_e {
};
struct ssh_channel_struct {
struct ssh_channel_struct *prev;
struct ssh_channel_struct *next;
ssh_session session; /* SSH_SESSION pointer */
uint32_t local_channel;
uint32_t local_window;
@@ -95,6 +93,7 @@ int channel_write_common(ssh_channel channel, const void *data,
#ifdef WITH_SSH1
SSH_PACKET_CALLBACK(ssh_packet_data1);
SSH_PACKET_CALLBACK(ssh_packet_close1);
SSH_PACKET_CALLBACK(ssh_packet_exist_status1);
/* channels1.c */
int channel_open_session1(ssh_channel channel);
@@ -104,7 +103,7 @@ int channel_change_pty_size1(ssh_channel channel, int cols, int rows);
int channel_request_shell1(ssh_channel channel);
int channel_request_exec1(ssh_channel channel, const char *cmd);
int channel_write1(ssh_channel channel, const void *data, int len);
ssh_channel ssh_get_channel1(ssh_session session);
#endif
#endif /* CHANNELS_H_ */

View File

@@ -79,7 +79,7 @@
/* libssh version */
#define LIBSSH_VERSION_MAJOR 0
#define LIBSSH_VERSION_MINOR 5
#define LIBSSH_VERSION_MICRO 0
#define LIBSSH_VERSION_MICRO 5
#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \
LIBSSH_VERSION_MINOR, \

View File

@@ -58,6 +58,7 @@ struct ssh_timestamp {
struct ssh_list *ssh_list_new(void);
void ssh_list_free(struct ssh_list *list);
struct ssh_iterator *ssh_list_get_iterator(const struct ssh_list *list);
struct ssh_iterator *ssh_list_find(const struct ssh_list *list, void *value);
int ssh_list_append(struct ssh_list *list, const void *data);
int ssh_list_prepend(struct ssh_list *list, const void *data);
void ssh_list_remove(struct ssh_list *list, struct ssh_iterator *iterator);
@@ -77,6 +78,7 @@ const void *_ssh_list_pop_head(struct ssh_list *list);
#define ssh_list_pop_head(type, ssh_list)\
((type)_ssh_list_pop_head(ssh_list))
int ssh_make_milliseconds(long sec, long usec);
void ssh_timestamp_init(struct ssh_timestamp *ts);
int ssh_timeout_elapsed(struct ssh_timestamp *ts, int timeout);
int ssh_timeout_update(struct ssh_timestamp *ts, int timeout);

View File

@@ -133,6 +133,7 @@ struct ssh_keys_struct {
};
struct ssh_message_struct;
struct ssh_common_struct;
/* server data */
@@ -208,6 +209,9 @@ int match_hostname(const char *host, const char *pattern, unsigned int len);
int message_handle(ssh_session session, void *user, uint8_t type, ssh_buffer packet);
/* log.c */
void ssh_log_common(struct ssh_common_struct *common, int verbosity,
const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
/* misc.c */
#ifdef _WIN32
int gettimeofday(struct timeval *__p, void *__t);
@@ -221,16 +225,16 @@ int gettimeofday(struct timeval *__p, void *__t);
#define _enter_function(sess) \
do {\
if((sess)->log_verbosity >= SSH_LOG_FUNCTIONS){ \
if((sess)->common.log_verbosity >= SSH_LOG_FUNCTIONS){ \
ssh_log((sess),SSH_LOG_FUNCTIONS,"entering function %s line %d in " __FILE__ , __FUNCTION__,__LINE__);\
(sess)->log_indent++; \
(sess)->common.log_indent++; \
} \
} while(0)
#define _leave_function(sess) \
do { \
if((sess)->log_verbosity >= SSH_LOG_FUNCTIONS){ \
(sess)->log_indent--; \
if((sess)->common.log_verbosity >= SSH_LOG_FUNCTIONS){ \
(sess)->common.log_indent--; \
ssh_log((sess),SSH_LOG_FUNCTIONS,"leaving function %s line %d in " __FILE__ , __FUNCTION__,__LINE__);\
}\
} while(0)

View File

@@ -61,8 +61,16 @@ enum ssh_pending_call_e {
/* libssh calls may block an undefined amount of time */
#define SSH_SESSION_FLAG_BLOCKING 1
struct ssh_session_struct {
/* members that are common to ssh_session and ssh_bind */
struct ssh_common_struct {
struct error_struct error;
ssh_callbacks callbacks; /* Callbacks to user functions */
int log_verbosity; /* verbosity of the log functions */
int log_indent; /* indentation level in enter_function logs */
};
struct ssh_session_struct {
struct ssh_common_struct common;
struct ssh_socket_struct *socket;
char *serverbanner;
char *clientbanner;
@@ -110,7 +118,7 @@ struct ssh_session_struct {
struct ssh_crypto_struct *current_crypto;
struct ssh_crypto_struct *next_crypto; /* next_crypto is going to be used after a SSH2_MSG_NEWKEYS */
ssh_channel channels; /* linked list of channels */
struct ssh_list *channels; /* linked list of channels */
int maxchannel;
int exec_channel_opened; /* version 1 only. more
info in channels1.c */
@@ -128,11 +136,8 @@ struct ssh_session_struct {
struct ssh_list *ssh_message_list; /* list of delayed SSH messages */
int (*ssh_message_callback)( struct ssh_session_struct *session, ssh_message msg, void *userdata);
void *ssh_message_callback_data;
int log_verbosity; /*cached copy of the option structure */
int log_indent; /* indentation level in enter_function logs */
void (*ssh_connection_callback)( struct ssh_session_struct *session);
ssh_callbacks callbacks; /* Callbacks to user functions */
struct ssh_packet_callbacks_struct default_packet_callbacks;
struct ssh_list *packet_callbacks;
struct ssh_socket_callbacks_struct socket_callbacks;

View File

@@ -62,6 +62,7 @@ int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int r
struct ssh_poll_handle_struct * ssh_socket_get_poll_handle_in(ssh_socket s);
struct ssh_poll_handle_struct * ssh_socket_get_poll_handle_out(ssh_socket s);
void ssh_socket_set_connecting(ssh_socket s, socket_t fd);
int ssh_socket_connect(ssh_socket s, const char *host, int port, const char *bind_addr);
#endif /* SOCKET_H_ */

5
libssh_threads.pc.cmake Normal file
View File

@@ -0,0 +1,5 @@
Name: ${APPLICATION_NAME}_threads
Description: The SSH Library Thread Extension
Version: ${APPLICATION_VERSION}
Libs: -L${LIB_INSTALL_DIR} -lssh_threads
Cflags: -I${INCLUDE_INSTALL_DIR}

View File

@@ -184,6 +184,11 @@ install(
if (WITH_STATIC_LIB)
add_library(${LIBSSH_STATIC_LIBRARY} STATIC ${libssh_SRCS})
if (MSVC)
set(OUTPUT_SUFFIX static)
else (MSVC)
set(OUTPUT_SUFFIX )
endif (MSVC)
set_target_properties(
${LIBSSH_STATIC_LIBRARY}
PROPERTIES
@@ -193,6 +198,8 @@ if (WITH_STATIC_LIB)
${LIBRARY_SOVERSION}
OUTPUT_NAME
ssh
ARCHIVE_OUTPUT_DIRECTORY
${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_SUFFIX}
)
if (WIN32)
@@ -208,7 +215,7 @@ if (WITH_STATIC_LIB)
TARGETS
${LIBSSH_STATIC_LIBRARY}
DESTINATION
${LIB_INSTALL_DIR}
${LIB_INSTALL_DIR}/${OUTPUT_SUFFIX}
COMPONENT
libraries
)

View File

@@ -44,6 +44,7 @@
#include <unistd.h>
#ifndef _WIN32
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
@@ -438,6 +439,7 @@ ssh_string agent_sign_data(struct ssh_session_struct *session,
}
ssh_string_free(blob);
blob = NULL;
reply = ssh_buffer_new();
if (reply == NULL) {
@@ -450,6 +452,7 @@ ssh_string agent_sign_data(struct ssh_session_struct *session,
return NULL;
}
ssh_buffer_free(request);
request = NULL;
/* check if reply is valid */
if (buffer_get_u8(reply, (uint8_t *) &type) != sizeof(uint8_t)) {

View File

@@ -27,6 +27,7 @@
#include <string.h>
#ifndef _WIN32
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
@@ -62,23 +63,28 @@
* again is necessary
*/
static int ask_userauth(ssh_session session) {
int rc = 0;
int rc = 0;
enter_function();
do {
rc=ssh_service_request(session,"ssh-userauth");
if(ssh_is_blocking(session)){
if(rc==SSH_AGAIN)
ssh_handle_packets(session,-1);
} else {
/* nonblocking */
ssh_handle_packets(session,0);
rc=ssh_service_request(session,"ssh-userauth");
break;
}
} while(rc==SSH_AGAIN);
leave_function();
return rc;
enter_function();
do {
rc = ssh_service_request(session,"ssh-userauth");
if (ssh_is_blocking(session)) {
if (rc == SSH_AGAIN) {
int err = ssh_handle_packets(session, -2);
if (err != SSH_OK) {
/* error or timeout */
return SSH_ERROR;
}
}
} else {
/* nonblocking */
ssh_handle_packets(session, 0);
rc = ssh_service_request(session, "ssh-userauth");
break;
}
} while (rc == SSH_AGAIN);
leave_function();
return rc;
}
/**
@@ -254,7 +260,7 @@ static int wait_auth_status(ssh_session session) {
enter_function();
if(ssh_is_blocking(session)){
if(ssh_handle_packets_termination(session,-1,auth_status_termination,
if(ssh_handle_packets_termination(session, -2, auth_status_termination,
session) == SSH_ERROR){
leave_function();
return SSH_AUTH_ERROR;
@@ -309,7 +315,7 @@ int ssh_auth_list(ssh_session session) {
* @brief retrieves available authentication methods for this session
* @param[in] session the SSH session
* @param[in] username Deprecated, set to NULL.
* @returns A bitfield of values SSH_AUTH_METHOD_NONE, SSH_AUTH_METHOD_PASSWORD,
* @returns A bitfield of values SSH_AUTH_METHOD_PASSWORD,
SSH_AUTH_METHOD_PUBLICKEY, SSH_AUTH_METHOD_HOSTBASED,
SSH_AUTH_METHOD_INTERACTIVE.
@warning Other reserved flags may appear in future versions.

View File

@@ -38,7 +38,7 @@ static int wait_auth1_status(ssh_session session) {
enter_function();
/* wait for a packet */
while(session->auth_state == SSH_AUTH_STATE_NONE)
if (ssh_handle_packets(session,-1) != SSH_OK)
if (ssh_handle_packets(session, -2) != SSH_OK)
break;
ssh_log(session,SSH_LOG_PROTOCOL,"Auth state : %d",session->auth_state);
leave_function();
@@ -108,6 +108,7 @@ static int send_username(ssh_session session, const char *username) {
if(wait_auth1_status(session) == SSH_AUTH_SUCCESS){
session->auth_service_state=SSH_AUTH_SERVICE_USER_SENT;
session->auth_state=SSH_AUTH_STATE_SUCCESS;
ssh_set_error(session, SSH_NO_ERROR, "Authentication successful");
return SSH_AUTH_SUCCESS;
} else {
session->auth_service_state=SSH_AUTH_SERVICE_USER_SENT;

View File

@@ -150,7 +150,7 @@ ssh_bind ssh_bind_new(void) {
ZERO_STRUCTP(ptr);
ptr->bindfd = SSH_INVALID_SOCKET;
ptr->bindport= 22;
ptr->log_verbosity = 0;
ptr->common.log_verbosity = 0;
return ptr;
}
@@ -359,7 +359,7 @@ int ssh_bind_accept(ssh_bind sshbind, ssh_session session) {
}
}
session->log_verbosity = sshbind->log_verbosity;
session->common.log_verbosity = sshbind->common.log_verbosity;
ssh_socket_free(session->socket);
session->socket = ssh_socket_new(session);
@@ -375,7 +375,7 @@ int ssh_bind_accept(ssh_bind sshbind, ssh_session session) {
session->dsa_key = dsa;
session->rsa_key = rsa;
return SSH_OK;
return SSH_OK;
}

View File

@@ -21,10 +21,12 @@
* MA 02111-1307, USA.
*/
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#ifndef _WIN32
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
@@ -109,13 +111,18 @@ void ssh_buffer_free(struct ssh_buffer_struct *buffer) {
SAFE_FREE(buffer);
}
static int realloc_buffer(struct ssh_buffer_struct *buffer, int needed) {
int smallest = 1;
char *new = NULL;
static int realloc_buffer(struct ssh_buffer_struct *buffer, size_t needed) {
size_t smallest = 1;
char *new;
buffer_verify(buffer);
/* Find the smallest power of two which is greater or equal to needed */
while(smallest <= needed) {
smallest <<= 1;
if (smallest == 0) {
return -1;
}
smallest <<= 1;
}
needed = smallest;
new = realloc(buffer->data, needed);
@@ -180,6 +187,10 @@ int buffer_reinit(struct ssh_buffer_struct *buffer) {
*/
int buffer_add_data(struct ssh_buffer_struct *buffer, const void *data, uint32_t len) {
buffer_verify(buffer);
if (buffer->used + len < len)
return -1;
if (buffer->allocated < (buffer->used + len)) {
if(buffer->pos > 0)
buffer_shift(buffer);
@@ -318,6 +329,8 @@ int buffer_prepend_data(struct ssh_buffer_struct *buffer, const void *data,
return 0;
}
/* pos isn't high enough */
if (buffer->used - buffer->pos + len < len)
return -1;
if (buffer->allocated < (buffer->used - buffer->pos + len)) {
if (realloc_buffer(buffer, buffer->used - buffer->pos + len) < 0) {
return -1;
@@ -429,7 +442,7 @@ uint32_t buffer_get_rest_len(struct ssh_buffer_struct *buffer){
*/
uint32_t buffer_pass_bytes(struct ssh_buffer_struct *buffer, uint32_t len){
buffer_verify(buffer);
if(buffer->used < buffer->pos+len)
if (buffer->pos + len < len || buffer->used < buffer->pos + len)
return 0;
buffer->pos+=len;
/* if the buffer is empty after having passed the whole bytes into it, we can clean it */
@@ -454,8 +467,11 @@ uint32_t buffer_pass_bytes(struct ssh_buffer_struct *buffer, uint32_t len){
*/
uint32_t buffer_pass_bytes_end(struct ssh_buffer_struct *buffer, uint32_t len){
buffer_verify(buffer);
if(buffer->used < buffer->pos + len)
return 0;
if (buffer->used < len) {
return 0;
}
buffer->used-=len;
buffer_verify(buffer);
return len;
@@ -548,7 +564,7 @@ struct ssh_string_struct *buffer_get_ssh_string(struct ssh_buffer_struct *buffer
}
hostlen = ntohl(stringlen);
/* verify if there is enough space in buffer to get it */
if ((buffer->pos + hostlen) > buffer->used) {
if (buffer->pos + hostlen < hostlen || buffer->pos + hostlen > buffer->used) {
return NULL; /* it is indeed */
}
str = ssh_string_new(hostlen);
@@ -585,7 +601,7 @@ struct ssh_string_struct *buffer_get_mpint(struct ssh_buffer_struct *buffer) {
}
bits = ntohs(bits);
len = (bits + 7) / 8;
if ((buffer->pos + len) > buffer->used) {
if (buffer->pos + len < len || buffer->pos + len > buffer->used) {
return NULL;
}
str = ssh_string_new(len);

View File

@@ -37,7 +37,7 @@ int ssh_set_callbacks(ssh_session session, ssh_callbacks cb) {
leave_function();
return SSH_ERROR;
}
session->callbacks = cb;
session->common.callbacks = cb;
leave_function();
return 0;
}

View File

@@ -22,6 +22,7 @@
* MA 02111-1307, USA.
*/
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
@@ -29,6 +30,7 @@
#include <time.h>
#ifndef _WIN32
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
@@ -45,9 +47,17 @@
#include "libssh/server.h"
#endif
#define WINDOWBASE 128000
#define WINDOWBASE 1280000
#define WINDOWLIMIT (WINDOWBASE/2)
/*
* All implementations MUST be able to process packets with an
* uncompressed payload length of 32768 bytes or less and a total packet
* size of 35000 bytes or less.
*/
#define CHANNEL_MAX_PACKET 32768
#define CHANNEL_INITIAL_WINDOW 64000
/**
* @defgroup libssh_channel The SSH channel functions
* @ingroup libssh
@@ -69,6 +79,10 @@ static ssh_channel channel_from_msg(ssh_session session, ssh_buffer packet);
ssh_channel ssh_channel_new(ssh_session session) {
ssh_channel channel = NULL;
if(session == NULL) {
return NULL;
}
channel = malloc(sizeof(struct ssh_channel_struct));
if (channel == NULL) {
ssh_set_error_oom(session);
@@ -96,15 +110,9 @@ ssh_channel ssh_channel_new(ssh_session session) {
channel->exit_status = -1;
if(session->channels == NULL) {
session->channels = channel;
channel->next = channel->prev = channel;
return channel;
session->channels = ssh_list_new();
}
channel->next = session->channels;
channel->prev = session->channels->prev;
channel->next->prev = channel;
channel->prev->next = channel;
ssh_list_prepend(session->channels, channel);
return channel;
}
@@ -284,7 +292,14 @@ static int channel_open(ssh_channel channel, const char *type_c, int window,
/* Todo: fix this into a correct loop */
/* wait until channel is opened by server */
while(channel->state == SSH_CHANNEL_STATE_NOT_OPEN){
ssh_handle_packets(session,-1);
err = ssh_handle_packets(session, -2);
if (err != SSH_OK) {
break;
}
if (session->session_state == SSH_SESSION_STATE_ERROR) {
err = SSH_ERROR;
break;
}
}
if(channel->state == SSH_CHANNEL_STATE_OPEN)
err=SSH_OK;
@@ -292,24 +307,22 @@ static int channel_open(ssh_channel channel, const char *type_c, int window,
return err;
}
/* get ssh channel from local session? */
/* return channel with corresponding local id, or NULL if not found */
ssh_channel ssh_channel_from_local(ssh_session session, uint32_t id) {
ssh_channel initchan = session->channels;
struct ssh_iterator *it;
ssh_channel channel;
/* We assume we are always the local */
if (initchan == NULL) {
return NULL;
}
for (channel = initchan; channel->local_channel != id;
channel=channel->next) {
if (channel->next == initchan) {
return NULL;
for (it = ssh_list_get_iterator(session->channels); it != NULL ; it=it->next) {
channel = ssh_iterator_value(ssh_channel, it);
if (channel == NULL) {
continue;
}
if (channel->local_channel == id) {
return channel;
}
}
return channel;
return NULL;
}
/**
@@ -323,6 +336,13 @@ static int grow_window(ssh_session session, ssh_channel channel, int minimumsize
uint32_t new_window = minimumsize > WINDOWBASE ? minimumsize : WINDOWBASE;
enter_function();
#ifdef WITH_SSH1
if (session->version == 1){
channel->remote_window = new_window;
leave_function();
return SSH_OK;
}
#endif
if(new_window <= channel->local_window){
ssh_log(session,SSH_LOG_PROTOCOL,
"growing window (channel %d:%d) to %d bytes : not needed (%d bytes)",
@@ -383,7 +403,7 @@ static ssh_channel channel_from_msg(ssh_session session, ssh_buffer packet) {
#ifdef WITH_SSH1
/* With SSH1, the channel is always the first one */
if(session->version==1)
return session->channels;
return ssh_get_channel1(session);
#endif
if (buffer_get_u32(packet, &chan) != sizeof(uint32_t)) {
ssh_set_error(session, SSH_FATAL,
@@ -871,13 +891,21 @@ int channel_default_bufferize(ssh_channel channel, void *data, int len,
* @see channel_request_exec()
*/
int ssh_channel_open_session(ssh_channel channel) {
if(channel == NULL) {
return SSH_ERROR;
}
#ifdef WITH_SSH1
if (channel->session->version == 1) {
return channel_open_session1(channel);
}
#endif
return channel_open(channel,"session",64000,32000,NULL);
return channel_open(channel,
"session",
CHANNEL_INITIAL_WINDOW,
CHANNEL_MAX_PACKET,
NULL);
}
/**
@@ -914,7 +942,6 @@ int ssh_channel_open_forward(ssh_channel channel, const char *remotehost,
}
session = channel->session;
enter_function();
if(remotehost == NULL || sourcehost == NULL) {
@@ -952,7 +979,11 @@ int ssh_channel_open_forward(ssh_channel channel, const char *remotehost,
goto error;
}
rc = channel_open(channel, "direct-tcpip", 64000, 32000, payload);
rc = channel_open(channel,
"direct-tcpip",
CHANNEL_INITIAL_WINDOW,
CHANNEL_MAX_PACKET,
payload);
error:
ssh_buffer_free(payload);
@@ -971,31 +1002,24 @@ error:
* @warning Any data unread on this channel will be lost.
*/
void ssh_channel_free(ssh_channel channel) {
ssh_session session = channel->session;
enter_function();
ssh_session session;
struct ssh_iterator *it;
if (channel == NULL) {
leave_function();
return;
}
session = channel->session;
enter_function();
if (session->alive && channel->state == SSH_CHANNEL_STATE_OPEN) {
ssh_channel_close(channel);
}
/* handle the "my channel is first on session list" case */
if (session->channels == channel) {
session->channels = channel->next;
it = ssh_list_find(session->channels, channel);
if(it != NULL){
ssh_list_remove(session->channels, it);
}
/* handle the "my channel is the only on session list" case */
if (channel->next == channel) {
session->channels = NULL;
} else {
channel->prev->next = channel->next;
channel->next->prev = channel->prev;
}
ssh_buffer_free(channel->stdout_buffer);
ssh_buffer_free(channel->stderr_buffer);
@@ -1019,9 +1043,14 @@ void ssh_channel_free(ssh_channel channel) {
* @see channel_free()
*/
int ssh_channel_send_eof(ssh_channel channel){
ssh_session session = channel->session;
ssh_session session;
int rc = SSH_ERROR;
if(channel == NULL) {
return rc;
}
session = channel->session;
enter_function();
if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_EOF) < 0) {
@@ -1063,9 +1092,14 @@ error:
* @see channel_eof()
*/
int ssh_channel_close(ssh_channel channel){
ssh_session session = channel->session;
ssh_session session;
int rc = 0;
if(channel == NULL) {
return SSH_ERROR;
}
session = channel->session;
enter_function();
if (channel->local_eof == 0) {
@@ -1105,9 +1139,11 @@ error:
int channel_write_common(ssh_channel channel, const void *data,
uint32_t len, int is_stderr) {
ssh_session session;
int origlen = len;
uint32_t origlen = len;
size_t effectivelen;
size_t maxpacketlen;
int timeout;
int rc;
if(channel == NULL || data == NULL) {
return -1;
@@ -1118,8 +1154,21 @@ int channel_write_common(ssh_channel channel, const void *data,
return -1;
}
enter_function();
if (len > INT_MAX) {
ssh_log(session, SSH_LOG_PROTOCOL,
"Length (%u) is bigger than INT_MAX", len);
return SSH_ERROR;
}
if(channel == NULL || data == NULL) {
return -1;
}
session = channel->session;
enter_function();
if(ssh_is_blocking(session))
timeout = -2;
else
timeout = 0;
/*
* Handle the max packet len from remote side, be nice
* 10 bytes for the headers
@@ -1143,7 +1192,7 @@ int channel_write_common(ssh_channel channel, const void *data,
#ifdef WITH_SSH1
if (channel->version == 1) {
int rc = channel_write1(channel, data, len);
rc = channel_write1(channel, data, len);
leave_function();
return rc;
}
@@ -1160,7 +1209,10 @@ int channel_write_common(ssh_channel channel, const void *data,
/* nothing can be written */
ssh_log(session, SSH_LOG_PROTOCOL,
"Wait for a growing window message...");
return 0;
rc = ssh_handle_packets(session, timeout);
if (rc == SSH_ERROR || (channel->remote_window == 0 && timeout==0))
goto out;
continue;
}
effectivelen = len > channel->remote_window ? channel->remote_window : len;
} else {
@@ -1199,9 +1251,16 @@ int channel_write_common(ssh_channel channel, const void *data,
len -= effectivelen;
data = ((uint8_t*)data + effectivelen);
}
/* it's a good idea to flush the socket now */
do {
rc = ssh_handle_packets(session, timeout);
} while(rc == SSH_OK &&
timeout != 0 &&
ssh_socket_buffered_write_bytes(session->socket) > 0);
out:
leave_function();
return origlen;
return (int)(origlen - len);
error:
buffer_reinit(session->out_buffer);
@@ -1379,6 +1438,7 @@ static int channel_request(ssh_channel channel, const char *request,
buffer_add_ssh_string(session->out_buffer, req) < 0 ||
buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1) < 0) {
ssh_set_error_oom(session);
ssh_string_free(req);
goto error;
}
ssh_string_free(req);
@@ -1404,7 +1464,12 @@ static int channel_request(ssh_channel channel, const char *request,
return SSH_OK;
}
while(channel->request_state == SSH_CHANNEL_REQ_STATE_PENDING){
ssh_handle_packets(session,-1);
ssh_handle_packets(session, -2);
if(session->session_state == SSH_SESSION_STATE_ERROR) {
channel->request_state = SSH_CHANNEL_REQ_STATE_ERROR;
break;
}
}
/* we received something */
switch (channel->request_state){
@@ -1433,7 +1498,6 @@ static int channel_request(ssh_channel channel, const char *request,
return rc;
error:
buffer_reinit(session->out_buffer);
ssh_string_free(req);
leave_function();
return rc;
@@ -1454,11 +1518,16 @@ error:
*/
int ssh_channel_request_pty_size(ssh_channel channel, const char *terminal,
int col, int row) {
ssh_session session = channel->session;
ssh_session session;
ssh_string term = NULL;
ssh_buffer buffer = NULL;
int rc = SSH_ERROR;
if (channel == NULL) {
return SSH_ERROR;
}
session = channel->session;
enter_function();
#ifdef WITH_SSH1
if (channel->version==1) {
@@ -1721,7 +1790,7 @@ static ssh_channel ssh_channel_accept(ssh_session session, int channeltype,
for (t = timeout_ms; t >= 0; t -= 50)
{
ssh_handle_packets(session,50);
ssh_handle_packets(session, 50);
if (session->ssh_message_list) {
iterator = ssh_list_get_iterator(session->ssh_message_list);
@@ -1878,7 +1947,7 @@ static int global_request(ssh_session session, const char *request,
return SSH_OK;
}
while(session->global_req_state == SSH_CHANNEL_REQ_STATE_PENDING){
rc=ssh_handle_packets(session,-1);
rc=ssh_handle_packets(session, -2);
if(rc==SSH_ERROR){
session->global_req_state = SSH_CHANNEL_REQ_STATE_ERROR;
break;
@@ -2231,11 +2300,16 @@ error:
*/
int channel_read_buffer(ssh_channel channel, ssh_buffer buffer, uint32_t count,
int is_stderr) {
ssh_session session=channel->session;
ssh_session session;
char buffer_tmp[8192];
int r;
uint32_t total=0;
if (channel == NULL) {
return SSH_ERROR;
}
session = channel->session;
enter_function();
buffer_reinit(buffer);
if(count==0){
@@ -2262,7 +2336,7 @@ int channel_read_buffer(ssh_channel channel, ssh_buffer buffer, uint32_t count,
leave_function();
return 0;
}
ssh_handle_packets(channel->session, -1);
ssh_handle_packets(channel->session, -2);
} while (r == 0);
}
while(total < count){
@@ -2312,6 +2386,7 @@ int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_std
ssh_session session = channel->session;
ssh_buffer stdbuf = channel->stdout_buffer;
uint32_t len;
int rc;
enter_function();
@@ -2360,7 +2435,10 @@ int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_std
break;
}
ssh_handle_packets(session,-1);
rc = ssh_handle_packets(session, -2);
if (rc != SSH_OK) {
return rc;
}
}
len = buffer_get_rest_len(stdbuf);
@@ -2450,7 +2528,7 @@ int ssh_channel_poll(ssh_channel channel, int is_stderr){
}
if (buffer_get_rest_len(stdbuf) == 0 && channel->remote_eof == 0) {
if (ssh_handle_packets(channel->session,0)==SSH_ERROR) {
if (ssh_handle_packets(channel->session, 0)==SSH_ERROR) {
leave_function();
return SSH_ERROR;
}
@@ -2497,7 +2575,7 @@ int ssh_channel_get_exit_status(ssh_channel channel) {
while ((channel->remote_eof == 0 || channel->exit_status == -1) && channel->session->alive) {
/* Parse every incoming packet */
if (ssh_handle_packets(channel->session,-1) != SSH_OK) {
if (ssh_handle_packets(channel->session, -2) != SSH_OK) {
return -1;
}
/* XXX We should actually wait for a close packet and not a close
@@ -2532,7 +2610,7 @@ static int channel_protocol_select(ssh_channel *rchans, ssh_channel *wchans,
chan = rchans[i];
while (ssh_channel_is_open(chan) && ssh_socket_data_available(chan->session->socket)) {
ssh_handle_packets(chan->session,-1);
ssh_handle_packets(chan->session, -2);
}
if ((chan->stdout_buffer && buffer_get_rest_len(chan->stdout_buffer) > 0) ||
@@ -2766,11 +2844,17 @@ int ssh_channel_write_stderr(ssh_channel channel, const void *data, uint32_t len
*/
int ssh_channel_open_reverse_forward(ssh_channel channel, const char *remotehost,
int remoteport, const char *sourcehost, int localport) {
ssh_session session = channel->session;
ssh_session session;
ssh_buffer payload = NULL;
ssh_string str = NULL;
int rc = SSH_ERROR;
if(channel == NULL) {
return rc;
}
session = channel->session;
enter_function();
payload = ssh_buffer_new();
@@ -2803,7 +2887,11 @@ int ssh_channel_open_reverse_forward(ssh_channel channel, const char *remotehost
goto error;
}
rc = channel_open(channel, "forwarded-tcpip", 64000, 32000, payload);
rc = channel_open(channel,
"forwarded-tcpip",
CHANNEL_INITIAL_WINDOW,
CHANNEL_MAX_PACKET,
payload);
error:
ssh_buffer_free(payload);
@@ -2830,6 +2918,10 @@ int ssh_channel_request_send_exit_status(ssh_channel channel, int exit_status) {
ssh_buffer buffer = NULL;
int rc = SSH_ERROR;
if(channel == NULL) {
return SSH_ERROR;
}
#ifdef WITH_SSH1
if (channel->version == 1) {
return SSH_ERROR; // TODO: Add support for SSH-v1 if possible.
@@ -2872,7 +2964,8 @@ error:
* @return SSH_OK on success, SSH_ERROR if an error occured
* (including attempts to send signal via SSH-v1 session).
*/
int ssh_channel_request_send_exit_signal(ssh_channel channel, const char *sig, int core, const char *errmsg, const char *lang) {
int ssh_channel_request_send_exit_signal(ssh_channel channel, const char *sig,
int core, const char *errmsg, const char *lang) {
ssh_buffer buffer = NULL;
ssh_string tmp = NULL;
int rc = SSH_ERROR;

View File

@@ -36,6 +36,7 @@
#include "libssh/packet.h"
#include "libssh/channels.h"
#include "libssh/session.h"
#include "libssh/misc.h"
#ifdef WITH_SSH1
@@ -49,11 +50,17 @@
*/
int channel_open_session1(ssh_channel chan) {
ssh_session session;
if (chan == NULL) {
return -1;
}
session = chan->session;
/*
* We guess we are requesting an *exec* channel. It can only have one exec
* channel. So we abort with an error if we need more than one.
*/
ssh_session session = chan->session;
if (session->exec_channel_opened) {
ssh_set_error(session, SSH_REQUEST_DENIED,
"SSH1 supports only one execution channel. "
@@ -61,6 +68,7 @@ int channel_open_session1(ssh_channel chan) {
return -1;
}
session->exec_channel_opened = 1;
chan->request_state = SSH_CHANNEL_REQ_STATE_ACCEPTED;
chan->state = SSH_CHANNEL_STATE_OPEN;
chan->local_maxpacket = 32000;
chan->local_window = 64000;
@@ -83,8 +91,14 @@ int channel_open_session1(ssh_channel chan) {
int channel_request_pty_size1(ssh_channel channel, const char *terminal, int col,
int row) {
ssh_session session = channel->session;
ssh_session session;
ssh_string str = NULL;
if (channel == NULL) {
return SSH_ERROR;
}
session = channel->session;
if(channel->request_state != SSH_CHANNEL_REQ_STATE_NONE){
ssh_set_error(session,SSH_REQUEST_DENIED,"Wrong request state");
return SSH_ERROR;
@@ -137,7 +151,13 @@ int channel_request_pty_size1(ssh_channel channel, const char *terminal, int col
}
int channel_change_pty_size1(ssh_channel channel, int cols, int rows) {
ssh_session session = channel->session;
ssh_session session;
if (channel == NULL) {
return SSH_ERROR;
}
session = channel->session;
if(channel->request_state != SSH_CHANNEL_REQ_STATE_NONE){
ssh_set_error(session,SSH_REQUEST_DENIED,"Wrong request state");
return SSH_ERROR;
@@ -180,7 +200,12 @@ int channel_change_pty_size1(ssh_channel channel, int cols, int rows) {
}
int channel_request_shell1(ssh_channel channel) {
ssh_session session = channel->session;
ssh_session session;
if (channel == NULL) {
return -1;
}
session = channel->session;
if (buffer_add_u8(session->out_buffer,SSH_CMSG_EXEC_SHELL) < 0) {
return -1;
@@ -196,9 +221,14 @@ int channel_request_shell1(ssh_channel channel) {
}
int channel_request_exec1(ssh_channel channel, const char *cmd) {
ssh_session session = channel->session;
ssh_session session;
ssh_string command = NULL;
if (channel == NULL) {
return -1;
}
session = channel->session;
command = ssh_string_from_char(cmd);
if (command == NULL) {
return -1;
@@ -221,10 +251,15 @@ int channel_request_exec1(ssh_channel channel, const char *cmd) {
}
SSH_PACKET_CALLBACK(ssh_packet_data1){
ssh_channel channel = session->channels;
ssh_channel channel = ssh_get_channel1(session);
ssh_string str = NULL;
int is_stderr=(type==SSH_SMSG_STDOUT_DATA ? 0 : 1);
(void)user;
if (channel == NULL) {
return SSH_PACKET_NOT_USED;
}
str = buffer_get_ssh_string(packet);
if (str == NULL) {
ssh_log(session, SSH_LOG_FUNCTIONS, "Invalid data packet !\n");
@@ -246,10 +281,16 @@ SSH_PACKET_CALLBACK(ssh_packet_data1){
}
SSH_PACKET_CALLBACK(ssh_packet_close1){
ssh_channel channel = session->channels;
ssh_channel channel = ssh_get_channel1(session);
uint32_t status;
(void)type;
(void)user;
if (channel == NULL) {
return SSH_PACKET_NOT_USED;
}
buffer_get_u32(packet, &status);
/*
* It's much more than a channel closing. spec says it's the last
@@ -266,12 +307,36 @@ SSH_PACKET_CALLBACK(ssh_packet_close1){
return SSH_PACKET_USED;
}
SSH_PACKET_CALLBACK(ssh_packet_exist_status1){
ssh_channel channel = ssh_get_channel1(session);
uint32_t status;
(void)type;
(void)user;
if (channel == NULL) {
return SSH_PACKET_NOT_USED;
}
buffer_get_u32(packet, &status);
channel->state = SSH_CHANNEL_STATE_CLOSED;
channel->remote_eof = 1;
channel->exit_status = ntohl(status);
return SSH_PACKET_USED;
}
int channel_write1(ssh_channel channel, const void *data, int len) {
ssh_session session = channel->session;
ssh_session session;
int origlen = len;
int effectivelen;
const unsigned char *ptr=data;
if (channel == NULL) {
return -1;
}
session = channel->session;
while (len > 0) {
if (buffer_add_u8(session->out_buffer, SSH_CMSG_STDIN_DATA) < 0) {
return -1;
@@ -295,5 +360,20 @@ int channel_write1(ssh_channel channel, const void *data, int len) {
return origlen;
}
ssh_channel ssh_get_channel1(ssh_session session){
struct ssh_iterator *it;
if (session == NULL) {
return NULL;
}
/* With SSH1, the channel is always the first one */
if(session->channels != NULL){
it = ssh_list_get_iterator(session->channels);
if(it)
return ssh_iterator_value(ssh_channel, it);
}
return NULL;
}
#endif /* WITH_SSH1 */
/* vim: set ts=2 sw=2 et cindent: */

View File

@@ -26,6 +26,7 @@
#include <string.h>
#ifndef _WIN32
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
@@ -40,8 +41,8 @@
#include "libssh/misc.h"
#define set_status(session, status) do {\
if (session->callbacks && session->callbacks->connect_status_function) \
session->callbacks->connect_status_function(session->callbacks->userdata, status); \
if (session->common.callbacks && session->common.callbacks->connect_status_function) \
session->common.callbacks->connect_status_function(session->common.callbacks->userdata, status); \
} while (0)
/**
@@ -664,7 +665,7 @@ int ssh_connect(ssh_session session) {
session->socket_callbacks.exception=ssh_socket_exception_callback;
session->socket_callbacks.userdata=session;
if (session->fd != SSH_INVALID_SOCKET) {
ssh_socket_set_fd(session->socket, session->fd);
ssh_socket_set_connecting(session->socket, session->fd);
ret=SSH_OK;
#ifndef _WIN32
} else if (session->ProxyCommand != NULL){
@@ -684,19 +685,21 @@ int ssh_connect(ssh_session session) {
session->alive = 1;
ssh_log(session,SSH_LOG_PROTOCOL,"Socket connecting, now waiting for the callbacks to work");
pending:
session->pending_call_state=SSH_PENDING_CALL_CONNECT;
if(ssh_is_blocking(session)) {
int timeout = session->timeout * 1000 + session->timeout_usec;
if (timeout <= 0)
timeout = -1;
ssh_handle_packets_termination(session,timeout,ssh_connect_termination,session);
if(!ssh_connect_termination(session)){
ssh_set_error(session,SSH_FATAL,"Timeout connecting to %s",session->host);
session->session_state = SSH_SESSION_STATE_ERROR;
}
}
session->pending_call_state=SSH_PENDING_CALL_CONNECT;
if(ssh_is_blocking(session)) {
int timeout = (session->timeout * 1000) + (session->timeout_usec / 1000);
if (timeout == 0) {
timeout = 10 * 1000;
}
ssh_log(session,SSH_LOG_PACKET,"ssh_connect: Actual timeout : %d", timeout);
ssh_handle_packets_termination(session, timeout, ssh_connect_termination, session);
if(!ssh_connect_termination(session)){
ssh_set_error(session,SSH_FATAL,"Timeout connecting to %s",session->host);
session->session_state = SSH_SESSION_STATE_ERROR;
}
}
else
ssh_handle_packets_termination(session,0,ssh_connect_termination, session);
ssh_handle_packets_termination(session, 0, ssh_connect_termination, session);
ssh_log(session,SSH_LOG_PACKET,"ssh_connect: Actual state : %d",session->session_state);
if(!ssh_is_blocking(session) && !ssh_connect_termination(session)){
leave_function();
@@ -753,6 +756,7 @@ int ssh_get_openssh_version(ssh_session session) {
*/
void ssh_disconnect(ssh_session session) {
ssh_string str = NULL;
struct ssh_iterator *it;
int i;
if (session == NULL) {
@@ -761,7 +765,7 @@ void ssh_disconnect(ssh_session session) {
enter_function();
if (ssh_socket_is_open(session->socket)) {
if (session->socket != NULL && ssh_socket_is_open(session->socket)) {
if (buffer_add_u8(session->out_buffer, SSH2_MSG_DISCONNECT) < 0) {
goto error;
}
@@ -786,13 +790,15 @@ void ssh_disconnect(ssh_session session) {
}
error:
session->alive = 0;
if(session->socket){
if (session->socket != NULL){
ssh_socket_reset(session->socket);
}
session->fd = SSH_INVALID_SOCKET;
session->session_state=SSH_SESSION_STATE_DISCONNECTED;
while (session->channels) {
ssh_channel_free(session->channels);
while ((it=ssh_list_get_iterator(session->channels)) != NULL) {
ssh_channel_free(ssh_iterator_value(ssh_channel,it));
ssh_list_remove(session->channels, it);
}
if(session->current_crypto){
crypto_free(session->current_crypto);

View File

@@ -78,7 +78,7 @@ static enum ssh_config_opcode_e ssh_config_get_opcode(char *keyword) {
return SOC_UNSUPPORTED;
}
static char *ssh_config_get_token(char **str) {
static char *ssh_config_get_cmd(char **str) {
register char *c;
char *r;
@@ -98,6 +98,25 @@ static char *ssh_config_get_token(char **str) {
}
}
for (r = c; *c; c++) {
if (*c == '\n') {
*c = '\0';
goto out;
}
}
out:
*str = c + 1;
return r;
}
static char *ssh_config_get_token(char **str) {
register char *c;
char *r;
c = ssh_config_get_cmd(str);
for (r = c; *c; c++) {
if (isblank(*c)) {
*c = '\0';
@@ -127,7 +146,7 @@ static int ssh_config_get_int(char **str, int notfound) {
return notfound;
}
static const char *ssh_config_get_str(char **str, const char *def) {
static const char *ssh_config_get_str_tok(char **str, const char *def) {
char *p;
p = ssh_config_get_token(str);
@@ -141,7 +160,7 @@ static const char *ssh_config_get_str(char **str, const char *def) {
static int ssh_config_get_yesno(char **str, int notfound) {
const char *p;
p = ssh_config_get_str(str, NULL);
p = ssh_config_get_str_tok(str, NULL);
if (p == NULL) {
return notfound;
}
@@ -192,8 +211,8 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
case SOC_HOST:
*parsing = 0;
lowerhost = (session->host) ? ssh_lowercase(session->host) : NULL;
for (p = ssh_config_get_str(&s, NULL); p && *p;
p = ssh_config_get_str(&s, NULL)) {
for (p = ssh_config_get_str_tok(&s, NULL); p && *p;
p = ssh_config_get_str_tok(&s, NULL)) {
if (match_hostname(lowerhost, p, strlen(p))) {
*parsing = 1;
}
@@ -201,14 +220,14 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
SAFE_FREE(lowerhost);
break;
case SOC_HOSTNAME:
p = ssh_config_get_str(&s, NULL);
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_HOST, p);
}
break;
case SOC_PORT:
if (session->port == 22) {
p = ssh_config_get_str(&s, NULL);
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_PORT_STR, p);
}
@@ -216,20 +235,20 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
break;
case SOC_USERNAME:
if (session->username == NULL) {
p = ssh_config_get_str(&s, NULL);
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_USER, p);
}
}
break;
case SOC_IDENTITY:
p = ssh_config_get_str(&s, NULL);
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_ADD_IDENTITY, p);
}
break;
case SOC_CIPHERS:
p = ssh_config_get_str(&s, NULL);
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_CIPHERS_C_S, p);
ssh_options_set(session, SSH_OPTIONS_CIPHERS_S_C, p);
@@ -246,7 +265,7 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
}
break;
case SOC_PROTOCOL:
p = ssh_config_get_str(&s, NULL);
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
char *a, *b;
b = strdup(p);
@@ -289,13 +308,13 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
}
break;
case SOC_KNOWNHOSTS:
p = ssh_config_get_str(&s, NULL);
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, p);
}
break;
case SOC_PROXYCOMMAND:
p = ssh_config_get_str(&s, NULL);
p = ssh_config_get_cmd(&s);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, p);
}

View File

@@ -159,7 +159,7 @@ static int ssh_connect_ai_timeout(ssh_session session, const char *host,
int timeout_ms;
ssh_pollfd_t fds;
int rc = 0;
unsigned int len = sizeof(rc);
socklen_t len = sizeof(rc);
enter_function();

View File

@@ -27,6 +27,7 @@
#include <string.h>
#ifndef _WIN32
#include <netinet/in.h>
#include <arpa/inet.h>
#endif

View File

@@ -44,8 +44,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#ifndef _WIN32
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
@@ -193,6 +195,9 @@ char *ssh_get_hexa(const unsigned char *what, size_t len) {
char *hexa = NULL;
size_t i;
if (len > (UINT_MAX - 1) / 3)
return NULL;
hexa = malloc(len * 3 + 1);
if (hexa == NULL) {
return NULL;

View File

@@ -24,6 +24,7 @@
#include <stdio.h>
#include <stdarg.h>
#include "libssh/priv.h"
#include "libssh/session.h"
/**
* @defgroup libssh_error The SSH error functions.
@@ -48,13 +49,13 @@
* @param ... The arguments for the format string.
*/
void ssh_set_error(void *error, int code, const char *descr, ...) {
struct error_struct *err = error;
struct ssh_common_struct *err = error;
va_list va;
va_start(va, descr);
vsnprintf(err->error_buffer, ERROR_BUFFERLEN, descr, va);
vsnprintf(err->error.error_buffer, ERROR_BUFFERLEN, descr, va);
va_end(va);
err->error_code = code;
ssh_log(error,SSH_LOG_RARE,"Error : %s",err->error_buffer);
err->error.error_code = code;
ssh_log_common(err,SSH_LOG_RARE,"Error : %s",err->error.error_buffer);
}
/**

View File

@@ -61,6 +61,7 @@ static int ssh_gets(const char *prompt, char *buf, size_t len, int verify) {
}
fflush(stdout);
if (fgets(tmp, len, stdin) == NULL) {
free(tmp);
return 0;
}

View File

@@ -173,7 +173,7 @@ static ssh_buffer gzip_decompress(ssh_session session, ssh_buffer source, size_t
do {
zin->avail_out = BLOCKSIZE;
status = inflate(zin, Z_PARTIAL_FLUSH);
if (status != Z_OK) {
if (status != Z_OK && status != Z_BUF_ERROR) {
ssh_set_error(session, SSH_FATAL,
"status %d inflating zlib packet", status);
ssh_buffer_free(dest);

View File

@@ -432,6 +432,7 @@ int ssh_send_kex(ssh_session session, int server_kex) {
goto error;
}
ssh_string_free(str);
str = NULL;
}
if (buffer_add_u8(session->out_buffer, 0) < 0) {
@@ -814,14 +815,14 @@ int ssh_get_kex1(ssh_session session) {
ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_PUBLIC_KEY");
/* Here the callback is called */
while(session->session_state==SSH_SESSION_STATE_INITIAL_KEX){
ssh_handle_packets(session,-1);
ssh_handle_packets(session, -2);
}
if(session->session_state==SSH_SESSION_STATE_ERROR)
goto error;
ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_SUCCESS");
/* Waiting for SSH_SMSG_SUCCESS */
while(session->session_state==SSH_SESSION_STATE_KEXINIT_RECEIVED){
ssh_handle_packets(session,-1);
ssh_handle_packets(session, -2);
}
if(session->session_state==SSH_SESSION_STATE_ERROR)
goto error;

View File

@@ -610,9 +610,9 @@ static int pem_get_password(char *buf, int size, int rwflag, void *userdata) {
ssh_log(session, SSH_LOG_RARE,
"Trying to call external authentication function");
if (session && session->callbacks && session->callbacks->auth_function) {
if (session->callbacks->auth_function("Passphrase for private key:", buf, size, 0, 0,
session->callbacks->userdata) < 0) {
if (session && session->common.callbacks && session->common.callbacks->auth_function) {
if (session->common.callbacks->auth_function("Passphrase for private key:", buf, size, 0, 0,
session->common.callbacks->userdata) < 0) {
return 0;
}
@@ -705,7 +705,7 @@ ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
ssh_log(session, SSH_LOG_RARE, "Trying to read %s, passphase=%s, authcb=%s",
filename, passphrase ? "true" : "false",
session->callbacks && session->callbacks->auth_function ? "true" : "false");
session->common.callbacks && session->common.callbacks->auth_function ? "true" : "false");
if (type == 0) {
type = privatekey_type_from_file(file);
@@ -719,9 +719,9 @@ ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
case SSH_KEYTYPE_DSS:
if (passphrase == NULL) {
#ifdef HAVE_LIBGCRYPT
if (session->callbacks && session->callbacks->auth_function) {
auth_cb = session->callbacks->auth_function;
auth_ud = session->callbacks->userdata;
if (session->common.callbacks && session->common.callbacks->auth_function) {
auth_cb = session->common.callbacks->auth_function;
auth_ud = session->common.callbacks->userdata;
valid = read_dsa_privatekey(file, &dsa, auth_cb, auth_ud,
"Passphrase for private key:");
@@ -738,7 +738,7 @@ ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
if (!valid) {
ssh_set_error(session, SSH_FATAL, "Parsing private key %s", filename);
#elif defined HAVE_LIBCRYPTO
if (session->callbacks && session->callbacks->auth_function) {
if (session->common.callbacks && session->common.callbacks->auth_function) {
dsa = PEM_read_bio_DSAPrivateKey(bio, NULL, pem_get_password, session);
} else { /* authcb */
/* openssl uses its own callback to get the passphrase here */
@@ -761,9 +761,9 @@ ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
case SSH_KEYTYPE_RSA:
if (passphrase == NULL) {
#ifdef HAVE_LIBGCRYPT
if (session->callbacks && session->callbacks->auth_function) {
auth_cb = session->callbacks->auth_function;
auth_ud = session->callbacks->userdata;
if (session->common.callbacks && session->common.callbacks->auth_function) {
auth_cb = session->common.callbacks->auth_function;
auth_ud = session->common.callbacks->userdata;
valid = read_rsa_privatekey(file, &rsa, auth_cb, auth_ud,
"Passphrase for private key:");
} else { /* authcb */
@@ -779,7 +779,7 @@ ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
if (!valid) {
ssh_set_error(session,SSH_FATAL, "Parsing private key %s", filename);
#elif defined HAVE_LIBCRYPTO
if (session->callbacks && session->callbacks->auth_function) {
if (session->common.callbacks && session->common.callbacks->auth_function) {
rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, pem_get_password, session);
} else { /* authcb */
/* openssl uses its own callback to get the passphrase here */
@@ -1214,7 +1214,7 @@ ssh_string try_publickey_from_file(ssh_session session, struct ssh_keys_struct k
const char *priv;
const char *pub;
char *new;
ssh_string pubkey=NULL;
ssh_string pubkey;
pub = keytab.publickey;
if (pub == NULL) {
@@ -1234,13 +1234,13 @@ ssh_string try_publickey_from_file(ssh_session session, struct ssh_keys_struct k
ssh_log(session, SSH_LOG_PACKET, "Trying to open publickey %s", pub);
if (!ssh_file_readaccess_ok(pub)) {
ssh_log(session, SSH_LOG_PACKET, "Failed to open publickey %s", pub);
goto error;
return NULL;
}
ssh_log(session, SSH_LOG_PACKET, "Trying to open privatekey %s", priv);
if (!ssh_file_readaccess_ok(priv)) {
ssh_log(session, SSH_LOG_PACKET, "Failed to open privatekey %s", priv);
goto error;
return NULL;
}
ssh_log(session, SSH_LOG_PACKET, "Success opening public and private key");
@@ -1255,18 +1255,18 @@ ssh_string try_publickey_from_file(ssh_session session, struct ssh_keys_struct k
"Wasn't able to open public key file %s: %s",
pub,
ssh_get_error(session));
goto error;
return NULL;
}
new = realloc(*privkeyfile, strlen(priv) + 1);
if (new == NULL) {
ssh_string_free(pubkey);
goto error;
return NULL;
}
strcpy(new, priv);
*privkeyfile = new;
error:
return pubkey;
}

View File

@@ -88,6 +88,7 @@ ssh_public_key publickey_make_dss(ssh_session session, ssh_buffer buffer) {
ssh_buffer_free(buffer);
return NULL;
}
ZERO_STRUCTP(key);
key->type = SSH_KEYTYPE_DSS;
key->type_c = ssh_type_to_char(key->type);
@@ -173,6 +174,7 @@ ssh_public_key publickey_make_rsa(ssh_session session, ssh_buffer buffer,
ssh_buffer_free(buffer);
return NULL;
}
ZERO_STRUCTP(key);
key->type = type;
key->type_c = ssh_type_to_char(key->type);
@@ -897,6 +899,7 @@ SIGNATURE *signature_from_string(ssh_session session, ssh_string signature,
ssh_set_error(session, SSH_FATAL, "Not enough space");
return NULL;
}
ZERO_STRUCTP(sign);
tmpbuf = ssh_buffer_new();
if (tmpbuf == NULL) {
@@ -1280,6 +1283,7 @@ ssh_string ssh_do_sign(ssh_session session, ssh_buffer sigbuf,
if (sign == NULL) {
return NULL;
}
ZERO_STRUCTP(sign);
switch(privatekey->type) {
case SSH_KEYTYPE_DSS:
@@ -1436,6 +1440,7 @@ ssh_string ssh_sign_session_id(ssh_session session, ssh_private_key privatekey)
if (sign == NULL) {
return NULL;
}
ZERO_STRUCTP(sign);
switch(privatekey->type) {
case SSH_KEYTYPE_DSS:

View File

@@ -47,6 +47,7 @@
#endif /* HAVE_LIBCRYPTO */
#ifndef _WIN32
# include <netinet/in.h>
# include <arpa/inet.h>
#endif

View File

@@ -37,6 +37,33 @@
* @{
*/
/** @internal
* @brief do the actual work of logging an event
*/
static void do_ssh_log(struct ssh_common_struct *common, int verbosity,
const char *buffer){
char indent[256];
int min;
if (common->callbacks && common->callbacks->log_function) {
common->callbacks->log_function((ssh_session)common, verbosity, buffer,
common->callbacks->userdata);
} else if (verbosity == SSH_LOG_FUNCTIONS) {
if (common->log_indent > 255) {
min = 255;
} else {
min = common->log_indent;
}
memset(indent, ' ', min);
indent[min] = '\0';
fprintf(stderr, "[func] %s%s\n", indent, buffer);
} else {
fprintf(stderr, "[%d] %s\n", verbosity, buffer);
}
}
/**
* @brief Log a SSH event.
*
@@ -48,32 +75,31 @@
*/
void ssh_log(ssh_session session, int verbosity, const char *format, ...) {
char buffer[1024];
char indent[256];
int min;
va_list va;
if (verbosity <= session->log_verbosity) {
if (verbosity <= session->common.log_verbosity) {
va_start(va, format);
vsnprintf(buffer, sizeof(buffer), format, va);
va_end(va);
do_ssh_log(&session->common, verbosity, buffer);
}
}
if (session->callbacks && session->callbacks->log_function) {
session->callbacks->log_function(session, verbosity, buffer,
session->callbacks->userdata);
} else if (verbosity == SSH_LOG_FUNCTIONS) {
if (session->log_indent > 255) {
min = 255;
} else {
min = session->log_indent;
}
/** @internal
* @brief log a SSH event with a common pointer
* @param common The SSH/bind session.
* @param verbosity The verbosity of the event.
* @param format The format string of the log entry.
*/
void ssh_log_common(struct ssh_common_struct *common, int verbosity, const char *format, ...){
char buffer[1024];
va_list va;
memset(indent, ' ', min);
indent[min] = '\0';
fprintf(stderr, "[func] %s%s\n", indent, buffer);
} else {
fprintf(stderr, "[%d] %s\n", verbosity, buffer);
}
if (verbosity <= common->log_verbosity) {
va_start(va, format);
vsnprintf(buffer, sizeof(buffer), format, va);
va_end(va);
do_ssh_log(common, verbosity, buffer);
}
}

View File

@@ -27,6 +27,7 @@
#include <stdlib.h>
#ifndef _WIN32
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
@@ -69,6 +70,26 @@ static ssh_message ssh_message_new(ssh_session session){
return msg;
}
#ifndef WITH_SERVER
/* Reduced version of the reply default that only reply with
* SSH_MSG_UNIMPLEMENTED
*/
static int ssh_message_reply_default(ssh_message msg) {
ssh_log(msg->session, SSH_LOG_FUNCTIONS, "Reporting unknown packet");
if (buffer_add_u8(msg->session->out_buffer, SSH2_MSG_UNIMPLEMENTED) < 0)
goto error;
if (buffer_add_u32(msg->session->out_buffer,
htonl(msg->session->recv_seq-1)) < 0)
goto error;
return packet_send(msg->session);
error:
return SSH_ERROR;
}
#endif
static int ssh_execute_message_callback(ssh_session session, ssh_message msg) {
int ret;
if(session->ssh_message_callback != NULL) {
@@ -161,7 +182,7 @@ ssh_message ssh_message_get(ssh_session session) {
session->ssh_message_list = ssh_list_new();
}
do {
if (ssh_handle_packets(session,-1) == SSH_ERROR) {
if (ssh_handle_packets(session, -2) == SSH_ERROR) {
leave_function();
return NULL;
}
@@ -891,6 +912,7 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){
char *bind_addr=NULL;
uint32_t bind_port;
uint8_t want_reply;
int rc = SSH_PACKET_USED;
(void)user;
(void)type;
(void)packet;
@@ -925,9 +947,9 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){
ssh_log(session, SSH_LOG_PROTOCOL, "Received SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, bind_addr, bind_port);
if(ssh_callbacks_exists(session->callbacks, global_request_function)) {
if(ssh_callbacks_exists(session->common.callbacks, global_request_function)) {
ssh_log(session, SSH_LOG_PROTOCOL, "Calling callback for SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, bind_addr, bind_port);
session->callbacks->global_request_function(session, msg, session->callbacks->userdata);
session->common.callbacks->global_request_function(session, msg, session->common.callbacks->userdata);
} else {
ssh_message_reply_default(msg);
}
@@ -947,19 +969,21 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){
ssh_log(session, SSH_LOG_PROTOCOL, "Received SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, bind_addr, bind_port);
if(ssh_callbacks_exists(session->callbacks, global_request_function)) {
session->callbacks->global_request_function(session, msg, session->callbacks->userdata);
if(ssh_callbacks_exists(session->common.callbacks, global_request_function)) {
session->common.callbacks->global_request_function(session, msg, session->common.callbacks->userdata);
} else {
ssh_message_reply_default(msg);
}
} else {
ssh_log(session, SSH_LOG_PROTOCOL, "UNKNOWN SSH_MSG_GLOBAL_REQUEST %s %d", request, want_reply);
rc = SSH_PACKET_NOT_USED;
}
SAFE_FREE(msg);
SAFE_FREE(request);
SAFE_FREE(bind_addr);
return SSH_PACKET_USED;
return rc;
}
#endif /* WITH_SERVER */

View File

@@ -215,7 +215,8 @@ char *ssh_get_user_home_dir(void) {
rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf);
if (rc != 0) {
return NULL;
szPath=getenv("HOME");
return szPath ? strdup(szPath) : NULL;
}
szPath = strdup(pwd.pw_dir);
@@ -286,18 +287,20 @@ int ssh_is_ipaddr(const char *str) {
#endif /* _WIN32 */
#ifndef HAVE_NTOHLL
uint64_t ntohll(uint64_t a) {
#ifdef WORDS_BIGENDIAN
return a;
#else
#else /* WORDS_BIGENDIAN */
uint32_t low = (uint32_t)(a & 0xffffffff);
uint32_t high = (uint32_t)(a >> 32);
low = ntohl(low);
high = ntohl(high);
return ((((uint64_t) low) << 32) | ( high));
#endif
#endif /* WORDS_BIGENDIAN */
}
#endif /* HAVE_NTOHLL */
char *ssh_lowercase(const char* str) {
char *new, *p;
@@ -374,6 +377,8 @@ struct ssh_list *ssh_list_new(){
void ssh_list_free(struct ssh_list *list){
struct ssh_iterator *ptr,*next;
if(!list)
return;
ptr=list->root;
while(ptr){
next=ptr->next;
@@ -384,9 +389,19 @@ void ssh_list_free(struct ssh_list *list){
}
struct ssh_iterator *ssh_list_get_iterator(const struct ssh_list *list){
if(!list)
return NULL;
return list->root;
}
struct ssh_iterator *ssh_list_find(const struct ssh_list *list, void *value){
struct ssh_iterator *it;
for(it = ssh_list_get_iterator(list); it != NULL ;it=it->next)
if(it->data==value)
return it;
return NULL;
}
static struct ssh_iterator *ssh_iterator_new(const void *data){
struct ssh_iterator *iterator=malloc(sizeof(struct ssh_iterator));
if(!iterator)
@@ -640,7 +655,7 @@ char *ssh_path_expand_tilde(const char *d) {
size_t s = p - d;
char u[128];
if (s > sizeof(u)) {
if (s >= sizeof(u)) {
return NULL;
}
memcpy(u, d, s);
@@ -704,7 +719,8 @@ char *ssh_path_expand_escape(ssh_session session, const char *s) {
if (*p != '%') {
buf[i] = *p;
i++;
if (i > MAX_BUF_SIZE) {
if (i >= MAX_BUF_SIZE) {
free(r);
return NULL;
}
buf[i] = '\0';
@@ -745,18 +761,22 @@ char *ssh_path_expand_escape(ssh_session session, const char *s) {
default:
ssh_set_error(session, SSH_FATAL,
"Wrong escape sequence detected");
free(r);
return NULL;
}
if (x == NULL) {
ssh_set_error_oom(session);
free(r);
return NULL;
}
i += strlen(x);
if (i > MAX_BUF_SIZE) {
if (i >= MAX_BUF_SIZE) {
ssh_set_error(session, SSH_FATAL,
"String too long");
free(x);
free(r);
return NULL;
}
l = strlen(buf);
@@ -908,6 +928,24 @@ static int ssh_timestamp_difference(struct ssh_timestamp *old,
return msecs;
}
/**
* @internal
* @brief turn seconds and microseconds pair (as provided by user-set options)
* into millisecond value
* @param[in] sec number of seconds
* @param[in] usec number of microseconds
* @returns milliseconds, or 10000 if user supplied values are equal to zero
*/
int ssh_make_milliseconds(long sec, long usec) {
int res = usec ? (usec / 1000) : 0;
res += (sec * 1000);
if (res == 0) {
res = 10 * 1000; /* use a reasonable default value in case
* SSH_OPTIONS_TIMEOUT is not set in options. */
}
return res;
}
/**
* @internal
* @brief Checks if a timeout is elapsed, in function of a previous
@@ -919,17 +957,20 @@ static int ssh_timestamp_difference(struct ssh_timestamp *old,
* 0 otherwise
*/
int ssh_timeout_elapsed(struct ssh_timestamp *ts, int timeout) {
struct ssh_timestamp now;
if(timeout < 0)
return 0; // -1 means infinite timeout
if(timeout == 0)
return 1; // 0 means no timeout
ssh_timestamp_init(&now);
if(ssh_timestamp_difference(ts,&now) >= timeout)
return 1;
else
return 0;
struct ssh_timestamp now;
switch(timeout) {
case -2: // -2 means user-defined timeout as available in session->timeout, session->timeout_usec.
fprintf(stderr, "ssh_timeout_elapsed called with -2. this needs to be fixed. "
"please set a breakpoint on %s:%d and fix the caller\n", __FILE__, __LINE__);
case -1: // -1 means infinite timeout
return 0;
case 0: // 0 means no timeout
return 1;
default:
break;
}
ssh_timestamp_init(&now);
return (ssh_timestamp_difference(ts,&now) >= timeout);
}
/**
@@ -937,15 +978,15 @@ int ssh_timeout_elapsed(struct ssh_timestamp *ts, int timeout) {
* @param[in] ts pointer to an existing timestamp
* @param[in] timeout timeout in milliseconds. Negative values mean infinite
* timeout
* @returns remaining time in milliseconds, 0 if elapsed, -1 if never.
* @returns remaining time in milliseconds, 0 if elapsed, -1 if never,
* -2 if option-set-timeout.
*/
int ssh_timeout_update(struct ssh_timestamp *ts, int timeout){
struct ssh_timestamp now;
int ms, ret;
if(timeout == 0)
return 0;
if(timeout==-1)
return -1;
if (timeout <= 0) {
return timeout;
}
ssh_timestamp_init(&now);
ms = ssh_timestamp_difference(ts,&now);
if(ms < 0)

View File

@@ -139,12 +139,12 @@ int ssh_options_copy(ssh_session src, ssh_session *dest) {
}
new->fd = src->fd;
new->port = src->port;
new->callbacks = src->callbacks;
new->common.callbacks = src->common.callbacks;
new->timeout = src->timeout;
new->timeout_usec = src->timeout_usec;
new->ssh2 = src->ssh2;
new->ssh1 = src->ssh1;
new->log_verbosity = src->log_verbosity;
new->common.log_verbosity = src->common.log_verbosity;
new->compressionlevel = src->compressionlevel;
return 0;
@@ -544,12 +544,12 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
} else {
int *x = (int *) value;
session->log_verbosity = *x & 0xffff;
session->common.log_verbosity = *x & 0xffff;
}
break;
case SSH_OPTIONS_LOG_VERBOSITY_STR:
if (value == NULL) {
session->log_verbosity = 0 & 0xffff;
session->common.log_verbosity = 0 & 0xffff;
} else {
q = strdup(value);
if (q == NULL) {
@@ -562,7 +562,7 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
}
SAFE_FREE(q);
session->log_verbosity = i & 0xffff;
session->common.log_verbosity = i & 0xffff;
}
break;
case SSH_OPTIONS_CIPHERS_C_S:
@@ -655,11 +655,15 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
return -1;
} else {
SAFE_FREE(session->ProxyCommand);
q = strdup(value);
if (q == NULL) {
return -1;
/* Setting the command to 'none' disables this option. */
rc = strcasecmp(value, "none");
if (rc != 0) {
q = strdup(value);
if (q == NULL) {
return -1;
}
session->ProxyCommand = q;
}
session->ProxyCommand = q;
}
break;
default:
@@ -698,7 +702,7 @@ int ssh_options_getopt(ssh_session session, int *argcptr, char **argv) {
char *cipher = NULL;
char *identity = NULL;
char *port = NULL;
char **save = NULL;
char **save = NULL, **tmp;
int i = 0;
int argc = *argcptr;
int debuglevel = 0;
@@ -720,12 +724,6 @@ int ssh_options_getopt(ssh_session session, int *argcptr, char **argv) {
int saveoptind = optind; /* need to save 'em */
int saveopterr = opterr;
save = malloc(argc * sizeof(char *));
if (save == NULL) {
ssh_set_error_oom(session);
return -1;
}
opterr = 0; /* shut up getopt */
while(cont && ((i = getopt(argc, argv, "c:i:Cl:p:vb:rd12")) != -1)) {
switch(i) {
@@ -765,6 +763,13 @@ int ssh_options_getopt(ssh_session session, int *argcptr, char **argv) {
{
char opt[3]="- ";
opt[1] = optopt;
tmp = realloc(save, (current + 1) * sizeof(char*));
if (tmp == NULL) {
SAFE_FREE(save);
ssh_set_error_oom(session);
return -1;
}
save = tmp;
save[current] = strdup(opt);
if (save[current] == NULL) {
SAFE_FREE(save);
@@ -780,7 +785,16 @@ int ssh_options_getopt(ssh_session session, int *argcptr, char **argv) {
} /* while */
opterr = saveopterr;
while (optind < argc) {
save[current++] = argv[optind++];
tmp = realloc(save, (current + 1) * sizeof(char*));
if (tmp == NULL) {
SAFE_FREE(save);
ssh_set_error_oom(session);
return -1;
}
save = tmp;
save[current] = argv[optind];
current++;
optind++;
}
if (usersa && usedss) {
@@ -1106,12 +1120,12 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
return -1;
} else {
int *x = (int *) value;
sshbind->log_verbosity = *x & 0xffff;
sshbind->common.log_verbosity = *x & 0xffff;
}
break;
case SSH_BIND_OPTIONS_LOG_VERBOSITY_STR:
if (value == NULL) {
sshbind->log_verbosity = 0;
sshbind->common.log_verbosity = 0;
} else {
q = strdup(value);
if (q == NULL) {
@@ -1124,7 +1138,7 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
}
SAFE_FREE(q);
sshbind->log_verbosity = i & 0xffff;
sshbind->common.log_verbosity = i & 0xffff;
}
break;
case SSH_BIND_OPTIONS_DSAKEY:

View File

@@ -29,6 +29,7 @@
#include <errno.h>
#ifndef _WIN32
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
@@ -255,7 +256,9 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
"After padding, %d bytes left in buffer",
buffer_get_rest_len(session->in_buffer));
#if defined(HAVE_LIBZ) && defined(WITH_LIBZ)
if (session->current_crypto && session->current_crypto->do_compress_in) {
if (session->current_crypto
&& session->current_crypto->do_compress_in
&& buffer_get_rest_len(session->in_buffer)) {
ssh_log(session, SSH_LOG_PACKET, "Decompressing in_buffer ...");
if (decompress_buffer(session, session->in_buffer,MAX_PACKET_LEN) < 0) {
goto error;
@@ -457,7 +460,9 @@ static int packet_send2(ssh_session session) {
"Writing on the wire a packet having %u bytes before", currentlen);
#if defined(HAVE_LIBZ) && defined(WITH_LIBZ)
if (session->current_crypto && session->current_crypto->do_compress_out) {
if (session->current_crypto
&& session->current_crypto->do_compress_out
&& buffer_get_rest_len(session->out_buffer)) {
ssh_log(session, SSH_LOG_PACKET, "Compressing out_buffer ...");
if (compress_buffer(session,session->out_buffer) < 0) {
goto error;

View File

@@ -55,7 +55,7 @@ ssh_packet_callback default_packet_handlers1[]= {
ssh_packet_data1, //SSH_SMSG_STDOUT_DATA 17
ssh_packet_data1, //SSH_SMSG_STDERR_DATA 18
NULL, //SSH_CMSG_EOF 19
NULL, //SSH_SMSG_EXITSTATUS 20
ssh_packet_exist_status1, //SSH_SMSG_EXITSTATUS 20
NULL, //SSH_MSG_CHANNEL_OPEN_CONFIRMATION 21
NULL, //SSH_MSG_CHANNEL_OPEN_FAILURE 22
NULL, //SSH_MSG_CHANNEL_DATA 23

View File

@@ -440,24 +440,9 @@ ssh_poll_ctx ssh_poll_ctx_new(size_t chunk_size) {
*/
void ssh_poll_ctx_free(ssh_poll_ctx ctx) {
if (ctx->polls_allocated > 0) {
register size_t i, used;
used = ctx->polls_used;
for (i = 0; i < used; ) {
ssh_poll_handle p = ctx->pollptrs[i];
socket_t fd = ctx->pollfds[i].fd;
/* force poll object removal */
if (p->cb && p->cb(p, fd, POLLERR, p->cb_data) < 0) {
if(ctx->polls_used < used) {
used = ctx->polls_used;
} else {
/* nothing to do */
i++;
}
} else {
i++;
}
while (ctx->polls_used > 0){
ssh_poll_handle p = ctx->pollptrs[0];
ssh_poll_ctx_remove(ctx, p);
}
SAFE_FREE(ctx->pollptrs);
@@ -596,7 +581,7 @@ int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout) {
int revents;
if (!ctx->polls_used)
return 0;
return SSH_ERROR;
rc = ssh_poll(ctx->pollfds, ctx->polls_used, timeout);
if(rc < 0)
@@ -608,11 +593,16 @@ int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout) {
if (!ctx->pollfds[i].revents) {
i++;
} else {
int ret;
p = ctx->pollptrs[i];
fd = ctx->pollfds[i].fd;
revents = ctx->pollfds[i].revents;
if (p->cb(p, fd, revents, p->cb_data) < 0) {
if (p->cb && (ret = p->cb(p, fd, revents, p->cb_data)) < 0) {
if (ret == -2) {
return -1;
}
/* the poll was removed, reload the used counter and start again */
used = ctx->polls_used;
i=0;

View File

@@ -380,8 +380,8 @@ int ssh_scp_response(ssh_scp scp, char **response){
*/
int ssh_scp_write(ssh_scp scp, const void *buffer, size_t len){
int w;
//int r;
//uint8_t code;
int r;
uint8_t code;
if(scp==NULL)
return SSH_ERROR;
if(scp->state != SSH_SCP_WRITE_WRITING){
@@ -400,19 +400,27 @@ int ssh_scp_write(ssh_scp scp, const void *buffer, size_t len){
//return=channel_get_exit_status(scp->channel);
return SSH_ERROR;
}
/* Far end sometimes send a status message, which we need to read
* and handle */
r = ssh_channel_poll(scp->channel,0);
if(r > 0){
r = ssh_channel_read(scp->channel, &code, 1, 0);
if(r == SSH_ERROR){
return SSH_ERROR;
}
if(code == 1 || code == 2){
ssh_set_error(scp->session,SSH_REQUEST_DENIED, "SCP: Error: status code %i received", code);
return SSH_ERROR;
}
}
/* Check if we arrived at end of file */
if(scp->processed == scp->filelen) {
/* r=channel_read(scp->channel,&code,1,0);
if(r==SSH_ERROR){
scp->state=SSH_SCP_ERROR;
code = 0;
w = ssh_channel_write(scp->channel, &code, 1);
if(w == SSH_ERROR){
scp->state = SSH_SCP_ERROR;
return SSH_ERROR;
}
if(code != 0){
ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code);
scp->state=SSH_SCP_ERROR;
return SSH_ERROR;
}
*/
scp->processed=scp->filelen=0;
scp->state=SSH_SCP_WRITE_INITED;
}
@@ -461,16 +469,20 @@ int ssh_scp_read_string(ssh_scp scp, char *buffer, size_t len){
*
* @returns SSH_SCP_REQUEST_NEWFILE: The other side is sending
* a file
* SSH_SCP_REQUEST_NEWDIRECTORY: The other side is sending
* SSH_SCP_REQUEST_NEWDIR: The other side is sending
* a directory
* SSH_SCP_REQUEST_END_DIRECTORY: The other side has
* SSH_SCP_REQUEST_ENDDIR: The other side has
* finished with the current
* directory
* SSH_SCP_REQUEST_WARNING: The other side sent us a warning
* SSH_SCP_REQUEST_EOF: The other side finished sending us
* files and data.
* SSH_ERROR: Some error happened
*
* @see ssh_scp_read()
* @see ssh_scp_deny_request()
* @see ssh_scp_accept_request()
* @see ssh_scp_request_get_warning()
*/
int ssh_scp_pull_request(ssh_scp scp){
char buffer[4096];

View File

@@ -59,8 +59,8 @@
#include "libssh/messages.h"
#define set_status(session, status) do {\
if (session->callbacks && session->callbacks->connect_status_function) \
session->callbacks->connect_status_function(session->callbacks->userdata, status); \
if (session->common.callbacks && session->common.callbacks->connect_status_function) \
session->common.callbacks->connect_status_function(session->common.callbacks->userdata, status); \
} while (0)
static int dh_handshake_server(ssh_session session);
@@ -184,7 +184,11 @@ static int dh_handshake_server(ssh_session session) {
prv = session->rsa_key;
break;
default:
prv = NULL;
ssh_set_error(session,
SSH_FATAL,
"Could not determine the specified hostkey");
ssh_string_free(f);
return -1;
}
pub = publickey_from_privatekey(prv);
@@ -270,6 +274,8 @@ static int dh_handshake_server(ssh_session session) {
*/
static void ssh_server_connection_callback(ssh_session session){
int ssh1,ssh2;
int rc;
enter_function();
switch(session->session_state){
case SSH_SESSION_STATE_NONE:
@@ -338,7 +344,10 @@ static void ssh_server_connection_callback(ssh_session session){
case SSH_SESSION_STATE_KEXINIT_RECEIVED:
set_status(session,0.6f);
ssh_list_kex(session, &session->client_kex); // log client kex
crypt_set_algorithms_server(session);
rc = crypt_set_algorithms_server(session);
if (rc == SSH_ERROR) {
goto error;
}
if (set_kex(session) < 0) {
goto error;
}
@@ -479,7 +488,7 @@ int ssh_handle_key_exchange(ssh_session session) {
* loop until SSH_SESSION_STATE_BANNER_RECEIVED or
* SSH_SESSION_STATE_ERROR
*/
ssh_handle_packets(session,-1);
ssh_handle_packets(session, -2);
ssh_log(session,SSH_LOG_PACKET, "ssh_handle_key_exchange: Actual state : %d",
session->session_state);
}

View File

@@ -86,7 +86,7 @@ ssh_session ssh_new(void) {
session->alive = 0;
session->auth_methods = 0;
ssh_set_blocking(session, 1);
session->log_indent = 0;
session->common.log_indent = 0;
session->maxchannel = FIRST_CHANNEL;
/* options */
@@ -143,6 +143,7 @@ ssh_session ssh_new(void) {
return session;
err:
free(id);
ssh_free(session);
return NULL;
}
@@ -157,16 +158,26 @@ err:
*/
void ssh_free(ssh_session session) {
int i;
enter_function();
struct ssh_iterator *it;
if (session == NULL) {
return;
}
SAFE_FREE(session->serverbanner);
SAFE_FREE(session->clientbanner);
SAFE_FREE(session->bindaddr);
SAFE_FREE(session->banner);
/* delete all channels */
while ((it=ssh_list_get_iterator(session->channels)) != NULL) {
ssh_channel_free(ssh_iterator_value(ssh_channel,it));
ssh_list_remove(session->channels, it);
}
ssh_list_free(session->channels);
session->channels=NULL;
ssh_socket_free(session->socket);
if (session->default_poll_ctx) {
ssh_poll_ctx_free(session->default_poll_ctx);
}
#ifdef WITH_PCAP
if(session->pcap_ctx){
ssh_pcap_context_free(session->pcap_ctx);
@@ -182,14 +193,6 @@ void ssh_free(ssh_session session) {
session->in_buffer=session->out_buffer=NULL;
crypto_free(session->current_crypto);
crypto_free(session->next_crypto);
ssh_socket_free(session->socket);
if(session->default_poll_ctx){
ssh_poll_ctx_free(session->default_poll_ctx);
}
/* delete all channels */
while (session->channels) {
ssh_channel_free(session->channels);
}
#ifndef _WIN32
agent_free(session->agent);
#endif /* _WIN32 */
@@ -232,6 +235,11 @@ void ssh_free(ssh_session session) {
ssh_list_free(session->identity);
}
SAFE_FREE(session->serverbanner);
SAFE_FREE(session->clientbanner);
SAFE_FREE(session->bindaddr);
SAFE_FREE(session->banner);
/* options */
SAFE_FREE(session->username);
SAFE_FREE(session->host);
@@ -301,7 +309,7 @@ int ssh_is_blocking(ssh_session session){
* @brief Blocking flush of the outgoing buffer
* @param[in] session The SSH session
* @param[in] timeout Set an upper limit on the time for which this function
* will block, in milliseconds. Specifying a negative value
* will block, in milliseconds. Specifying -1
* means an infinite timeout. This parameter is passed to
* the poll() function.
* @returns SSH_OK on success, SSH_AGAIN if timeout occurred,
@@ -310,24 +318,16 @@ int ssh_is_blocking(ssh_session session){
int ssh_blocking_flush(ssh_session session, int timeout){
ssh_socket s;
struct ssh_timestamp ts;
int rc = SSH_OK;
if(session==NULL)
return SSH_ERROR;
enter_function();
s=session->socket;
ssh_timestamp_init(&ts);
while (ssh_socket_buffered_write_bytes(s) > 0 && session->alive) {
rc=ssh_handle_packets(session, timeout);
if(ssh_timeout_elapsed(&ts,timeout)){
rc=SSH_AGAIN;
break;
}
timeout = ssh_timeout_update(&ts, timeout);
rc = ssh_handle_packets(session, timeout);
if(rc == SSH_AGAIN || rc == SSH_ERROR) break;
}
leave_function();
return rc;
}
@@ -415,38 +415,50 @@ void ssh_set_fd_except(ssh_session session) {
* @param[in] session The session handle to use.
*
* @param[in] timeout Set an upper limit on the time for which this function
* will block, in milliseconds. Specifying a negative value
* means an infinite timeout. This parameter is passed to
* the poll() function.
* will block, in milliseconds. Specifying -1
* means an infinite timeout.
* Specifying -2 means to use the timeout specified in
* options. 0 means poll will return immediately. This
* parameter is passed to the poll() function.
*
* @return SSH_OK on success, SSH_ERROR otherwise.
*/
int ssh_handle_packets(ssh_session session, int timeout) {
ssh_poll_handle spoll_in,spoll_out;
ssh_poll_ctx ctx;
int rc;
if(session==NULL || session->socket==NULL)
return SSH_ERROR;
enter_function();
spoll_in=ssh_socket_get_poll_handle_in(session->socket);
spoll_out=ssh_socket_get_poll_handle_out(session->socket);
if(session->server)
ssh_poll_add_events(spoll_in, POLLIN);
ctx=ssh_poll_get_ctx(spoll_in);
if(ctx==NULL){
ctx=ssh_poll_get_default_ctx(session);
ssh_poll_ctx_add(ctx,spoll_in);
if(spoll_in != spoll_out)
ssh_poll_ctx_add(ctx,spoll_out);
}
rc = ssh_poll_ctx_dopoll(ctx,timeout);
if(rc == SSH_ERROR)
session->session_state = SSH_SESSION_STATE_ERROR;
leave_function();
if (session->session_state != SSH_SESSION_STATE_ERROR)
return SSH_OK;
else
return SSH_ERROR;
ssh_poll_handle spoll_in,spoll_out;
ssh_poll_ctx ctx;
int tm = timeout;
int rc;
if (session == NULL || session->socket == NULL) {
return SSH_ERROR;
}
enter_function();
spoll_in = ssh_socket_get_poll_handle_in(session->socket);
spoll_out = ssh_socket_get_poll_handle_out(session->socket);
if (session->server) {
ssh_poll_add_events(spoll_in, POLLIN);
}
ctx = ssh_poll_get_ctx(spoll_in);
if (!ctx) {
ctx = ssh_poll_get_default_ctx(session);
ssh_poll_ctx_add(ctx, spoll_in);
if (spoll_in != spoll_out) {
ssh_poll_ctx_add(ctx, spoll_out);
}
}
if (timeout == -2) {
tm = ssh_make_milliseconds(session->timeout, session->timeout_usec);
}
rc = ssh_poll_ctx_dopoll(ctx, tm);
if (rc == SSH_ERROR) {
session->session_state = SSH_SESSION_STATE_ERROR;
}
leave_function();
return rc;
}
/**
@@ -469,23 +481,22 @@ int ssh_handle_packets(ssh_session session, int timeout) {
* @return SSH_OK on success, SSH_ERROR otherwise.
*/
int ssh_handle_packets_termination(ssh_session session, int timeout,
ssh_termination_function fct, void *user){
int ret = SSH_ERROR;
struct ssh_timestamp ts;
ssh_timestamp_init(&ts);
while(!fct(user)){
ret = ssh_handle_packets(session, timeout);
if(ret == SSH_ERROR)
return SSH_ERROR;
if(fct(user)) {
return SSH_OK;
} else if (ssh_timeout_elapsed(&ts, timeout)) {
return SSH_AGAIN;
}
timeout = ssh_timeout_update(&ts,timeout);
}
return ret;
ssh_termination_function fct, void *user){
int ret = SSH_OK;
struct ssh_timestamp ts;
ssh_timestamp_init(&ts);
while(!fct(user)){
ret = ssh_handle_packets(session, timeout);
if(ret == SSH_ERROR || ret == SSH_AGAIN)
return ret;
if(fct(user))
return SSH_OK;
else if(ssh_timeout_elapsed(&ts, timeout == -2 ? ssh_make_milliseconds(session->timeout, session->timeout_usec) : timeout))
/* it is possible that we get unrelated packets but still timeout our request,
* so simply relying on the poll timeout is not enough */
return SSH_AGAIN;
}
return ret;
}
/**

View File

@@ -35,6 +35,7 @@
#include <sys/stat.h>
#ifndef _WIN32
#include <netinet/in.h>
#include <arpa/inet.h>
#else
#define S_IFSOCK 0140000
@@ -668,10 +669,18 @@ int sftp_extension_supported(sftp_session sftp, const char *name,
const char *data) {
int i, n;
if (sftp == NULL || name == NULL || data == NULL) {
return 0;
}
n = sftp_extensions_get_count(sftp);
for (i = 0; i < n; i++) {
if (strcmp(sftp_extensions_get_name(sftp, i), name) == 0 &&
strcmp(sftp_extensions_get_data(sftp, i), data) == 0) {
const char *ext_name = sftp_extensions_get_name(sftp, i);
const char *ext_data = sftp_extensions_get_data(sftp, i);
if (ext_name != NULL && ext_data != NULL &&
strcmp(ext_name, name) == 0 &&
strcmp(ext_data, data) == 0) {
return 1;
}
}
@@ -939,6 +948,7 @@ sftp_dir sftp_opendir(sftp_session sftp, const char *path){
dir = malloc(sizeof(struct sftp_dir_struct));
if (dir == NULL) {
ssh_set_error_oom(sftp->session);
free(file);
return NULL;
}
ZERO_STRUCTP(dir);
@@ -1193,8 +1203,8 @@ static char *sftp_parse_longname(const char *longname,
so that number of pairs equals extended_count */
static sftp_attributes sftp_parse_attr_3(sftp_session sftp, ssh_buffer buf,
int expectname) {
ssh_string longname = NULL;
ssh_string name = NULL;
ssh_string longname;
ssh_string name;
sftp_attributes attr;
uint32_t flags = 0;
int ok = 0;
@@ -1209,19 +1219,27 @@ static sftp_attributes sftp_parse_attr_3(sftp_session sftp, ssh_buffer buf,
/* This isn't really a loop, but it is like a try..catch.. */
do {
if (expectname) {
if ((name = buffer_get_ssh_string(buf)) == NULL ||
(attr->name = ssh_string_to_char(name)) == NULL) {
break;
name = buffer_get_ssh_string(buf);
if (name == NULL) {
break;
}
attr->name = ssh_string_to_char(name);
ssh_string_free(name);
if (attr->name == NULL) {
break;
}
ssh_log(sftp->session, SSH_LOG_RARE, "Name: %s", attr->name);
if ((longname=buffer_get_ssh_string(buf)) == NULL ||
(attr->longname=ssh_string_to_char(longname)) == NULL) {
longname = buffer_get_ssh_string(buf);
if (longname == NULL) {
break;
}
attr->longname = ssh_string_to_char(longname);
ssh_string_free(longname);
if (attr->longname == NULL) {
break;
}
ssh_string_free(longname);
/* Set owner and group if we talk to openssh and have the longname */
if (ssh_get_openssh_version(sftp->session)) {
@@ -1326,8 +1344,6 @@ static sftp_attributes sftp_parse_attr_3(sftp_session sftp, ssh_buffer buf,
if (!ok) {
/* break issued somewhere */
ssh_string_free(name);
ssh_string_free(longname);
ssh_string_free(attr->extended_type);
ssh_string_free(attr->extended_data);
SAFE_FREE(attr->name);
@@ -1945,9 +1961,8 @@ int sftp_async_read(sftp_file file, void *data, uint32_t size, uint32_t id){
return SSH_ERROR;
}
len = ssh_string_len(datastring);
//handle->offset+=len;
/* We already have set the offset previously. All we can do is warn that the expected len
* and effective lengths are different */
/* Update the offset with the correct value */
file->offset = file->offset - (size - len);
memcpy(data, ssh_string_data(datastring), len);
ssh_string_free(datastring);
sftp_leave_function();
@@ -2270,6 +2285,7 @@ int sftp_mkdir(sftp_session sftp, const char *directory, mode_t mode) {
sftp_packet_write(sftp, SSH_FXP_MKDIR, buffer) < 0) {
ssh_buffer_free(buffer);
ssh_string_free(path);
return -1;
}
ssh_buffer_free(buffer);
ssh_string_free(path);

View File

@@ -26,6 +26,7 @@
#include <stdio.h>
#ifndef _WIN32
#include <netinet/in.h>
#include <arpa/inet.h>
#endif

View File

@@ -246,32 +246,34 @@ int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int r
s->read_wontblock=1;
r=ssh_socket_unbuffered_read(s,buffer,sizeof(buffer));
if(r<0){
if(p != NULL) {
ssh_poll_remove_events(p, POLLIN);
}
if(p != NULL) {
ssh_poll_remove_events(p, POLLIN);
}
if(s->callbacks && s->callbacks->exception){
s->callbacks->exception(
SSH_SOCKET_EXCEPTION_ERROR,
s->last_errno,s->callbacks->userdata);
/* p may have been freed, so don't use it
* anymore in this function */
p = NULL;
/* p may have been freed, so don't use it
* anymore in this function */
p = NULL;
return -2;
}
}
if(r==0){
if(p != NULL) {
ssh_poll_remove_events(p, POLLIN);
}
if(p != NULL) {
ssh_poll_remove_events(p, POLLIN);
}
if(p != NULL) {
ssh_poll_remove_events(p, POLLIN);
}
if(p != NULL) {
ssh_poll_remove_events(p, POLLIN);
}
if(s->callbacks && s->callbacks->exception){
s->callbacks->exception(
SSH_SOCKET_EXCEPTION_EOF,
0,s->callbacks->userdata);
/* p may have been freed, so don't use it
* anymore in this function */
p = NULL;
/* p may have been freed, so don't use it
* anymore in this function */
p = NULL;
return -2;
}
}
if(r>0){
@@ -282,9 +284,9 @@ int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int r
buffer_get_rest_len(s->in_buffer),
s->callbacks->userdata);
buffer_pass_bytes(s->in_buffer,r);
/* p may have been freed, so don't use it
* anymore in this function */
p = NULL;
/* p may have been freed, so don't use it
* anymore in this function */
p = NULL;
}
}
}
@@ -699,6 +701,25 @@ int ssh_socket_get_status(ssh_socket s) {
return r;
}
/**
* @internal
* @brief Set a socket into the connecting state
* @param s socket handle
* @param fd file descriptor
*/
void ssh_socket_set_connecting(ssh_socket s, int fd){
ssh_socket_set_fd(s,fd);
s->state=SSH_SOCKET_CONNECTING;
/* POLLOUT is the event to wait for in a nonblocking connect */
ssh_poll_set_events(ssh_socket_get_poll_handle_in(s),POLLOUT);
#ifdef _WIN32
ssh_poll_add_events(ssh_socket_get_poll_handle_in(s),POLLWRNORM);
#endif
}
/**
* @internal
* @brief Launches a socket connection
@@ -727,13 +748,7 @@ int ssh_socket_connect(ssh_socket s, const char *host, int port, const char *bin
ssh_log(session,SSH_LOG_PROTOCOL,"Nonblocking connection socket: %d",fd);
if(fd == SSH_INVALID_SOCKET)
return SSH_ERROR;
ssh_socket_set_fd(s,fd);
s->state=SSH_SOCKET_CONNECTING;
/* POLLOUT is the event to wait for in a nonblocking connect */
ssh_poll_set_events(ssh_socket_get_poll_handle_in(s),POLLOUT);
#ifdef _WIN32
ssh_poll_add_events(ssh_socket_get_poll_handle_in(s),POLLWRNORM);
#endif
ssh_socket_set_connecting(s,fd);
leave_function();
return SSH_OK;
}

View File

@@ -21,10 +21,13 @@
* MA 02111-1307, USA.
*/
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#ifndef _WIN32
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
@@ -50,7 +53,11 @@
struct ssh_string_struct *ssh_string_new(size_t size) {
struct ssh_string_struct *str = NULL;
str = malloc(size + 4);
if (size > UINT_MAX - sizeof(struct ssh_string_struct)) {
return NULL;
}
str = malloc(sizeof(struct ssh_string_struct) + size);
if (str == NULL) {
return NULL;
}
@@ -91,8 +98,15 @@ int ssh_string_fill(struct ssh_string_struct *s, const void *data, size_t len) {
* @note The nul byte is not copied nor counted in the ouput string.
*/
struct ssh_string_struct *ssh_string_from_char(const char *what) {
struct ssh_string_struct *ptr = NULL;
size_t len = strlen(what);
struct ssh_string_struct *ptr;
size_t len;
if(what == NULL) {
errno = EINVAL;
return NULL;
}
len = strlen(what);
ptr = malloc(4 + len);
if (ptr == NULL) {
@@ -133,16 +147,22 @@ size_t ssh_string_len(struct ssh_string_struct *s) {
char *ssh_string_to_char(struct ssh_string_struct *s) {
size_t len;
char *new;
if(s==NULL)
return NULL;
len = ntohl(s->size) + 1;
new = malloc(len);
if (s == NULL || s->string == NULL) {
return NULL;
}
len = ssh_string_len(s);
if (len + 1 < len) {
return NULL;
}
new = malloc(len + 1);
if (new == NULL) {
return NULL;
}
memcpy(new, s->string, len - 1);
new[len - 1] = '\0';
memcpy(new, s->string, len);
new[len] = '\0';
return new;
}
@@ -164,7 +184,12 @@ void ssh_string_free_char(char *s) {
* @return Newly allocated copy of the string, NULL on error.
*/
struct ssh_string_struct *ssh_string_copy(struct ssh_string_struct *s) {
struct ssh_string_struct *new = malloc(ntohl(s->size) + 4);
struct ssh_string_struct *new;
if(s == NULL || s->string == NULL) {
return NULL;
}
new = malloc(ntohl(s->size) + 4);
if (new == NULL) {
return NULL;

View File

@@ -86,6 +86,12 @@ install(
if (WITH_STATIC_LIB)
add_library(${LIBSSH_THREADS_STATIC_LIBRARY} STATIC ${libssh_threads_SRCS})
if (MSVC)
set(OUTPUT_SUFFIX static)
else (MSVC)
set(OUTPUT_SUFFIX )
endif (MSVC)
set_target_properties(
${LIBSSH_THREADS_STATIC_LIBRARY}
PROPERTIES
@@ -93,15 +99,26 @@ if (WITH_STATIC_LIB)
${LIBRARY_VERSION}
SOVERSION
${LIBRARY_SOVERSION}
COMPILE_FLAGS
"-DLIBSSH_STATIC"
OUTPUT_NAME
ssh_threads
ARCHIVE_OUTPUT_DIRECTORY
${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_SUFFIX}
)
if (WIN32)
set_target_properties(
${LIBSSH_THREADS_STATIC_LIBRARY}
PROPERTIES
COMPILE_FLAGS
"-DLIBSSH_STATIC"
)
endif (WIN32)
install(
TARGETS
${LIBSSH_THREADS_STATIC_LIBRARY}
DESTINATION
${LIB_INSTALL_DIR}
${LIB_INSTALL_DIR}/${OUTPUT_SUFFIX}
COMPONENT
libraries
)

View File

@@ -41,6 +41,8 @@ static void torture_sftp_mkdir(void **state) {
snprintf(tmpdir, sizeof(tmpdir), "%s/mkdir_test", t->testdir);
rc = sftp_mkdir(t->sftp, tmpdir, 0755);
if(rc != SSH_OK)
fprintf(stderr,"error:%s\n",ssh_get_error(t->sftp->session));
assert_true(rc == 0);
/* check if it really has been created */

View File

@@ -216,6 +216,8 @@ failed:
return NULL;
}
#ifdef WITH_SFTP
struct torture_sftp *torture_sftp_session(ssh_session session) {
struct torture_sftp *t;
char template[] = "/tmp/ssh_torture_XXXXXX";
@@ -246,6 +248,8 @@ struct torture_sftp *torture_sftp_session(ssh_session session) {
if (p == NULL) {
goto failed;
}
/* useful if TESTUSER is not the local user */
chmod(template,0777);
t->testdir = strdup(p);
if (t->testdir == NULL) {
goto failed;
@@ -282,7 +286,10 @@ void torture_sftp_close(struct torture_sftp *t) {
free(t->testdir);
free(t);
}
#endif
#endif /* WITH_SFTP */
#endif /* _WIN32 */
int torture_libssh_verbosity(void){
return verbosity;

View File

@@ -119,6 +119,23 @@ static void torture_options_set_identity(void **state) {
assert_string_equal(session->identity->root->next->data, "identity1");
}
static void torture_options_proxycommand(void **state) {
ssh_session session = *state;
int rc;
/* Enable ProxyCommand */
rc = ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, "ssh -q -A -X -W %h:%p JUMPHOST");
assert_int_equal(rc, 0);
assert_string_equal(session->ProxyCommand, "ssh -q -A -X -W %h:%p JUMPHOST");
/* Disable ProxyCommand */
rc = ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, "none");
assert_int_equal(rc, 0);
assert_true(session->ProxyCommand == NULL);
}
int torture_run_tests(void) {
int rc;
const UnitTest tests[] = {
@@ -127,6 +144,7 @@ int torture_run_tests(void) {
unit_test_setup_teardown(torture_options_set_fd, setup, teardown),
unit_test_setup_teardown(torture_options_set_user, setup, teardown),
unit_test_setup_teardown(torture_options_set_identity, setup, teardown),
unit_test_setup_teardown(torture_options_proxycommand, setup, teardown),
};
ssh_init();