mirror of
https://github.com/tmate-io/tmate.git
synced 2024-11-30 12:04:38 +01:00
Updated libssh
This commit is contained in:
parent
aab28e3796
commit
246bec30bc
@ -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}")
|
||||
|
@ -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")
|
||||
|
@ -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.
|
||||
|
@ -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 <string.h>
|
||||
|
||||
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)
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
324
libssh/cmake/Modules/FindGSSAPI.cmake
Normal file
324
libssh/cmake/Modules/FindGSSAPI.cmake
Normal file
@ -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 <asn@cryptomilk.org>
|
||||
#
|
||||
# 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)
|
@ -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 <asn@cryptomilk.org>
|
||||
# Copyright (c) 2010-2013 Andreas Schneider <asn@cryptomilk.org>
|
||||
#
|
||||
# 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)
|
||||
|
@ -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)
|
||||
|
@ -23,6 +23,9 @@
|
||||
/* Define to 1 if you have the <termios.h> header file. */
|
||||
#cmakedefine HAVE_TERMIOS_H 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#cmakedefine HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to 1 if you have the <openssl/aes.h> 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
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
<!-- Doxygen TracFooter -->
|
@ -1,4 +0,0 @@
|
||||
<!-- Doxygen TracHeader -->
|
||||
<style>@import url(/chrome/site/doxygen.css);</style>
|
||||
<style>@import url(/chrome/site/tabs.css);</style>
|
||||
<!-- /Doxygen TracHeader -->
|
@ -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 <input-file> 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
|
||||
|
@ -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 <libssh/libssh.h>
|
||||
@endcode
|
||||
|
||||
*/
|
||||
|
@ -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
|
||||
- <strong>Key Exchange Methods</strong>: <i>ecdh-sha2-nistp256</i>, diffie-hellman-group1-sha1, diffie-hellman-group14-sha1
|
||||
- <strong>Hostkey Types</strong>: <i>ecdsa-sha2-nistp256</i>, ssh-dss, ssh-rsa
|
||||
- <strong>Ciphers</strong>: <i>aes256-ctr, aes192-ctr, aes128-ctr</i>, aes256-cbc (rijndael-cbc@lysator.liu.se), aes192-cbc, aes128-cbc, 3des-cbc, des-cbc-ssh1, blowfish-cbc, none
|
||||
- <strong>Compression Schemes</strong>: zlib, <i>zlib@openssh.com</i>, none
|
||||
- <strong>MAC hashes</strong>: hmac-sha1, none
|
||||
- <strong>Authentication</strong>: none, password, public-key, hostbased, keyboard-interactive, <i>gssapi-with-mic</i>
|
||||
- <strong>Channels</strong>: shell, exec (incl. SCP wrapper), direct-tcpip, subsystem, <i>auth-agent-req@openssh.com</i>
|
||||
- <strong>Global Requests</strong>: tcpip-forward, forwarded-tcpip
|
||||
- <strong>Channel Requests</strong>: x11, pty, <i>exit-status, signal, exit-signal, keepalive@openssh.com, auth-agent-req@openssh.com</i>
|
||||
- <strong>Subsystems</strong>: sftp(version 3), publickey(version 2), <i>OpenSSH Extensions</i>
|
||||
- <strong>SFTP</strong>: <i>statvfs@openssh.com, fstatvfs@openssh.com</i>
|
||||
- <strong>Thread-safe</strong>: Just don't share sessions
|
||||
- <strong>Non-blocking</strong>: it can be used both blocking and non-blocking
|
||||
- <strong>Your sockets</strong>: the app hands over the socket, or uses libssh sockets
|
||||
- <b>OpenSSL</b> or <b>gcrypt</b>: builds with either
|
||||
|
||||
@section main-additional-features Additional Features
|
||||
|
||||
- Client <b>and</b> server support
|
||||
- SSHv2 and SSHv1 protocol support
|
||||
- Supports <a href="http://test.libssh.org/" target="_blank">Linux, UNIX, BSD, Solaris, OS/2 and Windows</a>
|
||||
- Automated test cases with nightly <a href="http://test.libssh.org/" target="_blank">tests</a>
|
||||
- Event model based on poll(2), or a poll(2)-emulation.
|
||||
|
||||
@section main-copyright Copyright Policy
|
||||
|
||||
|
@ -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})
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
347
libssh/examples/proxy.c
Normal file
347
libssh/examples/proxy.c
Normal file
@ -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 <libssh/libssh.h>
|
||||
#include <libssh/server.h>
|
||||
#include <libssh/callbacks.h>
|
||||
|
||||
#ifdef HAVE_ARGP_H
|
||||
#include <argp.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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 = "<libssh@libssh.org>";
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
@ -14,24 +14,31 @@ clients must be made or how a client should react.
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
#include <termios.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_PTY_H
|
||||
#include <pty.h>
|
||||
#endif
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <libssh/callbacks.h>
|
||||
#include <libssh/libssh.h>
|
||||
#include <libssh/sftp.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#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
|
||||
|
@ -15,11 +15,13 @@ clients must be made or how a client should react.
|
||||
|
||||
#include <sys/statvfs.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
#include <libssh/sftp.h>
|
||||
|
306
libssh/examples/samplesshd-cb.c
Normal file
306
libssh/examples/samplesshd-cb.c
Normal file
@ -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 <libssh/libssh.h>
|
||||
#include <libssh/server.h>
|
||||
#include <libssh/callbacks.h>
|
||||
|
||||
#ifdef HAVE_ARGP_H
|
||||
#include <argp.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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 = "<libssh@libssh.org>";
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
@ -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[] = {
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -13,10 +13,14 @@ clients must be made or how a client should react.
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
#include <termios.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
@ -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;
|
||||
}
|
||||
|
@ -71,6 +71,7 @@ struct ssh_agent_struct {
|
||||
struct ssh_socket_struct *sock;
|
||||
ssh_buffer ident;
|
||||
unsigned int count;
|
||||
ssh_channel channel;
|
||||
};
|
||||
|
||||
#ifndef _WIN32
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
45
libssh/include/libssh/gssapi.h
Normal file
45
libssh/include/libssh/gssapi.h
Normal file
@ -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 */
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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_ */
|
||||
|
@ -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_ */
|
||||
|
@ -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 <stdio.h>
|
||||
|
||||
@ -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 <sys/time.h>
|
||||
@ -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
|
||||
|
@ -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
|
||||
**********************************************************/
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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}
|
||||
|
@ -42,12 +42,12 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#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) {
|
||||
|
@ -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: */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -27,6 +27,8 @@
|
||||
#include <stdio.h>
|
||||
#ifndef _WIN32
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#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);
|
||||
|
||||
|
@ -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;i<len;++i){
|
||||
@ -115,20 +114,20 @@ static int callback_receive_banner(const void *data, size_t len, void *user) {
|
||||
ret=i+1;
|
||||
session->serverbanner=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) {
|
||||
|
@ -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)) {
|
||||
|
@ -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; i<maxfd ; ++i){
|
||||
if(FD_ISSET(i, readfds)){
|
||||
ssh_event_add_fd(event, i, POLLIN, ssh_select_cb, readfds);
|
||||
}
|
||||
|
||||
for (fd = 0; fd < maxfd ; fd++) {
|
||||
if (FD_ISSET(fd, readfds)) {
|
||||
ssh_event_add_fd(event, fd, POLLIN, ssh_select_cb, readfds);
|
||||
}
|
||||
}
|
||||
outchannels[0] = NULL;
|
||||
FD_ZERO(readfds);
|
||||
@ -481,9 +473,12 @@ int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
|
||||
if(j != 0)
|
||||
break;
|
||||
/* watch if a user socket was triggered */
|
||||
for(i = 0;i<maxfd;++i)
|
||||
if(FD_ISSET(i, readfds))
|
||||
goto out;
|
||||
for (fd = 0; fd < maxfd; fd++) {
|
||||
if (FD_ISSET(fd, readfds)) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the timeout is elapsed, we should go out */
|
||||
if(!firstround && ssh_timeout_elapsed(&ts, base_tm))
|
||||
goto out;
|
||||
|
@ -560,7 +560,7 @@ int dh_build_k(ssh_session session) {
|
||||
int ssh_client_dh_init(ssh_session session){
|
||||
ssh_string e = NULL;
|
||||
int rc;
|
||||
enter_function();
|
||||
|
||||
if (buffer_add_u8(session->out_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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21,6 +21,8 @@
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
@ -163,8 +165,12 @@ int ssh_getpass(const char *prompt,
|
||||
#else
|
||||
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
#include <termios.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup libssh_misc
|
||||
|
947
libssh/src/gssapi.c
Normal file
947
libssh/src/gssapi.c
Normal file
@ -0,0 +1,947 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2013 by Aris Adamantiadis <aris@badcode.be>
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <gssapi/gssapi.h>
|
||||
|
||||
#include <libssh/gssapi.h>
|
||||
#include <libssh/libssh.h>
|
||||
#include <libssh/ssh2.h>
|
||||
#include <libssh/buffer.h>
|
||||
#include <libssh/crypto.h>
|
||||
#include <libssh/callbacks.h>
|
||||
#include <libssh/string.h>
|
||||
#include <libssh/server.h>
|
||||
|
||||
/** 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; i<n_oid; ++i){
|
||||
rc = buffer_add_ssh_string(session->out_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; i<supported->count; ++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; i<n_oids; ++i){
|
||||
oids[i] = ssh_string_new(selected->elements[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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
127
libssh/src/log.c
127
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: */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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 */
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#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++;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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) {
|
||||
|
@ -30,7 +30,10 @@
|
||||
# include <sys/stat.h>
|
||||
# include <dirent.h>
|
||||
# include <errno.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "torture.h"
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user