summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnderson Toshiyuki Sasaki <ansasaki@redhat.com>2018-07-02 13:03:12 +0200
committerAndreas Schneider <asn@cryptomilk.org>2018-08-03 16:43:03 +0200
commit83b43443e51b5db06184750fb874e1e8d7ece95a (patch)
tree9c81acc146ee9d0d129ab953a38e2363574fa888
parent6a077fe7509fb3141c0c63365a32208e42aa90f1 (diff)
downloadlibssh-83b43443e51b5db06184750fb874e1e8d7ece95a.tar.gz
libssh-83b43443e51b5db06184750fb874e1e8d7ece95a.tar.xz
libssh-83b43443e51b5db06184750fb874e1e8d7ece95a.zip
threads: Automatically call ssh_init on load
This makes unnecessary to call ssh_init() when the library is dynamically loaded. Also removes the threads shared library. The used threads implementation is chosen in configuration time, changing the ssh_threads_get_default() depending on the available threads library. Internally, it is expected a threads implementation providing: - void ssh_mutex_lock(void **mutex); - void ssh_mutex_unlock(void **mutex); - struct ssh_threads_callbacks_struct *ssh_threads_get_default(void); and a crypto implementation providing: - int crypto_thread_init(struct ssh_threads_callbacks_struct *user_callbacks); - void crypto_thread_finalize(void); This adds internal threads implementation for pthreads and noop. Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com> Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
-rw-r--r--CMakeLists.txt16
-rw-r--r--include/libssh/threads.h25
-rw-r--r--src/CMakeLists.txt19
-rw-r--r--src/init.c182
-rw-r--r--src/threads.c222
-rw-r--r--src/threads/CMakeLists.txt132
-rw-r--r--src/threads/libcrypto.c125
-rw-r--r--src/threads/libgcrypt.c74
-rw-r--r--src/threads/mbedtls.c65
-rw-r--r--src/threads/noop.c74
-rw-r--r--src/threads/pthread.c139
-rw-r--r--tests/CMakeLists.txt7
-rw-r--r--tests/fuzz/CMakeLists.txt4
-rw-r--r--tests/pkd/CMakeLists.txt3
-rw-r--r--tests/unittests/CMakeLists.txt5
15 files changed, 662 insertions, 430 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fa0678de..c6223715 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -69,6 +69,7 @@ endif(WITH_GCRYPT)
# Find out if we have threading available
set(CMAKE_THREAD_PREFER_PTHREADS ON)
+set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads)
if (WITH_GSSAPI)
@@ -101,30 +102,15 @@ configure_file(libssh.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libssh.pc)
install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/libssh.pc
- ${CMAKE_CURRENT_BINARY_DIR}/libssh_threads.pc
DESTINATION
${LIB_INSTALL_DIR}/pkgconfig
COMPONENT
pkgconfig
)
-
- if (LIBSSH_THREADS)
- configure_file(libssh_threads.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libssh_threads.pc)
- install(
- FILES
- ${CMAKE_CURRENT_BINARY_DIR}/libssh.pc
- ${CMAKE_CURRENT_BINARY_DIR}/libssh_threads.pc
- DESTINATION
- ${LIB_INSTALL_DIR}/pkgconfig
- COMPONENT
- pkgconfig
- )
- endif (LIBSSH_THREADS)
endif (UNIX)
# cmake config files
set(LIBSSH_LIBRARY_NAME ${CMAKE_SHARED_LIBRARY_PREFIX}ssh${CMAKE_SHARED_LIBRARY_SUFFIX})
-set(LIBSSH_THREADS_LIBRARY_NAME ${CMAKE_SHARED_LIBRARY_PREFIX}ssh${CMAKE_SHARED_LIBRARY_SUFFIX})
configure_file(${PROJECT_NAME}-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake @ONLY)
configure_file(${PROJECT_NAME}-config-version.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake @ONLY)
diff --git a/include/libssh/threads.h b/include/libssh/threads.h
index 70072648..750793b2 100644
--- a/include/libssh/threads.h
+++ b/include/libssh/threads.h
@@ -24,8 +24,33 @@
#include <libssh/libssh.h>
#include <libssh/callbacks.h>
+#if HAVE_PTHREAD
+
+#include <pthread.h>
+#define SSH_MUTEX pthread_mutex_t
+
+#if defined _GNU_SOURCE
+#define SSH_MUTEX_STATIC_INIT PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
+#else
+#define SSH_MUTEX_STATIC_INIT PTHREAD_MUTEX_INITIALIZER
+#endif
+
+#else
+
+# define SSH_MUTEX void *
+#define SSH_MUTEX_STATIC_INIT NULL
+
+#endif
+
int ssh_threads_init(void);
void ssh_threads_finalize(void);
const char *ssh_threads_get_type(void);
+void ssh_mutex_lock(SSH_MUTEX *mutex);
+void ssh_mutex_unlock(SSH_MUTEX *mutex);
+
+struct ssh_threads_callbacks_struct *ssh_threads_get_default(void);
+int crypto_thread_init(struct ssh_threads_callbacks_struct *user_callbacks);
+void crypto_thread_finalize(void);
+
#endif /* THREADS_H_ */
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 819d05c2..c37ce4d3 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -167,9 +167,23 @@ set(libssh_SRCS
chachapoly.c
)
+if (CMAKE_USE_PTHREADS_INIT)
+ set(libssh_SRCS
+ ${libssh_SRCS}
+ threads/noop.c
+ threads/pthread.c
+ )
+else()
+ set(libssh_SRCS
+ ${libssh_SRCS}
+ threads/noop.c
+ )
+endif()
+
if (WITH_GCRYPT)
set(libssh_SRCS
${libssh_SRCS}
+ threads/libgcrypt.c
libgcrypt.c
gcrypt_missing.c
pki_gcrypt.c
@@ -178,6 +192,7 @@ if (WITH_GCRYPT)
elseif (WITH_MBEDTLS)
set(libssh_SRCS
${libssh_SRCS}
+ threads/mbedtls.c
libmbedcrypto.c
mbedcrypto_missing.c
pki_mbedcrypto.c
@@ -186,6 +201,7 @@ elseif (WITH_MBEDTLS)
else (WITH_GCRYPT)
set(libssh_SRCS
${libssh_SRCS}
+ threads/libcrypto.c
pki_crypto.c
ecdh_crypto.c
libcrypto.c
@@ -319,6 +335,3 @@ if (WITH_STATIC_LIB)
endif (WITH_STATIC_LIB)
message(STATUS "Threads_FOUND=${Threads_FOUND}")
-if (Threads_FOUND)
- add_subdirectory(threads)
-endif (Threads_FOUND)
diff --git a/src/init.c b/src/init.c
index f3b6d72c..e984beed 100644
--- a/src/init.c
+++ b/src/init.c
@@ -32,12 +32,94 @@
#include <winsock2.h>
#endif
+#define CONSTRUCTOR_ATTRIBUTE __attribute__((constructor))
+#define DESTRUCTOR_ATTRIBUTE __attribute__((destructor))
+
+/* Declare static mutex */
+static SSH_MUTEX ssh_init_mutex = SSH_MUTEX_STATIC_INIT;
+
+/* Counter for initializations */
+static int _ssh_initialized = 0;
+
+/* Cache the returned value */
+static int _ssh_init_ret = 0;
+
+void libssh_constructor(void) CONSTRUCTOR_ATTRIBUTE;
+void libssh_destructor(void) DESTRUCTOR_ATTRIBUTE;
+
+static int _ssh_init(unsigned constructor) {
+
+ int rc = 0;
+
+ if (!constructor) {
+ ssh_mutex_lock(&ssh_init_mutex);
+ }
+
+ _ssh_initialized++;
+
+ if (_ssh_initialized > 1) {
+ rc = _ssh_init_ret;
+ goto _ret;
+ }
+
+ rc = ssh_threads_init();
+ if (rc) {
+ goto _ret;
+ }
+
+ rc = ssh_crypto_init();
+ if (rc) {
+ goto _ret;
+ }
+
+ rc = ssh_dh_init();
+ if (rc) {
+ goto _ret;
+ }
+
+ rc = ssh_socket_init();
+ if (rc) {
+ goto _ret;
+ }
+
+_ret:
+ _ssh_init_ret = rc;
+
+ if (!constructor) {
+ ssh_mutex_unlock(&ssh_init_mutex);
+ }
+
+ return rc;
+}
+
+/**
+ * @brief Initialize global cryptographic data structures.
+ *
+ * This functions is automatically called when the library is loaded.
+ *
+ * @returns 0 on success, -1 if an error occured.
+ */
+void libssh_constructor(void)
+{
+
+ int rc;
+
+ rc = _ssh_init(1);
+
+ if (rc < 0) {
+ fprintf(stderr, "Error in auto_init()\n");
+ }
+
+ return;
+}
+
/**
* @defgroup libssh The libssh API
*
* The libssh library is implementing the SSH protocols and some of its
- * extensions. This group of functions is mostly used to implment a SSH client.
- * Some function are needed to implement a SSH server too.
+ * extensions. This group of functions is mostly used to implement an SSH
+ * client.
+ * Some function are needed to implement an SSH server too.
*
* @{
*/
@@ -45,57 +127,97 @@
/**
* @brief Initialize global cryptographic data structures.
*
- * This function should only be called once, at the beginning of the program, in
- * the main thread. It may be omitted if your program is not multithreaded.
+ * 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).
+ *
+ * If the library is already initialized, increments the _ssh_initialized
+ * counter and return the error code cached in _ssh_init_ret.
*
* @returns 0 on success, -1 if an error occured.
*/
int ssh_init(void) {
- int rc;
+ return _ssh_init(0);
+}
- rc = ssh_threads_init();
- if (rc != SSH_OK) {
- return -1;
- }
+static int _ssh_finalize(unsigned destructor) {
- rc = ssh_crypto_init();
- if (rc != SSH_OK) {
- return -1;
+ if (!destructor) {
+ ssh_mutex_lock(&ssh_init_mutex);
}
- rc = ssh_dh_init();
- if (rc != SSH_OK) {
- return -1;
- }
+ if (_ssh_initialized == 1) {
+ _ssh_initialized = 0;
+
+ if (_ssh_init_ret < 0) {
+ goto _ret;
+ }
+
+ ssh_dh_finalize();
+ ssh_crypto_finalize();
+ ssh_socket_cleanup();
+ /* It is important to finalize threading after CRYPTO because
+ * it still depends on it */
+ ssh_threads_finalize();
- rc = ssh_socket_init();
- if (rc != SSH_OK) {
- return -1;
+ }
+ else {
+ if (_ssh_initialized > 0) {
+ _ssh_initialized--;
+ }
}
+_ret:
+ if (!destructor) {
+ ssh_mutex_unlock(&ssh_init_mutex);
+ }
return 0;
}
-
/**
* @brief Finalize and cleanup all libssh and cryptographic data structures.
*
- * This function should only be called once, at the end of the program!
+ * This function is automatically called when the library is unloaded.
*
* @returns 0 on succes, -1 if an error occured.
*
- @returns 0 otherwise
*/
-int ssh_finalize(void)
+void libssh_destructor(void)
{
- ssh_dh_finalize();
- ssh_crypto_finalize();
- ssh_socket_cleanup();
- /* It is important to finalize threading after CRYPTO because
- * it still depends on it */
- ssh_threads_finalize();
+ int rc;
- return 0;
+ rc = _ssh_finalize(1);
+
+ if (rc < 0) {
+ fprintf(stderr, "Error in libssh_destructor()\n");
+ }
+
+ /* Detect if ssh_init() was called without matching ssh_finalize() */
+ if (_ssh_initialized > 0) {
+ fprintf(stderr,
+ "Error: ssh still initialized; probably ssh_init() was"
+ " called more than once\n");
+ }
+}
+
+/**
+ * @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.
+ *
+ * If ssh_init() is called explicitly, then ssh_finalize() must be called
+ * explicitly.
+ *
+ * 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 otherwise
+ */
+int ssh_finalize(void) {
+ return _ssh_finalize(0);
}
/** @} */
diff --git a/src/threads.c b/src/threads.c
index 52d437df..792b976d 100644
--- a/src/threads.c
+++ b/src/threads.c
@@ -33,213 +33,63 @@
#include "libssh/crypto.h"
#include "libssh/threads.h"
-#ifdef HAVE_LIBMBEDCRYPTO
-#include <mbedtls/threading.h>
-#endif
+static struct ssh_threads_callbacks_struct *user_callbacks = NULL;
-static int threads_noop (void **lock){
- (void)lock;
- return 0;
-}
-
-static unsigned long threads_id_noop (void){
- return 1;
-}
+/** @internal
+ * @brief inits the threading with the backend cryptographic libraries
+ */
-static struct ssh_threads_callbacks_struct ssh_threads_noop =
+int ssh_threads_init(void)
{
- "threads_noop",
- threads_noop,
- threads_noop,
- threads_noop,
- threads_noop,
- threads_id_noop
-};
-
-struct ssh_threads_callbacks_struct *ssh_threads_get_noop(void) {
- return &ssh_threads_noop;
-}
-
-static struct ssh_threads_callbacks_struct *user_callbacks =&ssh_threads_noop;
-
-#ifdef HAVE_LIBGCRYPT
-#if (GCRYPT_VERSION_NUMBER >= 0x010600)
-/* libgcrypt >= 1.6 does not support custom callbacks */
-GCRY_THREAD_OPTION_PTHREAD_IMPL;
-
-static int libgcrypt_thread_init(void){
- if(user_callbacks == NULL)
- return SSH_ERROR;
- if(user_callbacks == &ssh_threads_noop)
- return SSH_OK;
- if (strcmp(user_callbacks->type, "threads_pthread") == 0){
- gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
- return SSH_OK;
- } else {
- /* not supported */
- SSH_LOG(SSH_LOG_WARN, "Custom thread handlers not supported with libgcrypt >=1.6, using pthreads");
- gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
- return SSH_OK;
- }
-}
+ static int threads_initialized = 0;
+ int rc;
-#else
-/* Libgcrypt < 1.6 specific way of handling thread callbacks */
-
-static struct gcry_thread_cbs gcrypt_threads_callbacks;
-
-static int libgcrypt_thread_init(void){
- if(user_callbacks == NULL)
- return SSH_ERROR;
- if(user_callbacks == &ssh_threads_noop){
- gcrypt_threads_callbacks.option= GCRY_THREAD_OPTION_VERSION << 8 || GCRY_THREAD_OPTION_DEFAULT;
- } else {
- gcrypt_threads_callbacks.option= GCRY_THREAD_OPTION_VERSION << 8 || GCRY_THREAD_OPTION_USER;
- }
- gcrypt_threads_callbacks.mutex_init=user_callbacks->mutex_init;
- gcrypt_threads_callbacks.mutex_destroy=user_callbacks->mutex_destroy;
- gcrypt_threads_callbacks.mutex_lock=user_callbacks->mutex_lock;
- gcrypt_threads_callbacks.mutex_unlock=user_callbacks->mutex_unlock;
- gcry_control(GCRYCTL_SET_THREAD_CBS, &gcrypt_threads_callbacks);
- return SSH_OK;
-}
-#endif /* GCRYPT_VERSION_NUMBER */
-#elif defined HAVE_LIBMBEDCRYPTO
-static int libmbedcrypto_thread_init(void)
-{
- if (user_callbacks == NULL) {
- return SSH_ERROR;
+ if (threads_initialized) {
+ return SSH_OK;
}
- if (user_callbacks == &ssh_threads_noop) {
- return SSH_OK;
+ /* first initialize the user_callbacks with our default handlers if not
+ * already the case
+ */
+ if (user_callbacks == NULL){
+ user_callbacks = ssh_threads_get_default();
}
-#ifdef MBEDTLS_THREADING_ALT
- else {
- mbedtls_threading_set_alt(user_callbacks->mutex_init,
- user_callbacks->mutex_destroy, user_callbacks->mutex_lock,
- user_callbacks->mutex_unlock);
+
+ /* Then initialize the crypto libraries threading callbacks */
+ rc = crypto_thread_init(user_callbacks);
+ if (rc == SSH_OK) {
+ threads_initialized = 1;
}
-#elif defined MBEDTLS_THREADING_PTHREAD
- return SSH_OK;
-#else
- return SSH_ERROR;
-#endif
+ return rc;
}
-#else /* HAVE_LIBGCRYPT */
-
-/* Libcrypto specific stuff */
-
-static void **libcrypto_mutexes;
-void libcrypto_lock_callback(int mode, int i, const char *file, int line);
-
-void libcrypto_lock_callback(int mode, int i, const char *file, int line)
+void ssh_threads_finalize(void)
{
- (void)file;
- (void)line;
- if(mode & CRYPTO_LOCK){
- user_callbacks->mutex_lock(&libcrypto_mutexes[i]);
- } else {
- user_callbacks->mutex_unlock(&libcrypto_mutexes[i]);
- }
+ crypto_thread_finalize();
}
-#ifdef HAVE_OPENSSL_CRYPTO_THREADID_SET_CALLBACK
-static void libcrypto_THREADID_callback(CRYPTO_THREADID *id)
+int ssh_threads_set_callbacks(struct ssh_threads_callbacks_struct *cb)
{
- unsigned long thread_id = (*user_callbacks->thread_id)();
-
- CRYPTO_THREADID_set_numeric(id, thread_id);
-}
-#endif /* HAVE_OPENSSL_CRYPTO_THREADID_SET_CALLBACK */
-
-static int libcrypto_thread_init(void){
- int n=CRYPTO_num_locks();
- int i;
- if(user_callbacks == &ssh_threads_noop)
- return SSH_OK;
- libcrypto_mutexes = calloc(n, sizeof(void *));
- if (libcrypto_mutexes == NULL)
- return SSH_ERROR;
- for (i=0;i<n;++i){
- user_callbacks->mutex_init(&libcrypto_mutexes[i]);
- }
-
-#ifdef HAVE_OPENSSL_CRYPTO_THREADID_SET_CALLBACK
- CRYPTO_THREADID_set_callback(libcrypto_THREADID_callback);
-#else
- CRYPTO_set_id_callback(user_callbacks->thread_id);
-#endif
-
- CRYPTO_set_locking_callback(libcrypto_lock_callback);
-
- return SSH_OK;
-}
-static void libcrypto_thread_finalize(void){
- int n=CRYPTO_num_locks();
- int i;
- if (libcrypto_mutexes==NULL)
- return;
- for (i=0;i<n;++i){
- user_callbacks->mutex_destroy(&libcrypto_mutexes[i]);
- }
- SAFE_FREE(libcrypto_mutexes);
+ int rc;
-}
-
-#endif
-
-/** @internal
- * @brief inits the threading with the backend cryptographic libraries
- */
+ if (user_callbacks != NULL) {
+ crypto_thread_finalize();
+ }
-int ssh_threads_init(void){
- static int threads_initialized=0;
- int ret;
- if(threads_initialized)
- return SSH_OK;
- /* first initialize the user_callbacks with our default handlers if not
- * already the case
- */
- if(user_callbacks == NULL){
- user_callbacks=&ssh_threads_noop;
- }
-
- /* Then initialize the crypto libraries threading callbacks */
-#ifdef HAVE_LIBGCRYPT
- ret = libgcrypt_thread_init();
-#elif HAVE_LIBMBEDCRYPTO
- ret = libmbedcrypto_thread_init();
-#else /* Libcrypto */
- ret = libcrypto_thread_init();
-#endif
- if(ret == SSH_OK)
- threads_initialized=1;
- return ret;
-}
+ user_callbacks = cb;
-void ssh_threads_finalize(void){
-#ifdef HAVE_LIBGCRYPT
-#elif HAVE_LIBMBEDCRYPTO
-#ifdef MBEDTLS_THREADING_ALT
- mbedtls_threading_free_alt();
-#endif
-#else
- libcrypto_thread_finalize();
-#endif
-}
+ rc = crypto_thread_init(user_callbacks);
-int ssh_threads_set_callbacks(struct ssh_threads_callbacks_struct *cb){
- user_callbacks=cb;
- return SSH_OK;
+ return rc;
}
-const char *ssh_threads_get_type(void) {
- if(user_callbacks != NULL)
- return user_callbacks->type;
- return NULL;
+const char *ssh_threads_get_type(void)
+{
+ if (user_callbacks != NULL) {
+ return user_callbacks->type;
+ }
+ return NULL;
}
/**
diff --git a/src/threads/CMakeLists.txt b/src/threads/CMakeLists.txt
deleted file mode 100644
index 2ab4e1ba..00000000
--- a/src/threads/CMakeLists.txt
+++ /dev/null
@@ -1,132 +0,0 @@
-project(libssh-threads C)
-
-set(LIBSSH_THREADS_PUBLIC_INCLUDE_DIRS
- ${CMAKE_SOURCE_DIR}/include
- ${CMAKE_CURRENT_SOURCE_DIR}
- ${CMAKE_SOURCE_DIR}
- CACHE INTERNAL "libssh public include directories"
-)
-
-set(LIBSSH_THREADS_PRIVATE_INCLUDE_DIRS
- ${CMAKE_BINARY_DIR}
-)
-
-set(LIBSSH_THREADS_SHARED_LIBRARY
- ssh_threads_shared
- CACHE INTERNAL "libssh threads shared library"
-)
-
-if (WITH_STATIC_LIB)
- set(LIBSSH_THREADS_STATIC_LIBRARY
- ssh_threads_static
- CACHE INTERNAL "libssh threads static library"
- )
-endif (WITH_STATIC_LIB)
-
-set(LIBSSH_THREADS_LINK_LIBRARIES
- ${LIBSSH_SHARED_LIBRARY}
-)
-
-message(STATUS "threads library: Threads_FOUND=${Threads_FOUND}")
-
-set(libssh_threads_SRCS) # empty SRC
-
-# build and link pthread
-if (CMAKE_USE_PTHREADS_INIT)
- set(libssh_threads_SRCS
- ${libssh_threads_SRCS}
- pthread.c
- )
-
- set(LIBSSH_THREADS_LINK_LIBRARIES
- ${LIBSSH_THREADS_LINK_LIBRARIES}
- ${CMAKE_THREAD_LIBS_INIT}
- )
-
- message(STATUS "libssh_threads_SRCS=${libssh_threads_SRCS}")
-endif (CMAKE_USE_PTHREADS_INIT)
-
-set(LIBSSH_THREADS_LINK_LIBRARIES
- ${LIBSSH_THREADS_LINK_LIBRARIES}
- CACHE INTERNAL "libssh threads link libraries"
-)
-
-include_directories(
- ${LIBSSH_THREADS_PUBLIC_INCLUDE_DIRS}
- ${LIBSSH_THREADS_PRIVATE_INCLUDE_DIRS}
-)
-
-if (libssh_threads_SRCS)
- set(LIBSSH_THREADS ON CACHE "libssh threads lib" INTERNAL)
-
- add_library(${LIBSSH_THREADS_SHARED_LIBRARY} SHARED ${libssh_threads_SRCS})
-
- target_link_libraries(${LIBSSH_THREADS_SHARED_LIBRARY} ${LIBSSH_THREADS_LINK_LIBRARIES})
-
- set_target_properties(
- ${LIBSSH_THREADS_SHARED_LIBRARY}
- PROPERTIES
- VERSION
- ${LIBRARY_VERSION}
- SOVERSION
- ${LIBRARY_SOVERSION}
- OUTPUT_NAME
- ssh_threads
- DEFINE_SYMBOL
- LIBSSH_EXPORTS
- )
-
- if (WITH_VISIBILITY_HIDDEN)
- set_target_properties(${LIBSSH_THREADS_SHARED_LIBRARY} PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
- endif (WITH_VISIBILITY_HIDDEN)
-
- install(
- TARGETS
- ${LIBSSH_THREADS_SHARED_LIBRARY}
- RUNTIME DESTINATION ${BIN_INSTALL_DIR}
- LIBRARY DESTINATION ${LIB_INSTALL_DIR}
- ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
- COMPONENT libraries
- )
-
- if (WITH_STATIC_LIB)
- add_library(${LIBSSH_THREADS_STATIC_LIBRARY} STATIC ${libssh_threads_SRCS})
-
- if (MSVC)
- set(OUTPUT_SUFFIX static)
- else (MSVC)
- set(OUTPUT_SUFFIX )
- endif (MSVC)
-
- set_target_properties(
- ${LIBSSH_THREADS_STATIC_LIBRARY}
- PROPERTIES
- VERSION
- ${LIBRARY_VERSION}
- SOVERSION
- ${LIBRARY_SOVERSION}
- OUTPUT_NAME
- ssh_threads
- ARCHIVE_OUTPUT_DIRECTORY
- ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_SUFFIX}
- )
-
- if (WIN32)
- set_target_properties(
- ${LIBSSH_THREADS_STATIC_LIBRARY}
- PROPERTIES
- COMPILE_FLAGS
- "-DLIBSSH_STATIC"
- )
- endif (WIN32)
-
- install(
- TARGETS
- ${LIBSSH_THREADS_STATIC_LIBRARY}
- DESTINATION
- ${LIB_INSTALL_DIR}/${OUTPUT_SUFFIX}
- COMPONENT
- libraries
- )
- endif (WITH_STATIC_LIB)
-endif (libssh_threads_SRCS)
diff --git a/src/threads/libcrypto.c b/src/threads/libcrypto.c
new file mode 100644
index 00000000..156e5041
--- /dev/null
+++ b/src/threads/libcrypto.c
@@ -0,0 +1,125 @@
+/*
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2018 by Anderson Toshiyuki Sasaki
+ *
+ * The SSH 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.
+ *
+ * The SSH 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 the SSH Library; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "libssh/crypto.h"
+#include "libssh/threads.h"
+#include <libssh/callbacks.h>
+
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000)
+
+int crypto_thread_init(struct ssh_threads_callbacks_struct *cb)
+{
+ (void) cb;
+ return SSH_OK;
+}
+
+void crypto_thread_finalize(void)
+{
+ return;
+}
+
+#else
+
+static struct ssh_threads_callbacks_struct *user_callbacks = NULL;
+
+static void **libcrypto_mutexes;
+
+void libcrypto_lock_callback(int mode, int i, const char *file, int line);
+
+void libcrypto_lock_callback(int mode, int i, const char *file, int line)
+{
+ (void)file;
+ (void)line;
+
+ if (mode & CRYPTO_LOCK) {
+ user_callbacks->mutex_lock(&libcrypto_mutexes[i]);
+ } else {
+ user_callbacks->mutex_unlock(&libcrypto_mutexes[i]);
+ }
+}
+
+#ifdef HAVE_OPENSSL_CRYPTO_THREADID_SET_CALLBACK
+static void libcrypto_THREADID_callback(CRYPTO_THREADID *id)
+{
+ unsigned long thread_id = (*user_callbacks->thread_id)();
+
+ CRYPTO_THREADID_set_numeric(id, thread_id);
+}
+#endif /* HAVE_OPENSSL_CRYPTO_THREADID_SET_CALLBACK */
+
+int crypto_thread_init(struct ssh_threads_callbacks_struct *cb)
+{
+ int n = CRYPTO_num_locks();
+ int cmp;
+ int i;
+
+ if (cb == NULL) {
+ return SSH_OK;
+ }
+
+ if (user_callbacks != NULL) {
+ crypto_thread_finalize();
+ }
+
+ user_callbacks = cb;
+
+ cmp = strcmp(user_callbacks->type, "threads_noop");
+ if (cmp == 0) {
+ return SSH_OK;
+ }
+
+ libcrypto_mutexes = calloc(n, sizeof(void *));
+ if (libcrypto_mutexes == NULL) {
+ return SSH_ERROR;
+ }
+
+ for (i = 0; i < n; ++i){
+ user_callbacks->mutex_init(&libcrypto_mutexes[i]);
+ }
+
+#ifdef HAVE_OPENSSL_CRYPTO_THREADID_SET_CALLBACK
+ CRYPTO_THREADID_set_callback(libcrypto_THREADID_callback);
+#else
+ CRYPTO_set_id_callback(user_callbacks->thread_id);
+#endif
+
+ CRYPTO_set_locking_callback(libcrypto_lock_callback);
+
+ return SSH_OK;
+}
+
+void crypto_thread_finalize(void)
+{
+ int n = CRYPTO_num_locks();
+ int i;
+
+ if (libcrypto_mutexes == NULL) {
+ return;
+ }
+
+ for (i = 0; i < n; ++i) {
+ user_callbacks->mutex_destroy(&libcrypto_mutexes[i]);
+ }
+ SAFE_FREE(libcrypto_mutexes);
+}
+
+#endif
diff --git a/src/threads/libgcrypt.c b/src/threads/libgcrypt.c
new file mode 100644
index 00000000..3560dc55
--- /dev/null
+++ b/src/threads/libgcrypt.c
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2018 by Anderson Toshiyuki Sasaki
+ *
+ * The SSH 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.
+ *
+ * The SSH 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 the SSH Library; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "libssh/crypto.h"
+#include "libssh/threads.h"
+#include <libssh/callbacks.h>
+
+#if (GCRYPT_VERSION_NUMBER >= 0x010600)
+/* libgcrypt >= 1.6 does not support custom callbacks */
+GCRY_THREAD_OPTION_PTHREAD_IMPL;
+
+int crypto_thread_init(struct ssh_threads_callbacks_struct *user_callbacks)
+{
+ (void) user_callbacks;
+
+ return SSH_OK;
+}
+
+#else
+/* Libgcrypt < 1.6 specific way of handling thread callbacks */
+
+static struct gcry_thread_cbs gcrypt_threads_callbacks;
+
+int crypto_thread_init(struct ssh_threads_callbacks_struct *user_callbacks)
+{
+ int cmp;
+
+ if (user_callbacks == NULL) {
+ return SSH_OK;
+ }
+
+ cmp = strcmp(user_callbacks->type, "threads_noop");
+ if (cmp == 0) {
+ gcrypt_threads_callbacks.option= GCRY_THREAD_OPTION_VERSION << 8 ||
+ GCRY_THREAD_OPTION_DEFAULT;
+ } else {
+ gcrypt_threads_callbacks.option= GCRY_THREAD_OPTION_VERSION << 8 ||
+ GCRY_THREAD_OPTION_USER;
+ }
+
+ gcrypt_threads_callbacks.mutex_init = user_callbacks->mutex_init;
+ gcrypt_threads_callbacks.mutex_destroy = user_callbacks->mutex_destroy;
+ gcrypt_threads_callbacks.mutex_lock = user_callbacks->mutex_lock;
+ gcrypt_threads_callbacks.mutex_unlock = user_callbacks->mutex_unlock;
+ gcry_control(GCRYCTL_SET_THREAD_CBS, &gcrypt_threads_callbacks);
+
+ return SSH_OK;
+}
+
+#endif /* GCRYPT_VERSION_NUMBER */
+
+void crypto_thread_finalize(void)
+{
+ return;
+}
diff --git a/src/threads/mbedtls.c b/src/threads/mbedtls.c
new file mode 100644
index 00000000..6cc3fa53
--- /dev/null
+++ b/src/threads/mbedtls.c
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2018 by Anderson Toshiyuki Sasaki
+ *
+ * The SSH 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.
+ *
+ * The SSH 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 the SSH Library; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "libssh/crypto.h"
+#include "libssh/threads.h"
+#include <libssh/callbacks.h>
+
+#include <mbedtls/threading.h>
+
+int crypto_thread_init(struct ssh_threads_callbacks_struct *user_callbacks)
+{
+ int cmp;
+
+ if (user_callbacks == NULL) {
+ return SSH_OK;
+ }
+
+ cmp = strcmp(user_callbacks->type, "threads_noop");
+ if (cmp == 0) {
+ return SSH_OK;
+ }
+#ifdef MBEDTLS_THREADING_ALT
+ else {
+ if (user_callbacks != NULL) {
+ crypto_thread_finalize();
+ }
+
+ mbedtls_threading_set_alt(user_callbacks->mutex_init,
+ user_callbacks->mutex_destroy,
+ user_callbacks->mutex_lock,
+ user_callbacks->mutex_unlock);
+ }
+#elif defined MBEDTLS_THREADING_PTHREAD
+ return SSH_OK;
+#else
+ return SSH_ERROR;
+#endif
+}
+
+void crypto_thread_finalize(void)
+{
+#ifdef MBEDTLS_THREADING_ALT
+ mbedtls_threading_free_alt();
+#endif
+ return;
+}
diff --git a/src/threads/noop.c b/src/threads/noop.c
new file mode 100644
index 00000000..aad4934e
--- /dev/null
+++ b/src/threads/noop.c
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2018 by Anderson Toshiyuki Sasaki
+ *
+ * The SSH 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.
+ *
+ * The SSH 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 the SSH Library; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "libssh/threads.h"
+#include <libssh/callbacks.h>
+
+static int threads_noop(void **lock)
+{
+ (void)lock;
+
+ return 0;
+}
+
+static unsigned long threads_id_noop (void)
+{
+ return 1;
+}
+
+static struct ssh_threads_callbacks_struct ssh_threads_noop =
+{
+ .type = "threads_noop",
+ .mutex_init = threads_noop,
+ .mutex_destroy = threads_noop,
+ .mutex_lock = threads_noop,
+ .mutex_unlock = threads_noop,
+ .thread_id = threads_id_noop
+};
+
+/* Threads interface implementation */
+
+#if !(HAVE_PTHREAD)
+void ssh_mutex_lock(SSH_MUTEX *mutex)
+{
+ (void) mutex;
+
+ return;
+}
+
+void ssh_mutex_unlock(SSH_MUTEX *mutex)
+{
+ (void) mutex;
+
+ return;
+}
+
+struct ssh_threads_callbacks_struct *ssh_threads_get_default(void)
+{
+ return &ssh_threads_noop;
+}
+#endif
+
+struct ssh_threads_callbacks_struct *ssh_threads_get_noop(void)
+{
+ return &ssh_threads_noop;
+}
diff --git a/src/threads/pthread.c b/src/threads/pthread.c
index a0a266d7..422dd854 100644
--- a/src/threads/pthread.c
+++ b/src/threads/pthread.c
@@ -20,61 +20,64 @@
*/
#include "config.h"
+#include "libssh/threads.h"
#include <libssh/callbacks.h>
-#ifdef HAVE_PTHREAD
-
#include <errno.h>
#include <stdlib.h>
#include <pthread.h>
-/** @brief Defines the needed callbacks for pthread. Use this if your
- * OS supports libpthread and want to use it for threading.
- * @code
- * #include <libssh/callbacks.h>
- * #include <errno.h>
- * #include <pthread.h>
- * SSH_THREADS_PTHREAD(ssh_pthread_callbacks);
- * int main(){
- * ssh_init_set_threads_callbacks(&ssh_pthread_callbacks);
- * ssh_init();
- * ...
- * }
- * @endcode
- * @param name name of the structure to be declared, containing the
- * callbacks for threading
- *
- */
+static int ssh_pthread_mutex_init (void **mutex)
+{
+ int rc = 0;
+
+ if (mutex == NULL) {
+ return EINVAL;
+ }
-static int ssh_pthread_mutex_init (void **priv){
- int err = 0;
- *priv = malloc (sizeof (pthread_mutex_t));
- if (*priv==NULL)
- return ENOMEM;
- err = pthread_mutex_init (*priv, NULL);
- if (err != 0){
- free (*priv);
- *priv=NULL;
- }
- return err;
+ *mutex = malloc(sizeof(pthread_mutex_t));
+ if (*mutex == NULL) {
+ return ENOMEM;
+ }
+
+ rc = pthread_mutex_init ((pthread_mutex_t *)*mutex, NULL);
+ if (rc){
+ free (*mutex);
+ *mutex = NULL;
+ }
+
+ return rc;
}
-static int ssh_pthread_mutex_destroy (void **lock) {
- int err = pthread_mutex_destroy (*lock);
- free (*lock);
- *lock=NULL;
- return err;
+static int ssh_pthread_mutex_destroy (void **mutex)
+{
+
+ int rc = 0;
+
+ if (mutex == NULL) {
+ return EINVAL;
+ }
+
+ rc = pthread_mutex_destroy ((pthread_mutex_t *)*mutex);
+
+ free (*mutex);
+ *mutex = NULL;
+
+ return rc;
}
-static int ssh_pthread_mutex_lock (void **lock) {
- return pthread_mutex_lock (*lock);
+static int ssh_pthread_mutex_lock (void **mutex)
+{
+ return pthread_mutex_lock((pthread_mutex_t *)*mutex);
}
-static int ssh_pthread_mutex_unlock (void **lock){
- return pthread_mutex_unlock (*lock);
+static int ssh_pthread_mutex_unlock (void **mutex)
+{
+ return pthread_mutex_unlock((pthread_mutex_t *)*mutex);
}
-static unsigned long ssh_pthread_thread_id (void){
+static unsigned long ssh_pthread_thread_id (void)
+{
#if defined(_WIN32) && !defined(__WINPTHREADS_VERSION)
return (unsigned long) pthread_self().p;
#else
@@ -84,16 +87,54 @@ static unsigned long ssh_pthread_thread_id (void){
static struct ssh_threads_callbacks_struct ssh_threads_pthread =
{
- .type="threads_pthread",
- .mutex_init=ssh_pthread_mutex_init,
- .mutex_destroy=ssh_pthread_mutex_destroy,
- .mutex_lock=ssh_pthread_mutex_lock,
- .mutex_unlock=ssh_pthread_mutex_unlock,
- .thread_id=ssh_pthread_thread_id
+ .type = "threads_pthread",
+ .mutex_init = ssh_pthread_mutex_init,
+ .mutex_destroy = ssh_pthread_mutex_destroy,
+ .mutex_lock = ssh_pthread_mutex_lock,
+ .mutex_unlock = ssh_pthread_mutex_unlock,
+ .thread_id = ssh_pthread_thread_id
};
-struct ssh_threads_callbacks_struct *ssh_threads_get_pthread(void) {
- return &ssh_threads_pthread;
+/* Threads interface implementation */
+
+#if (HAVE_PTHREAD)
+void ssh_mutex_lock(SSH_MUTEX *mutex)
+{
+ int rc;
+
+ if (mutex == NULL) {
+ exit(EINVAL);
+ }
+
+ rc = pthread_mutex_lock(mutex);
+
+ if (rc) {
+ exit(rc);
+ }
+}
+
+void ssh_mutex_unlock(SSH_MUTEX *mutex)
+{
+ int rc;
+
+ if (mutex == NULL) {
+ exit(EINVAL);
+ }
+
+ rc = pthread_mutex_unlock(mutex);
+
+ if (rc) {
+ exit(rc);
+ }
+}
+
+struct ssh_threads_callbacks_struct *ssh_threads_get_default(void)
+{
+ return &ssh_threads_pthread;
}
+#endif
-#endif /* HAVE_PTHREAD */
+struct ssh_threads_callbacks_struct *ssh_threads_get_pthread(void)
+{
+ return &ssh_threads_pthread;
+}
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 4eba739c..001f9760 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -22,13 +22,6 @@ set(TORTURE_LINK_LIBRARIES
${LIBSSH_STATIC_LIBRARY}
${LIBSSH_LINK_LIBRARIES})
-if (LIBSSH_THREADS)
- set(TORTURE_LINK_LIBRARIES
- ${TORTURE_LINK_LIBRARIES}
- ${LIBSSH_THREADS_STATIC_LIBRARY}
- ${LIBSSH_THREADS_LINK_LIBRARIES})
-endif (LIBSSH_THREADS)
-
# create test library
add_library(${TORTURE_LIBRARY}
STATIC
diff --git a/tests/fuzz/CMakeLists.txt b/tests/fuzz/CMakeLists.txt
index c3e350be..5c1e63b0 100644
--- a/tests/fuzz/CMakeLists.txt
+++ b/tests/fuzz/CMakeLists.txt
@@ -6,8 +6,4 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
PROPERTIES
COMPILE_FLAGS "-fsanitize=fuzzer"
LINK_FLAGS "-fsanitize=fuzzer")
-
- target_link_libraries(ssh_server_fuzzer
- ${LIBSSH_THREADS_STATIC_LIBRARY}
- ${LIBSSH_THREADS_LINK_LIBRARIES})
endif()
diff --git a/tests/pkd/CMakeLists.txt b/tests/pkd/CMakeLists.txt
index a07021ec..d2da5766 100644
--- a/tests/pkd/CMakeLists.txt
+++ b/tests/pkd/CMakeLists.txt
@@ -24,9 +24,8 @@ set(pkd_libs
${CMOCKA_LIBRARY}
${LIBSSH_STATIC_LIBRARY}
${LIBSSH_LINK_LIBRARIES}
- ${LIBSSH_THREADS_STATIC_LIBRARY}
- ${LIBSSH_THREADS_LINK_LIBRARIES}
${ARGP_LIBRARIES}
+ pthread
)
add_executable(pkd_hello ${pkd_hello_src})
diff --git a/tests/unittests/CMakeLists.txt b/tests/unittests/CMakeLists.txt
index d518dd21..e833481a 100644
--- a/tests/unittests/CMakeLists.txt
+++ b/tests/unittests/CMakeLists.txt
@@ -32,11 +32,12 @@ if (UNIX AND NOT WIN32)
# requires /dev/null
add_cmocka_test(torture_channel torture_channel.c ${TORTURE_LIBRARY})
# requires pthread
- if (LIBSSH_THREADS)
+ if (CMAKE_USE_PTHREADS_INIT)
add_cmocka_test(torture_rand torture_rand.c ${TORTURE_LIBRARY})
+ target_link_libraries(torture_rand Threads::Threads)
# Not working correctly
#if (WITH_SERVER)
# add_cmocka_test(torture_server_x11 torture_server_x11.c ${TORTURE_LIBRARY})
#endif (WITH_SERVER)
- endif (LIBSSH_THREADS)
+ endif ()
endif (UNIX AND NOT WIN32)