Compare commits

...

26 Commits

Author SHA1 Message Date
Andreas Schneider
273fb4cfc6 Bump version to 0.8.5
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
2018-10-29 10:50:51 +01:00
Andreas Schneider
56f7c27852 Bump SO version to 4.7.2
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit a4342b97d6)
2018-10-29 09:34:09 +01:00
Mike Frysinger
1285b37b60 doc: fix up various typos and trailing whitespace
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 963c3077a4)
2018-10-28 14:31:12 +01:00
Andreas Schneider
b7de358cdc libcrypto: Fix memory leak in evp_final()
Fixes T116

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit a280747462)
2018-10-28 14:31:09 +01:00
Meng Tan
bea6393de0 gssapi: Set correct state after sending GSSAPI_RESPONSE (select mechanism OID)
Signed-off-by: Meng Tan <mtan@wallix.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit bce8d56705)
2018-10-26 09:03:58 +02:00
Sanne Raymaekers
9158cc524c socket: Undouble socket fds
Fixes T115

Signed-off-by: Sanne Raymaekers <sraymaek@redhat.com>
(cherry picked from commit ced05eb6db)
2018-10-26 09:03:40 +02:00
Meng Tan
8ba10ef42b client: Send KEX as soon as banners are exchanged
Signed-off-by: Meng Tan <mtan@wallix.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit b796924fea)
2018-10-24 19:56:36 +02:00
Jakub Jelen
2ff8a09ee6 tests: Verify we can authenticate using ed25519 key
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 0386e088eb)
2018-10-19 21:22:21 +02:00
Jakub Jelen
d52fa9a02c tests: Global known_hosts are used for host key verification
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit e91bb29e9d)
2018-10-19 21:22:21 +02:00
Jakub Jelen
ec3fdb434c knownhosts: Consult also the global known hosts file
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit f622c4309b)
2018-10-19 21:22:21 +02:00
Jakub Jelen
d877969db3 options: Set the global known_hosts file
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit ae6b0e0f49)
2018-10-19 21:22:21 +02:00
Jakub Jelen
b1a7bd21ad tests: Verify the hostkey ordering for negotiation is correct
Previously, not all of the host keys algorithms were used for algorithm
negotiation. This verifies the algorithms list is sane and ordered
with the key types from known hosts in the first place.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit bdb3bb9ccd)
2018-10-19 21:22:21 +02:00
Jakub Jelen
0831b85002 tests: Generate valid known_hosts file, fixing the current test
Previously, the file contained the known_hosts strings separated
by NULL bytes which somehow magically worked.

The test was also expecting all the keys from the file will have
the same key type, which was not indeed true.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 32e502a79d)
2018-10-19 21:22:21 +02:00
Jakub Jelen
34d1f5e097 tests: Verify the ecdsa key types are handled correctly
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 6ec5a08639)
2018-10-19 21:22:21 +02:00
Jakub Jelen
fcf2cd0d9e kex: Use all supported hostkey algorithms for negotiation
Previously, only the algorithms we had a keys for in known_hosts
were used, which could lead to no-matching algorithms errors if the
one key we used to depend on was removed from the server.

This commit adds also the other algorithms, but lists them only after
all the key types we have in known_hosts file.

Resolves: T105

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 35a6455489)
2018-10-19 21:22:21 +02:00
Jakub Jelen
4a4ca44b19 kex: Honor more host key algorithms than the first one (ssh-ed25519)
The code as it was written used only the first algorithm from
preferred_hostkeys  array and compared it with the list returned
from the known hosts.

This commit is fixing the code so we actually compare each of the
algorithms from both of the lists and returns the intersection.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit c1a8c41c5d)
2018-10-19 21:22:21 +02:00
Jakub Jelen
17a6c3f88f knownhosts: Use the correct name for ECDSA keys for host key negotiation
The conversion from  ssh_keytype_e  to string does not work for ECDSA keys,
because different key lengths have different string representation.

The usage of  type_c  should work also for every other key type in future,
but it does not reflrect different signature types (SHA2 extension for RSA
keys), but this early in the key exchange phase, we can not make any
assumptions about supported extensions by the server.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 893b69d82b)
2018-10-19 21:22:21 +02:00
Jakub Jelen
e24bb932ed tests: Do not trace sshd
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 9285e8516b)
2018-10-19 21:22:21 +02:00
Andreas Schneider
5c2d444fa8 tests: Add option tests for global and user specific known_hosts
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 49e287006f)
2018-10-19 14:05:23 +02:00
Andreas Schneider
9763563c02 options: Add support for getting the known_hosts locations
Fixes T111

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 85fc0d5b83)
2018-10-19 14:05:21 +02:00
Andreas Schneider
5f9d9f4a53 examples: Explicitly track auth state in samplesshd-kbdint
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 0ff566b6dd)
2018-10-19 14:05:16 +02:00
Andreas Schneider
e8f3207a0d messages: Check that the requested service is 'ssh-connection'
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 9c200d3ef4)
2018-10-19 14:05:14 +02:00
Meng Tan
e5cee205c1 server: Set correct state after sending INFO_REQUEST (Kbd Interactive)
Signed-off-by: Meng Tan <mtan@wallix.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 4ea46eecce)
2018-10-19 14:05:12 +02:00
Andreas Schneider
63056d1bb1 priv: Add ssize_t if not available with MSVC
Fixes T113

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Tested-by: Wolf Wolfswinkel <wolf.wolfswinkel@objectplus.nl>
(cherry picked from commit 009ca5c9dd)
2018-10-19 14:05:08 +02:00
Andreas Schneider
09e4f3d331 packet: Add missing break in ssh_packet_incoming_filter()
CID 1396239

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit fe618a35dc)
2018-10-19 14:05:05 +02:00
Andreas Schneider
4b886ac656 src: Fix typos
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 795389ae1b)
2018-10-19 14:05:02 +02:00
45 changed files with 1108 additions and 266 deletions

View File

@@ -10,7 +10,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules")
include(DefineCMakeDefaults) include(DefineCMakeDefaults)
include(DefineCompilerFlags) include(DefineCompilerFlags)
project(libssh VERSION 0.8.4 LANGUAGES C) project(libssh VERSION 0.8.5 LANGUAGES C)
# global needed variable # global needed variable
set(APPLICATION_NAME ${PROJECT_NAME}) set(APPLICATION_NAME ${PROJECT_NAME})
@@ -22,7 +22,7 @@ set(APPLICATION_NAME ${PROJECT_NAME})
# 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.7.1") set(LIBRARY_VERSION "4.7.2")
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

@@ -1,6 +1,17 @@
ChangeLog ChangeLog
========== ==========
version 0.8.5 (released 2018-10-29)
* Added support to get known_hosts locations with ssh_options_get()
* Fixed preferred algorithm for known hosts negotiations
* Fixed KEX with some server implementations (e.g. Cisco)
* Fixed issues with MSVC
* Fixed keyboard-interactive auth in server mode
(regression from CVE-2018-10933)
* Fixed gssapi auth in server mode (regression from CVE-2018-10933)
* Fixed socket fd handling with proxy command
* Fixed a memory leak with OpenSSL
version 0.8.4 (released 2018-10-16) version 0.8.4 (released 2018-10-16)
* Fixed CVE-2018-10933 * Fixed CVE-2018-10933
* Fixed building without globbing support * Fixed building without globbing support

View File

@@ -127,7 +127,7 @@ The keyboard-interactive method is, as its name tells, interactive. The
server will issue one or more challenges that the user has to answer, server will issue one or more challenges that the user has to answer,
until the server takes an authentication decision. until the server takes an authentication decision.
ssh_userauth_kbdint() is the the main keyboard-interactive function. ssh_userauth_kbdint() is the the main keyboard-interactive function.
It will return SSH_AUTH_SUCCESS,SSH_AUTH_DENIED, SSH_AUTH_PARTIAL, It will return SSH_AUTH_SUCCESS,SSH_AUTH_DENIED, SSH_AUTH_PARTIAL,
SSH_AUTH_ERROR, or SSH_AUTH_INFO, depending on the result of the request. SSH_AUTH_ERROR, or SSH_AUTH_INFO, depending on the result of the request.
@@ -154,9 +154,9 @@ Here are a few remarks:
- Even the first call can return SSH_AUTH_DENIED or SSH_AUTH_SUCCESS. - Even the first call can return SSH_AUTH_DENIED or SSH_AUTH_SUCCESS.
- The server can send an empty question set (this is the default behavior - The server can send an empty question set (this is the default behavior
on my system) after you have sent the answers to the first questions. on my system) after you have sent the answers to the first questions.
You must still parse the answer, it might contain some You must still parse the answer, it might contain some
message from the server saying hello or such things. Just call message from the server saying hello or such things. Just call
ssh_userauth_kbdint() until needed. ssh_userauth_kbdint() until needed.
- The meaning of "name", "prompt", "instruction" may be a little - The meaning of "name", "prompt", "instruction" may be a little
confusing. An explanation is given in the RFC section that follows. confusing. An explanation is given in the RFC section that follows.
@@ -187,7 +187,7 @@ keyboard-interactive authentication, coming from the RFC itself (rfc4256):
the name and prompts. If the server presents names or prompts longer than 30 the name and prompts. If the server presents names or prompts longer than 30
characters, the client MAY truncate these fields to the length it can characters, the client MAY truncate these fields to the length it can
display. If the client does truncate any fields, there MUST be an obvious display. If the client does truncate any fields, there MUST be an obvious
indication that such truncation has occured. indication that such truncation has occurred.
The instruction field SHOULD NOT be truncated. Clients SHOULD use control The instruction field SHOULD NOT be truncated. Clients SHOULD use control
character filtering as discussed in [SSH-ARCH] to avoid attacks by character filtering as discussed in [SSH-ARCH] to avoid attacks by

View File

@@ -4,7 +4,7 @@
Port forwarding comes in SSH protocol in two different flavours: Port forwarding comes in SSH protocol in two different flavours:
direct or reverse port forwarding. Direct port forwarding is also direct or reverse port forwarding. Direct port forwarding is also
named local port forwardind, and reverse port forwarding is also called named local port forwarding, and reverse port forwarding is also called
remote port forwarding. SSH also allows X11 tunnels. remote port forwarding. SSH also allows X11 tunnels.
@@ -23,15 +23,15 @@ Mail client application Google Mail
5555 (arbitrary) | 5555 (arbitrary) |
| 143 (IMAP2) | 143 (IMAP2)
V | V |
SSH client =====> SSH server SSH client =====> SSH server
Legend: Legend:
--P-->: port connexion through port P --P-->: port connections through port P
=====>: SSH tunnel =====>: SSH tunnel
@endverbatim @endverbatim
A mail client connects to port 5555 of a client. An encrypted tunnel is A mail client connects to port 5555 of a client. An encrypted tunnel is
established to the server. The server connects to port 143 of Google Mail (the established to the server. The server connects to port 143 of Google Mail (the
end point). Now the local mail client can retreive mail. end point). Now the local mail client can retrieve mail.
@subsection forwarding_reverse Reverse port forwarding @subsection forwarding_reverse Reverse port forwarding
@@ -51,7 +51,7 @@ Example of use of reverse port forwarding:
SSH client <===== SSH server SSH client <===== SSH server
Legend: Legend:
--P-->: port connexion through port P --P-->: port connections through port P
=====>: SSH tunnel =====>: SSH tunnel
@endverbatim @endverbatim
In this example, the SSH client establishes the tunnel, In this example, the SSH client establishes the tunnel,
@@ -148,9 +148,9 @@ To do reverse port forwarding, call ssh_channel_listen_forward(),
then ssh_channel_accept_forward(). then ssh_channel_accept_forward().
When you call ssh_channel_listen_forward(), you can let the remote server When you call ssh_channel_listen_forward(), you can let the remote server
chose the non-priviledged port it should listen to. Otherwise, you can chose chose the non-privileged port it should listen to. Otherwise, you can chose
your own priviledged or non-priviledged port. Beware that you should have your own privileged or non-privileged port. Beware that you should have
administrative priviledges on the remote server to open a priviledged port administrative privileges on the remote server to open a privileged port
(port number < 1024). (port number < 1024).
Below is an example of a very rough web server waiting for connections on port Below is an example of a very rough web server waiting for connections on port

View File

