Compare commits

...

56 Commits

Author SHA1 Message Date
Aris Adamantiadis
48f0bfc703 security: fix for vulnerability CVE-2014-0017
When accepting a new connection, a forking server based on libssh forks
and the child process handles the request. The RAND_bytes() function of
openssl doesn't reset its state after the fork, but simply adds the
current process id (getpid) to the PRNG state, which is not guaranteed
to be unique.
This can cause several children to end up with same PRNG state which is
a security issue.

Conflicts:
	src/bind.c
2014-03-04 09:54:25 +01:00
Andreas Schneider
87549f7bb6 tests: Add a sftp_read blocking test. 2013-10-23 15:54:12 +02:00
Johannes Krude
d7ab3d7b3d socket: Call data handler as long as handler takes data.
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-10-06 17:48:40 +02:00
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
50 changed files with 854 additions and 258 deletions

View File

@@ -8,7 +8,7 @@ set(APPLICATION_NAME ${PROJECT_NAME})
set(APPLICATION_VERSION_MAJOR "0") set(APPLICATION_VERSION_MAJOR "0")
set(APPLICATION_VERSION_MINOR "5") set(APPLICATION_VERSION_MINOR "5")
set(APPLICATION_VERSION_PATCH "2") set(APPLICATION_VERSION_PATCH "5")
set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}") 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 # Increment AGE. Set REVISION to 0
# If the source code was changed, but there were no interface changes: # If the source code was changed, but there were no interface changes:
# Increment REVISION. # Increment REVISION.
set(LIBRARY_VERSION "4.2.2") set(LIBRARY_VERSION "4.2.5")
set(LIBRARY_SOVERSION "4") set(LIBRARY_SOVERSION "4")
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked # where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked

View File

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

View File

@@ -1,6 +1,33 @@
ChangeLog 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) version 0.5.2 (released 2011-09-17)
* Increased window size x10. * Increased window size x10.
* Fixed SSHv1. * Fixed SSHv1.

109
README
View File

@@ -55,17 +55,102 @@ ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
5* Copyright policy 5* Copyright policy
-_-_-_-_-_-_-_-_-_-_ -_-_-_-_-_-_-_-_-_-_
The developers of libssh have a policy of asking for contributions to be made libssh is a project with distributed copyright ownership, which means we prefer
under the personal copyright of the contributor, instead of a corporate the copyright on parts of libssh to be held by individuals rather than
copyright. 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 So if possible, if youre doing libssh changes on behalf of a company who
process. normally owns all the work you do please get them to assign personal copyright
* If libssh is copyrighted by individuals rather than corporations, ownership of your changes to you as an individual, that makes things very easy
decisions regarding enforcement and protection of copyright will, more for us to work with and avoids bringing corporate legal departments into the
likely, be made in the interests of the project, and not in the interests picture.
of any corporations shareholders.
* If we ever need to relicense a portion of the code contacting individuals If you cant do this we can still accept patches from you owned by your
for permission to do so is much easier than contacting a company. 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") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector")
endif (WITH_STACK_PROTECTOR) endif (WITH_STACK_PROTECTOR)
check_c_compiler_flag("-D_FORTIFY_SOURCE=2" WITH_FORTIFY_SOURCE) if (CMAKE_BUILD_TYPE)
if (WITH_FORTIFY_SOURCE) string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWER)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FORTIFY_SOURCE=2") if (NOT CMAKE_BUILD_TYPE_LOWER MATCHES debug)
endif (WITH_FORTIFY_SOURCE) 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) endif (${CMAKE_C_COMPILER_ID} MATCHES GNU)
# #

View File

@@ -40,20 +40,105 @@ The libssh library provides:
@section main-copyright Copyright Policy @section main-copyright Copyright Policy
The developers of libssh have a policy of asking for contributions to be made libssh is a project with distributed copyright ownership, which means we prefer
under the personal copyright of the contributor, instead of a corporate the copyright on parts of libssh to be held by individuals rather than
copyright. 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 So if possible, if youre doing libssh changes on behalf of a company who
process. normally owns all the work you do please get them to assign personal copyright
@li If libssh is copyrighted by individuals rather than corporations, ownership of your changes to you as an individual, that makes things very easy
decisions regarding enforcement and protection of copyright will, more for us to work with and avoids bringing corporate legal departments into the
likely, be made in the interests of the project, and not in the interests picture.
of any corporations shareholders.
@li If we ever need to relicense a portion of the code contacting individuals If you cant do this we can still accept patches from you owned by your
for permission to do so is much easier than contacting a company. 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 @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 - Threading must be initialized during the initialization of libssh. This
initialization must be done outside of any threading context. initialization must be done outside of any threading context.
- If pthreads is being used by your application (or your framework's backend), - 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. threading with the ssh_threads_pthreads threading object.
- If an other threading library is being used by your application, you must - If an other threading library is being used by your application, you must
implement all the methods of the ssh_threads_callbacks_struct structure implement all the methods of the ssh_threads_callbacks_struct structure
and initialize libssh with it. and initialize libssh with it.
- At all times, you may use different sessions inside threads, make parallel - 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 connections, read/write on different sessions and so on. You *cannot* use a
single session in several channels at the same time. This will lead to single session (or channels for a single session) in several threads at the same
internal state corruption. This limitation is being worked out and will time. This will most likely lead to internal state corruption. This limitation is
maybe disappear later. being worked out and will maybe disappear later.
@subsection threads_init Initialization of threads @subsection threads_init Initialization of threads
@@ -25,7 +25,7 @@ use, using ssh_threads_set_callbacks(), then call ssh_init().
@code @code
#include <libssh/callbacks.h> #include <libssh/callbacks.h>
... ...
ssh_threads_set_callbacks(ssh_threads_noop); ssh_threads_set_callbacks(ssh_threads_get_noop());
ssh_init(); ssh_init();
@endcode @endcode
@@ -40,14 +40,14 @@ threading backend:
@code @code
#include <libssh/callbacks.h> #include <libssh/callbacks.h>
... ...
ssh_threads_set_callbacks(ssh_threads_pthread); ssh_threads_set_callbacks(ssh_threads_get_pthread());
ssh_init(); ssh_init();
@endcode @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 you're using gcc, you must use the commandline
@code @code
gcc -o output input.c -lssh -lssh_threads_pthread gcc -o output input.c -lssh -lssh_threads
@endcode @endcode

View File

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

View File

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

View File

@@ -78,6 +78,7 @@ const void *_ssh_list_pop_head(struct ssh_list *list);
#define ssh_list_pop_head(type, ssh_list)\ #define ssh_list_pop_head(type, ssh_list)\
((type)_ssh_list_pop_head(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); void ssh_timestamp_init(struct ssh_timestamp *ts);
int ssh_timeout_elapsed(struct ssh_timestamp *ts, int timeout); int ssh_timeout_elapsed(struct ssh_timestamp *ts, int timeout);
int ssh_timeout_update(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_message_struct;
struct ssh_common_struct;
/* server data */ /* 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); int message_handle(ssh_session session, void *user, uint8_t type, ssh_buffer packet);
/* log.c */ /* log.c */
void ssh_log_common(struct ssh_common_struct *common, int verbosity,
const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
/* misc.c */ /* misc.c */
#ifdef _WIN32 #ifdef _WIN32
int gettimeofday(struct timeval *__p, void *__t); int gettimeofday(struct timeval *__p, void *__t);
@@ -221,16 +225,16 @@ int gettimeofday(struct timeval *__p, void *__t);
#define _enter_function(sess) \ #define _enter_function(sess) \
do {\ 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__);\ ssh_log((sess),SSH_LOG_FUNCTIONS,"entering function %s line %d in " __FILE__ , __FUNCTION__,__LINE__);\
(sess)->log_indent++; \ (sess)->common.log_indent++; \
} \ } \
} while(0) } while(0)
#define _leave_function(sess) \ #define _leave_function(sess) \
do { \ do { \
if((sess)->log_verbosity >= SSH_LOG_FUNCTIONS){ \ if((sess)->common.log_verbosity >= SSH_LOG_FUNCTIONS){ \
(sess)->log_indent--; \ (sess)->common.log_indent--; \
ssh_log((sess),SSH_LOG_FUNCTIONS,"leaving function %s line %d in " __FILE__ , __FUNCTION__,__LINE__);\ ssh_log((sess),SSH_LOG_FUNCTIONS,"leaving function %s line %d in " __FILE__ , __FUNCTION__,__LINE__);\
}\ }\
} while(0) } while(0)

