diff --git a/libssh/CMakeLists.txt b/libssh/CMakeLists.txt index 81ac5884..e783c2b4 100644 --- a/libssh/CMakeLists.txt +++ b/libssh/CMakeLists.txt @@ -67,6 +67,10 @@ endif(WITH_GCRYPT) set(CMAKE_THREAD_PREFER_PTHREADS ON) find_package(Threads) +if (WITH_GSSAPI) + find_package(GSSAPI) +endif (WITH_GSSAPI) + # config.h checks include(ConfigureChecks.cmake) configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) @@ -122,6 +126,7 @@ message(STATUS "libgcrypt support: ${WITH_GCRYPT}") message(STATUS "SSH-1 support: ${WITH_SSH1}") message(STATUS "SFTP support: ${WITH_SFTP}") message(STATUS "Server support : ${WITH_SERVER}") +message(STATUS "GSSAPI support : ${WITH_GSSAPI}") message(STATUS "Pcap debugging support : ${WITH_PCAP}") message(STATUS "With static library: ${WITH_STATIC_LIB}") message(STATUS "Unit testing: ${WITH_TESTING}") diff --git a/libssh/CTestConfig.cmake b/libssh/CTestConfig.cmake index d8a41831..20d2e8f5 100644 --- a/libssh/CTestConfig.cmake +++ b/libssh/CTestConfig.cmake @@ -1,7 +1,7 @@ set(UPDATE_TYPE "true") set(CTEST_PROJECT_NAME "libssh") -set(CTEST_NIGHTLY_START_TIME "01:00:00 CET") +set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC") set(CTEST_DROP_METHOD "http") set(CTEST_DROP_SITE "test.libssh.org") diff --git a/libssh/ChangeLog b/libssh/ChangeLog index 5bc0784a..6f4d906c 100644 --- a/libssh/ChangeLog +++ b/libssh/ChangeLog @@ -1,13 +1,75 @@ ChangeLog ========== -version 0.5.x (released 2012-xx-xx) - * Added new PKI infrastructure. - * Added simplified user auth functions. - * Added ECDSA pubkey support. - * Added ECDSA hostkey support. - * Added diffie-hellman-group14-sha1 support. - * Fixed a ton of bugs. +version 0.6.0 (released 2013-XX-XX) + * Added new publicy key API. + * Added new userauth API. + * Added gssapi-mic userauth. + * Added new callback based server API. + * Added Elliptic Curve DSA (ECDSA) support (with OpenSSL). + * Added Elliptic Curve Diffie Hellman (ECDH) support. + * Added improved logging system. + * Added SSH-agent forwarding. + * Added key-reexchange. + * Improved documentation. + * Fixed timeout handling. + +version 0.5.5 (released 2013-07-26) + * BUG 103: Fix ProxyCommand parsing. + * Fix setting -D_FORTIFY_SOURCE=2. + * Fix pollset error return if emtpy. + * Fix NULL pointer checks in channel functions. + * Several bugfixes. + +version 0.5.4 (released 2013-01-22) + * CVE-2013-0176 - NULL dereference leads to denial of service + * Fixed several NULL pointer dereferences in SSHv1. + * Fixed a free crash bug in options parsing. + +version 0.5.3 (released 2012-11-20) + * CVE-2012-4559 Fixed multiple double free() flaws. + * CVE-2012-4560 Fixed multiple buffer overflow flaws. + * CVE-2012-4561 Fixed multiple invalid free() flaws. + * BUG #84 - Fix bug in sftp_mkdir not returning on error. + * BUG #85 - Fixed a possible channel infinite loop if the connection dropped. + * BUG #88 - Added missing channel request_state and set it to accepted. + * BUG #89 - Reset error state to no error on successful SSHv1 authentiction. + * Fixed a possible use after free in ssh_free(). + * Fixed multiple possible NULL pointer dereferences. + * Fixed multiple memory leaks in error paths. + * Fixed timeout handling. + * Fixed regression in pre-connected socket setting. + * Handle all unknown global messages. + +version 0.5.2 (released 2011-09-17) + * Increased window size x10. + * Fixed SSHv1. + * Fixed bugged lists. + * Fixed use-after-free + inconsistent callbacks call in poll. + * Fixed scp documentation. + * Fixed possible infinite loop in channel_read(). + * Fixed handling of short reads of sftp_async_read(). + * Fixed handling request service timeout in blocking mode. + * Fixed ssh_auth_list() documentation. + * Fixed incorrect return values in ssh_channel_write(). + * Fixed an infinite loop in the termination callback. + * Fixed handling of SSH_AGAIN in channel_open(). + * Fixed "status -5 inflating zlib packet" + +version 0.5.1 (released 2011-08-09) + * Added checks for NULL pointers in string.c. + * Set the channel max packet size to 32768. + * Don't (de)compress empty buffers. + * Fixed ssh_scp_write so it works when doing recursive copy. + * Fixed another source of endless wait. + * Fixed an endless loop in case of a channel_open error. + * Fixed session timeout handling. + * Fixed ssh_channel_from_local() loop. + * Fixed permissions of scp example when we copy a file. + * Workaround ssh_get_user_home_dir on LDAP users. + * Added pkg-config support for libssh_threads. + * Fixed compilation without server and sftp modes. + * Fix static .lib overwriting on Windows. version 0.5.0 (released 2011-06-01) * Added ssh_ prefix to all functions. diff --git a/libssh/ConfigureChecks.cmake b/libssh/ConfigureChecks.cmake index b0485d98..1c89c4c7 100644 --- a/libssh/ConfigureChecks.cmake +++ b/libssh/ConfigureChecks.cmake @@ -49,6 +49,7 @@ endif(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW AND NOT OS2) check_include_file(argp.h HAVE_ARGP_H) check_include_file(pty.h HAVE_PTY_H) check_include_file(termios.h HAVE_TERMIOS_H) +check_include_file(unistd.h HAVE_UNISTD_H) if (WIN32) check_include_files("winsock2.h;ws2tcpip.h;wspiapi.h" HAVE_WSPIAPI_H) @@ -56,12 +57,6 @@ if (WIN32) message(STATUS "WARNING: Without wspiapi.h, this build will only work on Windows XP and newer versions") endif (NOT HAVE_WSPIAPI_H) check_include_files("winsock2.h;ws2tcpip.h" HAVE_WS2TCPIP_H) - if (HAVE_WSPIAPI_H OR HAVE_WS2TCPIP_H) - set(HAVE_GETADDRINFO TRUE) - set(HAVE_GETHOSTBYNAME TRUE) - endif (HAVE_WSPIAPI_H OR HAVE_WS2TCPIP_H) - - set(HAVE_SELECT TRUE) endif (WIN32) set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIRS}) @@ -101,12 +96,30 @@ endif (NOT WITH_GCRYPT) check_function_exists(strncpy HAVE_STRNCPY) check_function_exists(vsnprintf HAVE_VSNPRINTF) check_function_exists(snprintf HAVE_SNPRINTF) +check_function_exists(poll HAVE_POLL) +check_function_exists(select HAVE_SELECT) +check_function_exists(getaddrinfo HAVE_GETADDRINFO) +check_function_exists(ntohll HAVE_NTOHLL) +check_function_exists(htonll HAVE_HTONLL) if (WIN32) + check_function_exists(_strtoui64 HAVE__STRTOUI64) + check_function_exists(_vsnprintf_s HAVE__VSNPRINTF_S) check_function_exists(_vsnprintf HAVE__VSNPRINTF) check_function_exists(_snprintf HAVE__SNPRINTF) check_function_exists(_snprintf_s HAVE__SNPRINTF_S) + + if (HAVE_WSPIAPI_H OR HAVE_WS2TCPIP_H) + set(HAVE_GETADDRINFO TRUE) + set(HAVE_GETHOSTBYNAME TRUE) + if (MSVC) + set(HAVE_NTOHLL TRUE) + set(HAVE_HTONLL TRUE) + endif (MSVC) + endif (HAVE_WSPIAPI_H OR HAVE_WS2TCPIP_H) + + set(HAVE_SELECT TRUE) endif (WIN32) if (UNIX) @@ -114,7 +127,8 @@ if (UNIX) # libsocket (Solaris) check_library_exists(socket getaddrinfo "" HAVE_LIBSOCKET) if (HAVE_LIBSOCKET) - set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} socket) + set(HAVE_GETADDRINFO TRUE) + set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} socket) endif (HAVE_LIBSOCKET) # libnsl/inet_pton (Solaris) @@ -133,12 +147,7 @@ if (UNIX) endif (HAVE_LIBRT OR HAVE_CLOCK_GETTIME) check_library_exists(util forkpty "" HAVE_LIBUTIL) - check_function_exists(getaddrinfo HAVE_GETADDRINFO) - check_function_exists(poll HAVE_POLL) - check_function_exists(select HAVE_SELECT) check_function_exists(cfmakeraw HAVE_CFMAKERAW) - check_function_exists(ntohll HAVE_NTOHLL) - check_function_exists(htonll HAVE_HTONLL) check_function_exists(strtoull HAVE_STRTOULL) check_function_exists(__strtoull HAVE___STRTOULL) endif (UNIX) @@ -165,6 +174,32 @@ if (CMAKE_HAVE_THREADS_LIBRARY) endif (CMAKE_HAVE_THREADS_LIBRARY) # OPTIONS +check_c_source_compiles(" +__thread int tls; + +int main(void) { + return 0; +}" HAVE_GCC_THREAD_LOCAL_STORAGE) + +check_c_source_compiles(" +__declspec(thread) int tls; + +int main(void) { + return 0; +}" HAVE_MSC_THREAD_LOCAL_STORAGE) + +check_c_source_compiles(" +#include + +int main(void) +{ + char buf[] = \"This is some content\"; + + memset(buf, '\\\\0', sizeof(buf)); __asm__ volatile(\"\" : : \"r\"(&buf) : \"memory\"); + + return 0; +}" HAVE_GCC_VOLATILE_MEMORY_PROTECTION) + if (WITH_DEBUG_CRYPTO) set(DEBUG_CRYPTO 1) endif (WITH_DEBUG_CRYPTO) @@ -173,6 +208,10 @@ if (WITH_DEBUG_CALLTRACE) set(DEBUG_CALLTRACE 1) endif (WITH_DEBUG_CALLTRACE) +if (WITH_GSSAPI AND NOT GSSAPI_FOUND) + set(WITH_GSSAPI 0) +endif (WITH_GSSAPI AND NOT GSSAPI_FOUND) + # ENDIAN if (NOT WIN32) test_big_endian(WORDS_BIGENDIAN) diff --git a/libssh/DefineOptions.cmake b/libssh/DefineOptions.cmake index ea8265c0..6913f040 100644 --- a/libssh/DefineOptions.cmake +++ b/libssh/DefineOptions.cmake @@ -1,3 +1,4 @@ +option(WITH_GSSAPI "Build with GSSAPI support" ON) option(WITH_ZLIB "Build with ZLIB support" ON) option(WITH_SSH1 "Build with SSH1 support" OFF) option(WITH_SFTP "Build with SFTP support" ON) diff --git a/libssh/INSTALL b/libssh/INSTALL index a772b824..25960367 100644 --- a/libssh/INSTALL +++ b/libssh/INSTALL @@ -21,7 +21,7 @@ build and run libssh successfully with an older version, please let us know. Windows binaries known to be working: - http://www.slproweb.com/products/Win32OpenSSL.html -- http://www.winimage.com/zLibDll/index.html +- http://zlib.net/ -> zlib compiled DLL We installed them in C:\Program Files @@ -34,7 +34,9 @@ GNU/Linux, MacOS X, MSYS/MinGW: cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug .. make -On Windows you should choose a makefile gernerator with -G. +On Windows you should choose a makefile gernerator with -G or use + + cmake-gui.exe .. ### CMake standard options Here is a list of the most interesting options provided out of the box by @@ -86,7 +88,7 @@ If you want to install libssh after compilation run: ## Running -The libssh binary can be found in the `build/libssh` directory. +The libssh binary can be found in the `build/src` directory. You can use `build/examples/samplessh` which is a sample client to test libssh on UNIX. diff --git a/libssh/cmake/Modules/DefineCompilerFlags.cmake b/libssh/cmake/Modules/DefineCompilerFlags.cmake index 582ea1ca..0ab8802c 100644 --- a/libssh/cmake/Modules/DefineCompilerFlags.cmake +++ b/libssh/cmake/Modules/DefineCompilerFlags.cmake @@ -28,10 +28,10 @@ if (UNIX AND NOT WIN32) if (CMAKE_BUILD_TYPE) string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWER) - if (NOT CMAKE_BUILD_TYPE_LOWER MATCHES debug) - check_c_compiler_flag("-D_FORTIFY_SOURCE=2" WITH_FORTIFY_SOURCE) + if (CMAKE_BUILD_TYPE_LOWER MATCHES (release|relwithdebinfo|minsizerel)) + check_c_compiler_flag("-Wp,-D_FORTIFY_SOURCE=2" WITH_FORTIFY_SOURCE) if (WITH_FORTIFY_SOURCE) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FORTIFY_SOURCE=2") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wp,-D_FORTIFY_SOURCE=2") endif (WITH_FORTIFY_SOURCE) endif() endif() diff --git a/libssh/cmake/Modules/FindCMocka.cmake b/libssh/cmake/Modules/FindCMocka.cmake index 2dd9fc5f..76b4ba74 100644 --- a/libssh/cmake/Modules/FindCMocka.cmake +++ b/libssh/cmake/Modules/FindCMocka.cmake @@ -21,6 +21,23 @@ #============================================================================= # +set(_CMOCKA_ROOT_HINTS +) + +set(_CMOCKA_ROOT_PATHS + "$ENV{PROGRAMFILES}/cmocka" +) + +find_path(CMOCKA_ROOT_DIR + NAMES + include/cmocka.h + HINTS + ${_CMOCKA_ROOT_HINTS} + PATHS + ${_CMOCKA_ROOT_PATHS} +) +mark_as_advanced(CMOCKA_ROOT_DIR) + find_path(CMOCKA_INCLUDE_DIR NAMES cmocka.h @@ -32,7 +49,7 @@ find_library(CMOCKA_LIBRARY NAMES cmocka PATHS - ${CMOCKA_ROOT_DIR}/include + ${CMOCKA_ROOT_DIR}/lib ) if (CMOCKA_LIBRARY) diff --git a/libssh/cmake/Modules/FindGSSAPI.cmake b/libssh/cmake/Modules/FindGSSAPI.cmake new file mode 100644 index 00000000..8520d35d --- /dev/null +++ b/libssh/cmake/Modules/FindGSSAPI.cmake @@ -0,0 +1,324 @@ +# - Try to find GSSAPI +# Once done this will define +# +# KRB5_CONFIG - Path to krb5-config +# GSSAPI_ROOT_DIR - Set this variable to the root installation of GSSAPI +# +# Read-Only variables: +# GSSAPI_FLAVOR_MIT - set to TURE if MIT Kerberos has been found +# GSSAPI_FLAVOR_HEIMDAL - set to TRUE if Heimdal Keberos has been found +# GSSAPI_FOUND - system has GSSAPI +# GSSAPI_INCLUDE_DIR - the GSSAPI include directory +# GSSAPI_LIBRARIES - Link these to use GSSAPI +# GSSAPI_DEFINITIONS - Compiler switches required for using GSSAPI +# +#============================================================================= +# Copyright (c) 2013 Andreas Schneider +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# + +find_path(GSSAPI_ROOT_DIR + NAMES + include/gssapi.h + include/gssapi/gssapi.h + HINTS + ${_GSSAPI_ROOT_HINTS} + PATHS + ${_GSSAPI_ROOT_PATHS} +) +mark_as_advanced(GSSAPI_ROOT_DIR) + +if (UNIX) + find_program(KRB5_CONFIG + NAMES + krb5-config + PATHS + ${GSSAPI_ROOT_DIR}/bin + /opt/local/bin) + mark_as_advanced(KRB5_CONFIG) + + if (KRB5_CONFIG) + # Check if we have MIT KRB5 + execute_process( + COMMAND + ${KRB5_CONFIG} --vendor + RESULT_VARIABLE + _GSSAPI_VENDOR_RESULT + OUTPUT_VARIABLE + _GSSAPI_VENDOR_STRING) + + if (_GSSAPI_VENDOR_STRING MATCHES ".*Massachusetts.*") + set(GSSAPI_FLAVOR_MIT TRUE) + else() + execute_process( + COMMAND + ${KRB5_CONFIG} --libs gssapi + RESULT_VARIABLE + _GSSAPI_LIBS_RESULT + OUTPUT_VARIABLE + _GSSAPI_LIBS_STRING) + + if (_GSSAPI_LIBS_STRING MATCHES ".*roken.*") + set(GSSAPI_FLAVOR_HEIMDAL TRUE) + endif() + endif() + + # Get the include dir + execute_process( + COMMAND + ${KRB5_CONFIG} --cflags gssapi + RESULT_VARIABLE + _GSSAPI_INCLUDE_RESULT + OUTPUT_VARIABLE + _GSSAPI_INCLUDE_STRING) + string(REGEX REPLACE "(\r?\n)+$" "" _GSSAPI_INCLUDE_STRING "${_GSSAPI_INCLUDE_STRING}") + string(REGEX REPLACE " *-I" "" _GSSAPI_INCLUDEDIR "${_GSSAPI_INCLUDE_STRING}") + endif() + + if (NOT GSSAPI_FLAVOR_MIT AND NOT GSSAPI_FLAVOR_HEIMDAL) + # Check for HEIMDAL + find_package(PkgConfig) + if (PKG_CONFIG_FOUND) + pkg_check_modules(_GSSAPI heimdal-gssapi) + endif (PKG_CONFIG_FOUND) + + if (_GSSAPI_FOUND) + set(GSSAPI_FLAVOR_HEIMDAL TRUE) + else() + find_path(_GSSAPI_ROKEN + NAMES + roken.h + PATHS + ${GSSAPI_ROOT_DIR}/include + ${_GSSAPI_INCLUDEDIR}) + if (_GSSAPI_ROKEN) + set(GSSAPI_FLAVOR_HEIMDAL TRUE) + endif() + endif () + endif() +endif (UNIX) + +find_path(GSSAPI_INCLUDE_DIR + NAMES + gssapi.h + gssapi/gssapi.h + PATHS + ${GSSAPI_ROOT_DIR}/include + ${_GSSAPI_INCLUDEDIR} +) + +if (GSSAPI_FLAVOR_MIT) + find_library(GSSAPI_LIBRARY + NAMES + gssapi_krb5 + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + find_library(KRB5_LIBRARY + NAMES + krb5 + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + find_library(K5CRYPTO_LIBRARY + NAMES + k5crypto + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + find_library(COM_ERR_LIBRARY + NAMES + com_err + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + if (GSSAPI_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${GSSAPI_LIBRARY} + ) + endif (GSSAPI_LIBRARY) + + if (KRB5_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${KRB5_LIBRARY} + ) + endif (KRB5_LIBRARY) + + if (K5CRYPTO_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${K5CRYPTO_LIBRARY} + ) + endif (K5CRYPTO_LIBRARY) + + if (COM_ERR_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${COM_ERR_LIBRARY} + ) + endif (COM_ERR_LIBRARY) +endif (GSSAPI_FLAVOR_MIT) + +if (GSSAPI_FLAVOR_HEIMDAL) + find_library(GSSAPI_LIBRARY + NAMES + gssapi + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + find_library(KRB5_LIBRARY + NAMES + krb5 + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + find_library(HCRYPTO_LIBRARY + NAMES + hcrypto + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + find_library(COM_ERR_LIBRARY + NAMES + com_err + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + find_library(HEIMNTLM_LIBRARY + NAMES + heimntlm + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + find_library(HX509_LIBRARY + NAMES + hx509 + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + find_library(ASN1_LIBRARY + NAMES + asn1 + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + find_library(WIND_LIBRARY + NAMES + wind + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + find_library(ROKEN_LIBRARY + NAMES + roken + PATHS + ${GSSAPI_ROOT_DIR}/lib + ${_GSSAPI_LIBDIR} + ) + + if (GSSAPI_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${GSSAPI_LIBRARY} + ) + endif (GSSAPI_LIBRARY) + + if (KRB5_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${KRB5_LIBRARY} + ) + endif (KRB5_LIBRARY) + + if (HCRYPTO_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${HCRYPTO_LIBRARY} + ) + endif (HCRYPTO_LIBRARY) + + if (COM_ERR_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${COM_ERR_LIBRARY} + ) + endif (COM_ERR_LIBRARY) + + if (HEIMNTLM_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${HEIMNTLM_LIBRARY} + ) + endif (HEIMNTLM_LIBRARY) + + if (HX509_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${HX509_LIBRARY} + ) + endif (HX509_LIBRARY) + + if (ASN1_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${ASN1_LIBRARY} + ) + endif (ASN1_LIBRARY) + + if (WIND_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${WIND_LIBRARY} + ) + endif (WIND_LIBRARY) + + if (ROKEN_LIBRARY) + set(GSSAPI_LIBRARIES + ${GSSAPI_LIBRARIES} + ${WIND_LIBRARY} + ) + endif (ROKEN_LIBRARY) +endif (GSSAPI_FLAVOR_HEIMDAL) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GSSAPI DEFAULT_MSG GSSAPI_LIBRARIES GSSAPI_INCLUDE_DIR) + +if (GSSAPI_INCLUDE_DIRS AND GSSAPI_LIBRARIES) + set(GSSAPI_FOUND TRUE) +endif (GSSAPI_INCLUDE_DIRS AND GSSAPI_LIBRARIES) + +# show the GSSAPI_INCLUDE_DIRS and GSSAPI_LIBRARIES variables only in the advanced view +mark_as_advanced(GSSAPI_INCLUDE_DIRS GSSAPI_LIBRARIES) diff --git a/libssh/cmake/Modules/FindNSIS.cmake b/libssh/cmake/Modules/FindNSIS.cmake index 98a17c78..21f80d86 100644 --- a/libssh/cmake/Modules/FindNSIS.cmake +++ b/libssh/cmake/Modules/FindNSIS.cmake @@ -1,14 +1,15 @@ # - Try to find NSIS # Once done this will define # -# NSIS_ROOT_DIR - Set this variable to the root installation of ZLIB +# NSIS_ROOT_PATH - Set this variable to the root installation of NSIS # # Read-Only variables: +# # NSIS_FOUND - system has NSIS # NSIS_MAKE - NSIS creator executable # #============================================================================= -# Copyright (c) 2010-2011 Andreas Schneider +# Copyright (c) 2010-2013 Andreas Schneider # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. @@ -19,21 +20,36 @@ #============================================================================= # -set(_NSIS_ROOT_PATHS - C:/NSIS/Bin - "$ENV{PROGRAMFILES}/NSIS" -) +if (WIN32) + set(_NSIS_ROOT_HINTS + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\NSIS;Default]") + + set(_NSIS_ROOT_PATHS + $ENV{PROGRAMFILES}/NSIS) + + find_path(NSIS_ROOT_PATH + NAMES + Include/Library.nsh + HINTS + ${_NSIS_ROOT_HINTS} + PATHS + ${_NSIS_ROOT_PATHS} + ) + mark_as_advanced(NSIS_ROOT_PATH) +endif (WIN32) find_program(NSIS_MAKE NAMES makensis PATHS ${NSIS_ROOT_PATH} - ${NSIS_ROOT_PATH}/Bin - ${_NSIS_ROOT_PATHS} ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(NSIS DEFAULT_MSG NSIS_MAKE) +if (NSIS_MAKE) + set(NSIS_FOUND TRUE) +endif (NSIS_MAKE) + mark_as_advanced(NSIS_MAKE) diff --git a/libssh/cmake/Modules/UseDoxygen.cmake b/libssh/cmake/Modules/UseDoxygen.cmake index c4ab7ccc..861afa51 100644 --- a/libssh/cmake/Modules/UseDoxygen.cmake +++ b/libssh/cmake/Modules/UseDoxygen.cmake @@ -63,27 +63,27 @@ if(DOXYGEN_FOUND AND DOXYFILE_IN_FOUND) set(DOXYFILE_PDFLATEX FALSE) set(DOXYFILE_DOT FALSE) - find_package(LATEX) - if(LATEX_COMPILER AND MAKEINDEX_COMPILER) - set(DOXYFILE_LATEX TRUE) - usedoxygen_set_default(DOXYFILE_LATEX_DIR "latex") - - set_property(DIRECTORY APPEND PROPERTY - ADDITIONAL_MAKE_CLEAN_FILES - "${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}") - - if(PDFLATEX_COMPILER) - set(DOXYFILE_PDFLATEX TRUE) - endif() - if(DOXYGEN_DOT_EXECUTABLE) - set(DOXYFILE_DOT TRUE) - endif() - - add_custom_command(TARGET doxygen - POST_BUILD - COMMAND ${CMAKE_MAKE_PROGRAM} - WORKING_DIRECTORY "${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}") - endif() + #find_package(LATEX) + #if(LATEX_COMPILER AND MAKEINDEX_COMPILER) + # set(DOXYFILE_LATEX TRUE) + # usedoxygen_set_default(DOXYFILE_LATEX_DIR "latex") + # + # set_property(DIRECTORY APPEND PROPERTY + # ADDITIONAL_MAKE_CLEAN_FILES + # "${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}") + # + # if(PDFLATEX_COMPILER) + # set(DOXYFILE_PDFLATEX TRUE) + # endif() + # if(DOXYGEN_DOT_EXECUTABLE) + # set(DOXYFILE_DOT TRUE) + # endif() + # + # add_custom_command(TARGET doxygen + # POST_BUILD + # COMMAND ${CMAKE_MAKE_PROGRAM} + # WORKING_DIRECTORY "${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}") + #endif() configure_file(${DOXYFILE_IN} ${CMAKE_CURRENT_BINARY_DIR}/doxy.config ESCAPE_QUOTES IMMEDIATE @ONLY) if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/doxy.trac.in) diff --git a/libssh/config.h.cmake b/libssh/config.h.cmake index 2014e8d9..f7f8957f 100644 --- a/libssh/config.h.cmake +++ b/libssh/config.h.cmake @@ -23,6 +23,9 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_TERMIOS_H 1 +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_UNISTD_H 1 + /* Define to 1 if you have the header file. */ #cmakedefine HAVE_OPENSSL_AES_H 1 @@ -106,6 +109,9 @@ /* Define to 1 if you have the `__strtoull' function. */ #cmakedefine HAVE___STRTOULL 1 +/* Define to 1 if you have the `_strtoui64' function. */ +#cmakedefine HAVE__STRTOUI64 1 + /*************************** LIBRARIES ***************************/ /* Define to 1 if you have the `crypto' library (-lcrypto). */ @@ -120,6 +126,14 @@ /**************************** OPTIONS ****************************/ +#cmakedefine HAVE_GCC_THREAD_LOCAL_STORAGE 1 +#cmakedefine HAVE_MSC_THREAD_LOCAL_STORAGE 1 + +#cmakedefine HAVE_GCC_VOLATILE_MEMORY_PROTECTION 1 + +/* Define to 1 if you want to enable GSSAPI */ +#cmakedefine WITH_GSSAPI 1 + /* Define to 1 if you want to enable ZLIB */ #cmakedefine WITH_ZLIB 1 diff --git a/libssh/doc/TracFooter.html b/libssh/doc/TracFooter.html deleted file mode 100644 index 867baf0e..00000000 --- a/libssh/doc/TracFooter.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/libssh/doc/TracHeader.html b/libssh/doc/TracHeader.html deleted file mode 100644 index 280a869b..00000000 --- a/libssh/doc/TracHeader.html +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/libssh/doc/doxy.config.in b/libssh/doc/doxy.config.in index 9810518f..276a2611 100644 --- a/libssh/doc/doxy.config.in +++ b/libssh/doc/doxy.config.in @@ -1,8 +1,10 @@ -# Doxyfile 1.8.2 +# Doxyfile 1.8.4 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # +# All text after a double hash (##) is considered a comment and is placed +# in front of the TAG it is preceding . # All text after a hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] @@ -70,9 +72,9 @@ CREATE_SUBDIRS = NO # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English -# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, -# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, -# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. +# messages), Korean, Korean-en, Latvian, Lithuanian, Norwegian, Macedonian, +# Persian, Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, +# Slovak, Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English @@ -262,10 +264,10 @@ EXTENSION_MAPPING = MARKDOWN_SUPPORT = YES -# When enabled doxygen tries to link words that correspond to documented classes, -# or namespaces to their corresponding documentation. Such a link can be -# prevented in individual cases by by putting a % sign in front of the word or -# globally by setting AUTOLINK_SUPPORT to NO. +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. AUTOLINK_SUPPORT = YES @@ -289,7 +291,12 @@ CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO -# For Microsoft's IDL there are propget and propput attributes to indicate getter and setter methods for a property. Setting this option to YES (the default) will make doxygen replace the get and set methods by a property in the documentation. This will only work if the methods are indeed getting or setting a simple type. If this is not the case, or you want to show the methods anyway, you should set this option to NO. +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES (the +# default) will make doxygen replace the get and set methods by a property in +# the documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES @@ -316,11 +323,11 @@ SUBGROUPING = YES INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and -# unions with only public data fields will be shown inline in the documentation -# of the scope in which they are defined (i.e. file, namespace, or group -# documentation), provided this scope is documented. If set to NO (the default), -# structs, classes, and unions are shown on a separate page (for HTML and Man -# pages) or section (for LaTeX and RTF). +# unions with only public data fields or simple typedef fields will be shown +# inline in the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO (the default), structs, classes, and unions are shown on a separate +# page (for HTML and Man pages) or section (for LaTeX and RTF). INLINE_SIMPLE_STRUCTS = NO @@ -334,30 +341,14 @@ INLINE_SIMPLE_STRUCTS = NO TYPEDEF_HIDES_STRUCT = YES -# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to -# determine which symbols to keep in memory and which to flush to disk. -# When the cache is full, less often used symbols will be written to disk. -# For small to medium size projects (<1000 input files) the default value is -# probably good enough. For larger projects a too small cache size can cause -# doxygen to be busy swapping symbols to and from disk most of the time -# causing a significant performance penalty. -# If the system has enough physical memory increasing the cache will improve the -# performance by keeping more symbols in memory. Note that the value works on -# a logarithmic scale so increasing the size by one will roughly double the -# memory usage. The cache size is given by this formula: -# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols. - -SYMBOL_CACHE_SIZE = 0 - -# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be -# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given -# their name and scope. Since this can be an expensive process and often the -# same symbol appear multiple times in the code, doxygen keeps a cache of -# pre-resolved symbols. If the cache is too small doxygen will become slower. -# If the cache is too large, memory is wasted. The cache size is given by this -# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols. +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can +# be an expensive process and often the same symbol appear multiple times in +# the code, doxygen keeps a cache of pre-resolved symbols. If the cache is too +# small doxygen will become slower. If the cache is too large, memory is wasted. +# The cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid +# range is 0..9, the default is 0, corresponding to a cache size of 2^16 = 65536 +# symbols. LOOKUP_CACHE_SIZE = 0 @@ -368,7 +359,7 @@ LOOKUP_CACHE_SIZE = 0 # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES +# the EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO @@ -549,7 +540,8 @@ GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. +# documentation sections, marked by \if section-label ... \endif +# and \cond section-label ... \endcond blocks. ENABLED_SECTIONS = @@ -607,7 +599,8 @@ LAYOUT_FILE = # requires the bibtex tool to be installed. See also # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this -# feature you need bibtex and perl available in the search path. +# feature you need bibtex and perl available in the search path. Do not use +# file names with spaces, bibtex cannot handle them. CITE_BIB_FILES = @@ -776,8 +769,10 @@ IMAGE_PATH = # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. -# If FILTER_PATTERNS is specified, this tag will be -# ignored. +# If FILTER_PATTERNS is specified, this tag will be ignored. +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. INPUT_FILTER = @@ -806,6 +801,13 @@ FILTER_SOURCE_FILES = NO FILTER_SOURCE_PATTERNS = +# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- @@ -947,7 +949,7 @@ HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the -# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that # the files will be copied as-is; there are no commands or markers available. @@ -1215,6 +1217,13 @@ FORMULA_TRANSPARENT = YES USE_MATHJAX = NO +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and +# SVG. The default value is HTML-CSS, which is slower, but has the best +# compatibility. + +MATHJAX_FORMAT = HTML-CSS + # When MathJax is enabled you need to specify the location relative to the # HTML output directory using the MATHJAX_RELPATH option. The destination # directory should contain the MathJax.js script. For instance, if the mathjax @@ -1232,6 +1241,11 @@ MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest MATHJAX_EXTENSIONS = +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript +# pieces of code that will be used on startup of the MathJax code. + +MATHJAX_CODEFILE = + # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using @@ -1243,15 +1257,55 @@ MATHJAX_EXTENSIONS = SEARCHENGINE = NO # When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a PHP enabled web server instead of at the web client -# using Javascript. Doxygen will generate the search PHP script and index -# file to put on the web server. The advantage of the server -# based approach is that it scales better to large projects and allows -# full text search. The disadvantages are that it is more difficult to setup -# and does not have live searching capabilities. +# implemented using a web server instead of a web client using Javascript. +# There are two flavours of web server based search depending on the +# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for +# searching and an index file used by the script. When EXTERNAL_SEARCH is +# enabled the indexing and searching needs to be provided by external tools. +# See the manual for details. SERVER_BASED_SEARCH = NO +# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain +# the search results. Doxygen ships with an example indexer (doxyindexer) and +# search engine (doxysearch.cgi) which are based on the open source search +# engine library Xapian. See the manual for configuration details. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will returned the search results when EXTERNAL_SEARCH is enabled. +# Doxygen ships with an example search engine (doxysearch) which is based on +# the open source search engine library Xapian. See the manual for configuration +# details. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id +# of to a relative location where the documentation can be found. +# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ... + +EXTRA_SEARCH_MAPPINGS = + #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- @@ -1259,7 +1313,7 @@ SERVER_BASED_SEARCH = NO # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. -GENERATE_LATEX = @DOXYFILE_LATEX@ +GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be @@ -1289,7 +1343,7 @@ COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, letter, legal and -# executive. If left blank a4wide will be used. +# executive. If left blank a4 will be used. PAPER_TYPE = a4 @@ -1312,6 +1366,13 @@ LATEX_HEADER = LATEX_FOOTER = +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images +# or other source files which should be copied to the LaTeX output directory. +# Note that the files will be copied as-is; there are no commands or markers +# available. + +LATEX_EXTRA_FILES = + # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references @@ -1456,6 +1517,21 @@ XML_DTD = XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES Doxygen will generate DOCBOOK files +# that can be used to generate PDF. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the DOCBOOK pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. If left blank docbook will be used as the default path. + +DOCBOOK_OUTPUT = docbook + #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- @@ -1605,6 +1681,12 @@ ALLEXTERNALS = YES EXTERNAL_GROUPS = YES +# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed +# in the related pages index. If set to NO, only the current project's +# pages will be listed. + +EXTERNAL_PAGES = YES + # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). @@ -1659,7 +1741,7 @@ DOT_NUM_THREADS = 0 # the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the # directory containing the font. -DOT_FONTNAME = FreeSans +DOT_FONTNAME = # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. @@ -1701,7 +1783,7 @@ UML_LOOK = NO # the class node. If there are many fields or methods and many nodes the # graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS # threshold limits the number of items for each type to make the size more -# managable. Set this to 0 for no limit. Note that the threshold may be +# manageable. Set this to 0 for no limit. Note that the threshold may be # exceeded by 50% before the limit is enforced. UML_LIMIT_NUM_FIELDS = 10 diff --git a/libssh/doc/linking.dox b/libssh/doc/linking.dox index 16dfab98..8cbc415c 100644 --- a/libssh/doc/linking.dox +++ b/libssh/doc/linking.dox @@ -17,8 +17,14 @@ On UNIX systems linking against the static version of the library is the same as linking against the shared library. Both have the same name. Some build system require to use the full path to the static library. -On Windows you need to define LIBSSH_STATIC in the compiler command -line. This is required cause the dynamic library needs to specify the -dllimport attribute. +To be able to compile the application you're developing you need to either pass +LIBSSH_STATIC as a define in the compiler command line or define it before you +include libssh.h. This is required cause the dynamic library needs to specify +the dllimport attribute. + +@code +#define LIBSSH_STATIC 1 +#include +@endcode */ diff --git a/libssh/doc/mainpage.dox b/libssh/doc/mainpage.dox index fc65e413..5fb695a6 100644 --- a/libssh/doc/mainpage.dox +++ b/libssh/doc/mainpage.dox @@ -19,24 +19,29 @@ the interesting functions as you go. The libssh library provides: - - Full C library functions for manipulating a client-side SSH connection - - SSH2 and SSH1 protocol compliant - - Fully configurable sessions - - Server support - - SSH agent authentication support - - Support for AES-128, AES-192, AES-256, Blowfish, 3DES in CBC mode, and AES in CTR mode - - Supports OpenSSL and GCrypt - - Use multiple SSH connections in a same process, at same time - - Use multiple channels in the same connection - - Thread safety when using different sessions at same time - - POSIX-like SFTP (Secure File Transfer) implementation with openssh extension support - - SCP implementation - - Large file system support (files bigger than 4GB) - - RSA and DSS server public key supported - - Compression support (with zlib) - - Public key (RSA and DSS), password and keyboard-interactive authentication - - Full poll()/WSAPoll() support and a poll-emulation for Win32. - - Runs and tested under x86_64, x86, ARM, Sparc32, PPC under Linux, BSD, MacOSX, Solaris and Windows + - Key Exchange Methods: ecdh-sha2-nistp256, diffie-hellman-group1-sha1, diffie-hellman-group14-sha1 + - Hostkey Types: ecdsa-sha2-nistp256, ssh-dss, ssh-rsa + - Ciphers: aes256-ctr, aes192-ctr, aes128-ctr, aes256-cbc (rijndael-cbc@lysator.liu.se), aes192-cbc, aes128-cbc, 3des-cbc, des-cbc-ssh1, blowfish-cbc, none + - Compression Schemes: zlib, zlib@openssh.com, none + - MAC hashes: hmac-sha1, none + - Authentication: none, password, public-key, hostbased, keyboard-interactive, gssapi-with-mic + - Channels: shell, exec (incl. SCP wrapper), direct-tcpip, subsystem, auth-agent-req@openssh.com + - Global Requests: tcpip-forward, forwarded-tcpip + - Channel Requests: x11, pty, exit-status, signal, exit-signal, keepalive@openssh.com, auth-agent-req@openssh.com + - Subsystems: sftp(version 3), publickey(version 2), OpenSSH Extensions + - SFTP: statvfs@openssh.com, fstatvfs@openssh.com + - Thread-safe: Just don't share sessions + - Non-blocking: it can be used both blocking and non-blocking + - Your sockets: the app hands over the socket, or uses libssh sockets + - OpenSSL or gcrypt: builds with either + +@section main-additional-features Additional Features + + - Client and server support + - SSHv2 and SSHv1 protocol support + - Supports Linux, UNIX, BSD, Solaris, OS/2 and Windows + - Automated test cases with nightly tests + - Event model based on poll(2), or a poll(2)-emulation. @section main-copyright Copyright Policy diff --git a/libssh/examples/CMakeLists.txt b/libssh/examples/CMakeLists.txt index 5513b758..fc1c9341 100644 --- a/libssh/examples/CMakeLists.txt +++ b/libssh/examples/CMakeLists.txt @@ -11,38 +11,52 @@ include_directories( ${CMAKE_BINARY_DIR} ) -if (LINUX) +if (BSD OR SOLARIS) + find_package(Argp) +endif (BSD OR SOLARIS) + +if (UNIX AND NOT WIN32) add_executable(libssh_scp libssh_scp.c ${examples_SRCS}) target_link_libraries(libssh_scp ${LIBSSH_SHARED_LIBRARY}) add_executable(scp_download scp_download.c ${examples_SRCS}) target_link_libraries(scp_download ${LIBSSH_SHARED_LIBRARY}) - add_executable(samplessh sample.c ${examples_SRCS}) - target_link_libraries(samplessh ${LIBSSH_SHARED_LIBRARY}) - add_executable(sshnetcat sshnetcat.c ${examples_SRCS}) target_link_libraries(sshnetcat ${LIBSSH_SHARED_LIBRARY}) + if (WITH_SERVER) + if (HAVE_LIBUTIL) + add_executable(samplesshd-tty samplesshd-tty.c) + target_link_libraries(samplesshd-tty ${LIBSSH_SHARED_LIBRARY} util) + endif (HAVE_LIBUTIL) + endif (WITH_SERVER) + if (WITH_SFTP) add_executable(samplesftp samplesftp.c ${examples_SRCS}) target_link_libraries(samplesftp ${LIBSSH_SHARED_LIBRARY}) endif (WITH_SFTP) + add_executable(samplessh sample.c ${examples_SRCS}) + target_link_libraries(samplessh ${LIBSSH_SHARED_LIBRARY}) + if (WITH_SERVER) add_executable(samplesshd samplesshd.c) - target_link_libraries(samplesshd ${LIBSSH_SHARED_LIBRARY}) + target_link_libraries(samplesshd ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARIES}) + + if (WITH_GSSAPI AND GSSAPI_FOUND) + add_executable(samplesshd-cb samplesshd-cb.c) + target_link_libraries(samplesshd-cb ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARIES}) + + add_executable(proxy proxy.c) + target_link_libraries(proxy ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARIES}) + endif (WITH_GSSAPI AND GSSAPI_FOUND) add_executable(samplesshd-kbdint samplesshd-kbdint.c) - target_link_libraries(samplesshd-kbdint ${LIBSSH_SHARED_LIBRARY}) - - if (HAVE_LIBUTIL) - add_executable(samplesshd-tty samplesshd-tty.c) - target_link_libraries(samplesshd-tty ${LIBSSH_SHARED_LIBRARY} util) - endif (HAVE_LIBUTIL) + target_link_libraries(samplesshd-kbdint ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARIES}) endif (WITH_SERVER) -endif (LINUX) +endif (UNIX AND NOT WIN32) add_executable(exec exec.c ${examples_SRCS}) target_link_libraries(exec ${LIBSSH_SHARED_LIBRARY}) diff --git a/libssh/examples/authentication.c b/libssh/examples/authentication.c index 0e749e54..ab5e64d6 100644 --- a/libssh/examples/authentication.c +++ b/libssh/examples/authentication.c @@ -118,6 +118,15 @@ int authenticate_console(ssh_session session){ method = ssh_auth_list(session); while (rc != SSH_AUTH_SUCCESS) { + if (method & SSH_AUTH_METHOD_GSSAPI_MIC){ + rc = ssh_userauth_gssapi(session); + if(rc == SSH_AUTH_ERROR) { + error(session); + return rc; + } else if (rc == SSH_AUTH_SUCCESS) { + break; + } + } // Try to authenticate with public key first if (method & SSH_AUTH_METHOD_PUBLICKEY) { rc = ssh_userauth_autopubkey(session, NULL); diff --git a/libssh/examples/libssh_scp.c b/libssh/examples/libssh_scp.c index b7471da6..99281db8 100644 --- a/libssh/examples/libssh_scp.c +++ b/libssh/examples/libssh_scp.c @@ -84,9 +84,15 @@ static int opts(int argc, char **argv){ } static struct location *parse_location(char *loc){ - struct location *location=malloc(sizeof(struct location)); + struct location *location; char *ptr; + location = malloc(sizeof(struct location)); + if (location == NULL) { + return NULL; + } + memset(location, 0, sizeof(struct location)); + location->host=location->user=NULL; ptr=strchr(loc,':'); if(ptr != NULL){ @@ -123,6 +129,7 @@ static int open_location(struct location *loc, int flag){ if(ssh_scp_init(loc->scp)==SSH_ERROR){ fprintf(stderr,"error : %s\n",ssh_get_error(loc->session)); ssh_scp_free(loc->scp); + loc->scp = NULL; return -1; } return 0; @@ -140,6 +147,7 @@ static int open_location(struct location *loc, int flag){ if(ssh_scp_init(loc->scp)==SSH_ERROR){ fprintf(stderr,"error : %s\n",ssh_get_error(loc->session)); ssh_scp_free(loc->scp); + loc->scp = NULL; return -1; } return 0; @@ -184,7 +192,10 @@ static int do_copy(struct location *src, struct location *dest, int recursive){ fprintf(stderr, "Invalid file pointer, error: %s\n", strerror(errno)); return -1; } - fstat(fd,&s); + r = fstat(fd, &s); + if (r < 0) { + return -1; + } size=s.st_size; mode = s.st_mode & ~S_IFMT; filename=ssh_basename(src->path); diff --git a/libssh/examples/proxy.c b/libssh/examples/proxy.c new file mode 100644 index 00000000..dcf4d0d7 --- /dev/null +++ b/libssh/examples/proxy.c @@ -0,0 +1,347 @@ +/* This is a sample implementation of a libssh based SSH proxy */ +/* +Copyright 2003-2013 Aris Adamantiadis + +This file is part of the SSH Library + +You are free to copy this file, modify it in any way, consider it being public +domain. This does not apply to the rest of the library though, but it is +allowed to cut-and-paste working code from this file to any license of +program. +The goal is to show the API in action. It's not a reference on how terminal +clients must be made or how a client should react. +*/ + +#include "config.h" + +#include +#include +#include + +#ifdef HAVE_ARGP_H +#include +#endif +#include +#include +#include + +#define USER "myuser" +#define PASSWORD "mypassword" + +static int authenticated=0; +static int tries = 0; +static int error = 0; +static ssh_channel chan=NULL; +static char *username; +static ssh_gssapi_creds client_creds = NULL; + +static int auth_password(ssh_session session, const char *user, + const char *password, void *userdata){ + + (void)userdata; + + printf("Authenticating user %s pwd %s\n",user, password); + if(strcmp(user,USER) == 0 && strcmp(password, PASSWORD) == 0){ + authenticated = 1; + printf("Authenticated\n"); + return SSH_AUTH_SUCCESS; + } + if (tries >= 3){ + printf("Too many authentication tries\n"); + ssh_disconnect(session); + error = 1; + return SSH_AUTH_DENIED; + } + tries++; + return SSH_AUTH_DENIED; +} + +static int auth_gssapi_mic(ssh_session session, const char *user, const char *principal, void *userdata){ + (void)userdata; + client_creds = ssh_gssapi_get_creds(session); + printf("Authenticating user %s with gssapi principal %s\n",user, principal); + if (client_creds != NULL) + printf("Received some gssapi credentials\n"); + else + printf("Not received any forwardable creds\n"); + printf("authenticated\n"); + authenticated = 1; + username = strdup(principal); + return SSH_AUTH_SUCCESS; +} + +static int pty_request(ssh_session session, ssh_channel channel, const char *term, + int x,int y, int px, int py, void *userdata){ + (void) session; + (void) channel; + (void) term; + (void) x; + (void) y; + (void) px; + (void) py; + (void) userdata; + printf("Allocated terminal\n"); + return 0; +} + +static int shell_request(ssh_session session, ssh_channel channel, void *userdata){ + (void)session; + (void)channel; + (void)userdata; + printf("Allocated shell\n"); + return 0; +} +struct ssh_channel_callbacks_struct channel_cb = { + .channel_pty_request_function = pty_request, + .channel_shell_request_function = shell_request +}; + +static ssh_channel new_session_channel(ssh_session session, void *userdata){ + (void) session; + (void) userdata; + if(chan != NULL) + return NULL; + printf("Allocated session channel\n"); + chan = ssh_channel_new(session); + ssh_callbacks_init(&channel_cb); + ssh_set_channel_callbacks(chan, &channel_cb); + return chan; +} + + +#ifdef HAVE_ARGP_H +const char *argp_program_version = "libssh proxy example " +SSH_STRINGIFY(LIBSSH_VERSION); +const char *argp_program_bug_address = ""; + +/* Program documentation. */ +static char doc[] = "libssh -- a Secure Shell protocol implementation"; + +/* A description of the arguments we accept. */ +static char args_doc[] = "BINDADDR"; + +/* The options we understand. */ +static struct argp_option options[] = { + { + .name = "port", + .key = 'p', + .arg = "PORT", + .flags = 0, + .doc = "Set the port to bind.", + .group = 0 + }, + { + .name = "hostkey", + .key = 'k', + .arg = "FILE", + .flags = 0, + .doc = "Set the host key.", + .group = 0 + }, + { + .name = "dsakey", + .key = 'd', + .arg = "FILE", + .flags = 0, + .doc = "Set the dsa key.", + .group = 0 + }, + { + .name = "rsakey", + .key = 'r', + .arg = "FILE", + .flags = 0, + .doc = "Set the rsa key.", + .group = 0 + }, + { + .name = "verbose", + .key = 'v', + .arg = NULL, + .flags = 0, + .doc = "Get verbose output.", + .group = 0 + }, + {NULL, 0, NULL, 0, NULL, 0} +}; + +/* Parse a single option. */ +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. + */ + ssh_bind sshbind = state->input; + + switch (key) { + case 'p': + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg); + break; + case 'd': + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, arg); + break; + case 'k': + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg); + break; + case 'r': + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, arg); + break; + case 'v': + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "3"); + break; + case ARGP_KEY_ARG: + if (state->arg_num >= 1) { + /* Too many arguments. */ + argp_usage (state); + } + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, arg); + break; + case ARGP_KEY_END: + if (state->arg_num < 1) { + /* Not enough arguments. */ + argp_usage (state); + } + break; + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; +} + +/* Our argp parser. */ +static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL}; +#endif /* HAVE_ARGP_H */ + +int main(int argc, char **argv){ + ssh_session session; + ssh_bind sshbind; + ssh_event mainloop; + ssh_session client_session; + + struct ssh_server_callbacks_struct cb = { + .userdata = NULL, + .auth_password_function = auth_password, + .auth_gssapi_mic_function = auth_gssapi_mic, + .channel_open_request_session_function = new_session_channel + }; + + char buf[2048]; + char host[128]=""; + char *ptr; + int i,r, rc; + + sshbind=ssh_bind_new(); + session=ssh_new(); + + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, "sshd_rsa"); + +#ifdef HAVE_ARGP_H + /* + * Parse our arguments; every option seen by parse_opt will + * be reflected in arguments. + */ + argp_parse (&argp, argc, argv, 0, 0, sshbind); +#else + (void) argc; + (void) argv; +#endif + + if(ssh_bind_listen(sshbind)<0){ + printf("Error listening to socket: %s\n",ssh_get_error(sshbind)); + return 1; + } + r=ssh_bind_accept(sshbind,session); + if(r==SSH_ERROR){ + printf("error accepting a connection : %s\n",ssh_get_error(sshbind)); + return 1; + } + ssh_callbacks_init(&cb); + ssh_set_server_callbacks(session, &cb); + + if (ssh_handle_key_exchange(session)) { + printf("ssh_handle_key_exchange: %s\n", ssh_get_error(session)); + return 1; + } + ssh_set_auth_methods(session,SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_GSSAPI_MIC); + mainloop = ssh_event_new(); + ssh_event_add_session(mainloop, session); + + while (!(authenticated && chan != NULL)){ + if(error) + break; + r = ssh_event_dopoll(mainloop, -1); + if (r == SSH_ERROR){ + printf("Error : %s\n",ssh_get_error(session)); + ssh_disconnect(session); + return 1; + } + } + if(error){ + printf("Error, exiting loop\n"); + return 1; + } else + printf("Authenticated and got a channel\n"); + if (!client_creds){ + snprintf(buf,sizeof(buf), "Sorry, but you do not have forwardable tickets. Try again with -K\r\n"); + ssh_channel_write(chan,buf,strlen(buf)); + printf("%s",buf); + ssh_disconnect(session); + return 1; + } + snprintf(buf,sizeof(buf), "Hello %s, welcome to the Sample SSH proxy.\r\nPlease select your destination: ", username); + ssh_channel_write(chan, buf, strlen(buf)); + do{ + i=ssh_channel_read(chan,buf, 2048, 0); + if(i>0) { + ssh_channel_write(chan, buf, i); + if(strlen(host) + i < sizeof(host)){ + strncat(host, buf, i); + } + if (strchr(host, '\x0d')) { + *strchr(host, '\x0d')='\0'; + ssh_channel_write(chan, "\n", 1); + break; + } + } else { + printf ("Error: %s\n", ssh_get_error(session) ); + return 1; + } + } while (i>0); + snprintf(buf,sizeof(buf),"Trying to connect to \"%s\"\r\n", host); + ssh_channel_write(chan, buf, strlen(buf)); + printf("%s",buf); + + client_session = ssh_new(); + + /* ssh servers expect username without realm */ + ptr = strchr(username,'@'); + if(ptr) + *ptr= '\0'; + ssh_options_set(client_session, SSH_OPTIONS_HOST, host); + ssh_options_set(client_session, SSH_OPTIONS_USER, username); + ssh_gssapi_set_creds(client_session, client_creds); + rc = ssh_connect(client_session); + if (rc != SSH_OK){ + printf("Error connecting to %s: %s", host, ssh_get_error(client_session)); + return 1; + } + rc = ssh_userauth_none(client_session, NULL); + if(rc == SSH_AUTH_SUCCESS){ + printf("Authenticated using method none\n"); + } else { + rc = ssh_userauth_gssapi(client_session); + if(rc != SSH_AUTH_SUCCESS){ + printf("GSSAPI Authentication failed: %s\n",ssh_get_error(client_session)); + return 1; + } + } + snprintf(buf,sizeof(buf), "Authentication success\r\n"); + printf("%s",buf); + ssh_channel_write(chan,buf,strlen(buf)); + ssh_disconnect(client_session); + ssh_disconnect(session); + ssh_bind_free(sshbind); + ssh_finalize(); + return 0; +} + diff --git a/libssh/examples/sample.c b/libssh/examples/sample.c index 93634d80..616372cb 100644 --- a/libssh/examples/sample.c +++ b/libssh/examples/sample.c @@ -14,24 +14,31 @@ clients must be made or how a client should react. #include "config.h" #include -#include #include #include -#include #include #include + +#ifdef HAVE_TERMIOS_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif #ifdef HAVE_PTY_H #include #endif + #include #include #include +#include + #include #include #include -#include #include "examples_common.h" #define MAXCMD 10 @@ -229,8 +236,6 @@ static void select_loop(ssh_session session,ssh_channel channel){ // we already looked for input from stdin. Now, we are looking for input from the channel if(channel && ssh_channel_is_closed(channel)){ - ssh_log(session,SSH_LOG_RARE,"exit-status : %d",ssh_channel_get_exit_status(channel)); - ssh_channel_free(channel); channel=NULL; channels[0]=NULL; @@ -244,9 +249,6 @@ static void select_loop(ssh_session session,ssh_channel channel){ return; } if(lus==0){ - ssh_log(session,SSH_LOG_RARE,"EOF received"); - ssh_log(session,SSH_LOG_RARE,"exit-status : %d",ssh_channel_get_exit_status(channel)); - ssh_channel_free(channel); channel=channels[0]=NULL; } else @@ -263,8 +265,6 @@ static void select_loop(ssh_session session,ssh_channel channel){ return; } if(lus==0){ - ssh_log(session,SSH_LOG_RARE,"EOF received"); - ssh_log(session,SSH_LOG_RARE,"exit-status : %d",ssh_channel_get_exit_status(channel)); ssh_channel_free(channel); channel=channels[0]=NULL; } else @@ -322,8 +322,6 @@ static void select_loop(ssh_session session,ssh_channel channel){ } } if(channel && ssh_channel_is_closed(channel)){ - ssh_log(session,SSH_LOG_RARE,"exit-status : %d",ssh_channel_get_exit_status(channel)); - ssh_channel_free(channel); channel=NULL; channels[0]=NULL; @@ -337,9 +335,6 @@ static void select_loop(ssh_session session,ssh_channel channel){ return; } if(lus==0){ - ssh_log(session,SSH_LOG_RARE,"EOF received"); - ssh_log(session,SSH_LOG_RARE,"exit-status : %d",ssh_channel_get_exit_status(channel)); - ssh_channel_free(channel); channel=channels[0]=NULL; } else @@ -356,8 +351,6 @@ static void select_loop(ssh_session session,ssh_channel channel){ return; } if(lus==0){ - ssh_log(session,SSH_LOG_RARE,"EOF received"); - ssh_log(session,SSH_LOG_RARE,"exit-status : %d",ssh_channel_get_exit_status(channel)); ssh_channel_free(channel); channel=channels[0]=NULL; } else @@ -461,7 +454,6 @@ static int client(ssh_session session){ if(auth != SSH_AUTH_SUCCESS){ return -1; } - ssh_log(session, SSH_LOG_FUNCTIONS, "Authentication success"); if(!cmds[0]) shell(session); else diff --git a/libssh/examples/samplesftp.c b/libssh/examples/samplesftp.c index 968624e8..457e60a4 100644 --- a/libssh/examples/samplesftp.c +++ b/libssh/examples/samplesftp.c @@ -15,11 +15,13 @@ clients must be made or how a client should react. #include #include -#include #include #include #include #include +#ifdef HAVE_UNISTD_H +#include +#endif #include #include diff --git a/libssh/examples/samplesshd-cb.c b/libssh/examples/samplesshd-cb.c new file mode 100644 index 00000000..f93ab4b4 --- /dev/null +++ b/libssh/examples/samplesshd-cb.c @@ -0,0 +1,306 @@ +/* This is a sample implementation of a libssh based SSH server */ +/* +Copyright 2003-2009 Aris Adamantiadis + +This file is part of the SSH Library + +You are free to copy this file, modify it in any way, consider it being public +domain. This does not apply to the rest of the library though, but it is +allowed to cut-and-paste working code from this file to any license of +program. +The goal is to show the API in action. It's not a reference on how terminal +clients must be made or how a client should react. +*/ + +#include "config.h" + +#include +#include +#include + +#ifdef HAVE_ARGP_H +#include +#endif +#include +#include +#include + +#ifndef KEYS_FOLDER +#ifdef _WIN32 +#define KEYS_FOLDER +#else +#define KEYS_FOLDER "/etc/ssh/" +#endif +#endif + +#define USER "myuser" +#define PASSWORD "mypassword" + +static int authenticated=0; +static int tries = 0; +static int error = 0; +static ssh_channel chan=NULL; + +static int auth_password(ssh_session session, const char *user, + const char *password, void *userdata){ + (void)userdata; + printf("Authenticating user %s pwd %s\n",user, password); + if(strcmp(user,USER) == 0 && strcmp(password, PASSWORD) == 0){ + authenticated = 1; + printf("Authenticated\n"); + return SSH_AUTH_SUCCESS; + } + if (tries >= 3){ + printf("Too many authentication tries\n"); + ssh_disconnect(session); + error = 1; + return SSH_AUTH_DENIED; + } + tries++; + return SSH_AUTH_DENIED; +} + +static int auth_gssapi_mic(ssh_session session, const char *user, const char *principal, 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("Received some gssapi credentials\n"); + else + printf("Not received any forwardable creds\n"); + printf("authenticated\n"); + authenticated = 1; + return SSH_AUTH_SUCCESS; +} + +static int pty_request(ssh_session session, ssh_channel channel, const char *term, + int x,int y, int px, int py, void *userdata){ + (void) session; + (void) channel; + (void) term; + (void) x; + (void) y; + (void) px; + (void) py; + (void) userdata; + printf("Allocated terminal\n"); + return 0; +} + +static int shell_request(ssh_session session, ssh_channel channel, void *userdata){ + (void)session; + (void)channel; + (void)userdata; + printf("Allocated shell\n"); + return 0; +} +struct ssh_channel_callbacks_struct channel_cb = { + .channel_pty_request_function = pty_request, + .channel_shell_request_function = shell_request +}; + +static ssh_channel new_session_channel(ssh_session session, void *userdata){ + (void) session; + (void) userdata; + if(chan != NULL) + return NULL; + printf("Allocated session channel\n"); + chan = ssh_channel_new(session); + ssh_callbacks_init(&channel_cb); + ssh_set_channel_callbacks(chan, &channel_cb); + return chan; +} + + +#ifdef HAVE_ARGP_H +const char *argp_program_version = "libssh server example " +SSH_STRINGIFY(LIBSSH_VERSION); +const char *argp_program_bug_address = ""; + +/* Program documentation. */ +static char doc[] = "libssh -- a Secure Shell protocol implementation"; + +/* A description of the arguments we accept. */ +static char args_doc[] = "BINDADDR"; + +/* The options we understand. */ +static struct argp_option options[] = { + { + .name = "port", + .key = 'p', + .arg = "PORT", + .flags = 0, + .doc = "Set the port to bind.", + .group = 0 + }, + { + .name = "hostkey", + .key = 'k', + .arg = "FILE", + .flags = 0, + .doc = "Set the host key.", + .group = 0 + }, + { + .name = "dsakey", + .key = 'd', + .arg = "FILE", + .flags = 0, + .doc = "Set the dsa key.", + .group = 0 + }, + { + .name = "rsakey", + .key = 'r', + .arg = "FILE", + .flags = 0, + .doc = "Set the rsa key.", + .group = 0 + }, + { + .name = "verbose", + .key = 'v', + .arg = NULL, + .flags = 0, + .doc = "Get verbose output.", + .group = 0 + }, + {NULL, 0, NULL, 0, NULL, 0} +}; + +/* Parse a single option. */ +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. + */ + ssh_bind sshbind = state->input; + + switch (key) { + case 'p': + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg); + break; + case 'd': + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, arg); + break; + case 'k': + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg); + break; + case 'r': + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, arg); + break; + case 'v': + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "3"); + break; + case ARGP_KEY_ARG: + if (state->arg_num >= 1) { + /* Too many arguments. */ + argp_usage (state); + } + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, arg); + break; + case ARGP_KEY_END: + if (state->arg_num < 1) { + /* Not enough arguments. */ + argp_usage (state); + } + break; + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; +} + +/* Our argp parser. */ +static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL}; +#endif /* HAVE_ARGP_H */ + +int main(int argc, char **argv){ + ssh_session session; + ssh_bind sshbind; + ssh_event mainloop; + struct ssh_server_callbacks_struct cb = { + .userdata = NULL, + .auth_password_function = auth_password, + .auth_gssapi_mic_function = auth_gssapi_mic, + .channel_open_request_session_function = new_session_channel + }; + + char buf[2048]; + int i; + int r; + + sshbind=ssh_bind_new(); + session=ssh_new(); + + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, KEYS_FOLDER "ssh_host_dsa_key"); + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, KEYS_FOLDER "ssh_host_rsa_key"); + +#ifdef HAVE_ARGP_H + /* + * Parse our arguments; every option seen by parse_opt will + * be reflected in arguments. + */ + argp_parse (&argp, argc, argv, 0, 0, sshbind); +#else + (void) argc; + (void) argv; +#endif + + if(ssh_bind_listen(sshbind)<0){ + printf("Error listening to socket: %s\n",ssh_get_error(sshbind)); + return 1; + } + r=ssh_bind_accept(sshbind,session); + if(r==SSH_ERROR){ + printf("error accepting a connection : %s\n",ssh_get_error(sshbind)); + return 1; + } + ssh_callbacks_init(&cb); + ssh_set_server_callbacks(session, &cb); + + if (ssh_handle_key_exchange(session)) { + printf("ssh_handle_key_exchange: %s\n", ssh_get_error(session)); + return 1; + } + ssh_set_auth_methods(session,SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_GSSAPI_MIC); + mainloop = ssh_event_new(); + ssh_event_add_session(mainloop, session); + + while (!(authenticated && chan != NULL)){ + if(error) + break; + r = ssh_event_dopoll(mainloop, -1); + if (r == SSH_ERROR){ + printf("Error : %s\n",ssh_get_error(session)); + ssh_disconnect(session); + return 1; + } + } + if(error){ + printf("Error, exiting loop\n"); + } else + printf("Authenticated and got a channel\n"); + do{ + i=ssh_channel_read(chan,buf, 2048, 0); + if(i>0) { + ssh_channel_write(chan, buf, i); + if (write(1,buf,i) < 0) { + printf("error writing to buffer\n"); + return 1; + } + if (buf[0] == '\x0d') { + if (write(1, "\n", 1) < 0) { + printf("error writing to buffer\n"); + return 1; + } + ssh_channel_write(chan, "\n", 1); + } + } + } while (i>0); + ssh_disconnect(session); + ssh_bind_free(sshbind); + ssh_finalize(); + return 0; +} + diff --git a/libssh/examples/samplesshd-kbdint.c b/libssh/examples/samplesshd-kbdint.c index faecfd9b..5c2c461e 100644 --- a/libssh/examples/samplesshd-kbdint.c +++ b/libssh/examples/samplesshd-kbdint.c @@ -35,6 +35,8 @@ clients must be made or how a client should react. #endif #endif +static int port = 22; + #ifdef WITH_PCAP static const char *pcap_file = "debug.server.pcap"; static ssh_pcap_file pcap; @@ -77,8 +79,6 @@ static char doc[] = "libssh -- a Secure Shell protocol implementation"; /* A description of the arguments we accept. */ static char args_doc[] = "BINDADDR"; -static int port = 22; - /* The options we understand. */ static struct argp_option options[] = { { diff --git a/libssh/examples/samplesshd-tty.c b/libssh/examples/samplesshd-tty.c index a0e79e43..7ed70d3d 100644 --- a/libssh/examples/samplesshd-tty.c +++ b/libssh/examples/samplesshd-tty.c @@ -286,7 +286,7 @@ static int main_loop(ssh_channel chan) { pid_t childpid; ssh_event event; short events; - + int rc; childpid = forkpty(&fd, NULL, term, win); if(childpid == 0) { @@ -318,7 +318,13 @@ static int main_loop(ssh_channel chan) { } do { - ssh_event_dopoll(event, 1000); + rc = ssh_event_dopoll(event, 1000); + if (rc == SSH_ERROR){ + fprintf(stderr, "Error : %s\n", ssh_get_error(session)); + ssh_event_free(event); + ssh_disconnect(session); + return -1; + } } while(!ssh_channel_is_closed(chan)); ssh_event_remove_fd(event, fd); diff --git a/libssh/examples/sshnetcat.c b/libssh/examples/sshnetcat.c index cad777bb..052cabf4 100644 --- a/libssh/examples/sshnetcat.c +++ b/libssh/examples/sshnetcat.c @@ -13,10 +13,14 @@ clients must be made or how a client should react. #include "config.h" #include -#include #include #include +#ifdef HAVE_TERMIOS_H #include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif #include #include @@ -105,8 +109,6 @@ static void select_loop(ssh_session session,ssh_channel channel){ } } if(channel && channel_is_closed(channel)){ - ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",channel_get_exit_status(channel)); - channel_free(channel); channel=NULL; channels[0]=NULL; @@ -120,9 +122,6 @@ static void select_loop(ssh_session session,ssh_channel channel){ return; } if(lus==0){ - ssh_log(session,SSH_LOG_RARE,"EOF received\n"); - ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",channel_get_exit_status(channel)); - channel_free(channel); channel=channels[0]=NULL; } else { @@ -142,8 +141,6 @@ static void select_loop(ssh_session session,ssh_channel channel){ return; } if(lus==0){ - ssh_log(session,SSH_LOG_RARE,"EOF received\n"); - ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",channel_get_exit_status(channel)); channel_free(channel); channel=channels[0]=NULL; } else @@ -202,7 +199,6 @@ static int client(ssh_session session){ if(auth != SSH_AUTH_SUCCESS){ return -1; } - ssh_log(session, SSH_LOG_FUNCTIONS, "Authentication success"); forwarding(session); return 0; } diff --git a/libssh/include/libssh/agent.h b/libssh/include/libssh/agent.h index 4641c9e2..77209d0f 100644 --- a/libssh/include/libssh/agent.h +++ b/libssh/include/libssh/agent.h @@ -71,6 +71,7 @@ struct ssh_agent_struct { struct ssh_socket_struct *sock; ssh_buffer ident; unsigned int count; + ssh_channel channel; }; #ifndef _WIN32 diff --git a/libssh/include/libssh/auth.h b/libssh/include/libssh/auth.h index 3a6012ec..2c0012b0 100644 --- a/libssh/include/libssh/auth.h +++ b/libssh/include/libssh/auth.h @@ -83,8 +83,13 @@ enum ssh_auth_state_e { /** Last state was a public key accepted for authentication */ SSH_AUTH_STATE_PK_OK, /** We asked for a keyboard-interactive authentication */ - SSH_AUTH_STATE_KBDINT_SENT - + SSH_AUTH_STATE_KBDINT_SENT, + /** We have sent an userauth request with gssapi-with-mic */ + SSH_AUTH_STATE_GSSAPI_REQUEST_SENT, + /** We are exchanging tokens until authentication */ + SSH_AUTH_STATE_GSSAPI_TOKEN, + /** We have sent the MIC and expecting to be authenticated */ + SSH_AUTH_STATE_GSSAPI_MIC_SENT, }; /** @internal diff --git a/libssh/include/libssh/callbacks.h b/libssh/include/libssh/callbacks.h index e15a0bd8..7525b73d 100644 --- a/libssh/include/libssh/callbacks.h +++ b/libssh/include/libssh/callbacks.h @@ -74,6 +74,24 @@ typedef int (*ssh_channel_callback_data) (ssh_channel channel, int code, void *d typedef void (*ssh_log_callback) (ssh_session session, int priority, const char *message, void *userdata); +/** + * @brief SSH log callback. + * + * All logging messages will go through this callback. + * + * @param priority Priority of the log, the smaller being the more important. + * + * @param function The function name calling the the logging fucntions. + * + * @param message The actual message + * + * @param userdata Userdata to be passed to the callback function. + */ +typedef void (*ssh_logging_callback) (int priority, + const char *function, + const char *buffer, + void *userdata); + /** * @brief SSH Connection status callback. * @param session Current session handler @@ -94,6 +112,18 @@ typedef void (*ssh_status_callback) (ssh_session session, float status, typedef void (*ssh_global_request_callback) (ssh_session session, ssh_message message, void *userdata); +/** + * @brief Handles an SSH new channel open X11 request. This happens when the server + * sends back an X11 connection attempt. This is a client-side API + * @param session current session handler + * @param userdata Userdata to be passed to the callback function. + * @returns a valid ssh_channel handle if the request is to be allowed + * @returns NULL if the request should not be allowed + * @warning The channel pointer returned by this callback must be closed by the application. + */ +typedef ssh_channel (*ssh_channel_open_request_x11_callback) (ssh_session session, + const char * originator_address, int originator_port, void *userdata); + /** * The structure to replace libssh functions with appropriate callbacks. */ @@ -121,9 +151,211 @@ struct ssh_callbacks_struct { * This function will be called each time a global request is received. */ ssh_global_request_callback global_request_function; + /** This function will be called when an incoming X11 request is received. + */ + ssh_channel_open_request_x11_callback channel_open_request_x11_function; }; typedef struct ssh_callbacks_struct *ssh_callbacks; +/** These are callbacks used specifically in SSH servers. + */ + +/** + * @brief SSH authentication callback. + * @param session Current session handler + * @param user User that wants to authenticate + * @param password Password used for authentication + * @param userdata Userdata to be passed to the callback function. + * @returns SSH_AUTH_OK Authentication is accepted. + * @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed. + * @returns SSH_AUTH_DENIED Authentication failed. + */ +typedef int (*ssh_auth_password_callback) (ssh_session session, const char *user, const char *password, + void *userdata); + +/** + * @brief SSH authentication callback. Tries to authenticates user with the "none" method + * which is anonymous or passwordless. + * @param session Current session handler + * @param user User that wants to authenticate + * @param userdata Userdata to be passed to the callback function. + * @returns SSH_AUTH_OK Authentication is accepted. + * @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed. + * @returns SSH_AUTH_DENIED Authentication failed. + */ +typedef int (*ssh_auth_none_callback) (ssh_session session, const char *user, void *userdata); + +/** + * @brief SSH authentication callback. Tries to authenticates user with the "gssapi-with-mic" method + * @param session Current session handler + * @param user Username of the user (can be spoofed) + * @param principal Authenticated principal of the user, including realm. + * @param userdata Userdata to be passed to the callback function. + * @returns SSH_AUTH_OK Authentication is accepted. + * @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed. + * @returns SSH_AUTH_DENIED Authentication failed. + * @warning Implementations should verify that parameter user matches in some way the principal. + * user and principal can be different. Only the latter is guaranteed to be safe. + */ +typedef int (*ssh_auth_gssapi_mic_callback) (ssh_session session, const char *user, const char *principal, + void *userdata); + +/** + * @brief SSH authentication callback. + * @param session Current session handler + * @param user User that wants to authenticate + * @param pubkey public key used for authentication + * @param signature_state SSH_PUBLICKEY_STATE_NONE if the key is not signed (simple public key probe), + * SSH_PUBLICKEY_STATE_VALID if the signature is valid. Others values should be + * replied with a SSH_AUTH_DENIED. + * @param userdata Userdata to be passed to the callback function. + * @returns SSH_AUTH_OK Authentication is accepted. + * @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed. + * @returns SSH_AUTH_DENIED Authentication failed. + */ +typedef int (*ssh_auth_pubkey_callback) (ssh_session session, const char *user, struct ssh_key_struct *pubkey, + char signature_state, void *userdata); + + +/** + * @brief Handles an SSH service request + * @param session current session handler + * @param service name of the service (e.g. "ssh-userauth") requested + * @param userdata Userdata to be passed to the callback function. + * @returns 0 if the request is to be allowed + * @returns -1 if the request should not be allowed + */ + +typedef int (*ssh_service_request_callback) (ssh_session session, const char *service, void *userdata); + +/** + * @brief Handles an SSH new channel open session request + * @param session current session handler + * @param userdata Userdata to be passed to the callback function. + * @returns a valid ssh_channel handle if the request is to be allowed + * @returns NULL if the request should not be allowed + * @warning The channel pointer returned by this callback must be closed by the application. + */ +typedef ssh_channel (*ssh_channel_open_request_session_callback) (ssh_session session, void *userdata); + +/* + * @brief handle the beginning of a GSSAPI authentication, server side. + * @param session current session handler + * @param user the username of the client + * @param n_oid number of available oids + * @param oids OIDs provided by the client + * @returns an ssh_string containing the chosen OID, that's supported by both + * client and server. + * @warning It is not necessary to fill this callback in if libssh is linked + * with libgssapi. + */ +typedef ssh_string (*ssh_gssapi_select_oid_callback) (ssh_session session, const char *user, + int n_oid, ssh_string *oids, void *userdata); + +/* + * @brief handle the negociation of a security context, server side. + * @param session current session handler + * @param[in] input_token input token provided by client + * @param[out] output_token output of the gssapi accept_sec_context method, + * NULL after completion. + * @returns SSH_OK if the token was generated correctly or accept_sec_context + * returned GSS_S_COMPLETE + * @returns SSH_ERROR in case of error + * @warning It is not necessary to fill this callback in if libssh is linked + * with libgssapi. + */ +typedef int (*ssh_gssapi_accept_sec_ctx_callback) (ssh_session session, + ssh_string input_token, ssh_string *output_token, void *userdata); + +/* + * @brief Verify and authenticates a MIC, server side. + * @param session current session handler + * @param[in] mic input mic to be verified provided by client + * @param[in] mic_buffer buffer of data to be signed. + * @param[in] mic_buffer_size size of mic_buffer + * @returns SSH_OK if the MIC was authenticated correctly + * @returns SSH_ERROR in case of error + * @warning It is not necessary to fill this callback in if libssh is linked + * with libgssapi. + */ +typedef int (*ssh_gssapi_verify_mic_callback) (ssh_session session, + ssh_string mic, void *mic_buffer, size_t mic_buffer_size, void *userdata); + + +/** + * This structure can be used to implement a libssh server, with appropriate callbacks. + */ + +struct ssh_server_callbacks_struct { + /** DON'T SET THIS use ssh_callbacks_init() instead. */ + size_t size; + /** + * User-provided data. User is free to set anything he wants here + */ + void *userdata; + /** This function gets called when a client tries to authenticate through + * password method. + */ + ssh_auth_password_callback auth_password_function; + + /** This function gets called when a client tries to authenticate through + * none method. + */ + ssh_auth_none_callback auth_none_function; + + /** This function gets called when a client tries to authenticate through + * gssapi-mic method. + */ + ssh_auth_gssapi_mic_callback auth_gssapi_mic_function; + + /** this function gets called when a client tries to authenticate or offer + * a public key. + */ + ssh_auth_pubkey_callback auth_pubkey_function; + + /** This functions gets called when a service request is issued by the + * client + */ + ssh_service_request_callback service_request_function; + /** This functions gets called when a new channel request is issued by + * the client + */ + ssh_channel_open_request_session_callback channel_open_request_session_function; + /** This function will be called when a new gssapi authentication is attempted. + */ + ssh_gssapi_select_oid_callback gssapi_select_oid_function; + /** This function will be called when a gssapi token comes in. + */ + ssh_gssapi_accept_sec_ctx_callback gssapi_accept_sec_ctx_function; + /* This function will be called when a MIC needs to be verified. + */ + ssh_gssapi_verify_mic_callback gssapi_verify_mic_function; +}; +typedef struct ssh_server_callbacks_struct *ssh_server_callbacks; + +/** + * @brief Set the session server callback functions. + * + * This functions sets the callback structure to use your own callback + * functions for user authentication, new channels and requests. + * + * @code + * struct ssh_server_callbacks_struct cb = { + * .userdata = data, + * .auth_password_function = my_auth_function + * }; + * ssh_callbacks_init(&cb); + * ssh_set_server_callbacks(session, &cb); + * @endcode + * + * @param session The session to set the callback structure. + * + * @param cb The callback structure itself. + * + * @return SSH_OK on success, SSH_ERROR on error. + */ +LIBSSH_API int ssh_set_server_callbacks(ssh_session session, ssh_server_callbacks cb); + /** * These are the callbacks exported by the socket structure * They are called by the socket module when a socket event appears @@ -332,6 +564,120 @@ typedef void (*ssh_channel_exit_signal_callback) (ssh_session session, const char *lang, void *userdata); +/** + * @brief SSH channel PTY request from a client. + * @param channel the channel + * @param term The type of terminal emulation + * @param width width of the terminal, in characters + * @param height height of the terminal, in characters + * @param pxwidth width of the terminal, in pixels + * @param pxheight height of the terminal, in pixels + * @param userdata Userdata to be passed to the callback function. + * @returns 0 if the pty request is accepted + * @returns -1 if the request is denied + */ +typedef int (*ssh_channel_pty_request_callback) (ssh_session session, + ssh_channel channel, + const char *term, + int width, int height, + int pxwidth, int pwheight, + void *userdata); + +/** + * @brief SSH channel Shell request from a client. + * @param channel the channel + * @param userdata Userdata to be passed to the callback function. + * @returns 0 if the shell request is accepted + * @returns 1 if the request is denied + */ +typedef int (*ssh_channel_shell_request_callback) (ssh_session session, + ssh_channel channel, + void *userdata); +/** + * @brief SSH auth-agent-request from the client. This request is + * sent by a client when agent forwarding is available. + * Server is free to ignore this callback, no answer is expected. + * @param channel the channel + * @param userdata Userdata to be passed to the callback function. + */ +typedef void (*ssh_channel_auth_agent_req_callback) (ssh_session session, + ssh_channel channel, + void *userdata); + +/** + * @brief SSH X11 request from the client. This request is + * sent by a client when X11 forwarding is requested(and available). + * Server is free to ignore this callback, no answer is expected. + * @param channel the channel + * @param userdata Userdata to be passed to the callback function. + */ +typedef void (*ssh_channel_x11_req_callback) (ssh_session session, + ssh_channel channel, + int single_connection, + const char *auth_protocol, + const char *auth_cookie, + uint32_t screen_number, + void *userdata); +/** + * @brief SSH channel PTY windows change (terminal size) from a client. + * @param channel the channel + * @param width width of the terminal, in characters + * @param height height of the terminal, in characters + * @param pxwidth width of the terminal, in pixels + * @param pxheight height of the terminal, in pixels + * @param userdata Userdata to be passed to the callback function. + * @returns 0 if the pty request is accepted + * @returns -1 if the request is denied + */ +typedef int (*ssh_channel_pty_window_change_callback) (ssh_session session, + ssh_channel channel, + int width, int height, + int pxwidth, int pwheight, + void *userdata); + +/** + * @brief SSH channel Exec request from a client. + * @param channel the channel + * @param command the shell command to be executed + * @param userdata Userdata to be passed to the callback function. + * @returns 0 if the exec request is accepted + * @returns 1 if the request is denied + */ +typedef int (*ssh_channel_exec_request_callback) (ssh_session session, + ssh_channel channel, + const char *command, + void *userdata); + +/** + * @brief SSH channel environment request from a client. + * @param channel the channel + * @param env_name name of the environment value to be set + * @param env_value value of the environment value to be set + * @param userdata Userdata to be passed to the callback function. + * @returns 0 if the env request is accepted + * @returns 1 if the request is denied + * @warning some environment variables can be dangerous if changed (e.g. + * LD_PRELOAD) and should not be fulfilled. + */ +typedef int (*ssh_channel_env_request_callback) (ssh_session session, + ssh_channel channel, + const char *env_name, + const char *env_value, + void *userdata); +/** + * @brief SSH channel subsystem request from a client. + * @param channel the channel + * @param subsystem the subsystem required + * @param userdata Userdata to be passed to the callback function. + * @returns 0 if the subsystem request is accepted + * @returns 1 if the request is denied + */ +typedef int (*ssh_channel_subsystem_request_callback) (ssh_session session, + ssh_channel channel, + const char *subsystem, + void *userdata); + + struct ssh_channel_callbacks_struct { /** DON'T SET THIS use ssh_callbacks_init() instead. */ size_t size; @@ -363,7 +709,40 @@ struct ssh_channel_callbacks_struct { * This functions will be called when an exit signal has been received */ ssh_channel_exit_signal_callback channel_exit_signal_function; + /** + * This function will be called when a client requests a PTY + */ + ssh_channel_pty_request_callback channel_pty_request_function; + /** + * This function will be called when a client requests a shell + */ + ssh_channel_shell_request_callback channel_shell_request_function; + /** This function will be called when a client requests agent + * authentication forwarding. + */ + ssh_channel_auth_agent_req_callback channel_auth_agent_req_function; + /** This function will be called when a client requests X11 + * forwarding. + */ + ssh_channel_x11_req_callback channel_x11_req_function; + /** This function will be called when a client requests a + * window change. + */ + ssh_channel_pty_window_change_callback channel_pty_window_change_function; + /** This function will be called when a client requests a + * command execution. + */ + ssh_channel_exec_request_callback channel_exec_request_function; + /** This function will be called when a client requests an environment + * variable to be set. + */ + ssh_channel_env_request_callback channel_env_request_function; + /** This function will be called when a client requests a subsystem + * (like sftp). + */ + ssh_channel_subsystem_request_callback channel_subsystem_request_function; }; + typedef struct ssh_channel_callbacks_struct *ssh_channel_callbacks; /** @@ -437,6 +816,22 @@ LIBSSH_API struct ssh_threads_callbacks_struct *ssh_threads_get_pthread(void); */ LIBSSH_API struct ssh_threads_callbacks_struct *ssh_threads_get_noop(void); +/** + * @brief Set the logging callback function. + * + * @param[in] cb The callback to set. + * + * @return 0 on success, < 0 on errror. + */ +LIBSSH_API int ssh_set_log_callback(ssh_logging_callback cb); + +/** + * @brief Get the pointer to the logging callback function. + * + * @return The pointer the the callback or NULL if none set. + */ +LIBSSH_API ssh_logging_callback ssh_get_log_callback(void); + /** @} */ #ifdef __cplusplus } diff --git a/libssh/include/libssh/channels.h b/libssh/include/libssh/channels.h index 45152236..4c726453 100644 --- a/libssh/include/libssh/channels.h +++ b/libssh/include/libssh/channels.h @@ -96,8 +96,6 @@ int channel_default_bufferize(ssh_channel channel, void *data, int len, int ssh_channel_flush(ssh_channel channel); uint32_t ssh_channel_new_id(ssh_session session); ssh_channel ssh_channel_from_local(ssh_session session, uint32_t id); -int channel_write_common(ssh_channel channel, const void *data, - uint32_t len, int is_stderr); void ssh_channel_do_free(ssh_channel channel); #ifdef WITH_SSH1 SSH_PACKET_CALLBACK(ssh_packet_data1); diff --git a/libssh/include/libssh/gssapi.h b/libssh/include/libssh/gssapi.h new file mode 100644 index 00000000..ccd83664 --- /dev/null +++ b/libssh/include/libssh/gssapi.h @@ -0,0 +1,45 @@ +/* + * This file is part of the SSH Library + * + * Copyright (c) 2013 by Aris Adamantiadis + * + * 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 GSSAPI_H_ +#define GSSAPI_H_ + +#include "config.h" +#include "session.h" + +/* all OID begin with the tag identifier + length */ +#define SSH_OID_TAG 06 + +typedef struct ssh_gssapi_struct *ssh_gssapi; + +#ifdef WITH_SERVER +int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n_oid, ssh_string *oids); +SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server); +SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_mic); +#endif /* WITH_SERVER */ + +SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token); +SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_client); +SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_response); + + +int ssh_gssapi_auth_mic(ssh_session session); + +#endif /* GSSAPI_H */ diff --git a/libssh/include/libssh/kex.h b/libssh/include/libssh/kex.h index 37d4be8e..1a5b6d41 100644 --- a/libssh/include/libssh/kex.h +++ b/libssh/include/libssh/kex.h @@ -37,7 +37,7 @@ SSH_PACKET_CALLBACK(ssh_packet_publickey1); #endif int ssh_send_kex(ssh_session session, int server_kex); -void ssh_list_kex(ssh_session session, struct ssh_kex_struct *kex); +void ssh_list_kex(struct ssh_kex_struct *kex); int set_client_kex(ssh_session session); int ssh_kex_select_methods(ssh_session session); int verify_existing_algo(int algo, const char *name); diff --git a/libssh/include/libssh/libssh.h b/libssh/include/libssh/libssh.h index d9cc8478..a451620e 100644 --- a/libssh/include/libssh/libssh.h +++ b/libssh/include/libssh/libssh.h @@ -115,6 +115,7 @@ typedef struct ssh_scp_struct* ssh_scp; typedef struct ssh_session_struct* ssh_session; typedef struct ssh_string_struct* ssh_string; typedef struct ssh_event_struct* ssh_event; +typedef void* ssh_gssapi_creds; /* Socket type */ #ifdef _WIN32 @@ -164,6 +165,7 @@ enum ssh_auth_e { #define SSH_AUTH_METHOD_PUBLICKEY 0x0004 #define SSH_AUTH_METHOD_HOSTBASED 0x0008 #define SSH_AUTH_METHOD_INTERACTIVE 0x0010 +#define SSH_AUTH_METHOD_GSSAPI_MIC 0x0020 /* messages */ enum ssh_requests_e { @@ -360,9 +362,11 @@ LIBSSH_API int ssh_channel_is_closed(ssh_channel channel); LIBSSH_API int ssh_channel_is_eof(ssh_channel channel); LIBSSH_API int ssh_channel_is_open(ssh_channel channel); LIBSSH_API ssh_channel ssh_channel_new(ssh_session session); +LIBSSH_API int ssh_channel_open_auth_agent(ssh_channel channel); LIBSSH_API int ssh_channel_open_forward(ssh_channel channel, const char *remotehost, int remoteport, const char *sourcehost, int localport); LIBSSH_API int ssh_channel_open_session(ssh_channel channel); +LIBSSH_API int ssh_channel_open_x11(ssh_channel channel, const char *orig_addr, int orig_port); LIBSSH_API int ssh_channel_poll(ssh_channel channel, int is_stderr); LIBSSH_API int ssh_channel_poll_timeout(ssh_channel channel, int timeout, int is_stderr); LIBSSH_API int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_stderr); @@ -414,10 +418,19 @@ LIBSSH_API int ssh_is_blocking(ssh_session session); LIBSSH_API int ssh_is_connected(ssh_session session); LIBSSH_API int ssh_is_server_known(ssh_session session); +/* LOGGING */ +LIBSSH_API int ssh_set_log_level(int level); +LIBSSH_API int ssh_get_log_level(void); +LIBSSH_API void *ssh_get_log_userdata(void); +LIBSSH_API int ssh_set_log_userdata(void *data); +LIBSSH_API void _ssh_log(int verbosity, + const char *function, + const char *format, ...) PRINTF_ATTRIBUTE(3, 4); + /* legacy */ -LIBSSH_API void ssh_log(ssh_session session, - int prioriry, - const char *format, ...) PRINTF_ATTRIBUTE(3, 4); +SSH_DEPRECATED LIBSSH_API void ssh_log(ssh_session session, + int prioriry, + const char *format, ...) PRINTF_ATTRIBUTE(3, 4); LIBSSH_API ssh_channel ssh_message_channel_request_open_reply_accept(ssh_message msg); LIBSSH_API int ssh_message_channel_request_reply_success(ssh_message msg); @@ -497,6 +510,7 @@ LIBSSH_API int ssh_pki_export_pubkey_file(const ssh_key key, LIBSSH_API void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len); LIBSSH_API int ssh_send_ignore (ssh_session session, const char *data); LIBSSH_API int ssh_send_debug (ssh_session session, const char *message, int always_display); +LIBSSH_API void ssh_gssapi_set_creds(ssh_session session, const ssh_gssapi_creds creds); LIBSSH_API int ssh_scp_accept_request(ssh_scp scp); LIBSSH_API int ssh_scp_close(ssh_scp scp); LIBSSH_API int ssh_scp_deny_request(ssh_scp scp, const char *reason); @@ -518,6 +532,7 @@ LIBSSH_API int ssh_scp_write(ssh_scp scp, const void *buffer, size_t len); LIBSSH_API int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd, fd_set *readfds, struct timeval *timeout); LIBSSH_API int ssh_service_request(ssh_session session, const char *service); +LIBSSH_API int ssh_set_agent_channel(ssh_session session, ssh_channel channel); LIBSSH_API void ssh_set_blocking(ssh_session session, int blocking); LIBSSH_API void ssh_set_fd_except(ssh_session session); LIBSSH_API void ssh_set_fd_toread(ssh_session session); @@ -554,6 +569,7 @@ LIBSSH_API int ssh_userauth_kbdint_getnanswers(ssh_session session); LIBSSH_API const char *ssh_userauth_kbdint_getanswer(ssh_session session, unsigned int i); LIBSSH_API int ssh_userauth_kbdint_setanswer(ssh_session session, unsigned int i, const char *answer); +LIBSSH_API int ssh_userauth_gssapi(ssh_session session); LIBSSH_API const char *ssh_version(int req_version); LIBSSH_API int ssh_write_knownhost(ssh_session session); diff --git a/libssh/include/libssh/libsshpp.hpp b/libssh/include/libssh/libsshpp.hpp index 16e27dd8..1a5d80a9 100644 --- a/libssh/include/libssh/libsshpp.hpp +++ b/libssh/include/libssh/libsshpp.hpp @@ -316,7 +316,7 @@ public: va_start(va, format); vsnprintf(buffer, sizeof(buffer), format, va); va_end(va); - ssh_log(c_session,priority, "%s", buffer); + _ssh_log(priority, "libsshpp", "%s", buffer); } /** @brief copies options from a session to another diff --git a/libssh/include/libssh/messages.h b/libssh/include/libssh/messages.h index f196c6f7..e766d08b 100644 --- a/libssh/include/libssh/messages.h +++ b/libssh/include/libssh/messages.h @@ -92,13 +92,17 @@ struct ssh_message_struct { }; SSH_PACKET_CALLBACK(ssh_packet_channel_open); +SSH_PACKET_CALLBACK(ssh_packet_global_request); + +#ifdef WITH_SERVER SSH_PACKET_CALLBACK(ssh_packet_service_request); SSH_PACKET_CALLBACK(ssh_packet_userauth_request); -SSH_PACKET_CALLBACK(ssh_packet_global_request); +#endif /* WITH_SERVER */ int ssh_message_handle_channel_request(ssh_session session, ssh_channel channel, ssh_buffer packet, const char *request, uint8_t want_reply); void ssh_message_queue(ssh_session session, ssh_message message); ssh_message ssh_message_pop_head(ssh_session session); +int ssh_message_channel_request_open_reply_accept_channel(ssh_message msg, ssh_channel chan); #endif /* MESSAGES_H_ */ diff --git a/libssh/include/libssh/pki.h b/libssh/include/libssh/pki.h index 566700b8..96bacd52 100644 --- a/libssh/include/libssh/pki.h +++ b/libssh/include/libssh/pki.h @@ -108,7 +108,7 @@ int ssh_pki_export_pubkey_rsa1(const ssh_key key, /* SSH Signing Functions */ ssh_string ssh_pki_do_sign(ssh_session session, ssh_buffer sigbuf, - ssh_key privatekey); + const ssh_key privatekey); ssh_string ssh_pki_do_sign_agent(ssh_session session, struct ssh_buffer_struct *buf, const ssh_key pubkey); @@ -116,7 +116,7 @@ ssh_string ssh_srv_pki_do_sign_sessionid(ssh_session session, const ssh_key privkey); /* Temporary functions, to be removed after migration to ssh_key */ -ssh_public_key ssh_pki_convert_key_to_publickey(ssh_key key); -ssh_private_key ssh_pki_convert_key_to_privatekey(ssh_key key); +ssh_public_key ssh_pki_convert_key_to_publickey(const ssh_key key); +ssh_private_key ssh_pki_convert_key_to_privatekey(const ssh_key key); #endif /* PKI_H_ */ diff --git a/libssh/include/libssh/priv.h b/libssh/include/libssh/priv.h index 912a1918..43f749bb 100644 --- a/libssh/include/libssh/priv.h +++ b/libssh/include/libssh/priv.h @@ -31,6 +31,18 @@ #include "config.h" +#if !defined(HAVE_STRTOULL) +# if defined(HAVE___STRTOULL) +# define strtoull __strtoull +# elif defined(HAVE__STRTOUI64) +# define strtoull _strtoui64 +# elif defined(__hpux) && defined(__LP64__) +# define strtoull strtoul +# else +# error "no strtoull function found" +# endif +#endif /* !defined(HAVE_STRTOULL) */ + #ifdef _WIN32 /* Imitate define of inttypes.h */ @@ -46,16 +58,6 @@ # endif /* __WORDSIZE */ # endif /* PRIu64 */ -#if !defined(HAVE_STRTOULL) -# if defined(HAVE___STRTOULL) -# define strtoull __strtoull -# elif defined(__hpux) && defined(__LP64__) -# define strtoull strtoul -# else -# error "no strtoull function found" -# endif -#endif /* !defined(HAVE_STRTOULL) */ - # ifdef _MSC_VER # include @@ -65,9 +67,6 @@ # define strcasecmp _stricmp # define strncasecmp _strnicmp -# if !defined(HAVE_STRTOULL) -# define strtoull _strtoui64 -# endif # define isblank(ch) ((ch) == ' ' || (ch) == '\t' || (ch) == '\n' || (ch) == '\r') # define usleep(X) Sleep(((X)+1000)/1000) @@ -105,6 +104,7 @@ # endif /* _MSC_VER */ +struct timeval; int gettimeofday(struct timeval *__p, void *__t); #else /* _WIN32 */ @@ -130,8 +130,24 @@ int gettimeofday(struct timeval *__p, void *__t); #endif #endif -#define enter_function() (void)session -#define leave_function() (void)session +#if defined(HAVE_GCC_THREAD_LOCAL_STORAGE) +# define LIBSSH_THREAD __thread +#elif defined(HAVE_MSC_THREAD_LOCAL_STORAGE) +# define LIBSSH_THREAD __declspec(thread) +#else +# define LIBSSH_THREAD +#endif + +/* + * This makes sure that the compiler doesn't optimize out the code + * + * Use it in a macro where the provided variable is 'x'. + */ +#if defined(HAVE_GCC_VOLATILE_MEMORY_PROTECTION) +# define LIBSSH_MEM_PROTECTION __asm__ volatile("" : : "r"(&(x)) : "memory") +#else +# define LIBSSH_MEM_PROTECTION +#endif #ifdef HAVE_SYS_TIME_H #include @@ -144,15 +160,17 @@ struct ssh_kex_struct; int ssh_get_key_params(ssh_session session, ssh_key *privkey); /* LOGGING */ -#define SSH_LOG(session, priority, ...) \ - ssh_log_common(&session->common, priority, __FUNCTION__, __VA_ARGS__) +void ssh_log_function(int verbosity, + const char *function, + const char *buffer); +#define SSH_LOG(priority, ...) \ + _ssh_log(priority, __FUNCTION__, __VA_ARGS__) + +/* LEGACY */ void ssh_log_common(struct ssh_common_struct *common, int verbosity, const char *function, const char *format, ...) PRINTF_ATTRIBUTE(4, 5); -void ssh_log_function(int verbosity, - const char *function, - const char *buffer); /* ERROR HANDLING */ @@ -179,9 +197,11 @@ void _ssh_set_error_oom(void *error, const char *function); void _ssh_set_error_invalid(void *error, const char *function); - - - +/* server.c */ +#ifdef WITH_SERVER +int ssh_auth_reply_default(ssh_session session,int partial); +int ssh_auth_reply_success(ssh_session session, int partial); +#endif /* client.c */ int ssh_send_banner(ssh_session session, int is_server); @@ -203,8 +223,9 @@ int decompress_buffer(ssh_session session,ssh_buffer buf, size_t maxlen); /* match.c */ int match_hostname(const char *host, const char *pattern, unsigned int len); - - +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif /** Free memory space */ #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0) @@ -218,11 +239,33 @@ int match_hostname(const char *host, const char *pattern, unsigned int len); /** Get the size of an array */ #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) +/* + * See http://llvm.org/bugs/show_bug.cgi?id=15495 + */ +#if defined(HAVE_GCC_VOLATILE_MEMORY_PROTECTION) /** Overwrite a string with '\0' */ -#define BURN_STRING(x) do { if ((x) != NULL) memset((x), '\0', strlen((x))); __asm__ volatile ("" : : : "memory"); } while(0) +# define BURN_STRING(x) do { \ + if ((x) != NULL) \ + memset((x), '\0', strlen((x))); __asm__ volatile("" : : "r"(&(x)) : "memory"); \ + } while(0) /** Overwrite the buffer with '\0' */ -#define BURN_BUFFER(x, size) do { if ((x) != NULL) memset((x), '\0', (size))); __asm__ volatile ("") : : : "memory"; } while(0) +# define BURN_BUFFER(x, size) do { \ + if ((x) != NULL) \ + memset((x), '\0', (size))); __asm__ volatile("" : : "r"(&(x)) : "memory"); \ + } while(0) +#else /* HAVE_GCC_VOLATILE_MEMORY_PROTECTION */ +/** Overwrite a string with '\0' */ +# define BURN_STRING(x) do { \ + if ((x) != NULL) memset((x), '\0', strlen((x))); \ + } while(0) + +/** Overwrite the buffer with '\0' */ +# define BURN_BUFFER(x, size) do { \ + if ((x) != NULL) \ + memset((x), '\0', (size))); __asm__ volatile("" : : "r"(&(x)) : "memory"); \ + } while(0) +#endif /* HAVE_GCC_VOLATILE_MEMORY_PROTECTION */ /** * This is a hack to fix warnings. The idea is to use this everywhere that we diff --git a/libssh/include/libssh/server.h b/libssh/include/libssh/server.h index 9fab8e3d..9d095feb 100644 --- a/libssh/include/libssh/server.h +++ b/libssh/include/libssh/server.h @@ -55,7 +55,6 @@ typedef struct ssh_bind_struct* ssh_bind; * @brief Incoming connection callback. This callback is called when a ssh_bind * has a new incoming connection. * @param sshbind Current sshbind session handler - * @param message the actual message * @param userdata Userdata to be passed to the callback function. */ typedef void (*ssh_bind_incoming_connection_callback) (ssh_bind sshbind, @@ -238,6 +237,8 @@ LIBSSH_API int ssh_bind_accept(ssh_bind ssh_bind_o, ssh_session session); LIBSSH_API int ssh_bind_accept_fd(ssh_bind ssh_bind_o, ssh_session session, socket_t fd); +LIBSSH_API ssh_gssapi_creds ssh_gssapi_get_creds(ssh_session session); + /** * @brief Handles the key exchange and set up encryption * @@ -254,6 +255,8 @@ LIBSSH_API int ssh_handle_key_exchange(ssh_session session); */ LIBSSH_API void ssh_bind_free(ssh_bind ssh_bind_o); +LIBSSH_API void ssh_set_auth_methods(ssh_session session, int auth_methods); + /********************************************************** * SERVER MESSAGING **********************************************************/ diff --git a/libssh/include/libssh/session.h b/libssh/include/libssh/session.h index 6edf9e51..f0d580dc 100644 --- a/libssh/include/libssh/session.h +++ b/libssh/include/libssh/session.h @@ -59,7 +59,8 @@ enum ssh_pending_call_e { SSH_PENDING_CALL_AUTH_PUBKEY, SSH_PENDING_CALL_AUTH_AGENT, SSH_PENDING_CALL_AUTH_KBDINT_INIT, - SSH_PENDING_CALL_AUTH_KBDINT_SEND + SSH_PENDING_CALL_AUTH_KBDINT_SEND, + SSH_PENDING_CALL_AUTH_GSSAPI_MIC }; /* libssh calls may block an undefined amount of time */ @@ -69,8 +70,13 @@ enum ssh_pending_call_e { #define SSH_SESSION_FLAG_AUTHENTICATED 2 /* codes to use with ssh_handle_packets*() */ +/* Infinite timeout */ #define SSH_TIMEOUT_INFINITE -1 +/* Use the timeout defined by user if any. Mostly used with new connections */ #define SSH_TIMEOUT_USER -2 +/* Use the default timeout, depending on ssh_is_blocking() */ +#define SSH_TIMEOUT_DEFAULT -3 +/* Don't block at all */ #define SSH_TIMEOUT_NONBLOCKING 0 /* members that are common to ssh_session and ssh_bind */ @@ -78,7 +84,6 @@ struct ssh_common_struct { struct error_struct error; ssh_callbacks callbacks; /* Callbacks to user functions */ int log_verbosity; /* verbosity of the log functions */ - int log_indent; /* indentation level in enter_function logs */ }; struct ssh_session_struct { @@ -138,6 +143,7 @@ struct ssh_session_struct { /* keyb interactive data */ struct ssh_kbdint_struct *kbdint; + struct ssh_gssapi_struct *gssapi; int version; /* 1 or 2 */ /* server host keys */ struct { @@ -153,7 +159,7 @@ struct ssh_session_struct { struct ssh_list *ssh_message_list; /* list of delayed SSH messages */ int (*ssh_message_callback)( struct ssh_session_struct *session, ssh_message msg, void *userdata); void *ssh_message_callback_data; - + ssh_server_callbacks server_callbacks; void (*ssh_connection_callback)( struct ssh_session_struct *session); struct ssh_packet_callbacks_struct default_packet_callbacks; struct ssh_list *packet_callbacks; diff --git a/libssh/include/libssh/sftp.h b/libssh/include/libssh/sftp.h index 462e04c5..d370f0ec 100644 --- a/libssh/include/libssh/sftp.h +++ b/libssh/include/libssh/sftp.h @@ -132,6 +132,8 @@ struct sftp_client_message_struct { int attr_num; ssh_buffer attrbuf; /* used by sftp_reply_attrs */ ssh_string data; /* can be newpath of rename() */ + ssh_buffer complete_message; /* complete message in case of retransmission*/ + char *str_data; /* cstring version of data */ }; struct sftp_request_queue_struct { @@ -202,6 +204,19 @@ struct sftp_statvfs_struct { */ LIBSSH_API sftp_session sftp_new(ssh_session session); +/** + * @brief Start a new sftp session with an existing channel. + * + * @param session The ssh session to use. + * @param channel An open session channel with subsystem already allocated + * + * @return A new sftp session or NULL on error. + * + * @see sftp_free() + */ +LIBSSH_API sftp_session sftp_new_channel(ssh_session session, ssh_channel channel); + + /** * @brief Close and deallocate a sftp session. * @@ -824,8 +839,14 @@ int buffer_add_attributes(ssh_buffer buffer, sftp_attributes attr); sftp_attributes sftp_parse_attr(sftp_session session, ssh_buffer buf,int expectname); /* sftpserver.c */ -sftp_client_message sftp_get_client_message(sftp_session sftp); -void sftp_client_message_free(sftp_client_message msg); +LIBSSH_API sftp_client_message sftp_get_client_message(sftp_session sftp); +LIBSSH_API void sftp_client_message_free(sftp_client_message msg); +LIBSSH_API uint8_t sftp_client_message_get_type(sftp_client_message msg); +LIBSSH_API const char *sftp_client_message_get_filename(sftp_client_message msg); +LIBSSH_API void sftp_client_message_set_filename(sftp_client_message msg, const char *newname); +LIBSSH_API const char *sftp_client_message_get_data(sftp_client_message msg); +LIBSSH_API uint32_t sftp_client_message_get_flags(sftp_client_message msg); +LIBSSH_API int sftp_send_client_message(sftp_session sftp, sftp_client_message msg); int sftp_reply_name(sftp_client_message msg, const char *name, sftp_attributes attr); int sftp_reply_handle(sftp_client_message msg, ssh_string handle); diff --git a/libssh/include/libssh/ssh2.h b/libssh/include/libssh/ssh2.h index f66dd2a9..8b39b9a6 100644 --- a/libssh/include/libssh/ssh2.h +++ b/libssh/include/libssh/ssh2.h @@ -30,7 +30,14 @@ #define SSH2_MSG_USERAUTH_PK_OK 60 #define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60 #define SSH2_MSG_USERAUTH_INFO_REQUEST 60 +#define SSH2_MSG_USERAUTH_GSSAPI_RESPONSE 60 #define SSH2_MSG_USERAUTH_INFO_RESPONSE 61 +#define SSH2_MSG_USERAUTH_GSSAPI_TOKEN 61 +#define SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE 63 +#define SSH2_MSG_USERAUTH_GSSAPI_ERROR 64 +#define SSH2_MSG_USERAUTH_GSSAPI_ERRTOK 65 +#define SSH2_MSG_USERAUTH_GSSAPI_MIC 66 + #define SSH2_MSG_GLOBAL_REQUEST 80 #define SSH2_MSG_REQUEST_SUCCESS 81 #define SSH2_MSG_REQUEST_FAILURE 82 diff --git a/libssh/src/CMakeLists.txt b/libssh/src/CMakeLists.txt index 1171c90d..06b239fa 100644 --- a/libssh/src/CMakeLists.txt +++ b/libssh/src/CMakeLists.txt @@ -64,6 +64,18 @@ if (WITH_ZLIB) ) endif (WITH_ZLIB) +if (WITH_GSSAPI AND GSSAPI_FOUND) + set(LIBSSH_PRIVATE_INCLUDE_DIRS + ${LIBSSH_PRIVATE_INCLUDE_DIRS} + ${GSSAPI_INCLUDE_DIR} + ) + + set(LIBSSH_LINK_LIBRARIES + ${LIBSSH_LINK_LIBRARIES} + ${GSSAPI_LIBRARIES} + ) +endif (WITH_GSSAPI AND GSSAPI_FOUND) + set(LIBSSH_LINK_LIBRARIES ${LIBSSH_LINK_LIBRARIES} CACHE INTERNAL "libssh link libraries" @@ -173,6 +185,13 @@ if (WITH_ZLIB) ) endif(WITH_ZLIB) +if (WITH_GSSAPI AND GSSAPI_FOUND) + set(libssh_SRCS + ${libssh_SRCS} + gssapi.c + ) +endif (WITH_GSSAPI AND GSSAPI_FOUND) + include_directories( ${LIBSSH_PUBLIC_INCLUDE_DIRS} ${LIBSSH_PRIVATE_INCLUDE_DIRS} diff --git a/libssh/src/agent.c b/libssh/src/agent.c index b962a8e3..1b094ed4 100644 --- a/libssh/src/agent.c +++ b/libssh/src/agent.c @@ -42,12 +42,12 @@ #include #include +#ifdef HAVE_UNISTD_H #include +#endif -#ifndef _WIN32 #include #include -#endif #include "libssh/agent.h" #include "libssh/priv.h" @@ -83,23 +83,27 @@ static void agent_put_u32(void *vp, uint32_t v) { p[3] = (uint8_t)v & 0xff; } -static size_t atomicio(ssh_socket s, void *buf, size_t n, int do_read) { +static size_t atomicio(struct ssh_agent_struct *agent, void *buf, size_t n, int do_read) { char *b = buf; size_t pos = 0; ssize_t res; ssh_pollfd_t pfd; - socket_t fd = ssh_socket_get_fd_in(s); + ssh_channel channel = agent->channel; + socket_t fd; - pfd.fd = fd; - pfd.events = do_read ? POLLIN : POLLOUT; + /* Using a socket ? */ + if (channel == NULL) { + fd = ssh_socket_get_fd_in(agent->sock); + pfd.fd = fd; + pfd.events = do_read ? POLLIN : POLLOUT; - while (n > pos) { - if (do_read) { - res = read(fd, b + pos, n - pos); - } else { - res = write(fd, b + pos, n - pos); - } - switch (res) { + while (n > pos) { + if (do_read) { + res = read(fd, b + pos, n - pos); + } else { + res = write(fd, b + pos, n - pos); + } + switch (res) { case -1: if (errno == EINTR) { continue; @@ -107,22 +111,36 @@ static size_t atomicio(ssh_socket s, void *buf, size_t n, int do_read) { #ifdef EWOULDBLOCK if (errno == EAGAIN || errno == EWOULDBLOCK) { #else - if (errno == EAGAIN) { + if (errno == EAGAIN) { #endif - (void) ssh_poll(&pfd, 1, -1); - continue; + (void) ssh_poll(&pfd, 1, -1); + continue; + } + return 0; + case 0: + /* read returns 0 on end-of-file */ + errno = do_read ? 0 : EPIPE; + return pos; + default: + pos += (size_t) res; } - return 0; - case 0: - /* read returns 0 on end-of-file */ - errno = do_read ? 0 : EPIPE; + } + return pos; + } else { + /* using an SSH channel */ + while (n > pos){ + if (do_read) + res = ssh_channel_read(channel,b + pos, n-pos, 0); + else + res = ssh_channel_write(channel, b+pos, n-pos); + if (res == SSH_AGAIN) + continue; + if (res == SSH_ERROR) + return 0; + pos += (size_t)res; + } return pos; - default: - pos += (size_t) res; } - } - - return pos; } ssh_agent agent_new(struct ssh_session_struct *session) { @@ -140,10 +158,34 @@ ssh_agent agent_new(struct ssh_session_struct *session) { SAFE_FREE(agent); return NULL; } - + agent->channel = NULL; return agent; } +static void agent_set_channel(struct ssh_agent_struct *agent, ssh_channel channel){ + agent->channel = channel; +} + +/** @brief sets the SSH agent channel. + * The SSH agent channel will be used to authenticate this client using + * an agent through a channel, from another session. The most likely use + * is to implement SSH Agent forwarding into a SSH proxy. + * @param[in] channel a SSH channel from another session. + * @returns SSH_OK in case of success + * SSH_ERROR in case of an error + */ +int ssh_set_agent_channel(ssh_session session, ssh_channel channel){ + if (!session) + return SSH_ERROR; + if (!session->agent){ + ssh_set_error(session, SSH_REQUEST_DENIED, "Session has no active agent"); + return SSH_ERROR; + } + agent_set_channel(session->agent, channel); + return SSH_OK; +} + + void agent_close(struct ssh_agent_struct *agent) { if (agent == NULL) { return; @@ -174,6 +216,9 @@ static int agent_connect(ssh_session session) { return -1; } + if (session->agent->channel != NULL) + return 0; + auth_sock = getenv("SSH_AUTH_SOCK"); if (auth_sock && *auth_sock) { @@ -212,27 +257,27 @@ static int agent_talk(struct ssh_session_struct *session, uint8_t payload[1024] = {0}; len = buffer_get_rest_len(request); - SSH_LOG(session, SSH_LOG_TRACE, "Request length: %u", len); + SSH_LOG(SSH_LOG_TRACE, "Request length: %u", len); agent_put_u32(payload, len); /* send length and then the request packet */ - if (atomicio(session->agent->sock, payload, 4, 0) == 4) { - if (atomicio(session->agent->sock, buffer_get_rest(request), len, 0) + if (atomicio(session->agent, payload, 4, 0) == 4) { + if (atomicio(session->agent, buffer_get_rest(request), len, 0) != len) { - SSH_LOG(session, SSH_LOG_WARN, "atomicio sending request failed: %s", + SSH_LOG(SSH_LOG_WARN, "atomicio sending request failed: %s", strerror(errno)); return -1; } } else { - SSH_LOG(session, SSH_LOG_WARN, + SSH_LOG(SSH_LOG_WARN, "atomicio sending request length failed: %s", strerror(errno)); return -1; } /* wait for response, read the length of the response packet */ - if (atomicio(session->agent->sock, payload, 4, 1) != 4) { - SSH_LOG(session, SSH_LOG_WARN, "atomicio read response length failed: %s", + if (atomicio(session->agent, payload, 4, 1) != 4) { + SSH_LOG(SSH_LOG_WARN, "atomicio read response length failed: %s", strerror(errno)); return -1; } @@ -243,20 +288,20 @@ static int agent_talk(struct ssh_session_struct *session, "Authentication response too long: %u", len); return -1; } - SSH_LOG(session, SSH_LOG_TRACE, "Response length: %u", len); + SSH_LOG(SSH_LOG_TRACE, "Response length: %u", len); while (len > 0) { size_t n = len; if (n > sizeof(payload)) { n = sizeof(payload); } - if (atomicio(session->agent->sock, payload, n, 1) != n) { - SSH_LOG(session, SSH_LOG_WARN, + if (atomicio(session->agent, payload, n, 1) != n) { + SSH_LOG(SSH_LOG_WARN, "Error reading response from authentication socket."); return -1; } if (buffer_add_data(reply, payload, n) < 0) { - SSH_LOG(session, SSH_LOG_WARN, "Not enough space"); + SSH_LOG(SSH_LOG_WARN, "Not enough space"); return -1; } len -= n; @@ -289,11 +334,11 @@ int ssh_agent_get_ident_count(struct ssh_session_struct *session) { /* send message to the agent requesting the list of identities */ request = ssh_buffer_new(); if (request == NULL) { - ssh_set_error_oom(request); + ssh_set_error_oom(session); return -1; } if (buffer_add_u8(request, c1) < 0) { - ssh_set_error_oom(request); + ssh_set_error_oom(session); ssh_buffer_free(request); return -1; } @@ -321,7 +366,7 @@ int ssh_agent_get_ident_count(struct ssh_session_struct *session) { return -1; } - SSH_LOG(session, SSH_LOG_WARN, + SSH_LOG(SSH_LOG_WARN, "Answer type: %d, expected answer: %d", type, c2); @@ -337,7 +382,7 @@ int ssh_agent_get_ident_count(struct ssh_session_struct *session) { buffer_get_u32(reply, (uint32_t *) buf); session->agent->count = agent_get_u32(buf); - SSH_LOG(session, SSH_LOG_DEBUG, "Agent count: %d", + SSH_LOG(SSH_LOG_DEBUG, "Agent count: %d", session->agent->count); if (session->agent->count > 1024) { ssh_set_error(session, SSH_FATAL, @@ -512,7 +557,7 @@ ssh_string ssh_agent_sign_data(ssh_session session, } if (agent_failed(type)) { - SSH_LOG(session, SSH_LOG_WARN, "Agent reports failure in signing the key"); + SSH_LOG(SSH_LOG_WARN, "Agent reports failure in signing the key"); ssh_buffer_free(reply); return NULL; } else if (type != SSH2_AGENT_SIGN_RESPONSE) { diff --git a/libssh/src/auth.c b/libssh/src/auth.c index bdad4e42..de7965d2 100644 --- a/libssh/src/auth.c +++ b/libssh/src/auth.c @@ -42,7 +42,7 @@ #include "libssh/keys.h" #include "libssh/auth.h" #include "libssh/pki.h" - +#include "libssh/gssapi.h" #include "libssh/legacy.h" /** @@ -70,7 +70,7 @@ static int ssh_userauth_request_service(ssh_session session) { rc = ssh_service_request(session, "ssh-userauth"); if (rc != SSH_OK) { - SSH_LOG(session, SSH_LOG_WARN, + SSH_LOG(SSH_LOG_WARN, "Failed to request \"ssh-userauth\" service"); } @@ -82,6 +82,9 @@ static int ssh_auth_response_termination(void *user){ switch(session->auth_state){ case SSH_AUTH_STATE_NONE: case SSH_AUTH_STATE_KBDINT_SENT: + case SSH_AUTH_STATE_GSSAPI_REQUEST_SENT: + case SSH_AUTH_STATE_GSSAPI_TOKEN: + case SSH_AUTH_STATE_GSSAPI_MIC_SENT: return 0; default: return 1; @@ -107,11 +110,9 @@ static int ssh_userauth_get_response(ssh_session session) { rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER, ssh_auth_response_termination, session); if (rc == SSH_ERROR) { - leave_function(); return SSH_AUTH_ERROR; } if (!ssh_auth_response_termination(session)){ - leave_function(); return SSH_AUTH_AGAIN; } @@ -132,7 +133,10 @@ static int ssh_userauth_get_response(ssh_session session) { case SSH_AUTH_STATE_SUCCESS: rc = SSH_AUTH_SUCCESS; break; - case SSH_AUTH_STATE_KBDINT_SENT: + case SSH_AUTH_STATE_KBDINT_SENT: + case SSH_AUTH_STATE_GSSAPI_REQUEST_SENT: + case SSH_AUTH_STATE_GSSAPI_TOKEN: + case SSH_AUTH_STATE_GSSAPI_MIC_SENT: case SSH_AUTH_STATE_NONE: /* not reached */ rc = SSH_AUTH_ERROR; @@ -153,19 +157,19 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_banner){ ssh_string banner; (void)type; (void)user; - enter_function(); + banner = buffer_get_ssh_string(packet); if (banner == NULL) { - SSH_LOG(session, SSH_LOG_WARN, + SSH_LOG(SSH_LOG_WARN, "Invalid SSH_USERAUTH_BANNER packet"); } else { - SSH_LOG(session, SSH_LOG_DEBUG, + SSH_LOG(SSH_LOG_DEBUG, "Received SSH_USERAUTH_BANNER packet"); if(session->banner != NULL) ssh_string_free(session->banner); session->banner = banner; } - leave_function(); + return SSH_PACKET_USED; } @@ -182,7 +186,6 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_failure){ uint8_t partial = 0; (void) type; (void) user; - enter_function(); auth = buffer_get_ssh_string(packet); if (auth == NULL || buffer_get_u8(packet, &partial) != 1) { @@ -200,12 +203,12 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_failure){ if (partial) { session->auth_state=SSH_AUTH_STATE_PARTIAL; - SSH_LOG(session, SSH_LOG_INFO, + SSH_LOG(SSH_LOG_INFO, "Partial success. Authentication that can continue: %s", auth_methods); } else { session->auth_state=SSH_AUTH_STATE_FAILED; - SSH_LOG(session, SSH_LOG_INFO, + SSH_LOG(SSH_LOG_INFO, "Access denied. Authentication that can continue: %s", auth_methods); ssh_set_error(session, SSH_REQUEST_DENIED, @@ -226,11 +229,14 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_failure){ if (strstr(auth_methods, "hostbased") != NULL) { session->auth_methods |= SSH_AUTH_METHOD_HOSTBASED; } + if (strstr(auth_methods, "gssapi-with-mic") != NULL) { + session->auth_methods |= SSH_AUTH_METHOD_GSSAPI_MIC; + } end: ssh_string_free(auth); SAFE_FREE(auth_methods); - leave_function(); + return SSH_PACKET_USED; } @@ -242,27 +248,26 @@ end: * It is also used to communicate the new to the upper levels. */ SSH_PACKET_CALLBACK(ssh_packet_userauth_success){ - enter_function(); (void)packet; (void)type; (void)user; - SSH_LOG(session, SSH_LOG_DEBUG, "Authentication successful"); - SSH_LOG(session, SSH_LOG_TRACE, "Received SSH_USERAUTH_SUCCESS"); + SSH_LOG(SSH_LOG_DEBUG, "Authentication successful"); + SSH_LOG(SSH_LOG_TRACE, "Received SSH_USERAUTH_SUCCESS"); session->auth_state=SSH_AUTH_STATE_SUCCESS; session->session_state=SSH_SESSION_STATE_AUTHENTICATED; session->flags |= SSH_SESSION_FLAG_AUTHENTICATED; if(session->current_crypto && session->current_crypto->delayed_compress_out){ - SSH_LOG(session, SSH_LOG_DEBUG, "Enabling delayed compression OUT"); + SSH_LOG(SSH_LOG_DEBUG, "Enabling delayed compression OUT"); session->current_crypto->do_compress_out=1; } if(session->current_crypto && session->current_crypto->delayed_compress_in){ - SSH_LOG(session,SSH_LOG_DEBUG, "Enabling delayed compression IN"); + SSH_LOG(SSH_LOG_DEBUG, "Enabling delayed compression IN"); session->current_crypto->do_compress_in=1; } - leave_function(); + return SSH_PACKET_USED; } @@ -276,21 +281,24 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_success){ */ SSH_PACKET_CALLBACK(ssh_packet_userauth_pk_ok){ int rc; - enter_function(); - SSH_LOG(session, SSH_LOG_TRACE, "Received SSH_USERAUTH_PK_OK/INFO_REQUEST"); + SSH_LOG(SSH_LOG_TRACE, "Received SSH_USERAUTH_PK_OK/INFO_REQUEST/GSSAPI_RESPONSE"); if(session->auth_state==SSH_AUTH_STATE_KBDINT_SENT){ /* Assuming we are in keyboard-interactive context */ - SSH_LOG(session, SSH_LOG_TRACE, + SSH_LOG(SSH_LOG_TRACE, "keyboard-interactive context, assuming SSH_USERAUTH_INFO_REQUEST"); rc=ssh_packet_userauth_info_request(session,type,packet,user); +#ifdef WITH_GSSAPI + } else if (session->auth_state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT){ + rc = ssh_packet_userauth_gssapi_response(session, type, packet, user); +#endif } else { session->auth_state=SSH_AUTH_STATE_PK_OK; - SSH_LOG(session, SSH_LOG_TRACE, "Assuming SSH_USERAUTH_PK_OK"); + SSH_LOG(SSH_LOG_TRACE, "Assuming SSH_USERAUTH_PK_OK"); rc=SSH_PACKET_USED; } - leave_function(); + return rc; } @@ -981,7 +989,7 @@ int ssh_userauth_agent(ssh_session session, state->pubkey = ssh_agent_get_first_ident(session, &state->comment); while (state->pubkey != NULL) { if(state->state == SSH_AGENT_STATE_NONE){ - SSH_LOG(session, SSH_LOG_DEBUG, + SSH_LOG(SSH_LOG_DEBUG, "Trying identity %s", state->comment); } if(state->state == SSH_AGENT_STATE_NONE || @@ -996,7 +1004,7 @@ int ssh_userauth_agent(ssh_session session, state->state = SSH_AGENT_STATE_PUBKEY; return rc; } else if (rc != SSH_AUTH_SUCCESS) { - SSH_LOG(session, SSH_LOG_DEBUG, + SSH_LOG(SSH_LOG_DEBUG, "Public key of %s refused by server", state->comment); ssh_string_free_char(state->comment); ssh_key_free(state->pubkey); @@ -1005,7 +1013,7 @@ int ssh_userauth_agent(ssh_session session, continue; } - SSH_LOG(session, SSH_LOG_DEBUG, + SSH_LOG(SSH_LOG_DEBUG, "Public key of %s accepted by server", state->comment); state->state = SSH_AGENT_STATE_AUTH; } @@ -1019,7 +1027,7 @@ int ssh_userauth_agent(ssh_session session, SAFE_FREE(session->agent_state); return rc; } else if (rc != SSH_AUTH_SUCCESS) { - SSH_LOG(session, SSH_LOG_INFO, + SSH_LOG(SSH_LOG_INFO, "Server accepted public key but refused the signature"); state->pubkey = ssh_agent_get_next_ident(session, &state->comment); state->state = SSH_AGENT_STATE_NONE; @@ -1109,8 +1117,9 @@ int ssh_userauth_publickey_auto(ssh_session session, #ifndef _WIN32 /* Try authentication with ssh-agent first */ rc = ssh_userauth_agent(session, username); - if (rc == SSH_AUTH_SUCCESS) + if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_AGAIN) { return rc; + } #endif state->state = SSH_AUTH_AUTO_STATE_PUBKEY; } @@ -1122,7 +1131,7 @@ int ssh_userauth_publickey_auto(ssh_session session, const char *privkey_file = state->it->data; char pubkey_file[1024] = {0}; if (state->state == SSH_AUTH_AUTO_STATE_PUBKEY){ - SSH_LOG(session, SSH_LOG_DEBUG, + SSH_LOG(SSH_LOG_DEBUG, "Trying to authenticate with %s", privkey_file); state->privkey = NULL; state->pubkey = NULL; @@ -1152,7 +1161,7 @@ int ssh_userauth_publickey_auto(ssh_session session, continue; } else if (rc == SSH_EOF) { /* If the file doesn't exist, continue */ - SSH_LOG(session, SSH_LOG_DEBUG, + SSH_LOG(SSH_LOG_DEBUG, "Private key %s doesn't exist.", privkey_file); state->it=state->it->next; @@ -1168,8 +1177,7 @@ int ssh_userauth_publickey_auto(ssh_session session, rc = ssh_pki_export_pubkey_file(state->pubkey, pubkey_file); if (rc == SSH_ERROR) { - SSH_LOG(session, - SSH_LOG_WARN, + SSH_LOG(SSH_LOG_WARN, "Could not write public key to file: %s", pubkey_file); } @@ -1179,8 +1187,7 @@ int ssh_userauth_publickey_auto(ssh_session session, if (state->state == SSH_AUTH_AUTO_STATE_KEY_IMPORTED){ rc = ssh_userauth_try_publickey(session, username, state->pubkey); if (rc == SSH_AUTH_ERROR) { - SSH_LOG(session, - SSH_LOG_WARN, + SSH_LOG(SSH_LOG_WARN, "Public key authentication error for %s", privkey_file); ssh_key_free(state->privkey); @@ -1190,8 +1197,7 @@ int ssh_userauth_publickey_auto(ssh_session session, } else if (rc == SSH_AUTH_AGAIN){ return rc; } else if (rc != SSH_AUTH_SUCCESS) { - SSH_LOG(session, - SSH_LOG_DEBUG, + SSH_LOG(SSH_LOG_DEBUG, "Public key for %s refused by server", privkey_file); ssh_key_free(state->privkey); @@ -1226,8 +1232,7 @@ int ssh_userauth_publickey_auto(ssh_session session, /* If the file doesn't exist, continue */ ssh_key_free(state->pubkey); state->pubkey=NULL; - SSH_LOG(session, - SSH_LOG_INFO, + SSH_LOG(SSH_LOG_INFO, "Private key %s doesn't exist.", privkey_file); state->it=state->it->next; @@ -1245,8 +1250,7 @@ int ssh_userauth_publickey_auto(ssh_session session, if (rc == SSH_AUTH_ERROR) { return rc; } else if (rc == SSH_AUTH_SUCCESS) { - SSH_LOG(session, - SSH_LOG_INFO, + SSH_LOG(SSH_LOG_INFO, "Successfully authenticated using %s", privkey_file); return rc; @@ -1254,16 +1258,14 @@ int ssh_userauth_publickey_auto(ssh_session session, return rc; } - SSH_LOG(session, - SSH_LOG_WARN, + SSH_LOG(SSH_LOG_WARN, "The server accepted the public key but refused the signature"); state->it=state->it->next; state->state=SSH_AUTH_AUTO_STATE_PUBKEY; /* continue */ } } - SSH_LOG(session, - SSH_LOG_INFO, + SSH_LOG(SSH_LOG_INFO, "Tried every public key, none matched"); SAFE_FREE(session->auth_auto_state); return SSH_AUTH_DENIED; @@ -1626,7 +1628,7 @@ static int ssh_userauth_kbdint_init(ssh_session session, session->auth_state = SSH_AUTH_STATE_KBDINT_SENT; session->pending_call_state = SSH_PENDING_CALL_AUTH_KBDINT_INIT; - SSH_LOG(session, SSH_LOG_DEBUG, + SSH_LOG(SSH_LOG_DEBUG, "Sending keyboard-interactive init request"); rc = packet_send(session); @@ -1700,7 +1702,7 @@ static int ssh_userauth_kbdint_send(ssh_session session) ssh_kbdint_free(session->kbdint); session->kbdint = NULL; - SSH_LOG(session, SSH_LOG_DEBUG, + SSH_LOG(SSH_LOG_DEBUG, "Sending keyboard-interactive response packet"); rc = packet_send(session); @@ -1733,7 +1735,6 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_request) { uint32_t i; (void)user; (void)type; - enter_function(); name = buffer_get_ssh_string(packet); instruction = buffer_get_ssh_string(packet); @@ -1747,7 +1748,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_request) { ssh_string_free(name); ssh_string_free(instruction); ssh_set_error(session, SSH_FATAL, "Invalid USERAUTH_INFO_REQUEST msg"); - leave_function(); + return SSH_PACKET_USED; } @@ -1758,7 +1759,6 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_request) { ssh_string_free(name); ssh_string_free(instruction); - leave_function(); return SSH_PACKET_USED; } } else { @@ -1771,7 +1771,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_request) { ssh_set_error_oom(session); ssh_kbdint_free(session->kbdint); ssh_string_free(instruction); - leave_function(); + return SSH_PACKET_USED; } @@ -1781,12 +1781,12 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_request) { ssh_set_error_oom(session); ssh_kbdint_free(session->kbdint); session->kbdint = NULL; - leave_function(); + return SSH_PACKET_USED; } nprompts = ntohl(nprompts); - SSH_LOG(session, SSH_LOG_DEBUG, + SSH_LOG(SSH_LOG_DEBUG, "%d keyboard-interactive prompts", nprompts); if (nprompts > KBDINT_MAX_PROMPT) { ssh_set_error(session, SSH_FATAL, @@ -1794,7 +1794,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_request) { nprompts, nprompts); ssh_kbdint_free(session->kbdint); session->kbdint = NULL; - leave_function(); + return SSH_PACKET_USED; } @@ -1806,7 +1806,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_request) { ssh_set_error_oom(session); ssh_kbdint_free(session->kbdint); session->kbdint = NULL; - leave_function(); + return SSH_PACKET_USED; } memset(session->kbdint->prompts, 0, nprompts * sizeof(char *)); @@ -1817,7 +1817,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_request) { ssh_set_error_oom(session); ssh_kbdint_free(session->kbdint); session->kbdint = NULL; - leave_function(); + return SSH_PACKET_USED; } memset(session->kbdint->echo, 0, nprompts); @@ -1829,7 +1829,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_request) { ssh_set_error(session, SSH_FATAL, "Short INFO_REQUEST packet"); ssh_kbdint_free(session->kbdint); session->kbdint = NULL; - leave_function(); + return SSH_PACKET_USED; } session->kbdint->prompts[i] = ssh_string_to_char(tmp); @@ -1839,12 +1839,12 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_request) { session->kbdint->nprompts = i; ssh_kbdint_free(session->kbdint); session->kbdint = NULL; - leave_function(); + return SSH_PACKET_USED; } } session->auth_state=SSH_AUTH_STATE_INFO; - leave_function(); + return SSH_PACKET_USED; } @@ -2108,6 +2108,62 @@ int ssh_userauth_kbdint_setanswer(ssh_session session, unsigned int i, return 0; } +/** + * @brief Try to authenticate through the "gssapi-with-mic" method. + * + * @param[in] session The ssh session to use. + * + * @returns SSH_AUTH_ERROR: A serious error happened\n + * SSH_AUTH_DENIED: Authentication failed : use another method\n + * SSH_AUTH_PARTIAL: You've been partially authenticated, you still + * have to use another method\n + * SSH_AUTH_SUCCESS: Authentication success\n + * SSH_AUTH_AGAIN: In nonblocking mode, you've got to call this again + * later. + */ +int ssh_userauth_gssapi(ssh_session session) { + int rc = SSH_AUTH_DENIED; +#ifdef WITH_GSSAPI + switch(session->pending_call_state) { + case SSH_PENDING_CALL_NONE: + break; + case SSH_PENDING_CALL_AUTH_GSSAPI_MIC: + goto pending; + default: + ssh_set_error(session, + SSH_FATAL, + "Wrong state during pending SSH call"); + return SSH_ERROR; + } + + rc = ssh_userauth_request_service(session); + if (rc == SSH_AGAIN) { + return SSH_AUTH_AGAIN; + } else if (rc == SSH_ERROR) { + return SSH_AUTH_ERROR; + } + SSH_LOG(SSH_LOG_PROTOCOL, "Authenticating with gssapi-with-mic"); + session->auth_state = SSH_AUTH_STATE_NONE; + session->pending_call_state = SSH_PENDING_CALL_AUTH_GSSAPI_MIC; + rc = ssh_gssapi_auth_mic(session); + + if (rc == SSH_AUTH_ERROR || rc == SSH_AUTH_DENIED) { + session->auth_state = SSH_AUTH_STATE_NONE; + session->pending_call_state = SSH_PENDING_CALL_NONE; + return rc; + } + +pending: + rc = ssh_userauth_get_response(session); + if (rc != SSH_AUTH_AGAIN) { + session->pending_call_state = SSH_PENDING_CALL_NONE; + } +#else + (void) session; /* unused */ +#endif + return rc; +} + /** @} */ /* vim: set ts=4 sw=4 et cindent: */ diff --git a/libssh/src/auth1.c b/libssh/src/auth1.c index 0f3f096d..a65c4475 100644 --- a/libssh/src/auth1.c +++ b/libssh/src/auth1.c @@ -44,15 +44,14 @@ static int ssh_auth_status_termination(void *s){ } static int wait_auth1_status(ssh_session session) { - enter_function(); /* wait for a packet */ if (ssh_handle_packets_termination(session,SSH_TIMEOUT_USER, ssh_auth_status_termination, session) != SSH_OK){ - leave_function(); + return SSH_AUTH_ERROR; } - ssh_log(session,SSH_LOG_PROTOCOL,"Auth state : %d",session->auth_state); - leave_function(); + SSH_LOG(SSH_LOG_PROTOCOL,"Auth state : %d",session->auth_state); + switch(session->auth_state) { case SSH_AUTH_STATE_SUCCESS: return SSH_AUTH_SUCCESS; @@ -153,8 +152,7 @@ int ssh_userauth1_offer_pubkey(ssh_session session, const char *username, (void) username; (void) type; (void) pubkey; - enter_function(); - leave_function(); + return SSH_AUTH_DENIED; } @@ -162,10 +160,9 @@ int ssh_userauth1_password(ssh_session session, const char *username, const char *password) { ssh_string pwd = NULL; int rc; - enter_function(); + rc = send_username(session, username); if (rc != SSH_AUTH_DENIED) { - leave_function(); return rc; } if (session->pending_call_state == SSH_PENDING_CALL_AUTH_PASSWORD) @@ -181,7 +178,6 @@ int ssh_userauth1_password(ssh_session session, const char *username, /* not risky to disclose the size of such a big password .. */ pwd = ssh_string_from_char(password); if (pwd == NULL) { - leave_function(); return SSH_AUTH_ERROR; } } else { @@ -194,7 +190,6 @@ int ssh_userauth1_password(ssh_session session, const char *username, */ pwd = ssh_string_new(sizeof(buf)); if (pwd == NULL) { - leave_function(); return SSH_AUTH_ERROR; } ssh_get_random(buf, sizeof(buf), 0); @@ -205,13 +200,13 @@ int ssh_userauth1_password(ssh_session session, const char *username, if (buffer_add_u8(session->out_buffer, SSH_CMSG_AUTH_PASSWORD) < 0) { ssh_string_burn(pwd); ssh_string_free(pwd); - leave_function(); + return SSH_AUTH_ERROR; } if (buffer_add_ssh_string(session->out_buffer, pwd) < 0) { ssh_string_burn(pwd); ssh_string_free(pwd); - leave_function(); + return SSH_AUTH_ERROR; } @@ -220,14 +215,13 @@ int ssh_userauth1_password(ssh_session session, const char *username, session->auth_state=SSH_AUTH_STATE_NONE; session->pending_call_state = SSH_PENDING_CALL_AUTH_PASSWORD; if (packet_send(session) == SSH_ERROR) { - leave_function(); return SSH_AUTH_ERROR; } pending: rc = wait_auth1_status(session); if (rc != SSH_AUTH_AGAIN) session->pending_call_state = SSH_PENDING_CALL_NONE; - leave_function(); + return rc; } diff --git a/libssh/src/bind.c b/libssh/src/bind.c index add5a702..e4c9327e 100644 --- a/libssh/src/bind.c +++ b/libssh/src/bind.c @@ -169,7 +169,7 @@ int ssh_bind_listen(ssh_bind sshbind) { NULL, NULL, &sshbind->ecdsa); - if (rc == SSH_ERROR) { + if (rc == SSH_ERROR || rc == SSH_EOF) { ssh_set_error(sshbind, SSH_FATAL, "Failed to import private ECDSA host key"); return SSH_ERROR; @@ -190,7 +190,7 @@ int ssh_bind_listen(ssh_bind sshbind) { NULL, NULL, &sshbind->dsa); - if (rc == SSH_ERROR) { + if (rc == SSH_ERROR || rc == SSH_EOF) { ssh_set_error(sshbind, SSH_FATAL, "Failed to import private DSA host key"); return SSH_ERROR; @@ -211,7 +211,7 @@ int ssh_bind_listen(ssh_bind sshbind) { NULL, NULL, &sshbind->rsa); - if (rc == SSH_ERROR) { + if (rc == SSH_ERROR || rc == SSH_EOF) { ssh_set_error(sshbind, SSH_FATAL, "Failed to import private RSA host key"); return SSH_ERROR; @@ -250,7 +250,7 @@ int ssh_bind_listen(ssh_bind sshbind) { return -1; } } else { - SSH_LOG(sshbind, SSH_LOG_INFO, "Using app-provided bind socket"); + SSH_LOG(SSH_LOG_INFO, "Using app-provided bind socket"); } return 0; } diff --git a/libssh/src/callbacks.c b/libssh/src/callbacks.c index 5a61180d..afc45019 100644 --- a/libssh/src/callbacks.c +++ b/libssh/src/callbacks.c @@ -26,19 +26,41 @@ #include "libssh/callbacks.h" #include "libssh/session.h" + +/* LEGACY */ +static void ssh_legacy_log_callback(int priority, + const char *function, + const char *buffer, + void *userdata) +{ + ssh_session session = (ssh_session)userdata; + ssh_log_callback log_fn = session->common.callbacks->log_function; + void *log_data = session->common.callbacks->userdata; + + (void)function; /* unused */ + + log_fn(session, priority, buffer, log_data); +} + int ssh_set_callbacks(ssh_session session, ssh_callbacks cb) { if (session == NULL || cb == NULL) { return SSH_ERROR; } - enter_function(); + if(cb->size <= 0 || cb->size > 1024 * sizeof(void *)){ ssh_set_error(session,SSH_FATAL, "Invalid callback passed in (badly initialized)"); - leave_function(); + return SSH_ERROR; } session->common.callbacks = cb; - leave_function(); + + /* LEGACY */ + if (ssh_get_log_callback() == NULL && cb->log_function) { + ssh_set_log_callback(ssh_legacy_log_callback); + ssh_set_log_userdata(session); + } + return 0; } @@ -48,14 +70,30 @@ int ssh_set_channel_callbacks(ssh_channel channel, ssh_channel_callbacks cb) { return SSH_ERROR; } session = channel->session; - enter_function(); + if(cb->size <= 0 || cb->size > 1024 * sizeof(void *)){ ssh_set_error(session,SSH_FATAL, "Invalid channel callback passed in (badly initialized)"); - leave_function(); + return SSH_ERROR; } channel->callbacks = cb; - leave_function(); + return 0; } + +int ssh_set_server_callbacks(ssh_session session, ssh_server_callbacks cb){ + if (session == NULL || cb == NULL) { + return SSH_ERROR; + } + + if(cb->size <= 0 || cb->size > 1024 * sizeof(void *)){ + ssh_set_error(session,SSH_FATAL, + "Invalid callback passed in (badly initialized)"); + + return SSH_ERROR; + } + session->server_callbacks = cb; + + return 0; +} diff --git a/libssh/src/channels.c b/libssh/src/channels.c index 902e04b0..f4376e83 100644 --- a/libssh/src/channels.c +++ b/libssh/src/channels.c @@ -143,8 +143,8 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf){ ssh_channel channel; (void)type; (void)user; - enter_function(); - ssh_log(session,SSH_LOG_PACKET,"Received SSH2_MSG_CHANNEL_OPEN_CONFIRMATION"); + + SSH_LOG(SSH_LOG_PACKET,"Received SSH2_MSG_CHANNEL_OPEN_CONFIRMATION"); buffer_get_u32(packet, &channelid); channelid=ntohl(channelid); @@ -154,7 +154,7 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf){ "Unknown channel id %lu", (long unsigned int) channelid); /* TODO: Set error marking in channel object */ - leave_function(); + return SSH_PACKET_USED; } @@ -167,18 +167,18 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf){ buffer_get_u32(packet,&tmp); channel->remote_maxpacket=ntohl(tmp); - ssh_log(session, SSH_LOG_PROTOCOL, + SSH_LOG(SSH_LOG_PROTOCOL, "Received a CHANNEL_OPEN_CONFIRMATION for channel %d:%d", channel->local_channel, channel->remote_channel); - ssh_log(session, SSH_LOG_PROTOCOL, + SSH_LOG(SSH_LOG_PROTOCOL, "Remote window : %lu, maxpacket : %lu", (long unsigned int) channel->remote_window, (long unsigned int) channel->remote_maxpacket); channel->state = SSH_CHANNEL_STATE_OPEN; channel->flags = channel->flags & ~SSH_CHANNEL_FLAG_NOT_BOUND; - leave_function(); + return SSH_PACKET_USED; } @@ -197,7 +197,7 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_fail){ (void)type; channel=channel_from_msg(session,packet); if(channel==NULL){ - ssh_log(session,SSH_LOG_RARE,"Invalid channel in packet"); + SSH_LOG(SSH_LOG_RARE,"Invalid channel in packet"); return SSH_PACKET_USED; } buffer_get_u32(packet, &code); @@ -254,7 +254,6 @@ static int channel_open(ssh_channel channel, const char *type_c, int window, ssh_string type = NULL; int err=SSH_ERROR; - enter_function(); switch(channel->state){ case SSH_CHANNEL_STATE_NOT_OPEN: break; @@ -271,14 +270,14 @@ static int channel_open(ssh_channel channel, const char *type_c, int window, channel->local_maxpacket = maxpacket; channel->local_window = window; - ssh_log(session, SSH_LOG_PROTOCOL, + SSH_LOG(SSH_LOG_PROTOCOL, "Creating a channel %d with %d window and %d max packet", channel->local_channel, window, maxpacket); type = ssh_string_from_char(type_c); if (type == NULL) { ssh_set_error_oom(session); - leave_function(); + return err; } @@ -289,7 +288,7 @@ static int channel_open(ssh_channel channel, const char *type_c, int window, buffer_add_u32(session->out_buffer, htonl(channel->local_maxpacket)) < 0) { ssh_set_error_oom(session); ssh_string_free(type); - leave_function(); + return err; } @@ -298,17 +297,17 @@ static int channel_open(ssh_channel channel, const char *type_c, int window, if (payload != NULL) { if (buffer_add_buffer(session->out_buffer, payload) < 0) { ssh_set_error_oom(session); - leave_function(); + return err; } } channel->state = SSH_CHANNEL_STATE_OPENING; if (packet_send(session) == SSH_ERROR) { - leave_function(); + return err; } - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Sent a SSH_MSG_CHANNEL_OPEN type %s for channel %d", type_c, channel->local_channel); pending: @@ -319,7 +318,7 @@ pending: end: if(channel->state == SSH_CHANNEL_STATE_OPEN) err=SSH_OK; - leave_function(); + return err; } @@ -351,20 +350,19 @@ ssh_channel ssh_channel_from_local(ssh_session session, uint32_t id) { static int grow_window(ssh_session session, ssh_channel channel, int minimumsize) { uint32_t new_window = minimumsize > WINDOWBASE ? minimumsize : WINDOWBASE; - enter_function(); #ifdef WITH_SSH1 if (session->version == 1){ channel->remote_window = new_window; - leave_function(); + return SSH_OK; } #endif if(new_window <= channel->local_window){ - ssh_log(session,SSH_LOG_PROTOCOL, + SSH_LOG(SSH_LOG_PROTOCOL, "growing window (channel %d:%d) to %d bytes : not needed (%d bytes)", channel->local_channel, channel->remote_channel, new_window, channel->local_window); - leave_function(); + return SSH_OK; } /* WINDOW_ADJUST packet needs a relative increment rather than an absolute @@ -381,7 +379,7 @@ static int grow_window(ssh_session session, ssh_channel channel, int minimumsize goto error; } - ssh_log(session, SSH_LOG_PROTOCOL, + SSH_LOG(SSH_LOG_PROTOCOL, "growing window (channel %d:%d) to %d bytes", channel->local_channel, channel->remote_channel, @@ -389,12 +387,10 @@ static int grow_window(ssh_session session, ssh_channel channel, int minimumsize channel->local_window = new_window; - leave_function(); return SSH_OK; error: buffer_reinit(session->out_buffer); - leave_function(); return SSH_ERROR; } @@ -443,23 +439,22 @@ SSH_PACKET_CALLBACK(channel_rcv_change_window) { int rc; (void)user; (void)type; - enter_function(); channel = channel_from_msg(session,packet); if (channel == NULL) { - ssh_log(session, SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); + SSH_LOG(SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); } rc = buffer_get_u32(packet, &bytes); if (channel == NULL || rc != sizeof(uint32_t)) { - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Error getting a window adjust message: invalid packet"); - leave_function(); + return SSH_PACKET_USED; } bytes = ntohl(bytes); - ssh_log(session, SSH_LOG_PROTOCOL, + SSH_LOG(SSH_LOG_PROTOCOL, "Adding %d bytes to channel (%d:%d) (from %d bytes)", bytes, channel->local_channel, @@ -468,7 +463,6 @@ SSH_PACKET_CALLBACK(channel_rcv_change_window) { channel->remote_window += bytes; - leave_function(); return SSH_PACKET_USED; } @@ -481,7 +475,7 @@ SSH_PACKET_CALLBACK(channel_rcv_data){ int is_stderr; int rest; (void)user; - enter_function(); + if(type==SSH2_MSG_CHANNEL_DATA) is_stderr=0; else @@ -489,9 +483,9 @@ SSH_PACKET_CALLBACK(channel_rcv_data){ channel = channel_from_msg(session,packet); if (channel == NULL) { - ssh_log(session, SSH_LOG_FUNCTIONS, + SSH_LOG(SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); - leave_function(); + return SSH_PACKET_USED; } @@ -503,13 +497,13 @@ SSH_PACKET_CALLBACK(channel_rcv_data){ str = buffer_get_ssh_string(packet); if (str == NULL) { - ssh_log(session, SSH_LOG_PACKET, "Invalid data packet!"); - leave_function(); + SSH_LOG(SSH_LOG_PACKET, "Invalid data packet!"); + return SSH_PACKET_USED; } len = ssh_string_len(str); - ssh_log(session, SSH_LOG_PROTOCOL, + SSH_LOG(SSH_LOG_PROTOCOL, "Channel receiving %" PRIdS " bytes data in %d (local win=%d remote win=%d)", len, is_stderr, @@ -518,7 +512,7 @@ SSH_PACKET_CALLBACK(channel_rcv_data){ /* What shall we do in this case? Let's accept it anyway */ if (len > channel->local_window) { - ssh_log(session, SSH_LOG_RARE, + SSH_LOG(SSH_LOG_RARE, "Data packet too big for our window(%" PRIdS " vs %d)", len, channel->local_window); @@ -527,7 +521,7 @@ SSH_PACKET_CALLBACK(channel_rcv_data){ if (channel_default_bufferize(channel, ssh_string_data(str), len, is_stderr) < 0) { ssh_string_free(str); - leave_function(); + return SSH_PACKET_USED; } @@ -537,7 +531,7 @@ SSH_PACKET_CALLBACK(channel_rcv_data){ channel->local_window = 0; /* buggy remote */ } - ssh_log(session, SSH_LOG_PROTOCOL, + SSH_LOG(SSH_LOG_PROTOCOL, "Channel windows are now (local win=%d remote win=%d)", channel->local_window, channel->remote_window); @@ -561,13 +555,11 @@ SSH_PACKET_CALLBACK(channel_rcv_data){ } if (channel->local_window + buffer_get_rest_len(buf) < WINDOWLIMIT) { if (grow_window(session, channel, 0) < 0) { - leave_function(); return -1; } } } - leave_function(); return SSH_PACKET_USED; } @@ -575,16 +567,15 @@ SSH_PACKET_CALLBACK(channel_rcv_eof) { ssh_channel channel; (void)user; (void)type; - enter_function(); channel = channel_from_msg(session,packet); if (channel == NULL) { - ssh_log(session, SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); - leave_function(); + SSH_LOG(SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); + return SSH_PACKET_USED; } - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Received eof on channel (%d:%d)", channel->local_channel, channel->remote_channel); @@ -597,7 +588,6 @@ SSH_PACKET_CALLBACK(channel_rcv_eof) { channel->callbacks->userdata); } - leave_function(); return SSH_PACKET_USED; } @@ -605,16 +595,15 @@ SSH_PACKET_CALLBACK(channel_rcv_close) { ssh_channel channel; (void)user; (void)type; - enter_function(); channel = channel_from_msg(session,packet); if (channel == NULL) { - ssh_log(session, SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); - leave_function(); + SSH_LOG(SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); + return SSH_PACKET_USED; } - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Received close on channel (%d:%d)", channel->local_channel, channel->remote_channel); @@ -628,7 +617,7 @@ SSH_PACKET_CALLBACK(channel_rcv_close) { channel->state = SSH_CHANNEL_STATE_CLOSED; } if (channel->remote_eof == 0) { - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Remote host not polite enough to send an eof before close"); } channel->remote_eof = 1; @@ -645,7 +634,7 @@ SSH_PACKET_CALLBACK(channel_rcv_close) { channel->flags &= SSH_CHANNEL_FLAG_CLOSED_REMOTE; if(channel->flags & SSH_CHANNEL_FLAG_FREED_LOCAL) ssh_channel_do_free(channel); - leave_function(); + return SSH_PACKET_USED; } @@ -658,26 +647,24 @@ SSH_PACKET_CALLBACK(channel_rcv_request) { (void)user; (void)type; - enter_function(); - channel = channel_from_msg(session,packet); if (channel == NULL) { - ssh_log(session, SSH_LOG_FUNCTIONS,"%s", ssh_get_error(session)); - leave_function(); + SSH_LOG(SSH_LOG_FUNCTIONS,"%s", ssh_get_error(session)); + return SSH_PACKET_USED; } request_s = buffer_get_ssh_string(packet); if (request_s == NULL) { - ssh_log(session, SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST"); - leave_function(); + SSH_LOG(SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST"); + return SSH_PACKET_USED; } request = ssh_string_to_char(request_s); ssh_string_free(request_s); if (request == NULL) { - leave_function(); + return SSH_PACKET_USED; } @@ -689,7 +676,7 @@ SSH_PACKET_CALLBACK(channel_rcv_request) { SAFE_FREE(request); buffer_get_u32(packet, &exit_status); channel->exit_status = ntohl(exit_status); - ssh_log(session, SSH_LOG_PACKET, "received exit-status %d", channel->exit_status); + SSH_LOG(SSH_LOG_PACKET, "received exit-status %d", channel->exit_status); if(ssh_callbacks_exists(channel->callbacks, channel_exit_status_function)) { channel->callbacks->channel_exit_status_function(channel->session, @@ -698,7 +685,6 @@ SSH_PACKET_CALLBACK(channel_rcv_request) { channel->callbacks->userdata); } - leave_function(); return SSH_PACKET_USED; } @@ -707,24 +693,24 @@ SSH_PACKET_CALLBACK(channel_rcv_request) { char *sig; SAFE_FREE(request); - ssh_log(session, SSH_LOG_PACKET, "received signal"); + SSH_LOG(SSH_LOG_PACKET, "received signal"); signal_str = buffer_get_ssh_string(packet); if (signal_str == NULL) { - ssh_log(session, SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST"); - leave_function(); + SSH_LOG(SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST"); + return SSH_PACKET_USED; } sig = ssh_string_to_char(signal_str); ssh_string_free(signal_str); if (sig == NULL) { - leave_function(); + return SSH_PACKET_USED; } - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Remote connection sent a signal SIG %s", sig); if(ssh_callbacks_exists(channel->callbacks, channel_signal_function)) { channel->callbacks->channel_signal_function(channel->session, @@ -734,7 +720,6 @@ SSH_PACKET_CALLBACK(channel_rcv_request) { } SAFE_FREE(sig); - leave_function(); return SSH_PACKET_USED; } @@ -750,15 +735,15 @@ SSH_PACKET_CALLBACK(channel_rcv_request) { tmp = buffer_get_ssh_string(packet); if (tmp == NULL) { - ssh_log(session, SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST"); - leave_function(); + SSH_LOG(SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST"); + return SSH_PACKET_USED; } sig = ssh_string_to_char(tmp); ssh_string_free(tmp); if (sig == NULL) { - leave_function(); + return SSH_PACKET_USED; } @@ -769,9 +754,9 @@ SSH_PACKET_CALLBACK(channel_rcv_request) { tmp = buffer_get_ssh_string(packet); if (tmp == NULL) { - ssh_log(session, SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST"); + SSH_LOG(SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST"); SAFE_FREE(sig); - leave_function(); + return SSH_PACKET_USED; } @@ -779,16 +764,16 @@ SSH_PACKET_CALLBACK(channel_rcv_request) { ssh_string_free(tmp); if (errmsg == NULL) { SAFE_FREE(sig); - leave_function(); + return SSH_PACKET_USED; } tmp = buffer_get_ssh_string(packet); if (tmp == NULL) { - ssh_log(session, SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST"); + SSH_LOG(SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST"); SAFE_FREE(errmsg); SAFE_FREE(sig); - leave_function(); + return SSH_PACKET_USED; } @@ -797,11 +782,11 @@ SSH_PACKET_CALLBACK(channel_rcv_request) { if (lang == NULL) { SAFE_FREE(errmsg); SAFE_FREE(sig); - leave_function(); + return SSH_PACKET_USED; } - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Remote connection closed by signal SIG %s %s", sig, core); if(ssh_callbacks_exists(channel->callbacks, channel_exit_signal_function)) { channel->callbacks->channel_exit_signal_function(channel->session, @@ -814,12 +799,11 @@ SSH_PACKET_CALLBACK(channel_rcv_request) { SAFE_FREE(errmsg); SAFE_FREE(sig); - leave_function(); return SSH_PACKET_USED; } if(strcmp(request,"keepalive@openssh.com")==0){ SAFE_FREE(request); - ssh_log(session, SSH_LOG_PROTOCOL,"Responding to Openssh's keepalive"); + SSH_LOG(SSH_LOG_PROTOCOL,"Responding to Openssh's keepalive"); rc = buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_FAILURE); if (rc < 0) { return SSH_PACKET_USED; @@ -829,19 +813,32 @@ SSH_PACKET_CALLBACK(channel_rcv_request) { return SSH_PACKET_USED; } packet_send(session); - leave_function(); + return SSH_PACKET_USED; } + if (strcmp(request, "auth-agent-req@openssh.com") == 0) { + SAFE_FREE(request); + SSH_LOG(SSH_LOG_PROTOCOL, "Received an auth-agent-req request"); + if(ssh_callbacks_exists(channel->callbacks, channel_auth_agent_req_function)) { + channel->callbacks->channel_auth_agent_req_function(channel->session, channel, + channel->callbacks->userdata); + } + + return SSH_PACKET_USED; + } +#ifdef WITH_SERVER /* If we are here, that means we have a request that is not in the understood * client requests. That means we need to create a ssh message to be passed * to the user code handling ssh messages */ ssh_message_handle_channel_request(session,channel,packet,request,status); - +#else + SSH_LOG(SSH_LOG_WARNING, "Unhandled channel request %s", request); +#endif + SAFE_FREE(request); - leave_function(); return SSH_PACKET_USED; } @@ -866,7 +863,7 @@ int channel_default_bufferize(ssh_channel channel, void *data, int len, return -1; } - ssh_log(session, SSH_LOG_RARE, + SSH_LOG(SSH_LOG_RARE, "placing %d bytes into channel buffer (stderr=%d)", len, is_stderr); if (is_stderr == 0) { /* stdout */ @@ -938,6 +935,40 @@ int ssh_channel_open_session(ssh_channel channel) { NULL); } +/** + * @brief Open an agent authentication forwarding channel. This type of channel + * can be opened by a server towards a client in order to provide SSH-Agent services + * to the server-side process. This channel can only be opened if the client + * claimed support by sending a channel request beforehand. + * + * @param[in] channel An allocated channel. + * + * @return SSH_OK on success, + * SSH_ERROR if an error occurred, + * SSH_AGAIN if in nonblocking mode and call has + * to be done again. + * + * @see channel_open_forward() + */ +int ssh_channel_open_auth_agent(ssh_channel channel){ + if(channel == NULL) { + return SSH_ERROR; + } + +#ifdef WITH_SSH1 + if (channel->session->version == 1) { + return SSH_ERROR; + } +#endif + + return channel_open(channel, + "auth-agent@openssh.com", + CHANNEL_INITIAL_WINDOW, + CHANNEL_MAX_PACKET, + NULL); +} + + /** * @brief Open a TCP/IP forwarding channel. * @@ -981,8 +1012,6 @@ int ssh_channel_open_forward(ssh_channel channel, const char *remotehost, return rc; } - enter_function(); - payload = ssh_buffer_new(); if (payload == NULL) { ssh_set_error_oom(session); @@ -1023,7 +1052,6 @@ error: ssh_buffer_free(payload); ssh_string_free(str); - leave_function(); return rc; } @@ -1043,8 +1071,6 @@ void ssh_channel_free(ssh_channel channel) { } session = channel->session; - enter_function(); - if (session->alive && channel->state == SSH_CHANNEL_STATE_OPEN) { ssh_channel_close(channel); } @@ -1059,7 +1085,6 @@ void ssh_channel_free(ssh_channel channel) { || (channel->flags & SSH_CHANNEL_FLAG_NOT_BOUND)){ ssh_channel_do_free(channel); } - leave_function(); } /** @@ -1103,7 +1128,6 @@ int ssh_channel_send_eof(ssh_channel channel){ } session = channel->session; - enter_function(); if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_EOF) < 0) { ssh_set_error_oom(session); @@ -1114,19 +1138,17 @@ int ssh_channel_send_eof(ssh_channel channel){ goto error; } rc = packet_send(session); - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Sent a EOF on client channel (%d:%d)", channel->local_channel, channel->remote_channel); channel->local_eof = 1; - leave_function(); return rc; error: buffer_reinit(session->out_buffer); - leave_function(); return rc; } @@ -1152,14 +1174,12 @@ int ssh_channel_close(ssh_channel channel){ } session = channel->session; - enter_function(); if (channel->local_eof == 0) { rc = ssh_channel_send_eof(channel); } if (rc != SSH_OK) { - leave_function(); return rc; } @@ -1170,7 +1190,7 @@ int ssh_channel_close(ssh_channel channel){ } rc = packet_send(session); - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Sent a close on client channel (%d:%d)", channel->local_channel, channel->remote_channel); @@ -1179,12 +1199,10 @@ int ssh_channel_close(ssh_channel channel){ channel->state=SSH_CHANNEL_STATE_CLOSED; } - leave_function(); return rc; error: buffer_reinit(session->out_buffer); - leave_function(); return rc; } @@ -1222,11 +1240,13 @@ static int ssh_waitsession_unblocked(void *s){ * SSH_AGAIN Timeout elapsed (or in nonblocking mode) */ int ssh_channel_flush(ssh_channel channel){ - return ssh_blocking_flush(channel->session, SSH_TIMEOUT_USER); + return ssh_blocking_flush(channel->session, SSH_TIMEOUT_DEFAULT); } -int channel_write_common(ssh_channel channel, const void *data, - uint32_t len, int is_stderr) { +static int channel_write_common(ssh_channel channel, + const void *data, + uint32_t len, int is_stderr) +{ ssh_session session; uint32_t origlen = len; size_t effectivelen; @@ -1243,13 +1263,11 @@ int channel_write_common(ssh_channel channel, const void *data, } if (len > INT_MAX) { - ssh_log(session, SSH_LOG_PROTOCOL, + SSH_LOG(SSH_LOG_PROTOCOL, "Length (%u) is bigger than INT_MAX", len); return SSH_ERROR; } - enter_function(); - /* * Handle the max packet len from remote side, be nice * 10 bytes for the headers @@ -1261,98 +1279,117 @@ int channel_write_common(ssh_channel channel, const void *data, "Can't write to channel %d:%d after EOF was sent", channel->local_channel, channel->remote_channel); - leave_function(); return -1; } if (channel->state != SSH_CHANNEL_STATE_OPEN || channel->delayed_close != 0) { ssh_set_error(session, SSH_REQUEST_DENIED, "Remote channel is closed"); - leave_function(); + return -1; } - if (channel->session->session_state == SSH_SESSION_STATE_ERROR){ - leave_function(); + + if (channel->session->session_state == SSH_SESSION_STATE_ERROR) { return SSH_ERROR; } #ifdef WITH_SSH1 if (channel->version == 1) { rc = channel_write1(channel, data, len); - leave_function(); + return rc; } #endif if (ssh_waitsession_unblocked(session) == 0){ - rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER, + rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_DEFAULT, ssh_waitsession_unblocked, session); if (rc == SSH_ERROR || !ssh_waitsession_unblocked(session)) goto out; } while (len > 0) { if (channel->remote_window < len) { - ssh_log(session, SSH_LOG_PROTOCOL, + SSH_LOG(SSH_LOG_PROTOCOL, "Remote window is %d bytes. going to write %d bytes", channel->remote_window, len); /* What happens when the channel window is zero? */ if(channel->remote_window == 0) { /* nothing can be written */ - ssh_log(session, SSH_LOG_PROTOCOL, + SSH_LOG(SSH_LOG_PROTOCOL, "Wait for a growing window message..."); - rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER, + rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_DEFAULT, ssh_channel_waitwindow_termination,channel); if (rc == SSH_ERROR || !ssh_channel_waitwindow_termination(channel)) goto out; continue; } - effectivelen = len > channel->remote_window ? channel->remote_window : len; + effectivelen = MIN(len, channel->remote_window); } else { effectivelen = len; } - effectivelen = effectivelen > maxpacketlen ? maxpacketlen : effectivelen; - if (buffer_add_u8(session->out_buffer, is_stderr ? - SSH2_MSG_CHANNEL_EXTENDED_DATA : SSH2_MSG_CHANNEL_DATA) < 0 || - buffer_add_u32(session->out_buffer, - htonl(channel->remote_channel)) < 0) { + + effectivelen = MIN(effectivelen, maxpacketlen);; + + rc = buffer_add_u8(session->out_buffer, + is_stderr ? SSH2_MSG_CHANNEL_EXTENDED_DATA + : SSH2_MSG_CHANNEL_DATA); + if (rc < 0) { ssh_set_error_oom(session); goto error; } + + rc = buffer_add_u32(session->out_buffer, htonl(channel->remote_channel)); + if (rc < 0) { + ssh_set_error_oom(session); + goto error; + } + /* stderr message has an extra field */ - if (is_stderr && - buffer_add_u32(session->out_buffer, htonl(SSH2_EXTENDED_DATA_STDERR)) < 0) { + if (is_stderr) { + rc = buffer_add_u32(session->out_buffer, + htonl(SSH2_EXTENDED_DATA_STDERR)); + if (rc < 0) { + ssh_set_error_oom(session); + goto error; + } + } + + /* append payload data */ + rc = buffer_add_u32(session->out_buffer, htonl(effectivelen)); + if (rc < 0) { ssh_set_error_oom(session); goto error; } - /* append payload data */ - if (buffer_add_u32(session->out_buffer, htonl(effectivelen)) < 0 || - buffer_add_data(session->out_buffer, data, effectivelen) < 0) { - ssh_set_error_oom(session); - goto error; + + rc = buffer_add_data(session->out_buffer, data, effectivelen); + if (rc < 0) { + ssh_set_error_oom(session); + goto error; } - if (packet_send(session) == SSH_ERROR) { - leave_function(); - return SSH_ERROR; + rc = packet_send(session); + if (rc == SSH_ERROR) { + return SSH_ERROR; } - ssh_log(session, SSH_LOG_RARE, + SSH_LOG(SSH_LOG_RARE, "channel_write wrote %ld bytes", (long int) effectivelen); channel->remote_window -= effectivelen; len -= effectivelen; data = ((uint8_t*)data + effectivelen); } + /* it's a good idea to flush the socket now */ rc = ssh_channel_flush(channel); - if(rc == SSH_ERROR) - goto error; + if (rc == SSH_ERROR) { + goto error; + } + out: - leave_function(); return (int)(origlen - len); error: buffer_reinit(session->out_buffer); - leave_function(); return SSH_ERROR; } @@ -1459,26 +1496,24 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_success){ ssh_channel channel; (void)type; (void)user; - enter_function(); + channel=channel_from_msg(session,packet); if (channel == NULL) { - ssh_log(session, SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); - leave_function(); + SSH_LOG(SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); return SSH_PACKET_USED; } - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Received SSH_CHANNEL_SUCCESS on channel (%d:%d)", channel->local_channel, channel->remote_channel); if(channel->request_state != SSH_CHANNEL_REQ_STATE_PENDING){ - ssh_log(session, SSH_LOG_RARE, "SSH_CHANNEL_SUCCESS received in incorrect state %d", + SSH_LOG(SSH_LOG_RARE, "SSH_CHANNEL_SUCCESS received in incorrect state %d", channel->request_state); } else { channel->request_state=SSH_CHANNEL_REQ_STATE_ACCEPTED; } - leave_function(); return SSH_PACKET_USED; } @@ -1493,25 +1528,25 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_failure){ ssh_channel channel; (void)type; (void)user; - enter_function(); + channel=channel_from_msg(session,packet); if (channel == NULL) { - ssh_log(session, SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); - leave_function(); + SSH_LOG(SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); + return SSH_PACKET_USED; } - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Received SSH_CHANNEL_FAILURE on channel (%d:%d)", channel->local_channel, channel->remote_channel); if(channel->request_state != SSH_CHANNEL_REQ_STATE_PENDING){ - ssh_log(session, SSH_LOG_RARE, "SSH_CHANNEL_FAILURE received in incorrect state %d", + SSH_LOG(SSH_LOG_RARE, "SSH_CHANNEL_FAILURE received in incorrect state %d", channel->request_state); } else { channel->request_state=SSH_CHANNEL_REQ_STATE_DENIED; } - leave_function(); + return SSH_PACKET_USED; } @@ -1530,7 +1565,6 @@ static int channel_request(ssh_channel channel, const char *request, ssh_string req = NULL; int rc = SSH_ERROR; - enter_function(); switch(channel->request_state){ case SSH_CHANNEL_REQ_STATE_NONE: break; @@ -1563,15 +1597,13 @@ static int channel_request(ssh_channel channel, const char *request, } channel->request_state = SSH_CHANNEL_REQ_STATE_PENDING; if (packet_send(session) == SSH_ERROR) { - leave_function(); return rc; } - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Sent a SSH_MSG_CHANNEL_REQUEST %s", request); if (reply == 0) { channel->request_state = SSH_CHANNEL_REQ_STATE_NONE; - leave_function(); return SSH_OK; } pending: @@ -1590,13 +1622,12 @@ pending: rc=SSH_ERROR; break; case SSH_CHANNEL_REQ_STATE_ACCEPTED: - ssh_log(session, SSH_LOG_PROTOCOL, + SSH_LOG(SSH_LOG_PROTOCOL, "Channel request %s success",request); rc=SSH_OK; break; case SSH_CHANNEL_REQ_STATE_PENDING: rc = SSH_AGAIN; - leave_function(); return rc; case SSH_CHANNEL_REQ_STATE_NONE: /* Never reached */ @@ -1605,12 +1636,11 @@ pending: break; } channel->request_state=SSH_CHANNEL_REQ_STATE_NONE; - leave_function(); + return rc; error: buffer_reinit(session->out_buffer); - leave_function(); return rc; } @@ -1647,11 +1677,10 @@ int ssh_channel_request_pty_size(ssh_channel channel, const char *terminal, return rc; } - enter_function(); #ifdef WITH_SSH1 if (channel->version==1) { rc = channel_request_pty_size1(channel,terminal, col, row); - leave_function(); + return rc; } #endif @@ -1690,7 +1719,6 @@ error: ssh_buffer_free(buffer); ssh_string_free(term); - leave_function(); return rc; } @@ -1730,12 +1758,10 @@ int ssh_channel_change_pty_size(ssh_channel channel, int cols, int rows) { ssh_buffer buffer = NULL; int rc = SSH_ERROR; - enter_function(); - #ifdef WITH_SSH1 if (channel->version == 1) { rc = channel_change_pty_size1(channel,cols,rows); - leave_function(); + return rc; } #endif @@ -1758,7 +1784,6 @@ int ssh_channel_change_pty_size(ssh_channel channel, int cols, int rows) { error: ssh_buffer_free(buffer); - leave_function(); return rc; } @@ -2013,18 +2038,16 @@ SSH_PACKET_CALLBACK(ssh_request_success){ (void)type; (void)user; (void)packet; - enter_function(); - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Received SSH_REQUEST_SUCCESS"); if(session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING){ - ssh_log(session, SSH_LOG_RARE, "SSH_REQUEST_SUCCESS received in incorrect state %d", + SSH_LOG(SSH_LOG_RARE, "SSH_REQUEST_SUCCESS received in incorrect state %d", session->global_req_state); } else { session->global_req_state=SSH_CHANNEL_REQ_STATE_ACCEPTED; } - leave_function(); return SSH_PACKET_USED; } @@ -2038,18 +2061,16 @@ SSH_PACKET_CALLBACK(ssh_request_denied){ (void)type; (void)user; (void)packet; - enter_function(); - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Received SSH_REQUEST_FAILURE"); if(session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING){ - ssh_log(session, SSH_LOG_RARE, "SSH_REQUEST_DENIED received in incorrect state %d", + SSH_LOG(SSH_LOG_RARE, "SSH_REQUEST_DENIED received in incorrect state %d", session->global_req_state); } else { session->global_req_state=SSH_CHANNEL_REQ_STATE_DENIED; } - leave_function(); return SSH_PACKET_USED; } @@ -2087,7 +2108,6 @@ static int global_request(ssh_session session, const char *request, ssh_string req = NULL; int rc = SSH_ERROR; - enter_function(); if(session->global_req_state != SSH_CHANNEL_REQ_STATE_NONE) goto pending; req = ssh_string_from_char(request); @@ -2114,15 +2134,14 @@ static int global_request(ssh_session session, const char *request, } session->global_req_state = SSH_CHANNEL_REQ_STATE_PENDING; if (packet_send(session) == SSH_ERROR) { - leave_function(); return rc; } - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Sent a SSH_MSG_GLOBAL_REQUEST %s", request); if (reply == 0) { session->global_req_state=SSH_CHANNEL_REQ_STATE_NONE; - leave_function(); + return SSH_OK; } pending: @@ -2133,11 +2152,11 @@ pending: } switch(session->global_req_state){ case SSH_CHANNEL_REQ_STATE_ACCEPTED: - ssh_log(session, SSH_LOG_PROTOCOL, "Global request %s success",request); + SSH_LOG(SSH_LOG_PROTOCOL, "Global request %s success",request); rc=SSH_OK; break; case SSH_CHANNEL_REQ_STATE_DENIED: - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Global request %s failed", request); ssh_set_error(session, SSH_REQUEST_DENIED, "Global request %s failed", request); @@ -2152,11 +2171,10 @@ pending: break; } - leave_function(); return rc; error: ssh_string_free(req); - leave_function(); + return rc; } @@ -2547,30 +2565,26 @@ int channel_read_buffer(ssh_channel channel, ssh_buffer buffer, uint32_t count, return SSH_ERROR; } - enter_function(); buffer_reinit(buffer); if(count==0){ do { r=ssh_channel_poll(channel, is_stderr); if(r < 0){ - leave_function(); return r; } if(r > 0){ r=ssh_channel_read(channel, buffer_tmp, r, is_stderr); if(r < 0){ - leave_function(); return r; } if(buffer_add_data(buffer,buffer_tmp,r) < 0){ ssh_set_error_oom(session); r = SSH_ERROR; } - leave_function(); + return r; } if(ssh_channel_is_eof(channel)){ - leave_function(); return 0; } ssh_handle_packets(channel->session, SSH_TIMEOUT_INFINITE); @@ -2579,21 +2593,19 @@ int channel_read_buffer(ssh_channel channel, ssh_buffer buffer, uint32_t count, while(total < count){ r=ssh_channel_read(channel, buffer_tmp, sizeof(buffer_tmp), is_stderr); if(r<0){ - leave_function(); return r; } if(r==0){ - leave_function(); return total; } if(buffer_add_data(buffer,buffer_tmp,r) < 0){ ssh_set_error_oom(session); - leave_function(); + return SSH_ERROR; } total += r; } - leave_function(); + return total; } @@ -2653,10 +2665,8 @@ int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_std session = channel->session; stdbuf = channel->stdout_buffer; - enter_function(); if (count == 0) { - leave_function(); return 0; } @@ -2668,7 +2678,7 @@ int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_std * We may have problem if the window is too small to accept as much data * as asked */ - ssh_log(session, SSH_LOG_PROTOCOL, + SSH_LOG(SSH_LOG_PROTOCOL, "Read (%d) buffered : %d bytes. Window: %d", count, buffer_get_rest_len(stdbuf), @@ -2676,29 +2686,25 @@ int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_std if (count > buffer_get_rest_len(stdbuf) + channel->local_window) { if (grow_window(session, channel, count - buffer_get_rest_len(stdbuf)) < 0) { - leave_function(); return -1; } } - /* block reading until all bytes are read + /* block reading until at least one byte has been read * and ignore the trivial case count=0 */ ctx.channel = channel; ctx.buffer = stdbuf; - ctx.count = count; - rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER, + ctx.count = 1; + rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_DEFAULT, ssh_channel_read_termination, &ctx); if (rc == SSH_ERROR){ - leave_function(); return rc; } if (channel->session->session_state == SSH_SESSION_STATE_ERROR){ - leave_function(); return SSH_ERROR; } if (channel->remote_eof && buffer_get_rest_len(stdbuf) == 0) { - leave_function(); return 0; } len = buffer_get_rest_len(stdbuf); @@ -2709,12 +2715,10 @@ int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_std /* Authorize some buffering while userapp is busy */ if (channel->local_window < WINDOWLIMIT) { if (grow_window(session, channel, 0) < 0) { - leave_function(); return -1; } } - leave_function(); return len; } @@ -2755,16 +2759,14 @@ int ssh_channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count } session = channel->session; - enter_function(); to_read = ssh_channel_poll(channel, is_stderr); if (to_read <= 0) { if (channel->session->session_state == SSH_SESSION_STATE_ERROR){ - leave_function(); return SSH_ERROR; } - leave_function(); + return to_read; /* may be an error code */ } @@ -2775,7 +2777,7 @@ int ssh_channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count ssh_set_blocking(session, 0); rc = ssh_channel_read(channel, dest, to_read, is_stderr); ssh_set_blocking(session,blocking); - leave_function(); + return rc; } @@ -2794,16 +2796,13 @@ int ssh_channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count * @see channel_is_eof() */ int ssh_channel_poll(ssh_channel channel, int is_stderr){ - ssh_session session; ssh_buffer stdbuf; if(channel == NULL) { return SSH_ERROR; } - session = channel->session; stdbuf = channel->stdout_buffer; - enter_function(); if (is_stderr) { stdbuf = channel->stderr_buffer; @@ -2811,26 +2810,21 @@ int ssh_channel_poll(ssh_channel channel, int is_stderr){ if (buffer_get_rest_len(stdbuf) == 0 && channel->remote_eof == 0) { if (channel->session->session_state == SSH_SESSION_STATE_ERROR){ - leave_function(); return SSH_ERROR; } if (ssh_handle_packets(channel->session, SSH_TIMEOUT_NONBLOCKING)==SSH_ERROR) { - leave_function(); return SSH_ERROR; } } if (buffer_get_rest_len(stdbuf) > 0){ - leave_function(); return buffer_get_rest_len(stdbuf); } if (channel->remote_eof) { - leave_function(); return SSH_EOF; } - leave_function(); return buffer_get_rest_len(stdbuf); } @@ -2865,7 +2859,6 @@ int ssh_channel_poll_timeout(ssh_channel channel, int timeout, int is_stderr){ session = channel->session; stdbuf = channel->stdout_buffer; - enter_function(); if (is_stderr) { stdbuf = channel->stderr_buffer; @@ -2885,7 +2878,6 @@ int ssh_channel_poll_timeout(ssh_channel channel, int timeout, int is_stderr){ if (channel->remote_eof) rc = SSH_EOF; end: - leave_function(); return rc; } @@ -3204,7 +3196,6 @@ int ssh_channel_open_reverse_forward(ssh_channel channel, const char *remotehost session = channel->session; - enter_function(); if(channel->state != SSH_CHANNEL_STATE_NOT_OPEN) goto pending; payload = ssh_buffer_new(); @@ -3247,7 +3238,6 @@ error: ssh_buffer_free(payload); ssh_string_free(str); - leave_function(); return rc; } @@ -3284,8 +3274,6 @@ int ssh_channel_open_x11(ssh_channel channel, } session = channel->session; - enter_function(); - if(channel->state != SSH_CHANNEL_STATE_NOT_OPEN) goto pending; @@ -3317,7 +3305,6 @@ error: ssh_buffer_free(payload); ssh_string_free(str); - leave_function(); return rc; } diff --git a/libssh/src/channels1.c b/libssh/src/channels1.c index 62faf4ae..bc66488d 100644 --- a/libssh/src/channels1.c +++ b/libssh/src/channels1.c @@ -27,6 +27,8 @@ #include #ifndef _WIN32 #include +#endif +#ifdef HAVE_UNISTD_H #include #endif @@ -72,7 +74,7 @@ int channel_open_session1(ssh_channel chan) { chan->state = SSH_CHANNEL_STATE_OPEN; chan->local_maxpacket = 32000; chan->local_window = 64000; - ssh_log(session, SSH_LOG_PACKET, "Opened a SSH1 channel session"); + SSH_LOG(SSH_LOG_PACKET, "Opened a SSH1 channel session"); return 0; } @@ -124,7 +126,7 @@ int channel_request_pty_size1(ssh_channel channel, const char *terminal, int col return -1; } - ssh_log(session, SSH_LOG_FUNCTIONS, "Opening a ssh1 pty"); + SSH_LOG(SSH_LOG_FUNCTIONS, "Opening a ssh1 pty"); channel->request_state = SSH_CHANNEL_REQ_STATE_PENDING; if (packet_send(session) == SSH_ERROR) { return -1; @@ -142,13 +144,13 @@ int channel_request_pty_size1(ssh_channel channel, const char *terminal, int col return SSH_ERROR; case SSH_CHANNEL_REQ_STATE_ACCEPTED: channel->request_state=SSH_CHANNEL_REQ_STATE_NONE; - ssh_log(session, SSH_LOG_RARE, "PTY: Success"); + SSH_LOG(SSH_LOG_RARE, "PTY: Success"); return SSH_OK; case SSH_CHANNEL_REQ_STATE_DENIED: channel->request_state=SSH_CHANNEL_REQ_STATE_NONE; ssh_set_error(session, SSH_REQUEST_DENIED, "Server denied PTY allocation"); - ssh_log(session, SSH_LOG_RARE, "PTY: denied\n"); + SSH_LOG(SSH_LOG_RARE, "PTY: denied\n"); return SSH_ERROR; } // Not reached @@ -179,7 +181,7 @@ int channel_change_pty_size1(ssh_channel channel, int cols, int rows) { return SSH_ERROR; } - ssh_log(session, SSH_LOG_PROTOCOL, "Change pty size send"); + SSH_LOG(SSH_LOG_PROTOCOL, "Change pty size send"); while(channel->request_state==SSH_CHANNEL_REQ_STATE_PENDING){ ssh_handle_packets(session, SSH_TIMEOUT_INFINITE); } @@ -191,11 +193,11 @@ int channel_change_pty_size1(ssh_channel channel, int cols, int rows) { return SSH_ERROR; case SSH_CHANNEL_REQ_STATE_ACCEPTED: channel->request_state=SSH_CHANNEL_REQ_STATE_NONE; - ssh_log(session, SSH_LOG_PROTOCOL, "pty size changed"); + SSH_LOG(SSH_LOG_PROTOCOL, "pty size changed"); return SSH_OK; case SSH_CHANNEL_REQ_STATE_DENIED: channel->request_state=SSH_CHANNEL_REQ_STATE_NONE; - ssh_log(session, SSH_LOG_RARE, "pty size change denied"); + SSH_LOG(SSH_LOG_RARE, "pty size change denied"); ssh_set_error(session, SSH_REQUEST_DENIED, "pty size change denied"); return SSH_ERROR; } @@ -220,7 +222,7 @@ int channel_request_shell1(ssh_channel channel) { return -1; } - ssh_log(session, SSH_LOG_RARE, "Launched a shell"); + SSH_LOG(SSH_LOG_RARE, "Launched a shell"); return 0; } @@ -250,7 +252,7 @@ int channel_request_exec1(ssh_channel channel, const char *cmd) { return -1; } - ssh_log(session, SSH_LOG_RARE, "Executing %s ...", cmd); + SSH_LOG(SSH_LOG_RARE, "Executing %s ...", cmd); return 0; } @@ -267,11 +269,11 @@ SSH_PACKET_CALLBACK(ssh_packet_data1){ str = buffer_get_ssh_string(packet); if (str == NULL) { - ssh_log(session, SSH_LOG_FUNCTIONS, "Invalid data packet !\n"); + SSH_LOG(SSH_LOG_FUNCTIONS, "Invalid data packet !\n"); return SSH_PACKET_USED; } - ssh_log(session, SSH_LOG_PROTOCOL, + SSH_LOG(SSH_LOG_PROTOCOL, "Adding %" PRIdS " bytes data in %d", ssh_string_len(str), is_stderr); diff --git a/libssh/src/client.c b/libssh/src/client.c index 6203bc4c..99a300b1 100644 --- a/libssh/src/client.c +++ b/libssh/src/client.c @@ -59,14 +59,14 @@ */ static void socket_callback_connected(int code, int errno_code, void *user){ ssh_session session=(ssh_session)user; - enter_function(); + if(session->session_state != SSH_SESSION_STATE_CONNECTING){ ssh_set_error(session,SSH_FATAL, "Wrong state in socket_callback_connected : %d", session->session_state); - leave_function(); + return; } - ssh_log(session,SSH_LOG_RARE,"Socket connection callback: %d (%d)",code, errno_code); + SSH_LOG(SSH_LOG_RARE,"Socket connection callback: %d (%d)",code, errno_code); if(code == SSH_SOCKET_CONNECTED_OK) session->session_state=SSH_SESSION_STATE_SOCKET_CONNECTED; else { @@ -74,7 +74,6 @@ static void socket_callback_connected(int code, int errno_code, void *user){ ssh_set_error(session,SSH_FATAL,"%s",strerror(errno_code)); } session->ssh_connection_callback(session); - leave_function(); } /** @@ -94,10 +93,10 @@ static int callback_receive_banner(const void *data, size_t len, void *user) { char *str = NULL; size_t i; int ret=0; - enter_function(); + if(session->session_state != SSH_SESSION_STATE_SOCKET_CONNECTED){ ssh_set_error(session,SSH_FATAL,"Wrong state in callback_receive_banner : %d",session->session_state); - leave_function(); + return SSH_ERROR; } for(i=0;iserverbanner=str; session->session_state=SSH_SESSION_STATE_BANNER_RECEIVED; - ssh_log(session,SSH_LOG_PACKET,"Received banner: %s",str); + SSH_LOG(SSH_LOG_PACKET,"Received banner: %s",str); session->ssh_connection_callback(session); - leave_function(); + return ret; } if(i>127){ /* Too big banner */ session->session_state=SSH_SESSION_STATE_ERROR; ssh_set_error(session,SSH_FATAL,"Receiving banner: too large banner"); - leave_function(); + return 0; } } - leave_function(); + return ret; } @@ -146,8 +145,6 @@ int ssh_send_banner(ssh_session session, int server) { char buffer[128] = {0}; int err=SSH_ERROR; - enter_function(); - banner = session->version == 1 ? CLIENTBANNER1 : CLIENTBANNER2; if (server) { @@ -173,7 +170,7 @@ int ssh_send_banner(ssh_session session, int server) { #endif err=SSH_OK; end: - leave_function(); + return err; } @@ -188,8 +185,6 @@ static int dh_handshake(ssh_session session) { int rc = SSH_AGAIN; - enter_function(); - switch (session->dh_handshake_state) { case DH_STATE_INIT: switch(session->next_crypto->kex_type){ @@ -203,12 +198,11 @@ static int dh_handshake(ssh_session session) { break; #endif default: - rc=SSH_ERROR; - goto error; + rc = SSH_ERROR; } if (rc == SSH_ERROR) { - goto error; + return SSH_ERROR; } session->dh_handshake_state = DH_STATE_INIT_SENT; @@ -219,16 +213,14 @@ static int dh_handshake(ssh_session session) { /* wait until ssh_packet_newkeys is called */ break; case DH_STATE_FINISHED: - leave_function(); return SSH_OK; default: ssh_set_error(session, SSH_FATAL, "Invalid state in dh_handshake(): %d", session->dh_handshake_state); - leave_function(); + return SSH_ERROR; } -error: - leave_function(); + return rc; } @@ -259,36 +251,37 @@ static int ssh_service_request_termination(void *s){ int ssh_service_request(ssh_session session, const char *service) { ssh_string service_s = NULL; int rc=SSH_ERROR; - enter_function(); + if(session->auth_service_state != SSH_AUTH_SERVICE_NONE) goto pending; if (buffer_add_u8(session->out_buffer, SSH2_MSG_SERVICE_REQUEST) < 0) { - goto error; + return SSH_ERROR; } service_s = ssh_string_from_char(service); if (service_s == NULL) { - goto error; + return SSH_ERROR; } if (buffer_add_ssh_string(session->out_buffer,service_s) < 0) { ssh_string_free(service_s); - goto error; + return SSH_ERROR; } ssh_string_free(service_s); session->auth_service_state=SSH_AUTH_SERVICE_SENT; if (packet_send(session) == SSH_ERROR) { ssh_set_error(session, SSH_FATAL, "Sending SSH2_MSG_SERVICE_REQUEST failed."); - goto error; + return SSH_ERROR; } - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Sent SSH_MSG_SERVICE_REQUEST (service %s)", service); pending: rc=ssh_handle_packets_termination(session,SSH_TIMEOUT_USER, ssh_service_request_termination, session); - if(rc == SSH_ERROR) - goto error; + if (rc == SSH_ERROR) { + return SSH_ERROR; + } switch(session->auth_service_state){ case SSH_AUTH_SERVICE_DENIED: ssh_set_error(session,SSH_FATAL,"ssh_auth_service request denied"); @@ -305,8 +298,7 @@ pending: rc=SSH_ERROR; break; } -error: - leave_function(); + return rc; } @@ -324,7 +316,7 @@ error: */ static void ssh_client_connection_callback(ssh_session session){ int ssh1,ssh2; - enter_function(); + switch(session->session_state){ case SSH_SESSION_STATE_NONE: case SSH_SESSION_STATE_CONNECTING: @@ -335,7 +327,7 @@ static void ssh_client_connection_callback(ssh_session session){ goto error; } set_status(session, 0.4f); - ssh_log(session, SSH_LOG_RARE, + SSH_LOG(SSH_LOG_RARE, "SSH server banner: %s", session->serverbanner); /* Here we analyze the different protocols the server allows. */ @@ -391,7 +383,7 @@ static void ssh_client_connection_callback(ssh_session session){ break; case SSH_SESSION_STATE_KEXINIT_RECEIVED: set_status(session,0.6f); - ssh_list_kex(session, &session->next_crypto->server_kex); + ssh_list_kex(&session->next_crypto->server_kex); if (set_client_kex(session) < 0) { goto error; } @@ -423,13 +415,13 @@ static void ssh_client_connection_callback(ssh_session session){ default: ssh_set_error(session,SSH_FATAL,"Invalid state %d",session->session_state); } - leave_function(); + return; - error: +error: ssh_socket_close(session->socket); session->alive = 0; session->session_state=SSH_SESSION_STATE_ERROR; - leave_function(); + } /** @internal @@ -466,7 +458,6 @@ int ssh_connect(ssh_session session) { return SSH_ERROR; } - enter_function(); switch(session->pending_call_state){ case SSH_PENDING_CALL_NONE: break; @@ -474,31 +465,28 @@ int ssh_connect(ssh_session session) { goto pending; default: ssh_set_error(session,SSH_FATAL,"Bad call during pending SSH call in ssh_connect"); - leave_function(); + return SSH_ERROR; } session->alive = 0; session->client = 1; if (ssh_init() < 0) { - leave_function(); 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"); - leave_function(); return SSH_ERROR; } ret = ssh_options_apply(session); if (ret < 0) { ssh_set_error(session, SSH_FATAL, "Couldn't apply options"); - leave_function(); return SSH_ERROR; } - ssh_log(session,SSH_LOG_RARE,"libssh %s, using threading %s", ssh_copyright(), ssh_threads_get_type()); + SSH_LOG(SSH_LOG_RARE,"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); @@ -521,14 +509,13 @@ int ssh_connect(ssh_session session) { session->opts.bindaddr); } if (ret == SSH_ERROR) { - leave_function(); return SSH_ERROR; } set_status(session, 0.2f); session->alive = 1; - ssh_log(session,SSH_LOG_PROTOCOL,"Socket connecting, now waiting for the callbacks to work"); + 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)) { @@ -537,7 +524,7 @@ pending: if (timeout == 0) { timeout = 10 * 1000; } - ssh_log(session,SSH_LOG_PACKET,"ssh_connect: Actual timeout : %d", timeout); + SSH_LOG(SSH_LOG_PACKET,"ssh_connect: Actual timeout : %d", timeout); ret = ssh_handle_packets_termination(session, timeout, ssh_connect_termination, session); if (ret == SSH_ERROR || !ssh_connect_termination(session)) { ssh_set_error(session, SSH_FATAL, @@ -554,12 +541,11 @@ pending: session->session_state = SSH_SESSION_STATE_ERROR; } } - ssh_log(session,SSH_LOG_PACKET,"ssh_connect: Actual state : %d",session->session_state); + SSH_LOG(SSH_LOG_PACKET,"ssh_connect: Actual state : %d",session->session_state); if(!ssh_is_blocking(session) && !ssh_connect_termination(session)){ - leave_function(); return SSH_AGAIN; } - leave_function(); + 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; @@ -616,8 +602,6 @@ void ssh_disconnect(ssh_session session) { return; } - enter_function(); - if (session->socket != NULL && ssh_socket_is_open(session->socket)) { if (buffer_add_u8(session->out_buffer, SSH2_MSG_DISCONNECT) < 0) { goto error; @@ -683,8 +667,6 @@ error: ssh_list_free(session->packet_callbacks); session->packet_callbacks=NULL; } - - leave_function(); } const char *ssh_copyright(void) { diff --git a/libssh/src/config.c b/libssh/src/config.c index 632a50bb..7935e884 100644 --- a/libssh/src/config.c +++ b/libssh/src/config.c @@ -324,7 +324,7 @@ static int ssh_config_parse_line(ssh_session session, const char *line, } break; case SOC_UNSUPPORTED: - ssh_log(session, SSH_LOG_RARE, "Unsupported option: %s, line: %d\n", + SSH_LOG(SSH_LOG_RARE, "Unsupported option: %s, line: %d\n", keyword, count); break; default: @@ -350,7 +350,7 @@ int ssh_config_parse_file(ssh_session session, const char *filename) { return 0; } - ssh_log(session, SSH_LOG_RARE, "Reading configuration data from %s", filename); + SSH_LOG(SSH_LOG_RARE, "Reading configuration data from %s", filename); parsing = 1; while (fgets(line, sizeof(line), f)) { diff --git a/libssh/src/connect.c b/libssh/src/connect.c index 91e6b6a7..f7965cbe 100644 --- a/libssh/src/connect.c +++ b/libssh/src/connect.c @@ -104,7 +104,7 @@ static int ssh_connect_socket_close(socket_t s){ } -static int getai(ssh_session session, const char *host, int port, struct addrinfo **ai) { +static int getai(const char *host, int port, struct addrinfo **ai) { const char *service = NULL; struct addrinfo hints; char s_port[10]; @@ -127,7 +127,7 @@ static int getai(ssh_session session, const char *host, int port, struct addrinf if (ssh_is_ipaddr(host)) { /* this is an IP address */ - ssh_log(session,SSH_LOG_PACKET,"host %s matches an IP address",host); + SSH_LOG(SSH_LOG_PACKET,"host %s matches an IP address",host); hints.ai_flags |= AI_NUMERICHOST; } @@ -142,8 +142,6 @@ static int ssh_connect_ai_timeout(ssh_session session, const char *host, int ret; socklen_t len = sizeof(rc); - enter_function(); - /* I know we're losing some precision. But it's not like poll-like family * type of mechanisms are precise up to the microsecond. */ @@ -157,7 +155,7 @@ static int ssh_connect_ai_timeout(ssh_session session, const char *host, return -1; } - ssh_log(session, SSH_LOG_RARE, "Trying to connect to host: %s:%d with " + SSH_LOG(SSH_LOG_RARE, "Trying to connect to host: %s:%d with " "timeout %d ms", host, port, timeout_ms); /* The return value is checked later */ @@ -177,7 +175,7 @@ static int ssh_connect_ai_timeout(ssh_session session, const char *host, ssh_set_error(session, SSH_FATAL, "Timeout while connecting to %s:%d", host, port); ssh_connect_socket_close(s); - leave_function(); + return -1; } @@ -185,7 +183,7 @@ static int ssh_connect_ai_timeout(ssh_session session, const char *host, ssh_set_error(session, SSH_FATAL, "poll error: %s", strerror(errno)); ssh_connect_socket_close(s); - leave_function(); + return -1; } rc = -1; @@ -196,12 +194,12 @@ static int ssh_connect_ai_timeout(ssh_session session, const char *host, ssh_set_error(session, SSH_FATAL, "Connect to %s:%d failed: %s", host, port, strerror(rc)); ssh_connect_socket_close(s); - leave_function(); + return -1; } /* s is connected ? */ - ssh_log(session, SSH_LOG_PACKET, "Socket connected with timeout\n"); + SSH_LOG(SSH_LOG_PACKET, "Socket connected with timeout\n"); ret = ssh_socket_set_blocking(s); if (ret < 0) { ssh_set_error(session, SSH_FATAL, @@ -211,7 +209,6 @@ static int ssh_connect_ai_timeout(ssh_session session, const char *host, return -1; } - leave_function(); return s; } @@ -230,13 +227,11 @@ socket_t ssh_connect_host(ssh_session session, const char *host, struct addrinfo *ai; struct addrinfo *itr; - enter_function(); - - rc = getai(session,host, port, &ai); + rc = getai(host, port, &ai); if (rc != 0) { ssh_set_error(session, SSH_FATAL, "Failed to resolve hostname %s (%s)", host, gai_strerror(rc)); - leave_function(); + return -1; } @@ -253,9 +248,9 @@ socket_t ssh_connect_host(ssh_session session, const char *host, struct addrinfo *bind_ai; struct addrinfo *bind_itr; - ssh_log(session, SSH_LOG_PACKET, "Resolving %s\n", bind_addr); + SSH_LOG(SSH_LOG_PACKET, "Resolving %s\n", bind_addr); - rc = getai(session,bind_addr, 0, &bind_ai); + rc = getai(bind_addr, 0, &bind_ai); if (rc != 0) { ssh_set_error(session, SSH_FATAL, "Failed to resolve bind address %s (%s)", @@ -263,7 +258,7 @@ socket_t ssh_connect_host(ssh_session session, const char *host, gai_strerror(rc)); freeaddrinfo(ai); close(s); - leave_function(); + return -1; } @@ -289,7 +284,7 @@ socket_t ssh_connect_host(ssh_session session, const char *host, if (timeout || usec) { socket_t ret = ssh_connect_ai_timeout(session, host, port, itr, timeout, usec, s); - leave_function(); + return ret; } @@ -297,7 +292,6 @@ socket_t ssh_connect_host(ssh_session session, const char *host, ssh_set_error(session, SSH_FATAL, "Connect failed: %s", strerror(errno)); ssh_connect_socket_close(s); s = -1; - leave_function(); continue; } else { /* We are connected */ @@ -306,7 +300,6 @@ socket_t ssh_connect_host(ssh_session session, const char *host, } freeaddrinfo(ai); - leave_function(); return s; } @@ -327,13 +320,11 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host, struct addrinfo *ai; struct addrinfo *itr; - enter_function(); - - rc = getai(session,host, port, &ai); + rc = getai(host, port, &ai); if (rc != 0) { ssh_set_error(session, SSH_FATAL, "Failed to resolve hostname %s (%s)", host, gai_strerror(rc)); - leave_function(); + return -1; } @@ -350,9 +341,9 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host, struct addrinfo *bind_ai; struct addrinfo *bind_itr; - ssh_log(session, SSH_LOG_PACKET, "Resolving %s\n", bind_addr); + SSH_LOG(SSH_LOG_PACKET, "Resolving %s\n", bind_addr); - rc = getai(session,bind_addr, 0, &bind_ai); + rc = getai(bind_addr, 0, &bind_ai); if (rc != 0) { ssh_set_error(session, SSH_FATAL, "Failed to resolve bind address %s (%s)", @@ -396,7 +387,6 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host, } freeaddrinfo(ai); - leave_function(); return s; } @@ -446,6 +436,7 @@ static int ssh_select_cb (socket_t fd, int revents, void *userdata){ */ int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd, fd_set *readfds, struct timeval *timeout) { + socket_t fd; int i,j; int rc; int base_tm, tm; @@ -457,10 +448,11 @@ int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd, for (i=0 ; channels[i] != NULL; ++i){ ssh_event_add_session(event, channels[i]->session); } - for (i=0; iout_buffer, SSH2_MSG_KEXDH_INIT) < 0) { goto error; } @@ -592,7 +592,6 @@ int ssh_client_dh_init(ssh_session session){ ssh_string_free(e); } - leave_function(); return SSH_ERROR; } @@ -639,7 +638,7 @@ int ssh_client_dh_reply(ssh_session session, ssh_buffer packet){ } rc=packet_send(session); - ssh_log(session, SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); + SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); return rc; error: return SSH_ERROR; @@ -664,8 +663,6 @@ int make_sessionid(ssh_session session) { uint32_t len; int rc = SSH_ERROR; - enter_function(); - buf = ssh_buffer_new(); if (buf == NULL) { return rc; @@ -762,7 +759,7 @@ int make_sessionid(ssh_session session) { } else if (session->next_crypto->kex_type == SSH_KEX_ECDH_SHA2_NISTP256){ if(session->next_crypto->ecdh_client_pubkey == NULL || session->next_crypto->ecdh_server_pubkey == NULL){ - ssh_log(session,SSH_LOG_WARNING,"ECDH parameted missing"); + SSH_LOG(SSH_LOG_WARNING, "ECDH parameted missing"); goto error; } rc = buffer_add_ssh_string(buf,session->next_crypto->ecdh_client_pubkey); @@ -828,7 +825,7 @@ int make_sessionid(ssh_session session) { session->next_crypto->digest_len); } #ifdef DEBUG_CRYPTO - printf("Session hash: "); + printf("Session hash: \n"); ssh_print_hexa("secret hash", session->next_crypto->secret_hash, session->next_crypto->digest_len); ssh_print_hexa("session id", session->next_crypto->session_id, session->next_crypto->digest_len); #endif @@ -845,8 +842,6 @@ error: ssh_string_free(str); ssh_string_free(num); - leave_function(); - return rc; } @@ -920,8 +915,6 @@ int generate_session_keys(ssh_session session) { struct ssh_crypto_struct *crypto = session->next_crypto; int rc = -1; - enter_function(); - k_string = make_bignum_string(crypto->k); if (k_string == NULL) { ssh_set_error_oom(session); @@ -983,7 +976,7 @@ int generate_session_keys(ssh_session session) { goto error; } ssh_mac_update(ctx, k_string, ssh_string_len(k_string) + 4); - ssh_mac_update(ctx, crypto->session_id, + ssh_mac_update(ctx, crypto->secret_hash, crypto->digest_len); ssh_mac_update(ctx, crypto->encryptkey, crypto->digest_len); ssh_mac_final(crypto->encryptkey + crypto->digest_len, ctx); @@ -995,7 +988,7 @@ int generate_session_keys(ssh_session session) { goto error; ctx = ssh_mac_ctx_init(crypto->mac_type); ssh_mac_update(ctx, k_string, ssh_string_len(k_string) + 4); - ssh_mac_update(ctx, crypto->session_id, + ssh_mac_update(ctx, crypto->secret_hash, crypto->digest_len); ssh_mac_update(ctx, crypto->decryptkey, crypto->digest_len); ssh_mac_final(crypto->decryptkey + crypto->digest_len, ctx); @@ -1030,7 +1023,6 @@ int generate_session_keys(ssh_session session) { rc = 0; error: ssh_string_free(k_string); - leave_function(); return rc; } diff --git a/libssh/src/ecdh.c b/libssh/src/ecdh.c index 075810a9..3f065e7e 100644 --- a/libssh/src/ecdh.c +++ b/libssh/src/ecdh.c @@ -99,6 +99,7 @@ static int ecdh_build_k(ssh_session session) { const EC_GROUP *group = EC_KEY_get0_group(session->next_crypto->ecdh_privkey); EC_POINT *pubkey; void *buffer; + int rc; int len = (EC_GROUP_get_degree(group) + 7) / 8; bignum_CTX ctx = bignum_ctx_new(); if (ctx == NULL) { @@ -117,19 +118,48 @@ static int ecdh_build_k(ssh_session session) { return -1; } - if (session->server) - EC_POINT_oct2point(group,pubkey,ssh_string_data(session->next_crypto->ecdh_client_pubkey), - ssh_string_len(session->next_crypto->ecdh_client_pubkey),ctx); - else - EC_POINT_oct2point(group,pubkey,ssh_string_data(session->next_crypto->ecdh_server_pubkey), - ssh_string_len(session->next_crypto->ecdh_server_pubkey),ctx); + if (session->server) { + rc = EC_POINT_oct2point(group, + pubkey, + ssh_string_data(session->next_crypto->ecdh_client_pubkey), + ssh_string_len(session->next_crypto->ecdh_client_pubkey), + ctx); + } else { + rc = EC_POINT_oct2point(group, + pubkey, + ssh_string_data(session->next_crypto->ecdh_server_pubkey), + ssh_string_len(session->next_crypto->ecdh_server_pubkey), + ctx); + } + bignum_ctx_free(ctx); + if (rc <= 0) { + EC_POINT_clear_free(pubkey); + return -1; + } + buffer = malloc(len); - ECDH_compute_key(buffer,len,pubkey,session->next_crypto->ecdh_privkey,NULL); - EC_POINT_free(pubkey); - BN_bin2bn(buffer,len,session->next_crypto->k); + if (buffer == NULL) { + EC_POINT_clear_free(pubkey); + return -1; + } + + rc = ECDH_compute_key(buffer, + len, + pubkey, + session->next_crypto->ecdh_privkey, + NULL); + EC_POINT_clear_free(pubkey); + if (rc <= 0) { + free(buffer); + return -1; + } + + BN_bin2bn(buffer, len, session->next_crypto->k); free(buffer); + EC_KEY_free(session->next_crypto->ecdh_privkey); - session->next_crypto->ecdh_privkey=NULL; + session->next_crypto->ecdh_privkey = NULL; + #ifdef DEBUG_CRYPTO ssh_print_hexa("Session server cookie", session->next_crypto->server_kex.cookie, 16); @@ -138,10 +168,6 @@ static int ecdh_build_k(ssh_session session) { ssh_print_bignum("Shared secret key", session->next_crypto->k); #endif -#ifdef HAVE_LIBCRYPTO - bignum_ctx_free(ctx); -#endif - return 0; } @@ -186,7 +212,7 @@ int ssh_client_ecdh_reply(ssh_session session, ssh_buffer packet){ } rc=packet_send(session); - ssh_log(session, SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); + SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); return rc; error: return SSH_ERROR; @@ -312,17 +338,7 @@ int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet){ return SSH_ERROR; } - /* Free private keys as they should not be readable after this point */ - if (session->srv.rsa_key) { - ssh_key_free(session->srv.rsa_key); - session->srv.rsa_key = NULL; - } - if (session->srv.dsa_key) { - ssh_key_free(session->srv.dsa_key); - session->srv.dsa_key = NULL; - } - - ssh_log(session,SSH_LOG_PROTOCOL, "SSH_MSG_KEXDH_REPLY sent"); + SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEXDH_REPLY sent"); rc = packet_send(session); if (rc == SSH_ERROR) { return SSH_ERROR; @@ -336,7 +352,7 @@ int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet){ session->dh_handshake_state = DH_STATE_NEWKEYS_SENT; rc = packet_send(session); - ssh_log(session, SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); + SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); return rc; } diff --git a/libssh/src/error.c b/libssh/src/error.c index f4a2af00..fbe0e787 100644 --- a/libssh/src/error.c +++ b/libssh/src/error.c @@ -61,11 +61,11 @@ void _ssh_set_error(void *error, va_end(va); err->error.error_code = code; - ssh_log_common(err, - SSH_LOG_WARN, - function, - "Error: %s", - err->error.error_buffer); + if (ssh_get_log_level() >= SSH_LOG_WARN) { + ssh_log_function(SSH_LOG_WARN, + function, + err->error.error_buffer); + } } /** diff --git a/libssh/src/getpass.c b/libssh/src/getpass.c index cc6d33ca..0ffb955d 100644 --- a/libssh/src/getpass.c +++ b/libssh/src/getpass.c @@ -21,6 +21,8 @@ * MA 02111-1307, USA. */ +#include "config.h" + #include #include #include @@ -163,8 +165,12 @@ int ssh_getpass(const char *prompt, #else #include +#ifdef HAVE_TERMIOS_H #include +#endif +#ifdef HAVE_UNISTD_H #include +#endif /** * @ingroup libssh_misc diff --git a/libssh/src/gssapi.c b/libssh/src/gssapi.c new file mode 100644 index 00000000..c92c66cb --- /dev/null +++ b/libssh/src/gssapi.c @@ -0,0 +1,947 @@ +/* + * This file is part of the SSH Library + * + * Copyright (c) 2013 by Aris Adamantiadis + * + * 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 +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/** current state of an GSSAPI authentication */ +enum ssh_gssapi_state_e { + SSH_GSSAPI_STATE_NONE, /* no status */ + SSH_GSSAPI_STATE_RCV_TOKEN, /* Expecting a token */ + SSH_GSSAPI_STATE_RCV_MIC, /* Expecting a MIC */ +}; + +struct ssh_gssapi_struct{ + enum ssh_gssapi_state_e state; /* current state */ + struct gss_OID_desc_struct mech; /* mechanism being elected for auth */ + gss_cred_id_t server_creds; /* credentials of server */ + gss_cred_id_t client_creds; /* creds of the client */ + gss_ctx_id_t ctx; /* the authentication context */ + gss_name_t client_name; /* Identity of the client */ + char *user; /* username of client */ + char *canonic_user; /* canonic form of the client's username */ + char *service; /* name of the service */ + struct { + gss_name_t server_name; /* identity of server */ + gss_OID oid; /* mech being used for authentication */ + gss_cred_id_t client_deleg_creds; /* delegated creds (const, not freeable) */ + } client; +}; + + +/** @internal + * @initializes a gssapi context for authentication + */ +static int ssh_gssapi_init(ssh_session session){ + if (session->gssapi != NULL) + return SSH_OK; + session->gssapi = malloc(sizeof(struct ssh_gssapi_struct)); + if(!session->gssapi){ + ssh_set_error_oom(session); + return SSH_ERROR; + } + ZERO_STRUCTP(session->gssapi); + session->gssapi->server_creds = GSS_C_NO_CREDENTIAL; + session->gssapi->client_creds = GSS_C_NO_CREDENTIAL; + session->gssapi->ctx = GSS_C_NO_CONTEXT; + session->gssapi->state = SSH_GSSAPI_STATE_NONE; + return SSH_OK; +} + +/** @internal + * @frees a gssapi context + */ +static void ssh_gssapi_free(ssh_session session){ + OM_uint32 min; + if (session->gssapi == NULL) + return; + if (session->gssapi->mech.elements) + SAFE_FREE(session->gssapi->mech.elements); + if (session->gssapi->user) + SAFE_FREE(session->gssapi->user); + if (session->gssapi->server_creds) + gss_release_cred(&min,&session->gssapi->server_creds); + SAFE_FREE(session->gssapi); +} + +SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token){ +#ifdef WITH_SERVER + if(session->server) + return ssh_packet_userauth_gssapi_token_server(session, type, packet, user); +#endif + return ssh_packet_userauth_gssapi_token_client(session, type, packet, user); +} +#ifdef WITH_SERVER + +/** @internal + * @brief sends a SSH_MSG_USERAUTH_GSSAPI_RESPONSE packet + * @param[in] oid the OID that was selected for authentication + */ +static int ssh_gssapi_send_response(ssh_session session, ssh_string oid){ + if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_GSSAPI_RESPONSE) < 0 || + buffer_add_ssh_string(session->out_buffer,oid) < 0) { + ssh_set_error_oom(session); + return SSH_ERROR; + } + + packet_send(session); + SSH_LOG(SSH_LOG_PACKET, + "Sent SSH_MSG_USERAUTH_GSSAPI_RESPONSE"); + return SSH_OK; +} + +#endif /* WITH_SERVER */ + +static void ssh_gssapi_log_error(int verb, const char *msg, int maj_stat){ + gss_buffer_desc buffer; + OM_uint32 dummy, message_context; + gss_display_status(&dummy,maj_stat,GSS_C_GSS_CODE, GSS_C_NO_OID, &message_context, &buffer); + SSH_LOG(verb, "GSSAPI(%s): %s", msg, (const char *)buffer.value); +} + +#ifdef WITH_SERVER + +/** @internal + * @brief handles an user authentication using GSSAPI + */ +int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n_oid, ssh_string *oids){ + char service_name[]="host"; + gss_buffer_desc name_buf; + gss_name_t server_name; /* local server fqdn */ + OM_uint32 maj_stat, min_stat; + unsigned int i; + char *ptr; + gss_OID_set supported; /* oids supported by server */ + gss_OID_set both_supported; /* oids supported by both client and server */ + gss_OID_set selected; /* oid selected for authentication */ + int present=0; + int oid_count=0; + struct gss_OID_desc_struct oid; + int rc; + + if (ssh_callbacks_exists(session->server_callbacks, gssapi_select_oid_function)){ + ssh_string oid_s = session->server_callbacks->gssapi_select_oid_function(session, + user, n_oid, oids, + session->server_callbacks->userdata); + if (oid_s != NULL){ + if (ssh_gssapi_init(session) == SSH_ERROR) + return SSH_ERROR; + session->gssapi->state = SSH_GSSAPI_STATE_RCV_TOKEN; + rc = ssh_gssapi_send_response(session, oid_s); + ssh_string_free(oid_s); + return rc; + } else { + return ssh_auth_reply_default(session,0); + } + } + gss_create_empty_oid_set(&min_stat, &both_supported); + + maj_stat = gss_indicate_mechs(&min_stat, &supported); + for (i=0; i < supported->count; ++i){ + ptr = ssh_get_hexa(supported->elements[i].elements, supported->elements[i].length); + SSH_LOG(SSH_LOG_DEBUG, "Supported mech %d: %s\n", i, ptr); + free(ptr); + } + + for (i=0 ; i< n_oid ; ++i){ + unsigned char *oid_s = (unsigned char *) ssh_string_data(oids[i]); + size_t len = ssh_string_len(oids[i]); + if(len < 2 || oid_s[0] != SSH_OID_TAG || ((size_t)oid_s[1]) != len - 2){ + SSH_LOG(SSH_LOG_WARNING,"GSSAPI: received invalid OID"); + continue; + } + oid.elements = &oid_s[2]; + oid.length = len - 2; + gss_test_oid_set_member(&min_stat,&oid,supported,&present); + if(present){ + gss_add_oid_set_member(&min_stat,&oid,&both_supported); + oid_count++; + } + } + gss_release_oid_set(&min_stat, &supported); + if (oid_count == 0){ + SSH_LOG(SSH_LOG_PROTOCOL,"GSSAPI: no OID match"); + ssh_auth_reply_default(session, 0); + gss_release_oid_set(&min_stat, &both_supported); + return SSH_OK; + } + /* from now we have room for context */ + if (ssh_gssapi_init(session) == SSH_ERROR) + return SSH_ERROR; + + name_buf.value = service_name; + name_buf.length = strlen(name_buf.value) + 1; + maj_stat = gss_import_name(&min_stat, &name_buf, + (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &server_name); + if (maj_stat != GSS_S_COMPLETE) { + SSH_LOG(0, "importing name %d, %d", maj_stat, min_stat); + ssh_gssapi_log_error(0, "importing name", maj_stat); + return -1; + } + + maj_stat = gss_acquire_cred(&min_stat, server_name, 0, + both_supported, GSS_C_ACCEPT, + &session->gssapi->server_creds, &selected, NULL); + gss_release_name(&min_stat, &server_name); + gss_release_oid_set(&min_stat, &both_supported); + + if (maj_stat != GSS_S_COMPLETE) { + SSH_LOG(0, "error acquiring credentials %d, %d", maj_stat, min_stat); + ssh_gssapi_log_error(0, "acquiring creds", maj_stat); + ssh_auth_reply_default(session,0); + return SSH_ERROR; + } + + SSH_LOG(0, "acquiring credentials %d, %d", maj_stat, min_stat); + + /* finding which OID from client we selected */ + for (i=0 ; i< n_oid ; ++i){ + unsigned char *oid_s = (unsigned char *) ssh_string_data(oids[i]); + size_t len = ssh_string_len(oids[i]); + if(len < 2 || oid_s[0] != SSH_OID_TAG || ((size_t)oid_s[1]) != len - 2){ + SSH_LOG(SSH_LOG_WARNING,"GSSAPI: received invalid OID"); + continue; + } + oid.elements = &oid_s[2]; + oid.length = len - 2; + gss_test_oid_set_member(&min_stat,&oid,selected,&present); + if(present){ + SSH_LOG(SSH_LOG_PACKET, "Selected oid %d", i); + break; + } + } + session->gssapi->mech.length = oid.length; + session->gssapi->mech.elements = malloc(oid.length); + if (session->gssapi->mech.elements == NULL){ + ssh_set_error_oom(session); + return SSH_ERROR; + } + memcpy(session->gssapi->mech.elements, oid.elements, oid.length); + gss_release_oid_set(&min_stat, &selected); + session->gssapi->user = strdup(user); + session->gssapi->service = service_name; + session->gssapi->state = SSH_GSSAPI_STATE_RCV_TOKEN; + return ssh_gssapi_send_response(session, oids[i]); +} + +static char *ssh_gssapi_name_to_char(gss_name_t name){ + gss_buffer_desc buffer; + OM_uint32 maj_stat, min_stat; + char *ptr; + maj_stat = gss_display_name(&min_stat, name, &buffer, NULL); + ssh_gssapi_log_error(0, "converting name", maj_stat); + ptr=malloc(buffer.length + 1); + memcpy(ptr, buffer.value, buffer.length); + ptr[buffer.length] = '\0'; + gss_release_buffer(&min_stat, &buffer); + return ptr; + +} + +SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server){ + ssh_string token; + char *hexa; + OM_uint32 maj_stat, min_stat; + gss_buffer_desc input_token, output_token = GSS_C_EMPTY_BUFFER; + gss_name_t client_name = GSS_C_NO_NAME; + OM_uint32 ret_flags=0; + gss_channel_bindings_t input_bindings=GSS_C_NO_CHANNEL_BINDINGS; + int rc; + + (void)user; + (void)type; + + SSH_LOG(SSH_LOG_PACKET,"Received SSH_MSG_USERAUTH_GSSAPI_TOKEN"); + if (!session->gssapi || session->gssapi->state != SSH_GSSAPI_STATE_RCV_TOKEN){ + ssh_set_error(session, SSH_FATAL, "Received SSH_MSG_USERAUTH_GSSAPI_TOKEN in invalid state"); + return SSH_PACKET_USED; + } + token = buffer_get_ssh_string(packet); + + if (token == NULL){ + ssh_set_error(session, SSH_REQUEST_DENIED, "ssh_packet_userauth_gssapi_token: invalid packet"); + return SSH_PACKET_USED; + } + + if (ssh_callbacks_exists(session->server_callbacks, gssapi_accept_sec_ctx_function)){ + ssh_string out_token=NULL; + rc = session->server_callbacks->gssapi_accept_sec_ctx_function(session, + token, &out_token, session->server_callbacks->userdata); + if (rc == SSH_ERROR){ + ssh_auth_reply_default(session, 0); + ssh_gssapi_free(session); + session->gssapi=NULL; + return SSH_PACKET_USED; + } + if (ssh_string_len(out_token) != 0){ + rc = buffer_add_u8(session->out_buffer, + SSH2_MSG_USERAUTH_GSSAPI_TOKEN); + if (rc < 0) { + ssh_set_error_oom(session); + return SSH_PACKET_USED; + } + rc = buffer_add_ssh_string(session->out_buffer, out_token); + if (rc < 0) { + ssh_set_error_oom(session); + return SSH_PACKET_USED; + } + packet_send(session); + ssh_string_free(out_token); + } else { + session->gssapi->state = SSH_GSSAPI_STATE_RCV_MIC; + } + return SSH_PACKET_USED; + } + hexa = ssh_get_hexa(ssh_string_data(token),ssh_string_len(token)); + SSH_LOG(SSH_LOG_PACKET, "GSSAPI Token : %s",hexa); + SAFE_FREE(hexa); + input_token.length = ssh_string_len(token); + input_token.value = ssh_string_data(token); + + maj_stat = gss_accept_sec_context(&min_stat, &session->gssapi->ctx, session->gssapi->server_creds, + &input_token, input_bindings, &client_name, NULL /*mech_oid*/, &output_token, &ret_flags, + NULL /*time*/, &session->gssapi->client_creds); + ssh_gssapi_log_error(0, "accepting token", maj_stat); + ssh_string_free(token); + if (client_name != GSS_C_NO_NAME){ + session->gssapi->client_name = client_name; + session->gssapi->canonic_user = ssh_gssapi_name_to_char(client_name); + } + if (GSS_ERROR(maj_stat)){ + ssh_gssapi_log_error(SSH_LOG_PROTOCOL, "Gssapi error", maj_stat); + ssh_auth_reply_default(session,0); + ssh_gssapi_free(session); + session->gssapi=NULL; + return SSH_PACKET_USED; + } + + if (output_token.length != 0){ + hexa = ssh_get_hexa(output_token.value, output_token.length); + SSH_LOG(SSH_LOG_PACKET, "GSSAPI: sending token %s",hexa); + SAFE_FREE(hexa); + token = ssh_string_new(output_token.length); + ssh_string_fill(token, output_token.value, output_token.length); + buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_GSSAPI_TOKEN); + buffer_add_ssh_string(session->out_buffer,token); + packet_send(session); + ssh_string_free(token); + } + if(maj_stat == GSS_S_COMPLETE){ + session->gssapi->state = SSH_GSSAPI_STATE_RCV_MIC; + } + return SSH_PACKET_USED; +} + +#endif /* WITH_SERVER */ + +static ssh_buffer ssh_gssapi_build_mic(ssh_session session){ + ssh_buffer mic_buffer; + ssh_string str; + int rc; + + str = ssh_string_new(session->current_crypto->digest_len); + if (str == NULL) { + return NULL; + } + ssh_string_fill(str, session->current_crypto->session_id, + session->current_crypto->digest_len); + + mic_buffer = ssh_buffer_new(); + if (mic_buffer == NULL) { + ssh_string_free(str); + return NULL; + } + + rc = buffer_add_ssh_string(mic_buffer, str); + ssh_string_free(str); + if (rc < 0) { + ssh_buffer_free(mic_buffer); + return NULL; + } + + rc = buffer_add_u8(mic_buffer, SSH2_MSG_USERAUTH_REQUEST); + if (rc < 0) { + ssh_buffer_free(mic_buffer); + return NULL; + } + + str = ssh_string_from_char(session->gssapi->user); + if (str == NULL) { + ssh_buffer_free(mic_buffer); + return NULL; + } + + rc = buffer_add_ssh_string(mic_buffer, str); + ssh_string_free(str); + if (rc < 0) { + ssh_buffer_free(mic_buffer); + return NULL; + } + + str = ssh_string_from_char("ssh-connection"); + if (str == NULL) { + ssh_buffer_free(mic_buffer); + return NULL; + } + rc = buffer_add_ssh_string(mic_buffer, str); + ssh_string_free(str); + if (rc < 0) { + ssh_buffer_free(mic_buffer); + return NULL; + } + + str = ssh_string_from_char("gssapi-with-mic"); + if (str == NULL) { + ssh_buffer_free(mic_buffer); + return NULL; + } + + rc = buffer_add_ssh_string(mic_buffer, str); + ssh_string_free(str); + if (rc < 0) { + ssh_buffer_free(mic_buffer); + return NULL; + } + + return mic_buffer; +} + +#ifdef WITH_SERVER + +SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_mic) +{ + ssh_string mic_token; + OM_uint32 maj_stat, min_stat; + gss_buffer_desc mic_buf = GSS_C_EMPTY_BUFFER; + gss_buffer_desc mic_token_buf = GSS_C_EMPTY_BUFFER; + ssh_buffer mic_buffer = NULL; + + (void)user; + (void)type; + + SSH_LOG(SSH_LOG_PACKET,"Received SSH_MSG_USERAUTH_GSSAPI_MIC"); + mic_token = buffer_get_ssh_string(packet); + if (mic_token == NULL) { + ssh_set_error(session, SSH_FATAL, "Missing MIC in packet"); + goto error; + } + if (session->gssapi == NULL + || session->gssapi->state != SSH_GSSAPI_STATE_RCV_MIC) { + ssh_set_error(session, SSH_FATAL, "Received SSH_MSG_USERAUTH_GSSAPI_MIC in invalid state"); + goto error; + } + + mic_buffer = ssh_gssapi_build_mic(session); + if (mic_buffer == NULL) { + ssh_set_error_oom(session); + goto error; + } + if (ssh_callbacks_exists(session->server_callbacks, gssapi_verify_mic_function)){ + int rc = session->server_callbacks->gssapi_verify_mic_function(session, mic_token, + ssh_buffer_get_begin(mic_buffer), ssh_buffer_get_len(mic_buffer), + session->server_callbacks->userdata); + if (rc != SSH_OK) { + goto error; + } + } else { + mic_buf.length = ssh_buffer_get_len(mic_buffer); + mic_buf.value = ssh_buffer_get_begin(mic_buffer); + mic_token_buf.length = ssh_string_len(mic_token); + mic_token_buf.value = ssh_string_data(mic_token); + + maj_stat = gss_verify_mic(&min_stat, session->gssapi->ctx, &mic_buf, &mic_token_buf, NULL); + ssh_gssapi_log_error(0, "verifying MIC", maj_stat); + ssh_gssapi_log_error(0, "verifying MIC (min stat)", min_stat); + if (maj_stat == GSS_S_DEFECTIVE_TOKEN || GSS_ERROR(maj_stat)) { + goto error; + } + } + + if (ssh_callbacks_exists(session->server_callbacks, auth_gssapi_mic_function)){ + switch(session->server_callbacks->auth_gssapi_mic_function(session, + session->gssapi->user, session->gssapi->canonic_user, + session->server_callbacks->userdata)){ + case SSH_AUTH_SUCCESS: + ssh_auth_reply_success(session, 0); + break; + case SSH_AUTH_PARTIAL: + ssh_auth_reply_success(session, 1); + break; + default: + ssh_auth_reply_default(session, 0); + break; + } + } + + goto end; + +error: + ssh_auth_reply_default(session,0); + +end: + ssh_gssapi_free(session); + if (mic_buffer != NULL) { + ssh_buffer_free(mic_buffer); + } + if (mic_token != NULL) { + ssh_string_free(mic_token); + } + + return SSH_PACKET_USED; +} + +/** @brief returns the client credentials of the connected client. + * If the client has given a forwardable token, the SSH server will + * retrieve it. + * @returns gssapi credentials handle. + * @returns NULL if no forwardable token is available. + */ +ssh_gssapi_creds ssh_gssapi_get_creds(ssh_session session){ + if (!session || !session->gssapi || session->gssapi->client_creds == GSS_C_NO_CREDENTIAL) + return NULL; + return (ssh_gssapi_creds)session->gssapi->client_creds; +} + +/** + * @brief Set the forwadable ticket to be given to the server for authentication. + * + * @param[in] creds gssapi credentials handle. + */ +void ssh_gssapi_set_creds(ssh_session session, const ssh_gssapi_creds creds) +{ + if (session == NULL) { + return; + } + if (session->gssapi == NULL) { + ssh_gssapi_init(session); + if (session->gssapi == NULL) { + return; + } + } + + session->gssapi->client.client_deleg_creds = (gss_cred_id_t)creds; +} + +#endif /* SERVER */ + +static int ssh_gssapi_send_auth_mic(ssh_session session, ssh_string *oid_set, int n_oid){ + ssh_string str; + int rc; + int i; + rc = buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST); + if (rc < 0) { + goto fail; + } + /* username */ + str = ssh_string_from_char(session->opts.username); + if (str == NULL) { + goto fail; + } + rc = buffer_add_ssh_string(session->out_buffer, str); + ssh_string_free(str); + if (rc < 0) { + goto fail; + } + /* service */ + str = ssh_string_from_char("ssh-connection"); + if (str == NULL) { + goto fail; + } + rc = buffer_add_ssh_string(session->out_buffer, str); + ssh_string_free(str); + if (rc < 0) { + goto fail; + } + /* method */ + str = ssh_string_from_char("gssapi-with-mic"); + if (str == NULL) { + goto fail; + } + rc = buffer_add_ssh_string(session->out_buffer, str); + ssh_string_free(str); + if (rc < 0) { + goto fail; + } + + rc = buffer_add_u32(session->out_buffer, htonl(n_oid)); + if (rc < 0) { + goto fail; + } + + for (i=0; iout_buffer, oid_set[i]); + if (rc < 0) { + goto fail; + } + } + + session->auth_state = SSH_AUTH_STATE_GSSAPI_REQUEST_SENT; + return packet_send(session); +fail: + buffer_reinit(session->out_buffer); + return SSH_ERROR; +} + +/** @brief returns the OIDs of the mechs that work with both + * hostname and username + */ +static int ssh_gssapi_match(ssh_session session, char *hostname, char *username, gss_OID_set *valid_oids, int deleg){ + gss_buffer_desc host_namebuf, user_namebuf; + gss_name_t host_name, user_name; + OM_uint32 maj_stat, min_stat; + gss_OID_set supported; + gss_OID oid; + gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + gss_cred_id_t client_creds = GSS_C_NO_CREDENTIAL; + unsigned int i; + char *ptr; + char hostname_buf[256]; + + + gss_create_empty_oid_set(&min_stat, valid_oids); + maj_stat = gss_indicate_mechs(&min_stat, &supported); + for (i=0; i < supported->count; ++i){ + ptr=ssh_get_hexa(supported->elements[i].elements, supported->elements[i].length); + SSH_LOG(SSH_LOG_DEBUG, "GSSAPI oid supported %d : %s\n",i, ptr); + SAFE_FREE(ptr); + } + + user_namebuf.value = username; + user_namebuf.length = strlen(username) + 1; + maj_stat = gss_import_name(&min_stat, &user_namebuf, + (gss_OID) GSS_C_NT_USER_NAME, &user_name); + if (maj_stat != GSS_S_COMPLETE) { + SSH_LOG(SSH_LOG_DEBUG, "importing name %d, %d", maj_stat, min_stat); + ssh_gssapi_log_error(SSH_LOG_DEBUG, "importing name", maj_stat); + return -1; + } + + snprintf(hostname_buf, sizeof(hostname_buf),"host@%s", hostname); + host_namebuf.value = hostname_buf; + host_namebuf.length = strlen(hostname_buf) + 1; + maj_stat = gss_import_name(&min_stat, &host_namebuf, + (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &host_name); + if (maj_stat != GSS_S_COMPLETE) { + SSH_LOG(0, "importing name %d, %d", maj_stat, min_stat); + ssh_gssapi_log_error(0, "importing name", maj_stat); + return -1; + } + + ssh_gssapi_init(session); + session->gssapi->client_name = user_name; + session->gssapi->client.server_name = host_name; + session->gssapi->user = strdup(username); + for (i=0; icount; ++i){ + oid = &supported->elements[i]; + maj_stat = gss_init_sec_context(&min_stat, + session->gssapi->client.client_deleg_creds, &ctx, host_name, oid, + GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | (deleg ? GSS_C_DELEG_FLAG : 0), + 0, NULL, &input_token, NULL, &output_token, NULL, NULL); + if (!GSS_ERROR(maj_stat)){ + gss_OID_set tmp; + if (session->gssapi->client.client_deleg_creds != GSS_C_NO_CREDENTIAL){ + /* we know the oid is ok since init_sec_context worked */ + gss_add_oid_set_member(&min_stat, oid, valid_oids); + SSH_LOG(SSH_LOG_PROTOCOL, "Matched oid %u for server (with forwarding)", i); + } else { + gss_create_empty_oid_set(&min_stat, &tmp); + gss_add_oid_set_member(&min_stat, oid, &tmp); + maj_stat = gss_acquire_cred(&min_stat, user_name, 0, + tmp, GSS_C_INITIATE, + &client_creds, NULL, NULL); + gss_release_oid_set(&min_stat, &tmp); + if (!GSS_ERROR(maj_stat)){ + gss_release_cred(&min_stat, &client_creds); + gss_add_oid_set_member(&min_stat,oid,valid_oids); + SSH_LOG(SSH_LOG_PROTOCOL, "Matched oid %u for server", i); + } + } + } + gss_delete_sec_context(&min_stat,&ctx, &output_token); + ctx = GSS_C_NO_CONTEXT; + } + + return SSH_OK; +} + +/** + * @brief launches a gssapi-with-mic auth request + * @returns SSH_AUTH_ERROR: A serious error happened\n + * SSH_AUTH_DENIED: Authentication failed : use another method\n + * SSH_AUTH_AGAIN: In nonblocking mode, you've got to call this again + * later. + */ +int ssh_gssapi_auth_mic(ssh_session session){ + int i; + gss_OID_set selected; /* oid selected for authentication */ + ssh_string *oids; + int rc; + int n_oids = 0; + + if (ssh_gssapi_init(session) == SSH_ERROR) + return SSH_AUTH_ERROR; + + + SSH_LOG(SSH_LOG_PROTOCOL, "Authenticating with gssapi to host %s with user %s", + session->opts.host, session->opts.username); + rc = ssh_gssapi_match(session,session->opts.host, session->opts.username, &selected, 0); + if (rc == SSH_ERROR) + return SSH_AUTH_DENIED; + + n_oids = selected->count; + SSH_LOG(SSH_LOG_PROTOCOL, "Sending %d oids", n_oids); + + oids = calloc(n_oids, sizeof(ssh_string)); + + for (i=0; ielements[i].length + 2); + ((unsigned char *)oids[i]->data)[0] = SSH_OID_TAG; + ((unsigned char *)oids[i]->data)[1] = selected->elements[i].length; + memcpy((unsigned char *)oids[i]->data + 2, selected->elements[i].elements, + selected->elements[i].length); + } + + rc = ssh_gssapi_send_auth_mic(session, oids, n_oids); + for (i = 0; i < n_oids; i++) { + ssh_string_free(oids[i]); + } + free(oids); + if (rc != SSH_ERROR) { + return SSH_AUTH_AGAIN; + } + + return SSH_AUTH_ERROR; +} + +static gss_OID ssh_gssapi_oid_from_string(ssh_string oid_s){ + gss_OID ret = malloc(sizeof (gss_OID_desc)); + unsigned char *data = ssh_string_data(oid_s); + size_t len = ssh_string_len(oid_s); + if(len > 256 || len <= 2){ + SAFE_FREE(ret); + return NULL; + } + if(data[0] != SSH_OID_TAG || data[1] != len - 2){ + SAFE_FREE(ret); + return NULL; + } + ret->elements = malloc(len - 2); + memcpy(ret->elements, &data[2], len-2); + ret->length = len-2; + return ret; +} + +SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_response){ + ssh_string oid_s; + gss_OID oid; + gss_uint32 maj_stat, min_stat; + int deleg = 0; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + gss_OID_set tmp; + char *hexa; + ssh_string token; + gss_cred_id_t creds = GSS_C_NO_CREDENTIAL; + (void)type; + (void)user; + + SSH_LOG(SSH_LOG_PACKET, "Received SSH_USERAUTH_GSSAPI_RESPONSE"); + if (session->auth_state != SSH_AUTH_STATE_GSSAPI_REQUEST_SENT){ + ssh_set_error(session, SSH_FATAL, "Invalid state in ssh_packet_userauth_gssapi_response"); + return SSH_PACKET_USED; + } + oid_s = buffer_get_ssh_string(packet); + if (!oid_s){ + ssh_set_error(session, SSH_FATAL, "Missing OID"); + return SSH_PACKET_USED; + } + oid = ssh_gssapi_oid_from_string(oid_s); + ssh_string_free(oid_s); + if (!oid) { + ssh_set_error(session, SSH_FATAL, "Invalid OID"); + return SSH_PACKET_USED; + } + if (session->gssapi->client.client_deleg_creds != GSS_C_NO_CREDENTIAL) + creds = session->gssapi->client.client_deleg_creds; + if (creds == GSS_C_NO_CREDENTIAL){ + gss_create_empty_oid_set(&min_stat, &tmp); + gss_add_oid_set_member(&min_stat, oid, &tmp); + maj_stat = gss_acquire_cred(&min_stat, session->gssapi->client_name, 0, + tmp, GSS_C_INITIATE, + &session->gssapi->client_creds, NULL, NULL); + gss_release_oid_set(&min_stat, &tmp); + if (GSS_ERROR(maj_stat)){ + ssh_gssapi_log_error(SSH_LOG_WARNING,"Error acquiring credentials",maj_stat); + return SSH_PACKET_USED; + } + } + /* prepare the first TOKEN response */ + maj_stat = gss_init_sec_context(&min_stat, + creds, &session->gssapi->ctx, session->gssapi->client.server_name, oid, + GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | (deleg ? GSS_C_DELEG_FLAG : 0), + 0, NULL, &input_token, NULL, &output_token, NULL, NULL); + if(GSS_ERROR(maj_stat)){ + ssh_gssapi_log_error(SSH_LOG_WARNING, "Initializing gssapi context", maj_stat); + return SSH_PACKET_USED; + } + if (output_token.length != 0){ + hexa = ssh_get_hexa(output_token.value, output_token.length); + SSH_LOG(SSH_LOG_PACKET, "GSSAPI: sending token %s",hexa); + SAFE_FREE(hexa); + token = ssh_string_new(output_token.length); + ssh_string_fill(token, output_token.value, output_token.length); + buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_GSSAPI_TOKEN); + buffer_add_ssh_string(session->out_buffer,token); + packet_send(session); + ssh_string_free(token); + session->auth_state = SSH_AUTH_STATE_GSSAPI_TOKEN; + } + session->gssapi->client.oid = oid; + return SSH_PACKET_USED; +} + +static int ssh_gssapi_send_mic(ssh_session session){ + OM_uint32 maj_stat, min_stat; + gss_buffer_desc mic_buf = GSS_C_EMPTY_BUFFER; + gss_buffer_desc mic_token_buf = GSS_C_EMPTY_BUFFER; + ssh_buffer mic_buffer; + int rc; + + SSH_LOG(SSH_LOG_PACKET,"Sending SSH_MSG_USERAUTH_GSSAPI_MIC"); + + mic_buffer = ssh_gssapi_build_mic(session); + if (mic_buffer == NULL) { + ssh_set_error_oom(session); + return SSH_ERROR; + } + mic_buf.length = ssh_buffer_get_len(mic_buffer); + mic_buf.value = ssh_buffer_get_begin(mic_buffer); + + maj_stat = gss_get_mic(&min_stat,session->gssapi->ctx, GSS_C_QOP_DEFAULT, &mic_buf, &mic_token_buf); + if (GSS_ERROR(maj_stat)){ + ssh_buffer_free(mic_buffer); + ssh_gssapi_log_error(0, "generating MIC", maj_stat); + return SSH_ERROR; + } + + rc = buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_GSSAPI_MIC); + if (rc < 0) { + ssh_buffer_free(mic_buffer); + ssh_set_error_oom(session); + return SSH_ERROR; + } + + rc = buffer_add_u32(session->out_buffer, htonl(mic_token_buf.length)); + if (rc < 0) { + ssh_buffer_free(mic_buffer); + ssh_set_error_oom(session); + return SSH_ERROR; + } + + rc = buffer_add_data(session->out_buffer, mic_token_buf.value, mic_token_buf.length); + ssh_buffer_free(mic_buffer); + if (rc < 0) { + ssh_set_error_oom(session); + return SSH_ERROR; + } + + return packet_send(session); +} + +SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_client){ + ssh_string token; + char *hexa; + OM_uint32 maj_stat, min_stat; + gss_buffer_desc input_token, output_token = GSS_C_EMPTY_BUFFER; + gss_cred_id_t creds = GSS_C_NO_CREDENTIAL; + int deleg = 0; + (void)user; + (void)type; + + SSH_LOG(SSH_LOG_PACKET,"Received SSH_MSG_USERAUTH_GSSAPI_TOKEN"); + if (!session->gssapi || session->auth_state != SSH_AUTH_STATE_GSSAPI_TOKEN){ + ssh_set_error(session, SSH_FATAL, "Received SSH_MSG_USERAUTH_GSSAPI_TOKEN in invalid state"); + return SSH_PACKET_USED; + } + token = buffer_get_ssh_string(packet); + + if (token == NULL){ + ssh_set_error(session, SSH_REQUEST_DENIED, "ssh_packet_userauth_gssapi_token: invalid packet"); + return SSH_PACKET_USED; + } + hexa = ssh_get_hexa(ssh_string_data(token),ssh_string_len(token)); + SSH_LOG(SSH_LOG_PACKET, "GSSAPI Token : %s",hexa); + SAFE_FREE(hexa); + input_token.length = ssh_string_len(token); + input_token.value = ssh_string_data(token); + if (session->gssapi->client.client_deleg_creds != GSS_C_NO_CREDENTIAL) + creds = session->gssapi->client.client_deleg_creds; + else + creds = session->gssapi->client_creds; + maj_stat = gss_init_sec_context(&min_stat, + creds, &session->gssapi->ctx, session->gssapi->client.server_name, session->gssapi->client.oid, + GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | (deleg ? GSS_C_DELEG_FLAG : 0), + 0, NULL, &input_token, NULL, &output_token, NULL, NULL); + + ssh_gssapi_log_error(0, "accepting token", maj_stat); + ssh_string_free(token); + if (GSS_ERROR(maj_stat)){ + ssh_gssapi_log_error(SSH_LOG_PROTOCOL, "Gssapi error", maj_stat); + ssh_gssapi_free(session); + session->gssapi=NULL; + return SSH_PACKET_USED; + } + + if (output_token.length != 0){ + hexa = ssh_get_hexa(output_token.value, output_token.length); + SSH_LOG(SSH_LOG_PACKET, "GSSAPI: sending token %s",hexa); + SAFE_FREE(hexa); + token = ssh_string_new(output_token.length); + ssh_string_fill(token, output_token.value, output_token.length); + buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_GSSAPI_TOKEN); + buffer_add_ssh_string(session->out_buffer,token); + packet_send(session); + ssh_string_free(token); + } + if(maj_stat == GSS_S_COMPLETE){ + session->auth_state = SSH_AUTH_STATE_NONE; + ssh_gssapi_send_mic(session); + } + return SSH_PACKET_USED; +} diff --git a/libssh/src/kex.c b/libssh/src/kex.c index c678731e..4de5a658 100644 --- a/libssh/src/kex.c +++ b/libssh/src/kex.c @@ -272,12 +272,11 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit){ char *strings[KEX_METHODS_SIZE]; int i; - enter_function(); (void)type; (void)user; memset(strings, 0, sizeof(strings)); if (session->session_state == SSH_SESSION_STATE_AUTHENTICATED){ - ssh_log(session,SSH_LOG_WARNING, "Other side initiating key re-exchange"); + SSH_LOG(SSH_LOG_WARNING, "Other side initiating key re-exchange"); } else if(session->session_state != SSH_SESSION_STATE_INITIAL_KEX){ ssh_set_error(session,SSH_FATAL,"SSH_KEXINIT received in wrong state"); goto error; @@ -335,7 +334,6 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit){ } } - leave_function(); session->session_state=SSH_SESSION_STATE_KEXINIT_RECEIVED; session->dh_handshake_state=DH_STATE_INIT; session->ssh_connection_callback(session); @@ -347,11 +345,11 @@ error: } session->session_state = SSH_SESSION_STATE_ERROR; - leave_function(); + return SSH_PACKET_USED; } -void ssh_list_kex(ssh_session session, struct ssh_kex_struct *kex) { +void ssh_list_kex(struct ssh_kex_struct *kex) { int i = 0; #ifdef DEBUG_CRYPTO @@ -362,7 +360,7 @@ void ssh_list_kex(ssh_session session, struct ssh_kex_struct *kex) { if (kex->methods[i] == NULL) { continue; } - ssh_log(session, SSH_LOG_FUNCTIONS, "%s: %s", + SSH_LOG(SSH_LOG_FUNCTIONS, "%s: %s", ssh_kex_descriptions[i], kex->methods[i]); } } @@ -395,17 +393,14 @@ int set_client_kex(ssh_session session){ int ssh_kex_select_methods (ssh_session session){ struct ssh_kex_struct *server = &session->next_crypto->server_kex; struct ssh_kex_struct *client = &session->next_crypto->client_kex; - int rc = SSH_ERROR; int i; - enter_function(); - for (i = 0; i < KEX_METHODS_SIZE; i++) { session->next_crypto->kex_methods[i]=ssh_find_matching(server->methods[i],client->methods[i]); if(session->next_crypto->kex_methods[i] == NULL && i < SSH_LANG_C_S){ ssh_set_error(session,SSH_FATAL,"kex error : no match for method %s: server [%s], client [%s]", ssh_kex_descriptions[i],server->methods[i],client->methods[i]); - goto error; + return SSH_ERROR; } else if ((i >= SSH_LANG_C_S) && (session->next_crypto->kex_methods[i] == NULL)) { /* we can safely do that for languages */ session->next_crypto->kex_methods[i] = strdup(""); @@ -418,10 +413,8 @@ int ssh_kex_select_methods (ssh_session session){ } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp256") == 0){ session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP256; } - rc = SSH_OK; -error: - leave_function(); - return rc; + + return SSH_OK; } @@ -432,8 +425,6 @@ int ssh_send_kex(ssh_session session, int server_kex) { ssh_string str = NULL; int i; - enter_function(); - if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXINIT) < 0) { goto error; } @@ -445,7 +436,7 @@ int ssh_send_kex(ssh_session session, int server_kex) { goto error; } - ssh_list_kex(session, kex); + ssh_list_kex(kex); for (i = 0; i < KEX_METHODS_SIZE; i++) { str = ssh_string_from_char(kex->methods[i]); @@ -471,18 +462,15 @@ int ssh_send_kex(ssh_session session, int server_kex) { } if (packet_send(session) == SSH_ERROR) { - leave_function(); return -1; } - leave_function(); return 0; error: buffer_reinit(session->out_buffer); buffer_reinit(session->out_hashbuf); ssh_string_free(str); - leave_function(); return -1; } diff --git a/libssh/src/kex1.c b/libssh/src/kex1.c index b396a719..22899429 100644 --- a/libssh/src/kex1.c +++ b/libssh/src/kex1.c @@ -247,7 +247,7 @@ static ssh_string encrypt_session_key(ssh_session session, ssh_public_key srvkey } ssh_string_fill(data1, buffer, 32); if (ABS(hlen - slen) < 128){ - ssh_log(session, SSH_LOG_FUNCTIONS, + SSH_LOG(SSH_LOG_FUNCTIONS, "Difference between server modulus and host modulus is only %d. " "It's illegal and may not work", ABS(hlen - slen)); @@ -317,10 +317,10 @@ SSH_PACKET_CALLBACK(ssh_packet_publickey1){ int ko; uint32_t support_3DES = 0; uint32_t support_DES = 0; - enter_function(); + (void)type; (void)user; - ssh_log(session, SSH_LOG_PROTOCOL, "Got a SSH_SMSG_PUBLIC_KEY"); + SSH_LOG(SSH_LOG_PROTOCOL, "Got a SSH_SMSG_PUBLIC_KEY"); if(session->session_state != SSH_SESSION_STATE_INITIAL_KEX){ ssh_set_error(session,SSH_FATAL,"SSH_KEXINIT received in wrong state"); goto error; @@ -354,7 +354,7 @@ SSH_PACKET_CALLBACK(ssh_packet_publickey1){ if ((ko != sizeof(uint32_t)) || !host_mod || !host_exp || !server_mod || !server_exp) { - ssh_log(session, SSH_LOG_RARE, "Invalid SSH_SMSG_PUBLIC_KEY packet"); + SSH_LOG(SSH_LOG_RARE, "Invalid SSH_SMSG_PUBLIC_KEY packet"); ssh_set_error(session, SSH_FATAL, "Invalid SSH_SMSG_PUBLIC_KEY packet"); goto error; } @@ -364,7 +364,7 @@ SSH_PACKET_CALLBACK(ssh_packet_publickey1){ protocol_flags = ntohl(protocol_flags); supported_ciphers_mask = ntohl(supported_ciphers_mask); supported_authentications_mask = ntohl(supported_authentications_mask); - ssh_log(session, SSH_LOG_PROTOCOL, + SSH_LOG(SSH_LOG_PROTOCOL, "Server bits: %d; Host bits: %d; Protocol flags: %.8lx; " "Cipher mask: %.8lx; Auth mask: %.8lx", server_bits, @@ -409,7 +409,7 @@ SSH_PACKET_CALLBACK(ssh_packet_publickey1){ ssh_set_error(session, SSH_FATAL, "Remote server doesn't accept 3DES"); goto error; } - ssh_log(session, SSH_LOG_PROTOCOL, "Sending SSH_CMSG_SESSION_KEY"); + SSH_LOG(SSH_LOG_PROTOCOL, "Sending SSH_CMSG_SESSION_KEY"); if (buffer_add_u8(session->out_buffer, SSH_CMSG_SESSION_KEY) < 0) { goto error; @@ -427,7 +427,7 @@ SSH_PACKET_CALLBACK(ssh_packet_publickey1){ } bits = ssh_string_len(enc_session) * 8 - 7; - ssh_log(session, SSH_LOG_PROTOCOL, "%d bits, %" PRIdS " bytes encrypted session", + SSH_LOG(SSH_LOG_PROTOCOL, "%d bits, %" PRIdS " bytes encrypted session", bits, ssh_string_len(enc_session)); bits = htons(bits); /* the encrypted mpint */ @@ -470,30 +470,28 @@ end: publickey_free(srv); publickey_free(host); - leave_function(); return SSH_PACKET_USED; } int ssh_get_kex1(ssh_session session) { - int ret=SSH_ERROR; - enter_function(); - ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_PUBLIC_KEY"); + SSH_LOG(SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_PUBLIC_KEY"); + /* Here the callback is called */ while(session->session_state==SSH_SESSION_STATE_INITIAL_KEX){ ssh_handle_packets(session, SSH_TIMEOUT_USER); } - if(session->session_state==SSH_SESSION_STATE_ERROR) - goto error; - ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_SUCCESS"); + if (session->session_state==SSH_SESSION_STATE_ERROR) { + return SSH_ERROR; + } + SSH_LOG(SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_SUCCESS"); /* Waiting for SSH_SMSG_SUCCESS */ while(session->session_state==SSH_SESSION_STATE_KEXINIT_RECEIVED){ ssh_handle_packets(session, SSH_TIMEOUT_USER); } - if(session->session_state==SSH_SESSION_STATE_ERROR) - goto error; - ssh_log(session, SSH_LOG_PROTOCOL, "received SSH_SMSG_SUCCESS\n"); - ret=SSH_OK; -error: - leave_function(); - return ret; + if(session->session_state==SSH_SESSION_STATE_ERROR) { + return SSH_ERROR; + } + SSH_LOG(SSH_LOG_PROTOCOL, "received SSH_SMSG_SUCCESS\n"); + + return SSH_OK; } diff --git a/libssh/src/known_hosts.c b/libssh/src/known_hosts.c index a9ae38c1..6e9eb915 100644 --- a/libssh/src/known_hosts.c +++ b/libssh/src/known_hosts.c @@ -106,18 +106,15 @@ static void tokens_free(char **tokens) { * free that value. NULL if no match was found or the file * was not found. */ -static char **ssh_get_knownhost_line(ssh_session session, FILE **file, - const char *filename, const char **found_type) { +static char **ssh_get_knownhost_line(FILE **file, const char *filename, + const char **found_type) { char buffer[4096] = {0}; char *ptr; char **tokens; - enter_function(); - if(*file == NULL){ *file = fopen(filename,"r"); if (*file == NULL) { - leave_function(); return NULL; } } @@ -141,7 +138,7 @@ static char **ssh_get_knownhost_line(ssh_session session, FILE **file, if (tokens == NULL) { fclose(*file); *file = NULL; - leave_function(); + return NULL; } @@ -168,7 +165,7 @@ static char **ssh_get_knownhost_line(ssh_session session, FILE **file, continue; } } - leave_function(); + return tokens; } @@ -176,7 +173,6 @@ static char **ssh_get_knownhost_line(ssh_session session, FILE **file, *file = NULL; /* we did not find anything, end of file*/ - leave_function(); return NULL; } @@ -293,8 +289,8 @@ static int check_public_key(ssh_session session, char **tokens) { * * @returns 1 if it matches, 0 otherwise. */ -static int match_hashed_host(ssh_session session, const char *host, - const char *sourcehash) { +static int match_hashed_host(const char *host, const char *sourcehash) +{ /* Openssh hash structure : * |1|base64 encoded salt|base64 encoded hash * hash is produced that way : @@ -309,16 +305,12 @@ static int match_hashed_host(ssh_session session, const char *host, int match; unsigned int size; - enter_function(); - if (strncmp(sourcehash, "|1|", 3) != 0) { - leave_function(); return 0; } source = strdup(sourcehash + 3); if (source == NULL) { - leave_function(); return 0; } @@ -326,7 +318,7 @@ static int match_hashed_host(ssh_session session, const char *host, if (b64hash == NULL) { /* Invalid hash */ SAFE_FREE(source); - leave_function(); + return 0; } @@ -336,7 +328,7 @@ static int match_hashed_host(ssh_session session, const char *host, salt = base64_to_bin(source); if (salt == NULL) { SAFE_FREE(source); - leave_function(); + return 0; } @@ -344,7 +336,7 @@ static int match_hashed_host(ssh_session session, const char *host, SAFE_FREE(source); if (hash == NULL) { ssh_buffer_free(salt); - leave_function(); + return 0; } @@ -352,7 +344,7 @@ static int match_hashed_host(ssh_session session, const char *host, if (mac == NULL) { ssh_buffer_free(salt); ssh_buffer_free(hash); - leave_function(); + return 0; } size = sizeof(buffer); @@ -369,10 +361,9 @@ static int match_hashed_host(ssh_session session, const char *host, ssh_buffer_free(salt); ssh_buffer_free(hash); - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Matching a hashed host: %s match=%d", host, match); - leave_function(); return match; } @@ -421,13 +412,11 @@ int ssh_is_server_known(ssh_session session) { int match; int ret = SSH_SERVER_NOT_KNOWN; - enter_function(); - if (session->opts.knownhosts == NULL) { if (ssh_options_apply(session) < 0) { ssh_set_error(session, SSH_REQUEST_DENIED, "Can't find a known_hosts file"); - leave_function(); + return SSH_SERVER_FILE_NOT_FOUND; } } @@ -435,14 +424,14 @@ int ssh_is_server_known(ssh_session session) { if (session->opts.host == NULL) { ssh_set_error(session, SSH_FATAL, "Can't verify host in known hosts if the hostname isn't known"); - leave_function(); + return SSH_SERVER_ERROR; } if (session->current_crypto == NULL){ ssh_set_error(session, SSH_FATAL, "ssh_is_host_known called without cryptographic context"); - leave_function(); + return SSH_SERVER_ERROR; } host = ssh_lowercase(session->opts.host); @@ -451,13 +440,12 @@ int ssh_is_server_known(ssh_session session) { ssh_set_error_oom(session); SAFE_FREE(host); SAFE_FREE(hostport); - leave_function(); + return SSH_SERVER_ERROR; } do { - tokens = ssh_get_knownhost_line(session, - &file, + tokens = ssh_get_knownhost_line(&file, session->opts.knownhosts, &type); @@ -465,7 +453,7 @@ int ssh_is_server_known(ssh_session session) { if (tokens == NULL) { break; } - match = match_hashed_host(session, host, tokens[0]); + match = match_hashed_host(host, tokens[0]); if (match == 0){ match = match_hostname(hostport, tokens[0], strlen(tokens[0])); } @@ -473,13 +461,12 @@ int ssh_is_server_known(ssh_session session) { match = match_hostname(host, tokens[0], strlen(tokens[0])); } if (match == 0) { - match = match_hashed_host(session, hostport, tokens[0]); + match = match_hashed_host(hostport, tokens[0]); } if (match) { /* We got a match. Now check the key type */ if (strcmp(session->current_crypto->server_pubkey_type, type) != 0) { - ssh_log(session, - SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "ssh_is_server_known: server type [%s] doesn't match the " "type [%s] in known_hosts file", session->current_crypto->server_pubkey_type, @@ -523,7 +510,6 @@ int ssh_is_server_known(ssh_session session) { } /* Return the current state at end of file */ - leave_function(); return ret; } diff --git a/libssh/src/legacy.c b/libssh/src/legacy.c index 6ad4fdc2..6e7bfffc 100644 --- a/libssh/src/legacy.c +++ b/libssh/src/legacy.c @@ -108,23 +108,21 @@ int ssh_userauth_privatekey_file(ssh_session session, int rc = SSH_AUTH_ERROR; size_t klen = strlen(filename) + 4 + 1; - enter_function(); - pubkeyfile = malloc(klen); if (pubkeyfile == NULL) { ssh_set_error_oom(session); - leave_function(); + return SSH_AUTH_ERROR; } snprintf(pubkeyfile, klen, "%s.pub", filename); pubkey = publickey_from_file(session, pubkeyfile, &type); if (pubkey == NULL) { - ssh_log(session, SSH_LOG_RARE, "Public key file %s not found. Trying to generate it.", pubkeyfile); + SSH_LOG(SSH_LOG_RARE, "Public key file %s not found. Trying to generate it.", pubkeyfile); /* auto-detect the key type with type=0 */ privkey = privatekey_from_file(session, filename, 0, passphrase); } else { - ssh_log(session, SSH_LOG_RARE, "Public key file %s loaded.", pubkeyfile); + SSH_LOG(SSH_LOG_RARE, "Public key file %s loaded.", pubkeyfile); privkey = privatekey_from_file(session, filename, type, passphrase); } if (privkey == NULL) { @@ -138,7 +136,6 @@ error: SAFE_FREE(pubkeyfile); ssh_string_free(pubkey); - leave_function(); return rc; } @@ -610,8 +607,8 @@ int ssh_publickey_to_file(ssh_session session, SAFE_FREE(pubkey_64); SAFE_FREE(user); - ssh_log(session, SSH_LOG_RARE, "Trying to write public key file: %s", file); - ssh_log(session, SSH_LOG_PACKET, "public key file content: %s", buffer); + SSH_LOG(SSH_LOG_RARE, "Trying to write public key file: %s", file); + SSH_LOG(SSH_LOG_PACKET, "public key file content: %s", buffer); fp = fopen(file, "w+"); if (fp == NULL) { @@ -652,9 +649,9 @@ int ssh_try_publickey_from_file(ssh_session session, } } - ssh_log(session, SSH_LOG_PACKET, "Trying to open privatekey %s", keyfile); + SSH_LOG(SSH_LOG_PACKET, "Trying to open privatekey %s", keyfile); if (!ssh_file_readaccess_ok(keyfile)) { - ssh_log(session, SSH_LOG_PACKET, "Failed to open privatekey %s", keyfile); + SSH_LOG(SSH_LOG_PACKET, "Failed to open privatekey %s", keyfile); return -1; } @@ -665,16 +662,16 @@ int ssh_try_publickey_from_file(ssh_session session, } snprintf(pubkey_file, len, "%s.pub", keyfile); - ssh_log(session, SSH_LOG_PACKET, "Trying to open publickey %s", + SSH_LOG(SSH_LOG_PACKET, "Trying to open publickey %s", pubkey_file); if (!ssh_file_readaccess_ok(pubkey_file)) { - ssh_log(session, SSH_LOG_PACKET, "Failed to open publickey %s", + SSH_LOG(SSH_LOG_PACKET, "Failed to open publickey %s", pubkey_file); SAFE_FREE(pubkey_file); return 1; } - ssh_log(session, SSH_LOG_PACKET, "Success opening public and private key"); + SSH_LOG(SSH_LOG_PACKET, "Success opening public and private key"); /* * We are sure both the private and public key file is readable. We return @@ -682,7 +679,7 @@ int ssh_try_publickey_from_file(ssh_session session, */ pubkey_string = publickey_from_file(session, pubkey_file, &pubkey_type); if (pubkey_string == NULL) { - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Wasn't able to open public key file %s: %s", pubkey_file, ssh_get_error(session)); diff --git a/libssh/src/log.c b/libssh/src/log.c index 687afabc..fba5fdc4 100644 --- a/libssh/src/log.c +++ b/libssh/src/log.c @@ -35,6 +35,10 @@ #include "libssh/misc.h" #include "libssh/session.h" +LIBSSH_THREAD int ssh_log_level; +LIBSSH_THREAD ssh_logging_callback ssh_log_cb; +LIBSSH_THREAD void *ssh_log_userdata; + /** * @defgroup libssh_log The SSH logging functions. * @ingroup libssh @@ -70,46 +74,60 @@ static int current_timestring(int hires, char *buf, size_t len) return 0; } -void ssh_log_function(int verbosity, - const char *function, - const char *buffer) +static void ssh_log_stderr(int verbosity, + const char *function, + const char *buffer) { char date[64] = {0}; int rc; rc = current_timestring(1, date, sizeof(date)); if (rc == 0) { - fprintf(stderr, "[%s, %d] %s", date, verbosity, function); + fprintf(stderr, "[%s, %d] %s:", date, verbosity, function); } else { fprintf(stderr, "[%d] %s", verbosity, function); } + fprintf(stderr, " %s\n", buffer); } -/** @internal - * @brief do the actual work of logging an event - */ - -static void do_ssh_log(struct ssh_common_struct *common, - int verbosity, - const char *function, - const char *buffer) { - if (common->callbacks && common->callbacks->log_function) { +void ssh_log_function(int verbosity, + const char *function, + const char *buffer) +{ + ssh_logging_callback log_fn = ssh_get_log_callback(); + if (log_fn) { char buf[1024]; snprintf(buf, sizeof(buf), "%s: %s", function, buffer); - common->callbacks->log_function((ssh_session)common, - verbosity, - buf, - common->callbacks->userdata); + log_fn(verbosity, + function, + buf, + ssh_get_log_userdata()); return; } - ssh_log_function(verbosity, function, buffer); + ssh_log_stderr(verbosity, function, buffer); } -/* legacy function */ +void _ssh_log(int verbosity, + const char *function, + const char *format, ...) +{ + char buffer[1024]; + va_list va; + + if (verbosity <= ssh_get_log_level()) { + va_start(va, format); + vsnprintf(buffer, sizeof(buffer), format, va); + va_end(va); + ssh_log_function(verbosity, function, buffer); + } +} + +/* LEGACY */ + void ssh_log(ssh_session session, int verbosity, const char *format, ...) @@ -121,7 +139,7 @@ void ssh_log(ssh_session session, va_start(va, format); vsnprintf(buffer, sizeof(buffer), format, va); va_end(va); - do_ssh_log(&session->common, verbosity, "", buffer); + ssh_log_function(verbosity, "", buffer); } } @@ -143,10 +161,77 @@ void ssh_log_common(struct ssh_common_struct *common, va_start(va, format); vsnprintf(buffer, sizeof(buffer), format, va); va_end(va); - do_ssh_log(common, verbosity, function, buffer); + ssh_log_function(verbosity, function, buffer); } } + +/* PUBLIC */ + +/** + * @brief Set the log level of the library. + * + * @param[in] level The level to set. + * + * @return SSH_OK on success, SSH_ERROR on error. + */ +int ssh_set_log_level(int level) { + if (level < 0) { + return SSH_ERROR; + } + + ssh_log_level = level; + + return SSH_OK; +} + +/** + * @brief Get the log level of the library. + * + * @return The value of the log level. + */ +int ssh_get_log_level(void) { + return ssh_log_level; +} + +int ssh_set_log_callback(ssh_logging_callback cb) { + if (cb == NULL) { + return SSH_ERROR; + } + + ssh_log_cb = cb; + + return SSH_OK; +} + +ssh_logging_callback ssh_get_log_callback(void) { + return ssh_log_cb; +} + +/** + * @brief Get the userdata of the logging function. + * + * @return The userdata if set or NULL. + */ +void *ssh_get_log_userdata(void) +{ + return ssh_log_userdata; +} + +/** + * @brief Set the userdata for the logging function. + * + * @param[in] data The userdata to set. + * + * @return SSH_OK on success. + */ +int ssh_set_log_userdata(void *data) +{ + ssh_log_userdata = data; + + return 0; +} + /** @} */ /* vim: set ts=4 sw=4 et cindent: */ diff --git a/libssh/src/messages.c b/libssh/src/messages.c index 5fcdd04e..003ecf8e 100644 --- a/libssh/src/messages.c +++ b/libssh/src/messages.c @@ -44,6 +44,7 @@ #include "libssh/messages.h" #ifdef WITH_SERVER #include "libssh/server.h" +#include "libssh/gssapi.h" #endif /** @@ -78,7 +79,7 @@ static ssh_message ssh_message_new(ssh_session session){ * SSH_MSG_UNIMPLEMENTED */ static int ssh_message_reply_default(ssh_message msg) { - ssh_log(msg->session, SSH_LOG_FUNCTIONS, "Reporting unknown packet"); + SSH_LOG(SSH_LOG_FUNCTIONS, "Reporting unknown packet"); if (buffer_add_u8(msg->session->out_buffer, SSH2_MSG_UNIMPLEMENTED) < 0) goto error; @@ -92,8 +93,217 @@ static int ssh_message_reply_default(ssh_message msg) { #endif +#ifdef WITH_SERVER + +static int ssh_execute_server_request(ssh_session session, ssh_message msg) +{ + ssh_channel channel = NULL; + int rc; + + switch(msg->type) { + case SSH_REQUEST_AUTH: + if (msg->auth_request.method == SSH_AUTH_METHOD_PASSWORD && + ssh_callbacks_exists(session->server_callbacks, auth_password_function)) { + rc = session->server_callbacks->auth_password_function(session, + msg->auth_request.username, msg->auth_request.password, + session->server_callbacks->userdata); + if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_PARTIAL) { + ssh_message_auth_reply_success(msg, rc == SSH_AUTH_PARTIAL); + } else { + ssh_message_reply_default(msg); + } + + return SSH_OK; + } else if(msg->auth_request.method == SSH_AUTH_METHOD_PUBLICKEY && + ssh_callbacks_exists(session->server_callbacks, auth_pubkey_function)) { + rc = session->server_callbacks->auth_pubkey_function(session, + msg->auth_request.username, msg->auth_request.pubkey, + msg->auth_request.signature_state, + session->server_callbacks->userdata); + if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_PARTIAL){ + ssh_message_auth_reply_success(msg, rc == SSH_AUTH_PARTIAL); + } else { + ssh_message_reply_default(msg); + } + + return SSH_OK; + } + break; + case SSH_REQUEST_CHANNEL_OPEN: + if (msg->channel_request_open.type == SSH_CHANNEL_SESSION && + ssh_callbacks_exists(session->server_callbacks, channel_open_request_session_function)) { + channel = session->server_callbacks->channel_open_request_session_function(session, + session->server_callbacks->userdata); + if (channel != NULL) { + rc = ssh_message_channel_request_open_reply_accept_channel(msg, channel); + return SSH_OK; + } else { + ssh_message_reply_default(msg); + } + + return SSH_OK; + } + break; + case SSH_REQUEST_CHANNEL: + channel = msg->channel_request.channel; + + if (msg->channel_request.type == SSH_CHANNEL_REQUEST_PTY && + ssh_callbacks_exists(channel->callbacks, channel_pty_request_function)) { + rc = channel->callbacks->channel_pty_request_function(session, channel, + msg->channel_request.TERM, + msg->channel_request.width, msg->channel_request.height, + msg->channel_request.pxwidth, msg->channel_request.pxheight, + channel->callbacks->userdata); + if (rc == 0) { + ssh_message_channel_request_reply_success(msg); + } else { + ssh_message_reply_default(msg); + } + + return SSH_OK; + } else if (msg->channel_request.type == SSH_CHANNEL_REQUEST_SHELL && + ssh_callbacks_exists(channel->callbacks, channel_shell_request_function)) { + rc = channel->callbacks->channel_shell_request_function(session, + channel, + channel->callbacks->userdata); + if (rc == 0) { + ssh_message_channel_request_reply_success(msg); + } else { + ssh_message_reply_default(msg); + } + + return SSH_OK; + } else if (msg->channel_request.type == SSH_CHANNEL_REQUEST_X11 && + ssh_callbacks_exists(channel->callbacks, channel_x11_req_function)) { + channel->callbacks->channel_x11_req_function(session, + channel, + msg->channel_request.x11_single_connection, + msg->channel_request.x11_auth_protocol, + msg->channel_request.x11_auth_cookie, + msg->channel_request.x11_screen_number, + channel->callbacks->userdata); + ssh_message_channel_request_reply_success(msg); + + return SSH_OK; + } else if (msg->channel_request.type == SSH_CHANNEL_REQUEST_WINDOW_CHANGE && + ssh_callbacks_exists(channel->callbacks, channel_pty_window_change_function)) { + rc = channel->callbacks->channel_pty_window_change_function(session, + channel, + msg->channel_request.height, msg->channel_request.width, + msg->channel_request.pxheight, msg->channel_request.pxwidth, + channel->callbacks->userdata); + } else if (msg->channel_request.type == SSH_CHANNEL_REQUEST_EXEC && + ssh_callbacks_exists(channel->callbacks, channel_exec_request_function)) { + rc = channel->callbacks->channel_exec_request_function(session, + channel, + msg->channel_request.command, + channel->callbacks->userdata); + if (rc == 0) { + ssh_message_channel_request_reply_success(msg); + } else { + ssh_message_reply_default(msg); + } + + return SSH_OK; + } else if (msg->channel_request.type == SSH_CHANNEL_REQUEST_ENV && + ssh_callbacks_exists(channel->callbacks, channel_env_request_function)) { + rc = channel->callbacks->channel_env_request_function(session, + channel, + msg->channel_request.var_name, msg->channel_request.var_value, + channel->callbacks->userdata); + if (rc == 0) { + ssh_message_channel_request_reply_success(msg); + } else { + ssh_message_reply_default(msg); + } + + return SSH_OK; + } else if (msg->channel_request.type == SSH_CHANNEL_REQUEST_SUBSYSTEM && + ssh_callbacks_exists(channel->callbacks, channel_subsystem_request_function)) { + rc = channel->callbacks->channel_subsystem_request_function(session, + channel, + msg->channel_request.subsystem, + channel->callbacks->userdata); + if (rc == 0) { + ssh_message_channel_request_reply_success(msg); + } else { + ssh_message_reply_default(msg); + } + + return SSH_OK; + } + break; + case SSH_REQUEST_SERVICE: + if (ssh_callbacks_exists(session->server_callbacks, service_request_function)) { + rc = session->server_callbacks->service_request_function(session, + msg->service_request.service, session->server_callbacks->userdata); + if (rc == 0) { + ssh_message_reply_default(msg); + } else { + ssh_disconnect(session); + } + + return SSH_OK; + } + + return SSH_AGAIN; + case SSH_REQUEST_GLOBAL: + break; + } + + return SSH_AGAIN; +} + +static int ssh_execute_client_request(ssh_session session, ssh_message msg) +{ + ssh_channel channel = NULL; + int rc = SSH_AGAIN; + + if (msg->type == SSH_REQUEST_CHANNEL_OPEN + && msg->channel_request_open.type == SSH_CHANNEL_X11 + && ssh_callbacks_exists(session->common.callbacks, channel_open_request_x11_function)) { + channel = session->common.callbacks->channel_open_request_x11_function (session, + msg->channel_request_open.originator, + msg->channel_request_open.originator_port, + session->common.callbacks->userdata); + if (channel != NULL) { + rc = ssh_message_channel_request_open_reply_accept_channel(msg, channel); + + return rc; + } else { + ssh_message_reply_default(msg); + } + + return SSH_OK; + } + + return rc; +} + +/** @internal + * Executes the callbacks defined in session->server_callbacks, out of an ssh_message + * I don't like ssh_message interface but it works. + * @returns SSH_OK if the message has been handled, or SSH_AGAIN otherwise. + */ +static int ssh_execute_server_callbacks(ssh_session session, ssh_message msg){ + int rc = SSH_AGAIN; + + if (session->server_callbacks != NULL){ + rc = ssh_execute_server_request(session, msg); + } + + /* This one is in fact a client callback... */ + if (session->common.callbacks != NULL) { + rc = ssh_execute_client_request(session, msg); + } + + return rc; +} + +#endif /* WITH_SERVER */ + static int ssh_execute_message_callback(ssh_session session, ssh_message msg) { - int ret; + int ret; if(session->ssh_message_callback != NULL) { ret = session->ssh_message_callback(session, msg, session->ssh_message_callback_data); @@ -116,23 +326,43 @@ static int ssh_execute_message_callback(ssh_session session, ssh_message msg) { return SSH_OK; } - /** * @internal * - * @brief Add a message to the current queue of messages to be parsed. + * @brief Add a message to the current queue of messages to be parsed and/or call + * the various callback functions. * * @param[in] session The SSH session to add the message. * * @param[in] message The message to add to the queue. */ void ssh_message_queue(ssh_session session, ssh_message message){ - if(message) { + if (message != NULL) { +#ifdef WITH_SERVER + int ret; + /* probably not the best place to execute server callbacks, but still better + * than nothing. + */ + ret = ssh_execute_server_callbacks(session, message); + if (ret == SSH_OK){ + ssh_message_free(message); + return; + } +#endif /* WITH_SERVER */ + if(session->ssh_message_callback != NULL) { + ssh_execute_message_callback(session, message); + return; + } + if (session->server_callbacks != NULL){ + /* if we have server callbacks, but nothing was executed, it means we are + * in non-synchronous mode, and we just don't care about the message we + * received. Just send a default response. Do not queue it. + */ + ssh_message_reply_default(message); + ssh_message_free(message); + return; + } if(session->ssh_message_list == NULL) { - if(session->ssh_message_callback != NULL) { - ssh_execute_message_callback(session, message); - return; - } session->ssh_message_list = ssh_list_new(); } if (session->ssh_message_list != NULL) { @@ -189,11 +419,9 @@ static int ssh_message_termination(void *s){ ssh_message ssh_message_get(ssh_session session) { ssh_message msg = NULL; int rc; - enter_function(); msg=ssh_message_pop_head(session); if(msg) { - leave_function(); return msg; } if(session->ssh_message_list == NULL) { @@ -204,7 +432,7 @@ ssh_message ssh_message_get(ssh_session session) { if(rc || session->session_state == SSH_SESSION_STATE_ERROR) return NULL; msg=ssh_list_pop_head(ssh_message, session->ssh_message_list); - leave_function(); + return msg; } @@ -292,12 +520,13 @@ void ssh_message_free(ssh_message msg){ SAFE_FREE(msg); } +#ifdef WITH_SERVER + SSH_PACKET_CALLBACK(ssh_packet_service_request){ ssh_string service = NULL; char *service_c = NULL; ssh_message msg=NULL; - enter_function(); (void)type; (void)user; service = buffer_get_ssh_string(packet); @@ -310,7 +539,7 @@ SSH_PACKET_CALLBACK(ssh_packet_service_request){ if (service_c == NULL) { goto error; } - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Received a SERVICE_REQUEST for service %s", service_c); msg=ssh_message_new(session); if(!msg){ @@ -323,7 +552,7 @@ error: ssh_string_free(service); if(msg != NULL) ssh_message_queue(session,msg); - leave_function(); + return SSH_PACKET_USED; } @@ -458,8 +687,6 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_request){ char *method = NULL; uint32_t method_size = 0; - enter_function(); - (void)user; (void)type; @@ -501,7 +728,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_request){ goto error; } - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Auth request for service %s, method %s for user '%s'", service, method, msg->auth_request.username); @@ -598,7 +825,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_request){ sig_blob = buffer_get_ssh_string(packet); if(sig_blob == NULL) { - ssh_log(session, SSH_LOG_PACKET, "Invalid signature packet from peer"); + SSH_LOG(SSH_LOG_PACKET, "Invalid signature packet from peer"); msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_ERROR; goto error; } @@ -606,7 +833,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_request){ digest = ssh_msg_userauth_build_digest(session, msg, service); if (digest == NULL) { ssh_string_free(sig_blob); - ssh_log(session, SSH_LOG_PACKET, "Failed to get digest"); + SSH_LOG(SSH_LOG_PACKET, "Failed to get digest"); msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_WRONG; goto error; } @@ -619,19 +846,69 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_request){ ssh_string_free(sig_blob); ssh_buffer_free(digest); if (rc < 0) { - ssh_log(session, + SSH_LOG( SSH_LOG_PACKET, "Received an invalid signature from peer"); msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_WRONG; goto error; } - ssh_log(session, SSH_LOG_PACKET, "Valid signature received"); + SSH_LOG(SSH_LOG_PACKET, "Valid signature received"); msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_VALID; } goto end; } +#ifdef WITH_GSSAPI + if (strncmp(method, "gssapi-with-mic", method_size) == 0) { + uint32_t n_oid; + ssh_string *oids; + ssh_string oid; + char *hexa; + int i; + buffer_get_u32(packet, &n_oid); + n_oid=ntohl(n_oid); + if(n_oid > 100){ + ssh_set_error(session, SSH_FATAL, "USERAUTH_REQUEST: gssapi-with-mic OID count too big (%d)",n_oid); + goto error; + } + SSH_LOG(SSH_LOG_PACKET, "gssapi: %d OIDs", n_oid); + oids = calloc(n_oid, sizeof(ssh_string)); + if (oids == NULL){ + ssh_set_error_oom(session); + goto error; + } + for (i=0;i<(int) n_oid;++i){ + oid=buffer_get_ssh_string(packet); + if(oid == NULL){ + for(i=i-1;i>=0;--i){ + SAFE_FREE(oids[i]); + } + SAFE_FREE(oids); + ssh_set_error(session, SSH_LOG_PACKET, "USERAUTH_REQUEST: gssapi-with-mic missing OID"); + goto error; + } + oids[i] = oid; + if(session->common.log_verbosity >= SSH_LOG_PACKET){ + hexa = ssh_get_hexa(ssh_string_data(oid), ssh_string_len(oid)); + SSH_LOG(SSH_LOG_PACKET,"gssapi: OID %d: %s",i, hexa); + SAFE_FREE(hexa); + } + } + ssh_gssapi_handle_userauth(session, msg->auth_request.username, n_oid, oids); + + for(i=0;i<(int)n_oid;++i){ + SAFE_FREE(oids[i]); + } + SAFE_FREE(oids); + /* bypass the message queue thing */ + SAFE_FREE(service); + SAFE_FREE(method); + ssh_message_free(msg); + + return SSH_PACKET_USED; + } +#endif msg->auth_request.method = SSH_AUTH_METHOD_UNKNOWN; SAFE_FREE(method); @@ -642,17 +919,17 @@ error: ssh_message_free(msg); - leave_function(); return SSH_PACKET_USED; end: SAFE_FREE(service); SAFE_FREE(method); ssh_message_queue(session,msg); - leave_function(); + return SSH_PACKET_USED; } +#endif /* WITH_SERVER */ /** * @internal * @@ -667,7 +944,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){ (void)user; return SSH_PACKET_USED; } -#else +#else /* WITH_SERVER */ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){ uint32_t nanswers; uint32_t i; @@ -675,8 +952,12 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){ ssh_message msg = NULL; - enter_function(); - + /* GSSAPI_TOKEN has same packed number. XXX fix this */ +#ifdef WITH_GSSAPI + if (session->gssapi != NULL) { + return ssh_packet_userauth_gssapi_token(session, type, packet, user); + } +#endif (void)user; (void)type; @@ -698,7 +979,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){ buffer_get_u32(packet, &nanswers); if (session->kbdint == NULL) { - ssh_log(session, SSH_LOG_PROTOCOL, "Warning: Got a keyboard-interactive " + SSH_LOG(SSH_LOG_PROTOCOL, "Warning: Got a keyboard-interactive " "response but it seems we didn't send the request."); session->kbdint = ssh_kbdint_new(); @@ -710,7 +991,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){ } nanswers = ntohl(nanswers); - ssh_log(session,SSH_LOG_PACKET,"kbdint: %d answers",nanswers); + SSH_LOG(SSH_LOG_PACKET,"kbdint: %d answers",nanswers); if (nanswers > KBDINT_MAX_PROMPT) { ssh_set_error(session, SSH_FATAL, "Too much answers received from client: %u (0x%.4x)", @@ -723,7 +1004,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){ if(nanswers != session->kbdint->nprompts) { /* warn but let the application handle this case */ - ssh_log(session, SSH_LOG_PROTOCOL, "Warning: Number of prompts and answers" + SSH_LOG(SSH_LOG_PROTOCOL, "Warning: Number of prompts and answers" " mismatch: p=%u a=%u", session->kbdint->nprompts, nanswers); } session->kbdint->nanswers = nanswers; @@ -761,16 +1042,15 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){ } ssh_message_queue(session,msg); - leave_function(); + return SSH_PACKET_USED; error: ssh_message_free(msg); - leave_function(); return SSH_PACKET_USED; } -#endif +#endif /* WITH_SERVER */ SSH_PACKET_CALLBACK(ssh_packet_channel_open){ ssh_message msg = NULL; @@ -778,7 +1058,6 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open){ char *type_c = NULL; uint32_t sender, window, packet_size, originator_port, destination_port; - enter_function(); (void)type; (void)user; msg = ssh_message_new(session); @@ -800,7 +1079,7 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open){ goto error; } - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Clients wants to open a %s channel", type_c); ssh_string_free(type_s); type_s=NULL; @@ -813,6 +1092,11 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open){ msg->channel_request_open.window = ntohl(window); msg->channel_request_open.packet_size = ntohl(packet_size); + if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED){ + ssh_set_error(session,SSH_FATAL, "Invalid state when receiving channel open request (must be authenticated)"); + goto error; + } + if (strcmp(type_c,"session") == 0) { msg->channel_request_open.type = SSH_CHANNEL_SESSION; SAFE_FREE(type_c); @@ -926,68 +1210,82 @@ end: SAFE_FREE(type_c); if(msg != NULL) ssh_message_queue(session,msg); - leave_function(); + return SSH_PACKET_USED; } -/* TODO: make this function accept a ssh_channel */ +int ssh_message_channel_request_open_reply_accept_channel(ssh_message msg, ssh_channel chan) { + ssh_session session; + int rc; + + if (msg == NULL) { + return SSH_ERROR; + } + + session = msg->session; + + chan->local_channel = ssh_channel_new_id(session); + chan->local_maxpacket = 35000; + chan->local_window = 32000; + chan->remote_channel = msg->channel_request_open.sender; + chan->remote_maxpacket = msg->channel_request_open.packet_size; + chan->remote_window = msg->channel_request_open.window; + chan->state = SSH_CHANNEL_STATE_OPEN; + + rc = buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); + if (rc < 0) { + return SSH_ERROR; + } + + rc = buffer_add_u32(session->out_buffer, htonl(chan->remote_channel)); + if (rc < 0) { + return SSH_ERROR; + } + + rc =buffer_add_u32(session->out_buffer, htonl(chan->local_channel)); + if (rc < 0) { + return SSH_ERROR; + } + + rc = buffer_add_u32(session->out_buffer, htonl(chan->local_window)); + if (rc < 0) { + return SSH_ERROR; + } + + rc = buffer_add_u32(session->out_buffer, htonl(chan->local_maxpacket)); + if (rc < 0) { + return SSH_ERROR; + } + + SSH_LOG(SSH_LOG_PACKET, + "Accepting a channel request_open for chan %d", + chan->remote_channel); + + rc = packet_send(session); + + return rc; +} + + ssh_channel ssh_message_channel_request_open_reply_accept(ssh_message msg) { - ssh_session session; - ssh_channel chan = NULL; + ssh_channel chan; + int rc; - enter_function(); + if (msg == NULL) { + return NULL; + } - if (msg == NULL) { - leave_function(); - return NULL; - } + chan = ssh_channel_new(msg->session); + if (chan == NULL) { + return NULL; + } + rc = ssh_message_channel_request_open_reply_accept_channel(msg, chan); + if (rc < 0) { + ssh_channel_free(chan); + chan = NULL; + } + return chan; - session = msg->session; - - chan = ssh_channel_new(session); - if (chan == NULL) { - leave_function(); - return NULL; - } - - chan->local_channel = ssh_channel_new_id(session); - chan->local_maxpacket = 35000; - chan->local_window = 32000; - chan->remote_channel = msg->channel_request_open.sender; - chan->remote_maxpacket = msg->channel_request_open.packet_size; - chan->remote_window = msg->channel_request_open.window; - chan->state = SSH_CHANNEL_STATE_OPEN; - - if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) < 0) { - goto error; - } - if (buffer_add_u32(session->out_buffer, htonl(chan->remote_channel)) < 0) { - goto error; - } - if (buffer_add_u32(session->out_buffer, htonl(chan->local_channel)) < 0) { - goto error; - } - if (buffer_add_u32(session->out_buffer, htonl(chan->local_window)) < 0) { - goto error; - } - if (buffer_add_u32(session->out_buffer, htonl(chan->local_maxpacket)) < 0) { - goto error; - } - - ssh_log(session, SSH_LOG_PACKET, - "Accepting a channel request_open for chan %d", chan->remote_channel); - - if (packet_send(session) == SSH_ERROR) { - goto error; - } - - leave_function(); - return chan; -error: - ssh_channel_free(chan); - - leave_function(); - return NULL; } /** @@ -1012,14 +1310,14 @@ error: int ssh_message_handle_channel_request(ssh_session session, ssh_channel channel, ssh_buffer packet, const char *request, uint8_t want_reply) { ssh_message msg = NULL; - enter_function(); + msg = ssh_message_new(session); if (msg == NULL) { ssh_set_error_oom(session); goto error; } - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Received a %s channel_request for channel (%d:%d) (want_reply=%hhd)", request, channel->local_channel, channel->remote_channel, want_reply); @@ -1190,12 +1488,11 @@ int ssh_message_handle_channel_request(ssh_session session, ssh_channel channel, msg->channel_request.type = SSH_CHANNEL_REQUEST_UNKNOWN; end: ssh_message_queue(session,msg); - leave_function(); + return SSH_OK; error: ssh_message_free(msg); - leave_function(); return SSH_ERROR; } @@ -1209,7 +1506,7 @@ int ssh_message_channel_request_reply_success(ssh_message msg) { if (msg->channel_request.want_reply) { channel = msg->channel_request.channel->remote_channel; - ssh_log(msg->session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Sending a channel_request success to channel %d", channel); if (buffer_add_u8(msg->session->out_buffer, SSH2_MSG_CHANNEL_SUCCESS) < 0) { @@ -1222,7 +1519,7 @@ int ssh_message_channel_request_reply_success(ssh_message msg) { return packet_send(msg->session); } - ssh_log(msg->session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "The client doesn't want to know the request succeeded"); return SSH_OK; @@ -1250,7 +1547,7 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){ buffer_get_u8(packet, &want_reply); - ssh_log(session,SSH_LOG_PROTOCOL,"Received SSH_MSG_GLOBAL_REQUEST packet"); + SSH_LOG(SSH_LOG_PROTOCOL,"Received SSH_MSG_GLOBAL_REQUEST packet"); msg = ssh_message_new(session); if (msg == NULL) { @@ -1274,10 +1571,10 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){ msg->global_request.bind_address = bind_addr; msg->global_request.bind_port = bind_port; - ssh_log(session, SSH_LOG_PROTOCOL, "Received SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, bind_addr, bind_port); + SSH_LOG(SSH_LOG_PROTOCOL, "Received SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, bind_addr, bind_port); if(ssh_callbacks_exists(session->common.callbacks, global_request_function)) { - ssh_log(session, SSH_LOG_PROTOCOL, "Calling callback for SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, bind_addr, bind_port); + SSH_LOG(SSH_LOG_PROTOCOL, "Calling callback for SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, bind_addr, bind_port); session->common.callbacks->global_request_function(session, msg, session->common.callbacks->userdata); } else { ssh_message_reply_default(msg); @@ -1296,7 +1593,7 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){ msg->global_request.bind_address = bind_addr; msg->global_request.bind_port = bind_port; - ssh_log(session, SSH_LOG_PROTOCOL, "Received SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, bind_addr, bind_port); + SSH_LOG(SSH_LOG_PROTOCOL, "Received SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, bind_addr, bind_port); if(ssh_callbacks_exists(session->common.callbacks, global_request_function)) { session->common.callbacks->global_request_function(session, msg, session->common.callbacks->userdata); @@ -1304,7 +1601,7 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){ ssh_message_reply_default(msg); } } else { - ssh_log(session, SSH_LOG_PROTOCOL, "UNKNOWN SSH_MSG_GLOBAL_REQUEST %s %d", request, want_reply); + SSH_LOG(SSH_LOG_PROTOCOL, "UNKNOWN SSH_MSG_GLOBAL_REQUEST %s %d", request, want_reply); rc = SSH_PACKET_NOT_USED; } diff --git a/libssh/src/misc.c b/libssh/src/misc.c index 99f60b48..18a59d60 100644 --- a/libssh/src/misc.c +++ b/libssh/src/misc.c @@ -219,7 +219,7 @@ char *ssh_get_user_home_dir(void) { return NULL; } memset(buf, 0, sizeof(buf)); - snprintf(buf, sizeof(buf), "%s", getenv("HOME")); + snprintf(buf, sizeof(buf), "%s", szPath); return strdup(buf); } @@ -839,7 +839,7 @@ int ssh_analyze_banner(ssh_session session, int server, int *ssh1, int *ssh2) { return -1; } - ssh_log(session, SSH_LOG_RARE, "Analyzing banner: %s", banner); + SSH_LOG(SSH_LOG_RARE, "Analyzing banner: %s", banner); switch(banner[4]) { case '1': @@ -874,7 +874,7 @@ int ssh_analyze_banner(ssh_session session, int server, int *ssh1, int *ssh2) { major = strtol(openssh + 8, (char **) NULL, 10); minor = strtol(openssh + 10, (char **) NULL, 10); session->openssh = SSH_VERSION_INT(major, minor, 0); - ssh_log(session, SSH_LOG_RARE, + SSH_LOG(SSH_LOG_RARE, "We are talking to an OpenSSH client version: %d.%d (%x)", major, minor, session->openssh); } diff --git a/libssh/src/options.c b/libssh/src/options.c index 931cb31e..f8055780 100644 --- a/libssh/src/options.c +++ b/libssh/src/options.c @@ -635,6 +635,7 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type, } session->common.log_verbosity = *x & 0xffff; + ssh_set_log_level(*x & 0xffff); } break; case SSH_OPTIONS_LOG_VERBOSITY_STR: @@ -780,11 +781,15 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type, return -1; } else { SAFE_FREE(session->opts.ProxyCommand); - q = strdup(v); - if (q == NULL) { - return -1; + /* Setting the command to 'none' disables this option. */ + rc = strcasecmp(v, "none"); + if (rc != 0) { + q = strdup(v); + if (q == NULL) { + return -1; + } + session->opts.ProxyCommand = q; } - session->opts.ProxyCommand = q; } break; default: @@ -931,7 +936,8 @@ int ssh_options_getopt(ssh_session session, int *argcptr, char **argv) { char *cipher = NULL; char *identity = NULL; char *port = NULL; - char **save = NULL, **tmp; + char **save = NULL; + char **tmp = NULL; int i = 0; int argc = *argcptr; int debuglevel = 0; @@ -1013,6 +1019,13 @@ int ssh_options_getopt(ssh_session session, int *argcptr, char **argv) { } /* switch */ } /* while */ opterr = saveopterr; + tmp = realloc(save, (current + (argc - optind)) * sizeof(char*)); + if (tmp == NULL) { + SAFE_FREE(save); + ssh_set_error_oom(session); + return -1; + } + save = tmp; while (optind < argc) { tmp = realloc(save, (current + 1) * sizeof(char*)); if (tmp == NULL) { @@ -1031,7 +1044,7 @@ int ssh_options_getopt(ssh_session session, int *argcptr, char **argv) { cont = 0; } - ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &debuglevel); + ssh_set_log_level(debuglevel); optind = saveoptind; @@ -1349,7 +1362,7 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type, return -1; } else { int *x = (int *) value; - sshbind->common.log_verbosity = *x & 0xffff; + ssh_set_log_level(*x & 0xffff); } break; case SSH_BIND_OPTIONS_LOG_VERBOSITY_STR: diff --git a/libssh/src/packet.c b/libssh/src/packet.c index 440e47c6..3302847a 100644 --- a/libssh/src/packet.c +++ b/libssh/src/packet.c @@ -46,6 +46,7 @@ #include "libssh/pcap.h" #include "libssh/kex.h" #include "libssh/auth.h" +#include "libssh/gssapi.h" #define MACSIZE SHA_DIGEST_LEN @@ -54,7 +55,11 @@ static ssh_packet_callback default_packet_handlers[]= { ssh_packet_ignore_callback, // SSH2_MSG_IGNORE 2 ssh_packet_unimplemented, // SSH2_MSG_UNIMPLEMENTED 3 ssh_packet_ignore_callback, // SSH2_MSG_DEBUG 4 +#if WITH_SERVER ssh_packet_service_request, // SSH2_MSG_SERVICE_REQUEST 5 +#else + NULL, +#endif ssh_packet_service_accept, // SSH2_MSG_SERVICE_ACCEPT 6 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 7-19 @@ -76,18 +81,33 @@ static ssh_packet_callback default_packet_handlers[]= { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 35-49 +#if WITH_SERVER ssh_packet_userauth_request, // SSH2_MSG_USERAUTH_REQUEST 50 +#else + NULL, +#endif ssh_packet_userauth_failure, // SSH2_MSG_USERAUTH_FAILURE 51 ssh_packet_userauth_success, // SSH2_MSG_USERAUTH_SUCCESS 52 ssh_packet_userauth_banner, // SSH2_MSG_USERAUTH_BANNER 53 NULL,NULL,NULL,NULL,NULL,NULL, // 54-59 ssh_packet_userauth_pk_ok, // SSH2_MSG_USERAUTH_PK_OK 60 // SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60 - // SSH2_MSG_USERAUTH_INFO_REQUEST 60 + // SSH2_MSG_USERAUTH_INFO_REQUEST 60 + // SSH2_MSG_USERAUTH_GSSAPI_RESPONSE 60 ssh_packet_userauth_info_response, // SSH2_MSG_USERAUTH_INFO_RESPONSE 61 + // SSH2_MSG_USERAUTH_GSSAPI_TOKEN 61 + NULL, // 62 + NULL, // SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE 63 + NULL, // SSH2_MSG_USERAUTH_GSSAPI_ERROR 64 + NULL, // SSH2_MSG_USERAUTH_GSSAPI_ERRTOK 65 +#if defined(WITH_GSSAPI) && defined(WITH_SERVER) + ssh_packet_userauth_gssapi_mic, // SSH2_MSG_USERAUTH_GSSAPI_MIC 66 +#else /* WITH_GSSAPI && WITH_SERVER */ + NULL, +#endif /* WITH_GSSAPI && WITH_SERVER */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, // 62-79 + NULL, NULL, NULL, NULL, // 67-79 #ifdef WITH_SERVER ssh_packet_global_request, // SSH2_MSG_GLOBAL_REQUEST 80 #else /* WITH_SERVER */ @@ -139,14 +159,12 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) goto error; } - enter_function(); if (session->session_state == SSH_SESSION_STATE_ERROR) goto error; switch(session->packet_state) { case PACKET_STATE_INIT: if(receivedlen < blocksize){ /* We didn't receive enough data to read at least one block size, give up */ - leave_function(); return 0; } memset(&session->in_packet, 0, sizeof(PACKET)); @@ -195,7 +213,7 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) if (to_be_read != 0) { if(receivedlen - processed < (unsigned int)to_be_read){ /* give up, not enough data in buffer */ - ssh_log(session,SSH_LOG_PACKET,"packet: partial packet (read len) [len=%d]",len); + SSH_LOG(SSH_LOG_PACKET,"packet: partial packet (read len) [len=%d]",len); return processed; } @@ -262,7 +280,7 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) /* We don't want to rewrite a new packet while still executing the packet callbacks */ session->packet_state = PACKET_STATE_PROCESSING; ssh_packet_parse_type(session); - ssh_log(session,SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "packet: read type %hhd [len=%d,padding=%hhd,comp=%d,payload=%d]", session->in_packet.type, len, padding, compsize, payloadsize); /* execute callbacks */ @@ -270,16 +288,16 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) session->packet_state = PACKET_STATE_INIT; if(processed < receivedlen){ /* Handle a potential packet left in socket buffer */ - ssh_log(session,SSH_LOG_PACKET,"Processing %" PRIdS " bytes left in socket buffer", + SSH_LOG(SSH_LOG_PACKET,"Processing %" PRIdS " bytes left in socket buffer", receivedlen-processed); rc = ssh_packet_socket_callback(((unsigned char *)data) + processed, receivedlen - processed,user); processed += rc; } - leave_function(); + return processed; case PACKET_STATE_PROCESSING: - ssh_log(session, SSH_LOG_RARE, "Nested packet processing. Delaying."); + SSH_LOG(SSH_LOG_RARE, "Nested packet processing. Delaying."); return 0; } @@ -289,7 +307,7 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) error: session->session_state= SSH_SESSION_STATE_ERROR; - leave_function(); + return processed; } @@ -339,11 +357,12 @@ void ssh_packet_process(ssh_session session, uint8_t type){ struct ssh_iterator *i; int r=SSH_PACKET_NOT_USED; ssh_packet_callbacks cb; - enter_function(); - ssh_log(session,SSH_LOG_PACKET, "Dispatching handler for packet type %d",type); + + SSH_LOG(SSH_LOG_PACKET, "Dispatching handler for packet type %d",type); if(session->packet_callbacks == NULL){ - ssh_log(session,SSH_LOG_RARE,"Packet callback is not initialized !"); - goto error; + SSH_LOG(SSH_LOG_RARE,"Packet callback is not initialized !"); + + return; } i=ssh_list_get_iterator(session->packet_callbacks); while(i != NULL){ @@ -362,11 +381,9 @@ void ssh_packet_process(ssh_session session, uint8_t type){ break; } if(r==SSH_PACKET_NOT_USED){ - ssh_log(session,SSH_LOG_RARE,"Couldn't do anything with packet type %d",type); + SSH_LOG(SSH_LOG_RARE,"Couldn't do anything with packet type %d",type); ssh_packet_send_unimplemented(session, session->recv_seq-1); } -error: - leave_function(); } /** @internal @@ -377,7 +394,7 @@ error: */ int ssh_packet_send_unimplemented(ssh_session session, uint32_t seqnum){ int r; - enter_function(); + r = buffer_add_u8(session->out_buffer, SSH2_MSG_UNIMPLEMENTED); if (r < 0) { return SSH_ERROR; @@ -387,7 +404,7 @@ int ssh_packet_send_unimplemented(ssh_session session, uint32_t seqnum){ return SSH_ERROR; } r = packet_send(session); - leave_function(); + return r; } @@ -396,11 +413,12 @@ int ssh_packet_send_unimplemented(ssh_session session, uint32_t seqnum){ */ SSH_PACKET_CALLBACK(ssh_packet_unimplemented){ uint32_t seq; + (void)session; /* unused */ (void)type; (void)user; buffer_get_u32(packet,&seq); seq=ntohl(seq); - ssh_log(session,SSH_LOG_RARE, + SSH_LOG(SSH_LOG_RARE, "Received SSH_MSG_UNIMPLEMENTED (sequence number %d)",seq); return SSH_PACKET_USED; } @@ -409,23 +427,18 @@ SSH_PACKET_CALLBACK(ssh_packet_unimplemented){ * @parse the "Type" header field of a packet and updates the session */ int ssh_packet_parse_type(ssh_session session) { - enter_function(); - memset(&session->in_packet, 0, sizeof(PACKET)); if(session->in_buffer == NULL) { - leave_function(); return SSH_ERROR; } if(buffer_get_u8(session->in_buffer, &session->in_packet.type) == 0) { ssh_set_error(session, SSH_FATAL, "Packet too short to read type"); - leave_function(); return SSH_ERROR; } session->in_packet.valid = 1; - leave_function(); return SSH_OK; } @@ -436,12 +449,10 @@ int ssh_packet_parse_type(ssh_session session) { static int ssh_packet_write(ssh_session session) { int rc = SSH_ERROR; - enter_function(); - rc=ssh_socket_write(session->socket, buffer_get_rest(session->out_buffer), buffer_get_rest_len(session->out_buffer)); - leave_function(); + return rc; } @@ -455,8 +466,6 @@ static int packet_send2(ssh_session session) { uint32_t finallen,payloadsize,compsize; uint8_t padding; - enter_function(); - payloadsize = currentlen; #ifdef WITH_ZLIB if (session->current_crypto @@ -509,14 +518,14 @@ static int packet_send2(ssh_session session) { rc = ssh_packet_write(session); session->send_seq++; - ssh_log(session,SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "packet: wrote [len=%d,padding=%hhd,comp=%d,payload=%d]", ntohl(finallen), padding, compsize, payloadsize); if (buffer_reinit(session->out_buffer) < 0) { rc = SSH_ERROR; } error: - leave_function(); + return rc; /* SSH_OK, AGAIN or ERROR */ } diff --git a/libssh/src/packet1.c b/libssh/src/packet1.c index 56bfb346..7ac8318d 100644 --- a/libssh/src/packet1.c +++ b/libssh/src/packet1.c @@ -108,7 +108,6 @@ int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user uint32_t crc; uint32_t len; ssh_session session=(ssh_session)user; - enter_function(); switch (session->packet_state){ case PACKET_STATE_INIT: @@ -126,7 +125,6 @@ int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user } /* must have at least enough bytes for size */ if(receivedlen < sizeof(uint32_t)){ - leave_function(); return 0; } memcpy(&len,data,sizeof(uint32_t)); @@ -140,7 +138,7 @@ int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user goto error; } - ssh_log(session, SSH_LOG_PACKET, "Reading a %d bytes packet", len); + SSH_LOG(SSH_LOG_PACKET, "Reading a %d bytes packet", len); session->in_packet.len = len; session->packet_state = PACKET_STATE_SIZEREAD; @@ -152,7 +150,6 @@ int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user to_be_read = len + padding; if(to_be_read + processed > receivedlen){ /* wait for rest of packet */ - leave_function(); return processed; } /* it is _not_ possible that to_be_read be < 8. */ @@ -182,10 +179,10 @@ int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user ssh_print_hexa("read packet decrypted:", ssh_buffer_get_begin(session->in_buffer), ssh_buffer_get_len(session->in_buffer)); #endif - ssh_log(session, SSH_LOG_PACKET, "%d bytes padding", padding); + SSH_LOG(SSH_LOG_PACKET, "%d bytes padding", padding); if(((len + padding) != buffer_get_rest_len(session->in_buffer)) || ((len + padding) < sizeof(uint32_t))) { - ssh_log(session, SSH_LOG_RARE, "no crc32 in packet"); + SSH_LOG(SSH_LOG_RARE, "no crc32 in packet"); ssh_set_error(session, SSH_FATAL, "no crc32 in packet"); goto error; } @@ -201,7 +198,7 @@ int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user ssh_print_hexa("crc32 on",buffer_get_rest(session->in_buffer), len + padding - sizeof(uint32_t)); #endif - ssh_log(session, SSH_LOG_RARE, "Invalid crc32"); + SSH_LOG(SSH_LOG_RARE, "Invalid crc32"); ssh_set_error(session, SSH_FATAL, "Invalid crc32: expected %.8x, got %.8x", crc, @@ -211,7 +208,7 @@ int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user } /* pass the padding */ buffer_pass_bytes(session->in_buffer, padding); - ssh_log(session, SSH_LOG_PACKET, "The packet is valid"); + SSH_LOG(SSH_LOG_PACKET, "The packet is valid"); /* TODO FIXME #ifdef WITH_ZLIB @@ -230,22 +227,22 @@ int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user if(processed < receivedlen){ int rc; /* Handle a potential packet left in socket buffer */ - ssh_log(session,SSH_LOG_PACKET,"Processing %" PRIdS " bytes left in socket buffer", + SSH_LOG(SSH_LOG_PACKET,"Processing %" PRIdS " bytes left in socket buffer", receivedlen-processed); rc = ssh_packet_socket_callback1((char *)data + processed, receivedlen - processed,user); processed += rc; } - leave_function(); + return processed; case PACKET_STATE_PROCESSING: - ssh_log(session, SSH_LOG_RARE, "Nested packet processing. Delaying."); + SSH_LOG(SSH_LOG_RARE, "Nested packet processing. Delaying."); return 0; } error: session->session_state=SSH_SESSION_STATE_ERROR; - leave_function(); + return processed; } @@ -260,8 +257,7 @@ int packet_send1(ssh_session session) { uint32_t crc; uint8_t padding; - enter_function(); - ssh_log(session,SSH_LOG_PACKET,"Sending a %d bytes long packet",currentlen); + SSH_LOG(SSH_LOG_PACKET,"Sending a %d bytes long packet",currentlen); /* TODO FIXME #ifdef WITH_ZLIB @@ -281,7 +277,7 @@ int packet_send1(ssh_session session) { } finallen = htonl(currentlen); - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "%d bytes after comp + %d padding bytes = %d bytes packet", currentlen, padding, ntohl(finallen)); @@ -323,7 +319,7 @@ int packet_send1(ssh_session session) { rc = SSH_ERROR; } error: - leave_function(); + return rc; /* SSH_OK, AGAIN or ERROR */ } @@ -331,7 +327,7 @@ SSH_PACKET_CALLBACK(ssh_packet_disconnect1){ (void)packet; (void)user; (void)type; - ssh_log(session, SSH_LOG_PACKET, "Received SSH_MSG_DISCONNECT"); + SSH_LOG(SSH_LOG_PACKET, "Received SSH_MSG_DISCONNECT"); ssh_set_error(session, SSH_FATAL, "Received SSH_MSG_DISCONNECT"); ssh_socket_close(session->socket); session->alive = 0; diff --git a/libssh/src/packet_cb.c b/libssh/src/packet_cb.c index 41d0985c..4a8beb54 100644 --- a/libssh/src/packet_cb.c +++ b/libssh/src/packet_cb.c @@ -53,7 +53,7 @@ SSH_PACKET_CALLBACK(ssh_packet_disconnect_callback){ error = ssh_string_to_char(error_s); ssh_string_free(error_s); } - ssh_log(session, SSH_LOG_PACKET, "Received SSH_MSG_DISCONNECT %d:%s",code, + SSH_LOG(SSH_LOG_PACKET, "Received SSH_MSG_DISCONNECT %d:%s",code, error != NULL ? error : "no error"); ssh_set_error(session, SSH_FATAL, "Received SSH_MSG_DISCONNECT: %d:%s",code, @@ -73,10 +73,11 @@ SSH_PACKET_CALLBACK(ssh_packet_disconnect_callback){ * @brief Handle a SSH_IGNORE and SSH_DEBUG packet. */ SSH_PACKET_CALLBACK(ssh_packet_ignore_callback){ + (void)session; /* unused */ (void)user; (void)type; (void)packet; - ssh_log(session,SSH_LOG_PROTOCOL,"Received %s packet",type==SSH2_MSG_IGNORE ? "SSH_MSG_IGNORE" : "SSH_MSG_DEBUG"); + SSH_LOG(SSH_LOG_PROTOCOL,"Received %s packet",type==SSH2_MSG_IGNORE ? "SSH_MSG_IGNORE" : "SSH_MSG_DEBUG"); /* TODO: handle a graceful disconnect */ return SSH_PACKET_USED; } @@ -85,7 +86,7 @@ SSH_PACKET_CALLBACK(ssh_packet_dh_reply){ int rc; (void)type; (void)user; - ssh_log(session,SSH_LOG_PROTOCOL,"Received SSH_KEXDH_REPLY"); + SSH_LOG(SSH_LOG_PROTOCOL,"Received SSH_KEXDH_REPLY"); if(session->session_state!= SSH_SESSION_STATE_DH && session->dh_handshake_state != DH_STATE_INIT_SENT){ ssh_set_error(session,SSH_FATAL,"ssh_packet_dh_reply called in wrong state : %d:%d", @@ -121,7 +122,7 @@ SSH_PACKET_CALLBACK(ssh_packet_newkeys){ (void)packet; (void)user; (void)type; - ssh_log(session, SSH_LOG_PROTOCOL, "Received SSH_MSG_NEWKEYS"); + SSH_LOG(SSH_LOG_PROTOCOL, "Received SSH_MSG_NEWKEYS"); if(session->session_state!= SSH_SESSION_STATE_DH && session->dh_handshake_state != DH_STATE_NEWKEYS_SENT){ ssh_set_error(session,SSH_FATAL,"ssh_packet_newkeys called in wrong state : %d:%d", @@ -191,7 +192,7 @@ SSH_PACKET_CALLBACK(ssh_packet_newkeys){ if (rc == SSH_ERROR) { goto error; } - ssh_log(session,SSH_LOG_PROTOCOL,"Signature verified and valid"); + SSH_LOG(SSH_LOG_PROTOCOL,"Signature verified and valid"); /* * Once we got SSH2_MSG_NEWKEYS we can switch next_crypto and @@ -235,10 +236,10 @@ SSH_PACKET_CALLBACK(ssh_packet_service_accept){ (void)packet; (void)type; (void)user; - enter_function(); + session->auth_service_state=SSH_AUTH_SERVICE_ACCEPTED; - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Received SSH_MSG_SERVICE_ACCEPT"); - leave_function(); + return SSH_PACKET_USED; } diff --git a/libssh/src/pki.c b/libssh/src/pki.c index a3616c2f..dd3d915a 100644 --- a/libssh/src/pki.c +++ b/libssh/src/pki.c @@ -1220,8 +1220,7 @@ int ssh_pki_signature_verify_blob(ssh_session session, return SSH_ERROR; } - ssh_log(session, - SSH_LOG_FUNCTIONS, + SSH_LOG(SSH_LOG_FUNCTIONS, "Going to verify a %s type signature", key->type_c); @@ -1260,7 +1259,7 @@ int ssh_pki_signature_verify_blob(ssh_session session, } /* - * This function signs the session id (known as H) as a string then + * This function signs the session id as a string then * the content of sigbuf */ ssh_string ssh_pki_do_sign(ssh_session session, ssh_buffer sigbuf, @@ -1284,7 +1283,7 @@ ssh_string ssh_pki_do_sign(ssh_session session, return NULL; } ssh_string_fill(session_id, crypto->session_id, crypto->digest_len); - + /* TODO: change when supporting ECDSA keys */ ctx = sha1_init(); if (ctx == NULL) { ssh_string_free(session_id); @@ -1381,18 +1380,18 @@ ssh_string ssh_srv_pki_do_sign_sessionid(ssh_session session, if (session == NULL || privkey == NULL || !ssh_key_is_private(privkey)) { return NULL; } - crypto = session->current_crypto ? session->current_crypto : - session->next_crypto; + crypto = session->next_crypto ? session->next_crypto : + session->current_crypto; ctx = sha1_init(); if (ctx == NULL) { return NULL; } - if (crypto->session_id == NULL){ - ssh_set_error(session,SSH_FATAL,"Missing session_id"); + if (crypto->secret_hash == NULL){ + ssh_set_error(session,SSH_FATAL,"Missing secret_hash"); return NULL; } - sha1_update(ctx, crypto->session_id, crypto->digest_len); + sha1_update(ctx, crypto->secret_hash, crypto->digest_len); sha1_final(hash, ctx); #ifdef DEBUG_CRYPTO diff --git a/libssh/src/poll.c b/libssh/src/poll.c index 932c4918..bde0198d 100644 --- a/libssh/src/poll.c +++ b/libssh/src/poll.c @@ -69,6 +69,7 @@ struct ssh_poll_handle_struct { size_t idx; } x; short events; + int lock; ssh_poll_callback cb; void *cb_data; }; @@ -114,10 +115,13 @@ static poll_fn ssh_poll_emu; #else /* _WIN32 */ #include #include -#include #include #endif /* _WIN32 */ +#ifdef HAVE_UNISTD_H +#include +#endif + /* * This is a poll(2)-emulation using select for systems not providing a native @@ -336,7 +340,7 @@ short ssh_poll_get_events(ssh_poll_handle p) { */ void ssh_poll_set_events(ssh_poll_handle p, short events) { p->events = events; - if (p->ctx != NULL) { + if (p->ctx != NULL && !p->lock) { p->ctx->pollfds[p->x.idx].events = events; } } @@ -595,7 +599,7 @@ int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout) { return SSH_AGAIN; used = ctx->polls_used; for (i = 0; i < used && rc > 0; ) { - if (!ctx->pollfds[i].revents) { + if (!ctx->pollfds[i].revents || ctx->pollptrs[i]->lock) { i++; } else { int ret; @@ -603,7 +607,9 @@ int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout) { p = ctx->pollptrs[i]; fd = ctx->pollfds[i].fd; revents = ctx->pollfds[i].revents; - + /* avoid having any event caught during callback */ + ctx->pollfds[i].events = 0; + p->lock = 1; if (p->cb && (ret = p->cb(p, fd, revents, p->cb_data)) < 0) { if (ret == -2) { return -1; @@ -613,6 +619,8 @@ int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout) { i=0; } else { ctx->pollfds[i].revents = 0; + ctx->pollfds[i].events = p->events; + p->lock = 0; i++; } diff --git a/libssh/src/scp.c b/libssh/src/scp.c index df4f5753..6838a3cd 100644 --- a/libssh/src/scp.c +++ b/libssh/src/scp.c @@ -83,7 +83,17 @@ ssh_scp ssh_scp_new(ssh_session session, int mode, const char *location){ return scp; } -int ssh_scp_init(ssh_scp scp){ +/** + * @brief Initialize the scp channel. + * + * @param[in] scp The scp context to initialize. + * + * @return SSH_OK on success or an SSH error code. + * + * @see ssh_scp_new() + */ +int ssh_scp_init(ssh_scp scp) +{ int r; char execbuffer[1024]; uint8_t code; @@ -93,7 +103,7 @@ int ssh_scp_init(ssh_scp scp){ ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_init called under invalid state"); return SSH_ERROR; } - ssh_log(scp->session,SSH_LOG_PROTOCOL,"Initializing scp session %s %son location '%s'", + SSH_LOG(SSH_LOG_PROTOCOL,"Initializing scp session %s %son location '%s'", scp->mode==SSH_SCP_WRITE?"write":"read", scp->recursive?"recursive ":"", scp->location); @@ -139,7 +149,17 @@ int ssh_scp_init(ssh_scp scp){ return SSH_OK; } -int ssh_scp_close(ssh_scp scp){ +/** + * @brief Close the scp channel. + * + * @param[in] scp The scp context to close. + * + * @return SSH_OK on success or an SSH error code. + * + * @see ssh_scp_init() + */ +int ssh_scp_close(ssh_scp scp) +{ char buffer[128]; int err; if(scp==NULL) @@ -169,7 +189,15 @@ int ssh_scp_close(ssh_scp scp){ return SSH_OK; } -void ssh_scp_free(ssh_scp scp){ +/** + * @brief Free a scp context. + * + * @param[in] scp The context to free. + * + * @see ssh_scp_new() + */ +void ssh_scp_free(ssh_scp scp) +{ if(scp==NULL) return; if(scp->state != SSH_SCP_NEW) @@ -300,7 +328,7 @@ int ssh_scp_push_file64(ssh_scp scp, const char *filename, uint64_t size, int mo } file=ssh_basename(filename); perms=ssh_scp_string_mode(mode); - ssh_log(scp->session,SSH_LOG_PROTOCOL,"SCP pushing file %s, size %" PRIu64 " with permissions '%s'",file,size,perms); + SSH_LOG(SSH_LOG_PROTOCOL,"SCP pushing file %s, size %" PRIu64 " with permissions '%s'",file,size,perms); snprintf(buffer, sizeof(buffer), "C%s %" PRIu64 " %s\n", perms, size, file); SAFE_FREE(file); SAFE_FREE(perms); @@ -379,7 +407,7 @@ int ssh_scp_response(ssh_scp scp, char **response){ /* Warning */ if(code == 1){ ssh_set_error(scp->session,SSH_REQUEST_DENIED, "SCP: Warning: status code 1 received: %s", msg); - ssh_log(scp->session,SSH_LOG_RARE,"SCP: Warning: status code 1 received: %s", msg); + SSH_LOG(SSH_LOG_RARE,"SCP: Warning: status code 1 received: %s", msg); if(response) *response=strdup(msg); return 1; @@ -540,7 +568,7 @@ int ssh_scp_pull_request(ssh_scp scp){ p=strchr(buffer,'\n'); if(p!=NULL) *p='\0'; - ssh_log(scp->session,SSH_LOG_PROTOCOL,"Received SCP request: '%s'",buffer); + SSH_LOG(SSH_LOG_PROTOCOL,"Received SCP request: '%s'",buffer); switch(buffer[0]){ case 'C': /* File */ @@ -751,7 +779,7 @@ int ssh_scp_request_get_permissions(ssh_scp scp){ size_t ssh_scp_request_get_size(ssh_scp scp){ if(scp==NULL) return 0; - return scp->filelen; + return (size_t)scp->filelen; } /** @brief Get the size of the file being pushed from the other party. diff --git a/libssh/src/server.c b/libssh/src/server.c index 6862370f..a2104642 100644 --- a/libssh/src/server.c +++ b/libssh/src/server.c @@ -167,10 +167,10 @@ SSH_PACKET_CALLBACK(ssh_packet_kexdh_init){ int rc; (void)type; (void)user; - enter_function(); - ssh_log(session,SSH_LOG_PACKET,"Received SSH_MSG_KEXDH_INIT"); + + SSH_LOG(SSH_LOG_PACKET,"Received SSH_MSG_KEXDH_INIT"); if(session->dh_handshake_state != DH_STATE_INIT){ - ssh_log(session,SSH_LOG_RARE,"Invalid state for SSH_MSG_KEXDH_INIT"); + SSH_LOG(SSH_LOG_RARE,"Invalid state for SSH_MSG_KEXDH_INIT"); goto error; } switch(session->next_crypto->kex_type){ @@ -190,7 +190,7 @@ SSH_PACKET_CALLBACK(ssh_packet_kexdh_init){ if (rc == SSH_ERROR) session->session_state = SSH_SESSION_STATE_ERROR; error: - leave_function(); + return SSH_PACKET_USED; } @@ -278,22 +278,6 @@ static int dh_handshake_server(ssh_session session) { return -1; } - /* Free private keys as they should not be readable after this point */ - if (session->srv.rsa_key) { - ssh_key_free(session->srv.rsa_key); - session->srv.rsa_key = NULL; - } - if (session->srv.dsa_key) { - ssh_key_free(session->srv.dsa_key); - session->srv.dsa_key = NULL; - } -#ifdef HAVE_ECC - if (session->srv.ecdsa_key) { - ssh_key_free(session->srv.ecdsa_key); - session->srv.ecdsa_key = NULL; - } -#endif - if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXDH_REPLY) < 0 || buffer_add_ssh_string(session->out_buffer, session->next_crypto->server_pubkey) < 0 || @@ -319,7 +303,7 @@ static int dh_handshake_server(ssh_session session) { if (packet_send(session) == SSH_ERROR) { return -1; } - ssh_log(session, SSH_LOG_PACKET, "SSH_MSG_NEWKEYS sent"); + SSH_LOG(SSH_LOG_PACKET, "SSH_MSG_NEWKEYS sent"); session->dh_handshake_state=DH_STATE_NEWKEYS_SENT; return 0; @@ -333,7 +317,7 @@ static int dh_handshake_server(ssh_session session) { */ static void ssh_server_connection_callback(ssh_session session){ int ssh1,ssh2; - enter_function(); + switch(session->session_state){ case SSH_SESSION_STATE_NONE: case SSH_SESSION_STATE_CONNECTING: @@ -344,7 +328,7 @@ static void ssh_server_connection_callback(ssh_session session){ goto error; } set_status(session, 0.4f); - ssh_log(session, SSH_LOG_RARE, + SSH_LOG(SSH_LOG_RARE, "SSH client banner: %s", session->clientbanner); /* Here we analyze the different protocols the server allows. */ @@ -400,7 +384,14 @@ static void ssh_server_connection_callback(ssh_session session){ break; case SSH_SESSION_STATE_KEXINIT_RECEIVED: set_status(session,0.6f); - ssh_list_kex(session, &session->next_crypto->client_kex); // log client kex + if(session->next_crypto->server_kex.methods[0]==NULL){ + if(server_set_kex(session) == SSH_ERROR) + goto error; + /* We are in a rekeying, so we need to send the server kex */ + if(ssh_send_kex(session, 1) < 0) + goto error; + } + ssh_list_kex(&session->next_crypto->client_kex); // log client kex if (ssh_kex_select_methods(session) < 0) { goto error; } @@ -429,10 +420,20 @@ static void ssh_server_connection_callback(ssh_session session){ if (session->next_crypto == NULL) { goto error; } - set_status(session,1.0f); - session->connected = 1; - session->session_state=SSH_SESSION_STATE_AUTHENTICATING; - } + session->next_crypto->session_id = malloc(session->current_crypto->digest_len); + if (session->next_crypto->session_id == NULL) { + ssh_set_error_oom(session); + goto error; + } + memcpy(session->next_crypto->session_id, session->current_crypto->session_id, + session->current_crypto->digest_len); + + set_status(session,1.0f); + session->connected = 1; + session->session_state=SSH_SESSION_STATE_AUTHENTICATING; + if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED) + session->session_state = SSH_SESSION_STATE_AUTHENTICATED; + } break; case SSH_SESSION_STATE_AUTHENTICATING: break; @@ -441,13 +442,12 @@ static void ssh_server_connection_callback(ssh_session session){ default: ssh_set_error(session,SSH_FATAL,"Invalid state %d",session->session_state); } - leave_function(); + return; - error: +error: ssh_socket_close(session->socket); session->alive = 0; session->session_state=SSH_SESSION_STATE_ERROR; - leave_function(); } /** @@ -468,8 +468,6 @@ static int callback_receive_banner(const void *data, size_t len, void *user) { size_t i; int ret=0; - enter_function(); - for (i = 0; i < len; i++) { #ifdef WITH_PCAP if(session->pcap_ctx && buffer[i] == '\n') { @@ -492,10 +490,9 @@ static int callback_receive_banner(const void *data, size_t len, void *user) { ret = i + 1; session->clientbanner = str; session->session_state = SSH_SESSION_STATE_BANNER_RECEIVED; - ssh_log(session, SSH_LOG_PACKET, "Received banner: %s", str); + SSH_LOG(SSH_LOG_PACKET, "Received banner: %s", str); session->ssh_connection_callback(session); - leave_function(); return ret; } @@ -504,12 +501,10 @@ static int callback_receive_banner(const void *data, size_t len, void *user) { session->session_state = SSH_SESSION_STATE_ERROR; ssh_set_error(session, SSH_FATAL, "Receiving banner: too large banner"); - leave_function(); return 0; } } - leave_function(); return ret; } @@ -524,6 +519,17 @@ static int ssh_server_kex_termination(void *s){ return 1; } +/** Set the acceptable authentication methods to be sent to + * client. + * @param[in] session the SSH server session + * @param[in] auth_methods Bitfield of authentication methods + * to be accepted, e.g. SSH_AUTH_METHOD_PUBLICKEY + */ +void ssh_set_auth_methods(ssh_session session, int auth_methods){ + /* accept only methods in range */ + session->auth_methods = auth_methods & 0x3f; +} + /* Do the banner and key exchange */ int ssh_handle_key_exchange(ssh_session session) { int rc; @@ -550,7 +556,7 @@ int ssh_handle_key_exchange(ssh_session session) { pending: rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER, ssh_server_kex_termination,session); - ssh_log(session,SSH_LOG_PACKET, "ssh_handle_key_exchange: Actual state : %d", + SSH_LOG(SSH_LOG_PACKET, "ssh_handle_key_exchange: current state : %d", session->session_state); if (rc != SSH_OK) return rc; @@ -564,14 +570,14 @@ int ssh_handle_key_exchange(ssh_session session) { /* messages */ -static int ssh_message_auth_reply_default(ssh_message msg,int partial) { - ssh_session session = msg->session; +/** @internal + * replies to an SSH_AUTH packet with a default (denied) response. + */ +int ssh_auth_reply_default(ssh_session session,int partial) { char methods_c[128] = {0}; ssh_string methods = NULL; int rc = SSH_ERROR; - enter_function(); - if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_FAILURE) < 0) { return rc; } @@ -583,6 +589,10 @@ static int ssh_message_auth_reply_default(ssh_message msg,int partial) { strncat(methods_c, "publickey,", sizeof(methods_c) - strlen(methods_c) - 1); } + if (session->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC){ + strncat(methods_c,"gssapi-with-mic,", + sizeof(methods_c) - strlen(methods_c) - 1); + } if (session->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) { strncat(methods_c, "keyboard-interactive,", sizeof(methods_c) - strlen(methods_c) - 1); @@ -603,7 +613,7 @@ static int ssh_message_auth_reply_default(ssh_message msg,int partial) { /* Strip the comma. */ methods_c[strlen(methods_c) - 1] = '\0'; // strip the comma. We are sure there is at - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Sending a auth failure. methods that can continue: %s", methods_c); methods = ssh_string_from_char(methods_c); @@ -611,7 +621,7 @@ static int ssh_message_auth_reply_default(ssh_message msg,int partial) { goto error; } - if (buffer_add_ssh_string(msg->session->out_buffer, methods) < 0) { + if (buffer_add_ssh_string(session->out_buffer, methods) < 0) { goto error; } @@ -625,16 +635,15 @@ static int ssh_message_auth_reply_default(ssh_message msg,int partial) { } } - rc = packet_send(msg->session); + rc = packet_send(session); error: ssh_string_free(methods); - leave_function(); return rc; } static int ssh_message_channel_request_open_reply_default(ssh_message msg) { - ssh_log(msg->session, SSH_LOG_FUNCTIONS, "Refusing a channel"); + SSH_LOG(SSH_LOG_FUNCTIONS, "Refusing a channel"); if (buffer_add_u8(msg->session->out_buffer , SSH2_MSG_CHANNEL_OPEN_FAILURE) < 0) { @@ -668,7 +677,7 @@ static int ssh_message_channel_request_reply_default(ssh_message msg) { if (msg->channel_request.want_reply) { channel = msg->channel_request.channel->remote_channel; - ssh_log(msg->session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Sending a default channel_request denied to channel %d", channel); if (buffer_add_u8(msg->session->out_buffer, SSH2_MSG_CHANNEL_FAILURE) < 0) { @@ -681,7 +690,7 @@ static int ssh_message_channel_request_reply_default(ssh_message msg) { return packet_send(msg->session); } - ssh_log(msg->session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "The client doesn't want to know the request failed!"); return SSH_OK; @@ -701,7 +710,7 @@ int ssh_message_service_reply_success(ssh_message msg) { } session = msg->session; - ssh_log(session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Sending a SERVICE_ACCEPT for service %s", msg->service_request.service); if (buffer_add_u8(session->out_buffer, SSH2_MSG_SERVICE_ACCEPT) < 0) { return -1; @@ -720,7 +729,7 @@ int ssh_message_service_reply_success(ssh_message msg) { } int ssh_message_global_request_reply_success(ssh_message msg, uint16_t bound_port) { - ssh_log(msg->session, SSH_LOG_FUNCTIONS, "Accepting a global request"); + SSH_LOG(SSH_LOG_FUNCTIONS, "Accepting a global request"); if (msg->global_request.want_reply) { if (buffer_add_u8(msg->session->out_buffer @@ -740,7 +749,7 @@ int ssh_message_global_request_reply_success(ssh_message msg, uint16_t bound_por if(msg->global_request.type == SSH_GLOBAL_REQUEST_TCPIP_FORWARD && msg->global_request.bind_port == 0) { - ssh_log(msg->session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "The client doesn't want to know the remote port!"); } @@ -750,7 +759,7 @@ error: } static int ssh_message_global_request_reply_default(ssh_message msg) { - ssh_log(msg->session, SSH_LOG_FUNCTIONS, "Refusing a global request"); + SSH_LOG(SSH_LOG_FUNCTIONS, "Refusing a global request"); if (msg->global_request.want_reply) { if (buffer_add_u8(msg->session->out_buffer @@ -759,7 +768,7 @@ static int ssh_message_global_request_reply_default(ssh_message msg) { } return packet_send(msg->session); } - ssh_log(msg->session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "The client doesn't want to know the request failed!"); return SSH_OK; @@ -774,7 +783,7 @@ int ssh_message_reply_default(ssh_message msg) { switch(msg->type) { case SSH_REQUEST_AUTH: - return ssh_message_auth_reply_default(msg, 0); + return ssh_auth_reply_default(msg->session, 0); case SSH_REQUEST_CHANNEL_OPEN: return ssh_message_channel_request_open_reply_default(msg); case SSH_REQUEST_CHANNEL: @@ -784,7 +793,7 @@ int ssh_message_reply_default(ssh_message msg) { case SSH_REQUEST_GLOBAL: return ssh_message_global_request_reply_default(msg); default: - ssh_log(msg->session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Don't know what to default reply to %d type", msg->type); break; @@ -940,7 +949,7 @@ int ssh_message_auth_interactive_request(ssh_message msg, const char *name, /* fill in the kbdint structure */ if (msg->session->kbdint == NULL) { - ssh_log(msg->session, SSH_LOG_PROTOCOL, "Warning: Got a " + SSH_LOG(SSH_LOG_PROTOCOL, "Warning: Got a " "keyboard-interactive response but it " "seems we didn't send the request."); @@ -1005,33 +1014,42 @@ int ssh_message_auth_interactive_request(ssh_message msg, const char *name, return r; } -int ssh_message_auth_reply_success(ssh_message msg, int partial) { +int ssh_auth_reply_success(ssh_session session, int partial) { int r; - if (msg == NULL) { - return SSH_ERROR; + if (session == NULL) { + return SSH_ERROR; } if (partial) { - return ssh_message_auth_reply_default(msg, partial); + return ssh_auth_reply_default(session, partial); } + + session->session_state = SSH_SESSION_STATE_AUTHENTICATED; + session->flags |= SSH_SESSION_FLAG_AUTHENTICATED; - if (buffer_add_u8(msg->session->out_buffer,SSH2_MSG_USERAUTH_SUCCESS) < 0) { + if (buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_SUCCESS) < 0) { return SSH_ERROR; } - r = packet_send(msg->session); - if(msg->session->current_crypto && msg->session->current_crypto->delayed_compress_out){ - ssh_log(msg->session,SSH_LOG_PROTOCOL,"Enabling delayed compression OUT"); - msg->session->current_crypto->do_compress_out=1; + r = packet_send(session); + if(session->current_crypto && session->current_crypto->delayed_compress_out){ + SSH_LOG(SSH_LOG_PROTOCOL,"Enabling delayed compression OUT"); + session->current_crypto->do_compress_out=1; } - if(msg->session->current_crypto && msg->session->current_crypto->delayed_compress_in){ - ssh_log(msg->session,SSH_LOG_PROTOCOL,"Enabling delayed compression IN"); - msg->session->current_crypto->do_compress_in=1; + if(session->current_crypto && session->current_crypto->delayed_compress_in){ + SSH_LOG(SSH_LOG_PROTOCOL,"Enabling delayed compression IN"); + session->current_crypto->do_compress_in=1; } return r; } +int ssh_message_auth_reply_success(ssh_message msg, int partial) { + if(msg == NULL) + return SSH_ERROR; + return ssh_auth_reply_success(msg->session, partial); +} + /* Answer OK to a pubkey auth request */ int ssh_message_auth_reply_pk_ok(ssh_message msg, ssh_string algo, ssh_string pubkey) { if (msg == NULL) { @@ -1197,39 +1215,38 @@ int ssh_execute_message_callbacks(ssh_session session){ return SSH_OK; } + int ssh_send_keepalive(ssh_session session) { - /* TODO check the reply and all that */ - struct ssh_string_struct *req; - int reply = 1; - int rc = SSH_ERROR; + /* TODO check the reply and all that */ + struct ssh_string_struct *req; + int reply = 1; + int rc = SSH_ERROR; - enter_function(); - req = ssh_string_from_char("keepalive@openssh.com"); - if (req == NULL) { - ssh_set_error_oom(session); - goto out; - } + req = ssh_string_from_char("keepalive@openssh.com"); + if (req == NULL) { + ssh_set_error_oom(session); + goto out; + } - if (buffer_add_u8(session->out_buffer, SSH2_MSG_GLOBAL_REQUEST) < 0 || - buffer_add_ssh_string(session->out_buffer, req) < 0 || - buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1) < 0) { - ssh_set_error_oom(session); - goto out; - } + if (buffer_add_u8(session->out_buffer, SSH2_MSG_GLOBAL_REQUEST) < 0 || + buffer_add_ssh_string(session->out_buffer, req) < 0 || + buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1) < 0) { + ssh_set_error_oom(session); + goto out; + } - if (packet_send(session) == SSH_ERROR) - goto out; + if (packet_send(session) == SSH_ERROR) + goto out; - ssh_handle_packets(session, 0); + ssh_handle_packets(session, 0); - ssh_log(session, SSH_LOG_PACKET, "Sent a keepalive"); - rc = SSH_OK; + SSH_LOG(SSH_LOG_PACKET, "Sent a keepalive"); + rc = SSH_OK; out: - ssh_string_free(req); - leave_function(); - return rc; + ssh_string_free(req); + return rc; } /** @} */ diff --git a/libssh/src/session.c b/libssh/src/session.c index fe5d897c..477e5ce4 100644 --- a/libssh/src/session.c +++ b/libssh/src/session.c @@ -89,7 +89,6 @@ ssh_session ssh_new(void) { session->alive = 0; session->auth_methods = 0; ssh_set_blocking(session, 1); - session->common.log_indent = 0; session->maxchannel = FIRST_CHANNEL; #ifndef _WIN32 @@ -286,8 +285,6 @@ const char* ssh_get_serverbanner(ssh_session session) { * @param[in] session The SSH session to disconnect. */ void ssh_silent_disconnect(ssh_session session) { - enter_function(); - if (session == NULL) { return; } @@ -295,7 +292,6 @@ void ssh_silent_disconnect(ssh_session session) { ssh_socket_close(session->socket); session->alive = 0; ssh_disconnect(session); - leave_function(); } /** @@ -347,20 +343,21 @@ static int ssh_flush_termination(void *c){ */ int ssh_blocking_flush(ssh_session session, int timeout){ - int rc; - if(!session) - return SSH_ERROR; - enter_function(); + int rc; + if (session == NULL) { + return SSH_ERROR; + } - rc = ssh_handle_packets_termination(session, timeout, - ssh_flush_termination, session); - if (rc == SSH_ERROR) - goto end; - if (!ssh_flush_termination(session)) - rc = SSH_AGAIN; -end: - leave_function(); - return rc; + rc = ssh_handle_packets_termination(session, timeout, + ssh_flush_termination, session); + if (rc == SSH_ERROR) { + return rc; + } + if (!ssh_flush_termination(session)) { + rc = SSH_AGAIN; + } + + return rc; } /** @@ -464,7 +461,6 @@ int ssh_handle_packets(ssh_session session, int timeout) { if (session == NULL || session->socket == NULL) { return SSH_ERROR; } - enter_function(); spoll_in = ssh_socket_get_poll_handle_in(session->socket); spoll_out = ssh_socket_get_poll_handle_out(session->socket); @@ -493,7 +489,6 @@ int ssh_handle_packets(ssh_session session, int timeout) { session->session_state = SSH_SESSION_STATE_ERROR; } - leave_function(); return rc; } @@ -512,6 +507,7 @@ int ssh_handle_packets(ssh_session session, int timeout) { * (-1) means an infinite timeout. * Specifying SSH_TIMEOUT_USER means to use the timeout * specified in options. 0 means poll will return immediately. + * SSH_TIMEOUT_DEFAULT uses blocking parameters of the session. * This parameter is passed to the poll() function. * * @param[in] fct Termination function to be used to determine if it is @@ -519,31 +515,46 @@ int ssh_handle_packets(ssh_session session, int timeout) { * @param[in] user User parameter to be passed to fct termination function. * @return SSH_OK on success, SSH_ERROR otherwise. */ -int ssh_handle_packets_termination(ssh_session session, int timeout, - ssh_termination_function fct, void *user){ - int ret = SSH_OK; - struct ssh_timestamp ts; - int tm; - if (timeout == SSH_TIMEOUT_USER) { - if (ssh_is_blocking(session)) - timeout = ssh_make_milliseconds(session->opts.timeout, - session->opts.timeout_usec); - else - timeout = SSH_TIMEOUT_NONBLOCKING; - } - ssh_timestamp_init(&ts); - tm = timeout; - while(!fct(user)){ - ret = ssh_handle_packets(session, tm); - if(ret == SSH_ERROR) - break; - if(ssh_timeout_elapsed(&ts,timeout)) { - ret = fct(user) ? SSH_OK : SSH_AGAIN; - break; - } - tm = ssh_timeout_update(&ts, timeout); - } - return ret; +int ssh_handle_packets_termination(ssh_session session, + int timeout, + ssh_termination_function fct, + void *user) +{ + struct ssh_timestamp ts; + int ret = SSH_OK; + int tm; + + if (timeout == SSH_TIMEOUT_USER) { + if (ssh_is_blocking(session)) { + timeout = ssh_make_milliseconds(session->opts.timeout, + session->opts.timeout_usec); + } else { + timeout = SSH_TIMEOUT_NONBLOCKING; + } + } else if (timeout == SSH_TIMEOUT_DEFAULT) { + if (ssh_is_blocking(session)) { + timeout = SSH_TIMEOUT_INFINITE; + } else { + timeout = SSH_TIMEOUT_NONBLOCKING; + } + } + + ssh_timestamp_init(&ts); + tm = timeout; + while(!fct(user)) { + ret = ssh_handle_packets(session, tm); + if (ret == SSH_ERROR) { + break; + } + if (ssh_timeout_elapsed(&ts,timeout)) { + ret = fct(user) ? SSH_OK : SSH_AGAIN; + break; + } + + tm = ssh_timeout_update(&ts, timeout); + } + + return ret; } /** @@ -575,7 +586,8 @@ int ssh_get_status(ssh_session session) { if (socketstate & SSH_WRITE_PENDING) { r |= SSH_WRITE_PENDING; } - if (session->closed && (socketstate & SSH_CLOSED_ERROR)) { + if ((session->closed && (socketstate & SSH_CLOSED_ERROR)) || + session->session_state == SSH_SESSION_STATE_ERROR) { r |= SSH_CLOSED_ERROR; } @@ -636,12 +648,11 @@ int ssh_get_version(ssh_session session) { */ void ssh_socket_exception_callback(int code, int errno_code, void *user){ ssh_session session=(ssh_session)user; - enter_function(); - ssh_log(session,SSH_LOG_RARE,"Socket exception callback: %d (%d)",code, errno_code); + + SSH_LOG(SSH_LOG_RARE,"Socket exception callback: %d (%d)",code, errno_code); session->session_state=SSH_SESSION_STATE_ERROR; ssh_set_error(session,SSH_FATAL,"Socket error: %s",strerror(errno_code)); session->ssh_connection_callback(session); - leave_function(); } /** diff --git a/libssh/src/sftp.c b/libssh/src/sftp.c index ee86107b..62460b4d 100644 --- a/libssh/src/sftp.c +++ b/libssh/src/sftp.c @@ -106,12 +106,11 @@ sftp_session sftp_new(ssh_session session){ if (session == NULL) { return NULL; } - enter_function(); sftp = malloc(sizeof(struct sftp_session_struct)); if (sftp == NULL) { ssh_set_error_oom(session); - leave_function(); + return NULL; } ZERO_STRUCTP(sftp); @@ -120,7 +119,7 @@ sftp_session sftp_new(ssh_session session){ if (sftp->ext == NULL) { ssh_set_error_oom(session); SAFE_FREE(sftp); - leave_function(); + return NULL; } @@ -128,24 +127,52 @@ sftp_session sftp_new(ssh_session session){ sftp->channel = ssh_channel_new(session); if (sftp->channel == NULL) { SAFE_FREE(sftp); - leave_function(); + return NULL; } if (ssh_channel_open_session(sftp->channel)) { ssh_channel_free(sftp->channel); SAFE_FREE(sftp); - leave_function(); + return NULL; } if (ssh_channel_request_sftp(sftp->channel)) { sftp_free(sftp); - leave_function(); + return NULL; } - leave_function(); + return sftp; +} + +sftp_session sftp_new_channel(ssh_session session, ssh_channel channel){ + sftp_session sftp; + + if (session == NULL) { + return NULL; + } + + sftp = malloc(sizeof(struct sftp_session_struct)); + if (sftp == NULL) { + ssh_set_error_oom(session); + + return NULL; + } + ZERO_STRUCTP(sftp); + + sftp->ext = sftp_ext_new(); + if (sftp->ext == NULL) { + ssh_set_error_oom(session); + SAFE_FREE(sftp); + + return NULL; + } + + sftp->session = session; + sftp->channel = channel; + return sftp; } @@ -186,11 +213,11 @@ int sftp_server_init(sftp_session sftp){ return -1; } - ssh_log(session, SSH_LOG_PACKET, "Received SSH_FXP_INIT"); + SSH_LOG(SSH_LOG_PACKET, "Received SSH_FXP_INIT"); buffer_get_u32(packet->payload, &version); version = ntohl(version); - ssh_log(session, SSH_LOG_PACKET, "Client version: %d", version); + SSH_LOG(SSH_LOG_PACKET, "Client version: %d", version); sftp->client_version = version; sftp_packet_free(packet); @@ -213,7 +240,7 @@ int sftp_server_init(sftp_session sftp){ } ssh_buffer_free(reply); - ssh_log(session, SSH_LOG_RARE, "Server version sent"); + SSH_LOG(SSH_LOG_RARE, "Server version sent"); if (version > LIBSFTP_VERSION) { sftp->version = LIBSFTP_VERSION; @@ -271,7 +298,7 @@ int sftp_packet_write(sftp_session sftp, uint8_t type, ssh_buffer payload){ if (size < 0) { return -1; } else if((uint32_t) size != buffer_get_rest_len(payload)) { - ssh_log(sftp->session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Had to write %d bytes, wrote only %d", buffer_get_rest_len(payload), size); @@ -419,7 +446,7 @@ static sftp_message sftp_get_message(sftp_packet packet) { return NULL; } - ssh_log(packet->sftp->session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Packet with id %d type %d", msg->id, msg->packet_type); @@ -508,7 +535,7 @@ int sftp_init(sftp_session sftp) { /* TODO: are we sure there are 4 bytes ready? */ buffer_get_u32(packet->payload, &version); version = ntohl(version); - ssh_log(sftp->session, SSH_LOG_RARE, + SSH_LOG(SSH_LOG_RARE, "SFTP server version %d", version); @@ -533,7 +560,7 @@ int sftp_init(sftp_session sftp) { ssh_string_free(ext_data_s); return -1; } - ssh_log(sftp->session, SSH_LOG_RARE, + SSH_LOG(SSH_LOG_RARE, "SFTP server extension: %s, version: %s", ext_name, ext_data); @@ -674,7 +701,7 @@ static int sftp_enqueue(sftp_session sftp, sftp_message msg) { return -1; } - ssh_log(sftp->session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Queued msg type %d id %d", msg->id, msg->packet_type); @@ -715,7 +742,7 @@ static sftp_message sftp_dequeue(sftp_session sftp, uint32_t id){ } msg = queue->message; request_queue_free(queue); - ssh_log(sftp->session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Dequeued msg id %d type %d", msg->id, msg->packet_type); @@ -1191,7 +1218,7 @@ static sftp_attributes sftp_parse_attr_3(sftp_session sftp, ssh_buffer buf, break; } - ssh_log(sftp->session, SSH_LOG_RARE, "Name: %s", attr->name); + SSH_LOG(SSH_LOG_RARE, "Name: %s", attr->name); longname = buffer_get_ssh_string(buf); if (longname == NULL) { @@ -1222,7 +1249,7 @@ static sftp_attributes sftp_parse_attr_3(sftp_session sftp, ssh_buffer buf, } flags = ntohl(flags); attr->flags = flags; - ssh_log(sftp->session, SSH_LOG_RARE, + SSH_LOG(SSH_LOG_RARE, "Flags: %.8lx\n", (long unsigned int) flags); if (flags & SSH_FILEXFER_ATTR_SIZE) { @@ -1230,7 +1257,7 @@ static sftp_attributes sftp_parse_attr_3(sftp_session sftp, ssh_buffer buf, break; } attr->size = ntohll(attr->size); - ssh_log(sftp->session, SSH_LOG_RARE, + SSH_LOG(SSH_LOG_RARE, "Size: %llu\n", (long long unsigned int) attr->size); } @@ -1419,7 +1446,7 @@ sftp_attributes sftp_readdir(sftp_session sftp, sftp_dir dir) { } ssh_buffer_free(payload); - ssh_log(sftp->session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Sent a ssh_fxp_readdir with id %d", id); while (msg == NULL) { @@ -1476,7 +1503,7 @@ sftp_attributes sftp_readdir(sftp_session sftp, sftp_dir dir) { return NULL; } - ssh_log(sftp->session, SSH_LOG_RARE, "Count is %d", dir->count); + SSH_LOG(SSH_LOG_RARE, "Count is %d", dir->count); attr = sftp_parse_attr(sftp, dir->buffer, 1); if (attr == NULL) { @@ -1652,7 +1679,7 @@ sftp_file sftp_open(sftp_session sftp, const char *file, int flags, sftp_flags |= SSH_FXF_TRUNC; if (flags & O_EXCL) sftp_flags |= SSH_FXF_EXCL; - ssh_log(sftp->session,SSH_LOG_PACKET,"Opening file %s with sftp flags %x",file,sftp_flags); + SSH_LOG(SSH_LOG_PACKET,"Opening file %s with sftp flags %x",file,sftp_flags); id = sftp_get_new_id(sftp); if (buffer_add_u32(buffer, id) < 0 || buffer_add_ssh_string(buffer, filename) < 0) { @@ -1971,7 +1998,7 @@ ssize_t sftp_write(sftp_file file, const void *buf, size_t count) { if (len < 0) { return -1; } else if (len != packetlen) { - ssh_log(sftp->session, SSH_LOG_PACKET, + SSH_LOG(SSH_LOG_PACKET, "Could not write as much data as expected"); } diff --git a/libssh/src/sftpserver.c b/libssh/src/sftpserver.c index 3ae93a99..0986b6ce 100644 --- a/libssh/src/sftpserver.c +++ b/libssh/src/sftpserver.c @@ -62,6 +62,10 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) { msg->type = packet->type; msg->sftp = sftp; + /* take a copy of the whole packet */ + msg->complete_message = ssh_buffer_new(); + buffer_add_data(msg->complete_message, buffer_get_rest(payload), buffer_get_rest_len(payload)); + buffer_get_u32(payload, &msg->id); switch(msg->type) { @@ -241,6 +245,34 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) { return msg; } +/* Send an sftp client message. Can be used in cas of proxying */ +int sftp_send_client_message(sftp_session sftp, sftp_client_message msg){ + return sftp_packet_write(sftp, msg->type, msg->complete_message); +} + +uint8_t sftp_client_message_get_type(sftp_client_message msg){ + return msg->type; +} + +const char *sftp_client_message_get_filename(sftp_client_message msg){ + return msg->filename; +} + +void sftp_client_message_set_filename(sftp_client_message msg, const char *newname){ + free(msg->filename); + msg->filename = strdup(newname); +} + +const char *sftp_client_message_get_data(sftp_client_message msg){ + if (msg->str_data == NULL) + msg->str_data = ssh_string_to_char(msg->data); + return msg->str_data; +} + +uint32_t sftp_client_message_get_flags(sftp_client_message msg){ + return msg->flags; +} + void sftp_client_message_free(sftp_client_message msg) { if (msg == NULL) { return; @@ -250,7 +282,8 @@ void sftp_client_message_free(sftp_client_message msg) { ssh_string_free(msg->data); ssh_string_free(msg->handle); sftp_attributes_free(msg->attr); - + ssh_buffer_free(msg->complete_message); + SAFE_FREE(msg->str_data); ZERO_STRUCTP(msg); SAFE_FREE(msg); } diff --git a/libssh/src/socket.c b/libssh/src/socket.c index 0f6c0a83..0dbbe2bc 100644 --- a/libssh/src/socket.c +++ b/libssh/src/socket.c @@ -305,7 +305,7 @@ int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int r #endif /* First, POLLOUT is a sign we may be connected */ if(s->state == SSH_SOCKET_CONNECTING){ - ssh_log(s->session,SSH_LOG_PACKET,"Received POLLOUT in connecting state"); + SSH_LOG(SSH_LOG_PACKET,"Received POLLOUT in connecting state"); s->state = SSH_SOCKET_CONNECTED; ssh_poll_set_events(p,POLLOUT | POLLIN); r = ssh_socket_set_blocking(ssh_socket_get_fd_in(s)); @@ -543,7 +543,7 @@ static int ssh_socket_unbuffered_write(ssh_socket s, const void *buffer, s->write_wontblock = 0; /* Reactive the POLLOUT detector in the poll multiplexer system */ if(s->poll_out){ - ssh_log(s->session, SSH_LOG_PACKET, "Enabling POLLOUT for socket"); + SSH_LOG(SSH_LOG_PACKET, "Enabling POLLOUT for socket"); ssh_poll_set_events(s->poll_out,ssh_poll_get_events(s->poll_out) | POLLOUT); } if (w < 0) { @@ -593,8 +593,6 @@ void ssh_socket_fd_set(ssh_socket s, fd_set *set, socket_t *max_fd) { * \warning has no effect on socket before a flush */ int ssh_socket_write(ssh_socket s, const void *buffer, int len) { - ssh_session session = s->session; - enter_function(); if(len > 0) { if (buffer_add_data(s->out_buffer, buffer, len) < 0) { ssh_set_error_oom(s->session); @@ -602,7 +600,7 @@ int ssh_socket_write(ssh_socket s, const void *buffer, int len) { } ssh_socket_nonblocking_flush(s); } - leave_function(); + return SSH_OK; } @@ -616,8 +614,6 @@ int ssh_socket_nonblocking_flush(ssh_socket s) { uint32_t len; int w; - enter_function(); - if (!ssh_socket_is_open(s)) { session->alive = 0; /* FIXME use ssh_socket_get_errno */ @@ -625,7 +621,6 @@ int ssh_socket_nonblocking_flush(ssh_socket s) { "Writing packet: error on socket (or connection closed): %s", strerror(s->last_errno)); - leave_function(); return SSH_ERROR; } @@ -633,7 +628,7 @@ int ssh_socket_nonblocking_flush(ssh_socket s) { if (!s->write_wontblock && s->poll_out && len > 0) { /* force the poll system to catch pollout events */ ssh_poll_add_events(s->poll_out, POLLOUT); - leave_function(); + return SSH_AGAIN; } if (s->write_wontblock && len > 0) { @@ -646,7 +641,7 @@ int ssh_socket_nonblocking_flush(ssh_socket s) { ssh_set_error(session, SSH_FATAL, "Writing packet: error on socket (or connection closed): %s", strerror(s->last_errno)); - leave_function(); + return SSH_ERROR; } buffer_pass_bytes(s->out_buffer, w); @@ -657,12 +652,11 @@ int ssh_socket_nonblocking_flush(ssh_socket s) { if (s->poll_out && len > 0) { /* force the poll system to catch pollout events */ ssh_poll_add_events(s->poll_out, POLLOUT); - leave_function(); + return SSH_AGAIN; } /* all data written */ - leave_function(); return SSH_OK; } @@ -754,15 +748,14 @@ int ssh_socket_set_blocking(socket_t fd) { int ssh_socket_connect(ssh_socket s, const char *host, int port, const char *bind_addr){ socket_t fd; - ssh_session session=s->session; - enter_function(); + if(s->state != SSH_SOCKET_NONE) { ssh_set_error(s->session, SSH_FATAL, "ssh_socket_connect called on socket not unconnected"); return SSH_ERROR; } fd=ssh_connect_host_nonblocking(s->session,host,bind_addr,port); - ssh_log(session,SSH_LOG_PROTOCOL,"Nonblocking connection socket: %d",fd); + SSH_LOG(SSH_LOG_PROTOCOL,"Nonblocking connection socket: %d",fd); if(fd == SSH_INVALID_SOCKET) return SSH_ERROR; ssh_socket_set_fd(s,fd); @@ -772,7 +765,7 @@ int ssh_socket_connect(ssh_socket s, const char *host, int port, const char *bin #ifdef _WIN32 ssh_poll_add_events(ssh_socket_get_poll_handle_in(s),POLLWRNORM); #endif - leave_function(); + return SSH_OK; } @@ -811,8 +804,7 @@ int ssh_socket_connect_proxycommand(ssh_socket s, const char *command){ socket_t out_pipe[2]; int pid; int rc; - ssh_session session=s->session; - enter_function(); + if(s->state != SSH_SOCKET_NONE) return SSH_ERROR; @@ -825,14 +817,14 @@ int ssh_socket_connect_proxycommand(ssh_socket s, const char *command){ return SSH_ERROR; } - ssh_log(session,SSH_LOG_PROTOCOL,"Executing proxycommand '%s'",command); + SSH_LOG(SSH_LOG_PROTOCOL,"Executing proxycommand '%s'",command); pid = fork(); if(pid == 0){ ssh_execute_command(command,out_pipe[0],in_pipe[1]); } close(in_pipe[1]); close(out_pipe[0]); - ssh_log(session,SSH_LOG_PROTOCOL,"ProxyCommand connection pipe: [%d,%d]",in_pipe[0],out_pipe[1]); + SSH_LOG(SSH_LOG_PROTOCOL,"ProxyCommand connection pipe: [%d,%d]",in_pipe[0],out_pipe[1]); ssh_socket_set_fd_in(s,in_pipe[0]); ssh_socket_set_fd_out(s,out_pipe[1]); s->state=SSH_SOCKET_CONNECTED; @@ -842,7 +834,7 @@ int ssh_socket_connect_proxycommand(ssh_socket s, const char *command){ ssh_poll_set_events(ssh_socket_get_poll_handle_out(s),POLLOUT); if(s->callbacks && s->callbacks->connected) s->callbacks->connected(SSH_SOCKET_CONNECTED_OK,0,s->callbacks->userdata); - leave_function(); + return SSH_OK; } diff --git a/libssh/src/wrapper.c b/libssh/src/wrapper.c index c04322a4..66593461 100644 --- a/libssh/src/wrapper.c +++ b/libssh/src/wrapper.c @@ -166,10 +166,8 @@ void crypto_free(struct ssh_crypto_struct *crypto){ static int crypt_set_algorithms2(ssh_session session){ const char *wanted; int i = 0; - int rc = SSH_ERROR; struct ssh_cipher_struct *ssh_ciphertab=ssh_get_ciphertab(); - enter_function(); /* we must scan the kex entries to find crypto algorithms and set their appropriate structure */ /* out */ wanted = session->next_crypto->kex_methods[SSH_CRYPT_C_S]; @@ -181,14 +179,14 @@ static int crypt_set_algorithms2(ssh_session session){ ssh_set_error(session, SSH_FATAL, "crypt_set_algorithms2: no crypto algorithm function found for %s", wanted); - goto error; + return SSH_ERROR; } - ssh_log(session, SSH_LOG_PACKET, "Set output algorithm to %s", wanted); + SSH_LOG(SSH_LOG_PACKET, "Set output algorithm to %s", wanted); session->next_crypto->out_cipher = cipher_new(i); if (session->next_crypto->out_cipher == NULL) { - ssh_set_error_oom(session); - goto error; + ssh_set_error_oom(session); + return SSH_ERROR; } i = 0; @@ -199,17 +197,17 @@ static int crypt_set_algorithms2(ssh_session session){ } if (ssh_ciphertab[i].name == NULL) { - ssh_set_error(session, SSH_FATAL, - "Crypt_set_algorithms: no crypto algorithm function found for %s", - wanted); - goto error; + ssh_set_error(session, SSH_FATAL, + "Crypt_set_algorithms: no crypto algorithm function found for %s", + wanted); + return SSH_ERROR; } - ssh_log(session, SSH_LOG_PACKET, "Set input algorithm to %s", wanted); + SSH_LOG(SSH_LOG_PACKET, "Set input algorithm to %s", wanted); session->next_crypto->in_cipher = cipher_new(i); if (session->next_crypto->in_cipher == NULL) { - ssh_set_error_oom(session); - goto error; + ssh_set_error_oom(session); + return SSH_ERROR; } /* compression */ @@ -225,10 +223,8 @@ static int crypt_set_algorithms2(ssh_session session){ if (strcmp(session->next_crypto->kex_methods[SSH_COMP_S_C], "zlib@openssh.com") == 0) { session->next_crypto->delayed_compress_in = 1; } - rc = SSH_OK; -error: - leave_function(); - return rc; + + return SSH_OK; } static int crypt_set_algorithms1(ssh_session session, enum ssh_des_e des_type) { @@ -270,15 +266,16 @@ int crypt_set_algorithms(ssh_session session, enum ssh_des_e des_type) { int crypt_set_algorithms_server(ssh_session session){ char *method = NULL; int i = 0; - int rc = SSH_ERROR; struct ssh_cipher_struct *ssh_ciphertab=ssh_get_ciphertab(); if (session == NULL) { return SSH_ERROR; } - /* we must scan the kex entries to find crypto algorithms and set their appropriate structure */ - enter_function(); + /* + * We must scan the kex entries to find crypto algorithms and set their + * appropriate structure + */ /* out */ method = session->next_crypto->kex_methods[SSH_CRYPT_S_C]; while(ssh_ciphertab[i].name && strcmp(method,ssh_ciphertab[i].name)) @@ -286,14 +283,14 @@ int crypt_set_algorithms_server(ssh_session session){ if(!ssh_ciphertab[i].name){ ssh_set_error(session,SSH_FATAL,"crypt_set_algorithms_server : " "no crypto algorithm function found for %s",method); - goto error; + return SSH_ERROR; } - ssh_log(session,SSH_LOG_PACKET,"Set output algorithm %s",method); + SSH_LOG(SSH_LOG_PACKET,"Set output algorithm %s",method); session->next_crypto->out_cipher = cipher_new(i); if (session->next_crypto->out_cipher == NULL) { - ssh_set_error_oom(session); - goto error; + ssh_set_error_oom(session); + return SSH_ERROR; } i=0; /* in */ @@ -303,43 +300,41 @@ int crypt_set_algorithms_server(ssh_session session){ if(!ssh_ciphertab[i].name){ ssh_set_error(session,SSH_FATAL,"Crypt_set_algorithms_server :" "no crypto algorithm function found for %s",method); - goto error; + return SSH_ERROR; } - ssh_log(session,SSH_LOG_PACKET,"Set input algorithm %s",method); + SSH_LOG(SSH_LOG_PACKET,"Set input algorithm %s",method); session->next_crypto->in_cipher = cipher_new(i); if (session->next_crypto->in_cipher == NULL) { - ssh_set_error_oom(session); - goto error; + ssh_set_error_oom(session); + return SSH_ERROR; } /* compression */ method = session->next_crypto->kex_methods[SSH_COMP_C_S]; if(strcmp(method,"zlib") == 0){ - ssh_log(session,SSH_LOG_PACKET,"enabling C->S compression"); + SSH_LOG(SSH_LOG_PACKET,"enabling C->S compression"); session->next_crypto->do_compress_in=1; } if(strcmp(method,"zlib@openssh.com") == 0){ - ssh_log(session,SSH_LOG_PACKET,"enabling C->S compression"); + SSH_LOG(SSH_LOG_PACKET,"enabling C->S compression"); session->next_crypto->delayed_compress_in=1; } method = session->next_crypto->kex_methods[SSH_COMP_S_C]; if(strcmp(method,"zlib") == 0){ - ssh_log(session,SSH_LOG_PACKET,"enabling S->C compression\n"); + SSH_LOG(SSH_LOG_PACKET, "enabling S->C compression\n"); session->next_crypto->do_compress_out=1; } if(strcmp(method,"zlib@openssh.com") == 0){ - ssh_log(session,SSH_LOG_PACKET,"enabling S->C delayed compression\n"); + SSH_LOG(SSH_LOG_PACKET,"enabling S->C delayed compression\n"); session->next_crypto->delayed_compress_out=1; } method = session->next_crypto->kex_methods[SSH_HOSTKEYS]; session->srv.hostkey = ssh_key_type_from_name(method); - rc = SSH_OK; - error: - leave_function(); - return rc; + + return SSH_OK; } #endif /* WITH_SERVER */ diff --git a/libssh/tests/client/torture_session.c b/libssh/tests/client/torture_session.c index 4e2f6477..f2e062b4 100644 --- a/libssh/tests/client/torture_session.c +++ b/libssh/tests/client/torture_session.c @@ -92,6 +92,8 @@ static void torture_channel_read_error(void **state) { break; } assert_true(rc == SSH_ERROR); + + ssh_channel_free(channel); } int torture_run_tests(void) { diff --git a/libssh/tests/torture.c b/libssh/tests/torture.c index 2a49f0d7..c7031fcb 100644 --- a/libssh/tests/torture.c +++ b/libssh/tests/torture.c @@ -30,7 +30,10 @@ # include # include # include -# include +#endif + +#ifdef HAVE_UNISTD_H +#include #endif #include "torture.h" diff --git a/libssh/tests/unittests/torture_options.c b/libssh/tests/unittests/torture_options.c index 76da3edb..6f5df1bb 100644 --- a/libssh/tests/unittests/torture_options.c +++ b/libssh/tests/unittests/torture_options.c @@ -176,6 +176,23 @@ static void torture_options_get_identity(void **state) { free(identity); } +static void torture_options_proxycommand(void **state) { + ssh_session session = *state; + int rc; + + /* Enable ProxyCommand */ + rc = ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, "ssh -q -A -X -W %h:%p JUMPHOST"); + assert_int_equal(rc, 0); + + assert_string_equal(session->opts.ProxyCommand, "ssh -q -A -X -W %h:%p JUMPHOST"); + + /* Disable ProxyCommand */ + rc = ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, "none"); + assert_int_equal(rc, 0); + + assert_null(session->opts.ProxyCommand); +} + int torture_run_tests(void) { int rc; const UnitTest tests[] = { @@ -188,6 +205,7 @@ int torture_run_tests(void) { unit_test_setup_teardown(torture_options_get_user, setup, teardown), unit_test_setup_teardown(torture_options_set_identity, setup, teardown), unit_test_setup_teardown(torture_options_get_identity, setup, teardown), + unit_test_setup_teardown(torture_options_proxycommand, setup, teardown), }; ssh_init(); diff --git a/libssh/tests/unittests/torture_pki.c b/libssh/tests/unittests/torture_pki.c index 20bf5c60..7324177e 100644 --- a/libssh/tests/unittests/torture_pki.c +++ b/libssh/tests/unittests/torture_pki.c @@ -86,22 +86,22 @@ static char *read_file(const char *filename) { int fd; int size; int rc; - struct stat buf; + struct stat sb; assert_true(filename != NULL); assert_true(*filename != '\0'); - rc = stat(filename, &buf); - assert_int_equal(rc, 0); - - key = malloc(buf.st_size + 1); - assert_true(key != NULL); - fd = open(filename, O_RDONLY); assert_true(fd >= 0); - size = read(fd, key, buf.st_size); - assert_true(size == buf.st_size); + rc = fstat(fd, &sb); + assert_int_equal(rc, 0); + + key = malloc(sb.st_size + 1); + assert_true(key != NULL); + + size = read(fd, key, sb.st_size); + assert_true(size == sb.st_size); close(fd); diff --git a/libssh/tests/valgrind.supp b/libssh/tests/valgrind.supp index 4b553ead..a4276c3b 100644 --- a/libssh/tests/valgrind.supp +++ b/libssh/tests/valgrind.supp @@ -17,6 +17,17 @@ fun:ssh_connect_host_nonblocking } +{ + glibc_dlopen_getdelim_selinux + Memcheck:Leak + fun:malloc + fun:getdelim + obj:/lib64/libselinux.so.1 + fun:call_init + fun:_dl_init + obj:/lib64/ld-2.15.so +} + ### OPENSSL { openssl_crypto_value8