@@ -31,20 +31,20 @@ A SSH session goes through the following steps:
- Invoke your own subsystem. This is outside the scope of this document, - Invoke your own subsystem. This is outside the scope of this document,
but can be done. but can be done.
- When everything is finished, just close the channels, and then the connection. - When everything is finished, just close the channels, and then the connection.
The sftp and scp subsystems use channels, but libssh hides them to The sftp and scp subsystems use channels, but libssh hides them to
the programmer. If you want to use those subsystems, instead of a channel, the programmer. If you want to use those subsystems, instead of a channel,
you'll usually open a "sftp session" or a "scp session". you'll usually open a "sftp session" or a "scp session".
@subsection setup Creating the session and setting options @subsection setup Creating the session and setting options
The most important object in a SSH connection is the SSH session. In order The most important object in a SSH connection is the SSH session. In order
to allocate a new SSH session, you use ssh_new(). Don't forget to to allocate a new SSH session, you use ssh_new(). Don't forget to
always verify that the allocation successed. always verify that the allocation succeeded.
@code @code
#include <libssh/libssh.h> #include <libssh/libssh.h>
#include <stdlib.h> #include <stdlib.h>
int main() int main()
@@ -69,12 +69,12 @@ The ssh_options_set() function sets the options of the session. The most importa
The complete list of options can be found in the documentation of ssh_options_set(). The complete list of options can be found in the documentation of ssh_options_set().
The only mandatory option is SSH_OPTIONS_HOST. If you don't use SSH_OPTIONS_USER, The only mandatory option is SSH_OPTIONS_HOST. If you don't use SSH_OPTIONS_USER,
the local username of your account will be used. the local username of your account will be used.
Here is a small example of how to use it: Here is a small example of how to use it:
@code @code
#include <libssh/libssh.h> #include <libssh/libssh.h>
#include <stdlib.h> #include <stdlib.h>
int main() int main()
@@ -122,7 +122,7 @@ Here's an example:
@code @code
#include <libssh/libssh.h> #include <libssh/libssh.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
int main() int main()
{ {
@@ -285,9 +285,9 @@ int verify_knownhost(ssh_session session)
The authentication process is the way a service provider can identify a The authentication process is the way a service provider can identify a
user and verify his/her identity. The authorization process is about enabling user and verify his/her identity. The authorization process is about enabling
the authenticated user the access to ressources. In SSH, the two concepts the authenticated user the access to resources. In SSH, the two concepts
are linked. After authentication, the server can grant the user access to are linked. After authentication, the server can grant the user access to
several ressources such as port forwarding, shell, sftp subsystem, and so on. several resources such as port forwarding, shell, sftp subsystem, and so on.
libssh supports several methods of authentication: libssh supports several methods of authentication:
- "none" method. This method allows to get the available authentications - "none" method. This method allows to get the available authentications
@@ -313,7 +313,7 @@ The example below shows an authentication with password:
@code @code
#include <libssh/libssh.h> #include <libssh/libssh.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
int main() int main()
{ {
@@ -338,7 +338,7 @@ int main()
} }
// Verify the server's identity // Verify the server's identity
// For the source code of verify_knowhost(), check previous example // For the source code of verify_knownhost(), check previous example
if (verify_knownhost(my_ssh_session) < 0) if (verify_knownhost(my_ssh_session) < 0)
{ {
ssh_disconnect(my_ssh_session); ssh_disconnect(my_ssh_session);
@@ -415,7 +415,7 @@ int show_remote_processes(ssh_session session)
} }
nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0); nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
} }
if (nbytes < 0) if (nbytes < 0)
{ {
ssh_channel_close(channel); ssh_channel_close(channel);
@@ -456,7 +456,7 @@ might be recoverable. SSH_FATAL means the connection has an important
problem and isn't probably recoverable. problem and isn't probably recoverable.
Most of time, the error returned are SSH_FATAL, but some functions Most of time, the error returned are SSH_FATAL, but some functions
(generaly the ssh_request_xxx ones) may fail because of server denying request. (generally the ssh_request_xxx ones) may fail because of server denying request.
In these cases, SSH_REQUEST_DENIED is returned. In these cases, SSH_REQUEST_DENIED is returned.
For thread safety, errors are bound to ssh_session objects. For thread safety, errors are bound to ssh_session objects.

View File

@@ -12,13 +12,13 @@ mean that you should not try to know about and understand these details.
libssh is a Free Software / Open Source project. The libssh library libssh is a Free Software / Open Source project. The libssh library
is distributed under LGPL license. The libssh project has nothing to do with is distributed under LGPL license. The libssh project has nothing to do with
"libssh2", which is a completly different and independant project. "libssh2", which is a completely different and independent project.
libssh can run on top of either libgcrypt or libcrypto, libssh can run on top of either libgcrypt or libcrypto,
two general-purpose cryptographic libraries. two general-purpose cryptographic libraries.
This tutorial concentrates for its main part on the "client" side of libssh. This tutorial concentrates for its main part on the "client" side of libssh.
To learn how to accept incoming SSH connexions (how to write a SSH server), To learn how to accept incoming SSH connections (how to write a SSH server),
you'll have to jump to the end of this document. you'll have to jump to the end of this document.
This tutorial describes libssh version 0.5.0. This version is a little different This tutorial describes libssh version 0.5.0. This version is a little different

View File

@@ -2,7 +2,7 @@
@page libssh_tutor_scp Chapter 6: The SCP subsystem @page libssh_tutor_scp Chapter 6: The SCP subsystem
@section scp_subsystem The SCP subsystem @section scp_subsystem The SCP subsystem
The SCP subsystem has far less functionnality than the SFTP subsystem. The SCP subsystem has far less functionality than the SFTP subsystem.
However, if you only need to copy files from and to the remote system, However, if you only need to copy files from and to the remote system,
it does its job. it does its job.
@@ -158,7 +158,7 @@ Let's say you want to copy the following tree of files to the remote site:
+-- file1 +-- file1
+-- B --+ +-- B --+
| +-- file2 | +-- file2
-- A --+ -- A --+
| +-- file3 | +-- file3
+-- C --+ +-- C --+
+-- file4 +-- file4
@@ -210,7 +210,7 @@ int scp_receive(ssh_session session, ssh_scp scp)
size = ssh_scp_request_get_size(scp); size = ssh_scp_request_get_size(scp);
filename = strdup(ssh_scp_request_get_filename(scp)); filename = strdup(ssh_scp_request_get_filename(scp));
mode = ssh_scp_request_get_permissions(scp); mode = ssh_scp_request_get_permissions(scp);
printf("Receiving file %s, size %d, permisssions 0%o\n", printf("Receiving file %s, size %d, permissions 0%o\n",
filename, size, mode); filename, size, mode);
free(filename); free(filename);

View File

@@ -100,7 +100,7 @@ Possible errors are:
@subsection sftp_mkdir Creating a directory @subsection sftp_mkdir Creating a directory
The function sftp_mkdir() tahes the "SFTP session" we juste created as The function sftp_mkdir() takes the "SFTP session" we just created as
its first argument. It also needs the name of the file to create, and the its first argument. It also needs the name of the file to create, and the
desired permissions. The permissions are the same as for the usual mkdir() desired permissions. The permissions are the same as for the usual mkdir()
function. To get a comprehensive list of the available permissions, use the function. To get a comprehensive list of the available permissions, use the
@@ -358,19 +358,19 @@ int sftp_read_async(ssh_session session, sftp_session sftp)
@subsection sftp_ls Listing the contents of a directory @subsection sftp_ls Listing the contents of a directory
The functions sftp_opendir(), sftp_readdir(), sftp_dir_eof(), The functions sftp_opendir(), sftp_readdir(), sftp_dir_eof(),
and sftp_closedir() enable to list the contents of a directory. and sftp_closedir() enable to list the contents of a directory.
They use a new handle_type, "sftp_dir", which gives access to the They use a new handle_type, "sftp_dir", which gives access to the
directory being read. directory being read.
In addition, sftp_readdir() returns a "sftp_attributes" which is a pointer In addition, sftp_readdir() returns a "sftp_attributes" which is a pointer
to a structure with informations about a directory entry: to a structure with information about a directory entry:
- name: the name of the file or directory - name: the name of the file or directory
- size: its size in bytes - size: its size in bytes
- etc. - etc.
sftp_readdir() might return NULL under two conditions: sftp_readdir() might return NULL under two conditions:
- when the end of the directory has been met - when the end of the directory has been met
- when an error occured - when an error occurred
To tell the difference, call sftp_dir_eof(). To tell the difference, call sftp_dir_eof().

View File

@@ -209,7 +209,7 @@ int interactive_shell_session(ssh_channel channel)
Of course, this is a poor terminal emulator, since the echo from the keys Of course, this is a poor terminal emulator, since the echo from the keys
pressed should not be done locally, but should be done by the remote side. pressed should not be done locally, but should be done by the remote side.
Also, user's input should not be sent once "Enter" key is pressed, but Also, user's input should not be sent once "Enter" key is pressed, but
immediately after each key is pressed. This can be accomplished immediately after each key is pressed. This can be accomplished
by setting the local terminal to "raw" mode with the cfmakeraw(3) function. by setting the local terminal to "raw" mode with the cfmakeraw(3) function.
cfmakeraw() is a standard function under Linux, on other systems you can cfmakeraw() is a standard function under Linux, on other systems you can
@@ -245,13 +245,13 @@ provide a more elegant way to wait for data coming from many sources.
The functions ssh_select() and ssh_channel_select() remind of the standard The functions ssh_select() and ssh_channel_select() remind of the standard
UNIX select(2) function. The idea is to wait for "something" to happen: UNIX select(2) function. The idea is to wait for "something" to happen:
incoming data to be read, outcoming data to block, or an exception to incoming data to be read, outgoing data to block, or an exception to
occur. Both these functions do a "passive wait", i.e. you can safely use occur. Both these functions do a "passive wait", i.e. you can safely use
them repeatedly in a loop, it will not consume exaggerate processor time them repeatedly in a loop, it will not consume exaggerate processor time
and make your computer unresponsive. It is quite common to use these and make your computer unresponsive. It is quite common to use these
functions in your application's main loop. functions in your application's main loop.
The difference between ssh_select() and ssh_channel_select() is that The difference between ssh_select() and ssh_channel_select() is that
ssh_channel_select() is simpler, but allows you only to watch SSH channels. ssh_channel_select() is simpler, but allows you only to watch SSH channels.
ssh_select() is more complete and enables watching regular file descriptors ssh_select() is more complete and enables watching regular file descriptors
as well, in the same function call. as well, in the same function call.

View File

@@ -11,10 +11,10 @@ libssh may be used in multithreaded applications, but under several conditions :
- If libssh is statically linked, threading must be initialized by calling - If libssh is statically linked, threading must be initialized by calling
ssh_init() before using any of libssh provided functions. This initialization ssh_init() before using any of libssh provided functions. This initialization
must be done outside of any threading context. Don't forget to call must be done outside of any threading context. Don't forget to call
ssh_finalize() to avoid memory leak ssh_finalize() to avoid memory leak
- 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 *cannot* use a connections, read/write on different sessions and so on. You *cannot* use a
single session (or channels for a single session) in several threads at the same single session (or channels for a single session) in several threads at the same
time. This will most likely lead to internal state corruption. This limitation is time. This will most likely lead to internal state corruption. This limitation is
being worked out and will maybe disappear later. being worked out and will maybe disappear later.

View File

@@ -23,6 +23,7 @@ clients must be made or how a client should react.
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <stdbool.h>
#define SSHD_USER "libssh" #define SSHD_USER "libssh"
#define SSHD_PASSWORD "libssh" #define SSHD_PASSWORD "libssh"
@@ -36,6 +37,7 @@ clients must be made or how a client should react.
#endif #endif
static int port = 22; static int port = 22;
static bool authenticated = false;
#ifdef WITH_PCAP #ifdef WITH_PCAP
static const char *pcap_file = "debug.server.pcap"; static const char *pcap_file = "debug.server.pcap";
@@ -61,11 +63,20 @@ static void cleanup_pcap(void) {
#endif #endif
static int auth_password(const char *user, const char *password){ static int auth_password(const char *user, const char *password)
if(strcmp(user, SSHD_USER)) {
int cmp;
cmp = strcmp(user, SSHD_USER);
if (cmp != 0) {
return 0; return 0;
if(strcmp(password, SSHD_PASSWORD)) }
cmp = strcmp(password, SSHD_PASSWORD);
if (cmp != 0) {
return 0; return 0;
}
authenticated = true;
return 1; // authenticated return 1; // authenticated
} }
#ifdef HAVE_ARGP_H #ifdef HAVE_ARGP_H
@@ -200,6 +211,7 @@ static int kbdint_check_response(ssh_session session) {
return 0; return 0;
} }
authenticated = true;
return 1; return 1;
} }
@@ -328,7 +340,7 @@ int main(int argc, char **argv){
/* proceed to authentication */ /* proceed to authentication */
auth = authenticate(session); auth = authenticate(session);
if(!auth){ if (!auth || !authenticated) {
printf("Authentication error: %s\n", ssh_get_error(session)); printf("Authentication error: %s\n", ssh_get_error(session));
ssh_disconnect(session); ssh_disconnect(session);
return 1; return 1;

View File

@@ -45,5 +45,6 @@ char *ssh_find_matching(const char *in_d, const char *what_d);
const char *ssh_kex_get_supported_method(uint32_t algo); const char *ssh_kex_get_supported_method(uint32_t algo);
const char *ssh_kex_get_default_methods(uint32_t algo); const char *ssh_kex_get_default_methods(uint32_t algo);
const char *ssh_kex_get_description(uint32_t algo); const char *ssh_kex_get_description(uint32_t algo);
char *ssh_client_select_hostkeys(ssh_session session);
#endif /* KEX_H_ */ #endif /* KEX_H_ */

View File

@@ -23,5 +23,9 @@
#define SSH_KNOWNHOSTS_H_ #define SSH_KNOWNHOSTS_H_
struct ssh_list *ssh_known_hosts_get_algorithms(ssh_session session); struct ssh_list *ssh_known_hosts_get_algorithms(ssh_session session);
enum ssh_known_hosts_e
ssh_session_get_known_hosts_entry_file(ssh_session session,
const char *filename,
struct ssh_knownhosts_entry **pentry);
#endif /* SSH_KNOWNHOSTS_H_ */ #endif /* SSH_KNOWNHOSTS_H_ */

View File

@@ -79,7 +79,7 @@
/* libssh version */ /* libssh version */
#define LIBSSH_VERSION_MAJOR 0 #define LIBSSH_VERSION_MAJOR 0
#define LIBSSH_VERSION_MINOR 8 #define LIBSSH_VERSION_MINOR 8
#define LIBSSH_VERSION_MICRO 4 #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

@@ -29,6 +29,7 @@
#ifndef _LIBSSH_PRIV_H #ifndef _LIBSSH_PRIV_H
#define _LIBSSH_PRIV_H #define _LIBSSH_PRIV_H
#include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -128,6 +129,13 @@ char *strndup(const char *s, size_t n);
# endif /* HAVE__VSNPRINTF */ # endif /* HAVE__VSNPRINTF */
# endif /* HAVE__VSNPRINTF_S */ # endif /* HAVE__VSNPRINTF_S */
# ifndef _SSIZE_T_DEFINED
# undef ssize_t
# include <BaseTsd.h>
typedef _W64 SSIZE_T ssize_t;
# define _SSIZE_T_DEFINED
# endif /* _SSIZE_T_DEFINED */
# endif /* _MSC_VER */ # endif /* _MSC_VER */
struct timeval; struct timeval;

View File

@@ -53,9 +53,14 @@ extern "C" {
typedef uint32_t gid_t; typedef uint32_t gid_t;
#endif /* gid_t */ #endif /* gid_t */
#ifdef _MSC_VER #ifdef _MSC_VER
#ifndef ssize_t
typedef _W64 SSIZE_T ssize_t; # ifndef _SSIZE_T_DEFINED
#endif /* ssize_t */ # undef ssize_t
# include <BaseTsd.h>
typedef _W64 SSIZE_T ssize_t;
# define _SSIZE_T_DEFINED
# endif /* _SSIZE_T_DEFINED */
#endif /* _MSC_VER */ #endif /* _MSC_VER */
#endif /* _WIN32 */ #endif /* _WIN32 */

View File

@@ -34,7 +34,7 @@ ssh_socket ssh_socket_new(ssh_session session);
void ssh_socket_reset(ssh_socket s); void ssh_socket_reset(ssh_socket s);
void ssh_socket_free(ssh_socket s); void ssh_socket_free(ssh_socket s);
void ssh_socket_set_fd(ssh_socket s, socket_t fd); void ssh_socket_set_fd(ssh_socket s, socket_t fd);
socket_t ssh_socket_get_fd_in(ssh_socket s); socket_t ssh_socket_get_fd(ssh_socket s);
#ifndef _WIN32 #ifndef _WIN32
int ssh_socket_unix(ssh_socket s, const char *path); int ssh_socket_unix(ssh_socket s, const char *path);
void ssh_execute_command(const char *command, socket_t in, socket_t out); void ssh_execute_command(const char *command, socket_t in, socket_t out);
@@ -61,8 +61,7 @@ int ssh_socket_set_blocking(socket_t fd);
void ssh_socket_set_callbacks(ssh_socket s, ssh_socket_callbacks callbacks); void ssh_socket_set_callbacks(ssh_socket s, ssh_socket_callbacks callbacks);
int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int revents, void *v_s); int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int revents, void *v_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(ssh_socket s);
struct ssh_poll_handle_struct * ssh_socket_get_poll_handle_out(ssh_socket s);
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);

View File

@@ -1 +1 @@
4.7.1 4.7.2

View File

@@ -0,0 +1,415 @@
_ssh_log
buffer_free
buffer_get
buffer_get_len
buffer_new
channel_accept_x11
channel_change_pty_size
channel_close
channel_forward_accept
channel_forward_cancel
channel_forward_listen
channel_free
channel_get_exit_status
channel_get_session
channel_is_closed
channel_is_eof
channel_is_open
channel_new
channel_open_forward
channel_open_session
channel_poll
channel_read
channel_read_buffer
channel_read_nonblocking
channel_request_env
channel_request_exec
channel_request_pty
channel_request_pty_size
channel_request_send_signal
channel_request_sftp
channel_request_shell
channel_request_subsystem
channel_request_x11
channel_select
channel_send_eof
channel_set_blocking
channel_write
channel_write_stderr
privatekey_free
privatekey_from_file
publickey_free
publickey_from_file
publickey_from_privatekey
publickey_to_string
sftp_async_read
sftp_async_read_begin
sftp_attributes_free
sftp_canonicalize_path
sftp_chmod
sftp_chown
sftp_client_message_free
sftp_client_message_get_data
sftp_client_message_get_filename
sftp_client_message_get_flags
sftp_client_message_get_submessage
sftp_client_message_get_type
sftp_client_message_set_filename
sftp_close
sftp_closedir
sftp_dir_eof
sftp_extension_supported
sftp_extensions_get_count
sftp_extensions_get_data
sftp_extensions_get_name
sftp_file_set_blocking
sftp_file_set_nonblocking
sftp_free
sftp_fstat
sftp_fstatvfs
sftp_fsync
sftp_get_client_message
sftp_get_error
sftp_handle
sftp_handle_alloc
sftp_handle_remove
sftp_init
sftp_lstat
sftp_mkdir
sftp_new
sftp_new_channel
sftp_open
sftp_opendir
sftp_read
sftp_readdir
sftp_readlink
sftp_rename
sftp_reply_attr
sftp_reply_data
sftp_reply_handle
sftp_reply_name
sftp_reply_names
sftp_reply_names_add
sftp_reply_status
sftp_rewind
sftp_rmdir
sftp_seek
sftp_seek64
sftp_send_client_message
sftp_server_init
sftp_server_new
sftp_server_version
sftp_setstat
sftp_stat
sftp_statvfs
sftp_statvfs_free
sftp_symlink
sftp_tell
sftp_tell64
sftp_unlink
sftp_utimes
sftp_write
ssh_accept
ssh_add_channel_callbacks
ssh_auth_list
ssh_basename
ssh_bind_accept
ssh_bind_accept_fd
ssh_bind_fd_toaccept
ssh_bind_free
ssh_bind_get_fd
ssh_bind_listen
ssh_bind_new
ssh_bind_options_set
ssh_bind_set_blocking
ssh_bind_set_callbacks
ssh_bind_set_fd
ssh_blocking_flush
ssh_buffer_add_data
ssh_buffer_free
ssh_buffer_get
ssh_buffer_get_data
ssh_buffer_get_len
ssh_buffer_new
ssh_buffer_reinit
ssh_channel_accept_forward
ssh_channel_accept_x11
ssh_channel_cancel_forward
ssh_channel_change_pty_size
ssh_channel_close
ssh_channel_free
ssh_channel_get_exit_status
ssh_channel_get_session
ssh_channel_is_closed
ssh_channel_is_eof
ssh_channel_is_open
ssh_channel_listen_forward
ssh_channel_new
ssh_channel_open_auth_agent
ssh_channel_open_forward
ssh_channel_open_reverse_forward
ssh_channel_open_session
ssh_channel_open_x11
ssh_channel_poll
ssh_channel_poll_timeout
ssh_channel_read
ssh_channel_read_nonblocking
ssh_channel_read_timeout
ssh_channel_request_auth_agent
ssh_channel_request_env
ssh_channel_request_exec
ssh_channel_request_pty
ssh_channel_request_pty_size
ssh_channel_request_send_break
ssh_channel_request_send_exit_signal
ssh_channel_request_send_exit_status
ssh_channel_request_send_signal
ssh_channel_request_sftp
ssh_channel_request_shell
ssh_channel_request_subsystem
ssh_channel_request_x11
ssh_channel_select
ssh_channel_send_eof
ssh_channel_set_blocking
ssh_channel_set_counter
ssh_channel_window_size
ssh_channel_write
ssh_channel_write_stderr
ssh_clean_pubkey_hash
ssh_connect
ssh_connector_free
ssh_connector_new
ssh_connector_set_in_channel
ssh_connector_set_in_fd
ssh_connector_set_out_channel
ssh_connector_set_out_fd
ssh_copyright
ssh_dirname
ssh_disconnect
ssh_dump_knownhost
ssh_event_add_connector
ssh_event_add_fd
ssh_event_add_session
ssh_event_dopoll
ssh_event_free
ssh_event_new
ssh_event_remove_connector
ssh_event_remove_fd
ssh_event_remove_session
ssh_execute_message_callbacks
ssh_finalize
ssh_forward_accept
ssh_forward_cancel
ssh_forward_listen
ssh_free
ssh_get_cipher_in
ssh_get_cipher_out
ssh_get_clientbanner
ssh_get_disconnect_message
ssh_get_error
ssh_get_error_code
ssh_get_fd
ssh_get_fingerprint_hash
ssh_get_hexa
ssh_get_hmac_in
ssh_get_hmac_out
ssh_get_issue_banner
ssh_get_kex_algo
ssh_get_log_callback
ssh_get_log_level
ssh_get_log_userdata
ssh_get_openssh_version
ssh_get_poll_flags
ssh_get_pubkey
ssh_get_pubkey_hash
ssh_get_publickey
ssh_get_publickey_hash
ssh_get_random
ssh_get_server_publickey
ssh_get_serverbanner
ssh_get_status
ssh_get_version
ssh_getpass
ssh_gssapi_get_creds
ssh_gssapi_set_creds
ssh_handle_key_exchange
ssh_init
ssh_is_blocking
ssh_is_connected
ssh_is_server_known
ssh_key_cmp
ssh_key_free
ssh_key_is_private
ssh_key_is_public
ssh_key_new
ssh_key_type
ssh_key_type_from_name
ssh_key_type_to_char
ssh_known_hosts_parse_line
ssh_knownhosts_entry_free
ssh_log
ssh_message_auth_interactive_request
ssh_message_auth_kbdint_is_response
ssh_message_auth_password
ssh_message_auth_pubkey
ssh_message_auth_publickey
ssh_message_auth_publickey_state
ssh_message_auth_reply_pk_ok
ssh_message_auth_reply_pk_ok_simple
ssh_message_auth_reply_success
ssh_message_auth_set_methods
ssh_message_auth_user
ssh_message_channel_request_channel
ssh_message_channel_request_command
ssh_message_channel_request_env_name
ssh_message_channel_request_env_value
ssh_message_channel_request_open_destination
ssh_message_channel_request_open_destination_port
ssh_message_channel_request_open_originator
ssh_message_channel_request_open_originator_port
ssh_message_channel_request_open_reply_accept
ssh_message_channel_request_pty_height
ssh_message_channel_request_pty_pxheight
ssh_message_channel_request_pty_pxwidth
ssh_message_channel_request_pty_term
ssh_message_channel_request_pty_width
ssh_message_channel_request_reply_success
ssh_message_channel_request_subsystem
ssh_message_channel_request_x11_auth_cookie
ssh_message_channel_request_x11_auth_protocol
ssh_message_channel_request_x11_screen_number
ssh_message_channel_request_x11_single_connection
ssh_message_free
ssh_message_get
ssh_message_global_request_address
ssh_message_global_request_port
ssh_message_global_request_reply_success
ssh_message_reply_default
ssh_message_retrieve
ssh_message_service_reply_success
ssh_message_service_service
ssh_message_subtype
ssh_message_type
ssh_mkdir
ssh_new
ssh_options_copy
ssh_options_get
ssh_options_get_port
ssh_options_getopt
ssh_options_parse_config
ssh_options_set
ssh_pcap_file_close
ssh_pcap_file_free
ssh_pcap_file_new
ssh_pcap_file_open
ssh_pki_copy_cert_to_privkey
ssh_pki_export_privkey_base64
ssh_pki_export_privkey_file
ssh_pki_export_privkey_to_pubkey
ssh_pki_export_pubkey_base64
ssh_pki_export_pubkey_file
ssh_pki_generate
ssh_pki_import_cert_base64
ssh_pki_import_cert_file
ssh_pki_import_privkey_base64
ssh_pki_import_privkey_file
ssh_pki_import_pubkey_base64
ssh_pki_import_pubkey_file
ssh_pki_key_ecdsa_name
ssh_print_hash
ssh_print_hexa
ssh_privatekey_type
ssh_publickey_to_file
ssh_remove_channel_callbacks
ssh_scp_accept_request
ssh_scp_close
ssh_scp_deny_request
ssh_scp_free
ssh_scp_init
ssh_scp_leave_directory
ssh_scp_new
ssh_scp_pull_request
ssh_scp_push_directory
ssh_scp_push_file
ssh_scp_push_file64
ssh_scp_read
ssh_scp_request_get_filename
ssh_scp_request_get_permissions
ssh_scp_request_get_size
ssh_scp_request_get_size64
ssh_scp_request_get_warning
ssh_scp_write
ssh_select
ssh_send_debug
ssh_send_ignore
ssh_send_keepalive
ssh_server_init_kex
ssh_service_request
ssh_session_export_known_hosts_entry
ssh_session_has_known_hosts_entry
ssh_session_is_known_server
ssh_session_update_known_hosts
ssh_set_agent_channel
ssh_set_agent_socket
ssh_set_auth_methods
ssh_set_blocking
ssh_set_callbacks
ssh_set_channel_callbacks
ssh_set_counters
ssh_set_fd_except
ssh_set_fd_toread
ssh_set_fd_towrite
ssh_set_log_callback
ssh_set_log_level
ssh_set_log_userdata
ssh_set_message_callback
ssh_set_pcap_file
ssh_set_server_callbacks
ssh_silent_disconnect
ssh_string_burn
ssh_string_copy
ssh_string_data
ssh_string_fill
ssh_string_free
ssh_string_free_char
ssh_string_from_char
ssh_string_get_char
ssh_string_len
ssh_string_new
ssh_string_to_char
ssh_threads_get_noop
ssh_threads_get_pthread
ssh_threads_set_callbacks
ssh_try_publickey_from_file
ssh_userauth_agent
ssh_userauth_agent_pubkey
ssh_userauth_autopubkey
ssh_userauth_gssapi
ssh_userauth_kbdint
ssh_userauth_kbdint_getanswer
ssh_userauth_kbdint_getinstruction
ssh_userauth_kbdint_getname
ssh_userauth_kbdint_getnanswers
ssh_userauth_kbdint_getnprompts
ssh_userauth_kbdint_getprompt
ssh_userauth_kbdint_setanswer
ssh_userauth_list
ssh_userauth_none
ssh_userauth_offer_pubkey
ssh_userauth_password
ssh_userauth_privatekey_file
ssh_userauth_pubkey
ssh_userauth_publickey
ssh_userauth_publickey_auto
ssh_userauth_try_publickey
ssh_version
ssh_write_knownhost
string_burn
string_copy
string_data
string_fill
string_free
string_from_char
string_len
string_new
string_to_char

View File

@@ -93,7 +93,7 @@ static size_t atomicio(struct ssh_agent_struct *agent, void *buf, size_t n, int
/* Using a socket ? */ /* Using a socket ? */
if (channel == NULL) { if (channel == NULL) {
fd = ssh_socket_get_fd_in(agent->sock); fd = ssh_socket_get_fd(agent->sock);
pfd.fd = fd; pfd.fd = fd;
pfd.events = do_read ? POLLIN : POLLOUT; pfd.events = do_read ? POLLIN : POLLOUT;

View File

@@ -447,7 +447,7 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
return SSH_ERROR; return SSH_ERROR;
} }
ssh_socket_set_fd(session->socket, fd); ssh_socket_set_fd(session->socket, fd);
ssh_socket_get_poll_handle_out(session->socket); ssh_socket_get_poll_handle(session->socket);
/* We must try to import any keys that could be imported in case /* We must try to import any keys that could be imported in case
* we are not using ssh_bind_listen (which is the other place * we are not using ssh_bind_listen (which is the other place

View File

@@ -411,6 +411,14 @@ static void ssh_client_connection_callback(ssh_session session)
ssh_packet_set_default_callbacks(session); ssh_packet_set_default_callbacks(session);
session->session_state = SSH_SESSION_STATE_INITIAL_KEX; session->session_state = SSH_SESSION_STATE_INITIAL_KEX;
rc = ssh_set_client_kex(session);
if (rc != SSH_OK) {
goto error;
}
rc = ssh_send_kex(session, 0);
if (rc < 0) {
goto error;
}
set_status(session, 0.5f); set_status(session, 0.5f);
break; break;
@@ -420,14 +428,19 @@ static void ssh_client_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->next_crypto->server_kex); ssh_list_kex(&session->next_crypto->server_kex);
if (ssh_set_client_kex(session) < 0) { if (session->next_crypto->client_kex.methods[0] == NULL) {
goto error; /* in rekeying state if next_crypto client_kex is empty */
rc = ssh_set_client_kex(session);
if (rc != SSH_OK) {
goto error;
}
rc = ssh_send_kex(session, 0);
if (rc < 0) {
goto error;
}
} }
if (ssh_kex_select_methods(session) == SSH_ERROR) if (ssh_kex_select_methods(session) == SSH_ERROR)
goto error; goto error;
if (ssh_send_kex(session, 0) < 0) {
goto error;
}
set_status(session,0.8f); set_status(session,0.8f);
session->session_state=SSH_SESSION_STATE_DH; session->session_state=SSH_SESSION_STATE_DH;
if (dh_handshake(session) == SSH_ERROR) { if (dh_handshake(session) == SSH_ERROR) {

View File

@@ -120,6 +120,7 @@ static int ssh_gssapi_send_response(ssh_session session, ssh_string oid){
ssh_set_error_oom(session); ssh_set_error_oom(session);
return SSH_ERROR; return SSH_ERROR;
} }
session->auth.state = SSH_AUTH_STATE_GSSAPI_TOKEN;
ssh_packet_send(session); ssh_packet_send(session);
SSH_LOG(SSH_LOG_PACKET, SSH_LOG(SSH_LOG_PACKET,

View File

@@ -26,6 +26,7 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <stdbool.h>
#include "libssh/priv.h" #include "libssh/priv.h"
#include "libssh/buffer.h" #include "libssh/buffer.h"
@@ -592,9 +593,11 @@ void ssh_list_kex(struct ssh_kex_struct *kex) {
* @returns a cstring containing a comma-separated list of hostkey methods. * @returns a cstring containing a comma-separated list of hostkey methods.
* NULL if no method matches * NULL if no method matches
*/ */
static char *ssh_client_select_hostkeys(ssh_session session) char *ssh_client_select_hostkeys(ssh_session session)
{ {
char methods_buffer[128]={0}; char methods_buffer[128]={0};
char tail_buffer[128]={0};
char *new_hostkeys = NULL;
static const char *preferred_hostkeys[] = { static const char *preferred_hostkeys[] = {
"ssh-ed25519", "ssh-ed25519",
"ecdsa-sha2-nistp521", "ecdsa-sha2-nistp521",
@@ -610,7 +613,7 @@ static char *ssh_client_select_hostkeys(ssh_session session)
struct ssh_iterator *it = NULL; struct ssh_iterator *it = NULL;
size_t algo_count; size_t algo_count;
int needcomma = 0; int needcomma = 0;
int i; size_t i, len;
algo_list = ssh_known_hosts_get_algorithms(session); algo_list = ssh_known_hosts_get_algorithms(session);
if (algo_list == NULL) { if (algo_list == NULL) {
@@ -624,9 +627,11 @@ static char *ssh_client_select_hostkeys(ssh_session session)
} }
for (i = 0; preferred_hostkeys[i] != NULL; ++i) { for (i = 0; preferred_hostkeys[i] != NULL; ++i) {
bool found = false;
for (it = ssh_list_get_iterator(algo_list); for (it = ssh_list_get_iterator(algo_list);
it != NULL; it != NULL;
it = ssh_list_get_iterator(algo_list)) { it = it->next) {
const char *algo = ssh_iterator_value(const char *, it); const char *algo = ssh_iterator_value(const char *, it);
int cmp; int cmp;
int ok; int ok;
@@ -644,10 +649,18 @@ static char *ssh_client_select_hostkeys(ssh_session session)
algo, algo,
sizeof(methods_buffer) - strlen(methods_buffer) - 1); sizeof(methods_buffer) - strlen(methods_buffer) - 1);
needcomma = 1; needcomma = 1;
found = true;
} }
} }
}
ssh_list_remove(algo_list, it); /* Collect the rest of the algorithms in other buffer, that will
* follow the preferred buffer. This will signalize all the algorithms
* we are willing to accept.
*/
if (!found) {
snprintf(tail_buffer + strlen(tail_buffer),
sizeof(tail_buffer) - strlen(tail_buffer),
",%s", preferred_hostkeys[i]);
} }
} }
ssh_list_free(algo_list); ssh_list_free(algo_list);
@@ -658,11 +671,23 @@ static char *ssh_client_select_hostkeys(ssh_session session)
return NULL; return NULL;
} }
/* Append the supported list to the preferred.
* The length is maximum 128 + 128 + 1, which will not overflow
*/
len = strlen(methods_buffer) + strlen(tail_buffer) + 1;
new_hostkeys = malloc(len);
if (new_hostkeys == NULL) {
ssh_set_error_oom(session);
return NULL;
}
snprintf(new_hostkeys, len,
"%s%s", methods_buffer, tail_buffer);
SSH_LOG(SSH_LOG_DEBUG, SSH_LOG(SSH_LOG_DEBUG,
"Changing host key method to \"%s\"", "Changing host key method to \"%s\"",
methods_buffer); new_hostkeys);
return strdup(methods_buffer); return new_hostkeys;
} }
/** /**

View File

@@ -182,11 +182,16 @@ static int known_hosts_read_line(FILE *fp,
return -1; return -1;
} }
/* This method reads the known_hosts file referenced by the path
* in filename argument, and entries matching the match argument
* will be added to the list in entries argument.
* If the entries list is NULL, it will allocate a new list. Caller
* is responsible to free it even if an error occurs.
*/
static int ssh_known_hosts_read_entries(const char *match, static int ssh_known_hosts_read_entries(const char *match,
const char *filename, const char *filename,
struct ssh_list **entries) struct ssh_list **entries)
{ {
struct ssh_list *entry_list;
char line[8192]; char line[8192];
size_t lineno = 0; size_t lineno = 0;
size_t len = 0; size_t len = 0;
@@ -195,13 +200,18 @@ static int ssh_known_hosts_read_entries(const char *match,
fp = fopen(filename, "r"); fp = fopen(filename, "r");
if (fp == NULL) { if (fp == NULL) {
return SSH_ERROR; SSH_LOG(SSH_LOG_WARN, "Failed to open the known_hosts file '%s': %s",
filename, strerror(errno));
/* The missing file is not an error here */
return SSH_OK;
} }
entry_list = ssh_list_new(); if (*entries == NULL) {
if (entry_list == NULL) { *entries = ssh_list_new();
fclose(fp); if (*entries == NULL) {
return SSH_ERROR; fclose(fp);
return SSH_ERROR;
}
} }
for (rc = known_hosts_read_line(fp, line, sizeof(line), &len, &lineno); for (rc = known_hosts_read_line(fp, line, sizeof(line), &len, &lineno);
@@ -231,15 +241,12 @@ static int ssh_known_hosts_read_entries(const char *match,
} else if (rc != SSH_OK) { } else if (rc != SSH_OK) {
goto error; goto error;
} }
ssh_list_append(entry_list, entry); ssh_list_append(*entries, entry);
} }
*entries = entry_list;
fclose(fp); fclose(fp);
return SSH_OK; return SSH_OK;
error: error:
ssh_list_free(entry_list);
fclose(fp); fclose(fp);
return SSH_ERROR; return SSH_ERROR;
} }
@@ -323,8 +330,23 @@ struct ssh_list *ssh_known_hosts_get_algorithms(ssh_session session)
rc = ssh_known_hosts_read_entries(host_port, rc = ssh_known_hosts_read_entries(host_port,
session->opts.knownhosts, session->opts.knownhosts,
&entry_list); &entry_list);
if (rc != 0) {
ssh_list_free(entry_list);
ssh_list_free(list);
return NULL;
}
rc = ssh_known_hosts_read_entries(host_port,
session->opts.global_knownhosts,
&entry_list);
SAFE_FREE(host_port); SAFE_FREE(host_port);
if (rc != 0) { if (rc != 0) {
ssh_list_free(entry_list);
ssh_list_free(list);
return NULL;
}
if (entry_list == NULL) {
ssh_list_free(list); ssh_list_free(list);
return NULL; return NULL;
} }
@@ -340,12 +362,10 @@ struct ssh_list *ssh_known_hosts_get_algorithms(ssh_session session)
it != NULL; it != NULL;
it = ssh_list_get_iterator(entry_list)) { it = ssh_list_get_iterator(entry_list)) {
struct ssh_knownhosts_entry *entry = NULL; struct ssh_knownhosts_entry *entry = NULL;
enum ssh_keytypes_e key_type;
const char *algo = NULL; const char *algo = NULL;
entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it); entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
key_type = ssh_key_type(entry->publickey); algo = entry->publickey->type_c;
algo = ssh_key_type_to_char(key_type);
rc = ssh_list_append(list, algo); rc = ssh_list_append(list, algo);
if (rc != SSH_OK) { if (rc != SSH_OK) {
@@ -556,8 +576,17 @@ enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session)
rc = ssh_known_hosts_read_entries(host_port, rc = ssh_known_hosts_read_entries(host_port,
session->opts.knownhosts, session->opts.knownhosts,
&entry_list); &entry_list);
if (rc != 0) {
ssh_list_free(entry_list);
return SSH_KNOWN_HOSTS_UNKNOWN;
}
rc = ssh_known_hosts_read_entries(host_port,
session->opts.global_knownhosts,
&entry_list);
SAFE_FREE(host_port); SAFE_FREE(host_port);
if (rc != 0) { if (rc != 0) {
ssh_list_free(entry_list);
return SSH_KNOWN_HOSTS_UNKNOWN; return SSH_KNOWN_HOSTS_UNKNOWN;
} }
@@ -621,7 +650,7 @@ int ssh_session_export_known_hosts_entry(ssh_session session,
if (session->current_crypto == NULL) { if (session->current_crypto == NULL) {
ssh_set_error(session, SSH_FATAL, ssh_set_error(session, SSH_FATAL,
"No current crypto context, please connnect first"); "No current crypto context, please connect first");
SAFE_FREE(host); SAFE_FREE(host);
return SSH_ERROR; return SSH_ERROR;
} }
@@ -657,10 +686,11 @@ int ssh_session_export_known_hosts_entry(ssh_session session,
} }
/** /**
* @brief Add the current connected server to the known_hosts file. * @brief Add the current connected server to the user known_hosts file.
* *
* This adds the currently connected server to the known_hosts file by * This adds the currently connected server to the known_hosts file by
* appending a new line at the end. * appending a new line at the end. The global known_hosts file is considered
* read-only so it is not touched by this function.
* *
* @param[in] session The session to use to write the entry. * @param[in] session The session to use to write the entry.
* *
@@ -747,6 +777,7 @@ ssh_known_hosts_check_server_key(const char *hosts_entry,
filename, filename,
&entry_list); &entry_list);
if (rc != 0) { if (rc != 0) {
ssh_list_free(entry_list);
return SSH_KNOWN_HOSTS_UNKNOWN; return SSH_KNOWN_HOSTS_UNKNOWN;
} }
@@ -824,9 +855,7 @@ enum ssh_known_hosts_e
ssh_session_get_known_hosts_entry(ssh_session session, ssh_session_get_known_hosts_entry(ssh_session session,
struct ssh_knownhosts_entry **pentry) struct ssh_knownhosts_entry **pentry)
{ {
ssh_key server_pubkey = NULL; enum ssh_known_hosts_e old_rv, rv = SSH_KNOWN_HOSTS_UNKNOWN;
char *host_port = NULL;
enum ssh_known_hosts_e found = SSH_KNOWN_HOSTS_UNKNOWN;
if (session->opts.knownhosts == NULL) { if (session->opts.knownhosts == NULL) {
if (ssh_options_apply(session) < 0) { if (ssh_options_apply(session) < 0) {
@@ -838,6 +867,65 @@ ssh_session_get_known_hosts_entry(ssh_session session,
} }
} }
rv = ssh_session_get_known_hosts_entry_file(session,
session->opts.knownhosts,
pentry);
if (rv == SSH_KNOWN_HOSTS_OK) {
/* We already found a match in the first file: return */
return rv;
}
old_rv = rv;
rv = ssh_session_get_known_hosts_entry_file(session,
session->opts.global_knownhosts,
pentry);
/* If we did not find any match at all: we report the previous result */
if (rv == SSH_KNOWN_HOSTS_UNKNOWN) {
return old_rv;
}
/* We found some match: return it */
return rv;
}
/**
* @brief Get the known_hosts entry for the current connected session
* from the given known_hosts file.
*
* @param[in] session The session to validate.
*
* @param[in] filename The filename to parse.
*
* @param[in] pentry A pointer to store the allocated known hosts entry.
*
* @returns SSH_KNOWN_HOSTS_OK: The server is known and has not changed.\n
* SSH_KNOWN_HOSTS_CHANGED: The server key has changed. Either you
* are under attack or the administrator
* changed the key. You HAVE to warn the
* user about a possible attack.\n
* SSH_KNOWN_HOSTS_OTHER: The server gave use a key of a type while
* we had an other type recorded. It is a
* possible attack.\n
* SSH_KNOWN_HOSTS_UNKNOWN: The server is unknown. User should
* confirm the public key hash is correct.\n
* SSH_KNOWN_HOSTS_NOT_FOUND: The known host file does not exist. The
* host is thus unknown. File will be
* created if host key is accepted.\n
* SSH_KNOWN_HOSTS_ERROR: There had been an eror checking the host.
*
* @see ssh_knownhosts_entry_free()
*/
enum ssh_known_hosts_e
ssh_session_get_known_hosts_entry_file(ssh_session session,
const char *filename,
struct ssh_knownhosts_entry **pentry)
{
ssh_key server_pubkey = NULL;
char *host_port = NULL;
enum ssh_known_hosts_e found = SSH_KNOWN_HOSTS_UNKNOWN;
server_pubkey = ssh_dh_get_current_server_publickey(session); server_pubkey = ssh_dh_get_current_server_publickey(session);
if (server_pubkey == NULL) { if (server_pubkey == NULL) {
ssh_set_error(session, ssh_set_error(session,
@@ -854,7 +942,7 @@ ssh_session_get_known_hosts_entry(ssh_session session,
} }
found = ssh_known_hosts_check_server_key(host_port, found = ssh_known_hosts_check_server_key(host_port,
session->opts.knownhosts, filename,
server_pubkey, server_pubkey,
pentry); pentry);
SAFE_FREE(host_port); SAFE_FREE(host_port);

View File

@@ -196,6 +196,7 @@ void evp_update(EVPCTX ctx, const void *data, unsigned long len)
void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen) void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen)
{ {
EVP_DigestFinal(ctx, md, mdlen); EVP_DigestFinal(ctx, md, mdlen);
EVP_MD_CTX_free(ctx);
} }
#endif #endif

View File

@@ -704,6 +704,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_request){
ssh_message msg = NULL; ssh_message msg = NULL;
char *service = NULL; char *service = NULL;
char *method = NULL; char *method = NULL;
int cmp;
int rc; int rc;
(void)user; (void)user;
@@ -730,6 +731,13 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_request){
service, method, service, method,
msg->auth_request.username); msg->auth_request.username);
cmp = strcmp(service, "ssh-connection");
if (cmp != 0) {
SSH_LOG(SSH_LOG_WARNING,
"Invalid service request: %s",
service);
goto end;
}
if (strcmp(method, "none") == 0) { if (strcmp(method, "none") == 0) {
msg->auth_request.method = SSH_AUTH_METHOD_NONE; msg->auth_request.method = SSH_AUTH_METHOD_NONE;

View File

@@ -1022,6 +1022,12 @@ int ssh_options_get_port(ssh_session session, unsigned int* port_target) {
* remote host. When not explicitly set, it will be read * remote host. When not explicitly set, it will be read
* from the ~/.ssh/config file. * from the ~/.ssh/config file.
* *
* - SSH_OPTIONS_GLOBAL_KNOWNHOSTS:
* Get the path to the global known_hosts file being used.
*
* - SSH_OPTIONS_KNOWNHOSTS:
* Get the path to the known_hosts file being used.
*
* @param value The value to get into. As a char**, space will be * @param value The value to get into. As a char**, space will be
* allocated by the function for the value, it is * allocated by the function for the value, it is
* your responsibility to free the memory using * your responsibility to free the memory using
@@ -1064,6 +1070,14 @@ int ssh_options_get(ssh_session session, enum ssh_options_e type, char** value)
src = session->opts.ProxyCommand; src = session->opts.ProxyCommand;
break; break;
} }
case SSH_OPTIONS_KNOWNHOSTS: {
src = session->opts.knownhosts;
break;
}
case SSH_OPTIONS_GLOBAL_KNOWNHOSTS: {
src = session->opts.global_knownhosts;
break;
}
default: default:
ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type); ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
return SSH_ERROR; return SSH_ERROR;
@@ -1356,6 +1370,17 @@ int ssh_options_apply(ssh_session session) {
free(session->opts.knownhosts); free(session->opts.knownhosts);
session->opts.knownhosts = tmp; session->opts.knownhosts = tmp;
if (session->opts.global_knownhosts == NULL) {
tmp = strdup("/etc/ssh/ssh_known_hosts");
} else {
tmp = ssh_path_expand_escape(session, session->opts.global_knownhosts);
}
if (tmp == NULL) {
return -1;
}
free(session->opts.global_knownhosts);
session->opts.global_knownhosts = tmp;
if (session->opts.ProxyCommand != NULL) { if (session->opts.ProxyCommand != NULL) {
tmp = ssh_path_expand_escape(session, session->opts.ProxyCommand); tmp = ssh_path_expand_escape(session, session->opts.ProxyCommand);
if (tmp == NULL) { if (tmp == NULL) {

View File

@@ -308,6 +308,7 @@ static enum ssh_packet_filter_result_e ssh_packet_incoming_filter(ssh_session se
(session->dh_handshake_state != DH_STATE_FINISHED)) (session->dh_handshake_state != DH_STATE_FINISHED))
{ {
rc = SSH_PACKET_DENIED; rc = SSH_PACKET_DENIED;
break;
} }
rc = SSH_PACKET_ALLOWED; rc = SSH_PACKET_ALLOWED;

View File

@@ -312,7 +312,7 @@ static int ssh_pcap_context_connect(ssh_pcap_context ctx){
return SSH_ERROR; return SSH_ERROR;
if(session->socket==NULL) if(session->socket==NULL)
return SSH_ERROR; return SSH_ERROR;
fd=ssh_socket_get_fd_in(session->socket); fd = ssh_socket_get_fd(session->socket);
/* TODO: adapt for windows */ /* TODO: adapt for windows */
if(fd<0) if(fd<0)
return SSH_ERROR; return SSH_ERROR;

View File

@@ -790,7 +790,7 @@ ssh_string pki_private_key_to_pem(const ssh_key key,
case SSH_KEYTYPE_UNKNOWN: case SSH_KEYTYPE_UNKNOWN:
default: default:
BIO_free(mem); BIO_free(mem);
SSH_LOG(SSH_LOG_WARN, "Unkown or invalid private key type %d", key->type); SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key type %d", key->type);
return NULL; return NULL;
} }
@@ -916,7 +916,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
case SSH_KEYTYPE_RSA_CERT01: case SSH_KEYTYPE_RSA_CERT01:
case SSH_KEYTYPE_UNKNOWN: case SSH_KEYTYPE_UNKNOWN:
BIO_free(mem); BIO_free(mem);
SSH_LOG(SSH_LOG_WARN, "Unkown or invalid private key type %d", type); SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key type %d", type);
return NULL; return NULL;
} }

View File

@@ -998,7 +998,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
case SSH_KEYTYPE_RSA1: case SSH_KEYTYPE_RSA1:
case SSH_KEYTYPE_UNKNOWN: case SSH_KEYTYPE_UNKNOWN:
default: default:
SSH_LOG(SSH_LOG_WARN, "Unkown or invalid private key type %d", type); SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key type %d", type);
return NULL; return NULL;
} }

