diff --git a/Changelog.rst b/Changelog.rst index de267bd5..c372b394 100644 --- a/Changelog.rst +++ b/Changelog.rst @@ -1,6 +1,13 @@ Change Log ============= +0.7.0 ++++++ + +Changes +------- + +* Updated embedded libssh to ``0.9.5``. 0.6.0 +++++ diff --git a/_setup_libssh.py b/_setup_libssh.py index 928f53c5..7114ead1 100644 --- a/_setup_libssh.py +++ b/_setup_libssh.py @@ -16,12 +16,19 @@ def build_ssh(): if not os.path.exists('src'): os.mkdir('src') + if not os.path.exists('local'): + os.mkdir('local') + if not os.path.exists('local/lib'): + os.mkdir('local/lib') + # Depending on architecture cmake installs libraries into lib64, + # but we don't care about that. + os.symlink('lib', 'local/lib64') os.chdir('src') - check_call('cmake -DCMAKE_BUILD_TYPE=Release -DWITH_GSS_API=ON ../libssh', + check_call('cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../local -DWITH_GSS_API=ON ../libssh', shell=True, env=os.environ) - check_call(['make', '-j%s' % (cpu_count(),)]) + check_call(['make', '-j%s' % (cpu_count(),), 'all', 'install']) os.chdir('..') - for src in glob('src/lib/libssh.so*'): + for src in glob('local/lib/libssh.so*'): copy2(src, 'ssh/') diff --git a/ci/appveyor/build_ssh.bat b/ci/appveyor/build_ssh.bat index aabc1245..58ffda9a 100755 --- a/ci/appveyor/build_ssh.bat +++ b/ci/appveyor/build_ssh.bat @@ -17,5 +17,6 @@ cp %OPENSSL_DIR%\lib\VC\libcrypto%PYTHON_ARCH%MD.lib %APPVEYOR_BUILD_FOLDER% cp %OPENSSL_DIR%\lib\VC\libssl%PYTHON_ARCH%MD.lib %APPVEYOR_BUILD_FOLDER% cmake --build . --config Release +cmake --install . --prefix ../local cd .. diff --git a/ci/docker/manylinux/Dockerfile b/ci/docker/manylinux/Dockerfile index bb85559d..abe49dc3 100644 --- a/ci/docker/manylinux/Dockerfile +++ b/ci/docker/manylinux/Dockerfile @@ -1,7 +1,7 @@ FROM quay.io/pypa/manylinux2010_x86_64 ENV OPENSSL openssl-1.0.2p -ENV LIBSSH 0.9.4 +ENV LIBSSH 0.9.5 ENV SYSTEM_LIBSSH 1 RUN yum install zlib-devel cmake3 -y diff --git a/ci/docker/manylinux/libssh-0.9.4.tar.xz b/ci/docker/manylinux/libssh-0.9.4.tar.xz deleted file mode 100644 index 8c8bed03..00000000 Binary files a/ci/docker/manylinux/libssh-0.9.4.tar.xz and /dev/null differ diff --git a/ci/docker/manylinux/libssh-0.9.5.tar.xz b/ci/docker/manylinux/libssh-0.9.5.tar.xz new file mode 100644 index 00000000..5a1a02c6 Binary files /dev/null and b/ci/docker/manylinux/libssh-0.9.5.tar.xz differ diff --git a/ci/docker/manylinux/libssh-0.9.5.tar.xz.asc b/ci/docker/manylinux/libssh-0.9.5.tar.xz.asc new file mode 100644 index 00000000..bf12d8af --- /dev/null +++ b/ci/docker/manylinux/libssh-0.9.5.tar.xz.asc @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNATURE----- + +iQIzBAABCgAdFiEEjf9T4Y8qvI2PPJIjfuD8TcwBTj0FAl9aH9kACgkQfuD8TcwB +Tj35ZA/9G7lNf/byK3cJeXKb8Lp2oZ3iiAral4uT/cylnXnEa7dOoTjwV5MYvQqm +BDYFta7wsGBEWLOLrtyDJr4+krh9TSs53UVwieRTd0Z87MlcTb+a0gtiJa3Y5Gdv +QNge9rnUGr1MdTwvpPcSvQmoa7iH9HGzC2KrOCCyihUWX9kB+DNKWeSGJAZLNIJv +C3DvB8N0di/X5f74loRsAkwA6DAfiRtd8QyuqY7NeP3ZK/cEG5R/4WpCmCHCriBI +oBamKQT2CmNkHGCxMhN5iQFcm3D92lKdTLrMP+v0HlZnIjkzVJVBJeqn7FkWT967 +JvGqDGEiNozH4eGGjQn5SyHaVCQIv5S815L2mEKG+p0F8BvW6fQs34/RA5np3J2s +SPSFhzKuORePQzoVzF8/Jsf7cTTuzgaSFKi2dkbgkqe39DnKOWhT0K6QVGfNbajz +C/a9GVRl7t6Q/kNR6dFAqc++7civlfQf2Dav1NfEobJxR+DpO5CPXBCuauTXgP8Y +gbvQjfBqk2Gl4VOfCObtEfLiHPNeLI/QpKq9+KAtQlWFawCOhIZsBH/p2ynDI+XJ +wxfLiXPkfeNuQUUuP126mkG9GxbsHGLY38p4WKEQQ3zVx1Pxilq77ZhKGMmTgnvA +/ArOwn3wNwgoP6OQdsy1hxTk16TZ+pRttJyhrdebEX7DnxAgPyw= +=eqzl +-----END PGP SIGNATURE----- diff --git a/libssh/CMakeLists.txt b/libssh/CMakeLists.txt index 41976ff2..1f5b0bf5 100644 --- a/libssh/CMakeLists.txt +++ b/libssh/CMakeLists.txt @@ -10,7 +10,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules") include(DefineCMakeDefaults) include(DefineCompilerFlags) -project(libssh VERSION 0.9.4 LANGUAGES C) +project(libssh VERSION 0.9.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.8.5") +set(LIBRARY_VERSION "4.8.6") set(LIBRARY_SOVERSION "4") # where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked diff --git a/libssh/ChangeLog b/libssh/ChangeLog index e8bc19db..3431d837 100644 --- a/libssh/ChangeLog +++ b/libssh/ChangeLog @@ -1,6 +1,17 @@ ChangeLog ========== +version 0.9.5 (released 2020-XX-XX) + * CVE-2020-16135: Avoid null pointer dereference in sftpserver (T232) + * Improve handling of library initialization (T222) + * Fix parsing of subsecond times in SFTP (T219) + * Make the documentation reproducible + * Remove deprecated API usage in OpenSSL + * Fix regression of ssh_channel_poll_timeout() returning SSH_AGAIN + * Define version in one place (T226) + * Prevent invalid free when using different C runtimes than OpenSSL (T229) + * Compatibility improvements to testsuite + version 0.9.4 (released 2020-04-09) * Fixed CVE-2020-1730 - Possible DoS in client and server when handling AES-CTR keys with OpenSSL diff --git a/libssh/doc/CMakeLists.txt b/libssh/doc/CMakeLists.txt index 8a666491..259424b4 100644 --- a/libssh/doc/CMakeLists.txt +++ b/libssh/doc/CMakeLists.txt @@ -13,6 +13,7 @@ if (DOXYGEN_FOUND) set(DOXYGEN_TAB_SIZE 4) set(DOXYGEN_OPTIMIZE_OUTPUT_FOR_C YES) set(DOXYGEN_MARKDOWN_SUPPORT YES) + set(DOXYGEN_FULL_PATH_NAMES NO) set(DOXYGEN_PREDEFINED DOXYGEN WITH_SERVER diff --git a/libssh/examples/CMakeLists.txt b/libssh/examples/CMakeLists.txt index 70a296c6..5e0c2ce9 100644 --- a/libssh/examples/CMakeLists.txt +++ b/libssh/examples/CMakeLists.txt @@ -6,7 +6,7 @@ set(examples_SRCS connect_ssh.c ) -include_directories(${libssh_BINARY_DIR}) +include_directories(${libssh_BINARY_DIR}/include ${libssh_BINARY_DIR}) if (ARGP_INCLUDE_DIR) include_directories(${ARGP_INCLUDE_DIR}) diff --git a/libssh/examples/exec.c b/libssh/examples/exec.c index 4d5e0c1a..7200ddef 100644 --- a/libssh/examples/exec.c +++ b/libssh/examples/exec.c @@ -8,7 +8,7 @@ int main(void) { ssh_session session; ssh_channel channel; char buffer[256]; - int nbytes; + int rbytes, wbytes, total = 0; int rc; session = connect_ssh("localhost", NULL, 0); @@ -35,15 +35,30 @@ int main(void) { goto failed; } - nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0); - while (nbytes > 0) { - if (fwrite(buffer, 1, nbytes, stdout) != (unsigned int) nbytes) { + rbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0); + if (rbytes <= 0) { + goto failed; + } + + do { + wbytes = fwrite(buffer + total, 1, rbytes, stdout); + if (wbytes <= 0) { goto failed; } - nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0); - } - if (nbytes < 0) { + total += wbytes; + + /* When it was not possible to write the whole buffer to stdout */ + if (wbytes < rbytes) { + rbytes -= wbytes; + continue; + } + + rbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0); + total = 0; + } while (rbytes > 0); + + if (rbytes < 0) { goto failed; } diff --git a/libssh/examples/sshd_direct-tcpip.c b/libssh/examples/sshd_direct-tcpip.c index 36a15a5b..35898880 100644 --- a/libssh/examples/sshd_direct-tcpip.c +++ b/libssh/examples/sshd_direct-tcpip.c @@ -27,6 +27,8 @@ clients must be made or how a client should react. #ifdef HAVE_ARGP_H #include #endif +#include +#include #include #include #include @@ -79,7 +81,10 @@ static struct cleanup_node_struct *cleanup_stack = NULL; static void _close_socket(struct event_fd_data_struct event_fd_data); -static void cleanup_push(struct cleanup_node_struct** head_ref, struct event_fd_data_struct *new_data) { +static void +cleanup_push(struct cleanup_node_struct** head_ref, + struct event_fd_data_struct *new_data) +{ // Allocate memory for node struct cleanup_node_struct *new_node = malloc(sizeof *new_node); @@ -92,7 +97,9 @@ static void cleanup_push(struct cleanup_node_struct** head_ref, struct event_fd_ (*head_ref) = new_node; } -static void do_cleanup(struct cleanup_node_struct **head_ref) { +static void +do_cleanup(struct cleanup_node_struct **head_ref) +{ struct cleanup_node_struct *current = (*head_ref); struct cleanup_node_struct *previous = NULL, *gone = NULL; @@ -131,16 +138,22 @@ static void do_cleanup(struct cleanup_node_struct **head_ref) { } } -static int auth_password(ssh_session session, const char *user, - const char *password, void *userdata) { - (void)userdata; - _ssh_log(SSH_LOG_PROTOCOL, "=== auth_password", "Authenticating user %s pwd %s",user, password); - if (strcmp(user,USER) == 0 && strcmp(password, PASSWORD) == 0){ +static int +auth_password(ssh_session session, + const char *user, + const char *password, + UNUSED_PARAM(void *userdata)) +{ + _ssh_log(SSH_LOG_PROTOCOL, + "=== auth_password", "Authenticating user %s pwd %s", + user, + password); + if (strcmp(user, USER) == 0 && strcmp(password, PASSWORD) == 0) { authenticated = true; printf("Authenticated\n"); return SSH_AUTH_SUCCESS; } - if (tries >= 3){ + if (tries >= 3) { printf("Too many authentication tries\n"); ssh_disconnect(session); error_set = true; @@ -150,25 +163,34 @@ static int auth_password(ssh_session session, const char *user, return SSH_AUTH_DENIED; } -static int auth_gssapi_mic(ssh_session session, const char *user, const char *principal, void *userdata) { +static int +auth_gssapi_mic(ssh_session session, + const char *user, + const char *principal, + UNUSED_PARAM(void *userdata)) +{ ssh_gssapi_creds creds = ssh_gssapi_get_creds(session); - (void)userdata; - printf("Authenticating user %s with gssapi principal %s\n", user, principal); - if (creds != NULL) + printf("Authenticating user %s with gssapi principal %s\n", + user, principal); + if (creds != NULL) { printf("Received some gssapi credentials\n"); - else + } else { printf("Not received any forwardable creds\n"); + } printf("authenticated\n"); authenticated = true; return SSH_AUTH_SUCCESS; } -static int subsystem_request(ssh_session session, ssh_channel channel, const char *subsystem, void *userdata) { - (void)session; - (void)channel; - //(void)subsystem; - (void)userdata; - _ssh_log(SSH_LOG_PROTOCOL, "=== subsystem_request", "Channel subsystem reqeuest: %s", subsystem); +static int +subsystem_request(UNUSED_PARAM(ssh_session session), + UNUSED_PARAM(ssh_channel channel), + const char *subsystem, + UNUSED_PARAM(void *userdata)) +{ + _ssh_log(SSH_LOG_PROTOCOL, + "=== subsystem_request", "Channel subsystem reqeuest: %s", + subsystem); return 0; } @@ -176,9 +198,10 @@ struct ssh_channel_callbacks_struct channel_cb = { .channel_subsystem_request_function = subsystem_request }; -static ssh_channel new_session_channel(ssh_session session, void *userdata) { - (void)session; - (void)userdata; +static ssh_channel +new_session_channel(UNUSED_PARAM(ssh_session session), + UNUSED_PARAM(void *userdata)) +{ _ssh_log(SSH_LOG_PROTOCOL, "=== subsystem_request", "Session channel request"); /* For TCP forward only there seems to be no need for a session channel */ /*if(chan != NULL) @@ -191,18 +214,25 @@ static ssh_channel new_session_channel(ssh_session session, void *userdata) { return NULL; } -static void stack_socket_close(UNUSED_PARAM(ssh_session session), - struct event_fd_data_struct *event_fd_data) +static void +stack_socket_close(UNUSED_PARAM(ssh_session session), + struct event_fd_data_struct *event_fd_data) { if (event_fd_data->stacked != 1) { - _ssh_log(SSH_LOG_FUNCTIONS, "=== stack_socket_close", "Closing fd = %d sockets_cnt = %d", *event_fd_data->p_fd, sockets_cnt); + _ssh_log(SSH_LOG_FUNCTIONS, "=== stack_socket_close", + "Closing fd = %d sockets_cnt = %d", *event_fd_data->p_fd, + sockets_cnt); event_fd_data->stacked = 1; cleanup_push(&cleanup_stack, event_fd_data); } } -static void _close_socket(struct event_fd_data_struct event_fd_data) { - _ssh_log(SSH_LOG_FUNCTIONS, "=== close_socket", "Closing fd = %d sockets_cnt = %d", *event_fd_data.p_fd, sockets_cnt); +static void +_close_socket(struct event_fd_data_struct event_fd_data) +{ + _ssh_log(SSH_LOG_FUNCTIONS, "=== close_socket", + "Closing fd = %d sockets_cnt = %d", *event_fd_data.p_fd, + sockets_cnt); ssh_event_remove_fd(mainloop, *event_fd_data.p_fd); sockets_cnt--; #ifdef _WIN32 @@ -213,23 +243,31 @@ static void _close_socket(struct event_fd_data_struct event_fd_data) { (*event_fd_data.p_fd) = SSH_INVALID_SOCKET; } -static int service_request(ssh_session session, const char *service, void *userdata) { - (void)session; - //(void)service; - (void)userdata; +static int +service_request(UNUSED_PARAM(ssh_session session), + const char *service, + UNUSED_PARAM(void *userdata)) +{ _ssh_log(SSH_LOG_PROTOCOL, "=== service_request", "Service request: %s", service); return 0; } -static void global_request(ssh_session session, ssh_message message, void *userdata) { - (void)session; - (void)userdata; - _ssh_log(SSH_LOG_PROTOCOL, "=== global_request", "Global request, message type: %d", ssh_message_type(message)); +static void +global_request(UNUSED_PARAM(ssh_session session), + ssh_message message, + UNUSED_PARAM(void *userdata)) +{ + _ssh_log(SSH_LOG_PROTOCOL, + "=== global_request", "Global request, message type: %d", + ssh_message_type(message)); } -static void my_channel_close_function(ssh_session session, ssh_channel channel, void *userdata) { +static void +my_channel_close_function(ssh_session session, + UNUSED_PARAM(ssh_channel channel), + void *userdata) +{ struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata; - (void)session; _ssh_log(SSH_LOG_PROTOCOL, "=== my_channel_close_function", @@ -238,9 +276,12 @@ static void my_channel_close_function(ssh_session session, ssh_channel channel, stack_socket_close(session, event_fd_data); } -static void my_channel_eof_function(ssh_session session, ssh_channel channel, void *userdata) { +static void +my_channel_eof_function(ssh_session session, + UNUSED_PARAM(ssh_channel channel), + void *userdata) +{ struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata; - (void)session; _ssh_log(SSH_LOG_PROTOCOL, "=== my_channel_eof_function", @@ -250,9 +291,13 @@ static void my_channel_eof_function(ssh_session session, ssh_channel channel, vo stack_socket_close(session, event_fd_data); } -static void my_channel_exit_status_function(ssh_session session, ssh_channel channel, int exit_status, void *userdata) { +static void +my_channel_exit_status_function(UNUSED_PARAM(ssh_session session), + UNUSED_PARAM(ssh_channel channel), + int exit_status, + void *userdata) +{ struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata; - (void)session; _ssh_log(SSH_LOG_PROTOCOL, "=== my_channel_exit_status_function", @@ -260,12 +305,13 @@ static void my_channel_exit_status_function(ssh_session session, ssh_channel cha exit_status, *event_fd_data->p_fd); } -static int my_channel_data_function(ssh_session session, - ssh_channel channel, - void *data, - uint32_t len, - UNUSED_PARAM(int is_stderr), - void *userdata) +static int +my_channel_data_function(ssh_session session, + UNUSED_PARAM(ssh_channel channel), + void *data, + uint32_t len, + UNUSED_PARAM(int is_stderr), + void *userdata) { int i = 0; struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata; @@ -283,7 +329,9 @@ static int my_channel_data_function(ssh_session session, i = send(*event_fd_data->p_fd, data, len, 0); } if (i < 0) { - _ssh_log(SSH_LOG_WARNING, "=== my_channel_data_function", "Writing to tcp socket %d: %s", *event_fd_data->p_fd, strerror(errno)); + _ssh_log(SSH_LOG_WARNING, "=== my_channel_data_function", + "Writing to tcp socket %d: %s", *event_fd_data->p_fd, + strerror(errno)); stack_socket_close(session, event_fd_data); } else { @@ -292,9 +340,10 @@ static int my_channel_data_function(ssh_session session, return i; } -static int my_fd_data_function(UNUSED_PARAM(socket_t fd), - int revents, - void *userdata) +static int +my_fd_data_function(UNUSED_PARAM(socket_t fd), + int revents, + void *userdata) { struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata; ssh_channel channel = event_fd_data->channel; @@ -387,7 +436,9 @@ static int my_fd_data_function(UNUSED_PARAM(socket_t fd), return len; } -static int open_tcp_socket(ssh_message msg) { +static int +open_tcp_socket(ssh_message msg) +{ struct sockaddr_in sin; int forwardsock = -1; struct hostent *host; @@ -428,17 +479,20 @@ static int open_tcp_socket(ssh_message msg) { return forwardsock; } -static int message_callback(ssh_session session, ssh_message message, void *userdata) { +static int +message_callback(UNUSED_PARAM(ssh_session session), + ssh_message message, + UNUSED_PARAM(void *userdata)) +{ ssh_channel channel; int socket_fd, *pFd; struct ssh_channel_callbacks_struct *cb_chan; struct event_fd_data_struct *event_fd_data; - (void)session; - (void)message; - (void)userdata; - _ssh_log(SSH_LOG_PACKET, "=== message_callback", "Message type: %d", ssh_message_type(message)); - _ssh_log(SSH_LOG_PACKET, "=== message_callback", "Message Subtype: %d", ssh_message_subtype(message)); + _ssh_log(SSH_LOG_PACKET, "=== message_callback", "Message type: %d", + ssh_message_type(message)); + _ssh_log(SSH_LOG_PACKET, "=== message_callback", "Message Subtype: %d", + ssh_message_subtype(message)); if (ssh_message_type(message) == SSH_REQUEST_CHANNEL_OPEN) { _ssh_log(SSH_LOG_PROTOCOL, "=== message_callback", "channel_request_open"); @@ -542,7 +596,9 @@ static struct argp_option options[] = { }; /* Parse a single option. */ -static error_t parse_opt (int key, char *arg, struct argp_state *state) { +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ /* Get the input argument from argp_parse, which we * know is a pointer to our arguments structure. */ @@ -588,7 +644,9 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) { static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL}; #endif /* HAVE_ARGP_H */ -int main(int argc, char **argv){ +int +main(int argc, char **argv) +{ ssh_session session; ssh_bind sshbind; struct ssh_server_callbacks_struct cb = { diff --git a/libssh/include/libssh/CMakeLists.txt b/libssh/include/libssh/CMakeLists.txt index acc966e3..83e7b9f8 100644 --- a/libssh/include/libssh/CMakeLists.txt +++ b/libssh/include/libssh/CMakeLists.txt @@ -31,3 +31,9 @@ install( headers ) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libssh_version.h.cmake + ${libssh_BINARY_DIR}/include/libssh/libssh_version.h + @ONLY) +install(FILES ${libssh_BINARY_DIR}/include/libssh/libssh_version.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${APPLICATION_NAME} + COMPONENT headers) diff --git a/libssh/include/libssh/libssh.h b/libssh/include/libssh/libssh.h index 79030131..d0776686 100644 --- a/libssh/include/libssh/libssh.h +++ b/libssh/include/libssh/libssh.h @@ -21,6 +21,8 @@ #ifndef _LIBSSH_H #define _LIBSSH_H +#include + #if defined _WIN32 || defined __CYGWIN__ #ifdef LIBSSH_STATIC #define LIBSSH_API @@ -71,23 +73,6 @@ #define SSH_STRINGIFY(s) SSH_TOSTRING(s) #define SSH_TOSTRING(s) #s -/* libssh version macros */ -#define SSH_VERSION_INT(a, b, c) ((a) << 16 | (b) << 8 | (c)) -#define SSH_VERSION_DOT(a, b, c) a ##.## b ##.## c -#define SSH_VERSION(a, b, c) SSH_VERSION_DOT(a, b, c) - -/* libssh version */ -#define LIBSSH_VERSION_MAJOR 0 -#define LIBSSH_VERSION_MINOR 9 -#define LIBSSH_VERSION_MICRO 3 - -#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \ - LIBSSH_VERSION_MINOR, \ - LIBSSH_VERSION_MICRO) -#define LIBSSH_VERSION SSH_VERSION(LIBSSH_VERSION_MAJOR, \ - LIBSSH_VERSION_MINOR, \ - LIBSSH_VERSION_MICRO) - /* GCC have printf type attribute check. */ #ifdef __GNUC__ #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b))) diff --git a/libssh/include/libssh/libssh_version.h.cmake b/libssh/include/libssh/libssh_version.h.cmake new file mode 100644 index 00000000..464fa14d --- /dev/null +++ b/libssh/include/libssh/libssh_version.h.cmake @@ -0,0 +1,41 @@ +/* + * This file is part of the SSH Library + * + * Copyright (c) 2020 by Heiko Thiery + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _LIBSSH_VERSION_H +#define _LIBSSH_VERSION_H + +/* libssh version macros */ +#define SSH_VERSION_INT(a, b, c) ((a) << 16 | (b) << 8 | (c)) +#define SSH_VERSION_DOT(a, b, c) a ##.## b ##.## c +#define SSH_VERSION(a, b, c) SSH_VERSION_DOT(a, b, c) + +/* libssh version */ +#define LIBSSH_VERSION_MAJOR @libssh_VERSION_MAJOR@ +#define LIBSSH_VERSION_MINOR @libssh_VERSION_MINOR@ +#define LIBSSH_VERSION_MICRO @libssh_VERSION_PATCH@ + +#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \ + LIBSSH_VERSION_MINOR, \ + LIBSSH_VERSION_MICRO) +#define LIBSSH_VERSION SSH_VERSION(LIBSSH_VERSION_MAJOR, \ + LIBSSH_VERSION_MINOR, \ + LIBSSH_VERSION_MICRO) + +#endif /* _LIBSSH_VERSION_H */ diff --git a/libssh/include/libssh/priv.h b/libssh/include/libssh/priv.h index 31405d6b..3e910860 100644 --- a/libssh/include/libssh/priv.h +++ b/libssh/include/libssh/priv.h @@ -32,6 +32,7 @@ #include #include #include +#include #if !defined(HAVE_STRTOULL) # if defined(HAVE___STRTOULL) @@ -423,4 +424,6 @@ void explicit_bzero(void *s, size_t n); void ssh_agent_state_free(void *data); +bool is_ssh_initialized(void); + #endif /* _LIBSSH_PRIV_H */ diff --git a/libssh/src/ABI/current b/libssh/src/ABI/current index dc24a896..c0f6eef2 100644 --- a/libssh/src/ABI/current +++ b/libssh/src/ABI/current @@ -1 +1 @@ -4.8.5 \ No newline at end of file +4.8.6 \ No newline at end of file diff --git a/libssh/src/CMakeLists.txt b/libssh/src/CMakeLists.txt index 532cc14d..ccf5a337 100644 --- a/libssh/src/CMakeLists.txt +++ b/libssh/src/CMakeLists.txt @@ -1,6 +1,7 @@ set(LIBSSH_PUBLIC_INCLUDE_DIRS ${libssh_SOURCE_DIR}/include) set(LIBSSH_PRIVATE_INCLUDE_DIRS + ${libssh_BINARY_DIR}/include ${libssh_BINARY_DIR} ) @@ -362,6 +363,7 @@ endif (WITH_VISIBILITY_HIDDEN) if (MINGW) set_target_properties(ssh PROPERTIES LINK_FLAGS "-Wl,--enable-stdcall-fixup") + set_target_properties(ssh PROPERTIES COMPILE_FLAGS "-D_POSIX_SOURCE") endif () diff --git a/libssh/src/buffer.c b/libssh/src/buffer.c index a2e6246a..ce12f491 100644 --- a/libssh/src/buffer.c +++ b/libssh/src/buffer.c @@ -299,28 +299,33 @@ int ssh_buffer_reinit(struct ssh_buffer_struct *buffer) */ int ssh_buffer_add_data(struct ssh_buffer_struct *buffer, const void *data, uint32_t len) { - buffer_verify(buffer); + if (buffer == NULL) { + return -1; + } - if (data == NULL) { - return -1; - } + buffer_verify(buffer); - if (buffer->used + len < len) { - return -1; - } + if (data == NULL) { + return -1; + } - if (buffer->allocated < (buffer->used + len)) { - if(buffer->pos > 0) - buffer_shift(buffer); - if (realloc_buffer(buffer, buffer->used + len) < 0) { - return -1; + if (buffer->used + len < len) { + return -1; } - } - memcpy(buffer->data+buffer->used, data, len); - buffer->used+=len; - buffer_verify(buffer); - return 0; + if (buffer->allocated < (buffer->used + len)) { + if (buffer->pos > 0) { + buffer_shift(buffer); + } + if (realloc_buffer(buffer, buffer->used + len) < 0) { + return -1; + } + } + + memcpy(buffer->data + buffer->used, data, len); + buffer->used += len; + buffer_verify(buffer); + return 0; } /** diff --git a/libssh/src/channels.c b/libssh/src/channels.c index 05dcf8f6..4eea885b 100644 --- a/libssh/src/channels.c +++ b/libssh/src/channels.c @@ -2932,15 +2932,16 @@ int ssh_channel_read_timeout(ssh_channel channel, if (session->session_state == SSH_SESSION_STATE_ERROR) { return SSH_ERROR; } + /* If the server closed the channel properly, there is nothing to do */ + if (channel->remote_eof && ssh_buffer_get_len(stdbuf) == 0) { + return 0; + } if (channel->state == SSH_CHANNEL_STATE_CLOSED) { ssh_set_error(session, SSH_FATAL, "Remote channel is closed."); return SSH_ERROR; } - if (channel->remote_eof && ssh_buffer_get_len(stdbuf) == 0) { - return 0; - } len = ssh_buffer_get_len(stdbuf); /* Read count bytes if len is greater, everything otherwise */ len = (len > count ? count : len); @@ -3095,7 +3096,7 @@ int ssh_channel_poll_timeout(ssh_channel channel, int timeout, int is_stderr) size_t len; int rc; - if(channel == NULL) { + if (channel == NULL) { return SSH_ERROR; } @@ -3113,9 +3114,15 @@ int ssh_channel_poll_timeout(ssh_channel channel, int timeout, int is_stderr) ssh_channel_read_termination, &ctx); if (rc == SSH_ERROR || - session->session_state == SSH_SESSION_STATE_ERROR) { + session->session_state == SSH_SESSION_STATE_ERROR) { rc = SSH_ERROR; goto out; + } else if (rc == SSH_AGAIN) { + /* If the above timeout expired, it is ok and we do not need to + * attempt to check the read buffer. The calling functions do not + * expect us to return SSH_AGAIN either here. */ + rc = SSH_OK; + goto out; } len = ssh_buffer_get_len(stdbuf); if (len > 0) { diff --git a/libssh/src/client.c b/libssh/src/client.c index ae170b93..4610b787 100644 --- a/libssh/src/client.c +++ b/libssh/src/client.c @@ -451,7 +451,7 @@ static void ssh_client_connection_callback(ssh_session session) if (dh_handshake(session) == SSH_ERROR) { goto error; } - /* FALL THROUGH */ + FALL_THROUGH; case SSH_SESSION_STATE_DH: if(session->dh_handshake_state==DH_STATE_FINISHED){ set_status(session,1.0f); @@ -505,119 +505,138 @@ static int ssh_connect_termination(void *user){ * @see ssh_new() * @see ssh_disconnect() */ -int ssh_connect(ssh_session session) { - int ret; +int ssh_connect(ssh_session session) +{ + int ret; - if (session == NULL) { - return SSH_ERROR; - } + if (!is_ssh_initialized()) { + ssh_set_error(session, SSH_FATAL, + "Library not initialized."); - switch(session->pending_call_state){ - case SSH_PENDING_CALL_NONE: - break; - case SSH_PENDING_CALL_CONNECT: - goto pending; - default: - ssh_set_error(session,SSH_FATAL,"Bad call during pending SSH call in ssh_connect"); + return SSH_ERROR; + } - return SSH_ERROR; - } - session->alive = 0; - session->client = 1; + if (session == NULL) { + return SSH_ERROR; + } - if (session->opts.fd == SSH_INVALID_SOCKET && - session->opts.host == NULL && - session->opts.ProxyCommand == NULL) { - ssh_set_error(session, SSH_FATAL, "Hostname required"); - return SSH_ERROR; - } + switch(session->pending_call_state) { + case SSH_PENDING_CALL_NONE: + break; + case SSH_PENDING_CALL_CONNECT: + goto pending; + default: + ssh_set_error(session, SSH_FATAL, + "Bad call during pending SSH call in ssh_connect"); - /* If the system configuration files were not yet processed, do it now */ - if (!session->opts.config_processed) { - ret = ssh_options_parse_config(session, NULL); - if (ret != 0) { - ssh_set_error(session, SSH_FATAL, - "Failed to process system configuration files"); - return SSH_ERROR; + return SSH_ERROR; } - } + session->alive = 0; + session->client = 1; - ret = ssh_options_apply(session); - if (ret < 0) { - ssh_set_error(session, SSH_FATAL, "Couldn't apply options"); - return SSH_ERROR; - } + if (session->opts.fd == SSH_INVALID_SOCKET && + session->opts.host == NULL && + session->opts.ProxyCommand == NULL) + { + ssh_set_error(session, SSH_FATAL, "Hostname required"); + return SSH_ERROR; + } + + /* If the system configuration files were not yet processed, do it now */ + if (!session->opts.config_processed) { + ret = ssh_options_parse_config(session, NULL); + if (ret != 0) { + ssh_set_error(session, SSH_FATAL, + "Failed to process system configuration files"); + return SSH_ERROR; + } + } + + ret = ssh_options_apply(session); + if (ret < 0) { + ssh_set_error(session, SSH_FATAL, "Couldn't apply options"); + return SSH_ERROR; + } - SSH_LOG(SSH_LOG_PROTOCOL, - "libssh %s, using threading %s", - ssh_copyright(), - ssh_threads_get_type()); - - session->ssh_connection_callback = ssh_client_connection_callback; - session->session_state=SSH_SESSION_STATE_CONNECTING; - ssh_socket_set_callbacks(session->socket,&session->socket_callbacks); - session->socket_callbacks.connected=socket_callback_connected; - session->socket_callbacks.data=callback_receive_banner; - session->socket_callbacks.exception=ssh_socket_exception_callback; - session->socket_callbacks.userdata=session; - if (session->opts.fd != SSH_INVALID_SOCKET) { - session->session_state=SSH_SESSION_STATE_SOCKET_CONNECTED; - ssh_socket_set_fd(session->socket, session->opts.fd); - ret=SSH_OK; + SSH_LOG(SSH_LOG_PROTOCOL, + "libssh %s, using threading %s", + ssh_copyright(), + ssh_threads_get_type()); + + session->ssh_connection_callback = ssh_client_connection_callback; + session->session_state = SSH_SESSION_STATE_CONNECTING; + ssh_socket_set_callbacks(session->socket, &session->socket_callbacks); + session->socket_callbacks.connected = socket_callback_connected; + session->socket_callbacks.data = callback_receive_banner; + session->socket_callbacks.exception = ssh_socket_exception_callback; + session->socket_callbacks.userdata = session; + + if (session->opts.fd != SSH_INVALID_SOCKET) { + session->session_state = SSH_SESSION_STATE_SOCKET_CONNECTED; + ssh_socket_set_fd(session->socket, session->opts.fd); + ret = SSH_OK; #ifndef _WIN32 - } else if (session->opts.ProxyCommand != NULL){ - ret = ssh_socket_connect_proxycommand(session->socket, - session->opts.ProxyCommand); + } else if (session->opts.ProxyCommand != NULL) { + ret = ssh_socket_connect_proxycommand(session->socket, + session->opts.ProxyCommand); #endif - } else { - ret=ssh_socket_connect(session->socket, - session->opts.host, - session->opts.port > 0 ? session->opts.port : 22, - session->opts.bindaddr); - } - if (ret == SSH_ERROR) { - return SSH_ERROR; - } + } else { + ret = ssh_socket_connect(session->socket, + session->opts.host, + session->opts.port > 0 ? session->opts.port : 22, + session->opts.bindaddr); + } + if (ret == SSH_ERROR) { + return SSH_ERROR; + } + + set_status(session, 0.2f); - set_status(session, 0.2f); + session->alive = 1; + SSH_LOG(SSH_LOG_PROTOCOL, + "Socket connecting, now waiting for the callbacks to work"); - session->alive = 1; - SSH_LOG(SSH_LOG_PROTOCOL,"Socket connecting, now waiting for the callbacks to work"); pending: - session->pending_call_state=SSH_PENDING_CALL_CONNECT; - if(ssh_is_blocking(session)) { - int timeout = (session->opts.timeout * 1000) + - (session->opts.timeout_usec / 1000); - if (timeout == 0) { - timeout = 10 * 1000; - } - SSH_LOG(SSH_LOG_PACKET,"Actual timeout : %d", timeout); - ret = ssh_handle_packets_termination(session, timeout, ssh_connect_termination, session); - if (session->session_state != SSH_SESSION_STATE_ERROR && - (ret == SSH_ERROR || !ssh_connect_termination(session))) { - ssh_set_error(session, SSH_FATAL, - "Timeout connecting to %s", session->opts.host); - session->session_state = SSH_SESSION_STATE_ERROR; - } - } - else { - ret = ssh_handle_packets_termination(session, - SSH_TIMEOUT_NONBLOCKING, - ssh_connect_termination, - session); - if (ret == SSH_ERROR) { - session->session_state = SSH_SESSION_STATE_ERROR; - } - } - SSH_LOG(SSH_LOG_PACKET,"current state : %d",session->session_state); - if(!ssh_is_blocking(session) && !ssh_connect_termination(session)){ - return SSH_AGAIN; - } + session->pending_call_state = SSH_PENDING_CALL_CONNECT; + if(ssh_is_blocking(session)) { + int timeout = (session->opts.timeout * 1000) + + (session->opts.timeout_usec / 1000); + if (timeout == 0) { + timeout = 10 * 1000; + } + SSH_LOG(SSH_LOG_PACKET, "Actual timeout : %d", timeout); + ret = ssh_handle_packets_termination(session, timeout, + ssh_connect_termination, session); + if (session->session_state != SSH_SESSION_STATE_ERROR && + (ret == SSH_ERROR || !ssh_connect_termination(session))) + { + ssh_set_error(session, SSH_FATAL, + "Timeout connecting to %s", session->opts.host); + session->session_state = SSH_SESSION_STATE_ERROR; + } + } else { + ret = ssh_handle_packets_termination(session, + SSH_TIMEOUT_NONBLOCKING, + ssh_connect_termination, + session); + if (ret == SSH_ERROR) { + session->session_state = SSH_SESSION_STATE_ERROR; + } + } + + SSH_LOG(SSH_LOG_PACKET, "current state : %d", session->session_state); + if (!ssh_is_blocking(session) && !ssh_connect_termination(session)) { + return SSH_AGAIN; + } + + session->pending_call_state = SSH_PENDING_CALL_NONE; + if (session->session_state == SSH_SESSION_STATE_ERROR || + session->session_state == SSH_SESSION_STATE_DISCONNECTED) + { + return SSH_ERROR; + } - session->pending_call_state=SSH_PENDING_CALL_NONE; - if(session->session_state == SSH_SESSION_STATE_ERROR || session->session_state == SSH_SESSION_STATE_DISCONNECTED) - return SSH_ERROR; - return SSH_OK; + return SSH_OK; } /** diff --git a/libssh/src/external/bcrypt_pbkdf.c b/libssh/src/external/bcrypt_pbkdf.c index 6fb35ff7..2208654d 100644 --- a/libssh/src/external/bcrypt_pbkdf.c +++ b/libssh/src/external/bcrypt_pbkdf.c @@ -87,7 +87,7 @@ bcrypt_hash(uint8_t *sha2pass, uint8_t *sha2salt, uint8_t *out) cdata[i] = Blowfish_stream2word(ciphertext, sizeof(ciphertext), &j); for (i = 0; i < 64; i++) - ssh_blf_enc(&state, cdata, sizeof(cdata) / sizeof(uint64_t)); + ssh_blf_enc(&state, cdata, BCRYPT_BLOCKS/2); /* copy out */ for (i = 0; i < BCRYPT_BLOCKS; i++) { diff --git a/libssh/src/init.c b/libssh/src/init.c index 9e70bf65..2ebcedf6 100644 --- a/libssh/src/init.c +++ b/libssh/src/init.c @@ -135,14 +135,20 @@ void libssh_constructor(void) /** * @brief Initialize global cryptographic data structures. * - * Since version 0.8.0, it is not necessary to call this function on systems - * which are fully supported with regards to threading (that is, system with - * pthreads available). + * Since version 0.8.0, when libssh is dynamically linked, it is not necessary + * to call this function on systems which are fully supported with regards to + * threading (that is, system with pthreads available). + * + * If libssh is statically linked, it is necessary to explicitly call ssh_init() + * before calling any other provided API, and it is necessary to explicitly call + * ssh_finalize() to free the allocated resources before exiting. * * If the library is already initialized, increments the _ssh_initialized * counter and return the error code cached in _ssh_init_ret. * * @returns SSH_OK on success, SSH_ERROR if an error occurred. + * + * @see ssh_finalize() */ int ssh_init(void) { return _ssh_init(0); @@ -202,8 +208,13 @@ void libssh_destructor(void) /** * @brief Finalize and cleanup all libssh and cryptographic data structures. * - * Since version 0.8.0, it is not necessary to call this function, since it is - * automatically called when the library is unloaded. + * Since version 0.8.0, when libssh is dynamically linked, it is not necessary + * to call this function, since it is automatically called when the library is + * unloaded. + * + * If libssh is statically linked, it is necessary to explicitly call ssh_init() + * before calling any other provided API, and it is necessary to explicitly call + * ssh_finalize() to free the allocated resources before exiting. * * If ssh_init() is called explicitly, then ssh_finalize() must be called * explicitly. @@ -211,9 +222,9 @@ void libssh_destructor(void) * When called, decrements the counter _ssh_initialized. If the counter reaches * zero, then the libssh and cryptographic data structures are cleaned up. * - * @returns 0 on succes, -1 if an error occured. + * @returns 0 on success, -1 if an error occurred. * - @returns 0 otherwise + * @see ssh_init() */ int ssh_finalize(void) { return _ssh_finalize(0); @@ -250,4 +261,23 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, #endif /* _WIN32 */ +/** + * @internal + * @brief Return whether the library is initialized + * + * @returns true if the library is initialized; false otherwise. + * + * @see ssh_init() + */ +bool is_ssh_initialized() { + + bool is_initialized = false; + + ssh_mutex_lock(&ssh_init_mutex); + is_initialized = _ssh_initialized > 0; + ssh_mutex_unlock(&ssh_init_mutex); + + return is_initialized; +} + /** @} */ diff --git a/libssh/src/libcrypto-compat.c b/libssh/src/libcrypto-compat.c index 048d1781..01ca70e7 100644 --- a/libssh/src/libcrypto-compat.c +++ b/libssh/src/libcrypto-compat.c @@ -280,6 +280,12 @@ void EVP_MD_CTX_free(EVP_MD_CTX *ctx) OPENSSL_free(ctx); } +int EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *ctx) +{ + EVP_CIPHER_CTX_init(ctx); + return 1; +} + HMAC_CTX *HMAC_CTX_new(void) { HMAC_CTX *ctx = OPENSSL_zalloc(sizeof(HMAC_CTX)); @@ -394,3 +400,12 @@ int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) } return 1; } + +const char *OpenSSL_version(int type) +{ + return SSLeay_version(type); +} +unsigned long OpenSSL_version_num(void) +{ + return SSLeay(); +} diff --git a/libssh/src/libcrypto-compat.h b/libssh/src/libcrypto-compat.h index bda0473e..0082e207 100644 --- a/libssh/src/libcrypto-compat.h +++ b/libssh/src/libcrypto-compat.h @@ -34,6 +34,8 @@ int EVP_MD_CTX_reset(EVP_MD_CTX *ctx); EVP_MD_CTX *EVP_MD_CTX_new(void); void EVP_MD_CTX_free(EVP_MD_CTX *ctx); +int EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *ctx); + HMAC_CTX *HMAC_CTX_new(void); int HMAC_CTX_reset(HMAC_CTX *ctx); void HMAC_CTX_free(HMAC_CTX *ctx); @@ -44,6 +46,10 @@ int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g); void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key); int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key); + +const char *OpenSSL_version(int type); +unsigned long OpenSSL_version_num(void); + #endif /* OPENSSL_VERSION_NUMBER */ #endif /* LIBCRYPTO_COMPAT_H */ diff --git a/libssh/src/libcrypto.c b/libssh/src/libcrypto.c index eefc98dd..8ff8a02b 100644 --- a/libssh/src/libcrypto.c +++ b/libssh/src/libcrypto.c @@ -536,7 +536,7 @@ static int evp_cipher_set_encrypt_key(struct ssh_cipher_struct *cipher, int rc; evp_cipher_init(cipher); - EVP_CIPHER_CTX_init(cipher->ctx); + EVP_CIPHER_CTX_reset(cipher->ctx); rc = EVP_EncryptInit_ex(cipher->ctx, cipher->cipher, NULL, key, IV); if (rc != 1){ @@ -569,7 +569,7 @@ static int evp_cipher_set_decrypt_key(struct ssh_cipher_struct *cipher, int rc; evp_cipher_init(cipher); - EVP_CIPHER_CTX_init(cipher->ctx); + EVP_CIPHER_CTX_reset(cipher->ctx); rc = EVP_DecryptInit_ex(cipher->ctx, cipher->cipher, NULL, key, IV); if (rc != 1){ @@ -652,7 +652,6 @@ static void evp_cipher_decrypt(struct ssh_cipher_struct *cipher, static void evp_cipher_cleanup(struct ssh_cipher_struct *cipher) { if (cipher->ctx != NULL) { - EVP_CIPHER_CTX_cleanup(cipher->ctx); EVP_CIPHER_CTX_free(cipher->ctx); } } @@ -1084,11 +1083,11 @@ int ssh_crypto_init(void) if (libcrypto_initialized) { return SSH_OK; } - if (SSLeay() != OPENSSL_VERSION_NUMBER){ + if (OpenSSL_version_num() != OPENSSL_VERSION_NUMBER){ SSH_LOG(SSH_LOG_WARNING, "libssh compiled with %s " "headers, currently running with %s.", OPENSSL_VERSION_TEXT, - SSLeay_version(SSLeay()) + OpenSSL_version(OpenSSL_version_num()) ); } #ifdef CAN_DISABLE_AESNI diff --git a/libssh/src/pki_crypto.c b/libssh/src/pki_crypto.c index 26d2da1d..67862a3e 100644 --- a/libssh/src/pki_crypto.c +++ b/libssh/src/pki_crypto.c @@ -1647,6 +1647,7 @@ static int pki_signature_from_dsa_blob(UNUSED_PARAM(const ssh_key pubkey), int raw_sig_len = 0; unsigned char *raw_sig_data = NULL; + unsigned char *temp_raw_sig = NULL; int rc; @@ -1705,8 +1706,23 @@ static int pki_signature_from_dsa_blob(UNUSED_PARAM(const ssh_key pubkey), ps = NULL; pr = NULL; - raw_sig_len = i2d_DSA_SIG(dsa_sig, &raw_sig_data); - if (raw_sig_len < 0) { + /* Get the expected size of the buffer */ + rc = i2d_DSA_SIG(dsa_sig, NULL); + if (rc <= 0) { + goto error; + } + raw_sig_len = rc; + + raw_sig_data = (unsigned char *)calloc(1, raw_sig_len); + if (raw_sig_data == NULL) { + goto error; + } + temp_raw_sig = raw_sig_data; + + /* It is necessary to use a temporary pointer as i2d_* "advances" the + * pointer */ + raw_sig_len = i2d_DSA_SIG(dsa_sig, &temp_raw_sig); + if (raw_sig_len <= 0) { goto error; } @@ -1750,6 +1766,7 @@ static int pki_signature_from_ecdsa_blob(UNUSED_PARAM(const ssh_key pubkey), uint32_t rlen; unsigned char *raw_sig_data = NULL; + unsigned char *temp_raw_sig = NULL; size_t raw_sig_len = 0; int rc; @@ -1825,12 +1842,26 @@ static int pki_signature_from_ecdsa_blob(UNUSED_PARAM(const ssh_key pubkey), pr = NULL; ps = NULL; - rc = i2d_ECDSA_SIG(ecdsa_sig, &raw_sig_data); - if (rc < 0) { + /* Get the expected size of the buffer */ + rc = i2d_ECDSA_SIG(ecdsa_sig, NULL); + if (rc <= 0) { goto error; } raw_sig_len = rc; + raw_sig_data = (unsigned char *)calloc(1, raw_sig_len); + if (raw_sig_data == NULL) { + goto error; + } + temp_raw_sig = raw_sig_data; + + /* It is necessary to use a temporary pointer as i2d_* "advances" the + * pointer */ + rc = i2d_ECDSA_SIG(ecdsa_sig, &temp_raw_sig); + if (rc <= 0) { + goto error; + } + sig->raw_sig = ssh_string_new(raw_sig_len); if (sig->raw_sig == NULL) { explicit_bzero(raw_sig_data, raw_sig_len); diff --git a/libssh/src/pki_ed25519_common.c b/libssh/src/pki_ed25519_common.c index 738825f5..9db14dac 100644 --- a/libssh/src/pki_ed25519_common.c +++ b/libssh/src/pki_ed25519_common.c @@ -112,7 +112,7 @@ int pki_ed25519_key_cmp(const ssh_key k1, if (cmp != 0) { return 1; } - /* FALL THROUGH */ + FALL_THROUGH; case SSH_KEY_CMP_PUBLIC: if (k1->ed25519_pubkey == NULL || k2->ed25519_pubkey == NULL) { return 1; diff --git a/libssh/src/session.c b/libssh/src/session.c index 3b3830f7..3199096a 100644 --- a/libssh/src/session.c +++ b/libssh/src/session.c @@ -689,7 +689,8 @@ int ssh_handle_packets(ssh_session session, int timeout) { * @param[in] fct Termination function to be used to determine if it is * possible to stop polling. * @param[in] user User parameter to be passed to fct termination function. - * @return SSH_OK on success, SSH_ERROR otherwise. + * @returns SSH_OK on success, SSH_AGAIN if timeout occurred, + * SSH_ERROR otherwise. */ int ssh_handle_packets_termination(ssh_session session, long timeout, diff --git a/libssh/src/sftp.c b/libssh/src/sftp.c index b64aad61..9a10b075 100644 --- a/libssh/src/sftp.c +++ b/libssh/src/sftp.c @@ -1173,13 +1173,13 @@ static sftp_attributes sftp_parse_attr_4(sftp_session sftp, ssh_buffer buf, break; } attr->atime64 = ntohll(attr->atime64); - } - if (flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) { - if (ssh_buffer_get_u32(buf, &attr->atime_nseconds) != 4) { - break; + if (flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) { + if (ssh_buffer_get_u32(buf, &attr->atime_nseconds) != 4) { + break; + } + attr->atime_nseconds = ntohl(attr->atime_nseconds); } - attr->atime_nseconds = ntohl(attr->atime_nseconds); } if (flags & SSH_FILEXFER_ATTR_CREATETIME) { @@ -1187,13 +1187,13 @@ static sftp_attributes sftp_parse_attr_4(sftp_session sftp, ssh_buffer buf, break; } attr->createtime = ntohll(attr->createtime); - } - if (flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) { - if (ssh_buffer_get_u32(buf, &attr->createtime_nseconds) != 4) { - break; + if (flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) { + if (ssh_buffer_get_u32(buf, &attr->createtime_nseconds) != 4) { + break; + } + attr->createtime_nseconds = ntohl(attr->createtime_nseconds); } - attr->createtime_nseconds = ntohl(attr->createtime_nseconds); } if (flags & SSH_FILEXFER_ATTR_MODIFYTIME) { @@ -1201,13 +1201,13 @@ static sftp_attributes sftp_parse_attr_4(sftp_session sftp, ssh_buffer buf, break; } attr->mtime64 = ntohll(attr->mtime64); - } - if (flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) { - if (ssh_buffer_get_u32(buf, &attr->mtime_nseconds) != 4) { - break; + if (flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) { + if (ssh_buffer_get_u32(buf, &attr->mtime_nseconds) != 4) { + break; + } + attr->mtime_nseconds = ntohl(attr->mtime_nseconds); } - attr->mtime_nseconds = ntohl(attr->mtime_nseconds); } if (flags & SSH_FILEXFER_ATTR_ACL) { diff --git a/libssh/src/sftpserver.c b/libssh/src/sftpserver.c index 5a2110e5..9117f155 100644 --- a/libssh/src/sftpserver.c +++ b/libssh/src/sftpserver.c @@ -67,9 +67,20 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) { /* take a copy of the whole packet */ msg->complete_message = ssh_buffer_new(); - ssh_buffer_add_data(msg->complete_message, - ssh_buffer_get(payload), - ssh_buffer_get_len(payload)); + if (msg->complete_message == NULL) { + ssh_set_error_oom(session); + sftp_client_message_free(msg); + return NULL; + } + + rc = ssh_buffer_add_data(msg->complete_message, + ssh_buffer_get(payload), + ssh_buffer_get_len(payload)); + if (rc < 0) { + ssh_set_error_oom(session); + sftp_client_message_free(msg); + return NULL; + } ssh_buffer_get_u32(payload, &msg->id); diff --git a/libssh/tests/CMakeLists.txt b/libssh/tests/CMakeLists.txt index 294038ef..75ff9b85 100644 --- a/libssh/tests/CMakeLists.txt +++ b/libssh/tests/CMakeLists.txt @@ -9,9 +9,11 @@ set(TORTURE_LIBRARY torture) include_directories(${OPENSSL_INCLUDE_DIR} ${CMOCKA_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} + ${libssh_BINARY_DIR}/include ${libssh_BINARY_DIR} ${libssh_SOURCE_DIR}/src - ${CMAKE_CURRENT_SOURCE_DIR}) + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_BINARY_DIR}/tests) set(TORTURE_LINK_LIBRARIES ${CMOCKA_LIBRARY} @@ -43,22 +45,96 @@ set(TEST_TARGET_LIBRARIES add_subdirectory(unittests) +# OpenSSH Capabilities are required for all unit tests +find_program(SSH_EXECUTABLE NAMES ssh) +if (SSH_EXECUTABLE) + execute_process(COMMAND ${SSH_EXECUTABLE} -V ERROR_VARIABLE OPENSSH_VERSION_STR) + string(REGEX REPLACE "^.*OpenSSH_([0-9]).[0-9].*$" "\\1" OPENSSH_VERSION_MAJOR "${OPENSSH_VERSION_STR}") + string(REGEX REPLACE "^.*OpenSSH_[0-9].([0-9]).*$" "\\1" OPENSSH_VERSION_MINOR "${OPENSSH_VERSION_STR}") + set(OPENSSH_VERSION "${OPENSSH_VERSION_MAJOR}.${OPENSSH_VERSION_MINOR}") + if("${OPENSSH_VERSION}" VERSION_LESS "6.3") + # ssh - Q was introduced in 6.3 + message("Version less than 6.3, hardcoding cipher list") + set(OPENSSH_CIPHERS "aes128-ctr\naes192-ctr\naes256-ctr\narcfour256\narcfour128\naes128-gcm@openssh.com\naes256-gcm@openssh.com\naes128-cbc\n3des-cbc\nblowfish-cbc\ncast128-cbc\naes192-cbc\naes256-cbc\narcfour\nrijndael-cbc@lysator.liu.se\n") + set(OPENSSH_MACS "hmac-md5-etm@openssh.com\nhmac-sha1-etm@openssh.com\numac-64-etm@openssh.com\numac-128-etm@openssh.com\nhmac-sha2-256-etm@openssh.com\nhmac-sha2-512-etm@openssh.com\nhmac-ripemd160-etm@openssh.com\nhmac-sha1-96-etm@openssh.com\nhmac-md5-96-etm@openssh.com\nhmac-md5\nhmac-sha1\numac-64@openssh.com\numac-128@openssh.com\nhmac-sha2-256\nhmac-sha2-512\nhmac-ripemd160\nhmac-ripemd160@openssh.com\nhmac-sha1-96\nhmac-md5-96\n") + set(OPENSSH_KEX "ecdh-sha2-nistp256\necdh-sha2-nistp384\necdh-sha2-nistp521\ndiffie-hellman-group-exchange-sha256\ndiffie-hellman-group-exchange-sha1\ndiffie-hellman-group14-sha1\ndiffie-hellman-group1-sha1\n") + set(OPENSSH_KEYS "ssh-rsa\nssh-dss\necdsa-sha2-nistp256\n") + else() + execute_process(COMMAND ${SSH_EXECUTABLE} -Q cipher OUTPUT_VARIABLE OPENSSH_CIPHERS) + execute_process(COMMAND ${SSH_EXECUTABLE} -Q mac OUTPUT_VARIABLE OPENSSH_MACS) + execute_process(COMMAND ${SSH_EXECUTABLE} -Q kex OUTPUT_VARIABLE OPENSSH_KEX) + execute_process(COMMAND ${SSH_EXECUTABLE} -Q key OUTPUT_VARIABLE OPENSSH_KEYS) + execute_process(COMMAND ${SSH_EXECUTABLE} -Q sig OUTPUT_VARIABLE OPENSSH_SIGS ERROR_QUIET) + + # We need both of them, but lets get rid of duplicate items presented in both lists + # to avoid processing too long arguments in pkd + set(OPENSSH_KEYS "${OPENSSH_KEYS}${OPENSSH_SIGS}") + string(REPLACE "\n" ";" OPENSSH_KEYS "${OPENSSH_KEYS}") + list(REMOVE_DUPLICATES OPENSSH_KEYS) + string(REPLACE ";" "\n" OPENSSH_KEYS "${OPENSSH_KEYS}") + endif() + + set(SSH_ALGORITHMS + 3des-cbc aes128-cbc aes192-cbc aes256-cbc rijndael-cbc@lysator.liu.se aes128-ctr aes192-ctr + aes256-ctr aes128-gcm@openssh.com aes256-gcm@openssh.com chacha20-poly1305@openssh.com + hmac-sha1 hmac-sha1-96 hmac-sha2-256 hmac-sha2-512 hmac-md5 hmac-md5-96 umac-64@openssh.com + umac-128@openssh.com hmac-sha1-etm@openssh.com hmac-sha1-96-etm@openssh.com + hmac-sha2-256-etm@openssh.com hmac-sha2-512-etm@openssh.com hmac-md5-etm@openssh.com + hmac-md5-96-etm@openssh.com umac-64-etm@openssh.com umac-128-etm@openssh.com + diffie-hellman-group1-sha1 diffie-hellman-group14-sha1 diffie-hellman-group14-sha256 + diffie-hellman-group16-sha512 diffie-hellman-group18-sha512 diffie-hellman-group-exchange-sha1 + diffie-hellman-group-exchange-sha256 ecdh-sha2-nistp256 ecdh-sha2-nistp384 ecdh-sha2-nistp521 + curve25519-sha256 curve25519-sha256@libssh.org + ssh-ed25519 ssh-ed25519-cert-v01@openssh.com ssh-rsa ssh-dss + ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521 + ssh-rsa-cert-v01@openssh.com ssh-dss-cert-v01@openssh.com + ecdsa-sha2-nistp256-cert-v01@openssh.com ecdsa-sha2-nistp384-cert-v01@openssh.com + ecdsa-sha2-nistp521-cert-v01@openssh.com + ) + foreach(ALGORITHM ${SSH_ALGORITHMS}) + string(TOUPPER ${ALGORITHM} VARNAME) + string(REGEX REPLACE "[-@.]" "_" VARNAME "OPENSSH_${VARNAME}") + + # Match the current algorithm into the complete list of OpenSSH supported algorithms. + # If matching, create an OPENSSH_CIPHER_NAME variable. + string(REGEX MATCH ".*${ALGORITHM}\n" "${VARNAME}" "${OPENSSH_CIPHERS}${OPENSSH_MACS}${OPENSSH_KEX}${OPENSSH_KEYS}") + endforeach(ALGORITHM) + + string(STRIP "${OPENSSH_CIPHERS}" OPENSSH_CIPHERS) + string(STRIP "${OPENSSH_MACS}" OPENSSH_MACS) + string(STRIP "${OPENSSH_KEX}" OPENSSH_KEX) + string(STRIP "${OPENSSH_KEYS}" OPENSSH_KEYS) + string(REPLACE "\n" "," OPENSSH_CIPHERS "${OPENSSH_CIPHERS}") + string(REPLACE "\n" "," OPENSSH_MACS "${OPENSSH_MACS}") + string(REPLACE "\n" "," OPENSSH_KEX "${OPENSSH_KEX}") + string(REPLACE "\n" "," OPENSSH_KEYS "${OPENSSH_KEYS}") + +endif() + +find_program(SSHD_EXECUTABLE + NAME + sshd + PATHS + /sbin + /usr/sbin + /usr/local/sbin) + if (CLIENT_TESTING OR SERVER_TESTING) find_package(socket_wrapper 1.1.5 REQUIRED) find_package(nss_wrapper 1.1.2 REQUIRED) find_package(uid_wrapper 1.2.0 REQUIRED) find_package(pam_wrapper 1.0.1 REQUIRED) - find_program(SSHD_EXECUTABLE - NAME - sshd - PATHS - /sbin - /usr/sbin - /usr/local/sbin) if (NOT SSHD_EXECUTABLE) message(SEND_ERROR "Could not find sshd which is required for client testing") endif() + find_program(NC_EXECUTABLE + NAME + nc + PATHS + /bin + /usr/bin + /usr/local/bin) find_program(SSH_EXECUTABLE NAMES ssh) if (SSH_EXECUTABLE) @@ -137,6 +213,8 @@ if (CLIENT_TESTING OR SERVER_TESTING) message(STATUS "TORTURE_ENVIRONMENT=${TORTURE_ENVIRONMENT}") endif () +configure_file(tests_config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/tests_config.h) + if (WITH_BENCHMARKS) add_subdirectory(benchmarks) endif () diff --git a/libssh/tests/client/torture_algorithms.c b/libssh/tests/client/torture_algorithms.c index 19f25dbb..729505ef 100644 --- a/libssh/tests/client/torture_algorithms.c +++ b/libssh/tests/client/torture_algorithms.c @@ -472,8 +472,7 @@ static void torture_algorithms_3des_cbc_hmac_sha2_512_etm(void **state) { test_algorithm(s->ssh.session, NULL/*kex*/, "3des-cbc", "hmac-sha2-512-etm@openssh.com"); } -#ifdef WITH_BLOWFISH_CIPHER -#if ((OPENSSH_VERSION_MAJOR == 7 && OPENSSH_VERSION_MINOR < 6) || OPENSSH_VERSION_MAJOR <= 6) +#if defined(WITH_BLOWFISH_CIPHER) && defined(OPENSSH_BLOWFISH_CBC) static void torture_algorithms_blowfish_cbc_hmac_sha1(void **state) { struct torture_state *s = *state; @@ -533,9 +532,9 @@ static void torture_algorithms_blowfish_cbc_hmac_sha2_512_etm(void **state) { test_algorithm(s->ssh.session, NULL/*kex*/, "blowfish-cbc", "hmac-sha2-512-etm@openssh.com"); } -#endif #endif /* WITH_BLOWFISH_CIPHER */ +#ifdef OPENSSH_CHACHA20_POLY1305_OPENSSH_COM static void torture_algorithms_chacha20_poly1305(void **state) { struct torture_state *s = *state; @@ -549,6 +548,7 @@ static void torture_algorithms_chacha20_poly1305(void **state) "chacha20-poly1305@openssh.com", NULL); } +#endif /* OPENSSH_CHACHA20_POLY1305_OPENSSH_COM */ static void torture_algorithms_zlib(void **state) { struct torture_state *s = *state; @@ -647,7 +647,7 @@ static void torture_algorithms_ecdh_sha2_nistp521(void **state) { } #endif -#if ((OPENSSH_VERSION_MAJOR == 7 && OPENSSH_VERSION_MINOR >= 3) || OPENSSH_VERSION_MAJOR > 7) +#ifdef OPENSSH_CURVE25519_SHA256 static void torture_algorithms_ecdh_curve25519_sha256(void **state) { struct torture_state *s = *state; @@ -657,9 +657,9 @@ static void torture_algorithms_ecdh_curve25519_sha256(void **state) { test_algorithm(s->ssh.session, "curve25519-sha256", NULL/*cipher*/, NULL/*hmac*/); } -#endif +#endif /* OPENSSH_CURVE25519_SHA256 */ -#if ((OPENSSH_VERSION_MAJOR == 6 && OPENSSH_VERSION_MINOR >= 5) || OPENSSH_VERSION_MAJOR > 6) +#ifdef OPENSSH_CURVE25519_SHA256_LIBSSH_ORG static void torture_algorithms_ecdh_curve25519_sha256_libssh_org(void **state) { struct torture_state *s = *state; @@ -669,7 +669,7 @@ static void torture_algorithms_ecdh_curve25519_sha256_libssh_org(void **state) { test_algorithm(s->ssh.session, "curve25519-sha256@libssh.org", NULL/*cipher*/, NULL/*hmac*/); } -#endif +#endif /* OPENSSH_CURVE25519_SHA256_LIBSSH_ORG */ static void torture_algorithms_dh_group1(void **state) { struct torture_state *s = *state; @@ -874,8 +874,7 @@ int torture_run_tests(void) { cmocka_unit_test_setup_teardown(torture_algorithms_3des_cbc_hmac_sha2_512_etm, session_setup, session_teardown), -#ifdef WITH_BLOWFISH_CIPHER -#if ((OPENSSH_VERSION_MAJOR == 7 && OPENSSH_VERSION_MINOR < 6) || OPENSSH_VERSION_MAJOR <= 6) +#if defined(WITH_BLOWFISH_CIPHER) && defined(OPENSSH_BLOWFISH_CBC) cmocka_unit_test_setup_teardown(torture_algorithms_blowfish_cbc_hmac_sha1, session_setup, session_teardown), @@ -894,11 +893,12 @@ int torture_run_tests(void) { cmocka_unit_test_setup_teardown(torture_algorithms_blowfish_cbc_hmac_sha2_512_etm, session_setup, session_teardown), -#endif #endif /* WITH_BLOWFISH_CIPHER */ +#ifdef OPENSSH_CHACHA20_POLY1305_OPENSSH_COM cmocka_unit_test_setup_teardown(torture_algorithms_chacha20_poly1305, session_setup, session_teardown), +#endif /* OPENSSH_CHACHA20_POLY1305_OPENSSH_COM */ cmocka_unit_test_setup_teardown(torture_algorithms_zlib, session_setup, session_teardown), @@ -928,16 +928,16 @@ int torture_run_tests(void) { session_setup, session_teardown), #endif /* WITH_GEX */ -#if ((OPENSSH_VERSION_MAJOR == 7 && OPENSSH_VERSION_MINOR >= 3) || OPENSSH_VERSION_MAJOR > 7) +#ifdef OPENSSH_CURVE25519_SHA256 cmocka_unit_test_setup_teardown(torture_algorithms_ecdh_curve25519_sha256, session_setup, session_teardown), -#endif -#if ((OPENSSH_VERSION_MAJOR == 6 && OPENSSH_VERSION_MINOR >= 5) || OPENSSH_VERSION_MAJOR > 6) +#endif /* OPENSSH_CURVE25519_SHA256 */ +#ifdef OPENSSH_CURVE25519_SHA256_LIBSSH_ORG cmocka_unit_test_setup_teardown(torture_algorithms_ecdh_curve25519_sha256_libssh_org, session_setup, session_teardown), -#endif +#endif /* OPENSSH_CURVE25519_SHA256_LIBSSH_ORG */ #if defined(HAVE_ECC) cmocka_unit_test_setup_teardown(torture_algorithms_ecdh_sha2_nistp256, session_setup, diff --git a/libssh/tests/client/torture_auth.c b/libssh/tests/client/torture_auth.c index 5a3d2e0d..4b97f5da 100644 --- a/libssh/tests/client/torture_auth.c +++ b/libssh/tests/client/torture_auth.c @@ -52,6 +52,7 @@ static int session_setup(void **state) { struct torture_state *s = *state; int verbosity = torture_libssh_verbosity(); + const char *all_keytypes = NULL; struct passwd *pwd; bool b = false; int rc; @@ -71,6 +72,11 @@ static int session_setup(void **state) rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_PROCESS_CONFIG, &b); assert_ssh_return_code(s->ssh.session, rc); + /* Enable all hostkeys */ + all_keytypes = ssh_kex_get_supported_method(SSH_HOSTKEYS); + rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES, all_keytypes); + assert_ssh_return_code(s->ssh.session, rc); + return 0; } diff --git a/libssh/tests/client/torture_connect.c b/libssh/tests/client/torture_connect.c index 0ad8ef55..f31f521f 100644 --- a/libssh/tests/client/torture_connect.c +++ b/libssh/tests/client/torture_connect.c @@ -183,6 +183,38 @@ static void torture_connect_socket(void **state) { assert_ssh_return_code(session, rc); } +static void torture_connect_uninitialized(UNUSED_PARAM(void **state)) +{ + int rc; + ssh_session session; + struct passwd *pwd; + + /* Make sure the library is unitialized */ + while (is_ssh_initialized()) { + rc = ssh_finalize(); + assert_return_code(rc, errno); + } + + pwd = getpwnam("bob"); + assert_non_null(pwd); + + rc = setuid(pwd->pw_uid); + assert_return_code(rc, errno); + + session = ssh_new(); + assert_non_null(session); + + rc = ssh_options_set(session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER); + assert_ssh_return_code(session, rc); + + /* Expect error from ssh_connect */ + rc = ssh_connect(session); + assert_false(rc == SSH_OK); + assert_string_equal(ssh_get_error(session), "Library not initialized."); + + ssh_free(session); +} + int torture_run_tests(void) { int rc; struct CMUnitTest tests[] = { @@ -193,6 +225,7 @@ int torture_run_tests(void) { cmocka_unit_test_setup_teardown(torture_connect_timeout, session_setup, session_teardown), #endif cmocka_unit_test_setup_teardown(torture_connect_socket, session_setup, session_teardown), + cmocka_unit_test(torture_connect_uninitialized), }; ssh_init(); diff --git a/libssh/tests/client/torture_knownhosts.c b/libssh/tests/client/torture_knownhosts.c index fcc54846..55aee217 100644 --- a/libssh/tests/client/torture_knownhosts.c +++ b/libssh/tests/client/torture_knownhosts.c @@ -307,6 +307,7 @@ static void torture_knownhosts_other_auto(void **state) { char tmp_file[1024] = {0}; char *known_hosts_file = NULL; int rc; + bool process_config = false; snprintf(tmp_file, sizeof(tmp_file), @@ -344,6 +345,9 @@ static void torture_knownhosts_other_auto(void **state) { s->ssh.session = session; + rc = ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &process_config); + assert_ssh_return_code(session, rc); + rc = ssh_options_set(session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER); assert_ssh_return_code(session, rc); @@ -368,6 +372,7 @@ static void torture_knownhosts_conflict(void **state) { char *known_hosts_file = NULL; FILE *file; int rc; + bool process_config = false; snprintf(tmp_file, sizeof(tmp_file), @@ -411,6 +416,9 @@ static void torture_knownhosts_conflict(void **state) { s->ssh.session = session; + rc = ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &process_config); + assert_ssh_return_code(session, rc); + ssh_options_set(session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER); ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file); rc = ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, "rsa-sha2-256"); diff --git a/libssh/tests/client/torture_proxycommand.c b/libssh/tests/client/torture_proxycommand.c index 77dd8ade..c04ff2ab 100644 --- a/libssh/tests/client/torture_proxycommand.c +++ b/libssh/tests/client/torture_proxycommand.c @@ -59,6 +59,7 @@ static int session_teardown(void **state) return 0; } +#ifdef NC_EXECUTABLE static void torture_options_set_proxycommand(void **state) { struct torture_state *s = *state; @@ -70,13 +71,13 @@ static void torture_options_set_proxycommand(void **state) int rc; socket_t fd; - rc = stat("/bin/nc", &sb); + rc = stat(NC_EXECUTABLE, &sb); if (rc != 0 || (sb.st_mode & S_IXOTH) == 0) { - SSH_LOG(SSH_LOG_WARNING, "Could not find /bin/nc: Skipping the test"); + SSH_LOG(SSH_LOG_WARNING, "Could not find " NC_EXECUTABLE ": Skipping the test"); skip(); } - rc = snprintf(command, sizeof(command), "/bin/nc %s %d", address, port); + rc = snprintf(command, sizeof(command), NC_EXECUTABLE " %s %d", address, port); assert_true((size_t)rc < sizeof(command)); rc = ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, command); @@ -89,6 +90,16 @@ static void torture_options_set_proxycommand(void **state) assert_int_equal(rc & O_RDWR, O_RDWR); } +#else /* NC_EXECUTABLE */ + +static void torture_options_set_proxycommand(void **state) +{ + (void) state; + skip(); +} + +#endif /* NC_EXECUTABLE */ + static void torture_options_set_proxycommand_notexist(void **state) { struct torture_state *s = *state; ssh_session session = s->ssh.session; diff --git a/libssh/tests/client/torture_rekey.c b/libssh/tests/client/torture_rekey.c index 7c9d8127..a70b39d6 100644 --- a/libssh/tests/client/torture_rekey.c +++ b/libssh/tests/client/torture_rekey.c @@ -283,7 +283,7 @@ static void torture_rekey_recv(void **state) memcpy(secret_hash, c->secret_hash, c->digest_len); /* Download a file */ - file = sftp_open(s->ssh.tsftp->sftp, "/usr/bin/ssh", O_RDONLY, 0); + file = sftp_open(s->ssh.tsftp->sftp, SSH_EXECUTABLE, O_RDONLY, 0); assert_non_null(file); mask = umask(S_IRWXO | S_IRWXG); @@ -473,7 +473,7 @@ static void torture_rekey_server_recv(void **state) memcpy(secret_hash, c->secret_hash, c->digest_len); /* Download a file */ - file = sftp_open(s->ssh.tsftp->sftp, "/usr/bin/ssh", O_RDONLY, 0); + file = sftp_open(s->ssh.tsftp->sftp, SSH_EXECUTABLE, O_RDONLY, 0); assert_non_null(file); mask = umask(S_IRWXO | S_IRWXG); diff --git a/libssh/tests/client/torture_scp.c b/libssh/tests/client/torture_scp.c index 8f080af3..59a00bae 100644 --- a/libssh/tests/client/torture_scp.c +++ b/libssh/tests/client/torture_scp.c @@ -37,6 +37,7 @@ #define BUF_SIZE 1024 #define TEMPLATE BINARYDIR "/tests/home/alice/temp_dir_XXXXXX" +#define ALICE_HOME BINARYDIR "/tests/home/alice" struct scp_st { struct torture_state *s; @@ -540,6 +541,86 @@ static void torture_scp_upload_newline(void **state) fclose(file); } +static void torture_scp_upload_appended_command(void **state) +{ + struct scp_st *ts = NULL; + struct torture_state *s = NULL; + + ssh_session session = NULL; + ssh_scp scp = NULL; + + FILE *file = NULL; + + char buf[1024]; + char *rs = NULL; + int rc; + + assert_non_null(state); + ts = *state; + + assert_non_null(ts->s); + s = ts->s; + + session = s->ssh.session; + assert_non_null(session); + + assert_non_null(ts->tmp_dir_basename); + assert_non_null(ts->tmp_dir); + + /* Upload a file path with a command appended */ + + /* Append a command to the file path */ + snprintf(buf, BUF_SIZE, "%s" + "/;touch hack", + ts->tmp_dir); + + /* When writing the file_name must be the directory name */ + scp = ssh_scp_new(session, SSH_SCP_WRITE | SSH_SCP_RECURSIVE, + buf); + assert_non_null(scp); + + rc = ssh_scp_init(scp); + assert_ssh_return_code(session, rc); + + /* Push directory where the new file will be copied */ + rc = ssh_scp_push_directory(scp, ";touch hack", 0755); + assert_ssh_return_code(session, rc); + + /* Try to push file */ + rc = ssh_scp_push_file(scp, "original", 8, 0644); + assert_ssh_return_code(session, rc); + + rc = ssh_scp_write(scp, "original", 8); + assert_ssh_return_code(session, rc); + + /* Leave the directory */ + rc = ssh_scp_leave_directory(scp); + assert_ssh_return_code(session, rc); + + /* Cleanup */ + ssh_scp_close(scp); + ssh_scp_free(scp); + + /* Make sure the command was not executed */ + snprintf(buf, BUF_SIZE, ALICE_HOME "/hack"); + file = fopen(buf, "r"); + assert_null(file); + + /* Open the file and check content */ + snprintf(buf, BUF_SIZE, "%s" + "/;touch hack/original", + ts->tmp_dir); + + file = fopen(buf, "r"); + assert_non_null(file); + + rs = fgets(buf, 1024, file); + assert_non_null(rs); + assert_string_equal(buf, "original"); + + fclose(file); +} + int torture_run_tests(void) { int rc; @@ -559,6 +640,9 @@ int torture_run_tests(void) cmocka_unit_test_setup_teardown(torture_scp_upload_newline, session_setup, session_teardown), + cmocka_unit_test_setup_teardown(torture_scp_upload_appended_command, + session_setup, + session_teardown), }; ssh_init(); diff --git a/libssh/tests/client/torture_sftp_read.c b/libssh/tests/client/torture_sftp_read.c index 2208fbae..687153eb 100644 --- a/libssh/tests/client/torture_sftp_read.c +++ b/libssh/tests/client/torture_sftp_read.c @@ -73,7 +73,7 @@ static void torture_sftp_read_blocking(void **state) { sftp_file file; mode_t mask; - file = sftp_open(t->sftp, "/usr/bin/ssh", O_RDONLY, 0); + file = sftp_open(t->sftp, SSH_EXECUTABLE, O_RDONLY, 0); assert_non_null(file); mask = umask(S_IRWXO | S_IRWXG); diff --git a/libssh/tests/pkd/CMakeLists.txt b/libssh/tests/pkd/CMakeLists.txt index 85a57775..9e550462 100644 --- a/libssh/tests/pkd/CMakeLists.txt +++ b/libssh/tests/pkd/CMakeLists.txt @@ -3,6 +3,7 @@ project(pkd C) if (WITH_SERVER AND UNIX AND NOT WIN32) include_directories(${libssh_SOURCE_DIR}/include + ${libssh_BINARY_DIR}/include ${CMOCKA_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} ${CMAKE_BINARY_DIR} diff --git a/libssh/tests/pkd/pkd_client.h b/libssh/tests/pkd/pkd_client.h index 474ca174..de42098b 100644 --- a/libssh/tests/pkd/pkd_client.h +++ b/libssh/tests/pkd/pkd_client.h @@ -9,42 +9,20 @@ #define __PKD_CLIENT_H__ #include "config.h" +#include "tests_config.h" /* OpenSSH */ -#define OPENSSH_BINARY "ssh" +#define OPENSSH_BINARY SSH_EXECUTABLE #define OPENSSH_KEYGEN "ssh-keygen" -#define OPENSSH_HOSTKEY_ALGOS_DEFAULT "ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa" -#define OPENSSH_PKACCEPTED_DEFAULT "ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa,ssh-rsa-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com" - -#if HAVE_ECC -#define OPENSSH_HOSTKEY_ALGOS_ECDSA ",ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521" -#define OPENSSH_PKACCEPTED_ECDSA ",ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com" -#else /* HAVE_ECC */ -#define OPENSSH_HOSTKEY_ALGOS_ECDSA "" -#define OPENSSH_PKACCEPTED_ECDSA "" -#endif /* HAVE_ECC */ - -#if HAVE_DSA -#define OPENSSH_HOSTKEY_ALGOS_DSA ",ssh-dss" -#define OPENSSH_PKACCEPTED_DSA ",ssh-dss,ssh-dss-cert-v01@openssh.com" -#else /* HAVE_DSA */ -#define OPENSSH_HOSTKEY_ALGOS_DSA "" -#define OPENSSH_PKACCEPTED_DSA "" -#endif /* HAVE_DSA */ - #define OPENSSH_HOSTKEY_ALGOS \ "-o HostKeyAlgorithms=" \ - OPENSSH_HOSTKEY_ALGOS_DEFAULT \ - OPENSSH_HOSTKEY_ALGOS_ECDSA \ - OPENSSH_HOSTKEY_ALGOS_DSA + OPENSSH_KEYS #define OPENSSH_PKACCEPTED_TYPES \ "-o PubkeyAcceptedKeyTypes=" \ - OPENSSH_PKACCEPTED_DEFAULT \ - OPENSSH_PKACCEPTED_ECDSA \ - OPENSSH_PKACCEPTED_DSA + OPENSSH_KEYS #define OPENSSH_CMD_START(hostkey_algos) \ OPENSSH_BINARY " " \ diff --git a/libssh/tests/pkd/pkd_hello.c b/libssh/tests/pkd/pkd_hello.c index 9ba45873..3a5768d7 100644 --- a/libssh/tests/pkd/pkd_hello.c +++ b/libssh/tests/pkd/pkd_hello.c @@ -610,7 +610,7 @@ static void torture_pkd_runtest(const char *testname, #define emit_keytest(client, testname, sshcmd, setup, teardown) \ static void torture_pkd_## client ## _ ## testname(void **state) { \ const char *tname = "torture_pkd_" #client "_" #testname; \ - char testcmd[1024] = { 0 }; \ + char testcmd[2048] = { 0 }; \ (void) state; \ snprintf(&testcmd[0], sizeof(testcmd), sshcmd, tname, tname); \ torture_pkd_runtest(tname, testcmd); \ diff --git a/libssh/tests/server/CMakeLists.txt b/libssh/tests/server/CMakeLists.txt index 9476ea91..ebe2d169 100644 --- a/libssh/tests/server/CMakeLists.txt +++ b/libssh/tests/server/CMakeLists.txt @@ -13,6 +13,7 @@ set(LIBSSH_SERVER_TESTS ) include_directories(${libssh_SOURCE_DIR}/include + ${libssh_BINARY_DIR}/include ${libssh_BINARY_DIR} test_server) diff --git a/libssh/tests/server/test_server/CMakeLists.txt b/libssh/tests/server/test_server/CMakeLists.txt index 10bf4b7d..fe5e7d09 100644 --- a/libssh/tests/server/test_server/CMakeLists.txt +++ b/libssh/tests/server/test_server/CMakeLists.txt @@ -17,6 +17,7 @@ set(LIBSSH_SERVER_TESTS ) include_directories(${libssh_SOURCE_DIR}/include + ${libssh_BINARY_DIR}/include ${libssh_BINARY_DIR}) if (ARGP_INCLUDE_DIR) diff --git a/libssh/tests/tests_config.h.cmake b/libssh/tests/tests_config.h.cmake new file mode 100644 index 00000000..38733844 --- /dev/null +++ b/libssh/tests/tests_config.h.cmake @@ -0,0 +1,69 @@ +/* OpenSSH capabilities */ + +#cmakedefine OPENSSH_VERSION_MAJOR ${OPENSSH_VERSION_MAJOR} +#cmakedefine OPENSSH_VERSION_MINOR ${OPENSSH_VERSION_MINOR} + +#cmakedefine OPENSSH_CIPHERS "${OPENSSH_CIPHERS}" +#cmakedefine OPENSSH_MACS "${OPENSSH_MACS}" +#cmakedefine OPENSSH_KEX "${OPENSSH_KEX}" +#cmakedefine OPENSSH_KEYS "${OPENSSH_KEYS}" + + +#cmakedefine OPENSSH_3DES_CBC 1 +#cmakedefine OPENSSH_AES128_CBC 1 +#cmakedefine OPENSSH_AES192_CBC 1 +#cmakedefine OPENSSH_AES256_CBC 1 +#cmakedefine OPENSSH_RIJNDAEL_CBC_LYSATOR_LIU_SE 1 +#cmakedefine OPENSSH_AES128_CTR 1 +#cmakedefine OPENSSH_AES192_CTR 1 +#cmakedefine OPENSSH_AES256_CTR 1 +#cmakedefine OPENSSH_AES128_GCM_OPENSSH_COM 1 +#cmakedefine OPENSSH_AES256_GCM_OPENSSH_COM 1 +#cmakedefine OPENSSH_CHACHA20_POLY1305_OPENSSH_COM 1 +#cmakedefine OPENSSH_BLOWFISH_CBC 1 +#cmakedefine OPENSSH_HMAC_SHA1 1 +#cmakedefine OPENSSH_HMAC_SHA1_96 1 +#cmakedefine OPENSSH_HMAC_SHA2_256 1 +#cmakedefine OPENSSH_HMAC_SHA2_512 1 +#cmakedefine OPENSSH_HMAC_MD5 1 +#cmakedefine OPENSSH_HMAC_MD5_96 1 +#cmakedefine OPENSSH_UMAC_64_OPENSSH_COM 1 +#cmakedefine OPENSSH_UMAC_128_OPENSSH_COM 1 +#cmakedefine OPENSSH_HMAC_SHA1_ETM_OPENSSH_COM 1 +#cmakedefine OPENSSH_HMAC_SHA1_96_ETM_OPENSSH_COM 1 +#cmakedefine OPENSSH_HMAC_SHA2_256_ETM_OPENSSH_COM 1 +#cmakedefine OPENSSH_HMAC_SHA2_512_ETM_OPENSSH_COM 1 +#cmakedefine OPENSSH_HMAC_MD5_ETM_OPENSSH_COM 1 +#cmakedefine OPENSSH_HMAC_MD5_96_ETM_OPENSSH_COM 1 +#cmakedefine OPENSSH_UMAC_64_ETM_OPENSSH_COM 1 +#cmakedefine OPENSSH_UMAC_128_ETM_OPENSSH_COM 1 +#cmakedefine OPENSSH_DIFFIE_HELLMAN_GROUP1_SHA1 1 +#cmakedefine OPENSSH_DIFFIE_HELLMAN_GROUP14_SHA1 1 +#cmakedefine OPENSSH_DIFFIE_HELLMAN_GROUP14_SHA256 1 +#cmakedefine OPENSSH_DIFFIE_HELLMAN_GROUP16_SHA512 1 +#cmakedefine OPENSSH_DIFFIE_HELLMAN_GROUP18_SHA512 1 +#cmakedefine OPENSSH_DIFFIE_HELLMAN_GROUP_EXCHANGE_SHA1 1 +#cmakedefine OPENSSH_DIFFIE_HELLMAN_GROUP_EXCHANGE_SHA256 1 +#cmakedefine OPENSSH_ECDH_SHA2_NISTP256 1 +#cmakedefine OPENSSH_ECDH_SHA2_NISTP384 1 +#cmakedefine OPENSSH_ECDH_SHA2_NISTP521 1 +#cmakedefine OPENSSH_CURVE25519_SHA256 1 +#cmakedefine OPENSSH_CURVE25519_SHA256_LIBSSH_ORG 1 +#cmakedefine OPENSSH_SSH_ED25519 1 +#cmakedefine OPENSSH_SSH_ED25519_CERT_V01_OPENSSH_COM 1 +#cmakedefine OPENSSH_SSH_RSA 1 +#cmakedefine OPENSSH_SSH_DSS 1 +#cmakedefine OPENSSH_ECDSA_SHA2_NISTP256 1 +#cmakedefine OPENSSH_ECDSA_SHA2_NISTP384 1 +#cmakedefine OPENSSH_ECDSA_SHA2_NISTP521 1 +#cmakedefine OPENSSH_SSH_RSA_CERT_V01_OPENSSH_COM 1 +#cmakedefine OPENSSH_SSH_DSS_CERT_V01_OPENSSH_COM 1 +#cmakedefine OPENSSH_ECDSA_SHA2_NISTP256_CERT_V01_OPENSSH_COM 1 +#cmakedefine OPENSSH_ECDSA_SHA2_NISTP384_CERT_V01_OPENSSH_COM 1 +#cmakedefine OPENSSH_ECDSA_SHA2_NISTP521_CERT_V01_OPENSSH_COM 1 + +/* Available programs */ + +#cmakedefine NC_EXECUTABLE "${NC_EXECUTABLE}" +#cmakedefine SSHD_EXECUTABLE "${SSHD_EXECUTABLE}" +#cmakedefine SSH_EXECUTABLE "${SSH_EXECUTABLE}" \ No newline at end of file diff --git a/libssh/tests/torture.c b/libssh/tests/torture.c index 907f45b3..7289a97f 100644 --- a/libssh/tests/torture.c +++ b/libssh/tests/torture.c @@ -22,7 +22,7 @@ */ #include "config.h" - +#include "tests_config.h" #include #include #include @@ -62,6 +62,10 @@ #define TORTURE_SSHD_CONFIG "sshd/sshd_config" #define TORTURE_PCAP_FILE "socket_trace.pcap" +#ifndef PATH_MAX +# define PATH_MAX 4096 +#endif + static const char torture_rsa_certauth_pub[]= "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCnA2n5vHzZbs/GvRkGloJNV1CXHI" "S5Xnrm05HusUJSWyPq3I1iCMHdYA7oezHa9GCFYbIenaYPy+G6USQRjYQz8SvAZo06" @@ -600,23 +604,20 @@ static void torture_setup_create_sshd_config(void **state, bool pam) struct stat sb; const char *sftp_server_locations[] = { "/usr/lib/ssh/sftp-server", + "/usr/libexec/ssh/sftp-server", /* Tumbleweed 20200829 */ "/usr/libexec/sftp-server", "/usr/libexec/openssh/sftp-server", "/usr/lib/openssh/sftp-server", /* Debian */ }; -#ifndef OPENSSH_VERSION_MAJOR -#define OPENSSH_VERSION_MAJOR 7U -#define OPENSSH_VERSION_MINOR 0U -#endif /* OPENSSH_VERSION_MAJOR */ const char config_string[]= "Port 22\n" "ListenAddress 127.0.0.10\n" - "%s %s\n" + "%s %s\n" /* ed25519 HostKey */ #ifdef HAVE_DSA - "%s %s\n" + "%s %s\n" /* DSA HostKey */ #endif /* HAVE_DSA */ - "%s %s\n" - "%s %s\n" + "%s %s\n" /* RSA HostKey */ + "%s %s\n" /* ECDSA HostKey */ "\n" "TrustedUserCAKeys %s\n" "\n" @@ -630,33 +631,14 @@ static void torture_setup_create_sshd_config(void **state, bool pam) "\n" "%s" /* Here comes UsePam */ "\n" -#if (OPENSSH_VERSION_MAJOR == 6 && OPENSSH_VERSION_MINOR >= 7) || (OPENSSH_VERSION_MAJOR >= 7) -# ifdef HAVE_DSA - "HostKeyAlgorithms +ssh-dss\n" -# else /* HAVE_DSA */ - "HostKeyAlgorithms +ssh-rsa\n" -# endif /* HAVE_DSA */ -# if (OPENSSH_VERSION_MAJOR == 7 && OPENSSH_VERSION_MINOR < 6) - "Ciphers +3des-cbc,aes128-cbc,aes192-cbc,aes256-cbc,blowfish-cbc\n" -# else /* OPENSSH_VERSION 7.0 - 7.5 */ - "Ciphers +3des-cbc,aes128-cbc,aes192-cbc,aes256-cbc\n" -# endif /* OPENSSH_VERSION 7.0 - 7.6 */ - "KexAlgorithms +diffie-hellman-group1-sha1," - "diffie-hellman-group-exchange-sha1" -#else /* OPENSSH_VERSION >= 6.7 */ - "Ciphers 3des-cbc,aes128-cbc,aes192-cbc,aes256-cbc,aes128-ctr," - "aes192-ctr,aes256-ctr,aes128-gcm@openssh.com," - "aes256-gcm@openssh.com,arcfour128,arcfour256,arcfour," - "blowfish-cbc,cast128-cbc,chacha20-poly1305@openssh.com\n" - "KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp256," - "ecdh-sha2-nistp384,ecdh-sha2-nistp521," - "diffie-hellman-group-exchange-sha256," - "diffie-hellman-group-exchange-sha1," - "diffie-hellman-group16-sha512," - "diffie-hellman-group18-sha512," - "diffie-hellman-group14-sha1," - "diffie-hellman-group1-sha1\n" -#endif /* OPENSSH_VERSION >= 6.7 */ + /* add all supported algorithms */ + "HostKeyAlgorithms " OPENSSH_KEYS "\n" +#if OPENSSH_VERSION_MAJOR == 8 && OPENSSH_VERSION_MINOR >= 2 + "CASignatureAlgorithms " OPENSSH_KEYS "\n" +#endif + "Ciphers " OPENSSH_CIPHERS "\n" + "KexAlgorithms " OPENSSH_KEX "\n" + "MACs " OPENSSH_MACS "\n" "\n" "AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES\n" "AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT\n" @@ -668,8 +650,8 @@ static void torture_setup_create_sshd_config(void **state, bool pam) const char fips_config_string[]= "Port 22\n" "ListenAddress 127.0.0.10\n" - "%s %s\n" /* HostKey */ - "%s %s\n" /* HostKey */ + "%s %s\n" /* RSA HostKey */ + "%s %s\n" /* ECDSA HostKey */ "\n" "TrustedUserCAKeys %s\n" /* Trusted CA */ "\n" @@ -867,7 +849,7 @@ void torture_setup_sshd_server(void **state, bool pam) s = *state; snprintf(sshd_start_cmd, sizeof(sshd_start_cmd), - "/usr/sbin/sshd -r -f %s -E %s/sshd/daemon.log 2> %s/sshd/cwrap.log", + SSHD_EXECUTABLE " -r -f %s -E %s/sshd/daemon.log 2> %s/sshd/cwrap.log", s->srv_config, s->socket_dir, s->socket_dir); rc = system(sshd_start_cmd); diff --git a/libssh/tests/torture.h b/libssh/tests/torture.h index 1cd52b20..a1dc6208 100644 --- a/libssh/tests/torture.h +++ b/libssh/tests/torture.h @@ -41,6 +41,7 @@ #include #include "torture_cmocka.h" +#include "tests_config.h" #ifndef assert_return_code /* hack for older versions of cmocka */ diff --git a/libssh/tests/unittests/torture_init.c b/libssh/tests/unittests/torture_init.c index 6a97a182..f719fc99 100644 --- a/libssh/tests/unittests/torture_init.c +++ b/libssh/tests/unittests/torture_init.c @@ -2,6 +2,7 @@ #define LIBSSH_STATIC +#include #include "torture.h" #include "libssh/libssh.h" @@ -32,11 +33,33 @@ static void torture_ssh_init_after_finalize(void **state) { assert_int_equal(rc, SSH_OK); } +static void torture_is_ssh_initialized(UNUSED_PARAM(void **state)) { + + int rc; + bool initialized = false; + + /* Make sure the library is not initialized */ + while (is_ssh_initialized()) { + rc = ssh_finalize(); + assert_return_code(rc, errno); + } + + rc = ssh_init(); + assert_return_code(rc, errno); + initialized = is_ssh_initialized(); + assert_true(initialized); + rc = ssh_finalize(); + assert_return_code(rc, errno); + initialized = is_ssh_initialized(); + assert_false(initialized); +} + int torture_run_tests(void) { int rc; struct CMUnitTest tests[] = { cmocka_unit_test(torture_ssh_init), cmocka_unit_test(torture_ssh_init_after_finalize), + cmocka_unit_test(torture_is_ssh_initialized), }; torture_filter_tests(tests); diff --git a/setup.py b/setup.py index f12fad58..0df44764 100644 --- a/setup.py +++ b/setup.py @@ -63,8 +63,8 @@ runtime_library_dirs = ["$ORIGIN/."] if not SYSTEM_LIBSSH else None -_lib_dir = os.path.abspath("./src/lib") if not SYSTEM_LIBSSH else "/usr/local/lib" -include_dirs = ["libssh/include"] if (ON_WINDOWS or ON_RTD) or \ +_lib_dir = os.path.abspath("./local/lib") if not SYSTEM_LIBSSH else "/usr/local/lib" +include_dirs = ["./local/include"] if (ON_WINDOWS or ON_RTD) or \ not SYSTEM_LIBSSH else ["/usr/local/include"] extensions = [ diff --git a/tests/test_channel.py b/tests/test_channel.py index 541f3e47..4d984f00 100644 --- a/tests/test_channel.py +++ b/tests/test_channel.py @@ -103,7 +103,6 @@ def test_channel_non_blocking_exec(self): break lines = [s.decode('utf-8') for s in all_data.splitlines()] self.assertEqual(lines[0], self.resp) - self.assertRaises(SSHError, chan.read) self.assertRaises(EOF, chan.poll) self.assertTrue(chan.is_eof()) rc = chan.close()