mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-04 20:30:38 +09:00
Compare commits
26 Commits
libssh-0.8
...
libssh-0.8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
273fb4cfc6 | ||
|
|
56f7c27852 | ||
|
|
1285b37b60 | ||
|
|
b7de358cdc | ||
|
|
bea6393de0 | ||
|
|
9158cc524c | ||
|
|
8ba10ef42b | ||
|
|
2ff8a09ee6 | ||
|
|
d52fa9a02c | ||
|
|
ec3fdb434c | ||
|
|
d877969db3 | ||
|
|
b1a7bd21ad | ||
|
|
0831b85002 | ||
|
|
34d1f5e097 | ||
|
|
fcf2cd0d9e | ||
|
|
4a4ca44b19 | ||
|
|
17a6c3f88f | ||
|
|
e24bb932ed | ||
|
|
5c2d444fa8 | ||
|
|
9763563c02 | ||
|
|
5f9d9f4a53 | ||
|
|
e8f3207a0d | ||
|
|
e5cee205c1 | ||
|
|
63056d1bb1 | ||
|
|
09e4f3d331 | ||
|
|
4b886ac656 |
@@ -10,7 +10,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules")
|
||||
include(DefineCMakeDefaults)
|
||||
include(DefineCompilerFlags)
|
||||
|
||||
project(libssh VERSION 0.8.4 LANGUAGES C)
|
||||
project(libssh VERSION 0.8.5 LANGUAGES C)
|
||||
|
||||
# global needed variable
|
||||
set(APPLICATION_NAME ${PROJECT_NAME})
|
||||
@@ -22,7 +22,7 @@ set(APPLICATION_NAME ${PROJECT_NAME})
|
||||
# Increment AGE. Set REVISION to 0
|
||||
# If the source code was changed, but there were no interface changes:
|
||||
# Increment REVISION.
|
||||
set(LIBRARY_VERSION "4.7.1")
|
||||
set(LIBRARY_VERSION "4.7.2")
|
||||
set(LIBRARY_SOVERSION "4")
|
||||
|
||||
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
|
||||
|
||||
11
ChangeLog
11
ChangeLog
@@ -1,6 +1,17 @@
|
||||
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)
|
||||
* Fixed CVE-2018-10933
|
||||
* Fixed building without globbing support
|
||||
|
||||
@@ -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,
|
||||
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,
|
||||
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.
|
||||
- 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.
|
||||
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
|
||||
ssh_userauth_kbdint() until needed.
|
||||
ssh_userauth_kbdint() until needed.
|
||||
- The meaning of "name", "prompt", "instruction" may be a little
|
||||
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
|
||||
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
|
||||
indication that such truncation has occured.
|
||||
indication that such truncation has occurred.
|
||||
|
||||
The instruction field SHOULD NOT be truncated. Clients SHOULD use control
|
||||
character filtering as discussed in [SSH-ARCH] to avoid attacks by
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
Port forwarding comes in SSH protocol in two different flavours:
|
||||
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.
|
||||
|
||||
|
||||
@@ -23,15 +23,15 @@ Mail client application Google Mail
|
||||
5555 (arbitrary) |
|
||||
| 143 (IMAP2)
|
||||
V |
|
||||
SSH client =====> SSH server
|
||||
SSH client =====> SSH server
|
||||
|
||||
Legend:
|
||||
--P-->: port connexion through port P
|
||||
--P-->: port connections through port P
|
||||
=====>: SSH tunnel
|
||||
@endverbatim
|
||||
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
|
||||
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
|
||||
@@ -51,7 +51,7 @@ Example of use of reverse port forwarding:
|
||||
SSH client <===== SSH server
|
||||
|
||||
Legend:
|
||||
--P-->: port connexion through port P
|
||||
--P-->: port connections through port P
|
||||
=====>: SSH tunnel
|
||||
@endverbatim
|
||||
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().
|
||||
|
||||
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
|
||||
your own priviledged or non-priviledged port. Beware that you should have
|
||||
administrative priviledges on the remote server to open a priviledged port
|
||||
chose the non-privileged port it should listen to. Otherwise, you can chose
|
||||
your own privileged or non-privileged port. Beware that you should have
|
||||
administrative privileges on the remote server to open a privileged port
|
||||
(port number < 1024).
|
||||
|
||||
Below is an example of a very rough web server waiting for connections on port
|
||||
|
||||
@@ -31,20 +31,20 @@ A SSH session goes through the following steps:
|
||||
- Invoke your own subsystem. This is outside the scope of this document,
|
||||
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 programmer. If you want to use those subsystems, instead of a channel,
|
||||
you'll usually open a "sftp session" or a "scp session".
|
||||
|
||||
|
||||
|
||||
@subsection setup Creating the session and setting options
|
||||
|
||||
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
|
||||
always verify that the allocation successed.
|
||||
always verify that the allocation succeeded.
|
||||
@code
|
||||
#include <libssh/libssh.h>
|
||||
#include <libssh/libssh.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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 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:
|
||||
|
||||
@code
|
||||
#include <libssh/libssh.h>
|
||||
#include <libssh/libssh.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main()
|
||||
@@ -122,7 +122,7 @@ Here's an example:
|
||||
@code
|
||||
#include <libssh/libssh.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
@@ -285,9 +285,9 @@ int verify_knownhost(ssh_session session)
|
||||
|
||||
The authentication process is the way a service provider can identify a
|
||||
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
|
||||
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:
|
||||
- "none" method. This method allows to get the available authentications
|
||||
@@ -313,7 +313,7 @@ The example below shows an authentication with password:
|
||||
@code
|
||||
#include <libssh/libssh.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
@@ -338,7 +338,7 @@ int main()
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
if (nbytes < 0)
|
||||
{
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
For thread safety, errors are bound to ssh_session objects.
|
||||
|
||||
@@ -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
|
||||
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,
|
||||
two general-purpose cryptographic libraries.
|
||||
|
||||
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.
|
||||
|
||||
This tutorial describes libssh version 0.5.0. This version is a little different
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@page libssh_tutor_scp Chapter 6: 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,
|
||||
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
|
||||
+-- B --+
|
||||
| +-- file2
|
||||
-- A --+
|
||||
-- A --+
|
||||
| +-- file3
|
||||
+-- C --+
|
||||
+-- file4
|
||||
@@ -210,7 +210,7 @@ int scp_receive(ssh_session session, ssh_scp scp)
|
||||
size = ssh_scp_request_get_size(scp);
|
||||
filename = strdup(ssh_scp_request_get_filename(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);
|
||||
free(filename);
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ Possible errors are:
|
||||
|
||||
@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
|
||||
desired permissions. The permissions are the same as for the usual mkdir()
|
||||
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
|
||||
|
||||
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
|
||||
directory being read.
|
||||
|
||||
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
|
||||
- size: its size in bytes
|
||||
- etc.
|
||||
|
||||
sftp_readdir() might return NULL under two conditions:
|
||||
- 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().
|
||||
|
||||
|
||||
@@ -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
|
||||
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
|
||||
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
|
||||
@@ -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
|
||||
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
|
||||
them repeatedly in a loop, it will not consume exaggerate processor time
|
||||
and make your computer unresponsive. It is quite common to use these
|
||||
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_select() is more complete and enables watching regular file descriptors
|
||||
as well, in the same function call.
|
||||
|
||||
@@ -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
|
||||
ssh_init() before using any of libssh provided functions. This initialization
|
||||
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
|
||||
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
|
||||
being worked out and will maybe disappear later.
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ clients must be made or how a client should react.
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define SSHD_USER "libssh"
|
||||
#define SSHD_PASSWORD "libssh"
|
||||
@@ -36,6 +37,7 @@ clients must be made or how a client should react.
|
||||
#endif
|
||||
|
||||
static int port = 22;
|
||||
static bool authenticated = false;
|
||||
|
||||
#ifdef WITH_PCAP
|
||||
static const char *pcap_file = "debug.server.pcap";
|
||||
@@ -61,11 +63,20 @@ static void cleanup_pcap(void) {
|
||||
#endif
|
||||
|
||||
|
||||
static int auth_password(const char *user, const char *password){
|
||||
if(strcmp(user, SSHD_USER))
|
||||
static int auth_password(const char *user, const char *password)
|
||||
{
|
||||
int cmp;
|
||||
|
||||
cmp = strcmp(user, SSHD_USER);
|
||||
if (cmp != 0) {
|
||||
return 0;
|
||||
if(strcmp(password, SSHD_PASSWORD))
|
||||
}
|
||||
cmp = strcmp(password, SSHD_PASSWORD);
|
||||
if (cmp != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
authenticated = true;
|
||||
return 1; // authenticated
|
||||
}
|
||||
#ifdef HAVE_ARGP_H
|
||||
@@ -200,6 +211,7 @@ static int kbdint_check_response(ssh_session session) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
authenticated = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -328,7 +340,7 @@ int main(int argc, char **argv){
|
||||
|
||||
/* proceed to authentication */
|
||||
auth = authenticate(session);
|
||||
if(!auth){
|
||||
if (!auth || !authenticated) {
|
||||
printf("Authentication error: %s\n", ssh_get_error(session));
|
||||
ssh_disconnect(session);
|
||||
return 1;
|
||||
|
||||
@@ -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_default_methods(uint32_t algo);
|
||||
const char *ssh_kex_get_description(uint32_t algo);
|
||||
char *ssh_client_select_hostkeys(ssh_session session);
|
||||
|
||||
#endif /* KEX_H_ */
|
||||
|
||||
@@ -23,5 +23,9 @@
|
||||
#define SSH_KNOWNHOSTS_H_
|
||||
|
||||
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_ */
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
/* libssh version */
|
||||
#define LIBSSH_VERSION_MAJOR 0
|
||||
#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, \
|
||||
LIBSSH_VERSION_MINOR, \
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#ifndef _LIBSSH_PRIV_H
|
||||
#define _LIBSSH_PRIV_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -128,6 +129,13 @@ char *strndup(const char *s, size_t n);
|
||||
# endif /* HAVE__VSNPRINTF */
|
||||
# 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 */
|
||||
|
||||
struct timeval;
|
||||
|
||||
@@ -53,9 +53,14 @@ extern "C" {
|
||||
typedef uint32_t gid_t;
|
||||
#endif /* gid_t */
|
||||
#ifdef _MSC_VER
|
||||
#ifndef ssize_t
|
||||
typedef _W64 SSIZE_T ssize_t;
|
||||
#endif /* ssize_t */
|
||||
|
||||
# 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 /* _WIN32 */
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ ssh_socket ssh_socket_new(ssh_session session);
|
||||
void ssh_socket_reset(ssh_socket s);
|
||||
void ssh_socket_free(ssh_socket s);
|
||||
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
|
||||
int ssh_socket_unix(ssh_socket s, const char *path);
|
||||
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);
|
||||
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_out(ssh_socket s);
|
||||
struct ssh_poll_handle_struct * ssh_socket_get_poll_handle(ssh_socket s);
|
||||
|
||||
int ssh_socket_connect(ssh_socket s, const char *host, int port, const char *bind_addr);
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
4.7.1
|
||||
4.7.2
|
||||
415
src/ABI/libssh-4.7.2.symbols
Normal file
415
src/ABI/libssh-4.7.2.symbols
Normal 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
|
||||
@@ -93,7 +93,7 @@ static size_t atomicio(struct ssh_agent_struct *agent, void *buf, size_t n, int
|
||||
|
||||
/* Using a socket ? */
|
||||
if (channel == NULL) {
|
||||
fd = ssh_socket_get_fd_in(agent->sock);
|
||||
fd = ssh_socket_get_fd(agent->sock);
|
||||
pfd.fd = fd;
|
||||
pfd.events = do_read ? POLLIN : POLLOUT;
|
||||
|
||||
|
||||
@@ -447,7 +447,7 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
|
||||
return SSH_ERROR;
|
||||
}
|
||||
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 are not using ssh_bind_listen (which is the other place
|
||||
|
||||
23
src/client.c
23
src/client.c
@@ -411,6 +411,14 @@ static void ssh_client_connection_callback(ssh_session session)
|
||||
|
||||
ssh_packet_set_default_callbacks(session);
|
||||
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);
|
||||
|
||||
break;
|
||||
@@ -420,14 +428,19 @@ static void ssh_client_connection_callback(ssh_session session)
|
||||
case SSH_SESSION_STATE_KEXINIT_RECEIVED:
|
||||
set_status(session,0.6f);
|
||||
ssh_list_kex(&session->next_crypto->server_kex);
|
||||
if (ssh_set_client_kex(session) < 0) {
|
||||
goto error;
|
||||
if (session->next_crypto->client_kex.methods[0] == NULL) {
|
||||
/* 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)
|
||||
goto error;
|
||||
if (ssh_send_kex(session, 0) < 0) {
|
||||
goto error;
|
||||
}
|
||||
set_status(session,0.8f);
|
||||
session->session_state=SSH_SESSION_STATE_DH;
|
||||
if (dh_handshake(session) == SSH_ERROR) {
|
||||
|
||||
@@ -120,6 +120,7 @@ static int ssh_gssapi_send_response(ssh_session session, ssh_string oid){
|
||||
ssh_set_error_oom(session);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
session->auth.state = SSH_AUTH_STATE_GSSAPI_TOKEN;
|
||||
|
||||
ssh_packet_send(session);
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
|
||||
39
src/kex.c
39
src/kex.c
@@ -26,6 +26,7 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "libssh/priv.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.
|
||||
* 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 tail_buffer[128]={0};
|
||||
char *new_hostkeys = NULL;
|
||||
static const char *preferred_hostkeys[] = {
|
||||
"ssh-ed25519",
|
||||
"ecdsa-sha2-nistp521",
|
||||
@@ -610,7 +613,7 @@ static char *ssh_client_select_hostkeys(ssh_session session)
|
||||
struct ssh_iterator *it = NULL;
|
||||
size_t algo_count;
|
||||
int needcomma = 0;
|
||||
int i;
|
||||
size_t i, len;
|
||||
|
||||
algo_list = ssh_known_hosts_get_algorithms(session);
|
||||
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) {
|
||||
bool found = false;
|
||||
|
||||
for (it = ssh_list_get_iterator(algo_list);
|
||||
it != NULL;
|
||||
it = ssh_list_get_iterator(algo_list)) {
|
||||
it = it->next) {
|
||||
const char *algo = ssh_iterator_value(const char *, it);
|
||||
int cmp;
|
||||
int ok;
|
||||
@@ -644,10 +649,18 @@ static char *ssh_client_select_hostkeys(ssh_session session)
|
||||
algo,
|
||||
sizeof(methods_buffer) - strlen(methods_buffer) - 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);
|
||||
@@ -658,11 +671,23 @@ static char *ssh_client_select_hostkeys(ssh_session session)
|
||||
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,
|
||||
"Changing host key method to \"%s\"",
|
||||
methods_buffer);
|
||||
new_hostkeys);
|
||||
|
||||
return strdup(methods_buffer);
|
||||
return new_hostkeys;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
128
src/knownhosts.c
128
src/knownhosts.c
@@ -182,11 +182,16 @@ static int known_hosts_read_line(FILE *fp,
|
||||
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,
|
||||
const char *filename,
|
||||
struct ssh_list **entries)
|
||||
{
|
||||
struct ssh_list *entry_list;
|
||||
char line[8192];
|
||||
size_t lineno = 0;
|
||||
size_t len = 0;
|
||||
@@ -195,13 +200,18 @@ static int ssh_known_hosts_read_entries(const char *match,
|
||||
|
||||
fp = fopen(filename, "r");
|
||||
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 (entry_list == NULL) {
|
||||
fclose(fp);
|
||||
return SSH_ERROR;
|
||||
if (*entries == NULL) {
|
||||
*entries = ssh_list_new();
|
||||
if (*entries == NULL) {
|
||||
fclose(fp);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
goto error;
|
||||
}
|
||||
ssh_list_append(entry_list, entry);
|
||||
ssh_list_append(*entries, entry);
|
||||
}
|
||||
|
||||
*entries = entry_list;
|
||||
|
||||
fclose(fp);
|
||||
return SSH_OK;
|
||||
error:
|
||||
ssh_list_free(entry_list);
|
||||
fclose(fp);
|
||||
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,
|
||||
session->opts.knownhosts,
|
||||
&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);
|
||||
if (rc != 0) {
|
||||
ssh_list_free(entry_list);
|
||||
ssh_list_free(list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (entry_list == NULL) {
|
||||
ssh_list_free(list);
|
||||
return NULL;
|
||||
}
|
||||
@@ -340,12 +362,10 @@ struct ssh_list *ssh_known_hosts_get_algorithms(ssh_session session)
|
||||
it != NULL;
|
||||
it = ssh_list_get_iterator(entry_list)) {
|
||||
struct ssh_knownhosts_entry *entry = NULL;
|
||||
enum ssh_keytypes_e key_type;
|
||||
const char *algo = NULL;
|
||||
|
||||
entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
|
||||
key_type = ssh_key_type(entry->publickey);
|
||||
algo = ssh_key_type_to_char(key_type);
|
||||
algo = entry->publickey->type_c;
|
||||
|
||||
rc = ssh_list_append(list, algo);
|
||||
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,
|
||||
session->opts.knownhosts,
|
||||
&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);
|
||||
if (rc != 0) {
|
||||
ssh_list_free(entry_list);
|
||||
return SSH_KNOWN_HOSTS_UNKNOWN;
|
||||
}
|
||||
|
||||
@@ -621,7 +650,7 @@ int ssh_session_export_known_hosts_entry(ssh_session session,
|
||||
|
||||
if (session->current_crypto == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"No current crypto context, please connnect first");
|
||||
"No current crypto context, please connect first");
|
||||
SAFE_FREE(host);
|
||||
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
|
||||
* 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.
|
||||
*
|
||||
@@ -747,6 +777,7 @@ ssh_known_hosts_check_server_key(const char *hosts_entry,
|
||||
filename,
|
||||
&entry_list);
|
||||
if (rc != 0) {
|
||||
ssh_list_free(entry_list);
|
||||
return SSH_KNOWN_HOSTS_UNKNOWN;
|
||||
}
|
||||
|
||||
@@ -824,9 +855,7 @@ enum ssh_known_hosts_e
|
||||
ssh_session_get_known_hosts_entry(ssh_session session,
|
||||
struct ssh_knownhosts_entry **pentry)
|
||||
{
|
||||
ssh_key server_pubkey = NULL;
|
||||
char *host_port = NULL;
|
||||
enum ssh_known_hosts_e found = SSH_KNOWN_HOSTS_UNKNOWN;
|
||||
enum ssh_known_hosts_e old_rv, rv = SSH_KNOWN_HOSTS_UNKNOWN;
|
||||
|
||||
if (session->opts.knownhosts == NULL) {
|
||||
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);
|
||||
if (server_pubkey == NULL) {
|
||||
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,
|
||||
session->opts.knownhosts,
|
||||
filename,
|
||||
server_pubkey,
|
||||
pentry);
|
||||
SAFE_FREE(host_port);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
EVP_DigestFinal(ctx, md, mdlen);
|
||||
EVP_MD_CTX_free(ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -704,6 +704,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_request){
|
||||
ssh_message msg = NULL;
|
||||
char *service = NULL;
|
||||
char *method = NULL;
|
||||
int cmp;
|
||||
int rc;
|
||||
|
||||
(void)user;
|
||||
@@ -730,6 +731,13 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_request){
|
||||
service, method,
|
||||
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) {
|
||||
msg->auth_request.method = SSH_AUTH_METHOD_NONE;
|
||||
|
||||
@@ -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
|
||||
* 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
|
||||
* allocated by the function for the value, it is
|
||||
* 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;
|
||||
break;
|
||||
}
|
||||
case SSH_OPTIONS_KNOWNHOSTS: {
|
||||
src = session->opts.knownhosts;
|
||||
break;
|
||||
}
|
||||
case SSH_OPTIONS_GLOBAL_KNOWNHOSTS: {
|
||||
src = session->opts.global_knownhosts;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
|
||||
return SSH_ERROR;
|
||||
@@ -1356,6 +1370,17 @@ int ssh_options_apply(ssh_session session) {
|
||||
free(session->opts.knownhosts);
|
||||
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) {
|
||||
tmp = ssh_path_expand_escape(session, session->opts.ProxyCommand);
|
||||
if (tmp == NULL) {
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
|
||||
@@ -312,7 +312,7 @@ static int ssh_pcap_context_connect(ssh_pcap_context ctx){
|
||||
return SSH_ERROR;
|
||||
if(session->socket==NULL)
|
||||
return SSH_ERROR;
|
||||
fd=ssh_socket_get_fd_in(session->socket);
|
||||
fd = ssh_socket_get_fd(session->socket);
|
||||
/* TODO: adapt for windows */
|
||||
if(fd<0)
|
||||
return SSH_ERROR;
|
||||
|
||||
@@ -790,7 +790,7 @@ ssh_string pki_private_key_to_pem(const ssh_key key,
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
default:
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -916,7 +916,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
|
||||
case SSH_KEYTYPE_RSA_CERT01:
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -998,7 +998,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
22
src/poll.c
22
src/poll.c
@@ -533,19 +533,17 @@ int ssh_poll_ctx_add(ssh_poll_ctx ctx, ssh_poll_handle p) {
|
||||
*
|
||||
* @return 0 on success, < 0 on error
|
||||
*/
|
||||
int ssh_poll_ctx_add_socket (ssh_poll_ctx ctx, ssh_socket s) {
|
||||
ssh_poll_handle p_in, p_out;
|
||||
int ret;
|
||||
p_in=ssh_socket_get_poll_handle_in(s);
|
||||
if(p_in==NULL)
|
||||
return -1;
|
||||
ret = ssh_poll_ctx_add(ctx,p_in);
|
||||
if(ret != 0)
|
||||
int ssh_poll_ctx_add_socket (ssh_poll_ctx ctx, ssh_socket s)
|
||||
{
|
||||
ssh_poll_handle p;
|
||||
int ret;
|
||||
|
||||
p = ssh_socket_get_poll_handle(s);
|
||||
if (p == NULL) {
|
||||
return -1;
|
||||
}
|
||||
ret = ssh_poll_ctx_add(ctx,p);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1039,6 +1039,7 @@ int ssh_message_auth_interactive_request(ssh_message msg, const char *name,
|
||||
msg->session->kbdint->prompts = NULL;
|
||||
msg->session->kbdint->echo = NULL;
|
||||
}
|
||||
msg->session->auth.state = SSH_AUTH_STATE_INFO;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -536,7 +536,7 @@ socket_t ssh_get_fd(ssh_session session) {
|
||||
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.
|
||||
*/
|
||||
int ssh_handle_packets(ssh_session session, int timeout) {
|
||||
ssh_poll_handle spoll_in,spoll_out;
|
||||
ssh_poll_handle spoll;
|
||||
ssh_poll_ctx ctx;
|
||||
int tm = timeout;
|
||||
int rc;
|
||||
@@ -608,17 +608,13 @@ int ssh_handle_packets(ssh_session session, int timeout) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
spoll_in = ssh_socket_get_poll_handle_in(session->socket);
|
||||
spoll_out = ssh_socket_get_poll_handle_out(session->socket);
|
||||
ssh_poll_add_events(spoll_in, POLLIN);
|
||||
ctx = ssh_poll_get_ctx(spoll_in);
|
||||
spoll = ssh_socket_get_poll_handle(session->socket);
|
||||
ssh_poll_add_events(spoll, POLLIN);
|
||||
ctx = ssh_poll_get_ctx(spoll);
|
||||
|
||||
if (!ctx) {
|
||||
ctx = ssh_poll_get_default_ctx(session);
|
||||
ssh_poll_ctx_add(ctx, spoll_in);
|
||||
if (spoll_in != spoll_out) {
|
||||
ssh_poll_ctx_add(ctx, spoll_out);
|
||||
}
|
||||
ssh_poll_ctx_add(ctx, spoll);
|
||||
}
|
||||
|
||||
if (timeout == SSH_TIMEOUT_USER) {
|
||||
|
||||
189
src/socket.c
189
src/socket.c
@@ -74,8 +74,7 @@ enum ssh_socket_states_e {
|
||||
};
|
||||
|
||||
struct ssh_socket_struct {
|
||||
socket_t fd_in;
|
||||
socket_t fd_out;
|
||||
socket_t fd;
|
||||
int fd_is_socket;
|
||||
int last_errno;
|
||||
int read_wontblock; /* reading now on socket will
|
||||
@@ -87,8 +86,7 @@ struct ssh_socket_struct {
|
||||
ssh_buffer in_buffer;
|
||||
ssh_session session;
|
||||
ssh_socket_callbacks callbacks;
|
||||
ssh_poll_handle poll_in;
|
||||
ssh_poll_handle poll_out;
|
||||
ssh_poll_handle poll_handle;
|
||||
};
|
||||
|
||||
static int sockets_initialized = 0;
|
||||
@@ -149,8 +147,7 @@ ssh_socket ssh_socket_new(ssh_session session) {
|
||||
ssh_set_error_oom(session);
|
||||
return NULL;
|
||||
}
|
||||
s->fd_in = SSH_INVALID_SOCKET;
|
||||
s->fd_out= SSH_INVALID_SOCKET;
|
||||
s->fd = SSH_INVALID_SOCKET;
|
||||
s->last_errno = -1;
|
||||
s->fd_is_socket = 1;
|
||||
s->session = session;
|
||||
@@ -170,7 +167,7 @@ ssh_socket ssh_socket_new(ssh_session session) {
|
||||
s->read_wontblock = 0;
|
||||
s->write_wontblock = 0;
|
||||
s->data_except = 0;
|
||||
s->poll_in=s->poll_out=NULL;
|
||||
s->poll_handle = NULL;
|
||||
s->state=SSH_SOCKET_NONE;
|
||||
return s;
|
||||
}
|
||||
@@ -181,8 +178,7 @@ ssh_socket ssh_socket_new(ssh_session session) {
|
||||
* @param[in] s socket to rest
|
||||
*/
|
||||
void ssh_socket_reset(ssh_socket s){
|
||||
s->fd_in = SSH_INVALID_SOCKET;
|
||||
s->fd_out= SSH_INVALID_SOCKET;
|
||||
s->fd = SSH_INVALID_SOCKET;
|
||||
s->last_errno = -1;
|
||||
s->fd_is_socket = 1;
|
||||
ssh_buffer_reinit(s->in_buffer);
|
||||
@@ -190,7 +186,7 @@ void ssh_socket_reset(ssh_socket s){
|
||||
s->read_wontblock = 0;
|
||||
s->write_wontblock = 0;
|
||||
s->data_except = 0;
|
||||
s->poll_in=s->poll_out=NULL;
|
||||
s->poll_handle = NULL;
|
||||
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);
|
||||
}
|
||||
|
||||
rc = ssh_socket_set_blocking(ssh_socket_get_fd_in(s));
|
||||
rc = ssh_socket_set_blocking(ssh_socket_get_fd(s));
|
||||
if (rc < 0) {
|
||||
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 */
|
||||
}
|
||||
|
||||
/* Return -1 if one of the poll handlers disappeared */
|
||||
if (s->poll_in == NULL || s->poll_out == NULL) {
|
||||
/* Return -1 if the poll handler disappeared */
|
||||
if (s->poll_handle == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -379,31 +375,17 @@ int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p,
|
||||
}
|
||||
|
||||
/** @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.
|
||||
* @returns allocated and initialized ssh_poll_handle object
|
||||
*/
|
||||
ssh_poll_handle ssh_socket_get_poll_handle_in(ssh_socket s){
|
||||
if(s->poll_in)
|
||||
return s->poll_in;
|
||||
s->poll_in=ssh_poll_new(s->fd_in,0,ssh_socket_pollcallback,s);
|
||||
if(s->fd_in == s->fd_out && s->poll_out == NULL)
|
||||
s->poll_out=s->poll_in;
|
||||
return s->poll_in;
|
||||
}
|
||||
|
||||
/** @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;
|
||||
ssh_poll_handle ssh_socket_get_poll_handle(ssh_socket s)
|
||||
{
|
||||
if (s->poll_handle) {
|
||||
return s->poll_handle;
|
||||
}
|
||||
s->poll_handle = ssh_poll_new(s->fd,0,ssh_socket_pollcallback,s);
|
||||
return s->poll_handle;
|
||||
}
|
||||
|
||||
/** \internal
|
||||
@@ -460,27 +442,17 @@ int ssh_socket_unix(ssh_socket s, const char *path) {
|
||||
void ssh_socket_close(ssh_socket s){
|
||||
if (ssh_socket_is_open(s)) {
|
||||
#ifdef _WIN32
|
||||
CLOSE_SOCKET(s->fd_in);
|
||||
/* fd_in = fd_out under win32 */
|
||||
CLOSE_SOCKET(s->fd);
|
||||
s->last_errno = WSAGetLastError();
|
||||
#else
|
||||
if (s->fd_out != s->fd_in && s->fd_out != -1) {
|
||||
CLOSE_SOCKET(s->fd_out);
|
||||
}
|
||||
CLOSE_SOCKET(s->fd_in);
|
||||
CLOSE_SOCKET(s->fd);
|
||||
s->last_errno = errno;
|
||||
#endif
|
||||
}
|
||||
|
||||
if(s->poll_in != NULL){
|
||||
if(s->poll_out == s->poll_in)
|
||||
s->poll_out = 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;
|
||||
if(s->poll_handle != NULL){
|
||||
ssh_poll_free(s->poll_handle);
|
||||
s->poll_handle=NULL;
|
||||
}
|
||||
|
||||
s->state = SSH_SOCKET_CLOSED;
|
||||
@@ -495,59 +467,34 @@ void ssh_socket_close(ssh_socket s){
|
||||
* file descriptors
|
||||
*/
|
||||
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) {
|
||||
ssh_poll_set_fd(s->poll_in,fd);
|
||||
if (s->poll_handle) {
|
||||
ssh_poll_set_fd(s->poll_handle,fd);
|
||||
} else {
|
||||
s->state = SSH_SOCKET_CONNECTING;
|
||||
|
||||
/* POLLOUT is the event to wait for in a nonblocking connect */
|
||||
ssh_poll_set_events(ssh_socket_get_poll_handle_in(s), POLLOUT);
|
||||
ssh_poll_set_events(ssh_socket_get_poll_handle(s), POLLOUT);
|
||||
#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
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
* \brief returns the input file descriptor of the socket
|
||||
*/
|
||||
socket_t ssh_socket_get_fd_in(ssh_socket s) {
|
||||
return s->fd_in;
|
||||
socket_t ssh_socket_get_fd(ssh_socket s)
|
||||
{
|
||||
return s->fd;
|
||||
}
|
||||
|
||||
/** \internal
|
||||
* \brief returns nonzero if the socket is open
|
||||
*/
|
||||
int ssh_socket_is_open(ssh_socket s) {
|
||||
return s->fd_in != SSH_INVALID_SOCKET;
|
||||
return s->fd != SSH_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
/** \internal
|
||||
@@ -563,9 +510,9 @@ static ssize_t ssh_socket_unbuffered_read(ssh_socket s,
|
||||
return -1;
|
||||
}
|
||||
if (s->fd_is_socket) {
|
||||
rc = recv(s->fd_in,buffer, len, 0);
|
||||
rc = recv(s->fd,buffer, len, 0);
|
||||
} else {
|
||||
rc = read(s->fd_in,buffer, len);
|
||||
rc = read(s->fd,buffer, len);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
s->last_errno = WSAGetLastError();
|
||||
@@ -600,9 +547,9 @@ static ssize_t ssh_socket_unbuffered_write(ssh_socket s,
|
||||
}
|
||||
|
||||
if (s->fd_is_socket) {
|
||||
w = send(s->fd_out, buffer, len, flags);
|
||||
w = send(s->fd, buffer, len, flags);
|
||||
} else {
|
||||
w = write(s->fd_out, buffer, len);
|
||||
w = write(s->fd, buffer, len);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
s->last_errno = WSAGetLastError();
|
||||
@@ -611,9 +558,9 @@ static ssize_t ssh_socket_unbuffered_write(ssh_socket s,
|
||||
#endif
|
||||
s->write_wontblock = 0;
|
||||
/* 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_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) {
|
||||
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
|
||||
*/
|
||||
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 FD_ISSET(s->fd_in,set) || FD_ISSET(s->fd_out,set);
|
||||
return FD_ISSET(s->fd,set);
|
||||
}
|
||||
|
||||
/** \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) {
|
||||
if (s->fd_in == SSH_INVALID_SOCKET) {
|
||||
if (s->fd == SSH_INVALID_SOCKET) {
|
||||
return;
|
||||
}
|
||||
|
||||
FD_SET(s->fd_in,set);
|
||||
FD_SET(s->fd_out,set);
|
||||
FD_SET(s->fd,set);
|
||||
|
||||
if (s->fd_in >= 0 &&
|
||||
s->fd_in >= *max_fd &&
|
||||
s->fd_in != SSH_INVALID_SOCKET) {
|
||||
*max_fd = s->fd_in + 1;
|
||||
}
|
||||
if (s->fd_out >= 0 &&
|
||||
s->fd_out >= *max_fd &&
|
||||
s->fd_out != SSH_INVALID_SOCKET) {
|
||||
*max_fd = s->fd_out + 1;
|
||||
if (s->fd >= 0 &&
|
||||
s->fd >= *max_fd &&
|
||||
s->fd != SSH_INVALID_SOCKET) {
|
||||
*max_fd = s->fd + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -701,9 +642,9 @@ int ssh_socket_nonblocking_flush(ssh_socket s)
|
||||
}
|
||||
|
||||
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 */
|
||||
ssh_poll_add_events(s->poll_out, POLLOUT);
|
||||
ssh_poll_add_events(s->poll_handle, POLLOUT);
|
||||
|
||||
return SSH_AGAIN;
|
||||
}
|
||||
@@ -741,9 +682,9 @@ int ssh_socket_nonblocking_flush(ssh_socket s)
|
||||
|
||||
/* Is there some data pending? */
|
||||
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 */
|
||||
ssh_poll_add_events(s->poll_out, POLLOUT);
|
||||
ssh_poll_add_events(s->poll_handle, POLLOUT);
|
||||
|
||||
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 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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){
|
||||
socket_t in_pipe[2];
|
||||
socket_t out_pipe[2];
|
||||
socket_t pair[2];
|
||||
int pid;
|
||||
int rc;
|
||||
|
||||
if(s->state != SSH_SOCKET_NONE)
|
||||
if (s->state != SSH_SOCKET_NONE) {
|
||||
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) {
|
||||
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);
|
||||
pid = fork();
|
||||
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(out_pipe[0]);
|
||||
SSH_LOG(SSH_LOG_PROTOCOL,"ProxyCommand connection pipe: [%d,%d]",in_pipe[0],out_pipe[1]);
|
||||
ssh_socket_set_fd_in(s,in_pipe[0]);
|
||||
ssh_socket_set_fd_out(s,out_pipe[1]);
|
||||
close(pair[0]);
|
||||
SSH_LOG(SSH_LOG_PROTOCOL,"ProxyCommand connection pipe: [%d,%d]",pair[0],pair[1]);
|
||||
ssh_socket_set_fd(s, pair[1]);
|
||||
s->state=SSH_SOCKET_CONNECTED;
|
||||
s->fd_is_socket=0;
|
||||
/* 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_out(s),POLLOUT);
|
||||
if(s->callbacks && s->callbacks->connected)
|
||||
ssh_poll_set_events(ssh_socket_get_poll_handle(s), POLLIN | POLLOUT);
|
||||
if(s->callbacks && s->callbacks->connected) {
|
||||
s->callbacks->connected(SSH_SOCKET_CONNECTED_OK,0,s->callbacks->userdata);
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
@@ -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_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_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
|
||||
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(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.
|
||||
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)
|
||||
|
||||
@@ -559,7 +559,7 @@ static void torture_auth_pubkey_types(void **state)
|
||||
rc = ssh_connect(session);
|
||||
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 */
|
||||
if (rc == SSH_ERROR) {
|
||||
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);
|
||||
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 */
|
||||
if (rc == SSH_ERROR) {
|
||||
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)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
@@ -634,7 +672,7 @@ static void torture_auth_pubkey_types_nonblocking(void **state)
|
||||
rc = ssh_connect(session);
|
||||
assert_ssh_return_code(session, rc);
|
||||
|
||||
ssh_set_blocking(session,0);
|
||||
ssh_set_blocking(session, 0);
|
||||
do {
|
||||
rc = ssh_userauth_none(session, NULL);
|
||||
} while (rc == SSH_AUTH_AGAIN);
|
||||
@@ -681,7 +719,7 @@ static void torture_auth_pubkey_types_ecdsa_nonblocking(void **state)
|
||||
rc = ssh_connect(session);
|
||||
assert_ssh_return_code(session, rc);
|
||||
|
||||
ssh_set_blocking(session,0);
|
||||
ssh_set_blocking(session, 0);
|
||||
do {
|
||||
rc = ssh_userauth_none(session, NULL);
|
||||
} while (rc == SSH_AUTH_AGAIN);
|
||||
@@ -704,7 +742,7 @@ static void torture_auth_pubkey_types_ecdsa_nonblocking(void **state)
|
||||
} while (rc == SSH_AUTH_AGAIN);
|
||||
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,
|
||||
"ecdsa-sha2-nistp256");
|
||||
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 rc;
|
||||
@@ -771,6 +855,12 @@ int torture_run_tests(void) {
|
||||
cmocka_unit_test_setup_teardown(torture_auth_pubkey_types_ecdsa_nonblocking,
|
||||
pubkey_setup,
|
||||
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();
|
||||
|
||||
@@ -167,6 +167,10 @@ static void torture_knownhosts_precheck(void **state)
|
||||
"127.0.0.10 %s\n",
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
assert_non_null(it);
|
||||
@@ -190,6 +194,13 @@ static void torture_knownhosts_precheck(void **state)
|
||||
algo = ssh_iterator_value(const char *, it);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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_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_COVERAGE_COMMAND NAMES gcov)
|
||||
|
||||
8
tests/keys/id_ed25519
Normal file
8
tests/keys/id_ed25519
Normal file
@@ -0,0 +1,8 @@
|
||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||
QyNTUxOQAAACCLo6vx1lX6ZZoe05lWTkuwrJUZN0T8hEer5UF9KPhOVgAAAKg+IRNSPiET
|
||||
UgAAAAtzc2gtZWQyNTUxOQAAACCLo6vx1lX6ZZoe05lWTkuwrJUZN0T8hEer5UF9KPhOVg
|
||||
AAAED2zFg52qYItoZaSUnir4VKubTxJveL9D2oWK7Prg/O24ujq/HWVfplmh7TmVZOS7Cs
|
||||
lRk3RPyER6vlQX0o+E5WAAAAHmpqZWxlbkB0NDcwcy5qamVsZW4ucmVkaGF0LmNvbQECAw
|
||||
QFBgc=
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
1
tests/keys/id_ed25519.pub
Normal file
1
tests/keys/id_ed25519.pub
Normal file
@@ -0,0 +1 @@
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIujq/HWVfplmh7TmVZOS7CslRk3RPyER6vlQX0o+E5W jjelen@t470s.jjelen.redhat.com
|
||||
@@ -42,18 +42,24 @@ static int setup_knownhosts_file(void **state)
|
||||
|
||||
nwritten = fwrite(LOCALHOST_PATTERN_ED25519,
|
||||
sizeof(char),
|
||||
sizeof(LOCALHOST_PATTERN_ED25519),
|
||||
strlen(LOCALHOST_PATTERN_ED25519),
|
||||
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);
|
||||
return -1;
|
||||
}
|
||||
|
||||
nwritten = fwrite(LOCALHOST_RSA_LINE,
|
||||
sizeof(char),
|
||||
sizeof(LOCALHOST_RSA_LINE),
|
||||
strlen(LOCALHOST_RSA_LINE),
|
||||
fp);
|
||||
if (nwritten != sizeof(LOCALHOST_RSA_LINE)) {
|
||||
if (nwritten != strlen(LOCALHOST_RSA_LINE)) {
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
@@ -210,6 +216,8 @@ static void torture_knownhosts_read_file(void **state)
|
||||
const char *knownhosts_file = *state;
|
||||
struct ssh_list *entry_list = NULL;
|
||||
struct ssh_iterator *it = NULL;
|
||||
struct ssh_knownhosts_entry *entry = NULL;
|
||||
enum ssh_keytypes_e type;
|
||||
int rc;
|
||||
|
||||
rc = ssh_known_hosts_read_entries("localhost",
|
||||
@@ -219,22 +227,27 @@ static void torture_knownhosts_read_file(void **state)
|
||||
assert_non_null(entry_list);
|
||||
it = ssh_list_get_iterator(entry_list);
|
||||
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);
|
||||
assert_non_null(entry);
|
||||
/* First key in known hosts file is ED25519 */
|
||||
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_ED25519);
|
||||
}
|
||||
assert_string_equal(entry->hostname, "localhost");
|
||||
type = ssh_key_type(entry->publickey);
|
||||
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);
|
||||
for (;it != NULL; it = it->next) {
|
||||
struct ssh_knownhosts_entry *entry = NULL;
|
||||
|
||||
entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
|
||||
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_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);
|
||||
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
|
||||
@@ -264,6 +279,89 @@ static void torture_knownhosts_host_exists(void **state)
|
||||
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 rc;
|
||||
struct CMUnitTest tests[] = {
|
||||
@@ -279,6 +377,15 @@ int torture_run_tests(void) {
|
||||
cmocka_unit_test_setup_teardown(torture_knownhosts_host_exists,
|
||||
setup_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();
|
||||
|
||||
@@ -346,6 +346,76 @@ static void torture_options_get_identity(void **state) {
|
||||
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) {
|
||||
ssh_session session = *state;
|
||||
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_set_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_set_ciphers, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_options_set_key_exchange, setup, teardown),
|
||||
|
||||
@@ -104,8 +104,7 @@ static void torture_packet(const char *cipher,
|
||||
|
||||
assert_non_null(session->out_buffer);
|
||||
ssh_buffer_add_data(session->out_buffer, test_data, payload_len);
|
||||
session->socket->fd_out = sockets[0];
|
||||
session->socket->fd_in = -2;
|
||||
session->socket->fd = sockets[0];
|
||||
session->socket->write_wontblock = 1;
|
||||
rc = ssh_packet_send(session);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
@@ -126,8 +125,7 @@ static void torture_packet(const char *cipher,
|
||||
}
|
||||
close(sockets[0]);
|
||||
close(sockets[1]);
|
||||
session->socket->fd_in = SSH_INVALID_SOCKET;
|
||||
session->socket->fd_out = SSH_INVALID_SOCKET;
|
||||
session->socket->fd = SSH_INVALID_SOCKET;
|
||||
ssh_free(session);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user