View File

@@ -533,19 +533,17 @@ int ssh_poll_ctx_add(ssh_poll_ctx ctx, ssh_poll_handle p) {
* *
* @return 0 on success, < 0 on error * @return 0 on success, < 0 on error
*/ */
int ssh_poll_ctx_add_socket (ssh_poll_ctx ctx, ssh_socket s) { int ssh_poll_ctx_add_socket (ssh_poll_ctx ctx, ssh_socket s)
ssh_poll_handle p_in, p_out; {
int ret; ssh_poll_handle p;
p_in=ssh_socket_get_poll_handle_in(s); int ret;
if(p_in==NULL)
return -1; p = ssh_socket_get_poll_handle(s);
ret = ssh_poll_ctx_add(ctx,p_in); if (p == NULL) {
if(ret != 0) return -1;
}
ret = ssh_poll_ctx_add(ctx,p);
return ret; return ret;
p_out=ssh_socket_get_poll_handle_out(s);
if(p_in != p_out)
ret = ssh_poll_ctx_add(ctx,p_out);
return ret;
} }

View File

@@ -1039,6 +1039,7 @@ int ssh_message_auth_interactive_request(ssh_message msg, const char *name,
msg->session->kbdint->prompts = NULL; msg->session->kbdint->prompts = NULL;
msg->session->kbdint->echo = NULL; msg->session->kbdint->echo = NULL;
} }
msg->session->auth.state = SSH_AUTH_STATE_INFO;
return rc; return rc;
} }