View File

@@ -61,8 +61,16 @@ enum ssh_pending_call_e {
/* libssh calls may block an undefined amount of time */ /* libssh calls may block an undefined amount of time */
#define SSH_SESSION_FLAG_BLOCKING 1 #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; 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; struct ssh_socket_struct *socket;
char *serverbanner; char *serverbanner;
char *clientbanner; char *clientbanner;
@@ -128,11 +136,8 @@ struct ssh_session_struct {
struct ssh_list *ssh_message_list; /* list of delayed SSH messages */ 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); int (*ssh_message_callback)( struct ssh_session_struct *session, ssh_message msg, void *userdata);
void *ssh_message_callback_data; 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); 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_packet_callbacks_struct default_packet_callbacks;
struct ssh_list *packet_callbacks; struct ssh_list *packet_callbacks;
struct ssh_socket_callbacks_struct socket_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_in(ssh_socket s);
struct ssh_poll_handle_struct * ssh_socket_get_poll_handle_out(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); int ssh_socket_connect(ssh_socket s, const char *host, int port, const char *bind_addr);
#endif /* SOCKET_H_ */ #endif /* SOCKET_H_ */

View File

@@ -44,5 +44,6 @@ int crypt_set_algorithms_server(ssh_session session);
struct ssh_crypto_struct *crypto_new(void); struct ssh_crypto_struct *crypto_new(void);
void crypto_free(struct ssh_crypto_struct *crypto); void crypto_free(struct ssh_crypto_struct *crypto);
void ssh_reseed(void);
#endif /* WRAPPER_H_ */ #endif /* WRAPPER_H_ */

View File

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

View File

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

View File