View File

@@ -536,7 +536,7 @@ socket_t ssh_get_fd(ssh_session session) {
return -1; return -1;
} }
return ssh_socket_get_fd_in(session->socket); return ssh_socket_get_fd(session->socket);
} }
/** /**
@@ -599,7 +599,7 @@ void ssh_set_fd_except(ssh_session session) {
* @return SSH_OK on success, SSH_ERROR otherwise. * @return SSH_OK on success, SSH_ERROR otherwise.
*/ */
int ssh_handle_packets(ssh_session session, int timeout) { int ssh_handle_packets(ssh_session session, int timeout) {
ssh_poll_handle spoll_in,spoll_out; ssh_poll_handle spoll;
ssh_poll_ctx ctx; ssh_poll_ctx ctx;
int tm = timeout; int tm = timeout;
int rc; int rc;
@@ -608,17 +608,13 @@ int ssh_handle_packets(ssh_session session, int timeout) {
return SSH_ERROR; return SSH_ERROR;
} }
spoll_in = ssh_socket_get_poll_handle_in(session->socket); spoll = ssh_socket_get_poll_handle(session->socket);
spoll_out = ssh_socket_get_poll_handle_out(session->socket); ssh_poll_add_events(spoll, POLLIN);
ssh_poll_add_events(spoll_in, POLLIN); ctx = ssh_poll_get_ctx(spoll);
ctx = ssh_poll_get_ctx(spoll_in);
if (!ctx) { if (!ctx) {
ctx = ssh_poll_get_default_ctx(session); ctx = ssh_poll_get_default_ctx(session);
ssh_poll_ctx_add(ctx, spoll_in); ssh_poll_ctx_add(ctx, spoll);
if (spoll_in != spoll_out) {
ssh_poll_ctx_add(ctx, spoll_out);
}
} }
if (timeout == SSH_TIMEOUT_USER) { if (timeout == SSH_TIMEOUT_USER) {

View File

@@ -74,8 +74,7 @@ enum ssh_socket_states_e {
}; };
struct ssh_socket_struct { struct ssh_socket_struct {
socket_t fd_in; socket_t fd;
socket_t fd_out;
int fd_is_socket; int fd_is_socket;
int last_errno; int last_errno;
int read_wontblock; /* reading now on socket will int read_wontblock; /* reading now on socket will
@@ -87,8 +86,7 @@ struct ssh_socket_struct {
ssh_buffer in_buffer; ssh_buffer in_buffer;
ssh_session session; ssh_session session;
ssh_socket_callbacks callbacks; ssh_socket_callbacks callbacks;
ssh_poll_handle poll_in; ssh_poll_handle poll_handle;
ssh_poll_handle poll_out;
}; };
static int sockets_initialized = 0; static int sockets_initialized = 0;
@@ -149,8 +147,7 @@ ssh_socket ssh_socket_new(ssh_session session) {
ssh_set_error_oom(session); ssh_set_error_oom(session);
return NULL; return NULL;
} }
s->fd_in = SSH_INVALID_SOCKET; s->fd = SSH_INVALID_SOCKET;
s->fd_out= SSH_INVALID_SOCKET;
s->last_errno = -1; s->last_errno = -1;
s->fd_is_socket = 1; s->fd_is_socket = 1;
s->session = session; s->session = session;
@@ -170,7 +167,7 @@ ssh_socket ssh_socket_new(ssh_session session) {
s->read_wontblock = 0; s->read_wontblock = 0;
s->write_wontblock = 0; s->write_wontblock = 0;
s->data_except = 0; s->data_except = 0;
s->poll_in=s->poll_out=NULL; s->poll_handle = NULL;
s->state=SSH_SOCKET_NONE; s->state=SSH_SOCKET_NONE;
return s; return s;
} }
@@ -181,8 +178,7 @@ ssh_socket ssh_socket_new(ssh_session session) {
* @param[in] s socket to rest * @param[in] s socket to rest
*/ */
void ssh_socket_reset(ssh_socket s){ void ssh_socket_reset(ssh_socket s){
s->fd_in = SSH_INVALID_SOCKET; s->fd = SSH_INVALID_SOCKET;
s->fd_out= SSH_INVALID_SOCKET;
s->last_errno = -1; s->last_errno = -1;
s->fd_is_socket = 1; s->fd_is_socket = 1;
ssh_buffer_reinit(s->in_buffer); ssh_buffer_reinit(s->in_buffer);
@@ -190,7 +186,7 @@ void ssh_socket_reset(ssh_socket s){
s->read_wontblock = 0; s->read_wontblock = 0;
s->write_wontblock = 0; s->write_wontblock = 0;
s->data_except = 0; s->data_except = 0;
s->poll_in=s->poll_out=NULL; s->poll_handle = NULL;
s->state=SSH_SOCKET_NONE; s->state=SSH_SOCKET_NONE;
} }
@@ -337,7 +333,7 @@ int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p,
ssh_poll_set_events(p, POLLOUT | POLLIN); ssh_poll_set_events(p, POLLOUT | POLLIN);
} }
rc = ssh_socket_set_blocking(ssh_socket_get_fd_in(s)); rc = ssh_socket_set_blocking(ssh_socket_get_fd(s));
if (rc < 0) { if (rc < 0) {
return -1; return -1;
} }
@@ -370,8 +366,8 @@ int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p,
/* TODO: Find a way to put back POLLOUT when buffering occurs */ /* TODO: Find a way to put back POLLOUT when buffering occurs */
} }
/* Return -1 if one of the poll handlers disappeared */ /* Return -1 if the poll handler disappeared */
if (s->poll_in == NULL || s->poll_out == NULL) { if (s->poll_handle == NULL) {
return -1; return -1;
} }
@@ -379,31 +375,17 @@ int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p,
} }
/** @internal /** @internal
* @brief returns the input poll handle corresponding to the socket, * @brief returns the poll handle corresponding to the socket,
* creates it if it does not exist. * creates it if it does not exist.
* @returns allocated and initialized ssh_poll_handle object * @returns allocated and initialized ssh_poll_handle object
*/ */
ssh_poll_handle ssh_socket_get_poll_handle_in(ssh_socket s){ ssh_poll_handle ssh_socket_get_poll_handle(ssh_socket s)
if(s->poll_in) {
return s->poll_in; if (s->poll_handle) {
s->poll_in=ssh_poll_new(s->fd_in,0,ssh_socket_pollcallback,s); return s->poll_handle;
if(s->fd_in == s->fd_out && s->poll_out == NULL) }
s->poll_out=s->poll_in; s->poll_handle = ssh_poll_new(s->fd,0,ssh_socket_pollcallback,s);
return s->poll_in; return s->poll_handle;
}
/** @internal
* @brief returns the output poll handle corresponding to the socket,
* creates it if it does not exist.
* @returns allocated and initialized ssh_poll_handle object
*/
ssh_poll_handle ssh_socket_get_poll_handle_out(ssh_socket s){
if(s->poll_out)
return s->poll_out;
s->poll_out=ssh_poll_new(s->fd_out,0,ssh_socket_pollcallback,s);
if(s->fd_in == s->fd_out && s->poll_in == NULL)
s->poll_in=s->poll_out;
return s->poll_out;
} }
/** \internal /** \internal
@@ -460,27 +442,17 @@ int ssh_socket_unix(ssh_socket s, const char *path) {
void ssh_socket_close(ssh_socket s){ void ssh_socket_close(ssh_socket s){
if (ssh_socket_is_open(s)) { if (ssh_socket_is_open(s)) {
#ifdef _WIN32 #ifdef _WIN32
CLOSE_SOCKET(s->fd_in); CLOSE_SOCKET(s->fd);
/* fd_in = fd_out under win32 */
s->last_errno = WSAGetLastError(); s->last_errno = WSAGetLastError();
#else #else
if (s->fd_out != s->fd_in && s->fd_out != -1) { CLOSE_SOCKET(s->fd);
CLOSE_SOCKET(s->fd_out);
}
CLOSE_SOCKET(s->fd_in);
s->last_errno = errno; s->last_errno = errno;
#endif #endif
} }
if(s->poll_in != NULL){ if(s->poll_handle != NULL){
if(s->poll_out == s->poll_in) ssh_poll_free(s->poll_handle);
s->poll_out = NULL; s->poll_handle=NULL;
ssh_poll_free(s->poll_in);
s->poll_in=NULL;
}
if(s->poll_out != NULL){
ssh_poll_free(s->poll_out);
s->poll_out=NULL;
} }
s->state = SSH_SOCKET_CLOSED; s->state = SSH_SOCKET_CLOSED;
@@ -495,59 +467,34 @@ void ssh_socket_close(ssh_socket s){
* file descriptors * file descriptors
*/ */
void ssh_socket_set_fd(ssh_socket s, socket_t fd) { void ssh_socket_set_fd(ssh_socket s, socket_t fd) {
s->fd_in = s->fd_out = fd; s->fd = fd;
if (s->poll_in) { if (s->poll_handle) {
ssh_poll_set_fd(s->poll_in,fd); ssh_poll_set_fd(s->poll_handle,fd);
} else { } else {
s->state = SSH_SOCKET_CONNECTING; s->state = SSH_SOCKET_CONNECTING;
/* POLLOUT is the event to wait for in a nonblocking connect */ /* POLLOUT is the event to wait for in a nonblocking connect */
ssh_poll_set_events(ssh_socket_get_poll_handle_in(s), POLLOUT); ssh_poll_set_events(ssh_socket_get_poll_handle(s), POLLOUT);
#ifdef _WIN32 #ifdef _WIN32
ssh_poll_add_events(ssh_socket_get_poll_handle_in(s), POLLWRNORM); ssh_poll_add_events(ssh_socket_get_poll_handle(s), POLLWRNORM);
#endif #endif
} }
} }
/**
* @internal
* @brief sets the input file descriptor of the socket.
* @param[out] s ssh_socket to update
* @param[in] fd file descriptor to set
*/
void ssh_socket_set_fd_in(ssh_socket s, socket_t fd) {
s->fd_in = fd;
if(s->poll_in)
ssh_poll_set_fd(s->poll_in,fd);
}
/**
* @internal
* @brief sets the output file descriptor of the socket.
* @param[out] s ssh_socket to update
* @param[in] fd file descriptor to set
*/
void ssh_socket_set_fd_out(ssh_socket s, socket_t fd) {
s->fd_out = fd;
if(s->poll_out)
ssh_poll_set_fd(s->poll_out,fd);
}
/** \internal /** \internal
* \brief returns the input file descriptor of the socket * \brief returns the input file descriptor of the socket
*/ */
socket_t ssh_socket_get_fd_in(ssh_socket s) { socket_t ssh_socket_get_fd(ssh_socket s)
return s->fd_in; {
return s->fd;
} }
/** \internal /** \internal
* \brief returns nonzero if the socket is open * \brief returns nonzero if the socket is open
*/ */
int ssh_socket_is_open(ssh_socket s) { int ssh_socket_is_open(ssh_socket s) {
return s->fd_in != SSH_INVALID_SOCKET; return s->fd != SSH_INVALID_SOCKET;
} }
/** \internal /** \internal
@@ -563,9 +510,9 @@ static ssize_t ssh_socket_unbuffered_read(ssh_socket s,
return -1; return -1;
} }
if (s->fd_is_socket) { if (s->fd_is_socket) {
rc = recv(s->fd_in,buffer, len, 0); rc = recv(s->fd,buffer, len, 0);
} else { } else {
rc = read(s->fd_in,buffer, len); rc = read(s->fd,buffer, len);
} }
#ifdef _WIN32 #ifdef _WIN32
s->last_errno = WSAGetLastError(); s->last_errno = WSAGetLastError();
@@ -600,9 +547,9 @@ static ssize_t ssh_socket_unbuffered_write(ssh_socket s,
} }
if (s->fd_is_socket) { if (s->fd_is_socket) {
w = send(s->fd_out, buffer, len, flags); w = send(s->fd, buffer, len, flags);
} else { } else {
w = write(s->fd_out, buffer, len); w = write(s->fd, buffer, len);
} }
#ifdef _WIN32 #ifdef _WIN32
s->last_errno = WSAGetLastError(); s->last_errno = WSAGetLastError();
@@ -611,9 +558,9 @@ static ssize_t ssh_socket_unbuffered_write(ssh_socket s,
#endif #endif
s->write_wontblock = 0; s->write_wontblock = 0;
/* Reactive the POLLOUT detector in the poll multiplexer system */ /* Reactive the POLLOUT detector in the poll multiplexer system */
if (s->poll_out) { if (s->poll_handle) {
SSH_LOG(SSH_LOG_PACKET, "Enabling POLLOUT for socket"); SSH_LOG(SSH_LOG_PACKET, "Enabling POLLOUT for socket");
ssh_poll_set_events(s->poll_out,ssh_poll_get_events(s->poll_out) | POLLOUT); ssh_poll_set_events(s->poll_handle,ssh_poll_get_events(s->poll_handle) | POLLOUT);
} }
if (w < 0) { if (w < 0) {
s->data_except = 1; s->data_except = 1;
@@ -626,10 +573,10 @@ static ssize_t ssh_socket_unbuffered_write(ssh_socket s,
* \brief returns nonzero if the current socket is in the fd_set * \brief returns nonzero if the current socket is in the fd_set
*/ */
int ssh_socket_fd_isset(ssh_socket s, fd_set *set) { int ssh_socket_fd_isset(ssh_socket s, fd_set *set) {
if(s->fd_in == SSH_INVALID_SOCKET) { if(s->fd == SSH_INVALID_SOCKET) {
return 0; return 0;
} }
return FD_ISSET(s->fd_in,set) || FD_ISSET(s->fd_out,set); return FD_ISSET(s->fd,set);
} }
/** \internal /** \internal
@@ -637,22 +584,16 @@ int ssh_socket_fd_isset(ssh_socket s, fd_set *set) {
*/ */
void ssh_socket_fd_set(ssh_socket s, fd_set *set, socket_t *max_fd) { void ssh_socket_fd_set(ssh_socket s, fd_set *set, socket_t *max_fd) {
if (s->fd_in == SSH_INVALID_SOCKET) { if (s->fd == SSH_INVALID_SOCKET) {
return; return;
} }
FD_SET(s->fd_in,set); FD_SET(s->fd,set);
FD_SET(s->fd_out,set);
if (s->fd_in >= 0 && if (s->fd >= 0 &&
s->fd_in >= *max_fd && s->fd >= *max_fd &&
s->fd_in != SSH_INVALID_SOCKET) { s->fd != SSH_INVALID_SOCKET) {
*max_fd = s->fd_in + 1; *max_fd = s->fd + 1;
}
if (s->fd_out >= 0 &&
s->fd_out >= *max_fd &&
s->fd_out != SSH_INVALID_SOCKET) {
*max_fd = s->fd_out + 1;
} }
} }
@@ -701,9 +642,9 @@ int ssh_socket_nonblocking_flush(ssh_socket s)
} }
len = ssh_buffer_get_len(s->out_buffer); len = ssh_buffer_get_len(s->out_buffer);
if (!s->write_wontblock && s->poll_out && len > 0) { if (!s->write_wontblock && s->poll_handle && len > 0) {
/* force the poll system to catch pollout events */ /* force the poll system to catch pollout events */
ssh_poll_add_events(s->poll_out, POLLOUT); ssh_poll_add_events(s->poll_handle, POLLOUT);
return SSH_AGAIN; return SSH_AGAIN;
} }
@@ -741,9 +682,9 @@ int ssh_socket_nonblocking_flush(ssh_socket s)
/* Is there some data pending? */ /* Is there some data pending? */
len = ssh_buffer_get_len(s->out_buffer); len = ssh_buffer_get_len(s->out_buffer);
if (s->poll_out && len > 0) { if (s->poll_handle && len > 0) {
/* force the poll system to catch pollout events */ /* force the poll system to catch pollout events */
ssh_poll_add_events(s->poll_out, POLLOUT); ssh_poll_add_events(s->poll_handle, POLLOUT);
return SSH_AGAIN; return SSH_AGAIN;
} }
@@ -804,10 +745,10 @@ int ssh_socket_get_status(ssh_socket s) {
int ssh_socket_get_poll_flags(ssh_socket s) { int ssh_socket_get_poll_flags(ssh_socket s) {
int r = 0; int r = 0;
if (s->poll_in != NULL && (ssh_poll_get_events (s->poll_in) & POLLIN) > 0) { if (s->poll_handle != NULL && (ssh_poll_get_events (s->poll_handle) & POLLIN) > 0) {
r |= SSH_READ_PENDING; r |= SSH_READ_PENDING;
} }
if (s->poll_out != NULL && (ssh_poll_get_events (s->poll_out) & POLLOUT) > 0) { if (s->poll_handle != NULL && (ssh_poll_get_events (s->poll_handle) & POLLOUT) > 0) {
r |= SSH_WRITE_PENDING; r |= SSH_WRITE_PENDING;
} }
return r; return r;
@@ -897,19 +838,15 @@ void ssh_execute_command(const char *command, socket_t in, socket_t out){
*/ */
int ssh_socket_connect_proxycommand(ssh_socket s, const char *command){ int ssh_socket_connect_proxycommand(ssh_socket s, const char *command){
socket_t in_pipe[2]; socket_t pair[2];
socket_t out_pipe[2];
int pid; int pid;
int rc; int rc;
if(s->state != SSH_SOCKET_NONE) if (s->state != SSH_SOCKET_NONE) {
return SSH_ERROR; return SSH_ERROR;
rc = pipe(in_pipe);
if (rc < 0) {
return SSH_ERROR;
} }
rc = pipe(out_pipe);
rc = socketpair(PF_LOCAL, SOCK_STREAM, 0, pair);
if (rc < 0) { if (rc < 0) {
return SSH_ERROR; return SSH_ERROR;
} }
@@ -917,20 +854,18 @@ int ssh_socket_connect_proxycommand(ssh_socket s, const char *command){
SSH_LOG(SSH_LOG_PROTOCOL,"Executing proxycommand '%s'",command); SSH_LOG(SSH_LOG_PROTOCOL,"Executing proxycommand '%s'",command);
pid = fork(); pid = fork();
if(pid == 0){ if(pid == 0){
ssh_execute_command(command,out_pipe[0],in_pipe[1]); ssh_execute_command(command,pair[0],pair[0]);
} }
close(in_pipe[1]); close(pair[0]);
close(out_pipe[0]); SSH_LOG(SSH_LOG_PROTOCOL,"ProxyCommand connection pipe: [%d,%d]",pair[0],pair[1]);
SSH_LOG(SSH_LOG_PROTOCOL,"ProxyCommand connection pipe: [%d,%d]",in_pipe[0],out_pipe[1]); ssh_socket_set_fd(s, pair[1]);
ssh_socket_set_fd_in(s,in_pipe[0]);
ssh_socket_set_fd_out(s,out_pipe[1]);
s->state=SSH_SOCKET_CONNECTED; s->state=SSH_SOCKET_CONNECTED;
s->fd_is_socket=0; s->fd_is_socket=0;
/* POLLOUT is the event to wait for in a nonblocking connect */ /* POLLOUT is the event to wait for in a nonblocking connect */
ssh_poll_set_events(ssh_socket_get_poll_handle_in(s),POLLIN); ssh_poll_set_events(ssh_socket_get_poll_handle(s), POLLIN | POLLOUT);
ssh_poll_set_events(ssh_socket_get_poll_handle_out(s),POLLOUT); if(s->callbacks && s->callbacks->connected) {
if(s->callbacks && s->callbacks->connected)
s->callbacks->connected(SSH_SOCKET_CONNECTED_OK,0,s->callbacks->userdata); s->callbacks->connected(SSH_SOCKET_CONNECTED_OK,0,s->callbacks->userdata);
}
return SSH_OK; return SSH_OK;
} }

View File

@@ -121,6 +121,8 @@ if (CLIENT_TESTING)
file(COPY keys/id_rsa.pub DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE) file(COPY keys/id_rsa.pub DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
file(COPY keys/id_ecdsa DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE) file(COPY keys/id_ecdsa DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
file(COPY keys/id_ecdsa.pub DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE) file(COPY keys/id_ecdsa.pub DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
file(COPY keys/id_ed25519 DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
file(COPY keys/id_ed25519.pub DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
# Allow to auth with bob his public keys on alice account # Allow to auth with bob his public keys on alice account
configure_file(keys/id_rsa.pub ${CMAKE_CURRENT_BINARY_DIR}/home/alice/.ssh/authorized_keys @ONLY) configure_file(keys/id_rsa.pub ${CMAKE_CURRENT_BINARY_DIR}/home/alice/.ssh/authorized_keys @ONLY)
@@ -128,6 +130,10 @@ if (CLIENT_TESTING)
file(READ keys/id_ecdsa.pub CONTENTS) file(READ keys/id_ecdsa.pub CONTENTS)
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/home/alice/.ssh/authorized_keys "${CONTENTS}") file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/home/alice/.ssh/authorized_keys "${CONTENTS}")
# append ed25519 public key
file(READ keys/id_ed25519.pub CONTENTS)
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/home/alice/.ssh/authorized_keys "${CONTENTS}")
# Copy the signed key to an alternative directory in bob's homedir. # Copy the signed key to an alternative directory in bob's homedir.
file(COPY keys/certauth/id_rsa DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh_cert/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE) file(COPY keys/certauth/id_rsa DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh_cert/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
file(COPY keys/certauth/id_rsa.pub DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh_cert/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE) file(COPY keys/certauth/id_rsa.pub DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh_cert/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)

View File

@@ -559,7 +559,7 @@ static void torture_auth_pubkey_types(void **state)
rc = ssh_connect(session); rc = ssh_connect(session);
assert_ssh_return_code(session, rc); assert_ssh_return_code(session, rc);
rc = ssh_userauth_none(session,NULL); rc = ssh_userauth_none(session, NULL);
/* This request should return a SSH_REQUEST_DENIED error */ /* This request should return a SSH_REQUEST_DENIED error */
if (rc == SSH_ERROR) { if (rc == SSH_ERROR) {
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED); assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
@@ -596,7 +596,7 @@ static void torture_auth_pubkey_types_ecdsa(void **state)
rc = ssh_connect(session); rc = ssh_connect(session);
assert_ssh_return_code(session, rc); assert_ssh_return_code(session, rc);
rc = ssh_userauth_none(session,NULL); rc = ssh_userauth_none(session, NULL);
/* This request should return a SSH_REQUEST_DENIED error */ /* This request should return a SSH_REQUEST_DENIED error */
if (rc == SSH_ERROR) { if (rc == SSH_ERROR) {
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED); assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
@@ -622,6 +622,44 @@ static void torture_auth_pubkey_types_ecdsa(void **state)
} }
static void torture_auth_pubkey_types_ed25519(void **state)
{
struct torture_state *s = *state;
ssh_session session = s->ssh.session;
int rc;
rc = ssh_options_set(session, SSH_OPTIONS_USER, TORTURE_SSH_USER_ALICE);
assert_ssh_return_code(session, rc);
rc = ssh_connect(session);
assert_ssh_return_code(session, rc);
rc = ssh_userauth_none(session, NULL);
/* This request should return a SSH_REQUEST_DENIED error */
if (rc == SSH_ERROR) {
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
}
rc = ssh_userauth_list(session, NULL);
assert_true(rc & SSH_AUTH_METHOD_PUBLICKEY);
/* Enable only DSA keys -- authentication should fail */
rc = ssh_options_set(session, SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES,
"ssh-dss");
assert_ssh_return_code(session, rc);
rc = ssh_userauth_publickey_auto(session, NULL, NULL);
assert_int_equal(rc, SSH_AUTH_DENIED);
/* Verify we can use also ed25519 keys */
rc = ssh_options_set(session, SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES,
"ssh-ed25519");
assert_ssh_return_code(session, rc);
rc = ssh_userauth_publickey_auto(session, NULL, NULL);
assert_int_equal(rc, SSH_AUTH_SUCCESS);
}
static void torture_auth_pubkey_types_nonblocking(void **state) static void torture_auth_pubkey_types_nonblocking(void **state)
{ {
struct torture_state *s = *state; struct torture_state *s = *state;
@@ -634,7 +672,7 @@ static void torture_auth_pubkey_types_nonblocking(void **state)
rc = ssh_connect(session); rc = ssh_connect(session);
assert_ssh_return_code(session, rc); assert_ssh_return_code(session, rc);
ssh_set_blocking(session,0); ssh_set_blocking(session, 0);
do { do {
rc = ssh_userauth_none(session, NULL); rc = ssh_userauth_none(session, NULL);
} while (rc == SSH_AUTH_AGAIN); } while (rc == SSH_AUTH_AGAIN);
@@ -681,7 +719,7 @@ static void torture_auth_pubkey_types_ecdsa_nonblocking(void **state)
rc = ssh_connect(session); rc = ssh_connect(session);
assert_ssh_return_code(session, rc); assert_ssh_return_code(session, rc);
ssh_set_blocking(session,0); ssh_set_blocking(session, 0);
do { do {
rc = ssh_userauth_none(session, NULL); rc = ssh_userauth_none(session, NULL);
} while (rc == SSH_AUTH_AGAIN); } while (rc == SSH_AUTH_AGAIN);
@@ -704,7 +742,7 @@ static void torture_auth_pubkey_types_ecdsa_nonblocking(void **state)
} while (rc == SSH_AUTH_AGAIN); } while (rc == SSH_AUTH_AGAIN);
assert_int_equal(rc, SSH_AUTH_DENIED); assert_int_equal(rc, SSH_AUTH_DENIED);
/* Verify we can use also ECDSA keys with their various names */ /* Verify we can use also ECDSA key to authenticate */
rc = ssh_options_set(session, SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES, rc = ssh_options_set(session, SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES,
"ecdsa-sha2-nistp256"); "ecdsa-sha2-nistp256");
assert_ssh_return_code(session, rc); assert_ssh_return_code(session, rc);
@@ -716,6 +754,52 @@ static void torture_auth_pubkey_types_ecdsa_nonblocking(void **state)
} }
static void torture_auth_pubkey_types_ed25519_nonblocking(void **state)
{
struct torture_state *s = *state;
ssh_session session = s->ssh.session;
int rc;
rc = ssh_options_set(session, SSH_OPTIONS_USER, TORTURE_SSH_USER_ALICE);
assert_ssh_return_code(session, rc);
rc = ssh_connect(session);
assert_ssh_return_code(session, rc);
ssh_set_blocking(session, 0);
do {
rc = ssh_userauth_none(session, NULL);
} while (rc == SSH_AUTH_AGAIN);
/* This request should return a SSH_REQUEST_DENIED error */
if (rc == SSH_ERROR) {
assert_int_equal(ssh_get_error_code(session), SSH_REQUEST_DENIED);
}
rc = ssh_userauth_list(session, NULL);
assert_true(rc & SSH_AUTH_METHOD_PUBLICKEY);
/* Enable only DSA keys -- authentication should fail */
rc = ssh_options_set(session, SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES,
"ssh-dss");
assert_ssh_return_code(session, rc);
do {
rc = ssh_userauth_publickey_auto(session, NULL, NULL);
} while (rc == SSH_AUTH_AGAIN);
assert_int_equal(rc, SSH_AUTH_DENIED);
/* Verify we can use also ED25519 key to authenticate */
rc = ssh_options_set(session, SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES,
"ssh-ed25519");
assert_ssh_return_code(session, rc);
do {
rc = ssh_userauth_publickey_auto(session, NULL, NULL);
} while (rc == SSH_AUTH_AGAIN);
assert_int_equal(rc, SSH_AUTH_SUCCESS);
}
int torture_run_tests(void) { int torture_run_tests(void) {
int rc; int rc;
@@ -771,6 +855,12 @@ int torture_run_tests(void) {
cmocka_unit_test_setup_teardown(torture_auth_pubkey_types_ecdsa_nonblocking, cmocka_unit_test_setup_teardown(torture_auth_pubkey_types_ecdsa_nonblocking,
pubkey_setup, pubkey_setup,
session_teardown), session_teardown),
cmocka_unit_test_setup_teardown(torture_auth_pubkey_types_ed25519,
pubkey_setup,
session_teardown),
cmocka_unit_test_setup_teardown(torture_auth_pubkey_types_ed25519_nonblocking,
pubkey_setup,
session_teardown),
}; };
ssh_init(); ssh_init();

View File

@@ -167,6 +167,10 @@ static void torture_knownhosts_precheck(void **state)
"127.0.0.10 %s\n", "127.0.0.10 %s\n",
torture_get_testkey_pub(SSH_KEYTYPE_ED25519, 0)); torture_get_testkey_pub(SSH_KEYTYPE_ED25519, 0));
fprintf(file,
"127.0.0.10 %s\n",
torture_get_testkey_pub(SSH_KEYTYPE_ECDSA, 521));
fclose(file); fclose(file);
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file); rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
@@ -176,7 +180,7 @@ static void torture_knownhosts_precheck(void **state)
assert_non_null(algo_list); assert_non_null(algo_list);
algo_count = ssh_list_count(algo_list); algo_count = ssh_list_count(algo_list);
assert_int_equal(algo_count, 2); assert_int_equal(algo_count, 3);
it = ssh_list_get_iterator(algo_list); it = ssh_list_get_iterator(algo_list);
assert_non_null(it); assert_non_null(it);
@@ -190,6 +194,13 @@ static void torture_knownhosts_precheck(void **state)
algo = ssh_iterator_value(const char *, it); algo = ssh_iterator_value(const char *, it);
assert_string_equal(algo, "ssh-ed25519"); assert_string_equal(algo, "ssh-ed25519");
ssh_list_remove(algo_list, it);
it = ssh_list_get_iterator(algo_list);
assert_non_null(it);
algo = ssh_iterator_value(const char *, it);
assert_string_equal(algo, "ecdsa-sha2-nistp521");
ssh_list_free(algo_list); ssh_list_free(algo_list);
} }

View File

@@ -39,7 +39,7 @@ set(CTEST_SOURCE_DIRECTORY "${CTEST_DIRECTORY}/${CTEST_BUILD_NAME}/source")
set(CTEST_BINARY_DIRECTORY "${CTEST_DIRECTORY}/${CTEST_BUILD_NAME}/build") set(CTEST_BINARY_DIRECTORY "${CTEST_DIRECTORY}/${CTEST_BUILD_NAME}/build")
set(CTEST_MEMORYCHECK_SUPPRESSIONS_FILE ${CMAKE_SOURCE_DIR}/tests/valgrind.supp) set(CTEST_MEMORYCHECK_SUPPRESSIONS_FILE ${CMAKE_SOURCE_DIR}/tests/valgrind.supp)
set(CTEST_MEMORYCHECK_COMMAND_OPTIONS " --trace-children-skip=sshd") set(CTEST_MEMORYCHECK_COMMAND_OPTIONS " --trace-children-skip=${SSHD_EXECUTABLE}")
find_program(CTEST_GIT_COMMAND NAMES git) find_program(CTEST_GIT_COMMAND NAMES git)
find_program(CTEST_COVERAGE_COMMAND NAMES gcov) find_program(CTEST_COVERAGE_COMMAND NAMES gcov)

8
tests/keys/id_ed25519 Normal file
View File

@@ -0,0 +1,8 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACCLo6vx1lX6ZZoe05lWTkuwrJUZN0T8hEer5UF9KPhOVgAAAKg+IRNSPiET
UgAAAAtzc2gtZWQyNTUxOQAAACCLo6vx1lX6ZZoe05lWTkuwrJUZN0T8hEer5UF9KPhOVg
AAAED2zFg52qYItoZaSUnir4VKubTxJveL9D2oWK7Prg/O24ujq/HWVfplmh7TmVZOS7Cs
lRk3RPyER6vlQX0o+E5WAAAAHmpqZWxlbkB0NDcwcy5qamVsZW4ucmVkaGF0LmNvbQECAw
QFBgc=
-----END OPENSSH PRIVATE KEY-----

View File

@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIujq/HWVfplmh7TmVZOS7CslRk3RPyER6vlQX0o+E5W jjelen@t470s.jjelen.redhat.com

View File

@@ -42,18 +42,24 @@ static int setup_knownhosts_file(void **state)
nwritten = fwrite(LOCALHOST_PATTERN_ED25519, nwritten = fwrite(LOCALHOST_PATTERN_ED25519,
sizeof(char), sizeof(char),
sizeof(LOCALHOST_PATTERN_ED25519), strlen(LOCALHOST_PATTERN_ED25519),
fp); fp);
if (nwritten != sizeof(LOCALHOST_PATTERN_ED25519)) { if (nwritten != strlen(LOCALHOST_PATTERN_ED25519)) {
fclose(fp);
return -1;
}
nwritten = fwrite("\n", sizeof(char), 1, fp);
if (nwritten != 1) {
fclose(fp); fclose(fp);
return -1; return -1;
} }
nwritten = fwrite(LOCALHOST_RSA_LINE, nwritten = fwrite(LOCALHOST_RSA_LINE,
sizeof(char), sizeof(char),
sizeof(LOCALHOST_RSA_LINE), strlen(LOCALHOST_RSA_LINE),
fp); fp);
if (nwritten != sizeof(LOCALHOST_RSA_LINE)) { if (nwritten != strlen(LOCALHOST_RSA_LINE)) {
fclose(fp); fclose(fp);
return -1; return -1;
} }
@@ -210,6 +216,8 @@ static void torture_knownhosts_read_file(void **state)
const char *knownhosts_file = *state; const char *knownhosts_file = *state;
struct ssh_list *entry_list = NULL; struct ssh_list *entry_list = NULL;
struct ssh_iterator *it = NULL; struct ssh_iterator *it = NULL;
struct ssh_knownhosts_entry *entry = NULL;
enum ssh_keytypes_e type;
int rc; int rc;
rc = ssh_known_hosts_read_entries("localhost", rc = ssh_known_hosts_read_entries("localhost",
@@ -219,22 +227,27 @@ static void torture_knownhosts_read_file(void **state)
assert_non_null(entry_list); assert_non_null(entry_list);
it = ssh_list_get_iterator(entry_list); it = ssh_list_get_iterator(entry_list);
assert_non_null(it); assert_non_null(it);
for (;it != NULL; it = it->next) {
struct ssh_knownhosts_entry *entry = NULL;
enum ssh_keytypes_e type;
entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it); /* First key in known hosts file is ED25519 */
assert_non_null(entry); entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
assert_non_null(entry);
assert_string_equal(entry->hostname, "localhost"); assert_string_equal(entry->hostname, "localhost");
type = ssh_key_type(entry->publickey); type = ssh_key_type(entry->publickey);
assert_int_equal(type, SSH_KEYTYPE_ED25519); assert_int_equal(type, SSH_KEYTYPE_ED25519);
}
it = it->next;
/* Second key in known hosts file is RSA */
entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
assert_non_null(entry);
assert_string_equal(entry->hostname, "localhost");
type = ssh_key_type(entry->publickey);
assert_int_equal(type, SSH_KEYTYPE_RSA);
it = ssh_list_get_iterator(entry_list); it = ssh_list_get_iterator(entry_list);
for (;it != NULL; it = it->next) { for (;it != NULL; it = it->next) {
struct ssh_knownhosts_entry *entry = NULL;
entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it); entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
SSH_KNOWNHOSTS_ENTRY_FREE(entry); SSH_KNOWNHOSTS_ENTRY_FREE(entry);
} }
@@ -252,6 +265,8 @@ static void torture_knownhosts_host_exists(void **state)
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost"); ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, knownhosts_file); ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, knownhosts_file);
/* This makes sure the system's known_hosts are not used */
ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, "/dev/null");
found = ssh_session_has_known_hosts_entry(session); found = ssh_session_has_known_hosts_entry(session);
assert_int_equal(found, SSH_KNOWN_HOSTS_OK); assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
@@ -264,6 +279,89 @@ static void torture_knownhosts_host_exists(void **state)
ssh_free(session); ssh_free(session);
} }
static void torture_knownhosts_host_exists_global(void **state)
{
const char *knownhosts_file = *state;
enum ssh_known_hosts_e found;
ssh_session session;
session = ssh_new();
assert_non_null(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
/* This makes sure the user's known_hosts are not used */
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, "/dev/null");
ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, knownhosts_file);
found = ssh_session_has_known_hosts_entry(session);
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
assert_true(found == SSH_KNOWN_HOSTS_OK);
ssh_options_set(session, SSH_OPTIONS_HOST, "wurstbrot");
found = ssh_session_has_known_hosts_entry(session);
assert_true(found == SSH_KNOWN_HOSTS_UNKNOWN);
ssh_free(session);
}
static void
torture_knownhosts_algorithms(void **state)
{
const char *knownhosts_file = *state;
char *algo_list = NULL;
ssh_session session;
const char *expect = "ssh-ed25519,ssh-rsa,ecdsa-sha2-nistp521,"
"ecdsa-sha2-nistp384,ecdsa-sha2-nistp256"
#ifdef HAVE_DSA
",ssh-dss"
#endif
;
session = ssh_new();
assert_non_null(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, knownhosts_file);
/* This makes sure the system's known_hosts are not used */
ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, "/dev/null");
algo_list = ssh_client_select_hostkeys(session);
assert_non_null(algo_list);
assert_string_equal(algo_list, expect);
free(algo_list);
ssh_free(session);
}
static void
torture_knownhosts_algorithms_global(void **state)
{
const char *knownhosts_file = *state;
char *algo_list = NULL;
ssh_session session;
const char *expect = "ssh-ed25519,ssh-rsa,ecdsa-sha2-nistp521,"
"ecdsa-sha2-nistp384,ecdsa-sha2-nistp256"
#ifdef HAVE_DSA
",ssh-dss"
#endif
;
session = ssh_new();
assert_non_null(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
/* This makes sure the current-user's known hosts are not used */
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, "/dev/null");
ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, knownhosts_file);
algo_list = ssh_client_select_hostkeys(session);
assert_non_null(algo_list);
assert_string_equal(algo_list, expect);
free(algo_list);
ssh_free(session);
}
int torture_run_tests(void) { int torture_run_tests(void) {
int rc; int rc;
struct CMUnitTest tests[] = { struct CMUnitTest tests[] = {
@@ -279,6 +377,15 @@ int torture_run_tests(void) {
cmocka_unit_test_setup_teardown(torture_knownhosts_host_exists, cmocka_unit_test_setup_teardown(torture_knownhosts_host_exists,
setup_knownhosts_file, setup_knownhosts_file,
teardown_knownhosts_file), teardown_knownhosts_file),
cmocka_unit_test_setup_teardown(torture_knownhosts_host_exists_global,
setup_knownhosts_file,
teardown_knownhosts_file),
cmocka_unit_test_setup_teardown(torture_knownhosts_algorithms,
setup_knownhosts_file,
teardown_knownhosts_file),
cmocka_unit_test_setup_teardown(torture_knownhosts_algorithms_global,
setup_knownhosts_file,
teardown_knownhosts_file),
}; };
ssh_init(); ssh_init();

View File

@@ -346,6 +346,76 @@ static void torture_options_get_identity(void **state) {
free(identity); free(identity);
} }
static void torture_options_set_global_knownhosts(void **state)
{
ssh_session session = *state;
int rc;
rc = ssh_options_set(session,
SSH_OPTIONS_GLOBAL_KNOWNHOSTS,
"/etc/libssh/known_hosts");
assert_ssh_return_code(session, rc);
assert_string_equal(session->opts.global_knownhosts,
"/etc/libssh/known_hosts");
}
static void torture_options_get_global_knownhosts(void **state)
{
ssh_session session = *state;
char *str = NULL;
int rc;
rc = ssh_options_set(session,
SSH_OPTIONS_GLOBAL_KNOWNHOSTS,
"/etc/libssh/known_hosts");
assert_ssh_return_code(session, rc);
assert_string_equal(session->opts.global_knownhosts,
"/etc/libssh/known_hosts");
rc = ssh_options_get(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, &str);
assert_ssh_return_code(session, rc);
assert_string_equal(session->opts.global_knownhosts,
"/etc/libssh/known_hosts");
SSH_STRING_FREE_CHAR(str);
}
static void torture_options_set_knownhosts(void **state)
{
ssh_session session = *state;
int rc;
rc = ssh_options_set(session,
SSH_OPTIONS_KNOWNHOSTS,
"/home/libssh/.ssh/known_hosts");
assert_ssh_return_code(session, rc);
assert_string_equal(session->opts.knownhosts,
"/home/libssh/.ssh/known_hosts");
}
static void torture_options_get_knownhosts(void **state)
{
ssh_session session = *state;
char *str = NULL;
int rc;
rc = ssh_options_set(session,
SSH_OPTIONS_KNOWNHOSTS,
"/home/libssh/.ssh/known_hosts");
assert_ssh_return_code(session, rc);
assert_string_equal(session->opts.knownhosts,
"/home/libssh/.ssh/known_hosts");
rc = ssh_options_get(session, SSH_OPTIONS_KNOWNHOSTS, &str);
assert_ssh_return_code(session, rc);
assert_string_equal(session->opts.knownhosts,
"/home/libssh/.ssh/known_hosts");
SSH_STRING_FREE_CHAR(str);
}
static void torture_options_proxycommand(void **state) { static void torture_options_proxycommand(void **state) {
ssh_session session = *state; ssh_session session = *state;
int rc; int rc;
@@ -604,6 +674,10 @@ int torture_run_tests(void) {
cmocka_unit_test_setup_teardown(torture_options_get_user, setup, teardown), cmocka_unit_test_setup_teardown(torture_options_get_user, setup, teardown),
cmocka_unit_test_setup_teardown(torture_options_set_identity, setup, teardown), cmocka_unit_test_setup_teardown(torture_options_set_identity, setup, teardown),
cmocka_unit_test_setup_teardown(torture_options_get_identity, setup, teardown), cmocka_unit_test_setup_teardown(torture_options_get_identity, setup, teardown),
cmocka_unit_test_setup_teardown(torture_options_set_global_knownhosts, setup, teardown),
cmocka_unit_test_setup_teardown(torture_options_get_global_knownhosts, setup, teardown),
cmocka_unit_test_setup_teardown(torture_options_set_knownhosts, setup, teardown),
cmocka_unit_test_setup_teardown(torture_options_get_knownhosts, setup, teardown),
cmocka_unit_test_setup_teardown(torture_options_proxycommand, setup, teardown), cmocka_unit_test_setup_teardown(torture_options_proxycommand, setup, teardown),
cmocka_unit_test_setup_teardown(torture_options_set_ciphers, setup, teardown), cmocka_unit_test_setup_teardown(torture_options_set_ciphers, setup, teardown),
cmocka_unit_test_setup_teardown(torture_options_set_key_exchange, setup, teardown), cmocka_unit_test_setup_teardown(torture_options_set_key_exchange, setup, teardown),

View File

@@ -104,8 +104,7 @@ static void torture_packet(const char *cipher,
assert_non_null(session->out_buffer); assert_non_null(session->out_buffer);
ssh_buffer_add_data(session->out_buffer, test_data, payload_len); ssh_buffer_add_data(session->out_buffer, test_data, payload_len);
session->socket->fd_out = sockets[0]; session->socket->fd = sockets[0];
session->socket->fd_in = -2;
session->socket->write_wontblock = 1; session->socket->write_wontblock = 1;
rc = ssh_packet_send(session); rc = ssh_packet_send(session);
assert_int_equal(rc, SSH_OK); assert_int_equal(rc, SSH_OK);
@@ -126,8 +125,7 @@ static void torture_packet(const char *cipher,
} }
close(sockets[0]); close(sockets[0]);
close(sockets[1]); close(sockets[1]);
session->socket->fd_in = SSH_INVALID_SOCKET; session->socket->fd = SSH_INVALID_SOCKET;
session->socket->fd_out = SSH_INVALID_SOCKET;
ssh_free(session); ssh_free(session);
} }