@@ -108,6 +108,7 @@ static int send_username(ssh_session session, const char *username) {
if(wait_auth1_status(session) == SSH_AUTH_SUCCESS){ if(wait_auth1_status(session) == SSH_AUTH_SUCCESS){
session->auth_service_state=SSH_AUTH_SERVICE_USER_SENT; session->auth_service_state=SSH_AUTH_SERVICE_USER_SENT;
session->auth_state=SSH_AUTH_STATE_SUCCESS; session->auth_state=SSH_AUTH_STATE_SUCCESS;
ssh_set_error(session, SSH_NO_ERROR, "Authentication successful");
return SSH_AUTH_SUCCESS; return SSH_AUTH_SUCCESS;
} else { } else {
session->auth_service_state=SSH_AUTH_SERVICE_USER_SENT; session->auth_service_state=SSH_AUTH_SERVICE_USER_SENT;

View File

@@ -150,7 +150,7 @@ ssh_bind ssh_bind_new(void) {
ZERO_STRUCTP(ptr); ZERO_STRUCTP(ptr);
ptr->bindfd = SSH_INVALID_SOCKET; ptr->bindfd = SSH_INVALID_SOCKET;
ptr->bindport= 22; ptr->bindport= 22;
ptr->log_verbosity = 0; ptr->common.log_verbosity = 0;
return ptr; 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); ssh_socket_free(session->socket);
session->socket = ssh_socket_new(session); session->socket = ssh_socket_new(session);
@@ -374,8 +374,9 @@ int ssh_bind_accept(ssh_bind sshbind, ssh_session session) {
ssh_socket_get_poll_handle_out(session->socket); ssh_socket_get_poll_handle_out(session->socket);
session->dsa_key = dsa; session->dsa_key = dsa;
session->rsa_key = rsa; session->rsa_key = rsa;
/* force PRNG to change state in case we fork after ssh_bind_accept */
return SSH_OK; ssh_reseed();
return SSH_OK;
} }

View File

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

View File

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

View File

@@ -30,6 +30,7 @@
#include <time.h> #include <time.h>
#ifndef _WIN32 #ifndef _WIN32
#include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#endif #endif
@@ -78,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 ssh_channel_new(ssh_session session) {
ssh_channel channel = NULL; ssh_channel channel = NULL;
if(session == NULL) {
return NULL;
}
channel = malloc(sizeof(struct ssh_channel_struct)); channel = malloc(sizeof(struct ssh_channel_struct));
if (channel == NULL) { if (channel == NULL) {
ssh_set_error_oom(session); ssh_set_error_oom(session);
@@ -886,6 +891,10 @@ int channel_default_bufferize(ssh_channel channel, void *data, int len,
* @see channel_request_exec() * @see channel_request_exec()
*/ */
int ssh_channel_open_session(ssh_channel channel) { int ssh_channel_open_session(ssh_channel channel) {
if(channel == NULL) {
return SSH_ERROR;
}
#ifdef WITH_SSH1 #ifdef WITH_SSH1
if (channel->session->version == 1) { if (channel->session->version == 1) {
return channel_open_session1(channel); return channel_open_session1(channel);
@@ -933,7 +942,6 @@ int ssh_channel_open_forward(ssh_channel channel, const char *remotehost,
} }
session = channel->session; session = channel->session;
enter_function(); enter_function();
if(remotehost == NULL || sourcehost == NULL) { if(remotehost == NULL || sourcehost == NULL) {
@@ -1035,9 +1043,14 @@ void ssh_channel_free(ssh_channel channel) {
* @see channel_free() * @see channel_free()
*/ */
int ssh_channel_send_eof(ssh_channel channel){ int ssh_channel_send_eof(ssh_channel channel){
ssh_session session = channel->session; ssh_session session;
int rc = SSH_ERROR; int rc = SSH_ERROR;
if(channel == NULL) {
return rc;
}
session = channel->session;
enter_function(); enter_function();
if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_EOF) < 0) { if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_EOF) < 0) {
@@ -1079,9 +1092,14 @@ error:
* @see channel_eof() * @see channel_eof()
*/ */
int ssh_channel_close(ssh_channel channel){ int ssh_channel_close(ssh_channel channel){
ssh_session session = channel->session; ssh_session session;
int rc = 0; int rc = 0;
if(channel == NULL) {
return SSH_ERROR;
}
session = channel->session;
enter_function(); enter_function();
if (channel->local_eof == 0) { if (channel->local_eof == 0) {
@@ -1142,6 +1160,10 @@ int channel_write_common(ssh_channel channel, const void *data,
return SSH_ERROR; return SSH_ERROR;
} }
if(channel == NULL || data == NULL) {
return -1;
}
session = channel->session;
enter_function(); enter_function();
if(ssh_is_blocking(session)) if(ssh_is_blocking(session))
timeout = -2; timeout = -2;
@@ -1232,7 +1254,9 @@ int channel_write_common(ssh_channel channel, const void *data,
/* it's a good idea to flush the socket now */ /* it's a good idea to flush the socket now */
do { do {
rc = ssh_handle_packets(session, timeout); rc = ssh_handle_packets(session, timeout);
} while(ssh_socket_buffered_write_bytes(session->socket) > 0 && timeout != 0); } while(rc == SSH_OK &&
timeout != 0 &&
ssh_socket_buffered_write_bytes(session->socket) > 0);
out: out:
leave_function(); leave_function();
return (int)(origlen - len); return (int)(origlen - len);
@@ -1414,6 +1438,7 @@ static int channel_request(ssh_channel channel, const char *request,
buffer_add_ssh_string(session->out_buffer, req) < 0 || buffer_add_ssh_string(session->out_buffer, req) < 0 ||
buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1) < 0) { buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1) < 0) {
ssh_set_error_oom(session); ssh_set_error_oom(session);
ssh_string_free(req);
goto error; goto error;
} }
ssh_string_free(req); ssh_string_free(req);
@@ -1473,7 +1498,6 @@ static int channel_request(ssh_channel channel, const char *request,
return rc; return rc;
error: error:
buffer_reinit(session->out_buffer); buffer_reinit(session->out_buffer);
ssh_string_free(req);
leave_function(); leave_function();
return rc; return rc;
@@ -1494,11 +1518,16 @@ error:
*/ */
int ssh_channel_request_pty_size(ssh_channel channel, const char *terminal, int ssh_channel_request_pty_size(ssh_channel channel, const char *terminal,
int col, int row) { int col, int row) {
ssh_session session = channel->session; ssh_session session;
ssh_string term = NULL; ssh_string term = NULL;
ssh_buffer buffer = NULL; ssh_buffer buffer = NULL;
int rc = SSH_ERROR; int rc = SSH_ERROR;
if (channel == NULL) {
return SSH_ERROR;
}
session = channel->session;
enter_function(); enter_function();
#ifdef WITH_SSH1 #ifdef WITH_SSH1
if (channel->version==1) { if (channel->version==1) {
@@ -2271,11 +2300,16 @@ error:
*/ */
int channel_read_buffer(ssh_channel channel, ssh_buffer buffer, uint32_t count, int channel_read_buffer(ssh_channel channel, ssh_buffer buffer, uint32_t count,
int is_stderr) { int is_stderr) {
ssh_session session=channel->session; ssh_session session;
char buffer_tmp[8192]; char buffer_tmp[8192];
int r; int r;
uint32_t total=0; uint32_t total=0;
if (channel == NULL) {
return SSH_ERROR;
}
session = channel->session;
enter_function(); enter_function();
buffer_reinit(buffer); buffer_reinit(buffer);
if(count==0){ if(count==0){
@@ -2810,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 ssh_channel_open_reverse_forward(ssh_channel channel, const char *remotehost,
int remoteport, const char *sourcehost, int localport) { int remoteport, const char *sourcehost, int localport) {
ssh_session session = channel->session; ssh_session session;
ssh_buffer payload = NULL; ssh_buffer payload = NULL;
ssh_string str = NULL; ssh_string str = NULL;
int rc = SSH_ERROR; int rc = SSH_ERROR;
if(channel == NULL) {
return rc;
}
session = channel->session;
enter_function(); enter_function();
payload = ssh_buffer_new(); payload = ssh_buffer_new();
@@ -2878,6 +2918,10 @@ int ssh_channel_request_send_exit_status(ssh_channel channel, int exit_status) {
ssh_buffer buffer = NULL; ssh_buffer buffer = NULL;
int rc = SSH_ERROR; int rc = SSH_ERROR;
if(channel == NULL) {
return SSH_ERROR;
}
#ifdef WITH_SSH1 #ifdef WITH_SSH1
if (channel->version == 1) { if (channel->version == 1) {
return SSH_ERROR; // TODO: Add support for SSH-v1 if possible. return SSH_ERROR; // TODO: Add support for SSH-v1 if possible.
@@ -2920,7 +2964,8 @@ error:
* @return SSH_OK on success, SSH_ERROR if an error occured * @return SSH_OK on success, SSH_ERROR if an error occured
* (including attempts to send signal via SSH-v1 session). * (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_buffer buffer = NULL;
ssh_string tmp = NULL; ssh_string tmp = NULL;
int rc = SSH_ERROR; int rc = SSH_ERROR;

View File

@@ -50,11 +50,17 @@
*/ */
int channel_open_session1(ssh_channel chan) { 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 * 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. * channel. So we abort with an error if we need more than one.
*/ */
ssh_session session = chan->session;
if (session->exec_channel_opened) { if (session->exec_channel_opened) {
ssh_set_error(session, SSH_REQUEST_DENIED, ssh_set_error(session, SSH_REQUEST_DENIED,
"SSH1 supports only one execution channel. " "SSH1 supports only one execution channel. "
@@ -62,6 +68,7 @@ int channel_open_session1(ssh_channel chan) {
return -1; return -1;
} }
session->exec_channel_opened = 1; session->exec_channel_opened = 1;
chan->request_state = SSH_CHANNEL_REQ_STATE_ACCEPTED;
chan->state = SSH_CHANNEL_STATE_OPEN; chan->state = SSH_CHANNEL_STATE_OPEN;
chan->local_maxpacket = 32000; chan->local_maxpacket = 32000;
chan->local_window = 64000; chan->local_window = 64000;
@@ -84,8 +91,14 @@ int channel_open_session1(ssh_channel chan) {
int channel_request_pty_size1(ssh_channel channel, const char *terminal, int col, int channel_request_pty_size1(ssh_channel channel, const char *terminal, int col,
int row) { int row) {
ssh_session session = channel->session; ssh_session session;
ssh_string str = NULL; ssh_string str = NULL;
if (channel == NULL) {
return SSH_ERROR;
}
session = channel->session;
if(channel->request_state != SSH_CHANNEL_REQ_STATE_NONE){ if(channel->request_state != SSH_CHANNEL_REQ_STATE_NONE){
ssh_set_error(session,SSH_REQUEST_DENIED,"Wrong request state"); ssh_set_error(session,SSH_REQUEST_DENIED,"Wrong request state");
return SSH_ERROR; return SSH_ERROR;
@@ -138,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) { 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){ if(channel->request_state != SSH_CHANNEL_REQ_STATE_NONE){
ssh_set_error(session,SSH_REQUEST_DENIED,"Wrong request state"); ssh_set_error(session,SSH_REQUEST_DENIED,"Wrong request state");
return SSH_ERROR; return SSH_ERROR;
@@ -181,7 +200,12 @@ int channel_change_pty_size1(ssh_channel channel, int cols, int rows) {
} }
int channel_request_shell1(ssh_channel channel) { 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) { if (buffer_add_u8(session->out_buffer,SSH_CMSG_EXEC_SHELL) < 0) {
return -1; return -1;
@@ -197,9 +221,14 @@ int channel_request_shell1(ssh_channel channel) {
} }
int channel_request_exec1(ssh_channel channel, const char *cmd) { int channel_request_exec1(ssh_channel channel, const char *cmd) {
ssh_session session = channel->session; ssh_session session;
ssh_string command = NULL; ssh_string command = NULL;
if (channel == NULL) {
return -1;
}
session = channel->session;
command = ssh_string_from_char(cmd); command = ssh_string_from_char(cmd);
if (command == NULL) { if (command == NULL) {
return -1; return -1;
@@ -226,6 +255,11 @@ SSH_PACKET_CALLBACK(ssh_packet_data1){
ssh_string str = NULL; ssh_string str = NULL;
int is_stderr=(type==SSH_SMSG_STDOUT_DATA ? 0 : 1); int is_stderr=(type==SSH_SMSG_STDOUT_DATA ? 0 : 1);
(void)user; (void)user;
if (channel == NULL) {
return SSH_PACKET_NOT_USED;
}
str = buffer_get_ssh_string(packet); str = buffer_get_ssh_string(packet);
if (str == NULL) { if (str == NULL) {
ssh_log(session, SSH_LOG_FUNCTIONS, "Invalid data packet !\n"); ssh_log(session, SSH_LOG_FUNCTIONS, "Invalid data packet !\n");
@@ -253,6 +287,10 @@ SSH_PACKET_CALLBACK(ssh_packet_close1){
(void)type; (void)type;
(void)user; (void)user;
if (channel == NULL) {
return SSH_PACKET_NOT_USED;
}
buffer_get_u32(packet, &status); buffer_get_u32(packet, &status);
/* /*
* It's much more than a channel closing. spec says it's the last * It's much more than a channel closing. spec says it's the last
@@ -274,6 +312,11 @@ SSH_PACKET_CALLBACK(ssh_packet_exist_status1){
uint32_t status; uint32_t status;
(void)type; (void)type;
(void)user; (void)user;
if (channel == NULL) {
return SSH_PACKET_NOT_USED;
}
buffer_get_u32(packet, &status); buffer_get_u32(packet, &status);
channel->state = SSH_CHANNEL_STATE_CLOSED; channel->state = SSH_CHANNEL_STATE_CLOSED;
channel->remote_eof = 1; channel->remote_eof = 1;
@@ -284,10 +327,16 @@ SSH_PACKET_CALLBACK(ssh_packet_exist_status1){
int channel_write1(ssh_channel channel, const void *data, int len) { int channel_write1(ssh_channel channel, const void *data, int len) {
ssh_session session = channel->session; ssh_session session;
int origlen = len; int origlen = len;
int effectivelen; int effectivelen;
const unsigned char *ptr=data; const unsigned char *ptr=data;
if (channel == NULL) {
return -1;
}
session = channel->session;
while (len > 0) { while (len > 0) {
if (buffer_add_u8(session->out_buffer, SSH_CMSG_STDIN_DATA) < 0) { if (buffer_add_u8(session->out_buffer, SSH_CMSG_STDIN_DATA) < 0) {
return -1; return -1;
@@ -313,6 +362,11 @@ int channel_write1(ssh_channel channel, const void *data, int len) {
ssh_channel ssh_get_channel1(ssh_session session){ ssh_channel ssh_get_channel1(ssh_session session){
struct ssh_iterator *it; struct ssh_iterator *it;
if (session == NULL) {
return NULL;
}
/* With SSH1, the channel is always the first one */ /* With SSH1, the channel is always the first one */
if(session->channels != NULL){ if(session->channels != NULL){
it = ssh_list_get_iterator(session->channels); it = ssh_list_get_iterator(session->channels);

View File

@@ -26,6 +26,7 @@
#include <string.h> #include <string.h>
#ifndef _WIN32 #ifndef _WIN32
#include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#endif #endif
@@ -40,8 +41,8 @@
#include "libssh/misc.h" #include "libssh/misc.h"
#define set_status(session, status) do {\ #define set_status(session, status) do {\
if (session->callbacks && session->callbacks->connect_status_function) \ if (session->common.callbacks && session->common.callbacks->connect_status_function) \
session->callbacks->connect_status_function(session->callbacks->userdata, status); \ session->common.callbacks->connect_status_function(session->common.callbacks->userdata, status); \
} while (0) } while (0)
/** /**
@@ -664,7 +665,7 @@ int ssh_connect(ssh_session session) {
session->socket_callbacks.exception=ssh_socket_exception_callback; session->socket_callbacks.exception=ssh_socket_exception_callback;
session->socket_callbacks.userdata=session; session->socket_callbacks.userdata=session;
if (session->fd != SSH_INVALID_SOCKET) { 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; ret=SSH_OK;
#ifndef _WIN32 #ifndef _WIN32
} else if (session->ProxyCommand != NULL){ } else if (session->ProxyCommand != NULL){
@@ -764,7 +765,7 @@ void ssh_disconnect(ssh_session session) {
enter_function(); 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) { if (buffer_add_u8(session->out_buffer, SSH2_MSG_DISCONNECT) < 0) {
goto error; goto error;
} }
@@ -789,7 +790,7 @@ void ssh_disconnect(ssh_session session) {
} }
error: error:
session->alive = 0; session->alive = 0;
if(session->socket){ if (session->socket != NULL){
ssh_socket_reset(session->socket); ssh_socket_reset(session->socket);
} }
session->fd = SSH_INVALID_SOCKET; session->fd = SSH_INVALID_SOCKET;

View File

@@ -78,7 +78,7 @@ static enum ssh_config_opcode_e ssh_config_get_opcode(char *keyword) {
return SOC_UNSUPPORTED; return SOC_UNSUPPORTED;
} }
static char *ssh_config_get_token(char **str) { static char *ssh_config_get_cmd(char **str) {
register char *c; register char *c;
char *r; 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++) { for (r = c; *c; c++) {
if (isblank(*c)) { if (isblank(*c)) {
*c = '\0'; *c = '\0';
@@ -127,7 +146,7 @@ static int ssh_config_get_int(char **str, int notfound) {
return 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; char *p;
p = ssh_config_get_token(str); 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) { static int ssh_config_get_yesno(char **str, int notfound) {
const char *p; const char *p;
p = ssh_config_get_str(str, NULL); p = ssh_config_get_str_tok(str, NULL);
if (p == NULL) { if (p == NULL) {
return notfound; return notfound;
} }
@@ -192,8 +211,8 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
case SOC_HOST: case SOC_HOST:
*parsing = 0; *parsing = 0;
lowerhost = (session->host) ? ssh_lowercase(session->host) : NULL; lowerhost = (session->host) ? ssh_lowercase(session->host) : NULL;
for (p = ssh_config_get_str(&s, NULL); p && *p; for (p = ssh_config_get_str_tok(&s, NULL); p && *p;
p = ssh_config_get_str(&s, NULL)) { p = ssh_config_get_str_tok(&s, NULL)) {
if (match_hostname(lowerhost, p, strlen(p))) { if (match_hostname(lowerhost, p, strlen(p))) {
*parsing = 1; *parsing = 1;
} }
@@ -201,14 +220,14 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
SAFE_FREE(lowerhost); SAFE_FREE(lowerhost);
break; break;
case SOC_HOSTNAME: case SOC_HOSTNAME:
p = ssh_config_get_str(&s, NULL); p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) { if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_HOST, p); ssh_options_set(session, SSH_OPTIONS_HOST, p);
} }
break; break;
case SOC_PORT: case SOC_PORT:
if (session->port == 22) { if (session->port == 22) {
p = ssh_config_get_str(&s, NULL); p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) { if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_PORT_STR, p); 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; break;
case SOC_USERNAME: case SOC_USERNAME:
if (session->username == NULL) { if (session->username == NULL) {
p = ssh_config_get_str(&s, NULL); p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) { if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_USER, p); ssh_options_set(session, SSH_OPTIONS_USER, p);
} }
} }
break; break;
case SOC_IDENTITY: case SOC_IDENTITY:
p = ssh_config_get_str(&s, NULL); p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) { if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_ADD_IDENTITY, p); ssh_options_set(session, SSH_OPTIONS_ADD_IDENTITY, p);
} }
break; break;
case SOC_CIPHERS: case SOC_CIPHERS:
p = ssh_config_get_str(&s, NULL); p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) { if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_CIPHERS_C_S, p); ssh_options_set(session, SSH_OPTIONS_CIPHERS_C_S, p);
ssh_options_set(session, SSH_OPTIONS_CIPHERS_S_C, 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; break;
case SOC_PROTOCOL: case SOC_PROTOCOL:
p = ssh_config_get_str(&s, NULL); p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) { if (p && *parsing) {
char *a, *b; char *a, *b;
b = strdup(p); b = strdup(p);
@@ -289,13 +308,13 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
} }
break; break;
case SOC_KNOWNHOSTS: case SOC_KNOWNHOSTS:
p = ssh_config_get_str(&s, NULL); p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) { if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, p); ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, p);
} }
break; break;
case SOC_PROXYCOMMAND: case SOC_PROXYCOMMAND:
p = ssh_config_get_str(&s, NULL); p = ssh_config_get_cmd(&s);
if (p && *parsing) { if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, p); 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; int timeout_ms;
ssh_pollfd_t fds; ssh_pollfd_t fds;
int rc = 0; int rc = 0;
unsigned int len = sizeof(rc); socklen_t len = sizeof(rc);
enter_function(); enter_function();

View File

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

View File

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

View File

@@ -24,6 +24,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include "libssh/priv.h" #include "libssh/priv.h"
#include "libssh/session.h"
/** /**
* @defgroup libssh_error The SSH error functions. * @defgroup libssh_error The SSH error functions.
@@ -48,13 +49,13 @@
* @param ... The arguments for the format string. * @param ... The arguments for the format string.
*/ */
void ssh_set_error(void *error, int code, const char *descr, ...) { 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_list va;
va_start(va, descr); va_start(va, descr);
vsnprintf(err->error_buffer, ERROR_BUFFERLEN, descr, va); vsnprintf(err->error.error_buffer, ERROR_BUFFERLEN, descr, va);
va_end(va); va_end(va);
err->error_code = code; err->error.error_code = code;
ssh_log(error,SSH_LOG_RARE,"Error : %s",err->error_buffer); 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); fflush(stdout);
if (fgets(tmp, len, stdin) == NULL) { if (fgets(tmp, len, stdin) == NULL) {
free(tmp);
return 0; return 0;
} }

View File

@@ -432,6 +432,7 @@ int ssh_send_kex(ssh_session session, int server_kex) {
goto error; goto error;
} }
ssh_string_free(str); ssh_string_free(str);
str = NULL;
} }
if (buffer_add_u8(session->out_buffer, 0) < 0) { if (buffer_add_u8(session->out_buffer, 0) < 0) {

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

View File

@@ -88,6 +88,7 @@ ssh_public_key publickey_make_dss(ssh_session session, ssh_buffer buffer) {
ssh_buffer_free(buffer); ssh_buffer_free(buffer);
return NULL; return NULL;
} }
ZERO_STRUCTP(key);
key->type = SSH_KEYTYPE_DSS; key->type = SSH_KEYTYPE_DSS;
key->type_c = ssh_type_to_char(key->type); 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); ssh_buffer_free(buffer);
return NULL; return NULL;
} }
ZERO_STRUCTP(key);
key->type = type; key->type = type;
key->type_c = ssh_type_to_char(key->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"); ssh_set_error(session, SSH_FATAL, "Not enough space");
return NULL; return NULL;
} }
ZERO_STRUCTP(sign);
tmpbuf = ssh_buffer_new(); tmpbuf = ssh_buffer_new();
if (tmpbuf == NULL) { if (tmpbuf == NULL) {
@@ -1280,6 +1283,7 @@ ssh_string ssh_do_sign(ssh_session session, ssh_buffer sigbuf,
if (sign == NULL) { if (sign == NULL) {
return NULL; return NULL;
} }
ZERO_STRUCTP(sign);
switch(privatekey->type) { switch(privatekey->type) {
case SSH_KEYTYPE_DSS: case SSH_KEYTYPE_DSS:
@@ -1436,6 +1440,7 @@ ssh_string ssh_sign_session_id(ssh_session session, ssh_private_key privatekey)
if (sign == NULL) { if (sign == NULL) {
return NULL; return NULL;
} }
ZERO_STRUCTP(sign);
switch(privatekey->type) { switch(privatekey->type) {
case SSH_KEYTYPE_DSS: case SSH_KEYTYPE_DSS:

View File

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

View File

@@ -23,6 +23,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/time.h>
#include "libssh/priv.h" #include "libssh/priv.h"
#include "libssh/session.h" #include "libssh/session.h"
@@ -38,6 +39,8 @@
#include <openssl/rsa.h> #include <openssl/rsa.h>
#include <openssl/hmac.h> #include <openssl/hmac.h>
#include <openssl/opensslv.h> #include <openssl/opensslv.h>
#include <openssl/rand.h>
#ifdef HAVE_OPENSSL_AES_H #ifdef HAVE_OPENSSL_AES_H
#define HAS_AES #define HAS_AES
#include <openssl/aes.h> #include <openssl/aes.h>
@@ -66,6 +69,12 @@ static int alloc_key(struct crypto_struct *cipher) {
return 0; return 0;
} }
void ssh_reseed(void){
struct timeval tv;
gettimeofday(&tv, NULL);
RAND_add(&tv, sizeof(tv), 0.0);
}
SHACTX sha1_init(void) { SHACTX sha1_init(void) {
SHACTX c = malloc(sizeof(*c)); SHACTX c = malloc(sizeof(*c));
if (c == NULL) { if (c == NULL) {

View File

@@ -41,6 +41,9 @@ static int alloc_key(struct crypto_struct *cipher) {
return 0; return 0;
} }
void ssh_reseed(void){
}
SHACTX sha1_init(void) { SHACTX sha1_init(void) {
SHACTX ctx = NULL; SHACTX ctx = NULL;
gcry_md_open(&ctx, GCRY_MD_SHA1, 0); gcry_md_open(&ctx, GCRY_MD_SHA1, 0);

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

View File

@@ -27,6 +27,7 @@
#include <stdlib.h> #include <stdlib.h>
#ifndef _WIN32 #ifndef _WIN32
#include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#endif #endif
@@ -911,6 +912,7 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){
char *bind_addr=NULL; char *bind_addr=NULL;
uint32_t bind_port; uint32_t bind_port;
uint8_t want_reply; uint8_t want_reply;
int rc = SSH_PACKET_USED;
(void)user; (void)user;
(void)type; (void)type;
(void)packet; (void)packet;
@@ -945,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); 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); 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 { } else {
ssh_message_reply_default(msg); ssh_message_reply_default(msg);
} }
@@ -967,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); 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)) {
session->callbacks->global_request_function(session, msg, session->callbacks->userdata); session->common.callbacks->global_request_function(session, msg, session->common.callbacks->userdata);
} else { } else {
ssh_message_reply_default(msg); ssh_message_reply_default(msg);
} }
} else { } else {
ssh_log(session, SSH_LOG_PROTOCOL, "UNKNOWN SSH_MSG_GLOBAL_REQUEST %s %d", request, want_reply); 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(msg);
SAFE_FREE(request); SAFE_FREE(request);
SAFE_FREE(bind_addr); SAFE_FREE(bind_addr);
return SSH_PACKET_USED;
return rc;
} }
#endif /* WITH_SERVER */ #endif /* WITH_SERVER */

View File

@@ -655,7 +655,7 @@ char *ssh_path_expand_tilde(const char *d) {
size_t s = p - d; size_t s = p - d;
char u[128]; char u[128];
if (s > sizeof(u)) { if (s >= sizeof(u)) {
return NULL; return NULL;
} }
memcpy(u, d, s); memcpy(u, d, s);
@@ -719,7 +719,8 @@ char *ssh_path_expand_escape(ssh_session session, const char *s) {
if (*p != '%') { if (*p != '%') {
buf[i] = *p; buf[i] = *p;
i++; i++;
if (i > MAX_BUF_SIZE) { if (i >= MAX_BUF_SIZE) {
free(r);
return NULL; return NULL;
} }
buf[i] = '\0'; buf[i] = '\0';
@@ -760,18 +761,22 @@ char *ssh_path_expand_escape(ssh_session session, const char *s) {
default: default:
ssh_set_error(session, SSH_FATAL, ssh_set_error(session, SSH_FATAL,
"Wrong escape sequence detected"); "Wrong escape sequence detected");
free(r);
return NULL; return NULL;
} }
if (x == NULL) { if (x == NULL) {
ssh_set_error_oom(session); ssh_set_error_oom(session);
free(r);
return NULL; return NULL;
} }
i += strlen(x); i += strlen(x);
if (i > MAX_BUF_SIZE) { if (i >= MAX_BUF_SIZE) {
ssh_set_error(session, SSH_FATAL, ssh_set_error(session, SSH_FATAL,
"String too long"); "String too long");
free(x);
free(r);
return NULL; return NULL;
} }
l = strlen(buf); l = strlen(buf);
@@ -923,6 +928,24 @@ static int ssh_timestamp_difference(struct ssh_timestamp *old,
return msecs; 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 * @internal
* @brief Checks if a timeout is elapsed, in function of a previous * @brief Checks if a timeout is elapsed, in function of a previous
@@ -934,17 +957,20 @@ static int ssh_timestamp_difference(struct ssh_timestamp *old,
* 0 otherwise * 0 otherwise
*/ */
int ssh_timeout_elapsed(struct ssh_timestamp *ts, int timeout) { int ssh_timeout_elapsed(struct ssh_timestamp *ts, int timeout) {
struct ssh_timestamp now; struct ssh_timestamp now;
if(timeout < 0) switch(timeout) {
return 0; // -1 means infinite timeout case -2: // -2 means user-defined timeout as available in session->timeout, session->timeout_usec.
if(timeout == 0) fprintf(stderr, "ssh_timeout_elapsed called with -2. this needs to be fixed. "
return 1; // 0 means no timeout "please set a breakpoint on %s:%d and fix the caller\n", __FILE__, __LINE__);
ssh_timestamp_init(&now); case -1: // -1 means infinite timeout
return 0;
if(ssh_timestamp_difference(ts,&now) >= timeout) case 0: // 0 means no timeout
return 1; return 1;
else default:
return 0; break;
}
ssh_timestamp_init(&now);
return (ssh_timestamp_difference(ts,&now) >= timeout);
} }
/** /**

View File

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

View File

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

View File

@@ -581,7 +581,7 @@ int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout) {
int revents; int revents;
if (!ctx->polls_used) if (!ctx->polls_used)
return 0; return SSH_ERROR;
rc = ssh_poll(ctx->pollfds, ctx->polls_used, timeout); rc = ssh_poll(ctx->pollfds, ctx->polls_used, timeout);
if(rc < 0) if(rc < 0)

View File

@@ -59,8 +59,8 @@
#include "libssh/messages.h" #include "libssh/messages.h"
#define set_status(session, status) do {\ #define set_status(session, status) do {\
if (session->callbacks && session->callbacks->connect_status_function) \ if (session->common.callbacks && session->common.callbacks->connect_status_function) \
session->callbacks->connect_status_function(session->callbacks->userdata, status); \ session->common.callbacks->connect_status_function(session->common.callbacks->userdata, status); \
} while (0) } while (0)
static int dh_handshake_server(ssh_session session); static int dh_handshake_server(ssh_session session);
@@ -184,7 +184,11 @@ static int dh_handshake_server(ssh_session session) {
prv = session->rsa_key; prv = session->rsa_key;
break; break;
default: 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); 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){ static void ssh_server_connection_callback(ssh_session session){
int ssh1,ssh2; int ssh1,ssh2;
int rc;
enter_function(); enter_function();
switch(session->session_state){ switch(session->session_state){
case SSH_SESSION_STATE_NONE: case SSH_SESSION_STATE_NONE:
@@ -338,7 +344,10 @@ static void ssh_server_connection_callback(ssh_session session){
case SSH_SESSION_STATE_KEXINIT_RECEIVED: case SSH_SESSION_STATE_KEXINIT_RECEIVED:
set_status(session,0.6f); set_status(session,0.6f);
ssh_list_kex(session, &session->client_kex); // log client kex 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) { if (set_kex(session) < 0) {
goto error; goto error;
} }

View File

@@ -86,7 +86,7 @@ ssh_session ssh_new(void) {
session->alive = 0; session->alive = 0;
session->auth_methods = 0; session->auth_methods = 0;
ssh_set_blocking(session, 1); ssh_set_blocking(session, 1);
session->log_indent = 0; session->common.log_indent = 0;
session->maxchannel = FIRST_CHANNEL; session->maxchannel = FIRST_CHANNEL;
/* options */ /* options */
@@ -143,6 +143,7 @@ ssh_session ssh_new(void) {
return session; return session;
err: err:
free(id);
ssh_free(session); ssh_free(session);
return NULL; return NULL;
} }
@@ -163,10 +164,20 @@ void ssh_free(ssh_session session) {
return; return;
} }
SAFE_FREE(session->serverbanner); /* delete all channels */
SAFE_FREE(session->clientbanner); while ((it=ssh_list_get_iterator(session->channels)) != NULL) {
SAFE_FREE(session->bindaddr); ssh_channel_free(ssh_iterator_value(ssh_channel,it));
SAFE_FREE(session->banner); 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 #ifdef WITH_PCAP
if(session->pcap_ctx){ if(session->pcap_ctx){
ssh_pcap_context_free(session->pcap_ctx); ssh_pcap_context_free(session->pcap_ctx);
@@ -182,17 +193,6 @@ void ssh_free(ssh_session session) {
session->in_buffer=session->out_buffer=NULL; session->in_buffer=session->out_buffer=NULL;
crypto_free(session->current_crypto); crypto_free(session->current_crypto);
crypto_free(session->next_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 ((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;
#ifndef _WIN32 #ifndef _WIN32
agent_free(session->agent); agent_free(session->agent);
#endif /* _WIN32 */ #endif /* _WIN32 */
@@ -235,6 +235,11 @@ void ssh_free(ssh_session session) {
ssh_list_free(session->identity); ssh_list_free(session->identity);
} }
SAFE_FREE(session->serverbanner);
SAFE_FREE(session->clientbanner);
SAFE_FREE(session->bindaddr);
SAFE_FREE(session->banner);
/* options */ /* options */
SAFE_FREE(session->username); SAFE_FREE(session->username);
SAFE_FREE(session->host); SAFE_FREE(session->host);
@@ -304,7 +309,7 @@ int ssh_is_blocking(ssh_session session){
* @brief Blocking flush of the outgoing buffer * @brief Blocking flush of the outgoing buffer
* @param[in] session The SSH session * @param[in] session The SSH session
* @param[in] timeout Set an upper limit on the time for which this function * @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 * means an infinite timeout. This parameter is passed to
* the poll() function. * the poll() function.
* @returns SSH_OK on success, SSH_AGAIN if timeout occurred, * @returns SSH_OK on success, SSH_AGAIN if timeout occurred,
@@ -313,24 +318,16 @@ int ssh_is_blocking(ssh_session session){
int ssh_blocking_flush(ssh_session session, int timeout){ int ssh_blocking_flush(ssh_session session, int timeout){
ssh_socket s; ssh_socket s;
struct ssh_timestamp ts;
int rc = SSH_OK; int rc = SSH_OK;
if(session==NULL) if(session==NULL)
return SSH_ERROR; return SSH_ERROR;
enter_function();
s=session->socket; s=session->socket;
ssh_timestamp_init(&ts);
while (ssh_socket_buffered_write_bytes(s) > 0 && session->alive) { while (ssh_socket_buffered_write_bytes(s) > 0 && session->alive) {
rc=ssh_handle_packets(session, timeout); rc = ssh_handle_packets(session, timeout);
if(ssh_timeout_elapsed(&ts,timeout)){ if(rc == SSH_AGAIN || rc == SSH_ERROR) break;
rc=SSH_AGAIN;
break;
}
timeout = ssh_timeout_update(&ts, timeout);
} }
leave_function();
return rc; return rc;
} }
@@ -407,17 +404,6 @@ void ssh_set_fd_except(ssh_session session) {
ssh_socket_set_except(session->socket); ssh_socket_set_except(session->socket);
} }
static 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 * @internal
* *
@@ -497,13 +483,18 @@ int ssh_handle_packets(ssh_session session, int timeout) {
int ssh_handle_packets_termination(ssh_session session, int timeout, int ssh_handle_packets_termination(ssh_session session, int timeout,
ssh_termination_function fct, void *user){ ssh_termination_function fct, void *user){
int ret = SSH_OK; int ret = SSH_OK;
struct ssh_timestamp ts;
ssh_timestamp_init(&ts);
while(!fct(user)){ while(!fct(user)){
ret = ssh_handle_packets(session, timeout); ret = ssh_handle_packets(session, timeout);
if(ret == SSH_ERROR || ret == SSH_AGAIN) if(ret == SSH_ERROR || ret == SSH_AGAIN)
return ret; return ret;
if(fct(user)) if(fct(user))
return SSH_OK; 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; return ret;
} }

View File

@@ -35,6 +35,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#ifndef _WIN32 #ifndef _WIN32
#include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#else #else
#define S_IFSOCK 0140000 #define S_IFSOCK 0140000
@@ -668,10 +669,18 @@ int sftp_extension_supported(sftp_session sftp, const char *name,
const char *data) { const char *data) {
int i, n; int i, n;
if (sftp == NULL || name == NULL || data == NULL) {
return 0;
}
n = sftp_extensions_get_count(sftp); n = sftp_extensions_get_count(sftp);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
if (strcmp(sftp_extensions_get_name(sftp, i), name) == 0 && const char *ext_name = sftp_extensions_get_name(sftp, i);
strcmp(sftp_extensions_get_data(sftp, i), data) == 0) { 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; return 1;
} }
} }
@@ -939,6 +948,7 @@ sftp_dir sftp_opendir(sftp_session sftp, const char *path){
dir = malloc(sizeof(struct sftp_dir_struct)); dir = malloc(sizeof(struct sftp_dir_struct));
if (dir == NULL) { if (dir == NULL) {
ssh_set_error_oom(sftp->session); ssh_set_error_oom(sftp->session);
free(file);
return NULL; return NULL;
} }
ZERO_STRUCTP(dir); ZERO_STRUCTP(dir);
@@ -1193,8 +1203,8 @@ static char *sftp_parse_longname(const char *longname,
so that number of pairs equals extended_count */ so that number of pairs equals extended_count */
static sftp_attributes sftp_parse_attr_3(sftp_session sftp, ssh_buffer buf, static sftp_attributes sftp_parse_attr_3(sftp_session sftp, ssh_buffer buf,
int expectname) { int expectname) {
ssh_string longname = NULL; ssh_string longname;
ssh_string name = NULL; ssh_string name;
sftp_attributes attr; sftp_attributes attr;
uint32_t flags = 0; uint32_t flags = 0;
int ok = 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.. */ /* This isn't really a loop, but it is like a try..catch.. */
do { do {
if (expectname) { if (expectname) {
if ((name = buffer_get_ssh_string(buf)) == NULL || name = buffer_get_ssh_string(buf);
(attr->name = ssh_string_to_char(name)) == NULL) { if (name == NULL) {
break; break;
} }
attr->name = ssh_string_to_char(name);
ssh_string_free(name); ssh_string_free(name);
if (attr->name == NULL) {
break;
}
ssh_log(sftp->session, SSH_LOG_RARE, "Name: %s", attr->name); ssh_log(sftp->session, SSH_LOG_RARE, "Name: %s", attr->name);
if ((longname=buffer_get_ssh_string(buf)) == NULL || longname = buffer_get_ssh_string(buf);
(attr->longname=ssh_string_to_char(longname)) == NULL) { if (longname == NULL) {
break;
}
attr->longname = ssh_string_to_char(longname);
ssh_string_free(longname);
if (attr->longname == NULL) {
break; break;
} }
ssh_string_free(longname);
/* Set owner and group if we talk to openssh and have the longname */ /* Set owner and group if we talk to openssh and have the longname */
if (ssh_get_openssh_version(sftp->session)) { 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) { if (!ok) {
/* break issued somewhere */ /* break issued somewhere */
ssh_string_free(name);
ssh_string_free(longname);
ssh_string_free(attr->extended_type); ssh_string_free(attr->extended_type);
ssh_string_free(attr->extended_data); ssh_string_free(attr->extended_data);
SAFE_FREE(attr->name); SAFE_FREE(attr->name);
@@ -2269,6 +2285,7 @@ int sftp_mkdir(sftp_session sftp, const char *directory, mode_t mode) {
sftp_packet_write(sftp, SSH_FXP_MKDIR, buffer) < 0) { sftp_packet_write(sftp, SSH_FXP_MKDIR, buffer) < 0) {
ssh_buffer_free(buffer); ssh_buffer_free(buffer);
ssh_string_free(path); ssh_string_free(path);
return -1;
} }
ssh_buffer_free(buffer); ssh_buffer_free(buffer);
ssh_string_free(path); ssh_string_free(path);

View File

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

View File

@@ -280,10 +280,12 @@ int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int r
/* Bufferize the data and then call the callback */ /* Bufferize the data and then call the callback */
buffer_add_data(s->in_buffer,buffer,r); buffer_add_data(s->in_buffer,buffer,r);
if(s->callbacks && s->callbacks->data){ if(s->callbacks && s->callbacks->data){
r= s->callbacks->data(buffer_get_rest(s->in_buffer), do {
buffer_get_rest_len(s->in_buffer), r= s->callbacks->data(buffer_get_rest(s->in_buffer),
s->callbacks->userdata); buffer_get_rest_len(s->in_buffer),
buffer_pass_bytes(s->in_buffer,r); s->callbacks->userdata);
buffer_pass_bytes(s->in_buffer,r);
} while (r > 0);
/* p may have been freed, so don't use it /* p may have been freed, so don't use it
* anymore in this function */ * anymore in this function */
p = NULL; p = NULL;
@@ -701,6 +703,25 @@ int ssh_socket_get_status(ssh_socket s) {
return r; 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 * @internal
* @brief Launches a socket connection * @brief Launches a socket connection
@@ -729,13 +750,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); ssh_log(session,SSH_LOG_PROTOCOL,"Nonblocking connection socket: %d",fd);
if(fd == SSH_INVALID_SOCKET) if(fd == SSH_INVALID_SOCKET)
return SSH_ERROR; return SSH_ERROR;
ssh_socket_set_fd(s,fd); ssh_socket_set_connecting(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
leave_function(); leave_function();
return SSH_OK; return SSH_OK;
} }

View File

@@ -22,10 +22,12 @@
*/ */
#include <errno.h> #include <errno.h>
#include <limits.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifndef _WIN32 #ifndef _WIN32
#include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#endif #endif
@@ -51,7 +53,11 @@
struct ssh_string_struct *ssh_string_new(size_t size) { struct ssh_string_struct *ssh_string_new(size_t size) {
struct ssh_string_struct *str = NULL; 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) { if (str == NULL) {
return NULL; return NULL;
} }
@@ -141,16 +147,22 @@ size_t ssh_string_len(struct ssh_string_struct *s) {
char *ssh_string_to_char(struct ssh_string_struct *s) { char *ssh_string_to_char(struct ssh_string_struct *s) {
size_t len; size_t len;
char *new; char *new;
if(s==NULL || s->string == NULL) if (s == NULL || s->string == NULL) {
return NULL; return NULL;
len = ntohl(s->size) + 1; }
new = malloc(len);
len = ssh_string_len(s);
if (len + 1 < len) {
return NULL;
}
new = malloc(len + 1);
if (new == NULL) { if (new == NULL) {
return NULL; return NULL;
} }
memcpy(new, s->string, len - 1); memcpy(new, s->string, len);
new[len - 1] = '\0'; new[len] = '\0';
return new; return new;
} }

View File

@@ -8,4 +8,5 @@ add_cmockery_test(torture_proxycommand torture_proxycommand.c ${TORTURE_LIBRARY}
if (WITH_SFTP) if (WITH_SFTP)
add_cmockery_test(torture_sftp_static torture_sftp_static.c ${TORTURE_LIBRARY}) add_cmockery_test(torture_sftp_static torture_sftp_static.c ${TORTURE_LIBRARY})
add_cmockery_test(torture_sftp_dir torture_sftp_dir.c ${TORTURE_LIBRARY}) add_cmockery_test(torture_sftp_dir torture_sftp_dir.c ${TORTURE_LIBRARY})
add_cmockery_test(torture_sftp_read torture_sftp_read.c ${TORTURE_LIBRARY})
endif (WITH_SFTP) endif (WITH_SFTP)

View File

@@ -0,0 +1,82 @@
#define LIBSSH_STATIC
#include "torture.h"
#include "sftp.c"
#define MAX_XFER_BUF_SIZE 16384
static void setup(void **state) {
ssh_session session;
struct torture_sftp *t;
const char *host;
const char *user;
const char *password;
host = getenv("TORTURE_HOST");
if (host == NULL) {
host = "localhost";
}
user = getenv("TORTURE_USER");
password = getenv("TORTURE_PASSWORD");
session = torture_ssh_session(host, user, password);
assert_false(session == NULL);
t = torture_sftp_session(session);
assert_false(t == NULL);
*state = t;
}
static void teardown(void **state) {
struct torture_sftp *t = *state;
assert_false(t == NULL);
torture_rmdirs(t->testdir);
torture_sftp_close(t);
}
static void torture_sftp_read_blocking(void **state) {
struct torture_sftp *t = *state;
char libssh_tmp_file[] = "/tmp/libssh_sftp_test_XXXXXX";
char buf[MAX_XFER_BUF_SIZE];
ssize_t bytesread;
ssize_t byteswritten;
int fd;
sftp_file file;
file = sftp_open(t->sftp, "/usr/bin/ssh", O_RDONLY, 0);
fd = mkstemp(libssh_tmp_file);
unlink(libssh_tmp_file);
for (;;) {
bytesread = sftp_read(file, buf, MAX_XFER_BUF_SIZE);
if (bytesread == 0) {
break; /* EOF */
}
assert_false(bytesread < 0);
byteswritten = write(fd, buf, bytesread);
assert_int_equal(byteswritten, bytesread);
}
close(fd);
sftp_close(file);
}
int torture_run_tests(void) {
int rc;
const UnitTest tests[] = {
unit_test_setup_teardown(torture_sftp_read_blocking, setup, teardown)
};
ssh_init();
rc = run_tests(tests);
ssh_finalize();
return rc;
}

View File

@@ -119,6 +119,23 @@ static void torture_options_set_identity(void **state) {
assert_string_equal(session->identity->root->next->data, "identity1"); 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 torture_run_tests(void) {
int rc; int rc;
const UnitTest tests[] = { 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_fd, setup, teardown),
unit_test_setup_teardown(torture_options_set_user, 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_set_identity, setup, teardown),
unit_test_setup_teardown(torture_options_proxycommand, setup, teardown),
}; };
ssh_init(); ssh_init();