mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-04 12:20:42 +09:00
Compare commits
1 Commits
libssh-0.9
...
master-fix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8daf03c564 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -4,8 +4,6 @@
|
||||
*.swp
|
||||
*~$
|
||||
cscope.*
|
||||
compile_commands.json
|
||||
/.clangd
|
||||
tags
|
||||
/build
|
||||
/obj*
|
||||
|
||||
122
.gitlab-ci.yml
122
.gitlab-ci.yml
@@ -4,8 +4,9 @@ variables:
|
||||
CENTOS7_BUILD: buildenv-centos7
|
||||
TUMBLEWEED_BUILD: buildenv-tumbleweed
|
||||
MINGW_BUILD: buildenv-mingw
|
||||
DEBIAN_CROSS_BUILD: buildenv-debian-cross
|
||||
|
||||
# pkd tests fail on CentOS7 docker images, so we don't use -DSERVER_TESTING=ON
|
||||
# torture_auth fails on centos7 docker images, so we don't use -DCLIENT_TESTING=ON
|
||||
centos7/openssl_1.0.x/x86_64:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS7_BUILD
|
||||
script:
|
||||
@@ -13,7 +14,7 @@ centos7/openssl_1.0.x/x86_64:
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON .. &&
|
||||
-DUNIT_TESTING=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
@@ -31,10 +32,7 @@ fedora/openssl_1.1.x/x86_64:
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_BLOWFISH_CIPHER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DWITH_DEBUG_CRYPTO=ON
|
||||
-DWITH_DEBUG_PACKET=ON -DWITH_DEBUG_CALLTRACE=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
@@ -47,48 +45,6 @@ fedora/openssl_1.1.x/x86_64:
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
fedora/openssl_1.1.x/x86_64/fips:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||
script:
|
||||
- echo 1 > /etc/system-fips
|
||||
- update-crypto-policies --set FIPS
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_BLOWFISH_CIPHER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DWITH_DEBUG_CRYPTO=ON -DWITH_DEBUG_PACKET=ON -DWITH_DEBUG_CALLTRACE=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
|
||||
make -j$(nproc) && OPENSSL_FORCE_FIPS_MODE=1 ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
fedora/openssl_1.1.x/x86_64/minimal:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=OFF -DWITH_SERVER=OFF -DWITH_ZLIB=OFF -DWITH_PCAP=OFF
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DWITH_GEX=OFF .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
# Address sanitizer doesn't mix well with LD_PRELOAD used in the testsuite
|
||||
# so, this is only enabled for unit tests right now.
|
||||
# TODO: add -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
|
||||
@@ -111,34 +67,11 @@ fedora/address-sanitizer:
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
# This is disabled as it report OpenSSL issues
|
||||
# It also has ethe same issues with cwrap as AddressSanitizer
|
||||
.fedora/memory-sanitizer:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_BUILD_TYPE=MemorySanitizer
|
||||
-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON ..
|
||||
&& make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
fedora/undefined-sanitizer:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_BUILD_TYPE=UndefinedSanitizer
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DCMAKE_C_FLAGS="-fsanitize=undefined -fsanitize=null -fsanitize=alignment -fno-sanitize-recover"
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON ..
|
||||
&& make -j$(nproc) && ctest --output-on-failure
|
||||
@@ -168,7 +101,8 @@ fedora/csbuild:
|
||||
|
||||
- csbuild
|
||||
--build-dir=obj-csbuild
|
||||
--build-cmd "rm -rf CMakeFiles CMakeCache.txt && cmake -DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DFUZZ_TESTING=ON @SRCDIR@ && make clean && make -j$(nproc)"
|
||||
--prep-cmd="cmake -DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DFUZZ_TESTING=ON @SRCDIR@"
|
||||
--build-cmd "make clean && make -j$(nproc)"
|
||||
--git-commit-range $CI_COMMIT_RANGE
|
||||
--color
|
||||
--print-current --print-fixed
|
||||
@@ -214,7 +148,7 @@ fedora/libgcrypt/x86_64:
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
|
||||
-DWITH_GCRYPT=ON -DWITH_DEBUG_CRYPTO=ON .. &&
|
||||
-DWITH_GCRYPT=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
@@ -234,7 +168,7 @@ fedora/mbedtls/x86_64:
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
|
||||
-DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON .. &&
|
||||
-DWITH_MBEDTLS=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
@@ -294,6 +228,33 @@ fedora/mingw32:
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
.Debian.cross.template: &Debian_cross_template
|
||||
stage: test
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$DEBIAN_CROSS_BUILD
|
||||
script:
|
||||
- build=$(dpkg-architecture -qDEB_HOST_GNU_TYPE)
|
||||
- host="${CI_JOB_NAME#*.cross.}"
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_C_COMPILER="$(which $host-gcc)"
|
||||
-DCMAKE_CXX_COMPILER="$(which $host-g++)"
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
-DUNIT_TESTING=ON -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON
|
||||
-DWITH_PCAP=ON .. &&
|
||||
make -j$(nproc) &&
|
||||
ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
Debian.cross.mips-linux-gnu:
|
||||
<<: *Debian_cross_template
|
||||
|
||||
tumbleweed/openssl_1.1.x/x86_64/gcc:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
|
||||
script:
|
||||
@@ -302,7 +263,7 @@ tumbleweed/openssl_1.1.x/x86_64/gcc:
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config
|
||||
-DUNIT_TESTING=ON -DSERVER_TESTING=ON .. &&
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
@@ -343,7 +304,7 @@ tumbleweed/openssl_1.1.x/x86_64/gcc7:
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config
|
||||
-DUNIT_TESTING=ON -DSERVER_TESTING=ON .. &&
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
@@ -385,8 +346,7 @@ tumbleweed/openssl_1.1.x/x86_64/clang:
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config
|
||||
-DUNIT_TESTING=ON
|
||||
-DSERVER_TESTING=ON .. &&
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
@@ -419,7 +379,7 @@ tumbleweed/undefined-sanitizer:
|
||||
-DCMAKE_BUILD_TYPE=UndefinedSanitizer
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DSERVER_TESTING=ON .. &&
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
@@ -441,7 +401,7 @@ tumbleweed/static-analysis:
|
||||
-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DSERVER_TESTING=ON .. &&
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
|
||||
scan-build --status-bugs -o scan make -j$(nproc)
|
||||
tags:
|
||||
- shared
|
||||
@@ -474,7 +434,6 @@ visualstudio/x86_64:
|
||||
- branches@libssh/libssh-mirror
|
||||
- branches@ansasaki/libssh-mirror
|
||||
- branches@cryptomilk/libssh-mirror
|
||||
- branches@jjelen/libssh-mirror
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
@@ -501,7 +460,6 @@ visualstudio/x86:
|
||||
- branches@libssh/libssh-mirror
|
||||
- branches@ansasaki/libssh-mirror
|
||||
- branches@cryptomilk/libssh-mirror
|
||||
- branches@jjelen/libssh-mirror
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
|
||||
@@ -10,7 +10,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules")
|
||||
include(DefineCMakeDefaults)
|
||||
include(DefineCompilerFlags)
|
||||
|
||||
project(libssh VERSION 0.9.2 LANGUAGES C)
|
||||
project(libssh VERSION 0.8.90 LANGUAGES C)
|
||||
|
||||
# global needed variable
|
||||
set(APPLICATION_NAME ${PROJECT_NAME})
|
||||
@@ -22,16 +22,16 @@ set(APPLICATION_NAME ${PROJECT_NAME})
|
||||
# Increment AGE. Set REVISION to 0
|
||||
# If the source code was changed, but there were no interface changes:
|
||||
# Increment REVISION.
|
||||
set(LIBRARY_VERSION "4.8.3")
|
||||
set(LIBRARY_VERSION "4.7.2")
|
||||
set(LIBRARY_SOVERSION "4")
|
||||
|
||||
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
|
||||
|
||||
# add definitions
|
||||
include(DefinePlatformDefaults)
|
||||
include(DefineInstallationPaths)
|
||||
include(DefineOptions.cmake)
|
||||
include(CPackConfig.cmake)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
include(CompilerChecks.cmake)
|
||||
|
||||
@@ -117,7 +117,7 @@ install(
|
||||
FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/libssh.pc
|
||||
DESTINATION
|
||||
${CMAKE_INSTALL_LIBDIR}/pkgconfig
|
||||
${LIB_INSTALL_DIR}/pkgconfig
|
||||
COMPONENT
|
||||
pkgconfig
|
||||
)
|
||||
@@ -133,13 +133,21 @@ write_basic_package_version_file(libssh-config-version.cmake
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY SameMajorVersion)
|
||||
|
||||
# libssh-config.cmake
|
||||
configure_package_config_file(${PROJECT_NAME}-config.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_DIR}/${PROJECT_NAME}
|
||||
PATH_VARS INCLUDE_INSTALL_DIR LIB_INSTALL_DIR)
|
||||
|
||||
install(
|
||||
FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake
|
||||
DESTINATION
|
||||
${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
|
||||
${CMAKE_INSTALL_DIR}/${PROJECT_NAME}
|
||||
COMPONENT
|
||||
devel)
|
||||
devel
|
||||
)
|
||||
|
||||
if (WITH_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
@@ -205,11 +213,6 @@ endif (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
|
||||
|
||||
add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source DEPENDS ${_SYMBOL_TARGET})
|
||||
|
||||
# Link compile database for clangd
|
||||
execute_process(COMMAND cmake -E create_symlink
|
||||
"${CMAKE_BINARY_DIR}/compile_commands.json"
|
||||
"${CMAKE_SOURCE_DIR}/compile_commands.json")
|
||||
|
||||
message(STATUS "********************************************")
|
||||
message(STATUS "********** ${PROJECT_NAME} build options : **********")
|
||||
|
||||
@@ -220,12 +223,10 @@ message(STATUS "libnacl support: ${WITH_NACL}")
|
||||
message(STATUS "SFTP support: ${WITH_SFTP}")
|
||||
message(STATUS "Server support : ${WITH_SERVER}")
|
||||
message(STATUS "GSSAPI support : ${WITH_GSSAPI}")
|
||||
message(STATUS "GEX support : ${WITH_GEX}")
|
||||
message(STATUS "Pcap debugging support : ${WITH_PCAP}")
|
||||
message(STATUS "Build shared library: ${BUILD_SHARED_LIBS}")
|
||||
message(STATUS "With static library: ${WITH_STATIC_LIB}")
|
||||
message(STATUS "Unit testing: ${UNIT_TESTING}")
|
||||
message(STATUS "Client code testing: ${CLIENT_TESTING}")
|
||||
message(STATUS "Blowfish cipher support: ${WITH_BLOWFISH_CIPHER}")
|
||||
set(_SERVER_TESTING OFF)
|
||||
if (WITH_SERVER)
|
||||
set(_SERVER_TESTING ${SERVER_TESTING})
|
||||
@@ -240,9 +241,5 @@ message(STATUS "Benchmarks: ${WITH_BENCHMARKS}")
|
||||
message(STATUS "Symbol versioning: ${WITH_SYMBOL_VERSIONING}")
|
||||
message(STATUS "Allow ABI break: ${WITH_ABI_BREAK}")
|
||||
message(STATUS "Release is final: ${WITH_FINAL}")
|
||||
message(STATUS "Global client config: ${GLOBAL_CLIENT_CONFIG}")
|
||||
if (WITH_SERVER)
|
||||
message(STATUS "Global bind config: ${GLOBAL_BIND_CONFIG}")
|
||||
endif()
|
||||
message(STATUS "********************************************")
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
|
||||
|
||||
# SOURCE GENERATOR
|
||||
set(CPACK_SOURCE_GENERATOR "TXZ")
|
||||
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]git/;/[.]clangd/;.gitignore;/build*;/obj*;tags;cscope.*;compile_commands.json")
|
||||
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]git/;.gitignore;/build*;/obj*;tags;cscope.*")
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
|
||||
|
||||
### NSIS INSTALLER
|
||||
|
||||
99
ChangeLog
99
ChangeLog
@@ -1,105 +1,6 @@
|
||||
ChangeLog
|
||||
==========
|
||||
|
||||
version 0.9.2 (released 2019-11-07)
|
||||
* Fixed libssh-config.cmake
|
||||
* Fixed issues with rsa algorithm negotiation (T191)
|
||||
* Fixed detection of OpenSSL ed25519 support (T197)
|
||||
|
||||
version 0.9.1 (released 2019-10-25)
|
||||
* Added support for Ed25519 via OpenSSL
|
||||
* Added support for X25519 via OpenSSL
|
||||
* Added support for localuser in Match keyword
|
||||
* Fixed Match keyword to be case sensitive
|
||||
* Fixed compilation with LibreSSL
|
||||
* Fixed error report of channel open (T75)
|
||||
* Fixed sftp documentation (T137)
|
||||
* Fixed known_hosts parsing (T156)
|
||||
* Fixed build issue with MinGW (T157)
|
||||
* Fixed build with gcc 9 (T164)
|
||||
* Fixed deprecation issues (T165)
|
||||
* Fixed known_hosts directory creation (T166)
|
||||
|
||||
version 0.9.0 (released 2019-06-28)
|
||||
* Added support for AES-GCM
|
||||
* Added improved rekeying support
|
||||
* Added performance improvements
|
||||
* Disabled blowfish support by default
|
||||
* Fixed several ssh config parsing issues
|
||||
* Added support for DH Group Exchange KEX
|
||||
* Added support for Encrypt-then-MAC mode
|
||||
* Added support for parsing server side configuration file
|
||||
* Added support for ECDSA/Ed25519 certificates
|
||||
* Added FIPS 140-2 compatibility
|
||||
* Improved known_hosts parsing
|
||||
* Improved documentation
|
||||
* Improved OpenSSL API usage for KEX, DH, and signatures
|
||||
|
||||
version 0.8.7 (released 2019-02-25)
|
||||
* Fixed handling extension flags in the server implementation
|
||||
* Fixed exporting ed25519 private keys
|
||||
* Fixed corner cases for rsa-sha2 signatures
|
||||
* Fixed some issues with connector
|
||||
|
||||
version 0.8.6 (released 2018-12-24)
|
||||
* Fixed compilation issues with different OpenSSL versions
|
||||
* Fixed StrictHostKeyChecking in new knownhosts API
|
||||
* Fixed ssh_send_keepalive() with packet filter
|
||||
* Fixed possible crash with knownhosts options
|
||||
* Fixed issus with rekeying
|
||||
* Fixed strong ECDSA keys
|
||||
* Fixed some issues with rsa-sha2 extentions
|
||||
* Fixed access violation in ssh_init() (static linking)
|
||||
* Fixed ssh_channel_close() handling
|
||||
|
||||
version 0.8.5 (released 2018-10-29)
|
||||
* Added support to get known_hosts locations with ssh_options_get()
|
||||
* Fixed preferred algorithm for known hosts negotiations
|
||||
* Fixed KEX with some server implementations (e.g. Cisco)
|
||||
* Fixed issues with MSVC
|
||||
* Fixed keyboard-interactive auth in server mode
|
||||
(regression from CVE-2018-10933)
|
||||
* Fixed gssapi auth in server mode (regression from CVE-2018-10933)
|
||||
* Fixed socket fd handling with proxy command
|
||||
* Fixed a memory leak with OpenSSL
|
||||
|
||||
version 0.8.4 (released 2018-10-16)
|
||||
* Fixed CVE-2018-10933
|
||||
* Fixed building without globbing support
|
||||
* Fixed possible memory leaks
|
||||
* Avoid SIGPIPE on sockets
|
||||
|
||||
version 0.8.3 (released 2018-09-21)
|
||||
* Added support for rsa-sha2
|
||||
* Added support to parse private keys in openssh container format
|
||||
(other than ed25519)
|
||||
* Added support for diffie-hellman-group18-sha512 and
|
||||
diffie-hellman-group16-sha512
|
||||
* Added ssh_get_fingerprint_hash()
|
||||
* Added ssh_pki_export_privkey_base64()
|
||||
* Added support for Match keyword in config file
|
||||
* Improved performance and reduced memory footprint for sftp
|
||||
* Fixed ecdsa publickey auth
|
||||
* Fixed reading a closed channel
|
||||
* Added support to announce posix-rename@openssh.com and
|
||||
hardlink@openssh.com in the sftp server
|
||||
|
||||
version 0.8.2 (released 2018-08-30)
|
||||
* Added sha256 fingerprints for pubkeys
|
||||
* Improved compiler flag detection
|
||||
* Fixed race condition in reading sftp messages
|
||||
* Fixed doxygen generation and added modern style
|
||||
* Fixed library initialization on Windows
|
||||
* Fixed __bounded__ attribute detection
|
||||
* Fixed a bug in the options parser
|
||||
* Fixed documentation for new knwon_hosts API
|
||||
|
||||
version 0.8.1 (released 2018-08-13)
|
||||
* Fixed version number in the header
|
||||
* Fixed version number in pkg-config and cmake config
|
||||
* Fixed library initialization
|
||||
* Fixed attribute detection
|
||||
|
||||
version 0.8.0 (released 2018-08-10)
|
||||
* Removed support for deprecated SSHv1 protocol
|
||||
* Added new connector API for clients
|
||||
|
||||
@@ -41,7 +41,6 @@ if (UNIX)
|
||||
add_c_compiler_flag("-Werror=strict-overflow" SUPPORTED_COMPILER_FLAGS)
|
||||
add_c_compiler_flag("-Wstrict-overflow=2" SUPPORTED_COMPILER_FLAGS)
|
||||
add_c_compiler_flag("-Wno-format-zero-length" SUPPORTED_COMPILER_FLAGS)
|
||||
add_c_compiler_flag("-Wmissing-field-initializers" SUPPORTED_COMPILER_FLAGS)
|
||||
|
||||
check_c_compiler_flag("-Wformat" REQUIRED_FLAGS_WFORMAT)
|
||||
if (REQUIRED_FLAGS_WFORMAT)
|
||||
|
||||
@@ -9,7 +9,10 @@ include(TestBigEndian)
|
||||
|
||||
set(PACKAGE ${PROJECT_NAME})
|
||||
set(VERSION ${PROJECT_VERSION})
|
||||
set(SYSCONFDIR ${CMAKE_INSTALL_SYSCONFDIR})
|
||||
set(DATADIR ${DATA_INSTALL_DIR})
|
||||
set(LIBDIR ${LIB_INSTALL_DIR})
|
||||
set(PLUGINDIR "${PLUGIN_INSTALL_DIR}-${LIBRARY_SOVERSION}")
|
||||
set(SYSCONFDIR ${SYSCONF_INSTALL_DIR})
|
||||
|
||||
set(BINARYDIR ${CMAKE_BINARY_DIR})
|
||||
set(SOURCEDIR ${CMAKE_SOURCE_DIR})
|
||||
@@ -86,10 +89,8 @@ if (OPENSSL_FOUND)
|
||||
message(FATAL_ERROR "Could not detect openssl/aes.h")
|
||||
endif()
|
||||
|
||||
if (WITH_BLOWFISH_CIPHER)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
check_include_file(openssl/blowfish.h HAVE_OPENSSL_BLOWFISH_H)
|
||||
endif()
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
check_include_file(openssl/blowfish.h HAVE_OPENSSL_BLOWFISH_H)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
check_include_file(openssl/ecdh.h HAVE_OPENSSL_ECDH_H)
|
||||
@@ -124,41 +125,12 @@ if (OPENSSL_FOUND)
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_function_exists(EVP_CIPHER_CTX_new HAVE_OPENSSL_EVP_CIPHER_CTX_NEW)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_function_exists(EVP_KDF_CTX_new_id HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_function_exists(FIPS_mode HAVE_OPENSSL_FIPS_MODE)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_function_exists(RAND_priv_bytes HAVE_OPENSSL_RAND_PRIV_BYTES)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_function_exists(EVP_DigestSign HAVE_OPENSSL_EVP_DIGESTSIGN)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_function_exists(EVP_DigestVerify HAVE_OPENSSL_EVP_DIGESTVERIFY)
|
||||
|
||||
check_function_exists(OPENSSL_ia32cap_loc HAVE_OPENSSL_IA32CAP_LOC)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_symbol_exists(EVP_PKEY_ED25519 "openssl/evp.h" FOUND_OPENSSL_ED25519)
|
||||
|
||||
if (HAVE_OPENSSL_EVP_DIGESTSIGN AND HAVE_OPENSSL_EVP_DIGESTVERIFY AND
|
||||
FOUND_OPENSSL_ED25519)
|
||||
set(HAVE_OPENSSL_ED25519 1)
|
||||
endif()
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_symbol_exists(EVP_PKEY_X25519 "openssl/evp.h" HAVE_OPENSSL_X25519)
|
||||
|
||||
unset(CMAKE_REQUIRED_INCLUDES)
|
||||
unset(CMAKE_REQUIRED_LIBRARIES)
|
||||
endif()
|
||||
@@ -405,6 +377,18 @@ int main(void)
|
||||
return 0;
|
||||
}" HAVE_GCC_VOLATILE_MEMORY_PROTECTION)
|
||||
|
||||
check_c_source_compiles("
|
||||
#include <stdio.h>
|
||||
#define __VA_NARG__(...) (__VA_NARG_(_0, ## __VA_ARGS__, __RSEQ_N()) - 1)
|
||||
#define __VA_NARG_(...) __VA_ARG_N(__VA_ARGS__)
|
||||
#define __VA_ARG_N( _1, _2, _3, _4, _5, _6, _7, _8, _9,_10,N,...) N
|
||||
#define __RSEQ_N() 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
|
||||
#define myprintf(format, ...) printf((format), __VA_NARG__(__VA_ARGS__), __VA_ARGS__)
|
||||
int main(void) {
|
||||
myprintf(\"%d %d %d %d\",1,2,3);
|
||||
return 0;
|
||||
}" HAVE_GCC_NARG_MACRO)
|
||||
|
||||
check_c_source_compiles("
|
||||
#include <stdio.h>
|
||||
int main(void) {
|
||||
|
||||
@@ -2,15 +2,14 @@ option(WITH_GSSAPI "Build with GSSAPI support" ON)
|
||||
option(WITH_ZLIB "Build with ZLIB support" ON)
|
||||
option(WITH_SFTP "Build with SFTP support" ON)
|
||||
option(WITH_SERVER "Build with SSH server support" ON)
|
||||
option(WITH_STATIC_LIB "Build with a static library" OFF)
|
||||
option(WITH_DEBUG_CRYPTO "Build with cryto debug output" OFF)
|
||||
option(WITH_DEBUG_PACKET "Build with packet debug output" OFF)
|
||||
option(WITH_DEBUG_CALLTRACE "Build with calltrace debug output" ON)
|
||||
option(WITH_GCRYPT "Compile against libgcrypt" OFF)
|
||||
option(WITH_MBEDTLS "Compile against libmbedtls" OFF)
|
||||
option(WITH_BLOWFISH_CIPHER "Compile with blowfish support" OFF)
|
||||
option(WITH_PCAP "Compile with Pcap generation support" ON)
|
||||
option(WITH_INTERNAL_DOC "Compile doxygen internal documentation" OFF)
|
||||
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
|
||||
option(UNIT_TESTING "Build with unit tests" OFF)
|
||||
option(CLIENT_TESTING "Build with client tests; requires openssh" OFF)
|
||||
option(SERVER_TESTING "Build with server tests; requires openssh and dropbear" OFF)
|
||||
@@ -19,7 +18,6 @@ option(WITH_EXAMPLES "Build examples" ON)
|
||||
option(WITH_NACL "Build with libnacl (curve25519)" ON)
|
||||
option(WITH_SYMBOL_VERSIONING "Build with symbol versioning" ON)
|
||||
option(WITH_ABI_BREAK "Allow ABI break" OFF)
|
||||
option(WITH_GEX "Enable DH Group exchange mechanisms" ON)
|
||||
option(FUZZ_TESTING "Build with fuzzer for the server" OFF)
|
||||
option(PICKY_DEVELOPER "Build with picky developer flags" OFF)
|
||||
|
||||
@@ -34,9 +32,13 @@ if (WITH_BENCHMARKS)
|
||||
set(CLIENT_TESTING ON)
|
||||
endif()
|
||||
|
||||
if (UNIT_TESTING OR CLIENT_TESTING OR SERVER_TESTING)
|
||||
if (WITH_STATIC_LIB)
|
||||
set(BUILD_STATIC_LIB ON)
|
||||
endif (WITH_STATIC_LIB)
|
||||
|
||||
if (UNIT_TESTING)
|
||||
set(BUILD_STATIC_LIB ON)
|
||||
endif()
|
||||
endif (UNIT_TESTING)
|
||||
|
||||
if (WITH_NACL)
|
||||
set(WITH_NACL ON)
|
||||
@@ -45,11 +47,3 @@ endif (WITH_NACL)
|
||||
if (WITH_ABI_BREAK)
|
||||
set(WITH_SYMBOL_VERSIONING ON)
|
||||
endif (WITH_ABI_BREAK)
|
||||
|
||||
if (NOT GLOBAL_BIND_CONFIG)
|
||||
set(GLOBAL_BIND_CONFIG "/etc/ssh/libssh_server_config")
|
||||
endif (NOT GLOBAL_BIND_CONFIG)
|
||||
|
||||
if (NOT GLOBAL_CLIENT_CONFIG)
|
||||
set(GLOBAL_CLIENT_CONFIG "/etc/ssh/ssh_config")
|
||||
endif (NOT GLOBAL_CLIENT_CONFIG)
|
||||
|
||||
5
INSTALL
5
INSTALL
@@ -11,10 +11,9 @@ In order to build libssh, you need to install several components:
|
||||
- [openssl](http://www.openssl.org) >= 0.9.8
|
||||
or
|
||||
- [gcrypt](http://www.gnu.org/directory/Security/libgcrypt.html) >= 1.4
|
||||
- [libz](http://www.zlib.net) >= 1.2
|
||||
|
||||
optional:
|
||||
- [cmocka](https://cmocka.org/) >= 1.1.0
|
||||
- [libz](http://www.zlib.net) >= 1.2
|
||||
- [socket_wrapper](https://cwrap.org/) >= 1.1.5
|
||||
- [nss_wrapper](https://cwrap.org/) >= 1.1.2
|
||||
- [uid_wrapper](https://cwrap.org/) >= 1.2.0
|
||||
@@ -27,7 +26,7 @@ For Windows use vcpkg:
|
||||
|
||||
https://github.com/Microsoft/vcpkg
|
||||
|
||||
which you can use to install openssl and zlib. libssh itself is also part of
|
||||
which you can use to install openssl and zilib. libssh itself is also part of
|
||||
vcpkg!
|
||||
|
||||
## Building
|
||||
|
||||
@@ -23,18 +23,6 @@ if (UNIX AND NOT WIN32)
|
||||
set(CMAKE_EXEC_LINKER_FLAGS_ADDRESSSANITIZER "-fsanitize=address"
|
||||
CACHE STRING "Flags used by the linker during ADDRESSSANITIZER builds.")
|
||||
|
||||
# Activate with: -DCMAKE_BUILD_TYPE=MemorySanitizer
|
||||
set(CMAKE_C_FLAGS_MEMORYSANITIZER "-g -O2 -fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer"
|
||||
CACHE STRING "Flags used by the C compiler during MEMORYSANITIZER builds.")
|
||||
set(CMAKE_CXX_FLAGS_MEMORYSANITIZER "-g -O2 -fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer"
|
||||
CACHE STRING "Flags used by the CXX compiler during MEMORYSANITIZER builds.")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_MEMORYSANITIZER "-fsanitize=memory"
|
||||
CACHE STRING "Flags used by the linker during the creation of shared libraries during MEMORYSANITIZER builds.")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS_MEMORYSANITIZER "-fsanitize=memory"
|
||||
CACHE STRING "Flags used by the linker during the creation of shared libraries during MEMORYSANITIZER builds.")
|
||||
set(CMAKE_EXEC_LINKER_FLAGS_MEMORYSANITIZER "-fsanitize=memory"
|
||||
CACHE STRING "Flags used by the linker during MEMORYSANITIZER builds.")
|
||||
|
||||
# Activate with: -DCMAKE_BUILD_TYPE=UndefinedSanitizer
|
||||
set(CMAKE_C_FLAGS_UNDEFINEDSANITIZER "-g -O1 -fsanitize=undefined -fsanitize=null -fsanitize=alignment -fno-sanitize-recover"
|
||||
CACHE STRING "Flags used by the C compiler during UNDEFINEDSANITIZER builds.")
|
||||
|
||||
109
cmake/Modules/DefineInstallationPaths.cmake
Normal file
109
cmake/Modules/DefineInstallationPaths.cmake
Normal file
@@ -0,0 +1,109 @@
|
||||
if (UNIX OR OS2)
|
||||
IF (NOT APPLICATION_NAME)
|
||||
MESSAGE(STATUS "${PROJECT_NAME} is used as APPLICATION_NAME")
|
||||
SET(APPLICATION_NAME ${PROJECT_NAME})
|
||||
ENDIF (NOT APPLICATION_NAME)
|
||||
|
||||
# Suffix for Linux
|
||||
SET(LIB_SUFFIX
|
||||
CACHE STRING "Define suffix of directory name (32/64)"
|
||||
)
|
||||
|
||||
SET(EXEC_INSTALL_PREFIX
|
||||
"${CMAKE_INSTALL_PREFIX}"
|
||||
CACHE PATH "Base directory for executables and libraries"
|
||||
)
|
||||
SET(SHARE_INSTALL_PREFIX
|
||||
"${CMAKE_INSTALL_PREFIX}/share"
|
||||
CACHE PATH "Base directory for files which go to share/"
|
||||
)
|
||||
SET(DATA_INSTALL_PREFIX
|
||||
"${SHARE_INSTALL_PREFIX}/${APPLICATION_NAME}"
|
||||
CACHE PATH "The parent directory where applications can install their data")
|
||||
|
||||
# The following are directories where stuff will be installed to
|
||||
SET(BIN_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/bin"
|
||||
CACHE PATH "The ${APPLICATION_NAME} binary install dir (default prefix/bin)"
|
||||
)
|
||||
SET(SBIN_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/sbin"
|
||||
CACHE PATH "The ${APPLICATION_NAME} sbin install dir (default prefix/sbin)"
|
||||
)
|
||||
SET(LIB_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX}"
|
||||
CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/lib)"
|
||||
)
|
||||
SET(LIBEXEC_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/libexec"
|
||||
CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/libexec)"
|
||||
)
|
||||
SET(PLUGIN_INSTALL_DIR
|
||||
"${LIB_INSTALL_DIR}/${APPLICATION_NAME}"
|
||||
CACHE PATH "The subdirectory relative to the install prefix where plugins will be installed (default is prefix/lib/${APPLICATION_NAME})"
|
||||
)
|
||||
SET(INCLUDE_INSTALL_DIR
|
||||
"${CMAKE_INSTALL_PREFIX}/include"
|
||||
CACHE PATH "The subdirectory to the header prefix (default prefix/include)"
|
||||
)
|
||||
|
||||
set(CMAKE_INSTALL_DIR
|
||||
"${LIB_INSTALL_DIR}/cmake"
|
||||
CACHE PATH "The subdirectory to install cmake config files")
|
||||
|
||||
SET(DATA_INSTALL_DIR
|
||||
"${DATA_INSTALL_PREFIX}"
|
||||
CACHE PATH "The parent directory where applications can install their data (default prefix/share/${APPLICATION_NAME})"
|
||||
)
|
||||
SET(HTML_INSTALL_DIR
|
||||
"${DATA_INSTALL_PREFIX}/doc/HTML"
|
||||
CACHE PATH "The HTML install dir for documentation (default data/doc/html)"
|
||||
)
|
||||
SET(ICON_INSTALL_DIR
|
||||
"${DATA_INSTALL_PREFIX}/icons"
|
||||
CACHE PATH "The icon install dir (default data/icons/)"
|
||||
)
|
||||
SET(SOUND_INSTALL_DIR
|
||||
"${DATA_INSTALL_PREFIX}/sounds"
|
||||
CACHE PATH "The install dir for sound files (default data/sounds)"
|
||||
)
|
||||
|
||||
SET(LOCALE_INSTALL_DIR
|
||||
"${SHARE_INSTALL_PREFIX}/locale"
|
||||
CACHE PATH "The install dir for translations (default prefix/share/locale)"
|
||||
)
|
||||
|
||||
SET(XDG_APPS_DIR
|
||||
"${SHARE_INSTALL_PREFIX}/applications/"
|
||||
CACHE PATH "The XDG apps dir"
|
||||
)
|
||||
SET(XDG_DIRECTORY_DIR
|
||||
"${SHARE_INSTALL_PREFIX}/desktop-directories"
|
||||
CACHE PATH "The XDG directory"
|
||||
)
|
||||
|
||||
SET(SYSCONF_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/etc"
|
||||
CACHE PATH "The ${APPLICATION_NAME} sysconfig install dir (default prefix/etc)"
|
||||
)
|
||||
SET(MAN_INSTALL_DIR
|
||||
"${SHARE_INSTALL_PREFIX}/man"
|
||||
CACHE PATH "The ${APPLICATION_NAME} man install dir (default prefix/man)"
|
||||
)
|
||||
SET(INFO_INSTALL_DIR
|
||||
"${SHARE_INSTALL_PREFIX}/info"
|
||||
CACHE PATH "The ${APPLICATION_NAME} info install dir (default prefix/info)"
|
||||
)
|
||||
else()
|
||||
# Same same
|
||||
set(BIN_INSTALL_DIR "bin" CACHE PATH "-")
|
||||
set(SBIN_INSTALL_DIR "sbin" CACHE PATH "-")
|
||||
set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}" CACHE PATH "-")
|
||||
set(INCLUDE_INSTALL_DIR "include" CACHE PATH "-")
|
||||
set(CMAKE_INSTALL_DIR "CMake" CACHE PATH "-")
|
||||
set(PLUGIN_INSTALL_DIR "plugins" CACHE PATH "-")
|
||||
set(HTML_INSTALL_DIR "doc/HTML" CACHE PATH "-")
|
||||
set(ICON_INSTALL_DIR "icons" CACHE PATH "-")
|
||||
set(SOUND_INSTALL_DIR "soudns" CACHE PATH "-")
|
||||
set(LOCALE_INSTALL_DIR "lang" CACHE PATH "-")
|
||||
endif ()
|
||||
@@ -4,16 +4,14 @@
|
||||
/* Version number of package */
|
||||
#cmakedefine VERSION "${PROJECT_VERSION}"
|
||||
|
||||
#cmakedefine LOCALEDIR "${LOCALE_INSTALL_DIR}"
|
||||
#cmakedefine DATADIR "${DATADIR}"
|
||||
#cmakedefine LIBDIR "${LIBDIR}"
|
||||
#cmakedefine PLUGINDIR "${PLUGINDIR}"
|
||||
#cmakedefine SYSCONFDIR "${SYSCONFDIR}"
|
||||
#cmakedefine BINARYDIR "${BINARYDIR}"
|
||||
#cmakedefine SOURCEDIR "${SOURCEDIR}"
|
||||
|
||||
/* Global bind configuration file path */
|
||||
#cmakedefine GLOBAL_BIND_CONFIG "${GLOBAL_BIND_CONFIG}"
|
||||
|
||||
/* Global client configuration file path */
|
||||
#cmakedefine GLOBAL_CLIENT_CONFIG "${GLOBAL_CLIENT_CONFIG}"
|
||||
|
||||
/************************** HEADER FILES *************************/
|
||||
|
||||
/* Define to 1 if you have the <argp.h> header file. */
|
||||
@@ -97,12 +95,6 @@
|
||||
/* Define to 1 if you have gl_flags as a glob_t sturct member */
|
||||
#cmakedefine HAVE_GLOB_GL_FLAGS_MEMBER 1
|
||||
|
||||
/* Define to 1 if you have OpenSSL with Ed25519 support */
|
||||
#cmakedefine HAVE_OPENSSL_ED25519 1
|
||||
|
||||
/* Define to 1 if you have OpenSSL with X25519 support */
|
||||
#cmakedefine HAVE_OPENSSL_X25519 1
|
||||
|
||||
/*************************** FUNCTIONS ***************************/
|
||||
|
||||
/* Define to 1 if you have the `EVP_aes128_ctr' function. */
|
||||
@@ -123,18 +115,6 @@
|
||||
/* Define to 1 if you have the `EVP_CIPHER_CTX_new' function. */
|
||||
#cmakedefine HAVE_OPENSSL_EVP_CIPHER_CTX_NEW 1
|
||||
|
||||
/* Define to 1 if you have the `EVP_KDF_CTX_new_id' function. */
|
||||
#cmakedefine HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID 1
|
||||
|
||||
/* Define to 1 if you have the `FIPS_mode' function. */
|
||||
#cmakedefine HAVE_OPENSSL_FIPS_MODE 1
|
||||
|
||||
/* Define to 1 if you have the `EVP_DigestSign' function. */
|
||||
#cmakedefine HAVE_OPENSSL_EVP_DIGESTSIGN 1
|
||||
|
||||
/* Define to 1 if you have the `EVP_DigestVerify' function. */
|
||||
#cmakedefine HAVE_OPENSSL_EVP_DIGESTVERIFY 1
|
||||
|
||||
/* Define to 1 if you have the `OPENSSL_ia32cap_loc' function. */
|
||||
#cmakedefine HAVE_OPENSSL_IA32CAP_LOC 1
|
||||
|
||||
@@ -239,6 +219,7 @@
|
||||
#cmakedefine HAVE_DESTRUCTOR_ATTRIBUTE 1
|
||||
|
||||
#cmakedefine HAVE_GCC_VOLATILE_MEMORY_PROTECTION 1
|
||||
#cmakedefine HAVE_GCC_NARG_MACRO 1
|
||||
|
||||
#cmakedefine HAVE_COMPILER__FUNC__ 1
|
||||
#cmakedefine HAVE_COMPILER__FUNCTION__ 1
|
||||
@@ -257,12 +238,6 @@
|
||||
/* Define to 1 if you want to enable server support */
|
||||
#cmakedefine WITH_SERVER 1
|
||||
|
||||
/* Define to 1 if you want to enable DH group exchange algorithms */
|
||||
#cmakedefine WITH_GEX 1
|
||||
|
||||
/* Define to 1 if you want to enable blowfish cipher support */
|
||||
#cmakedefine WITH_BLOWFISH_CIPHER 1
|
||||
|
||||
/* Define to 1 if you want to enable debug output for crypto functions */
|
||||
#cmakedefine DEBUG_CRYPTO 1
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ int authenticate_pubkey(ssh_session session)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ssh_userauth_publickey_auto(session, NULL, NULL);
|
||||
rc = ssh_userauth_publickey_auto(session, NULL);
|
||||
|
||||
if (rc == SSH_AUTH_ERROR)
|
||||
{
|
||||
@@ -281,7 +281,7 @@ pass, ssh_userauth_none() might answer SSH_AUTH_SUCCESS.
|
||||
The following example shows how to perform "none" authentication:
|
||||
|
||||
@code
|
||||
int authenticate_none(ssh_session session)
|
||||
int authenticate_kbdint(ssh_session session)
|
||||
{
|
||||
int rc;
|
||||
|
||||
|
||||
@@ -431,9 +431,6 @@ int show_remote_processes(ssh_session session)
|
||||
}
|
||||
@endcode
|
||||
|
||||
Each ssh_channel_request_exec() needs to be run on freshly created
|
||||
and connected (with ssh_channel_open_session()) channel.
|
||||
|
||||
@see @ref opening_shell
|
||||
@see @ref remote_command
|
||||
@see @ref sftp_subsystem
|
||||
|
||||
@@ -27,7 +27,4 @@ the dllimport attribute.
|
||||
#include <libssh/libssh.h>
|
||||
@endcode
|
||||
|
||||
If you're are statically linking with OpenSSL, read the "Linking your
|
||||
application" section in the NOTES.<OS> in the OpenSSL source tree!
|
||||
|
||||
*/
|
||||
|
||||
@@ -23,7 +23,7 @@ The libssh library provides:
|
||||
- <strong>Public Key Algorithms</strong>: ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, ssh-rsa, rsa-sha2-512, rsa-sha2-256,ssh-dss
|
||||
- <strong>Ciphers</strong>: <i>aes256-ctr, aes192-ctr, aes128-ctr</i>, aes256-cbc (rijndael-cbc@lysator.liu.se), aes192-cbc, aes128-cbc, 3des-cbc, blowfish-cbc, none
|
||||
- <strong>Compression Schemes</strong>: zlib, <i>zlib@openssh.com</i>, none
|
||||
- <strong>MAC hashes</strong>: hmac-sha1, hmac-sha2-256, hmac-sha2-512, hmac-md5, none
|
||||
- <strong>MAC hashes</strong>: hmac-sha1, hmac-sha2-256, hmac-sha2-384, hmac-sha2-512, hmac-md5, none
|
||||
- <strong>Authentication</strong>: none, password, public-key, 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
|
||||
|
||||
@@ -61,7 +61,7 @@ int sftp_helloworld(ssh_session session)
|
||||
rc = sftp_init(sftp);
|
||||
if (rc != SSH_OK)
|
||||
{
|
||||
fprintf(stderr, "Error initializing SFTP session: code %d.\n",
|
||||
fprintf(stderr, "Error initializing SFTP session: %s.\n",
|
||||
sftp_get_error(sftp));
|
||||
sftp_free(sftp);
|
||||
return rc;
|
||||
|
||||
@@ -6,7 +6,10 @@ set(examples_SRCS
|
||||
connect_ssh.c
|
||||
)
|
||||
|
||||
include_directories(${libssh_BINARY_DIR})
|
||||
include_directories(
|
||||
${LIBSSH_PUBLIC_INCLUDE_DIRS}
|
||||
${CMAKE_BINARY_DIR}
|
||||
)
|
||||
|
||||
if (ARGP_INCLUDE_DIR)
|
||||
include_directories(${ARGP_INCLUDE_DIR})
|
||||
@@ -15,68 +18,60 @@ endif()
|
||||
if (UNIX AND NOT WIN32)
|
||||
add_executable(libssh_scp libssh_scp.c ${examples_SRCS})
|
||||
target_compile_options(libssh_scp PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
target_link_libraries(libssh_scp ssh::ssh)
|
||||
target_link_libraries(libssh_scp ${LIBSSH_SHARED_LIBRARY})
|
||||
|
||||
add_executable(scp_download scp_download.c ${examples_SRCS})
|
||||
target_compile_options(scp_download PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
target_link_libraries(scp_download ssh::ssh)
|
||||
target_link_libraries(scp_download ${LIBSSH_SHARED_LIBRARY})
|
||||
|
||||
add_executable(sshnetcat sshnetcat.c ${examples_SRCS})
|
||||
target_compile_options(sshnetcat PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
target_link_libraries(sshnetcat ssh::ssh)
|
||||
target_link_libraries(sshnetcat ${LIBSSH_SHARED_LIBRARY})
|
||||
|
||||
if (WITH_SFTP)
|
||||
add_executable(samplesftp samplesftp.c ${examples_SRCS})
|
||||
target_compile_options(samplesftp PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
target_link_libraries(samplesftp ssh::ssh)
|
||||
target_link_libraries(samplesftp ${LIBSSH_SHARED_LIBRARY})
|
||||
endif (WITH_SFTP)
|
||||
|
||||
add_executable(ssh-client ssh_client.c ${examples_SRCS})
|
||||
target_compile_options(ssh-client PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
target_link_libraries(ssh-client ssh::ssh)
|
||||
target_link_libraries(ssh-client ${LIBSSH_SHARED_LIBRARY})
|
||||
|
||||
if (WITH_SERVER AND (ARGP_LIBRARY OR HAVE_ARGP_H))
|
||||
if (HAVE_LIBUTIL)
|
||||
add_executable(ssh_server_fork ssh_server_fork.c)
|
||||
target_compile_options(ssh_server_fork PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
target_link_libraries(ssh_server_fork ssh::ssh ${ARGP_LIBRARY} util)
|
||||
target_link_libraries(ssh_server_fork ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARY} util)
|
||||
endif (HAVE_LIBUTIL)
|
||||
|
||||
if (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||
add_executable(samplesshd-cb samplesshd-cb.c)
|
||||
target_compile_options(samplesshd-cb PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
target_link_libraries(samplesshd-cb ssh::ssh ${ARGP_LIBRARY})
|
||||
target_link_libraries(samplesshd-cb ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARY})
|
||||
|
||||
add_executable(proxy proxy.c)
|
||||
target_compile_options(proxy PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
target_link_libraries(proxy ssh::ssh ${ARGP_LIBRARY})
|
||||
|
||||
add_executable(sshd_direct-tcpip sshd_direct-tcpip.c)
|
||||
target_compile_options(sshd_direct-tcpip PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
target_link_libraries(sshd_direct-tcpip ssh::ssh ${ARGP_LIBRARY})
|
||||
target_link_libraries(proxy ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARY})
|
||||
endif (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||
|
||||
add_executable(samplesshd-kbdint samplesshd-kbdint.c)
|
||||
target_compile_options(samplesshd-kbdint PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
target_link_libraries(samplesshd-kbdint ssh::ssh ${ARGP_LIBRARY})
|
||||
target_link_libraries(samplesshd-kbdint ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARY})
|
||||
|
||||
endif()
|
||||
endif (UNIX AND NOT WIN32)
|
||||
|
||||
add_executable(exec exec.c ${examples_SRCS})
|
||||
target_compile_options(exec PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
target_link_libraries(exec ssh::ssh)
|
||||
target_link_libraries(exec ${LIBSSH_SHARED_LIBRARY})
|
||||
|
||||
add_executable(senddata senddata.c ${examples_SRCS})
|
||||
target_compile_options(senddata PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
target_link_libraries(senddata ssh::ssh)
|
||||
|
||||
add_executable(keygen keygen.c)
|
||||
target_compile_options(keygen PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
target_link_libraries(keygen ssh::ssh)
|
||||
target_link_libraries(senddata ${LIBSSH_SHARED_LIBRARY})
|
||||
|
||||
add_executable(libsshpp libsshpp.cpp)
|
||||
target_link_libraries(libsshpp ssh::ssh)
|
||||
target_link_libraries(libsshpp ${LIBSSH_SHARED_LIBRARY})
|
||||
|
||||
add_executable(libsshpp_noexcept libsshpp_noexcept.cpp)
|
||||
target_link_libraries(libsshpp_noexcept ssh::ssh)
|
||||
target_link_libraries(libsshpp_noexcept ${LIBSSH_SHARED_LIBRARY})
|
||||
|
||||
@@ -100,39 +100,6 @@ int authenticate_kbdint(ssh_session session, const char *password)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int auth_keyfile(ssh_session session, char* keyfile)
|
||||
{
|
||||
ssh_key key = NULL;
|
||||
char pubkey[132] = {0}; // +".pub"
|
||||
int rc;
|
||||
|
||||
snprintf(pubkey, sizeof(pubkey), "%s.pub", keyfile);
|
||||
|
||||
rc = ssh_pki_import_pubkey_file( pubkey, &key);
|
||||
|
||||
if (rc != SSH_OK)
|
||||
return SSH_AUTH_DENIED;
|
||||
|
||||
rc = ssh_userauth_try_publickey(session, NULL, key);
|
||||
|
||||
ssh_key_free(key);
|
||||
|
||||
if (rc!=SSH_AUTH_SUCCESS)
|
||||
return SSH_AUTH_DENIED;
|
||||
|
||||
rc = ssh_pki_import_privkey_file(keyfile, NULL, NULL, NULL, &key);
|
||||
|
||||
if (rc != SSH_OK)
|
||||
return SSH_AUTH_DENIED;
|
||||
|
||||
rc = ssh_userauth_publickey(session, NULL, key);
|
||||
|
||||
ssh_key_free(key);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static void error(ssh_session session)
|
||||
{
|
||||
fprintf(stderr,"Authentication failed: %s\n",ssh_get_error(session));
|
||||
@@ -173,35 +140,6 @@ int authenticate_console(ssh_session session)
|
||||
break;
|
||||
}
|
||||
}
|
||||
{
|
||||
char buffer[128] = {0};
|
||||
char *p = NULL;
|
||||
|
||||
printf("Automatic pubkey failed. "
|
||||
"Do you want to try a specific key? (y/n)\n");
|
||||
if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
|
||||
break;
|
||||
}
|
||||
if ((buffer[0]=='Y') || (buffer[0]=='y')) {
|
||||
printf("private key filename: ");
|
||||
|
||||
if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
buffer[sizeof(buffer) - 1] = '\0';
|
||||
if ((p = strchr(buffer, '\n'))) {
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
rc = auth_keyfile(session, buffer);
|
||||
|
||||
if(rc == SSH_AUTH_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, "failed with key\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Try to authenticate with keyboard interactive";
|
||||
if (method & SSH_AUTH_METHOD_INTERACTIVE) {
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/* keygen.c
|
||||
* Sample implementation of ssh-keygen using libssh
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2019 Red Hat, Inc.
|
||||
|
||||
Author: Jakub Jelen <jjelen@redhat.com>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
ssh_key key = NULL;
|
||||
int rv;
|
||||
|
||||
/* Generate a new ED25519 private key file */
|
||||
rv = ssh_pki_generate(SSH_KEYTYPE_ED25519, 0, &key);
|
||||
if (rv != SSH_OK) {
|
||||
fprintf(stderr, "Failed to generate private key");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Write it to a file testkey in the current dirrectory */
|
||||
rv = ssh_pki_export_privkey_file(key, NULL, NULL, NULL, "testkey");
|
||||
if (rv != SSH_OK) {
|
||||
fprintf(stderr, "Failed to write private key file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,17 +1,16 @@
|
||||
/* ssh_client.c */
|
||||
|
||||
/* client.c */
|
||||
/*
|
||||
* Copyright 2003-2015 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.
|
||||
*/
|
||||
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 <stdio.h>
|
||||
@@ -198,20 +197,19 @@ static void sizechanged(void)
|
||||
static void select_loop(ssh_session session,ssh_channel channel)
|
||||
{
|
||||
ssh_connector connector_in, connector_out, connector_err;
|
||||
int rc;
|
||||
|
||||
ssh_event event = ssh_event_new();
|
||||
|
||||
/* stdin */
|
||||
connector_in = ssh_connector_new(session);
|
||||
ssh_connector_set_out_channel(connector_in, channel, SSH_CONNECTOR_STDINOUT);
|
||||
ssh_connector_set_out_channel(connector_in, channel, SSH_CONNECTOR_STDOUT);
|
||||
ssh_connector_set_in_fd(connector_in, 0);
|
||||
ssh_event_add_connector(event, connector_in);
|
||||
|
||||
/* stdout */
|
||||
connector_out = ssh_connector_new(session);
|
||||
ssh_connector_set_out_fd(connector_out, 1);
|
||||
ssh_connector_set_in_channel(connector_out, channel, SSH_CONNECTOR_STDINOUT);
|
||||
ssh_connector_set_in_channel(connector_out, channel, SSH_CONNECTOR_STDOUT);
|
||||
ssh_event_add_connector(event, connector_out);
|
||||
|
||||
/* stderr */
|
||||
@@ -224,11 +222,7 @@ static void select_loop(ssh_session session,ssh_channel channel)
|
||||
if (signal_delayed) {
|
||||
sizechanged();
|
||||
}
|
||||
rc = ssh_event_dopoll(event, 60000);
|
||||
if (rc == SSH_ERROR) {
|
||||
fprintf(stderr, "Error in ssh_event_dopoll()\n");
|
||||
break;
|
||||
}
|
||||
ssh_event_dopoll(event, 60000);
|
||||
}
|
||||
ssh_event_remove_connector(event, connector_in);
|
||||
ssh_event_remove_connector(event, connector_out);
|
||||
@@ -239,6 +233,7 @@ static void select_loop(ssh_session session,ssh_channel channel)
|
||||
ssh_connector_free(connector_err);
|
||||
|
||||
ssh_event_free(event);
|
||||
ssh_channel_free(channel);
|
||||
}
|
||||
|
||||
static void shell(ssh_session session)
|
||||
@@ -246,11 +241,7 @@ static void shell(ssh_session session)
|
||||
ssh_channel channel;
|
||||
struct termios terminal_local;
|
||||
int interactive=isatty(0);
|
||||
|
||||
channel = ssh_channel_new(session);
|
||||
if (channel == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (interactive) {
|
||||
tcgetattr(0, &terminal_local);
|
||||
@@ -259,7 +250,6 @@ static void shell(ssh_session session)
|
||||
|
||||
if (ssh_channel_open_session(channel)) {
|
||||
printf("Error opening channel : %s\n", ssh_get_error(session));
|
||||
ssh_channel_free(channel);
|
||||
return;
|
||||
}
|
||||
chan = channel;
|
||||
@@ -270,7 +260,6 @@ static void shell(ssh_session session)
|
||||
|
||||
if (ssh_channel_request_shell(channel)) {
|
||||
printf("Requesting shell : %s\n", ssh_get_error(session));
|
||||
ssh_channel_free(channel);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -284,7 +273,6 @@ static void shell(ssh_session session)
|
||||
if (interactive) {
|
||||
do_cleanup(0);
|
||||
}
|
||||
ssh_channel_free(channel);
|
||||
}
|
||||
|
||||
static void batch_shell(ssh_session session)
|
||||
@@ -301,18 +289,12 @@ static void batch_shell(ssh_session session)
|
||||
}
|
||||
|
||||
channel = ssh_channel_new(session);
|
||||
if (channel == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ssh_channel_open_session(channel);
|
||||
if (ssh_channel_request_exec(channel, buffer)) {
|
||||
printf("Error executing '%s' : %s\n", buffer, ssh_get_error(session));
|
||||
ssh_channel_free(channel);
|
||||
return;
|
||||
}
|
||||
select_loop(session, channel);
|
||||
ssh_channel_free(channel);
|
||||
}
|
||||
|
||||
static int client(ssh_session session)
|
||||
|
||||
@@ -37,7 +37,6 @@ The goal is to show the API in action.
|
||||
#endif
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef KEYS_FOLDER
|
||||
@@ -70,11 +69,8 @@ static void set_default_keys(ssh_bind sshbind,
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_ECDSAKEY,
|
||||
KEYS_FOLDER "ssh_host_ecdsa_key");
|
||||
}
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY,
|
||||
KEYS_FOLDER "ssh_host_ed25519_key");
|
||||
}
|
||||
#define DEF_STR_SIZE 1024
|
||||
char authorizedkeys[DEF_STR_SIZE] = {0};
|
||||
|
||||
#ifdef HAVE_ARGP_H
|
||||
const char *argp_program_version = "libssh server example "
|
||||
SSH_STRINGIFY(LIBSSH_VERSION);
|
||||
@@ -129,14 +125,6 @@ static struct argp_option options[] = {
|
||||
.doc = "Set the ecdsa key.",
|
||||
.group = 0
|
||||
},
|
||||
{
|
||||
.name = "authorizedkeys",
|
||||
.key = 'a',
|
||||
.arg = "FILE",
|
||||
.flags = 0,
|
||||
.doc = "Set the authorized keys file.",
|
||||
.group = 0
|
||||
},
|
||||
{
|
||||
.name = "no-default-keys",
|
||||
.key = 'n',
|
||||
@@ -190,9 +178,6 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) {
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_ECDSAKEY, arg);
|
||||
ecdsa_already_set = 1;
|
||||
break;
|
||||
case 'a':
|
||||
strncpy(authorizedkeys, arg, DEF_STR_SIZE-1);
|
||||
break;
|
||||
case 'v':
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR,
|
||||
"3");
|
||||
@@ -449,53 +434,6 @@ static int auth_password(ssh_session session, const char *user,
|
||||
return SSH_AUTH_DENIED;
|
||||
}
|
||||
|
||||
static int auth_publickey(ssh_session session,
|
||||
const char *user,
|
||||
struct ssh_key_struct *pubkey,
|
||||
char signature_state,
|
||||
void *userdata)
|
||||
{
|
||||
struct session_data_struct *sdata = (struct session_data_struct *) userdata;
|
||||
|
||||
(void) user;
|
||||
(void) session;
|
||||
|
||||
if (signature_state == SSH_PUBLICKEY_STATE_NONE) {
|
||||
return SSH_AUTH_SUCCESS;
|
||||
}
|
||||
|
||||
if (signature_state != SSH_PUBLICKEY_STATE_VALID) {
|
||||
return SSH_AUTH_DENIED;
|
||||
}
|
||||
|
||||
// valid so far. Now look through authorized keys for a match
|
||||
if (authorizedkeys[0]) {
|
||||
ssh_key key = NULL;
|
||||
int result;
|
||||
struct stat buf;
|
||||
|
||||
if (stat(authorizedkeys, &buf) == 0) {
|
||||
result = ssh_pki_import_pubkey_file( authorizedkeys, &key );
|
||||
if ((result != SSH_OK) || (key==NULL)) {
|
||||
fprintf(stderr,
|
||||
"Unable to import public key file %s\n",
|
||||
authorizedkeys);
|
||||
} else {
|
||||
result = ssh_key_cmp( key, pubkey, SSH_KEY_CMP_PUBLIC );
|
||||
ssh_key_free(key);
|
||||
if (result == 0) {
|
||||
sdata->authenticated = 1;
|
||||
return SSH_AUTH_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no matches
|
||||
sdata->authenticated = 0;
|
||||
return SSH_AUTH_DENIED;
|
||||
}
|
||||
|
||||
static ssh_channel channel_open(ssh_session session, void *userdata) {
|
||||
struct session_data_struct *sdata = (struct session_data_struct *) userdata;
|
||||
|
||||
@@ -580,12 +518,6 @@ static void handle_session(ssh_event event, ssh_session session) {
|
||||
.channel_open_request_session_function = channel_open,
|
||||
};
|
||||
|
||||
if (authorizedkeys[0]) {
|
||||
server_cb.auth_pubkey_function = auth_publickey;
|
||||
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_PUBLICKEY);
|
||||
} else
|
||||
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD);
|
||||
|
||||
ssh_callbacks_init(&server_cb);
|
||||
ssh_callbacks_init(&channel_cb);
|
||||
|
||||
@@ -596,6 +528,7 @@ static void handle_session(ssh_event event, ssh_session session) {
|
||||
return;
|
||||
}
|
||||
|
||||
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD);
|
||||
ssh_event_add_session(event, session);
|
||||
|
||||
n = 0;
|
||||
|
||||
@@ -1,654 +0,0 @@
|
||||
/* This is a sample implementation of a libssh based SSH server */
|
||||
/*
|
||||
Copyright 2003-2009 Aris Adamantiadis
|
||||
Copyright 2018 T. Wimmer
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
Example:
|
||||
./sshd_direct-tcpip -v -p 2022 -d serverkey.dsa -r serverkey.rsa 127.0.0.1
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
#include <libssh/server.h>
|
||||
#include <libssh/callbacks.h>
|
||||
#include <libssh/channels.h>
|
||||
|
||||
#ifdef HAVE_ARGP_H
|
||||
#include <argp.h>
|
||||
#endif
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <poll.h>
|
||||
|
||||
#ifndef KEYS_FOLDER
|
||||
#ifdef _WIN32
|
||||
#define KEYS_FOLDER
|
||||
#else
|
||||
#define KEYS_FOLDER "/etc/ssh/"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define USER "user"
|
||||
#define PASSWORD "pwd"
|
||||
|
||||
struct event_fd_data_struct {
|
||||
int *p_fd;
|
||||
ssh_channel channel;
|
||||
struct ssh_channel_callbacks_struct *cb_chan;
|
||||
int stacked;
|
||||
};
|
||||
|
||||
struct cleanup_node_struct {
|
||||
struct event_fd_data_struct *data;
|
||||
struct cleanup_node_struct *next;
|
||||
};
|
||||
|
||||
static bool authenticated = false;
|
||||
static int tries = 0;
|
||||
static bool error_set = false;
|
||||
static int sockets_cnt = 0;
|
||||
static ssh_event mainloop = NULL;
|
||||
static struct cleanup_node_struct *cleanup_stack = NULL;
|
||||
|
||||
static void _close_socket(struct event_fd_data_struct event_fd_data);
|
||||
|
||||
static void cleanup_push(struct cleanup_node_struct** head_ref, struct event_fd_data_struct *new_data) {
|
||||
// Allocate memory for node
|
||||
struct cleanup_node_struct *new_node = malloc(sizeof *new_node);
|
||||
|
||||
new_node->next = (*head_ref);
|
||||
|
||||
// Copy new_data
|
||||
new_node->data = new_data;
|
||||
|
||||
// Change head pointer as new node is added at the beginning
|
||||
(*head_ref) = new_node;
|
||||
}
|
||||
|
||||
static void do_cleanup(struct cleanup_node_struct **head_ref) {
|
||||
struct cleanup_node_struct *current = (*head_ref);
|
||||
struct cleanup_node_struct *previous = NULL, *gone = NULL;
|
||||
|
||||
while (current != NULL) {
|
||||
if (ssh_channel_is_closed(current->data->channel)) {
|
||||
if (current == (*head_ref)) {
|
||||
(*head_ref) = current->next;
|
||||
}
|
||||
if (previous != NULL) {
|
||||
previous->next = current->next;
|
||||
}
|
||||
gone = current;
|
||||
current = current->next;
|
||||
|
||||
if (gone->data->channel) {
|
||||
_close_socket(*gone->data);
|
||||
ssh_remove_channel_callbacks(gone->data->channel, gone->data->cb_chan);
|
||||
ssh_channel_free(gone->data->channel);
|
||||
gone->data->channel = NULL;
|
||||
|
||||
SAFE_FREE(gone->data->p_fd);
|
||||
SAFE_FREE(gone->data->cb_chan);
|
||||
SAFE_FREE(gone->data);
|
||||
SAFE_FREE(gone);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "channel already freed!\n");
|
||||
}
|
||||
_ssh_log(SSH_LOG_FUNCTIONS, "=== do_cleanup", "Freed.");
|
||||
}
|
||||
else {
|
||||
ssh_channel_close(current->data->channel);
|
||||
previous = current;
|
||||
current = current->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int auth_password(ssh_session session, const char *user,
|
||||
const char *password, void *userdata) {
|
||||
(void)userdata;
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== auth_password", "Authenticating user %s pwd %s",user, password);
|
||||
if (strcmp(user,USER) == 0 && strcmp(password, PASSWORD) == 0){
|
||||
authenticated = true;
|
||||
printf("Authenticated\n");
|
||||
return SSH_AUTH_SUCCESS;
|
||||
}
|
||||
if (tries >= 3){
|
||||
printf("Too many authentication tries\n");
|
||||
ssh_disconnect(session);
|
||||
error_set = true;
|
||||
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 = true;
|
||||
return SSH_AUTH_SUCCESS;
|
||||
}
|
||||
|
||||
static int subsystem_request(ssh_session session, ssh_channel channel, const char *subsystem, void *userdata) {
|
||||
(void)session;
|
||||
(void)channel;
|
||||
//(void)subsystem;
|
||||
(void)userdata;
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== subsystem_request", "Channel subsystem reqeuest: %s", subsystem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ssh_channel_callbacks_struct channel_cb = {
|
||||
.channel_subsystem_request_function = subsystem_request
|
||||
};
|
||||
|
||||
static ssh_channel new_session_channel(ssh_session session, void *userdata) {
|
||||
(void)session;
|
||||
(void)userdata;
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== subsystem_request", "Session channel request");
|
||||
/* For TCP forward only there seems to be no need for a session channel */
|
||||
/*if(chan != NULL)
|
||||
return NULL;
|
||||
printf("Session channel request\n");
|
||||
chan = ssh_channel_new(session);
|
||||
ssh_callbacks_init(&channel_cb);
|
||||
ssh_set_channel_callbacks(chan, &channel_cb);
|
||||
return chan;*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void stack_socket_close(UNUSED_PARAM(ssh_session session),
|
||||
struct event_fd_data_struct *event_fd_data)
|
||||
{
|
||||
if (event_fd_data->stacked != 1) {
|
||||
_ssh_log(SSH_LOG_FUNCTIONS, "=== stack_socket_close", "Closing fd = %d sockets_cnt = %d", *event_fd_data->p_fd, sockets_cnt);
|
||||
event_fd_data->stacked = 1;
|
||||
cleanup_push(&cleanup_stack, event_fd_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void _close_socket(struct event_fd_data_struct event_fd_data) {
|
||||
_ssh_log(SSH_LOG_FUNCTIONS, "=== close_socket", "Closing fd = %d sockets_cnt = %d", *event_fd_data.p_fd, sockets_cnt);
|
||||
ssh_event_remove_fd(mainloop, *event_fd_data.p_fd);
|
||||
sockets_cnt--;
|
||||
#ifdef _WIN32
|
||||
closesocket(*event_fd_data.p_fd);
|
||||
#else
|
||||
close(*event_fd_data.p_fd);
|
||||
#endif // _WIN32
|
||||
(*event_fd_data.p_fd) = SSH_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
static int service_request(ssh_session session, const char *service, void *userdata) {
|
||||
(void)session;
|
||||
//(void)service;
|
||||
(void)userdata;
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== service_request", "Service request: %s", service);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void global_request(ssh_session session, ssh_message message, void *userdata) {
|
||||
(void)session;
|
||||
(void)userdata;
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== global_request", "Global request, message type: %d", ssh_message_type(message));
|
||||
}
|
||||
|
||||
static void my_channel_close_function(ssh_session session, ssh_channel channel, void *userdata) {
|
||||
struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata;
|
||||
(void)session;
|
||||
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== my_channel_close_function", "Channel %d:%d closed by remote. State=%d", channel->local_channel, channel->remote_channel, channel->state);
|
||||
|
||||
stack_socket_close(session, event_fd_data);
|
||||
}
|
||||
|
||||
static void my_channel_eof_function(ssh_session session, ssh_channel channel, void *userdata) {
|
||||
struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata;
|
||||
(void)session;
|
||||
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== my_channel_eof_function", "Got EOF on channel %d:%d. Shuting down write on socket (fd = %d).", channel->local_channel, channel->remote_channel, *event_fd_data->p_fd);
|
||||
|
||||
stack_socket_close(session, event_fd_data);
|
||||
}
|
||||
|
||||
static void my_channel_exit_status_function(ssh_session session, ssh_channel channel, int exit_status, void *userdata) {
|
||||
struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata;
|
||||
(void)session;
|
||||
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== my_channel_exit_status_function", "Got exit status %d on channel %d:%d fd = %d.", exit_status, channel->local_channel, channel->remote_channel, *event_fd_data->p_fd);
|
||||
}
|
||||
|
||||
static int my_channel_data_function(ssh_session session,
|
||||
ssh_channel channel,
|
||||
void *data,
|
||||
uint32_t len,
|
||||
UNUSED_PARAM(int is_stderr),
|
||||
void *userdata)
|
||||
{
|
||||
int i = 0;
|
||||
struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata;
|
||||
|
||||
if (event_fd_data->channel == NULL) {
|
||||
fprintf(stderr, "Why we're here? Stacked = %d\n", event_fd_data->stacked);
|
||||
}
|
||||
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== my_channel_data_function", "%d bytes waiting on channel %d:%d for reading. Fd = %d",len, channel->local_channel, channel->remote_channel, *event_fd_data->p_fd);
|
||||
if (len > 0) {
|
||||
i = send(*event_fd_data->p_fd, data, len, 0);
|
||||
}
|
||||
if (i < 0) {
|
||||
_ssh_log(SSH_LOG_WARNING, "=== my_channel_data_function", "Writing to tcp socket %d: %s", *event_fd_data->p_fd, strerror(errno));
|
||||
stack_socket_close(session, event_fd_data);
|
||||
}
|
||||
else {
|
||||
_ssh_log(SSH_LOG_FUNCTIONS, "=== my_channel_data_function", "Sent %d bytes", i);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int my_fd_data_function(UNUSED_PARAM(socket_t fd),
|
||||
int revents,
|
||||
void *userdata)
|
||||
{
|
||||
struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata;
|
||||
ssh_channel channel = event_fd_data->channel;
|
||||
ssh_session session;
|
||||
int len, i, wr;
|
||||
char buf[16384];
|
||||
int blocking;
|
||||
|
||||
if (channel == NULL) {
|
||||
_ssh_log(SSH_LOG_FUNCTIONS, "=== my_fd_data_function", "channel == NULL!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
session = ssh_channel_get_session(channel);
|
||||
|
||||
if (ssh_channel_is_closed(channel)) {
|
||||
_ssh_log(SSH_LOG_FUNCTIONS, "=== my_fd_data_function", "channel is closed!");
|
||||
stack_socket_close(session, event_fd_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(revents & POLLIN)) {
|
||||
if (revents & POLLPRI) {
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLPRI");
|
||||
}
|
||||
if (revents & POLLOUT) {
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLOUT");
|
||||
}
|
||||
if (revents & POLLHUP) {
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLHUP");
|
||||
}
|
||||
if (revents & POLLNVAL) {
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLNVAL");
|
||||
}
|
||||
if (revents & POLLERR) {
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLERR");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
blocking = ssh_is_blocking(session);
|
||||
ssh_set_blocking(session, 0);
|
||||
|
||||
_ssh_log(SSH_LOG_FUNCTIONS, "=== my_fd_data_function", "Trying to read from tcp socket fd = %d... (Channel %d:%d state=%d)",
|
||||
*event_fd_data->p_fd, channel->local_channel, channel->remote_channel, channel->state);
|
||||
#ifdef _WIN32
|
||||
struct sockaddr from;
|
||||
int fromlen = sizeof(from);
|
||||
len = recvfrom(*event_fd_data->p_fd, buf, sizeof(buf), 0, &from, &fromlen);
|
||||
#else
|
||||
len = recv(*event_fd_data->p_fd, buf, sizeof(buf), 0);
|
||||
#endif // _WIN32
|
||||
if (len < 0) {
|
||||
_ssh_log(SSH_LOG_WARNING, "=== my_fd_data_function", "Reading from tcp socket: %s", strerror(errno));
|
||||
|
||||
ssh_channel_send_eof(channel);
|
||||
}
|
||||
else if (len > 0) {
|
||||
if (ssh_channel_is_open(channel)) {
|
||||
wr = 0;
|
||||
do {
|
||||
i = ssh_channel_write(channel, buf, len);
|
||||
if (i < 0) {
|
||||
_ssh_log(SSH_LOG_WARNING, "=== my_fd_data_function", "Error writing on the direct-tcpip channel: %d", i);
|
||||
len = wr;
|
||||
break;
|
||||
}
|
||||
wr += i;
|
||||
_ssh_log(SSH_LOG_FUNCTIONS, "=== my_fd_data_function", "channel_write (%d from %d)", wr, len);
|
||||
} while (i > 0 && wr < len);
|
||||
}
|
||||
else {
|
||||
_ssh_log(SSH_LOG_WARNING, "=== my_fd_data_function", "Can't write on closed channel!");
|
||||
}
|
||||
}
|
||||
else {
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "The destination host has disconnected!");
|
||||
|
||||
ssh_channel_close(channel);
|
||||
#ifdef _WIN32
|
||||
shutdown(*event_fd_data->p_fd, SD_RECEIVE);
|
||||
#else
|
||||
shutdown(*event_fd_data->p_fd, SHUT_RD);
|
||||
#endif // _WIN32
|
||||
}
|
||||
ssh_set_blocking(session, blocking);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int open_tcp_socket(ssh_message msg) {
|
||||
struct sockaddr_in sin;
|
||||
int forwardsock = -1;
|
||||
struct hostent *host;
|
||||
const char *dest_hostname;
|
||||
int dest_port;
|
||||
|
||||
forwardsock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (forwardsock < 0) {
|
||||
_ssh_log(SSH_LOG_WARNING, "=== open_tcp_socket", "ERROR opening socket: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
dest_hostname = ssh_message_channel_request_open_destination(msg);
|
||||
dest_port = ssh_message_channel_request_open_destination_port(msg);
|
||||
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== open_tcp_socket", "Connecting to %s on port %d", dest_hostname, dest_port);
|
||||
|
||||
host = gethostbyname(dest_hostname);
|
||||
if (host == NULL) {
|
||||
close(forwardsock);
|
||||
_ssh_log(SSH_LOG_WARNING, "=== open_tcp_socket", "ERROR, no such host: %s", dest_hostname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset((char *)&sin, '\0', sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
memcpy((char *)&sin.sin_addr.s_addr, (char *)host->h_addr, host->h_length);
|
||||
sin.sin_port = htons(dest_port);
|
||||
|
||||
if (connect(forwardsock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
|
||||
close(forwardsock);
|
||||
_ssh_log(SSH_LOG_WARNING, "=== open_tcp_socket", "ERROR connecting: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
sockets_cnt++;
|
||||
_ssh_log(SSH_LOG_FUNCTIONS, "=== open_tcp_socket", "Connected. sockets_cnt = %d", sockets_cnt);
|
||||
return forwardsock;
|
||||
}
|
||||
|
||||
static int message_callback(ssh_session session, ssh_message message, void *userdata) {
|
||||
ssh_channel channel;
|
||||
int socket_fd, *pFd;
|
||||
struct ssh_channel_callbacks_struct *cb_chan;
|
||||
struct event_fd_data_struct *event_fd_data;
|
||||
(void)session;
|
||||
(void)message;
|
||||
(void)userdata;
|
||||
|
||||
_ssh_log(SSH_LOG_PACKET, "=== message_callback", "Message type: %d", ssh_message_type(message));
|
||||
_ssh_log(SSH_LOG_PACKET, "=== message_callback", "Message Subtype: %d", ssh_message_subtype(message));
|
||||
if (ssh_message_type(message) == SSH_REQUEST_CHANNEL_OPEN) {
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== message_callback", "channel_request_open");
|
||||
|
||||
if (ssh_message_subtype(message) == SSH_CHANNEL_DIRECT_TCPIP) {
|
||||
channel = ssh_message_channel_request_open_reply_accept(message);
|
||||
|
||||
if (channel == NULL) {
|
||||
_ssh_log(SSH_LOG_WARNING, "=== message_callback", "Accepting direct-tcpip channel failed!");
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== message_callback", "Connected to channel!");
|
||||
|
||||
socket_fd = open_tcp_socket(message);
|
||||
if (-1 == socket_fd) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
pFd = malloc(sizeof *pFd);
|
||||
cb_chan = malloc(sizeof *cb_chan);
|
||||
event_fd_data = malloc(sizeof *event_fd_data);
|
||||
|
||||
(*pFd) = socket_fd;
|
||||
event_fd_data->channel = channel;
|
||||
event_fd_data->p_fd = pFd;
|
||||
event_fd_data->stacked = 0;
|
||||
event_fd_data->cb_chan = cb_chan;
|
||||
|
||||
cb_chan->userdata = event_fd_data;
|
||||
cb_chan->channel_eof_function = my_channel_eof_function;
|
||||
cb_chan->channel_close_function = my_channel_close_function;
|
||||
cb_chan->channel_data_function = my_channel_data_function;
|
||||
cb_chan->channel_exit_status_function = my_channel_exit_status_function;
|
||||
|
||||
ssh_callbacks_init(cb_chan);
|
||||
ssh_set_channel_callbacks(channel, cb_chan);
|
||||
|
||||
ssh_event_add_fd(mainloop, (socket_t)*pFd, POLLIN, my_fd_data_function, event_fd_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#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, "1");
|
||||
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;
|
||||
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,
|
||||
.service_request_function = service_request
|
||||
};
|
||||
struct ssh_callbacks_struct cb_gen = {
|
||||
.userdata = NULL,
|
||||
.global_request_function = global_request
|
||||
};
|
||||
|
||||
int ret = 1;
|
||||
|
||||
sshbind = ssh_bind_new();
|
||||
session = ssh_new();
|
||||
mainloop = ssh_event_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;
|
||||
}
|
||||
|
||||
if (ssh_bind_accept(sshbind, session) == SSH_ERROR) {
|
||||
printf("error accepting a connection : %s\n", ssh_get_error(sshbind));
|
||||
ret = 1;
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
ssh_callbacks_init(&cb);
|
||||
ssh_callbacks_init(&cb_gen);
|
||||
ssh_set_server_callbacks(session, &cb);
|
||||
ssh_set_callbacks(session, &cb_gen);
|
||||
ssh_set_message_callback(session, message_callback, (void *)NULL);
|
||||
|
||||
if (ssh_handle_key_exchange(session)) {
|
||||
printf("ssh_handle_key_exchange: %s\n", ssh_get_error(session));
|
||||
ret = 1;
|
||||
goto shutdown;
|
||||
}
|
||||
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_GSSAPI_MIC);
|
||||
ssh_event_add_session(mainloop, session);
|
||||
|
||||
while (!authenticated) {
|
||||
if (error_set) {
|
||||
break;
|
||||
}
|
||||
if (ssh_event_dopoll(mainloop, -1) == SSH_ERROR) {
|
||||
printf("Error : %s\n", ssh_get_error(session));
|
||||
ret = 1;
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
if (error_set) {
|
||||
printf("Error, exiting loop\n");
|
||||
} else {
|
||||
printf("Authenticated and got a channel\n");
|
||||
|
||||
while (!error_set) {
|
||||
if (ssh_event_dopoll(mainloop, 100) == SSH_ERROR) {
|
||||
printf("Error : %s\n", ssh_get_error(session));
|
||||
ret = 1;
|
||||
goto shutdown;
|
||||
}
|
||||
do_cleanup(&cleanup_stack);
|
||||
}
|
||||
}
|
||||
|
||||
shutdown:
|
||||
ssh_disconnect(session);
|
||||
ssh_bind_free(sshbind);
|
||||
ssh_finalize();
|
||||
return ret;
|
||||
}
|
||||
@@ -26,7 +26,7 @@ install(
|
||||
FILES
|
||||
${libssh_HDRS}
|
||||
DESTINATION
|
||||
${CMAKE_INSTALL_INCLUDEDIR}/${APPLICATION_NAME}
|
||||
${INCLUDE_INSTALL_DIR}/${APPLICATION_NAME}
|
||||
COMPONENT
|
||||
headers
|
||||
)
|
||||
|
||||
@@ -26,8 +26,9 @@
|
||||
#include "libssh/libmbedcrypto.h"
|
||||
|
||||
bignum ssh_make_string_bn(ssh_string string);
|
||||
void ssh_make_string_bn_inplace(ssh_string string, bignum bnout);
|
||||
ssh_string ssh_make_bignum_string(bignum num);
|
||||
void ssh_print_bignum(const char *which, const_bignum num);
|
||||
void ssh_print_bignum(const char *which, const bignum num);
|
||||
|
||||
|
||||
#endif /* BIGNUM_H_ */
|
||||
|
||||
@@ -46,9 +46,6 @@ struct ssh_bind_struct {
|
||||
unsigned int bindport;
|
||||
int blocking;
|
||||
int toaccept;
|
||||
bool config_processed;
|
||||
char *config_dir;
|
||||
char *pubkey_accepted_key_types;
|
||||
};
|
||||
|
||||
struct ssh_poll_handle_struct *ssh_bind_get_poll(struct ssh_bind_struct
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* bind_config.h - Parse the SSH server configuration file
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2019 by Red Hat, Inc.
|
||||
*
|
||||
* Author: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef BIND_CONFIG_H_
|
||||
#define BIND_CONFIG_H_
|
||||
|
||||
#include "libssh/server.h"
|
||||
|
||||
enum ssh_bind_config_opcode_e {
|
||||
/* Known but not allowed in Match block */
|
||||
BIND_CFG_NOT_ALLOWED_IN_MATCH = -4,
|
||||
/* Unknown opcode */
|
||||
BIND_CFG_UNKNOWN = -3,
|
||||
/* Known and not applicable to libssh */
|
||||
BIND_CFG_NA = -2,
|
||||
/* Known but not supported by current libssh version */
|
||||
BIND_CFG_UNSUPPORTED = -1,
|
||||
BIND_CFG_INCLUDE,
|
||||
BIND_CFG_HOSTKEY,
|
||||
BIND_CFG_LISTENADDRESS,
|
||||
BIND_CFG_PORT,
|
||||
BIND_CFG_LOGLEVEL,
|
||||
BIND_CFG_CIPHERS,
|
||||
BIND_CFG_MACS,
|
||||
BIND_CFG_KEXALGORITHMS,
|
||||
BIND_CFG_MATCH,
|
||||
BIND_CFG_PUBKEY_ACCEPTED_KEY_TYPES,
|
||||
BIND_CFG_HOSTKEY_ALGORITHMS,
|
||||
|
||||
BIND_CFG_MAX /* Keep this one last in the list */
|
||||
};
|
||||
|
||||
/* @brief Parse configuration file and set the options to the given ssh_bind
|
||||
*
|
||||
* @params[in] sshbind The ssh_bind context to be configured
|
||||
* @params[in] filename The path to the configuration file
|
||||
*
|
||||
* @returns 0 on successful parsing the configuration file, -1 on error
|
||||
*/
|
||||
int ssh_bind_config_parse_file(ssh_bind sshbind, const char *filename);
|
||||
|
||||
#endif /* BIND_CONFIG_H_ */
|
||||
@@ -50,11 +50,11 @@ int _ssh_buffer_pack(struct ssh_buffer_struct *buffer,
|
||||
_ssh_buffer_pack((buffer), (format), __VA_NARG__(__VA_ARGS__), __VA_ARGS__, SSH_BUFFER_PACK_END)
|
||||
|
||||
int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
const char *format, size_t argc,
|
||||
const char *format, int argc,
|
||||
va_list ap);
|
||||
int _ssh_buffer_unpack(struct ssh_buffer_struct *buffer,
|
||||
const char *format,
|
||||
size_t argc,
|
||||
int argc,
|
||||
...);
|
||||
#define ssh_buffer_unpack(buffer, format, ...) \
|
||||
_ssh_buffer_unpack((buffer), (format), __VA_NARG__(__VA_ARGS__), __VA_ARGS__, SSH_BUFFER_PACK_END)
|
||||
|
||||
@@ -854,7 +854,7 @@ typedef struct ssh_channel_callbacks_struct *ssh_channel_callbacks;
|
||||
* @code
|
||||
* struct ssh_channel_callbacks_struct cb = {
|
||||
* .userdata = data,
|
||||
* .channel_data_function = my_channel_data_function
|
||||
* .channel_data = my_channel_data_function
|
||||
* };
|
||||
* ssh_callbacks_init(&cb);
|
||||
* ssh_set_channel_callbacks(channel, &cb);
|
||||
@@ -944,20 +944,9 @@ LIBSSH_API int ssh_threads_set_callbacks(struct ssh_threads_callbacks_struct
|
||||
*cb);
|
||||
|
||||
/**
|
||||
* @brief Returns a pointer to the appropriate callbacks structure for the
|
||||
* environment, to be used with ssh_threads_set_callbacks.
|
||||
*
|
||||
* @returns A pointer to a ssh_threads_callbacks_struct to be used with
|
||||
* @brief returns a pointer on the pthread threads callbacks, to be used with
|
||||
* ssh_threads_set_callbacks.
|
||||
*
|
||||
* @see ssh_threads_set_callbacks
|
||||
*/
|
||||
LIBSSH_API struct ssh_threads_callbacks_struct *ssh_threads_get_default(void);
|
||||
|
||||
/**
|
||||
* @brief Returns a pointer on the pthread threads callbacks, to be used with
|
||||
* ssh_threads_set_callbacks.
|
||||
*
|
||||
* @warning you have to link with the library ssh_threads.
|
||||
* @see ssh_threads_set_callbacks
|
||||
*/
|
||||
LIBSSH_API struct ssh_threads_callbacks_struct *ssh_threads_get_pthread(void);
|
||||
|
||||
@@ -48,16 +48,11 @@ enum ssh_channel_state_e {
|
||||
};
|
||||
|
||||
/* The channel has been closed by the remote side */
|
||||
#define SSH_CHANNEL_FLAG_CLOSED_REMOTE 0x0001
|
||||
|
||||
/* The channel has been closed locally */
|
||||
#define SSH_CHANNEL_FLAG_CLOSED_LOCAL 0x0002
|
||||
|
||||
#define SSH_CHANNEL_FLAG_CLOSED_REMOTE 0x1
|
||||
/* The channel has been freed by the calling program */
|
||||
#define SSH_CHANNEL_FLAG_FREED_LOCAL 0x0004
|
||||
|
||||
#define SSH_CHANNEL_FLAG_FREED_LOCAL 0x2
|
||||
/* the channel has not yet been bound to a remote one */
|
||||
#define SSH_CHANNEL_FLAG_NOT_BOUND 0x0008
|
||||
#define SSH_CHANNEL_FLAG_NOT_BOUND 0x4
|
||||
|
||||
struct ssh_channel_struct {
|
||||
ssh_session session; /* SSH_SESSION pointer */
|
||||
|
||||
@@ -46,7 +46,6 @@ enum ssh_config_opcode_e {
|
||||
SOC_STRICTHOSTKEYCHECK,
|
||||
SOC_KNOWNHOSTS,
|
||||
SOC_PROXYCOMMAND,
|
||||
SOC_PROXYJUMP,
|
||||
SOC_GSSAPISERVERIDENTITY,
|
||||
SOC_GSSAPICLIENTIDENTITY,
|
||||
SOC_GSSAPIDELEGATECREDENTIALS,
|
||||
@@ -61,7 +60,6 @@ enum ssh_config_opcode_e {
|
||||
SOC_PASSWORDAUTHENTICATION,
|
||||
SOC_PUBKEYAUTHENTICATION,
|
||||
SOC_PUBKEYACCEPTEDTYPES,
|
||||
SOC_REKEYLIMIT,
|
||||
|
||||
SOC_MAX /* Keep this one last in the list */
|
||||
};
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* config_parser.h - Common configuration file parser functions
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2019 by Red Hat, Inc.
|
||||
*
|
||||
* Author: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_PARSER_H_
|
||||
#define CONFIG_PARSER_H_
|
||||
|
||||
char *ssh_config_get_cmd(char **str);
|
||||
|
||||
char *ssh_config_get_token(char **str);
|
||||
|
||||
long ssh_config_get_long(char **str, long notfound);
|
||||
|
||||
const char *ssh_config_get_str_tok(char **str, const char *def);
|
||||
|
||||
int ssh_config_get_yesno(char **str, int notfound);
|
||||
|
||||
/* @brief Parse SSH URI in format [user@]host[:port] from the given string
|
||||
*
|
||||
* @param[in] tok String to parse
|
||||
* @param[out] username Pointer to the location, where the new username will
|
||||
* be stored or NULL if we do not care about the result.
|
||||
* @param[out] hostname Pointer to the location, where the new hostname will
|
||||
* be stored or NULL if we do not care about the result.
|
||||
* @param[out] port Pointer to the location, where the new port will
|
||||
* be stored or NULL if we do not care about the result.
|
||||
*
|
||||
* @returns SSH_OK if the provided string is in format of SSH URI,
|
||||
* SSH_ERROR on failure
|
||||
*/
|
||||
int ssh_config_parse_uri(const char *tok,
|
||||
char **username,
|
||||
char **hostname,
|
||||
char **port);
|
||||
|
||||
#endif /* LIBSSH_CONFIG_H_ */
|
||||
@@ -25,7 +25,6 @@
|
||||
#ifndef _CRYPTO_H_
|
||||
#define _CRYPTO_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
@@ -45,7 +44,6 @@
|
||||
#ifdef HAVE_OPENSSL_ECDH_H
|
||||
#include <openssl/ecdh.h>
|
||||
#endif
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/ecdh.h"
|
||||
#include "libssh/kex.h"
|
||||
#include "libssh/curve25519.h"
|
||||
@@ -60,12 +58,6 @@ enum ssh_key_exchange_e {
|
||||
SSH_KEX_DH_GROUP1_SHA1=1,
|
||||
/* diffie-hellman-group14-sha1 */
|
||||
SSH_KEX_DH_GROUP14_SHA1,
|
||||
#ifdef WITH_GEX
|
||||
/* diffie-hellman-group-exchange-sha1 */
|
||||
SSH_KEX_DH_GEX_SHA1,
|
||||
/* diffie-hellman-group-exchange-sha256 */
|
||||
SSH_KEX_DH_GEX_SHA256,
|
||||
#endif /* WITH_GEX */
|
||||
/* ecdh-sha2-nistp256 */
|
||||
SSH_KEX_ECDH_SHA2_NISTP256,
|
||||
/* ecdh-sha2-nistp384 */
|
||||
@@ -84,9 +76,7 @@ enum ssh_key_exchange_e {
|
||||
|
||||
enum ssh_cipher_e {
|
||||
SSH_NO_CIPHER=0,
|
||||
#ifdef WITH_BLOWFISH_CIPHER
|
||||
SSH_BLOWFISH_CBC,
|
||||
#endif /* WITH_BLOWFISH_CIPHER */
|
||||
SSH_3DES_CBC,
|
||||
SSH_AES128_CBC,
|
||||
SSH_AES192_CBC,
|
||||
@@ -99,14 +89,8 @@ enum ssh_cipher_e {
|
||||
SSH_AEAD_CHACHA20_POLY1305
|
||||
};
|
||||
|
||||
struct dh_ctx;
|
||||
|
||||
struct ssh_crypto_struct {
|
||||
bignum shared_secret;
|
||||
struct dh_ctx *dh_ctx;
|
||||
#ifdef WITH_GEX
|
||||
size_t dh_pmin; int dh_pn; int dh_pmax; /* preferred group parameters */
|
||||
#endif /* WITH_GEX */
|
||||
bignum e,f,x,k,y;
|
||||
#ifdef HAVE_ECDH
|
||||
#ifdef HAVE_OPENSSL_ECC
|
||||
EC_KEY *ecdh_privkey;
|
||||
@@ -124,7 +108,7 @@ struct ssh_crypto_struct {
|
||||
ssh_curve25519_pubkey curve25519_server_pubkey;
|
||||
#endif
|
||||
ssh_string dh_server_signature; /* information used by dh_handshake. */
|
||||
size_t digest_len; /* len of the two fields below */
|
||||
size_t digest_len; /* len of all the fields below */
|
||||
unsigned char *session_id;
|
||||
unsigned char *secret_hash; /* Secret hash is same as session id until re-kex */
|
||||
unsigned char *encryptIV;
|
||||
@@ -136,7 +120,6 @@ struct ssh_crypto_struct {
|
||||
unsigned char hmacbuf[DIGEST_MAX_LEN];
|
||||
struct ssh_cipher_struct *in_cipher, *out_cipher; /* the cipher structures/objects */
|
||||
enum ssh_hmac_e in_hmac, out_hmac; /* the MAC algorithms used */
|
||||
bool in_hmac_etm, out_hmac_etm; /* Whether EtM mode is used or not */
|
||||
|
||||
ssh_key server_pubkey;
|
||||
int do_compress_out; /* idem */
|
||||
@@ -150,8 +133,7 @@ struct ssh_crypto_struct {
|
||||
struct ssh_kex_struct client_kex;
|
||||
char *kex_methods[SSH_KEX_METHODS];
|
||||
enum ssh_key_exchange_e kex_type;
|
||||
enum ssh_kdf_digest digest_type; /* Digest type for session keys derivation */
|
||||
enum ssh_crypto_direction_e used; /* Is this crypto still used for either of directions? */
|
||||
enum ssh_mac_e mac_type; /* Mac operations to use for key gen */
|
||||
};
|
||||
|
||||
struct ssh_cipher_struct {
|
||||
@@ -180,11 +162,6 @@ struct ssh_cipher_struct {
|
||||
struct chacha20_poly1305_keysched *chacha20_schedule;
|
||||
unsigned int keysize; /* bytes of key used. != keylen */
|
||||
size_t tag_size; /* overhead required for tag */
|
||||
/* Counters for rekeying initialization */
|
||||
uint32_t packets;
|
||||
uint64_t blocks;
|
||||
/* Rekeying limit for the cipher or manually enforced */
|
||||
uint64_t max_blocks;
|
||||
/* sets the new key for immediate use */
|
||||
int (*set_encrypt_key)(struct ssh_cipher_struct *cipher, void *key, void *IV);
|
||||
int (*set_decrypt_key)(struct ssh_cipher_struct *cipher, void *key, void *IV);
|
||||
@@ -206,9 +183,5 @@ struct ssh_cipher_struct {
|
||||
};
|
||||
|
||||
const struct ssh_cipher_struct *ssh_get_chacha20poly1305_cipher(void);
|
||||
int sshkdf_derive_key(struct ssh_crypto_struct *crypto,
|
||||
unsigned char *key, size_t key_len,
|
||||
int key_type, unsigned char *output,
|
||||
size_t requested_len);
|
||||
|
||||
#endif /* _CRYPTO_H_ */
|
||||
|
||||
@@ -48,9 +48,10 @@ typedef unsigned char ssh_curve25519_privkey[CURVE25519_PRIVKEY_SIZE];
|
||||
|
||||
|
||||
int ssh_client_curve25519_init(ssh_session session);
|
||||
int ssh_client_curve25519_reply(ssh_session session, ssh_buffer packet);
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
void ssh_server_curve25519_init(ssh_session session);
|
||||
int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet);
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
#endif /* CURVE25519_H_ */
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2016 by Aris Adamantiadis <aris@0xbadc0de.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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SRC_DH_GEX_H_
|
||||
#define SRC_DH_GEX_H_
|
||||
|
||||
int ssh_client_dhgex_init(ssh_session session);
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
void ssh_server_dhgex_init(ssh_session session);
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
#endif /* SRC_DH_GEX_H_ */
|
||||
@@ -25,37 +25,25 @@
|
||||
|
||||
#include "libssh/crypto.h"
|
||||
|
||||
struct dh_ctx;
|
||||
int ssh_dh_generate_e(ssh_session session);
|
||||
int ssh_dh_generate_f(ssh_session session);
|
||||
int ssh_dh_generate_x(ssh_session session);
|
||||
int ssh_dh_generate_y(ssh_session session);
|
||||
|
||||
#define DH_CLIENT_KEYPAIR 0
|
||||
#define DH_SERVER_KEYPAIR 1
|
||||
|
||||
/* functions implemented by crypto backends */
|
||||
int ssh_dh_init_common(struct ssh_crypto_struct *crypto);
|
||||
void ssh_dh_cleanup(struct ssh_crypto_struct *crypto);
|
||||
|
||||
int ssh_dh_get_parameters(struct dh_ctx *ctx,
|
||||
const_bignum *modulus, const_bignum *generator);
|
||||
int ssh_dh_set_parameters(struct dh_ctx *ctx,
|
||||
const bignum modulus, const bignum generator);
|
||||
|
||||
int ssh_dh_keypair_gen_keys(struct dh_ctx *ctx, int peer);
|
||||
int ssh_dh_keypair_get_keys(struct dh_ctx *ctx, int peer,
|
||||
const_bignum *priv, const_bignum *pub);
|
||||
int ssh_dh_keypair_set_keys(struct dh_ctx *ctx, int peer,
|
||||
const bignum priv, const bignum pub);
|
||||
|
||||
int ssh_dh_compute_shared_secret(struct dh_ctx *ctx, int local, int remote,
|
||||
bignum *dest);
|
||||
|
||||
void ssh_dh_debug_crypto(struct ssh_crypto_struct *c);
|
||||
|
||||
/* common functions */
|
||||
int ssh_dh_init(void);
|
||||
void ssh_dh_finalize(void);
|
||||
|
||||
int ssh_dh_import_next_pubkey_blob(ssh_session session,
|
||||
ssh_string pubkey_blob);
|
||||
ssh_string ssh_dh_get_e(ssh_session session);
|
||||
ssh_string ssh_dh_get_f(ssh_session session);
|
||||
int ssh_dh_import_f(ssh_session session,ssh_string f_string);
|
||||
int ssh_dh_import_e(ssh_session session, ssh_string e_string);
|
||||
|
||||
int ssh_dh_import_pubkey_blob(ssh_session session, ssh_string pubkey_blob);
|
||||
int ssh_dh_import_next_pubkey_blob(ssh_session session, ssh_string pubkey_blob);
|
||||
|
||||
int ssh_dh_build_k(ssh_session session);
|
||||
int ssh_client_dh_init(ssh_session session);
|
||||
int ssh_client_dh_reply(ssh_session session, ssh_buffer packet);
|
||||
|
||||
ssh_key ssh_dh_get_current_server_publickey(ssh_session session);
|
||||
int ssh_dh_get_current_server_publickey_blob(ssh_session session,
|
||||
@@ -64,12 +52,10 @@ ssh_key ssh_dh_get_next_server_publickey(ssh_session session);
|
||||
int ssh_dh_get_next_server_publickey_blob(ssh_session session,
|
||||
ssh_string *pubkey_blob);
|
||||
|
||||
int ssh_client_dh_init(ssh_session session);
|
||||
#ifdef WITH_SERVER
|
||||
void ssh_server_dh_init(ssh_session session);
|
||||
#endif /* WITH_SERVER */
|
||||
int ssh_server_dh_process_init(ssh_session session, ssh_buffer packet);
|
||||
int ssh_fallback_group(uint32_t pmax, bignum *p, bignum *g);
|
||||
bool ssh_dh_is_known_group(bignum modulus, bignum generator);
|
||||
int ssh_make_sessionid(ssh_session session);
|
||||
/* add data for the final cookie */
|
||||
int ssh_hashbufin_add_cookie(ssh_session session, unsigned char *cookie);
|
||||
int ssh_hashbufout_add_cookie(ssh_session session);
|
||||
int ssh_generate_session_keys(ssh_session session);
|
||||
|
||||
#endif /* DH_H_ */
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#define ECDH_H_
|
||||
|
||||
#include "config.h"
|
||||
#include "libssh/callbacks.h"
|
||||
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
#ifdef HAVE_OPENSSL_ECDH_H
|
||||
@@ -42,15 +41,15 @@
|
||||
#define HAVE_ECDH 1
|
||||
#endif
|
||||
|
||||
extern struct ssh_packet_callbacks_struct ssh_ecdh_client_callbacks;
|
||||
/* Common functions. */
|
||||
int ssh_client_ecdh_reply(ssh_session session, ssh_buffer packet);
|
||||
|
||||
/* Backend-specific functions. */
|
||||
int ssh_client_ecdh_init(ssh_session session);
|
||||
int ecdh_build_k(ssh_session session);
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
extern struct ssh_packet_callbacks_struct ssh_ecdh_server_callbacks;
|
||||
void ssh_server_ecdh_init(ssh_session session);
|
||||
SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init);
|
||||
int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet);
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
#endif /* ECDH_H_ */
|
||||
|
||||
@@ -56,8 +56,8 @@ int crypto_sign_ed25519_keypair(ed25519_pubkey pk, ed25519_privkey sk);
|
||||
* @return 0 on success.
|
||||
*/
|
||||
int crypto_sign_ed25519(
|
||||
unsigned char *sm, uint64_t *smlen,
|
||||
const unsigned char *m, uint64_t mlen,
|
||||
unsigned char *sm,unsigned long long *smlen,
|
||||
const unsigned char *m,unsigned long long mlen,
|
||||
const ed25519_privkey sk);
|
||||
|
||||
/** @internal
|
||||
@@ -71,8 +71,8 @@ int crypto_sign_ed25519(
|
||||
* @returns 0 on success (supposedly).
|
||||
*/
|
||||
int crypto_sign_ed25519_open(
|
||||
unsigned char *m, uint64_t *mlen,
|
||||
const unsigned char *sm, uint64_t smlen,
|
||||
unsigned char *m,unsigned long long *mlen,
|
||||
const unsigned char *sm,unsigned long long smlen,
|
||||
const ed25519_pubkey pk);
|
||||
|
||||
/** @} */
|
||||
|
||||
@@ -39,21 +39,12 @@ int ssh_set_client_kex(ssh_session session);
|
||||
int ssh_kex_select_methods(ssh_session session);
|
||||
int ssh_verify_existing_algo(enum ssh_kex_types_e algo, const char *name);
|
||||
char *ssh_keep_known_algos(enum ssh_kex_types_e algo, const char *list);
|
||||
char *ssh_keep_fips_algos(enum ssh_kex_types_e algo, const char *list);
|
||||
char **ssh_space_tokenize(const char *chain);
|
||||
int ssh_get_kex1(ssh_session session);
|
||||
char *ssh_find_matching(const char *in_d, const char *what_d);
|
||||
const char *ssh_kex_get_supported_method(uint32_t algo);
|
||||
const char *ssh_kex_get_default_methods(uint32_t algo);
|
||||
const char *ssh_kex_get_fips_methods(uint32_t algo);
|
||||
const char *ssh_kex_get_description(uint32_t algo);
|
||||
char *ssh_client_select_hostkeys(ssh_session session);
|
||||
int ssh_send_rekex(ssh_session session);
|
||||
int server_set_kex(ssh_session session);
|
||||
int ssh_make_sessionid(ssh_session session);
|
||||
/* add data for the final cookie */
|
||||
int ssh_hashbufin_add_cookie(ssh_session session, unsigned char *cookie);
|
||||
int ssh_hashbufout_add_cookie(ssh_session session);
|
||||
int ssh_generate_session_keys(ssh_session session);
|
||||
|
||||
#endif /* KEX_H_ */
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#define SSH_KNOWNHOSTS_H_
|
||||
|
||||
struct ssh_list *ssh_known_hosts_get_algorithms(ssh_session session);
|
||||
char *ssh_known_hosts_get_algorithms_names(ssh_session session);
|
||||
enum ssh_known_hosts_e
|
||||
ssh_session_get_known_hosts_entry_file(ssh_session session,
|
||||
const char *filename,
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
typedef EVP_MD_CTX* SHACTX;
|
||||
typedef EVP_MD_CTX* SHA256CTX;
|
||||
@@ -65,7 +64,6 @@ typedef void *EVPCTX;
|
||||
#define BROKEN_AES_CTR
|
||||
#endif
|
||||
typedef BIGNUM* bignum;
|
||||
typedef const BIGNUM* const_bignum;
|
||||
typedef BN_CTX* bignum_CTX;
|
||||
|
||||
#define bignum_new() BN_new()
|
||||
@@ -76,47 +74,19 @@ typedef BN_CTX* bignum_CTX;
|
||||
} \
|
||||
} while(0)
|
||||
#define bignum_set_word(bn,n) BN_set_word(bn,n)
|
||||
#define bignum_bin2bn(data, datalen, dest) \
|
||||
do { \
|
||||
(*dest) = BN_new(); \
|
||||
if ((*dest) != NULL) { \
|
||||
BN_bin2bn(data,datalen,(*dest)); \
|
||||
} \
|
||||
} while(0)
|
||||
#define bignum_bin2bn(bn,datalen,data) BN_bin2bn(bn,datalen,data)
|
||||
#define bignum_bn2dec(num) BN_bn2dec(num)
|
||||
#define bignum_dec2bn(data, bn) BN_dec2bn(bn, data)
|
||||
#define bignum_hex2bn(data, bn) BN_hex2bn(bn, data)
|
||||
#define bignum_bn2hex(num, dest) (*dest)=(unsigned char *)BN_bn2hex(num)
|
||||
#define bignum_dec2bn(bn,data) BN_dec2bn(data,bn)
|
||||
#define bignum_bn2hex(num) BN_bn2hex(num)
|
||||
#define bignum_rand(rnd, bits) BN_rand(rnd, bits, 0, 1)
|
||||
#define bignum_rand_range(rnd, max) BN_rand_range(rnd, max)
|
||||
#define bignum_ctx_new() BN_CTX_new()
|
||||
#define bignum_ctx_free(num) BN_CTX_free(num)
|
||||
#define bignum_ctx_invalid(ctx) ((ctx) == NULL)
|
||||
#define bignum_mod_exp(dest,generator,exp,modulo,ctx) BN_mod_exp(dest,generator,exp,modulo,ctx)
|
||||
#define bignum_add(dest, a, b) BN_add(dest, a, b)
|
||||
#define bignum_sub(dest, a, b) BN_sub(dest, a, b)
|
||||
#define bignum_mod(dest, a, b, ctx) BN_mod(dest, a, b, ctx)
|
||||
#define bignum_num_bytes(num) BN_num_bytes(num)
|
||||
#define bignum_num_bits(num) BN_num_bits(num)
|
||||
#define bignum_is_bit_set(num,bit) BN_is_bit_set(num,bit)
|
||||
#define bignum_bn2bin(num,len, ptr) BN_bn2bin(num, ptr)
|
||||
#define bignum_bn2bin(num,ptr) BN_bn2bin(num,ptr)
|
||||
#define bignum_cmp(num1,num2) BN_cmp(num1,num2)
|
||||
#define bignum_rshift1(dest, src) BN_rshift1(dest, src)
|
||||
#define bignum_dup(orig, dest) do { \
|
||||
if (*(dest) == NULL) { \
|
||||
*(dest) = BN_dup(orig); \
|
||||
} else { \
|
||||
BN_copy(*(dest), orig); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
||||
/* Returns true if the OpenSSL is operating in FIPS mode */
|
||||
#ifdef HAVE_OPENSSL_FIPS_MODE
|
||||
#define ssh_fips_mode() (FIPS_mode() != 0)
|
||||
#else
|
||||
#define ssh_fips_mode() false
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_LIBCRYPTO */
|
||||
|
||||
|
||||
@@ -50,8 +50,6 @@ typedef gcry_md_hd_t EVPCTX;
|
||||
#define EVP_DIGEST_LEN EVP_MAX_MD_SIZE
|
||||
|
||||
typedef gcry_mpi_t bignum;
|
||||
typedef const struct gcry_mpi *const_bignum;
|
||||
typedef void* bignum_CTX;
|
||||
|
||||
/* Constants for curves. */
|
||||
#define NID_gcrypt_nistp256 0
|
||||
@@ -61,7 +59,6 @@ typedef void* bignum_CTX;
|
||||
/* missing gcrypt functions */
|
||||
int ssh_gcry_dec2bn(bignum *bn, const char *data);
|
||||
char *ssh_gcry_bn2dec(bignum bn);
|
||||
int ssh_gcry_rand_range(bignum rnd, bignum max);
|
||||
|
||||
#define bignum_new() gcry_mpi_new(0)
|
||||
#define bignum_safe_free(num) do { \
|
||||
@@ -70,38 +67,20 @@ int ssh_gcry_rand_range(bignum rnd, bignum max);
|
||||
(num)=NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
#define bignum_free(num) gcry_mpi_release(num)
|
||||
#define bignum_ctx_new() NULL
|
||||
#define bignum_ctx_free(ctx) do {(ctx) = NULL;} while(0)
|
||||
#define bignum_ctx_invalid(ctx) (ctx != NULL)
|
||||
#define bignum_set_word(bn,n) (gcry_mpi_set_ui(bn,n)!=NULL ? 1 : 0)
|
||||
#define bignum_bin2bn(data,datalen,dest) gcry_mpi_scan(dest,GCRYMPI_FMT_USG,data,datalen,NULL)
|
||||
#define bignum_set_word(bn,n) gcry_mpi_set_ui(bn,n)
|
||||
#define bignum_bin2bn(bn,datalen,data) gcry_mpi_scan(data,GCRYMPI_FMT_USG,bn,datalen,NULL)
|
||||
#define bignum_bn2dec(num) ssh_gcry_bn2dec(num)
|
||||
#define bignum_dec2bn(num, data) ssh_gcry_dec2bn(data, num)
|
||||
|
||||
#define bignum_bn2hex(num, data) \
|
||||
gcry_mpi_aprint(GCRYMPI_FMT_HEX, data, NULL, (const gcry_mpi_t)num)
|
||||
|
||||
#define bignum_hex2bn(data, num) (gcry_mpi_scan(num,GCRYMPI_FMT_HEX,data,0,NULL)==0?1:0)
|
||||
#define bignum_rand(num,bits) 1,gcry_mpi_randomize(num,bits,GCRY_STRONG_RANDOM),gcry_mpi_set_bit(num,bits-1),gcry_mpi_set_bit(num,0)
|
||||
#define bignum_mod_exp(dest,generator,exp,modulo, ctx) 1,gcry_mpi_powm(dest,generator,exp,modulo)
|
||||
#define bignum_bn2hex(num,data) gcry_mpi_aprint(GCRYMPI_FMT_HEX,data,NULL,num)
|
||||
#define bignum_hex2bn(num,datalen,data) gcry_mpi_scan(num,GCRYMPI_FMT_HEX,data,datalen,NULL)
|
||||
#define bignum_rand(num,bits) gcry_mpi_randomize(num,bits,GCRY_STRONG_RANDOM),gcry_mpi_set_bit(num,bits-1),gcry_mpi_set_bit(num,0)
|
||||
#define bignum_mod_exp(dest,generator,exp,modulo) gcry_mpi_powm(dest,generator,exp,modulo)
|
||||
#define bignum_num_bits(num) gcry_mpi_get_nbits(num)
|
||||
#define bignum_num_bytes(num) ((gcry_mpi_get_nbits(num)+7)/8)
|
||||
#define bignum_is_bit_set(num,bit) gcry_mpi_test_bit(num,bit)
|
||||
#define bignum_bn2bin(num,datalen,data) gcry_mpi_print(GCRYMPI_FMT_USG,data,datalen,NULL,num)
|
||||
#define bignum_cmp(num1,num2) gcry_mpi_cmp(num1,num2)
|
||||
#define bignum_rshift1(dest, src) gcry_mpi_rshift (dest, src, 1)
|
||||
#define bignum_add(dst, a, b) gcry_mpi_add(dst, a, b)
|
||||
#define bignum_sub(dst, a, b) gcry_mpi_sub(dst, a, b)
|
||||
#define bignum_mod(dst, a, b, ctx) 1,gcry_mpi_mod(dst, a, b)
|
||||
#define bignum_rand_range(rnd, max) ssh_gcry_rand_range(rnd, max);
|
||||
#define bignum_dup(orig, dest) do { \
|
||||
if (*(dest) == NULL) { \
|
||||
*(dest) = gcry_mpi_copy(orig); \
|
||||
} else { \
|
||||
gcry_mpi_set(*(dest), orig); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/* Helper functions for data conversions. */
|
||||
|
||||
/* Extract an MPI from the given s-expression SEXP named NAME which is
|
||||
@@ -112,8 +91,6 @@ ssh_string ssh_sexp_extract_mpi(const gcry_sexp_t sexp,
|
||||
enum gcry_mpi_format informat,
|
||||
enum gcry_mpi_format outformat);
|
||||
|
||||
#define ssh_fips_mode() false
|
||||
|
||||
#endif /* HAVE_LIBGCRYPT */
|
||||
|
||||
#endif /* LIBGCRYPT_H_ */
|
||||
|
||||
@@ -60,8 +60,6 @@ typedef mbedtls_md_context_t *EVPCTX;
|
||||
#define EVP_DIGEST_LEN EVP_MAX_MD_SIZE
|
||||
|
||||
typedef mbedtls_mpi *bignum;
|
||||
typedef const mbedtls_mpi *const_bignum;
|
||||
typedef void* bignum_CTX;
|
||||
|
||||
/* Constants for curves */
|
||||
#define NID_mbedtls_nistp256 0
|
||||
@@ -75,11 +73,9 @@ struct mbedtls_ecdsa_sig {
|
||||
|
||||
bignum ssh_mbedcry_bn_new(void);
|
||||
void ssh_mbedcry_bn_free(bignum num);
|
||||
unsigned char *ssh_mbedcry_bn2num(const_bignum num, int radix);
|
||||
char *ssh_mbedcry_bn2num(bignum num, int radix);
|
||||
int ssh_mbedcry_rand(bignum rnd, int bits, int top, int bottom);
|
||||
int ssh_mbedcry_is_bit_set(bignum num, size_t pos);
|
||||
int ssh_mbedcry_rand_range(bignum dest, bignum max);
|
||||
int ssh_mbedcry_hex2bn(bignum *dest, char *data);
|
||||
|
||||
#define bignum_new() ssh_mbedcry_bn_new()
|
||||
#define bignum_safe_free(num) do { \
|
||||
@@ -88,44 +84,22 @@ int ssh_mbedcry_hex2bn(bignum *dest, char *data);
|
||||
(num)=NULL; \
|
||||
} \
|
||||
} while(0)
|
||||
#define bignum_ctx_new() NULL
|
||||
#define bignum_ctx_free(num) do {(num) = NULL;} while(0)
|
||||
#define bignum_ctx_invalid(ctx) (ctx == NULL?0:1)
|
||||
#define bignum_set_word(bn, n) (mbedtls_mpi_lset(bn, n)==0?1:0) /* TODO fix
|
||||
#define bignum_set_word(bn, n) mbedtls_mpi_lset(bn, n) /* TODO fix
|
||||
overflow/underflow */
|
||||
#define bignum_bin2bn(data, datalen, bn) do { \
|
||||
*(bn) = bignum_new(); \
|
||||
if (*(bn) != NULL) { \
|
||||
mbedtls_mpi_read_binary(*(bn), data, datalen); \
|
||||
} \
|
||||
} while(0)
|
||||
#define bignum_bin2bn(data, datalen, bn) mbedtls_mpi_read_binary(bn, data, \
|
||||
datalen)
|
||||
#define bignum_bn2dec(num) ssh_mbedcry_bn2num(num, 10)
|
||||
#define bignum_dec2bn(data, bn) mbedtls_mpi_read_string(bn, 10, data)
|
||||
#define bignum_bn2hex(num, dest) (*dest)=ssh_mbedcry_bn2num(num, 16)
|
||||
#define bignum_hex2bn(data, dest) ssh_mbedcry_hex2bn(dest, data)
|
||||
#define bignum_bn2hex(num) ssh_mbedcry_bn2num(num, 16)
|
||||
#define bignum_rand(rnd, bits) ssh_mbedcry_rand((rnd), (bits), 0, 1)
|
||||
#define bignum_rand_range(rnd, max) ssh_mbedcry_rand_range(rnd, max)
|
||||
#define bignum_mod_exp(dest, generator, exp, modulo, ctx) \
|
||||
(mbedtls_mpi_exp_mod(dest, generator, exp, modulo, NULL)==0?1:0)
|
||||
#define bignum_add(dest, a, b) mbedtls_mpi_add_mpi(dest, a, b)
|
||||
#define bignum_sub(dest, a, b) mbedtls_mpi_sub_mpi(dest, a, b)
|
||||
#define bignum_mod(dest, a, b, ctx) \
|
||||
(mbedtls_mpi_mod_mpi(dest, a, b) == 0 ? 1 : 0)
|
||||
mbedtls_mpi_exp_mod(dest, generator, exp, modulo, NULL)
|
||||
#define bignum_num_bytes(num) mbedtls_mpi_size(num)
|
||||
#define bignum_num_bits(num) mbedtls_mpi_bitlen(num)
|
||||
#define bignum_is_bit_set(num, bit) ssh_mbedcry_is_bit_set(num, bit)
|
||||
#define bignum_bn2bin(num, len, ptr) mbedtls_mpi_write_binary(num, ptr, \
|
||||
#define bignum_bn2bin(num, ptr) mbedtls_mpi_write_binary(num, ptr, \
|
||||
mbedtls_mpi_size(num))
|
||||
#define bignum_cmp(num1, num2) mbedtls_mpi_cmp_mpi(num1, num2)
|
||||
#define bignum_rshift1(dest, src) mbedtls_mpi_copy(dest, src), mbedtls_mpi_shift_r(dest, 1)
|
||||
#define bignum_dup(orig, dest) do { \
|
||||
if (*(dest) == NULL) { \
|
||||
*(dest) = bignum_new(); \
|
||||
} \
|
||||
if (*(dest) != NULL) { \
|
||||
mbedtls_mpi_copy(orig, *(dest)); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
mbedtls_ctr_drbg_context *ssh_get_mbedtls_ctr_drbg_context(void);
|
||||
|
||||
@@ -134,7 +108,5 @@ int ssh_mbedtls_random(void *where, int len, int strong);
|
||||
ssh_string make_ecpoint_string(const mbedtls_ecp_group *g, const
|
||||
mbedtls_ecp_point *p);
|
||||
|
||||
#define ssh_fips_mode() false
|
||||
|
||||
#endif /* HAVE_LIBMBEDCRYPTO */
|
||||
#endif /* LIBMBEDCRYPTO_H_ */
|
||||
|
||||
@@ -78,8 +78,8 @@
|
||||
|
||||
/* libssh version */
|
||||
#define LIBSSH_VERSION_MAJOR 0
|
||||
#define LIBSSH_VERSION_MINOR 9
|
||||
#define LIBSSH_VERSION_MICRO 2
|
||||
#define LIBSSH_VERSION_MINOR 8
|
||||
#define LIBSSH_VERSION_MICRO 90
|
||||
|
||||
#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \
|
||||
LIBSSH_VERSION_MINOR, \
|
||||
@@ -293,17 +293,10 @@ enum ssh_keytypes_e{
|
||||
SSH_KEYTYPE_DSS=1,
|
||||
SSH_KEYTYPE_RSA,
|
||||
SSH_KEYTYPE_RSA1,
|
||||
SSH_KEYTYPE_ECDSA, /* deprecated */
|
||||
SSH_KEYTYPE_ECDSA,
|
||||
SSH_KEYTYPE_ED25519,
|
||||
SSH_KEYTYPE_DSS_CERT01,
|
||||
SSH_KEYTYPE_RSA_CERT01,
|
||||
SSH_KEYTYPE_ECDSA_P256,
|
||||
SSH_KEYTYPE_ECDSA_P384,
|
||||
SSH_KEYTYPE_ECDSA_P521,
|
||||
SSH_KEYTYPE_ECDSA_P256_CERT01,
|
||||
SSH_KEYTYPE_ECDSA_P384_CERT01,
|
||||
SSH_KEYTYPE_ECDSA_P521_CERT01,
|
||||
SSH_KEYTYPE_ED25519_CERT01,
|
||||
SSH_KEYTYPE_RSA_CERT01
|
||||
};
|
||||
|
||||
enum ssh_keycmp_e {
|
||||
@@ -413,8 +406,6 @@ enum ssh_options_e {
|
||||
SSH_OPTIONS_NODELAY,
|
||||
SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES,
|
||||
SSH_OPTIONS_PROCESS_CONFIG,
|
||||
SSH_OPTIONS_REKEY_DATA,
|
||||
SSH_OPTIONS_REKEY_TIME,
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -441,7 +432,6 @@ enum ssh_scp_request_types {
|
||||
enum ssh_connector_flags_e {
|
||||
/** Only the standard stream of the channel */
|
||||
SSH_CONNECTOR_STDOUT = 1,
|
||||
SSH_CONNECTOR_STDINOUT = 1,
|
||||
/** Only the exception stream of the channel */
|
||||
SSH_CONNECTOR_STDERR = 2,
|
||||
/** Merge both standard and exception streams */
|
||||
@@ -462,8 +452,6 @@ 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_forward_unix(ssh_channel channel, const char *remotepath,
|
||||
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);
|
||||
@@ -559,7 +547,6 @@ SSH_DEPRECATED LIBSSH_API int ssh_get_publickey(ssh_session session, ssh_key *ke
|
||||
SSH_DEPRECATED LIBSSH_API int ssh_write_knownhost(ssh_session session);
|
||||
SSH_DEPRECATED LIBSSH_API char *ssh_dump_knownhost(ssh_session session);
|
||||
SSH_DEPRECATED LIBSSH_API int ssh_is_server_known(ssh_session session);
|
||||
SSH_DEPRECATED LIBSSH_API void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len);
|
||||
|
||||
|
||||
|
||||
@@ -589,8 +576,9 @@ LIBSSH_API int ssh_session_export_known_hosts_entry(ssh_session session,
|
||||
char **pentry_string);
|
||||
LIBSSH_API int ssh_session_update_known_hosts(ssh_session session);
|
||||
|
||||
LIBSSH_API enum ssh_known_hosts_e ssh_session_get_known_hosts_entry(ssh_session session,
|
||||
struct ssh_knownhosts_entry **pentry);
|
||||
LIBSSH_API enum ssh_known_hosts_e
|
||||
ssh_session_get_known_hosts_entry(ssh_session session,
|
||||
struct ssh_knownhosts_entry **pentry);
|
||||
LIBSSH_API enum ssh_known_hosts_e ssh_session_is_known_server(ssh_session session);
|
||||
|
||||
/* LOGGING */
|
||||
@@ -608,7 +596,6 @@ SSH_DEPRECATED LIBSSH_API void ssh_log(ssh_session session,
|
||||
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_open_reply_accept_channel(ssh_message msg, ssh_channel chan);
|
||||
LIBSSH_API int ssh_message_channel_request_reply_success(ssh_message msg);
|
||||
#define SSH_MESSAGE_FREE(x) \
|
||||
do { if ((x) != NULL) { ssh_message_free(x); (x) = NULL; } } while(0)
|
||||
@@ -712,6 +699,7 @@ LIBSSH_API char *ssh_get_fingerprint_hash(enum ssh_publickey_hash_type type,
|
||||
unsigned char *hash,
|
||||
size_t len);
|
||||
LIBSSH_API void ssh_print_hash(enum ssh_publickey_hash_type type, unsigned char *hash, size_t len);
|
||||
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);
|
||||
|
||||
@@ -102,5 +102,6 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_request);
|
||||
int ssh_message_handle_channel_request(ssh_session session, ssh_channel channel, ssh_buffer packet,
|
||||
const char *request, uint8_t want_reply);
|
||||
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_ */
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
char *ssh_get_user_home_dir(void);
|
||||
char *ssh_get_local_username(void);
|
||||
int ssh_file_readaccess_ok(const char *file);
|
||||
int ssh_dir_writeable(const char *path);
|
||||
|
||||
char *ssh_path_expand_tilde(const char *d);
|
||||
char *ssh_path_expand_escape(ssh_session session, const char *s);
|
||||
@@ -84,8 +83,4 @@ int ssh_match_group(const char *group, const char *object);
|
||||
|
||||
void uint64_inc(unsigned char *counter);
|
||||
|
||||
void ssh_log_hexdump(const char *descr, const unsigned char *what, size_t len);
|
||||
|
||||
int ssh_mkdirs(const char *pathname, mode_t mode);
|
||||
|
||||
#endif /* MISC_H_ */
|
||||
|
||||
@@ -81,11 +81,7 @@ int ssh_packet_decrypt(ssh_session session, uint8_t *destination, uint8_t *sourc
|
||||
unsigned char *ssh_packet_encrypt(ssh_session session,
|
||||
void *packet,
|
||||
unsigned int len);
|
||||
int ssh_packet_hmac_verify(ssh_session session, const void *data, size_t len,
|
||||
int ssh_packet_hmac_verify(ssh_session session,ssh_buffer buffer,
|
||||
unsigned char *mac, enum ssh_hmac_e type);
|
||||
int ssh_packet_set_newkeys(ssh_session session,
|
||||
enum ssh_crypto_direction_e direction);
|
||||
struct ssh_crypto_struct *ssh_packet_get_current_crypto(ssh_session session,
|
||||
enum ssh_crypto_direction_e direction);
|
||||
|
||||
#endif /* PACKET_H_ */
|
||||
|
||||
@@ -30,15 +30,7 @@
|
||||
#endif
|
||||
|
||||
#include "libssh/crypto.h"
|
||||
#ifdef HAVE_OPENSSL_ED25519
|
||||
/* If using OpenSSL implementation, define the signature lenght which would be
|
||||
* defined in libssh/ed25519.h otherwise */
|
||||
#define ED25519_SIG_LEN 64
|
||||
#else
|
||||
#include "libssh/ed25519.h"
|
||||
#endif
|
||||
/* This definition is used for both OpenSSL and internal implementations */
|
||||
#define ED25519_KEY_LEN 32
|
||||
|
||||
#define MAX_PUBKEY_SIZE 0x100000 /* 1M */
|
||||
#define MAX_PRIVKEY_SIZE 0x400000 /* 4M */
|
||||
@@ -69,13 +61,8 @@ struct ssh_key_struct {
|
||||
void *ecdsa;
|
||||
# endif /* HAVE_OPENSSL_EC_H */
|
||||
#endif /* HAVE_LIBGCRYPT */
|
||||
#ifdef HAVE_OPENSSL_ED25519
|
||||
uint8_t *ed25519_pubkey;
|
||||
uint8_t *ed25519_privkey;
|
||||
#else
|
||||
ed25519_pubkey *ed25519_pubkey;
|
||||
ed25519_privkey *ed25519_privkey;
|
||||
#endif
|
||||
void *cert;
|
||||
enum ssh_keytypes_e cert_type;
|
||||
};
|
||||
@@ -88,14 +75,19 @@ struct ssh_signature_struct {
|
||||
gcry_sexp_t dsa_sig;
|
||||
gcry_sexp_t rsa_sig;
|
||||
gcry_sexp_t ecdsa_sig;
|
||||
#elif defined(HAVE_LIBCRYPTO)
|
||||
DSA_SIG *dsa_sig;
|
||||
ssh_string rsa_sig;
|
||||
# ifdef HAVE_OPENSSL_ECC
|
||||
ECDSA_SIG *ecdsa_sig;
|
||||
# else
|
||||
void *ecdsa_sig;
|
||||
# endif
|
||||
#elif defined(HAVE_LIBMBEDCRYPTO)
|
||||
ssh_string rsa_sig;
|
||||
struct mbedtls_ecdsa_sig ecdsa_sig;
|
||||
#endif /* HAVE_LIBGCRYPT */
|
||||
#ifndef HAVE_OPENSSL_ED25519
|
||||
ed25519_signature *ed25519_sig;
|
||||
#endif
|
||||
ssh_string raw_sig;
|
||||
};
|
||||
|
||||
typedef struct ssh_signature_struct *ssh_signature;
|
||||
@@ -108,19 +100,6 @@ const char *
|
||||
ssh_key_get_signature_algorithm(ssh_session session,
|
||||
enum ssh_keytypes_e type);
|
||||
enum ssh_keytypes_e ssh_key_type_from_signature_name(const char *name);
|
||||
enum ssh_keytypes_e ssh_key_type_plain(enum ssh_keytypes_e type);
|
||||
enum ssh_digest_e ssh_key_type_to_hash(ssh_session session,
|
||||
enum ssh_keytypes_e type);
|
||||
enum ssh_digest_e ssh_key_hash_from_name(const char *name);
|
||||
|
||||
#define is_ecdsa_key_type(t) \
|
||||
((t) >= SSH_KEYTYPE_ECDSA_P256 && (t) <= SSH_KEYTYPE_ECDSA_P521)
|
||||
|
||||
#define is_cert_type(kt)\
|
||||
((kt) == SSH_KEYTYPE_DSS_CERT01 ||\
|
||||
(kt) == SSH_KEYTYPE_RSA_CERT01 ||\
|
||||
((kt) >= SSH_KEYTYPE_ECDSA_P256_CERT01 &&\
|
||||
(kt) <= SSH_KEYTYPE_ED25519_CERT01))
|
||||
|
||||
/* SSH Signature Functions */
|
||||
ssh_signature ssh_signature_new(void);
|
||||
@@ -134,7 +113,7 @@ int ssh_pki_import_signature_blob(const ssh_string sig_blob,
|
||||
int ssh_pki_signature_verify(ssh_session session,
|
||||
ssh_signature sig,
|
||||
const ssh_key key,
|
||||
const unsigned char *digest,
|
||||
unsigned char *digest,
|
||||
size_t dlen);
|
||||
|
||||
/* SSH Public Key Functions */
|
||||
@@ -149,13 +128,12 @@ int ssh_pki_import_cert_blob(const ssh_string cert_blob,
|
||||
|
||||
/* SSH Signing Functions */
|
||||
ssh_string ssh_pki_do_sign(ssh_session session, ssh_buffer sigbuf,
|
||||
const ssh_key privatekey, enum ssh_digest_e hash_type);
|
||||
const ssh_key privatekey);
|
||||
ssh_string ssh_pki_do_sign_agent(ssh_session session,
|
||||
struct ssh_buffer_struct *buf,
|
||||
const ssh_key pubkey);
|
||||
ssh_string ssh_srv_pki_do_sign_sessionid(ssh_session session,
|
||||
const ssh_key privkey,
|
||||
const enum ssh_digest_e digest);
|
||||
const ssh_key privkey);
|
||||
|
||||
/* Temporary functions, to be removed after migration to ssh_key */
|
||||
ssh_public_key ssh_pki_convert_key_to_publickey(const ssh_key key);
|
||||
|
||||
@@ -61,8 +61,6 @@ int pki_key_compare(const ssh_key k1,
|
||||
const ssh_key k2,
|
||||
enum ssh_keycmp_e what);
|
||||
|
||||
int pki_key_check_hash_compatible(ssh_key key,
|
||||
enum ssh_digest_e hash_type);
|
||||
/* SSH Private Key Functions */
|
||||
enum ssh_keytypes_e pki_privatekey_type_from_string(const char *privkey);
|
||||
ssh_key pki_private_key_from_base64(const char *b64_key,
|
||||
@@ -111,29 +109,30 @@ int pki_privkey_build_ecdsa(ssh_key key,
|
||||
ssh_string pki_publickey_to_blob(const ssh_key key);
|
||||
|
||||
/* SSH Signature Functions */
|
||||
ssh_signature pki_sign_data(const ssh_key privkey,
|
||||
enum ssh_digest_e hash_type,
|
||||
const unsigned char *input,
|
||||
size_t input_len);
|
||||
int pki_verify_data_signature(ssh_signature signature,
|
||||
const ssh_key pubkey,
|
||||
const unsigned char *input,
|
||||
size_t input_len);
|
||||
ssh_string pki_signature_to_blob(const ssh_signature sign);
|
||||
ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
const ssh_string sig_blob,
|
||||
enum ssh_keytypes_e type,
|
||||
enum ssh_digest_e hash_type);
|
||||
int pki_signature_verify(ssh_session session,
|
||||
const ssh_signature sig,
|
||||
const ssh_key key,
|
||||
const unsigned char *hash,
|
||||
size_t hlen);
|
||||
|
||||
/* SSH Signing Functions */
|
||||
ssh_signature pki_do_sign(const ssh_key privkey,
|
||||
const unsigned char *input,
|
||||
size_t input_len,
|
||||
enum ssh_digest_e hash_type);
|
||||
#define pki_do_sign(key, hash, hlen) \
|
||||
pki_do_sign_hash(key, hash, hlen, SSH_DIGEST_AUTO)
|
||||
ssh_signature pki_do_sign_hash(const ssh_key privkey,
|
||||
const unsigned char *hash,
|
||||
size_t hlen,
|
||||
enum ssh_digest_e hash_type);
|
||||
#define pki_do_sign_sessionid(key, hash, hlen) \
|
||||
pki_do_sign_sessionid_hash(key, hash, hlen, SSH_DIGEST_AUTO)
|
||||
ssh_signature pki_do_sign_sessionid_hash(const ssh_key key,
|
||||
const unsigned char *hash,
|
||||
size_t hlen,
|
||||
enum ssh_digest_e hash_type);
|
||||
int pki_ed25519_sign(const ssh_key privkey, ssh_signature sig,
|
||||
const unsigned char *hash, size_t hlen);
|
||||
int pki_ed25519_verify(const ssh_key pubkey, ssh_signature sig,
|
||||
@@ -143,8 +142,8 @@ int pki_ed25519_key_cmp(const ssh_key k1,
|
||||
enum ssh_keycmp_e what);
|
||||
int pki_ed25519_key_dup(ssh_key new, const ssh_key key);
|
||||
int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key);
|
||||
ssh_string pki_ed25519_signature_to_blob(ssh_signature sig);
|
||||
int pki_signature_from_ed25519_blob(ssh_signature sig, ssh_string sig_blob);
|
||||
ssh_string pki_ed25519_sig_to_blob(ssh_signature sig);
|
||||
int pki_ed25519_sig_from_blob(ssh_signature sig, ssh_string sig_blob);
|
||||
int pki_privkey_build_ed25519(ssh_key key,
|
||||
ssh_string pubkey,
|
||||
ssh_string privkey);
|
||||
|
||||
@@ -78,22 +78,6 @@ char *strndup(const char *s, size_t n);
|
||||
# endif /* __WORDSIZE */
|
||||
# endif /* PRIu64 */
|
||||
|
||||
# ifndef PRIu32
|
||||
# define PRIu32 "u"
|
||||
# endif /* PRIu32 */
|
||||
|
||||
# ifndef PRIx64
|
||||
# if __WORDSIZE == 64
|
||||
# define PRIx64 "lx"
|
||||
# else
|
||||
# define PRIx64 "llx"
|
||||
# endif /* __WORDSIZE */
|
||||
# endif /* PRIx64 */
|
||||
|
||||
# ifndef PRIx32
|
||||
# define PRIx32 "x"
|
||||
# endif /* PRIx32 */
|
||||
|
||||
# ifdef _MSC_VER
|
||||
# include <stdio.h>
|
||||
# include <stdarg.h> /* va_copy define check */
|
||||
@@ -221,17 +205,7 @@ int gettimeofday(struct timeval *__p, void *__t);
|
||||
struct ssh_common_struct;
|
||||
struct ssh_kex_struct;
|
||||
|
||||
enum ssh_digest_e {
|
||||
SSH_DIGEST_AUTO=0,
|
||||
SSH_DIGEST_SHA1=1,
|
||||
SSH_DIGEST_SHA256,
|
||||
SSH_DIGEST_SHA384,
|
||||
SSH_DIGEST_SHA512,
|
||||
};
|
||||
|
||||
int ssh_get_key_params(ssh_session session,
|
||||
ssh_key *privkey,
|
||||
enum ssh_digest_e *digest);
|
||||
int ssh_get_key_params(ssh_session session, ssh_key *privkey);
|
||||
|
||||
/* LOGGING */
|
||||
void ssh_log_function(int verbosity,
|
||||
@@ -282,6 +256,8 @@ int ssh_auth_reply_success(ssh_session session, int partial);
|
||||
int ssh_send_banner(ssh_session session, int is_server);
|
||||
|
||||
/* connect.c */
|
||||
socket_t ssh_connect_host(ssh_session session, const char *host,const char
|
||||
*bind_addr, int port, long timeout, long usec);
|
||||
socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
||||
const char *bind_addr, int port);
|
||||
|
||||
@@ -348,6 +324,7 @@ void explicit_bzero(void *s, size_t n);
|
||||
/**
|
||||
* Get the argument cound of variadic arguments
|
||||
*/
|
||||
#ifdef HAVE_GCC_NARG_MACRO
|
||||
/*
|
||||
* Since MSVC 2010 there is a bug in passing __VA_ARGS__ to subsequent
|
||||
* macros as a single token, which results in:
|
||||
@@ -357,7 +334,7 @@ void explicit_bzero(void *s, size_t n);
|
||||
#define VA_APPLY_VARIADIC_MACRO(macro, tuple) macro tuple
|
||||
|
||||
#define __VA_NARG__(...) \
|
||||
(__VA_NARG_(__VA_ARGS__, __RSEQ_N()))
|
||||
(__VA_NARG_(_0, ## __VA_ARGS__, __RSEQ_N()) - 1)
|
||||
#define __VA_NARG_(...) \
|
||||
VA_APPLY_VARIADIC_MACRO(__VA_ARG_N, (__VA_ARGS__))
|
||||
#define __VA_ARG_N( \
|
||||
@@ -376,6 +353,10 @@ void explicit_bzero(void *s, size_t n);
|
||||
29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \
|
||||
19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \
|
||||
9, 8, 7, 6, 5, 4, 3, 2, 1, 0
|
||||
#else
|
||||
/* clang does not support the above construction */
|
||||
#define __VA_NARG__(...) (-1)
|
||||
#endif
|
||||
|
||||
#define CLOSE_SOCKET(s) do { if ((s) != SSH_INVALID_SOCKET) { _XCLOSESOCKET(s); (s) = SSH_INVALID_SOCKET;} } while(0)
|
||||
|
||||
|
||||
@@ -46,16 +46,7 @@ enum ssh_bind_options_e {
|
||||
SSH_BIND_OPTIONS_LOG_VERBOSITY,
|
||||
SSH_BIND_OPTIONS_LOG_VERBOSITY_STR,
|
||||
SSH_BIND_OPTIONS_ECDSAKEY,
|
||||
SSH_BIND_OPTIONS_IMPORT_KEY,
|
||||
SSH_BIND_OPTIONS_KEY_EXCHANGE,
|
||||
SSH_BIND_OPTIONS_CIPHERS_C_S,
|
||||
SSH_BIND_OPTIONS_CIPHERS_S_C,
|
||||
SSH_BIND_OPTIONS_HMAC_C_S,
|
||||
SSH_BIND_OPTIONS_HMAC_S_C,
|
||||
SSH_BIND_OPTIONS_CONFIG_DIR,
|
||||
SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES,
|
||||
SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS,
|
||||
SSH_BIND_OPTIONS_PROCESS_CONFIG,
|
||||
SSH_BIND_OPTIONS_IMPORT_KEY
|
||||
};
|
||||
|
||||
typedef struct ssh_bind_struct* ssh_bind;
|
||||
@@ -94,9 +85,6 @@ LIBSSH_API ssh_bind ssh_bind_new(void);
|
||||
LIBSSH_API int ssh_bind_options_set(ssh_bind sshbind,
|
||||
enum ssh_bind_options_e type, const void *value);
|
||||
|
||||
LIBSSH_API int ssh_bind_options_parse_config(ssh_bind sshbind,
|
||||
const char *filename);
|
||||
|
||||
/**
|
||||
* @brief Start listening to the socket.
|
||||
*
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include "libssh/channels.h"
|
||||
#include "libssh/poll.h"
|
||||
#include "libssh/config.h"
|
||||
#include "libssh/misc.h"
|
||||
|
||||
/* These are the different states a SSH session can be into its life */
|
||||
enum ssh_session_state_e {
|
||||
@@ -49,8 +48,6 @@ enum ssh_session_state_e {
|
||||
|
||||
enum ssh_dh_state_e {
|
||||
DH_STATE_INIT=0,
|
||||
DH_STATE_GROUP_SENT,
|
||||
DH_STATE_REQUEST_SENT,
|
||||
DH_STATE_INIT_SENT,
|
||||
DH_STATE_NEWKEYS_SENT,
|
||||
DH_STATE_FINISHED
|
||||
@@ -93,11 +90,10 @@ enum ssh_pending_call_e {
|
||||
#define SSH_OPT_FLAG_GSSAPI_AUTH 0x8
|
||||
|
||||
/* extensions flags */
|
||||
/* negotiation enabled */
|
||||
#define SSH_EXT_NEGOTIATION 0x01
|
||||
/* server-sig-algs extension */
|
||||
#define SSH_EXT_SIG_RSA_SHA256 0x02
|
||||
#define SSH_EXT_SIG_RSA_SHA512 0x04
|
||||
#define SSH_EXT_SIG_RSA_SHA256 0x01
|
||||
#define SSH_EXT_SIG_RSA_SHA512 0x02
|
||||
#define SSH_EXT_ALL SSH_EXT_SIG_RSA_SHA256 | SSH_EXT_SIG_RSA_SHA512
|
||||
|
||||
/* members that are common to ssh_session and ssh_bind */
|
||||
struct ssh_common_struct {
|
||||
@@ -117,7 +113,6 @@ struct ssh_session_struct {
|
||||
int openssh;
|
||||
uint32_t send_seq;
|
||||
uint32_t recv_seq;
|
||||
struct ssh_timestamp last_rekey_time;
|
||||
|
||||
int connected;
|
||||
/* !=0 when the user got a session handle */
|
||||
@@ -138,8 +133,6 @@ struct ssh_session_struct {
|
||||
ssh_buffer in_buffer;
|
||||
PACKET in_packet;
|
||||
ssh_buffer out_buffer;
|
||||
struct ssh_list *out_queue; /* This list is used for delaying packets
|
||||
when rekeying is required */
|
||||
|
||||
/* the states are used by the nonblocking stuff to remember */
|
||||
/* where it was before being interrupted */
|
||||
@@ -188,7 +181,6 @@ struct ssh_session_struct {
|
||||
ssh_key ed25519_key;
|
||||
/* The type of host key wanted by client */
|
||||
enum ssh_keytypes_e hostkey;
|
||||
enum ssh_digest_e hostkey_digest;
|
||||
} srv;
|
||||
|
||||
/* auths accepted by server */
|
||||
@@ -230,8 +222,6 @@ struct ssh_session_struct {
|
||||
int nodelay;
|
||||
bool config_processed;
|
||||
uint8_t options_seen[SOC_MAX];
|
||||
uint64_t rekey_data;
|
||||
uint32_t rekey_time;
|
||||
} opts;
|
||||
/* counters */
|
||||
ssh_counter socket_counter;
|
||||
|
||||
@@ -201,18 +201,13 @@ struct sftp_statvfs_struct {
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Creates a new sftp session.
|
||||
*
|
||||
* This function creates a new sftp session and allocates a new sftp channel
|
||||
* with the server inside of the provided ssh session. This function call is
|
||||
* usually followed by the sftp_init(), which initializes SFTP protocol itself.
|
||||
* @brief Start a new sftp session.
|
||||
*
|
||||
* @param session The ssh session to use.
|
||||
*
|
||||
* @return A new sftp session or NULL on error.
|
||||
*
|
||||
* @see sftp_free()
|
||||
* @see sftp_init()
|
||||
*/
|
||||
LIBSSH_API sftp_session sftp_new(ssh_session session);
|
||||
|
||||
@@ -237,10 +232,7 @@ LIBSSH_API sftp_session sftp_new_channel(ssh_session session, ssh_channel channe
|
||||
LIBSSH_API void sftp_free(sftp_session sftp);
|
||||
|
||||
/**
|
||||
* @brief Initialize the sftp protocol with the server.
|
||||
*
|
||||
* This function involves the SFTP protocol initialization (as described
|
||||
* in the SFTP specification), including the version and extensions negotiation.
|
||||
* @brief Initialize the sftp session with the server.
|
||||
*
|
||||
* @param sftp The sftp session to initialize.
|
||||
*
|
||||
@@ -826,9 +818,7 @@ LIBSSH_API int sftp_fsync(sftp_file file);
|
||||
*
|
||||
* @param path The path to be canonicalized.
|
||||
*
|
||||
* @return A pointer to the newly allocated canonicalized path,
|
||||
* NULL on error. The caller needs to free the memory
|
||||
* using ssh_string_free_char().
|
||||
* @return The canonicalize path, NULL on error.
|
||||
*/
|
||||
LIBSSH_API char *sftp_canonicalize_path(sftp_session sftp, const char *path);
|
||||
|
||||
@@ -861,13 +851,6 @@ LIBSSH_API sftp_session sftp_server_new(ssh_session session, ssh_channel chan);
|
||||
* @return 0 on success, < 0 on error.
|
||||
*/
|
||||
LIBSSH_API int sftp_server_init(sftp_session sftp);
|
||||
|
||||
/**
|
||||
* @brief Close and deallocate a sftp server session.
|
||||
*
|
||||
* @param sftp The sftp session handle to free.
|
||||
*/
|
||||
LIBSSH_API void sftp_server_free(sftp_session sftp);
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
/* this is not a public interface */
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* token.h - Tokens list handling
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2019 by Red Hat, Inc.
|
||||
*
|
||||
* Author: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef TOKEN_H_
|
||||
#define TOKEN_H_
|
||||
|
||||
struct ssh_tokens_st {
|
||||
char *buffer;
|
||||
char **tokens;
|
||||
};
|
||||
|
||||
struct ssh_tokens_st *ssh_tokenize(const char *chain, char separator);
|
||||
|
||||
void ssh_tokens_free(struct ssh_tokens_st *tokens);
|
||||
|
||||
char *ssh_find_matching(const char *available_d,
|
||||
const char *preferred_d);
|
||||
|
||||
char *ssh_find_all_matching(const char *available_d,
|
||||
const char *preferred_d);
|
||||
|
||||
char *ssh_remove_duplicates(const char *list);
|
||||
|
||||
char *ssh_append_without_duplicates(const char *list,
|
||||
const char *appended_list);
|
||||
#endif /* TOKEN_H_ */
|
||||
@@ -21,24 +21,30 @@
|
||||
#ifndef WRAPPER_H_
|
||||
#define WRAPPER_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "libssh/libssh.h"
|
||||
#include "libssh/libcrypto.h"
|
||||
#include "libssh/libgcrypt.h"
|
||||
#include "libssh/libmbedcrypto.h"
|
||||
|
||||
enum ssh_kdf_digest {
|
||||
SSH_KDF_SHA1=1,
|
||||
SSH_KDF_SHA256,
|
||||
SSH_KDF_SHA384,
|
||||
SSH_KDF_SHA512
|
||||
enum ssh_digest_e {
|
||||
SSH_DIGEST_AUTO=0,
|
||||
SSH_DIGEST_SHA1=1,
|
||||
SSH_DIGEST_SHA256,
|
||||
SSH_DIGEST_SHA512
|
||||
};
|
||||
|
||||
enum ssh_mac_e {
|
||||
SSH_MAC_SHA1=1,
|
||||
SSH_MAC_SHA256,
|
||||
SSH_MAC_SHA384,
|
||||
SSH_MAC_SHA512
|
||||
};
|
||||
|
||||
enum ssh_hmac_e {
|
||||
SSH_HMAC_SHA1 = 1,
|
||||
SSH_HMAC_SHA256,
|
||||
SSH_HMAC_SHA384,
|
||||
SSH_HMAC_SHA512,
|
||||
SSH_HMAC_MD5,
|
||||
SSH_HMAC_AEAD_POLY1305,
|
||||
@@ -53,17 +59,9 @@ enum ssh_des_e {
|
||||
struct ssh_hmac_struct {
|
||||
const char* name;
|
||||
enum ssh_hmac_e hmac_type;
|
||||
bool etm;
|
||||
};
|
||||
|
||||
enum ssh_crypto_direction_e {
|
||||
SSH_DIRECTION_IN = 1,
|
||||
SSH_DIRECTION_OUT = 2,
|
||||
SSH_DIRECTION_BOTH = 3,
|
||||
};
|
||||
|
||||
struct ssh_cipher_struct;
|
||||
struct ssh_crypto_struct;
|
||||
|
||||
typedef struct ssh_mac_ctx_struct *ssh_mac_ctx;
|
||||
MD5CTX md5_init(void);
|
||||
@@ -73,38 +71,37 @@ void md5_final(unsigned char *md,MD5CTX c);
|
||||
SHACTX sha1_init(void);
|
||||
void sha1_update(SHACTX c, const void *data, unsigned long len);
|
||||
void sha1_final(unsigned char *md,SHACTX c);
|
||||
void sha1(const unsigned char *digest,int len,unsigned char *hash);
|
||||
void sha1(unsigned char *digest,int len,unsigned char *hash);
|
||||
|
||||
SHA256CTX sha256_init(void);
|
||||
void sha256_update(SHA256CTX c, const void *data, unsigned long len);
|
||||
void sha256_final(unsigned char *md,SHA256CTX c);
|
||||
void sha256(const unsigned char *digest, int len, unsigned char *hash);
|
||||
void sha256(unsigned char *digest, int len, unsigned char *hash);
|
||||
|
||||
SHA384CTX sha384_init(void);
|
||||
void sha384_update(SHA384CTX c, const void *data, unsigned long len);
|
||||
void sha384_final(unsigned char *md,SHA384CTX c);
|
||||
void sha384(const unsigned char *digest, int len, unsigned char *hash);
|
||||
void sha384(unsigned char *digest, int len, unsigned char *hash);
|
||||
|
||||
SHA512CTX sha512_init(void);
|
||||
void sha512_update(SHA512CTX c, const void *data, unsigned long len);
|
||||
void sha512_final(unsigned char *md,SHA512CTX c);
|
||||
void sha512(const unsigned char *digest, int len, unsigned char *hash);
|
||||
void sha512(unsigned char *digest, int len, unsigned char *hash);
|
||||
|
||||
void evp(int nid, unsigned char *digest, int len, unsigned char *hash, unsigned int *hlen);
|
||||
EVPCTX evp_init(int nid);
|
||||
void evp_update(EVPCTX ctx, const void *data, unsigned long len);
|
||||
void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen);
|
||||
|
||||
ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type);
|
||||
void ssh_mac_update(ssh_mac_ctx ctx, const void *data, unsigned long len);
|
||||
void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx);
|
||||
|
||||
HMACCTX hmac_init(const void *key,int len, enum ssh_hmac_e type);
|
||||
void hmac_update(HMACCTX c, const void *data, unsigned long len);
|
||||
void hmac_final(HMACCTX ctx,unsigned char *hashmacbuf,unsigned int *len);
|
||||
size_t hmac_digest_len(enum ssh_hmac_e type);
|
||||
|
||||
int ssh_kdf(struct ssh_crypto_struct *crypto,
|
||||
unsigned char *key, size_t key_len,
|
||||
int key_type, unsigned char *output,
|
||||
size_t requested_len);
|
||||
|
||||
int crypt_set_algorithms_client(ssh_session session);
|
||||
int crypt_set_algorithms_server(ssh_session session);
|
||||
struct ssh_crypto_struct *crypto_new(void);
|
||||
@@ -117,6 +114,6 @@ void ssh_crypto_finalize(void);
|
||||
void ssh_cipher_clear(struct ssh_cipher_struct *cipher);
|
||||
struct ssh_hmac_struct *ssh_get_hmactab(void);
|
||||
struct ssh_cipher_struct *ssh_get_ciphertab(void);
|
||||
const char *ssh_hmac_type_to_string(enum ssh_hmac_e hmac_type, bool etm);
|
||||
const char *ssh_hmac_type_to_string(enum ssh_hmac_e hmac_type);
|
||||
|
||||
#endif /* WRAPPER_H_ */
|
||||
|
||||
15
libssh-config.cmake.in
Normal file
15
libssh-config.cmake.in
Normal file
@@ -0,0 +1,15 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/CMakeCache.txt")
|
||||
# In tree build
|
||||
set_and_check(LIBSSH_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/include")
|
||||
set_and_check(LIBSSH_LIBRARIES "${CMAKE_CURRENT_LIST_DIR}/lib/@LIBSSH_LIBRARY_NAME@")
|
||||
else()
|
||||
set_and_check(LIBSSH_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
|
||||
set_and_check(LIBSSH_LIBRARIES "@PACKAGE_LIB_INSTALL_DIR@/@LIBSSH_LIBRARY_NAME@")
|
||||
endif()
|
||||
|
||||
# For backward compatibility
|
||||
set(LIBSSH_LIBRARY ${LIBSSH_LIBRARIES})
|
||||
|
||||
mark_as_advanced(LIBSSH_LIBRARIES LIBSSH_LIBRARY LIBSSH_INCLUDE_DIR)
|
||||
@@ -1,6 +1,6 @@
|
||||
Name: ${PROJECT_NAME}
|
||||
Description: The SSH Library
|
||||
Version: ${PROJECT_VERSION}
|
||||
Libs: -L${CMAKE_INSTALL_FULL_LIBDIR} -lssh
|
||||
Cflags: -I${CMAKE_INSTALL_FULL_INCLUDEDIR}
|
||||
Libs: -L${LIB_INSTALL_DIR} -lssh
|
||||
Cflags: -I${INCLUDE_INSTALL_DIR}
|
||||
|
||||
|
||||
200
obj/build_make.sh
Executable file
200
obj/build_make.sh
Executable file
@@ -0,0 +1,200 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Last Change: 2008-06-18 14:13:46
|
||||
#
|
||||
# Script to build libssh on UNIX.
|
||||
#
|
||||
# Copyright (c) 2006-2007 Andreas Schneider <asn@cryptomilk.org>
|
||||
#
|
||||
|
||||
SOURCE_DIR=".."
|
||||
|
||||
LANG=C
|
||||
export LANG
|
||||
|
||||
SCRIPT="$0"
|
||||
COUNT=0
|
||||
while [ -L "${SCRIPT}" ]
|
||||
do
|
||||
SCRIPT=$(readlink ${SCRIPT})
|
||||
COUNT=$(expr ${COUNT} + 1)
|
||||
if [ ${COUNT} -gt 100 ]; then
|
||||
echo "Too many symbolic links"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
BUILDDIR=$(dirname ${SCRIPT})
|
||||
|
||||
cleanup_and_exit () {
|
||||
if test "$1" = 0 -o -z "$1" ; then
|
||||
exit 0
|
||||
else
|
||||
exit $1
|
||||
fi
|
||||
}
|
||||
|
||||
function configure() {
|
||||
if [ -n "${CMAKEDIR}" ]; then
|
||||
${CMAKEDIR}/bin/cmake "$@" ${SOURCE_DIR} || cleanup_and_exit $?
|
||||
else
|
||||
cmake "$@" ${SOURCE_DIR} || cleanup_and_exit $?
|
||||
fi
|
||||
}
|
||||
|
||||
function compile() {
|
||||
if [ -f /proc/cpuinfo ]; then
|
||||
CPUCOUNT=$(grep -c processor /proc/cpuinfo)
|
||||
elif test `uname` = "SunOS" ; then
|
||||
CPUCOUNT=$(psrinfo -p)
|
||||
else
|
||||
CPUCOUNT="1"
|
||||
fi
|
||||
|
||||
if [ "${CPUCOUNT}" -gt "1" ]; then
|
||||
${MAKE} -j${CPUCOUNT} $1 || cleanup_and_exit $?
|
||||
else
|
||||
${MAKE} $1 || exit $?
|
||||
fi
|
||||
}
|
||||
|
||||
function clean_build_dir() {
|
||||
find ! -path "*.svn*" ! -name "*.bat" ! -name "*.sh" ! -name "." -print0 | xargs -0 rm -rf
|
||||
}
|
||||
|
||||
function usage () {
|
||||
echo "Usage: `basename $0` [--prefix /install_prefix|--build [debug|final]|--clean|--verbose|--libsuffix (32|64)|--help|--clang|--cmakedir /directory|--make
|
||||
(gmake|make)|--ccompiler(gcc|cc)|--withstaticlib|--unittesting|--clientunittesting|--withserver|--withoutsymbolversioning]"
|
||||
cleanup_and_exit
|
||||
}
|
||||
|
||||
cd ${BUILDDIR}
|
||||
|
||||
# the default CMake options:
|
||||
OPTIONS="--graphviz=${BUILDDIR}/libssh.dot"
|
||||
|
||||
# the default 'make' utility:
|
||||
MAKE="make"
|
||||
|
||||
while test -n "$1"; do
|
||||
PARAM="$1"
|
||||
ARG="$2"
|
||||
shift
|
||||
case ${PARAM} in
|
||||
*-*=*)
|
||||
ARG=${PARAM#*=}
|
||||
PARAM=${PARAM%%=*}
|
||||
set -- "----noarg=${PARAM}" "$@"
|
||||
esac
|
||||
case ${PARAM} in
|
||||
*-help|-h)
|
||||
#echo_help
|
||||
usage
|
||||
cleanup_and_exit
|
||||
;;
|
||||
*-build)
|
||||
DOMAKE="1"
|
||||
BUILD_TYPE="${ARG}"
|
||||
test -n "${BUILD_TYPE}" && shift
|
||||
;;
|
||||
*-clean)
|
||||
clean_build_dir
|
||||
cleanup_and_exit
|
||||
;;
|
||||
*-clang)
|
||||
OPTIONS="${OPTIONS} -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++"
|
||||
;;
|
||||
*-verbose)
|
||||
DOVERBOSE="1"
|
||||
;;
|
||||
*-memtest)
|
||||
OPTIONS="${OPTIONS} -DMEM_NULL_TESTS=ON"
|
||||
;;
|
||||
*-libsuffix)
|
||||
OPTIONS="${OPTIONS} -DLIB_SUFFIX=${ARG}"
|
||||
shift
|
||||
;;
|
||||
*-prefix)
|
||||
OPTIONS="${OPTIONS} -DCMAKE_INSTALL_PREFIX=${ARG}"
|
||||
shift
|
||||
;;
|
||||
*-sysconfdir)
|
||||
OPTIONS="${OPTIONS} -DSYSCONF_INSTALL_DIR=${ARG}"
|
||||
shift
|
||||
;;
|
||||
*-cmakedir)
|
||||
CMAKEDIR="${ARG}"
|
||||
shift
|
||||
;;
|
||||
*-make)
|
||||
MAKE="${ARG}"
|
||||
shift
|
||||
;;
|
||||
*-ccompiler)
|
||||
OPTIONS="${OPTIONS} -DCMAKE_C_COMPILER=${ARG}"
|
||||
shift
|
||||
;;
|
||||
*-withstaticlib)
|
||||
OPTIONS="${OPTIONS} -DWITH_STATIC_LIB=ON"
|
||||
;;
|
||||
*-unittesting)
|
||||
OPTIONS="${OPTIONS} -DUNIT_TESTING=ON"
|
||||
;;
|
||||
*-clientunittesting)
|
||||
OPTIONS="${OPTIONS} -DCLIENT_TESTING=ON"
|
||||
;;
|
||||
*-withserver)
|
||||
OPTIONS="${OPTIONS} -DWITH_SERVER=ON"
|
||||
;;
|
||||
*-withoutsymbolversioning)
|
||||
OPTIONS="${OPTIONS} -DWITH_SYMBOL_VERSIONING=OFF"
|
||||
;;
|
||||
*-finalrelease)
|
||||
OPTIONS="${OPTIONS} -DWITH_FINAL=ON"
|
||||
;;
|
||||
----noarg)
|
||||
echo "$ARG does not take an argument"
|
||||
cleanup_and_exit
|
||||
;;
|
||||
-*)
|
||||
echo Unknown Option "$PARAM". Exit.
|
||||
cleanup_and_exit 1
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "${DOMAKE}" == "1" ]; then
|
||||
OPTIONS="${OPTIONS} -DCMAKE_BUILD_TYPE=${BUILD_TYPE}"
|
||||
fi
|
||||
|
||||
if [ -n "${DOVERBOSE}" ]; then
|
||||
OPTIONS="${OPTIONS} -DCMAKE_VERBOSE_MAKEFILE=1"
|
||||
else
|
||||
OPTIONS="${OPTIONS} -DCMAKE_VERBOSE_MAKEFILE=0"
|
||||
fi
|
||||
|
||||
test -f "${BUILDDIR}/.build.log" && rm -f ${BUILDDIR}/.build.log
|
||||
touch ${BUILDDIR}/.build.log
|
||||
# log everything from here to .build.log
|
||||
exec 1> >(exec -a 'build logging tee' tee -a ${BUILDDIR}/.build.log) 2>&1
|
||||
echo "${HOST} started build at $(date)."
|
||||
echo
|
||||
|
||||
configure ${OPTIONS} "$@"
|
||||
|
||||
if [ -n "${DOMAKE}" ]; then
|
||||
test -n "${DOVERBOSE}" && compile VERBOSE=1 || compile
|
||||
fi
|
||||
|
||||
DOT=$(which dot 2>/dev/null)
|
||||
if [ -n "${DOT}" ]; then
|
||||
${DOT} -Tpng -o${BUILDDIR}/libssh.png ${BUILDDIR}/libssh.dot
|
||||
${DOT} -Tsvg -o${BUILDDIR}/libssh.svg ${BUILDDIR}/libssh.dot
|
||||
fi
|
||||
|
||||
exec >&0 2>&0 # so that the logging tee finishes
|
||||
sleep 1 # wait till tee terminates
|
||||
|
||||
cleanup_and_exit 0
|
||||
@@ -1 +1 @@
|
||||
4.8.3
|
||||
4.7.2
|
||||
@@ -1,415 +0,0 @@
|
||||
_ssh_log
|
||||
buffer_free
|
||||
buffer_get
|
||||
buffer_get_len
|
||||
buffer_new
|
||||
channel_accept_x11
|
||||
channel_change_pty_size
|
||||
channel_close
|
||||
channel_forward_accept
|
||||
channel_forward_cancel
|
||||
channel_forward_listen
|
||||
channel_free
|
||||
channel_get_exit_status
|
||||
channel_get_session
|
||||
channel_is_closed
|
||||
channel_is_eof
|
||||
channel_is_open
|
||||
channel_new
|
||||
channel_open_forward
|
||||
channel_open_session
|
||||
channel_poll
|
||||
channel_read
|
||||
channel_read_buffer
|
||||
channel_read_nonblocking
|
||||
channel_request_env
|
||||
channel_request_exec
|
||||
channel_request_pty
|
||||
channel_request_pty_size
|
||||
channel_request_send_signal
|
||||
channel_request_sftp
|
||||
channel_request_shell
|
||||
channel_request_subsystem
|
||||
channel_request_x11
|
||||
channel_select
|
||||
channel_send_eof
|
||||
channel_set_blocking
|
||||
channel_write
|
||||
channel_write_stderr
|
||||
privatekey_free
|
||||
privatekey_from_file
|
||||
publickey_free
|
||||
publickey_from_file
|
||||
publickey_from_privatekey
|
||||
publickey_to_string
|
||||
sftp_async_read
|
||||
sftp_async_read_begin
|
||||
sftp_attributes_free
|
||||
sftp_canonicalize_path
|
||||
sftp_chmod
|
||||
sftp_chown
|
||||
sftp_client_message_free
|
||||
sftp_client_message_get_data
|
||||
sftp_client_message_get_filename
|
||||
sftp_client_message_get_flags
|
||||
sftp_client_message_get_submessage
|
||||
sftp_client_message_get_type
|
||||
sftp_client_message_set_filename
|
||||
sftp_close
|
||||
sftp_closedir
|
||||
sftp_dir_eof
|
||||
sftp_extension_supported
|
||||
sftp_extensions_get_count
|
||||
sftp_extensions_get_data
|
||||
sftp_extensions_get_name
|
||||
sftp_file_set_blocking
|
||||
sftp_file_set_nonblocking
|
||||
sftp_free
|
||||
sftp_fstat
|
||||
sftp_fstatvfs
|
||||
sftp_fsync
|
||||
sftp_get_client_message
|
||||
sftp_get_error
|
||||
sftp_handle
|
||||
sftp_handle_alloc
|
||||
sftp_handle_remove
|
||||
sftp_init
|
||||
sftp_lstat
|
||||
sftp_mkdir
|
||||
sftp_new
|
||||
sftp_new_channel
|
||||
sftp_open
|
||||
sftp_opendir
|
||||
sftp_read
|
||||
sftp_readdir
|
||||
sftp_readlink
|
||||
sftp_rename
|
||||
sftp_reply_attr
|
||||
sftp_reply_data
|
||||
sftp_reply_handle
|
||||
sftp_reply_name
|
||||
sftp_reply_names
|
||||
sftp_reply_names_add
|
||||
sftp_reply_status
|
||||
sftp_rewind
|
||||
sftp_rmdir
|
||||
sftp_seek
|
||||
sftp_seek64
|
||||
sftp_send_client_message
|
||||
sftp_server_init
|
||||
sftp_server_new
|
||||
sftp_server_version
|
||||
sftp_setstat
|
||||
sftp_stat
|
||||
sftp_statvfs
|
||||
sftp_statvfs_free
|
||||
sftp_symlink
|
||||
sftp_tell
|
||||
sftp_tell64
|
||||
sftp_unlink
|
||||
sftp_utimes
|
||||
sftp_write
|
||||
ssh_accept
|
||||
ssh_add_channel_callbacks
|
||||
ssh_auth_list
|
||||
ssh_basename
|
||||
ssh_bind_accept
|
||||
ssh_bind_accept_fd
|
||||
ssh_bind_fd_toaccept
|
||||
ssh_bind_free
|
||||
ssh_bind_get_fd
|
||||
ssh_bind_listen
|
||||
ssh_bind_new
|
||||
ssh_bind_options_set
|
||||
ssh_bind_set_blocking
|
||||
ssh_bind_set_callbacks
|
||||
ssh_bind_set_fd
|
||||
ssh_blocking_flush
|
||||
ssh_buffer_add_data
|
||||
ssh_buffer_free
|
||||
ssh_buffer_get
|
||||
ssh_buffer_get_data
|
||||
ssh_buffer_get_len
|
||||
ssh_buffer_new
|
||||
ssh_buffer_reinit
|
||||
ssh_channel_accept_forward
|
||||
ssh_channel_accept_x11
|
||||
ssh_channel_cancel_forward
|
||||
ssh_channel_change_pty_size
|
||||
ssh_channel_close
|
||||
ssh_channel_free
|
||||
ssh_channel_get_exit_status
|
||||
ssh_channel_get_session
|
||||
ssh_channel_is_closed
|
||||
ssh_channel_is_eof
|
||||
ssh_channel_is_open
|
||||
ssh_channel_listen_forward
|
||||
ssh_channel_new
|
||||
ssh_channel_open_auth_agent
|
||||
ssh_channel_open_forward
|
||||
ssh_channel_open_reverse_forward
|
||||
ssh_channel_open_session
|
||||
ssh_channel_open_x11
|
||||
ssh_channel_poll
|
||||
ssh_channel_poll_timeout
|
||||
ssh_channel_read
|
||||
ssh_channel_read_nonblocking
|
||||
ssh_channel_read_timeout
|
||||
ssh_channel_request_auth_agent
|
||||
ssh_channel_request_env
|
||||
ssh_channel_request_exec
|
||||
ssh_channel_request_pty
|
||||
ssh_channel_request_pty_size
|
||||
ssh_channel_request_send_break
|
||||
ssh_channel_request_send_exit_signal
|
||||
ssh_channel_request_send_exit_status
|
||||
ssh_channel_request_send_signal
|
||||
ssh_channel_request_sftp
|
||||
ssh_channel_request_shell
|
||||
ssh_channel_request_subsystem
|
||||
ssh_channel_request_x11
|
||||
ssh_channel_select
|
||||
ssh_channel_send_eof
|
||||
ssh_channel_set_blocking
|
||||
ssh_channel_set_counter
|
||||
ssh_channel_window_size
|
||||
ssh_channel_write
|
||||
ssh_channel_write_stderr
|
||||
ssh_clean_pubkey_hash
|
||||
ssh_connect
|
||||
ssh_connector_free
|
||||
ssh_connector_new
|
||||
ssh_connector_set_in_channel
|
||||
ssh_connector_set_in_fd
|
||||
ssh_connector_set_out_channel
|
||||
ssh_connector_set_out_fd
|
||||
ssh_copyright
|
||||
ssh_dirname
|
||||
ssh_disconnect
|
||||
ssh_dump_knownhost
|
||||
ssh_event_add_connector
|
||||
ssh_event_add_fd
|
||||
ssh_event_add_session
|
||||
ssh_event_dopoll
|
||||
ssh_event_free
|
||||
ssh_event_new
|
||||
ssh_event_remove_connector
|
||||
ssh_event_remove_fd
|
||||
ssh_event_remove_session
|
||||
ssh_execute_message_callbacks
|
||||
ssh_finalize
|
||||
ssh_forward_accept
|
||||
ssh_forward_cancel
|
||||
ssh_forward_listen
|
||||
ssh_free
|
||||
ssh_get_cipher_in
|
||||
ssh_get_cipher_out
|
||||
ssh_get_clientbanner
|
||||
ssh_get_disconnect_message
|
||||
ssh_get_error
|
||||
ssh_get_error_code
|
||||
ssh_get_fd
|
||||
ssh_get_fingerprint_hash
|
||||
ssh_get_hexa
|
||||
ssh_get_hmac_in
|
||||
ssh_get_hmac_out
|
||||
ssh_get_issue_banner
|
||||
ssh_get_kex_algo
|
||||
ssh_get_log_callback
|
||||
ssh_get_log_level
|
||||
ssh_get_log_userdata
|
||||
ssh_get_openssh_version
|
||||
ssh_get_poll_flags
|
||||
ssh_get_pubkey
|
||||
ssh_get_pubkey_hash
|
||||
ssh_get_publickey
|
||||
ssh_get_publickey_hash
|
||||
ssh_get_random
|
||||
ssh_get_server_publickey
|
||||
ssh_get_serverbanner
|
||||
ssh_get_status
|
||||
ssh_get_version
|
||||
ssh_getpass
|
||||
ssh_gssapi_get_creds
|
||||
ssh_gssapi_set_creds
|
||||
ssh_handle_key_exchange
|
||||
ssh_init
|
||||
ssh_is_blocking
|
||||
ssh_is_connected
|
||||
ssh_is_server_known
|
||||
ssh_key_cmp
|
||||
ssh_key_free
|
||||
ssh_key_is_private
|
||||
ssh_key_is_public
|
||||
ssh_key_new
|
||||
ssh_key_type
|
||||
ssh_key_type_from_name
|
||||
ssh_key_type_to_char
|
||||
ssh_known_hosts_parse_line
|
||||
ssh_knownhosts_entry_free
|
||||
ssh_log
|
||||
ssh_message_auth_interactive_request
|
||||
ssh_message_auth_kbdint_is_response
|
||||
ssh_message_auth_password
|
||||
ssh_message_auth_pubkey
|
||||
ssh_message_auth_publickey
|
||||
ssh_message_auth_publickey_state
|
||||
ssh_message_auth_reply_pk_ok
|
||||
ssh_message_auth_reply_pk_ok_simple
|
||||
ssh_message_auth_reply_success
|
||||
ssh_message_auth_set_methods
|
||||
ssh_message_auth_user
|
||||
ssh_message_channel_request_channel
|
||||
ssh_message_channel_request_command
|
||||
ssh_message_channel_request_env_name
|
||||
ssh_message_channel_request_env_value
|
||||
ssh_message_channel_request_open_destination
|
||||
ssh_message_channel_request_open_destination_port
|
||||
ssh_message_channel_request_open_originator
|
||||
ssh_message_channel_request_open_originator_port
|
||||
ssh_message_channel_request_open_reply_accept
|
||||
ssh_message_channel_request_pty_height
|
||||
ssh_message_channel_request_pty_pxheight
|
||||
ssh_message_channel_request_pty_pxwidth
|
||||
ssh_message_channel_request_pty_term
|
||||
ssh_message_channel_request_pty_width
|
||||
ssh_message_channel_request_reply_success
|
||||
ssh_message_channel_request_subsystem
|
||||
ssh_message_channel_request_x11_auth_cookie
|
||||
ssh_message_channel_request_x11_auth_protocol
|
||||
ssh_message_channel_request_x11_screen_number
|
||||
ssh_message_channel_request_x11_single_connection
|
||||
ssh_message_free
|
||||
ssh_message_get
|
||||
ssh_message_global_request_address
|
||||
ssh_message_global_request_port
|
||||
ssh_message_global_request_reply_success
|
||||
ssh_message_reply_default
|
||||
ssh_message_retrieve
|
||||
ssh_message_service_reply_success
|
||||
ssh_message_service_service
|
||||
ssh_message_subtype
|
||||
ssh_message_type
|
||||
ssh_mkdir
|
||||
ssh_new
|
||||
ssh_options_copy
|
||||
ssh_options_get
|
||||
ssh_options_get_port
|
||||
ssh_options_getopt
|
||||
ssh_options_parse_config
|
||||
ssh_options_set
|
||||
ssh_pcap_file_close
|
||||
ssh_pcap_file_free
|
||||
ssh_pcap_file_new
|
||||
ssh_pcap_file_open
|
||||
ssh_pki_copy_cert_to_privkey
|
||||
ssh_pki_export_privkey_base64
|
||||
ssh_pki_export_privkey_file
|
||||
ssh_pki_export_privkey_to_pubkey
|
||||
ssh_pki_export_pubkey_base64
|
||||
ssh_pki_export_pubkey_file
|
||||
ssh_pki_generate
|
||||
ssh_pki_import_cert_base64
|
||||
ssh_pki_import_cert_file
|
||||
ssh_pki_import_privkey_base64
|
||||
ssh_pki_import_privkey_file
|
||||
ssh_pki_import_pubkey_base64
|
||||
ssh_pki_import_pubkey_file
|
||||
ssh_pki_key_ecdsa_name
|
||||
ssh_print_hash
|
||||
ssh_print_hexa
|
||||
ssh_privatekey_type
|
||||
ssh_publickey_to_file
|
||||
ssh_remove_channel_callbacks
|
||||
ssh_scp_accept_request
|
||||
ssh_scp_close
|
||||
ssh_scp_deny_request
|
||||
ssh_scp_free
|
||||
ssh_scp_init
|
||||
ssh_scp_leave_directory
|
||||
ssh_scp_new
|
||||
ssh_scp_pull_request
|
||||
ssh_scp_push_directory
|
||||
ssh_scp_push_file
|
||||
ssh_scp_push_file64
|
||||
ssh_scp_read
|
||||
ssh_scp_request_get_filename
|
||||
ssh_scp_request_get_permissions
|
||||
ssh_scp_request_get_size
|
||||
ssh_scp_request_get_size64
|
||||
ssh_scp_request_get_warning
|
||||
ssh_scp_write
|
||||
ssh_select
|
||||
ssh_send_debug
|
||||
ssh_send_ignore
|
||||
ssh_send_keepalive
|
||||
ssh_server_init_kex
|
||||
ssh_service_request
|
||||
ssh_session_export_known_hosts_entry
|
||||
ssh_session_has_known_hosts_entry
|
||||
ssh_session_is_known_server
|
||||
ssh_session_update_known_hosts
|
||||
ssh_set_agent_channel
|
||||
ssh_set_agent_socket
|
||||
ssh_set_auth_methods
|
||||
ssh_set_blocking
|
||||
ssh_set_callbacks
|
||||
ssh_set_channel_callbacks
|
||||
ssh_set_counters
|
||||
ssh_set_fd_except
|
||||
ssh_set_fd_toread
|
||||
ssh_set_fd_towrite
|
||||
ssh_set_log_callback
|
||||
ssh_set_log_level
|
||||
ssh_set_log_userdata
|
||||
ssh_set_message_callback
|
||||
ssh_set_pcap_file
|
||||
ssh_set_server_callbacks
|
||||
ssh_silent_disconnect
|
||||
ssh_string_burn
|
||||
ssh_string_copy
|
||||
ssh_string_data
|
||||
ssh_string_fill
|
||||
ssh_string_free
|
||||
ssh_string_free_char
|
||||
ssh_string_from_char
|
||||
ssh_string_get_char
|
||||
ssh_string_len
|
||||
ssh_string_new
|
||||
ssh_string_to_char
|
||||
ssh_threads_get_noop
|
||||
ssh_threads_get_pthread
|
||||
ssh_threads_set_callbacks
|
||||
ssh_try_publickey_from_file
|
||||
ssh_userauth_agent
|
||||
ssh_userauth_agent_pubkey
|
||||
ssh_userauth_autopubkey
|
||||
ssh_userauth_gssapi
|
||||
ssh_userauth_kbdint
|
||||
ssh_userauth_kbdint_getanswer
|
||||
ssh_userauth_kbdint_getinstruction
|
||||
ssh_userauth_kbdint_getname
|
||||
ssh_userauth_kbdint_getnanswers
|
||||
ssh_userauth_kbdint_getnprompts
|
||||
ssh_userauth_kbdint_getprompt
|
||||
ssh_userauth_kbdint_setanswer
|
||||
ssh_userauth_list
|
||||
ssh_userauth_none
|
||||
ssh_userauth_offer_pubkey
|
||||
ssh_userauth_password
|
||||
ssh_userauth_privatekey_file
|
||||
ssh_userauth_pubkey
|
||||
ssh_userauth_publickey
|
||||
ssh_userauth_publickey_auto
|
||||
ssh_userauth_try_publickey
|
||||
ssh_version
|
||||
ssh_write_knownhost
|
||||
string_burn
|
||||
string_copy
|
||||
string_data
|
||||
string_fill
|
||||
string_free
|
||||
string_from_char
|
||||
string_len
|
||||
string_new
|
||||
string_to_char
|
||||
@@ -1,415 +0,0 @@
|
||||
_ssh_log
|
||||
buffer_free
|
||||
buffer_get
|
||||
buffer_get_len
|
||||
buffer_new
|
||||
channel_accept_x11
|
||||
channel_change_pty_size
|
||||
channel_close
|
||||
channel_forward_accept
|
||||
channel_forward_cancel
|
||||
channel_forward_listen
|
||||
channel_free
|
||||
channel_get_exit_status
|
||||
channel_get_session
|
||||
channel_is_closed
|
||||
channel_is_eof
|
||||
channel_is_open
|
||||
channel_new
|
||||
channel_open_forward
|
||||
channel_open_session
|
||||
channel_poll
|
||||
channel_read
|
||||
channel_read_buffer
|
||||
channel_read_nonblocking
|
||||
channel_request_env
|
||||
channel_request_exec
|
||||
channel_request_pty
|
||||
channel_request_pty_size
|
||||
channel_request_send_signal
|
||||
channel_request_sftp
|
||||
channel_request_shell
|
||||
channel_request_subsystem
|
||||
channel_request_x11
|
||||
channel_select
|
||||
channel_send_eof
|
||||
channel_set_blocking
|
||||
channel_write
|
||||
channel_write_stderr
|
||||
privatekey_free
|
||||
privatekey_from_file
|
||||
publickey_free
|
||||
publickey_from_file
|
||||
publickey_from_privatekey
|
||||
publickey_to_string
|
||||
sftp_async_read
|
||||
sftp_async_read_begin
|
||||
sftp_attributes_free
|
||||
sftp_canonicalize_path
|
||||
sftp_chmod
|
||||
sftp_chown
|
||||
sftp_client_message_free
|
||||
sftp_client_message_get_data
|
||||
sftp_client_message_get_filename
|
||||
sftp_client_message_get_flags
|
||||
sftp_client_message_get_submessage
|
||||
sftp_client_message_get_type
|
||||
sftp_client_message_set_filename
|
||||
sftp_close
|
||||
sftp_closedir
|
||||
sftp_dir_eof
|
||||
sftp_extension_supported
|
||||
sftp_extensions_get_count
|
||||
sftp_extensions_get_data
|
||||
sftp_extensions_get_name
|
||||
sftp_file_set_blocking
|
||||
sftp_file_set_nonblocking
|
||||
sftp_free
|
||||
sftp_fstat
|
||||
sftp_fstatvfs
|
||||
sftp_fsync
|
||||
sftp_get_client_message
|
||||
sftp_get_error
|
||||
sftp_handle
|
||||
sftp_handle_alloc
|
||||
sftp_handle_remove
|
||||
sftp_init
|
||||
sftp_lstat
|
||||
sftp_mkdir
|
||||
sftp_new
|
||||
sftp_new_channel
|
||||
sftp_open
|
||||
sftp_opendir
|
||||
sftp_read
|
||||
sftp_readdir
|
||||
sftp_readlink
|
||||
sftp_rename
|
||||
sftp_reply_attr
|
||||
sftp_reply_data
|
||||
sftp_reply_handle
|
||||
sftp_reply_name
|
||||
sftp_reply_names
|
||||
sftp_reply_names_add
|
||||
sftp_reply_status
|
||||
sftp_rewind
|
||||
sftp_rmdir
|
||||
sftp_seek
|
||||
sftp_seek64
|
||||
sftp_send_client_message
|
||||
sftp_server_init
|
||||
sftp_server_new
|
||||
sftp_server_version
|
||||
sftp_setstat
|
||||
sftp_stat
|
||||
sftp_statvfs
|
||||
sftp_statvfs_free
|
||||
sftp_symlink
|
||||
sftp_tell
|
||||
sftp_tell64
|
||||
sftp_unlink
|
||||
sftp_utimes
|
||||
sftp_write
|
||||
ssh_accept
|
||||
ssh_add_channel_callbacks
|
||||
ssh_auth_list
|
||||
ssh_basename
|
||||
ssh_bind_accept
|
||||
ssh_bind_accept_fd
|
||||
ssh_bind_fd_toaccept
|
||||
ssh_bind_free
|
||||
ssh_bind_get_fd
|
||||
ssh_bind_listen
|
||||
ssh_bind_new
|
||||
ssh_bind_options_set
|
||||
ssh_bind_set_blocking
|
||||
ssh_bind_set_callbacks
|
||||
ssh_bind_set_fd
|
||||
ssh_blocking_flush
|
||||
ssh_buffer_add_data
|
||||
ssh_buffer_free
|
||||
ssh_buffer_get
|
||||
ssh_buffer_get_data
|
||||
ssh_buffer_get_len
|
||||
ssh_buffer_new
|
||||
ssh_buffer_reinit
|
||||
ssh_channel_accept_forward
|
||||
ssh_channel_accept_x11
|
||||
ssh_channel_cancel_forward
|
||||
ssh_channel_change_pty_size
|
||||
ssh_channel_close
|
||||
ssh_channel_free
|
||||
ssh_channel_get_exit_status
|
||||
ssh_channel_get_session
|
||||
ssh_channel_is_closed
|
||||
ssh_channel_is_eof
|
||||
ssh_channel_is_open
|
||||
ssh_channel_listen_forward
|
||||
ssh_channel_new
|
||||
ssh_channel_open_auth_agent
|
||||
ssh_channel_open_forward
|
||||
ssh_channel_open_reverse_forward
|
||||
ssh_channel_open_session
|
||||
ssh_channel_open_x11
|
||||
ssh_channel_poll
|
||||
ssh_channel_poll_timeout
|
||||
ssh_channel_read
|
||||
ssh_channel_read_nonblocking
|
||||
ssh_channel_read_timeout
|
||||
ssh_channel_request_auth_agent
|
||||
ssh_channel_request_env
|
||||
ssh_channel_request_exec
|
||||
ssh_channel_request_pty
|
||||
ssh_channel_request_pty_size
|
||||
ssh_channel_request_send_break
|
||||
ssh_channel_request_send_exit_signal
|
||||
ssh_channel_request_send_exit_status
|
||||
ssh_channel_request_send_signal
|
||||
ssh_channel_request_sftp
|
||||
ssh_channel_request_shell
|
||||
ssh_channel_request_subsystem
|
||||
ssh_channel_request_x11
|
||||
ssh_channel_select
|
||||
ssh_channel_send_eof
|
||||
ssh_channel_set_blocking
|
||||
ssh_channel_set_counter
|
||||
ssh_channel_window_size
|
||||
ssh_channel_write
|
||||
ssh_channel_write_stderr
|
||||
ssh_clean_pubkey_hash
|
||||
ssh_connect
|
||||
ssh_connector_free
|
||||
ssh_connector_new
|
||||
ssh_connector_set_in_channel
|
||||
ssh_connector_set_in_fd
|
||||
ssh_connector_set_out_channel
|
||||
ssh_connector_set_out_fd
|
||||
ssh_copyright
|
||||
ssh_dirname
|
||||
ssh_disconnect
|
||||
ssh_dump_knownhost
|
||||
ssh_event_add_connector
|
||||
ssh_event_add_fd
|
||||
ssh_event_add_session
|
||||
ssh_event_dopoll
|
||||
ssh_event_free
|
||||
ssh_event_new
|
||||
ssh_event_remove_connector
|
||||
ssh_event_remove_fd
|
||||
ssh_event_remove_session
|
||||
ssh_execute_message_callbacks
|
||||
ssh_finalize
|
||||
ssh_forward_accept
|
||||
ssh_forward_cancel
|
||||
ssh_forward_listen
|
||||
ssh_free
|
||||
ssh_get_cipher_in
|
||||
ssh_get_cipher_out
|
||||
ssh_get_clientbanner
|
||||
ssh_get_disconnect_message
|
||||
ssh_get_error
|
||||
ssh_get_error_code
|
||||
ssh_get_fd
|
||||
ssh_get_fingerprint_hash
|
||||
ssh_get_hexa
|
||||
ssh_get_hmac_in
|
||||
ssh_get_hmac_out
|
||||
ssh_get_issue_banner
|
||||
ssh_get_kex_algo
|
||||
ssh_get_log_callback
|
||||
ssh_get_log_level
|
||||
ssh_get_log_userdata
|
||||
ssh_get_openssh_version
|
||||
ssh_get_poll_flags
|
||||
ssh_get_pubkey
|
||||
ssh_get_pubkey_hash
|
||||
ssh_get_publickey
|
||||
ssh_get_publickey_hash
|
||||
ssh_get_random
|
||||
ssh_get_server_publickey
|
||||
ssh_get_serverbanner
|
||||
ssh_get_status
|
||||
ssh_get_version
|
||||
ssh_getpass
|
||||
ssh_gssapi_get_creds
|
||||
ssh_gssapi_set_creds
|
||||
ssh_handle_key_exchange
|
||||
ssh_init
|
||||
ssh_is_blocking
|
||||
ssh_is_connected
|
||||
ssh_is_server_known
|
||||
ssh_key_cmp
|
||||
ssh_key_free
|
||||
ssh_key_is_private
|
||||
ssh_key_is_public
|
||||
ssh_key_new
|
||||
ssh_key_type
|
||||
ssh_key_type_from_name
|
||||
ssh_key_type_to_char
|
||||
ssh_known_hosts_parse_line
|
||||
ssh_knownhosts_entry_free
|
||||
ssh_log
|
||||
ssh_message_auth_interactive_request
|
||||
ssh_message_auth_kbdint_is_response
|
||||
ssh_message_auth_password
|
||||
ssh_message_auth_pubkey
|
||||
ssh_message_auth_publickey
|
||||
ssh_message_auth_publickey_state
|
||||
ssh_message_auth_reply_pk_ok
|
||||
ssh_message_auth_reply_pk_ok_simple
|
||||
ssh_message_auth_reply_success
|
||||
ssh_message_auth_set_methods
|
||||
ssh_message_auth_user
|
||||
ssh_message_channel_request_channel
|
||||
ssh_message_channel_request_command
|
||||
ssh_message_channel_request_env_name
|
||||
ssh_message_channel_request_env_value
|
||||
ssh_message_channel_request_open_destination
|
||||
ssh_message_channel_request_open_destination_port
|
||||
ssh_message_channel_request_open_originator
|
||||
ssh_message_channel_request_open_originator_port
|
||||
ssh_message_channel_request_open_reply_accept
|
||||
ssh_message_channel_request_pty_height
|
||||
ssh_message_channel_request_pty_pxheight
|
||||
ssh_message_channel_request_pty_pxwidth
|
||||
ssh_message_channel_request_pty_term
|
||||
ssh_message_channel_request_pty_width
|
||||
ssh_message_channel_request_reply_success
|
||||
ssh_message_channel_request_subsystem
|
||||
ssh_message_channel_request_x11_auth_cookie
|
||||
ssh_message_channel_request_x11_auth_protocol
|
||||
ssh_message_channel_request_x11_screen_number
|
||||
ssh_message_channel_request_x11_single_connection
|
||||
ssh_message_free
|
||||
ssh_message_get
|
||||
ssh_message_global_request_address
|
||||
ssh_message_global_request_port
|
||||
ssh_message_global_request_reply_success
|
||||
ssh_message_reply_default
|
||||
ssh_message_retrieve
|
||||
ssh_message_service_reply_success
|
||||
ssh_message_service_service
|
||||
ssh_message_subtype
|
||||
ssh_message_type
|
||||
ssh_mkdir
|
||||
ssh_new
|
||||
ssh_options_copy
|
||||
ssh_options_get
|
||||
ssh_options_get_port
|
||||
ssh_options_getopt
|
||||
ssh_options_parse_config
|
||||
ssh_options_set
|
||||
ssh_pcap_file_close
|
||||
ssh_pcap_file_free
|
||||
ssh_pcap_file_new
|
||||
ssh_pcap_file_open
|
||||
ssh_pki_copy_cert_to_privkey
|
||||
ssh_pki_export_privkey_base64
|
||||
ssh_pki_export_privkey_file
|
||||
ssh_pki_export_privkey_to_pubkey
|
||||
ssh_pki_export_pubkey_base64
|
||||
ssh_pki_export_pubkey_file
|
||||
ssh_pki_generate
|
||||
ssh_pki_import_cert_base64
|
||||
ssh_pki_import_cert_file
|
||||
ssh_pki_import_privkey_base64
|
||||
ssh_pki_import_privkey_file
|
||||
ssh_pki_import_pubkey_base64
|
||||
ssh_pki_import_pubkey_file
|
||||
ssh_pki_key_ecdsa_name
|
||||
ssh_print_hash
|
||||
ssh_print_hexa
|
||||
ssh_privatekey_type
|
||||
ssh_publickey_to_file
|
||||
ssh_remove_channel_callbacks
|
||||
ssh_scp_accept_request
|
||||
ssh_scp_close
|
||||
ssh_scp_deny_request
|
||||
ssh_scp_free
|
||||
ssh_scp_init
|
||||
ssh_scp_leave_directory
|
||||
ssh_scp_new
|
||||
ssh_scp_pull_request
|
||||
ssh_scp_push_directory
|
||||
ssh_scp_push_file
|
||||
ssh_scp_push_file64
|
||||
ssh_scp_read
|
||||
ssh_scp_request_get_filename
|
||||
ssh_scp_request_get_permissions
|
||||
ssh_scp_request_get_size
|
||||
ssh_scp_request_get_size64
|
||||
ssh_scp_request_get_warning
|
||||
ssh_scp_write
|
||||
ssh_select
|
||||
ssh_send_debug
|
||||
ssh_send_ignore
|
||||
ssh_send_keepalive
|
||||
ssh_server_init_kex
|
||||
ssh_service_request
|
||||
ssh_session_export_known_hosts_entry
|
||||
ssh_session_has_known_hosts_entry
|
||||
ssh_session_is_known_server
|
||||
ssh_session_update_known_hosts
|
||||
ssh_set_agent_channel
|
||||
ssh_set_agent_socket
|
||||
ssh_set_auth_methods
|
||||
ssh_set_blocking
|
||||
ssh_set_callbacks
|
||||
ssh_set_channel_callbacks
|
||||
ssh_set_counters
|
||||
ssh_set_fd_except
|
||||
ssh_set_fd_toread
|
||||
ssh_set_fd_towrite
|
||||
ssh_set_log_callback
|
||||
ssh_set_log_level
|
||||
ssh_set_log_userdata
|
||||
ssh_set_message_callback
|
||||
ssh_set_pcap_file
|
||||
ssh_set_server_callbacks
|
||||
ssh_silent_disconnect
|
||||
ssh_string_burn
|
||||
ssh_string_copy
|
||||
ssh_string_data
|
||||
ssh_string_fill
|
||||
ssh_string_free
|
||||
ssh_string_free_char
|
||||
ssh_string_from_char
|
||||
ssh_string_get_char
|
||||
ssh_string_len
|
||||
ssh_string_new
|
||||
ssh_string_to_char
|
||||
ssh_threads_get_noop
|
||||
ssh_threads_get_pthread
|
||||
ssh_threads_set_callbacks
|
||||
ssh_try_publickey_from_file
|
||||
ssh_userauth_agent
|
||||
ssh_userauth_agent_pubkey
|
||||
ssh_userauth_autopubkey
|
||||
ssh_userauth_gssapi
|
||||
ssh_userauth_kbdint
|
||||
ssh_userauth_kbdint_getanswer
|
||||
ssh_userauth_kbdint_getinstruction
|
||||
ssh_userauth_kbdint_getname
|
||||
ssh_userauth_kbdint_getnanswers
|
||||
ssh_userauth_kbdint_getnprompts
|
||||
ssh_userauth_kbdint_getprompt
|
||||
ssh_userauth_kbdint_setanswer
|
||||
ssh_userauth_list
|
||||
ssh_userauth_none
|
||||
ssh_userauth_offer_pubkey
|
||||
ssh_userauth_password
|
||||
ssh_userauth_privatekey_file
|
||||
ssh_userauth_pubkey
|
||||
ssh_userauth_publickey
|
||||
ssh_userauth_publickey_auto
|
||||
ssh_userauth_try_publickey
|
||||
ssh_version
|
||||
ssh_write_knownhost
|
||||
string_burn
|
||||
string_copy
|
||||
string_data
|
||||
string_fill
|
||||
string_free
|
||||
string_from_char
|
||||
string_len
|
||||
string_new
|
||||
string_to_char
|
||||
@@ -1,419 +0,0 @@
|
||||
_ssh_log
|
||||
buffer_free
|
||||
buffer_get
|
||||
buffer_get_len
|
||||
buffer_new
|
||||
channel_accept_x11
|
||||
channel_change_pty_size
|
||||
channel_close
|
||||
channel_forward_accept
|
||||
channel_forward_cancel
|
||||
channel_forward_listen
|
||||
channel_free
|
||||
channel_get_exit_status
|
||||
channel_get_session
|
||||
channel_is_closed
|
||||
channel_is_eof
|
||||
channel_is_open
|
||||
channel_new
|
||||
channel_open_forward
|
||||
channel_open_session
|
||||
channel_poll
|
||||
channel_read
|
||||
channel_read_buffer
|
||||
channel_read_nonblocking
|
||||
channel_request_env
|
||||
channel_request_exec
|
||||
channel_request_pty
|
||||
channel_request_pty_size
|
||||
channel_request_send_signal
|
||||
channel_request_sftp
|
||||
channel_request_shell
|
||||
channel_request_subsystem
|
||||
channel_request_x11
|
||||
channel_select
|
||||
channel_send_eof
|
||||
channel_set_blocking
|
||||
channel_write
|
||||
channel_write_stderr
|
||||
privatekey_free
|
||||
privatekey_from_file
|
||||
publickey_free
|
||||
publickey_from_file
|
||||
publickey_from_privatekey
|
||||
publickey_to_string
|
||||
sftp_async_read
|
||||
sftp_async_read_begin
|
||||
sftp_attributes_free
|
||||
sftp_canonicalize_path
|
||||
sftp_chmod
|
||||
sftp_chown
|
||||
sftp_client_message_free
|
||||
sftp_client_message_get_data
|
||||
sftp_client_message_get_filename
|
||||
sftp_client_message_get_flags
|
||||
sftp_client_message_get_submessage
|
||||
sftp_client_message_get_type
|
||||
sftp_client_message_set_filename
|
||||
sftp_close
|
||||
sftp_closedir
|
||||
sftp_dir_eof
|
||||
sftp_extension_supported
|
||||
sftp_extensions_get_count
|
||||
sftp_extensions_get_data
|
||||
sftp_extensions_get_name
|
||||
sftp_file_set_blocking
|
||||
sftp_file_set_nonblocking
|
||||
sftp_free
|
||||
sftp_fstat
|
||||
sftp_fstatvfs
|
||||
sftp_fsync
|
||||
sftp_get_client_message
|
||||
sftp_get_error
|
||||
sftp_handle
|
||||
sftp_handle_alloc
|
||||
sftp_handle_remove
|
||||
sftp_init
|
||||
sftp_lstat
|
||||
sftp_mkdir
|
||||
sftp_new
|
||||
sftp_new_channel
|
||||
sftp_open
|
||||
sftp_opendir
|
||||
sftp_read
|
||||
sftp_readdir
|
||||
sftp_readlink
|
||||
sftp_rename
|
||||
sftp_reply_attr
|
||||
sftp_reply_data
|
||||
sftp_reply_handle
|
||||
sftp_reply_name
|
||||
sftp_reply_names
|
||||
sftp_reply_names_add
|
||||
sftp_reply_status
|
||||
sftp_rewind
|
||||
sftp_rmdir
|
||||
sftp_seek
|
||||
sftp_seek64
|
||||
sftp_send_client_message
|
||||
sftp_server_free
|
||||
sftp_server_init
|
||||
sftp_server_new
|
||||
sftp_server_version
|
||||
sftp_setstat
|
||||
sftp_stat
|
||||
sftp_statvfs
|
||||
sftp_statvfs_free
|
||||
sftp_symlink
|
||||
sftp_tell
|
||||
sftp_tell64
|
||||
sftp_unlink
|
||||
sftp_utimes
|
||||
sftp_write
|
||||
ssh_accept
|
||||
ssh_add_channel_callbacks
|
||||
ssh_auth_list
|
||||
ssh_basename
|
||||
ssh_bind_accept
|
||||
ssh_bind_accept_fd
|
||||
ssh_bind_fd_toaccept
|
||||
ssh_bind_free
|
||||
ssh_bind_get_fd
|
||||
ssh_bind_listen
|
||||
ssh_bind_new
|
||||
ssh_bind_options_parse_config
|
||||
ssh_bind_options_set
|
||||
ssh_bind_set_blocking
|
||||
ssh_bind_set_callbacks
|
||||
ssh_bind_set_fd
|
||||
ssh_blocking_flush
|
||||
ssh_buffer_add_data
|
||||
ssh_buffer_free
|
||||
ssh_buffer_get
|
||||
ssh_buffer_get_data
|
||||
ssh_buffer_get_len
|
||||
ssh_buffer_new
|
||||
ssh_buffer_reinit
|
||||
ssh_channel_accept_forward
|
||||
ssh_channel_accept_x11
|
||||
ssh_channel_cancel_forward
|
||||
ssh_channel_change_pty_size
|
||||
ssh_channel_close
|
||||
ssh_channel_free
|
||||
ssh_channel_get_exit_status
|
||||
ssh_channel_get_session
|
||||
ssh_channel_is_closed
|
||||
ssh_channel_is_eof
|
||||
ssh_channel_is_open
|
||||
ssh_channel_listen_forward
|
||||
ssh_channel_new
|
||||
ssh_channel_open_auth_agent
|
||||
ssh_channel_open_forward
|
||||
ssh_channel_open_forward_unix
|
||||
ssh_channel_open_reverse_forward
|
||||
ssh_channel_open_session
|
||||
ssh_channel_open_x11
|
||||
ssh_channel_poll
|
||||
ssh_channel_poll_timeout
|
||||
ssh_channel_read
|
||||
ssh_channel_read_nonblocking
|
||||
ssh_channel_read_timeout
|
||||
ssh_channel_request_auth_agent
|
||||
ssh_channel_request_env
|
||||
ssh_channel_request_exec
|
||||
ssh_channel_request_pty
|
||||
ssh_channel_request_pty_size
|
||||
ssh_channel_request_send_break
|
||||
ssh_channel_request_send_exit_signal
|
||||
ssh_channel_request_send_exit_status
|
||||
ssh_channel_request_send_signal
|
||||
ssh_channel_request_sftp
|
||||
ssh_channel_request_shell
|
||||
ssh_channel_request_subsystem
|
||||
ssh_channel_request_x11
|
||||
ssh_channel_select
|
||||
ssh_channel_send_eof
|
||||
ssh_channel_set_blocking
|
||||
ssh_channel_set_counter
|
||||
ssh_channel_window_size
|
||||
ssh_channel_write
|
||||
ssh_channel_write_stderr
|
||||
ssh_clean_pubkey_hash
|
||||
ssh_connect
|
||||
ssh_connector_free
|
||||
ssh_connector_new
|
||||
ssh_connector_set_in_channel
|
||||
ssh_connector_set_in_fd
|
||||
ssh_connector_set_out_channel
|
||||
ssh_connector_set_out_fd
|
||||
ssh_copyright
|
||||
ssh_dirname
|
||||
ssh_disconnect
|
||||
ssh_dump_knownhost
|
||||
ssh_event_add_connector
|
||||
ssh_event_add_fd
|
||||
ssh_event_add_session
|
||||
ssh_event_dopoll
|
||||
ssh_event_free
|
||||
ssh_event_new
|
||||
ssh_event_remove_connector
|
||||
ssh_event_remove_fd
|
||||
ssh_event_remove_session
|
||||
ssh_execute_message_callbacks
|
||||
ssh_finalize
|
||||
ssh_forward_accept
|
||||
ssh_forward_cancel
|
||||
ssh_forward_listen
|
||||
ssh_free
|
||||
ssh_get_cipher_in
|
||||
ssh_get_cipher_out
|
||||
ssh_get_clientbanner
|
||||
ssh_get_disconnect_message
|
||||
ssh_get_error
|
||||
ssh_get_error_code
|
||||
ssh_get_fd
|
||||
ssh_get_fingerprint_hash
|
||||
ssh_get_hexa
|
||||
ssh_get_hmac_in
|
||||
ssh_get_hmac_out
|
||||
ssh_get_issue_banner
|
||||
ssh_get_kex_algo
|
||||
ssh_get_log_callback
|
||||
ssh_get_log_level
|
||||
ssh_get_log_userdata
|
||||
ssh_get_openssh_version
|
||||
ssh_get_poll_flags
|
||||
ssh_get_pubkey
|
||||
ssh_get_pubkey_hash
|
||||
ssh_get_publickey
|
||||
ssh_get_publickey_hash
|
||||
ssh_get_random
|
||||
ssh_get_server_publickey
|
||||
ssh_get_serverbanner
|
||||
ssh_get_status
|
||||
ssh_get_version
|
||||
ssh_getpass
|
||||
ssh_gssapi_get_creds
|
||||
ssh_gssapi_set_creds
|
||||
ssh_handle_key_exchange
|
||||
ssh_init
|
||||
ssh_is_blocking
|
||||
ssh_is_connected
|
||||
ssh_is_server_known
|
||||
ssh_key_cmp
|
||||
ssh_key_free
|
||||
ssh_key_is_private
|
||||
ssh_key_is_public
|
||||
ssh_key_new
|
||||
ssh_key_type
|
||||
ssh_key_type_from_name
|
||||
ssh_key_type_to_char
|
||||
ssh_known_hosts_parse_line
|
||||
ssh_knownhosts_entry_free
|
||||
ssh_log
|
||||
ssh_message_auth_interactive_request
|
||||
ssh_message_auth_kbdint_is_response
|
||||
ssh_message_auth_password
|
||||
ssh_message_auth_pubkey
|
||||
ssh_message_auth_publickey
|
||||
ssh_message_auth_publickey_state
|
||||
ssh_message_auth_reply_pk_ok
|
||||
ssh_message_auth_reply_pk_ok_simple
|
||||
ssh_message_auth_reply_success
|
||||
ssh_message_auth_set_methods
|
||||
ssh_message_auth_user
|
||||
ssh_message_channel_request_channel
|
||||
ssh_message_channel_request_command
|
||||
ssh_message_channel_request_env_name
|
||||
ssh_message_channel_request_env_value
|
||||
ssh_message_channel_request_open_destination
|
||||
ssh_message_channel_request_open_destination_port
|
||||
ssh_message_channel_request_open_originator
|
||||
ssh_message_channel_request_open_originator_port
|
||||
ssh_message_channel_request_open_reply_accept
|
||||
ssh_message_channel_request_open_reply_accept_channel
|
||||
ssh_message_channel_request_pty_height
|
||||
ssh_message_channel_request_pty_pxheight
|
||||
ssh_message_channel_request_pty_pxwidth
|
||||
ssh_message_channel_request_pty_term
|
||||
ssh_message_channel_request_pty_width
|
||||
ssh_message_channel_request_reply_success
|
||||
ssh_message_channel_request_subsystem
|
||||
ssh_message_channel_request_x11_auth_cookie
|
||||
ssh_message_channel_request_x11_auth_protocol
|
||||
ssh_message_channel_request_x11_screen_number
|
||||
ssh_message_channel_request_x11_single_connection
|
||||
ssh_message_free
|
||||
ssh_message_get
|
||||
ssh_message_global_request_address
|
||||
ssh_message_global_request_port
|
||||
ssh_message_global_request_reply_success
|
||||
ssh_message_reply_default
|
||||
ssh_message_retrieve
|
||||
ssh_message_service_reply_success
|
||||
ssh_message_service_service
|
||||
ssh_message_subtype
|
||||
ssh_message_type
|
||||
ssh_mkdir
|
||||
ssh_new
|
||||
ssh_options_copy
|
||||
ssh_options_get
|
||||
ssh_options_get_port
|
||||
ssh_options_getopt
|
||||
ssh_options_parse_config
|
||||
ssh_options_set
|
||||
ssh_pcap_file_close
|
||||
ssh_pcap_file_free
|
||||
ssh_pcap_file_new
|
||||
ssh_pcap_file_open
|
||||
ssh_pki_copy_cert_to_privkey
|
||||
ssh_pki_export_privkey_base64
|
||||
ssh_pki_export_privkey_file
|
||||
ssh_pki_export_privkey_to_pubkey
|
||||
ssh_pki_export_pubkey_base64
|
||||
ssh_pki_export_pubkey_file
|
||||
ssh_pki_generate
|
||||
ssh_pki_import_cert_base64
|
||||
ssh_pki_import_cert_file
|
||||
ssh_pki_import_privkey_base64
|
||||
ssh_pki_import_privkey_file
|
||||
ssh_pki_import_pubkey_base64
|
||||
ssh_pki_import_pubkey_file
|
||||
ssh_pki_key_ecdsa_name
|
||||
ssh_print_hash
|
||||
ssh_print_hexa
|
||||
ssh_privatekey_type
|
||||
ssh_publickey_to_file
|
||||
ssh_remove_channel_callbacks
|
||||
ssh_scp_accept_request
|
||||
ssh_scp_close
|
||||
ssh_scp_deny_request
|
||||
ssh_scp_free
|
||||
ssh_scp_init
|
||||
ssh_scp_leave_directory
|
||||
ssh_scp_new
|
||||
ssh_scp_pull_request
|
||||
ssh_scp_push_directory
|
||||
ssh_scp_push_file
|
||||
ssh_scp_push_file64
|
||||
ssh_scp_read
|
||||
ssh_scp_request_get_filename
|
||||
ssh_scp_request_get_permissions
|
||||
ssh_scp_request_get_size
|
||||
ssh_scp_request_get_size64
|
||||
ssh_scp_request_get_warning
|
||||
ssh_scp_write
|
||||
ssh_select
|
||||
ssh_send_debug
|
||||
ssh_send_ignore
|
||||
ssh_send_keepalive
|
||||
ssh_server_init_kex
|
||||
ssh_service_request
|
||||
ssh_session_export_known_hosts_entry
|
||||
ssh_session_has_known_hosts_entry
|
||||
ssh_session_is_known_server
|
||||
ssh_session_update_known_hosts
|
||||
ssh_set_agent_channel
|
||||
ssh_set_agent_socket
|
||||
ssh_set_auth_methods
|
||||
ssh_set_blocking
|
||||
ssh_set_callbacks
|
||||
ssh_set_channel_callbacks
|
||||
ssh_set_counters
|
||||
ssh_set_fd_except
|
||||
ssh_set_fd_toread
|
||||
ssh_set_fd_towrite
|
||||
ssh_set_log_callback
|
||||
ssh_set_log_level
|
||||
ssh_set_log_userdata
|
||||
ssh_set_message_callback
|
||||
ssh_set_pcap_file
|
||||
ssh_set_server_callbacks
|
||||
ssh_silent_disconnect
|
||||
ssh_string_burn
|
||||
ssh_string_copy
|
||||
ssh_string_data
|
||||
ssh_string_fill
|
||||
ssh_string_free
|
||||
ssh_string_free_char
|
||||
ssh_string_from_char
|
||||
ssh_string_get_char
|
||||
ssh_string_len
|
||||
ssh_string_new
|
||||
ssh_string_to_char
|
||||
ssh_threads_get_noop
|
||||
ssh_threads_get_pthread
|
||||
ssh_threads_set_callbacks
|
||||
ssh_try_publickey_from_file
|
||||
ssh_userauth_agent
|
||||
ssh_userauth_agent_pubkey
|
||||
ssh_userauth_autopubkey
|
||||
ssh_userauth_gssapi
|
||||
ssh_userauth_kbdint
|
||||
ssh_userauth_kbdint_getanswer
|
||||
ssh_userauth_kbdint_getinstruction
|
||||
ssh_userauth_kbdint_getname
|
||||
ssh_userauth_kbdint_getnanswers
|
||||
ssh_userauth_kbdint_getnprompts
|
||||
ssh_userauth_kbdint_getprompt
|
||||
ssh_userauth_kbdint_setanswer
|
||||
ssh_userauth_list
|
||||
ssh_userauth_none
|
||||
ssh_userauth_offer_pubkey
|
||||
ssh_userauth_password
|
||||
ssh_userauth_privatekey_file
|
||||
ssh_userauth_pubkey
|
||||
ssh_userauth_publickey
|
||||
ssh_userauth_publickey_auto
|
||||
ssh_userauth_try_publickey
|
||||
ssh_version
|
||||
ssh_write_knownhost
|
||||
string_burn
|
||||
string_copy
|
||||
string_data
|
||||
string_fill
|
||||
string_free
|
||||
string_from_char
|
||||
string_len
|
||||
string_new
|
||||
string_to_char
|
||||
@@ -1,421 +0,0 @@
|
||||
_ssh_log
|
||||
buffer_free
|
||||
buffer_get
|
||||
buffer_get_len
|
||||
buffer_new
|
||||
channel_accept_x11
|
||||
channel_change_pty_size
|
||||
channel_close
|
||||
channel_forward_accept
|
||||
channel_forward_cancel
|
||||
channel_forward_listen
|
||||
channel_free
|
||||
channel_get_exit_status
|
||||
channel_get_session
|
||||
channel_is_closed
|
||||
channel_is_eof
|
||||
channel_is_open
|
||||
channel_new
|
||||
channel_open_forward
|
||||
channel_open_session
|
||||
channel_poll
|
||||
channel_read
|
||||
channel_read_buffer
|
||||
channel_read_nonblocking
|
||||
channel_request_env
|
||||
channel_request_exec
|
||||
channel_request_pty
|
||||
channel_request_pty_size
|
||||
channel_request_send_signal
|
||||
channel_request_sftp
|
||||
channel_request_shell
|
||||
channel_request_subsystem
|
||||
channel_request_x11
|
||||
channel_select
|
||||
channel_send_eof
|
||||
channel_set_blocking
|
||||
channel_write
|
||||
channel_write_stderr
|
||||
privatekey_free
|
||||
privatekey_from_file
|
||||
publickey_free
|
||||
publickey_from_file
|
||||
publickey_from_privatekey
|
||||
publickey_to_string
|
||||
sftp_async_read
|
||||
sftp_async_read_begin
|
||||
sftp_attributes_free
|
||||
sftp_canonicalize_path
|
||||
sftp_chmod
|
||||
sftp_chown
|
||||
sftp_client_message_free
|
||||
sftp_client_message_get_data
|
||||
sftp_client_message_get_filename
|
||||
sftp_client_message_get_flags
|
||||
sftp_client_message_get_submessage
|
||||
sftp_client_message_get_type
|
||||
sftp_client_message_set_filename
|
||||
sftp_close
|
||||
sftp_closedir
|
||||
sftp_dir_eof
|
||||
sftp_extension_supported
|
||||
sftp_extensions_get_count
|
||||
sftp_extensions_get_data
|
||||
sftp_extensions_get_name
|
||||
sftp_file_set_blocking
|
||||
sftp_file_set_nonblocking
|
||||
sftp_free
|
||||
sftp_fstat
|
||||
sftp_fstatvfs
|
||||
sftp_fsync
|
||||
sftp_get_client_message
|
||||
sftp_get_error
|
||||
sftp_handle
|
||||
sftp_handle_alloc
|
||||
sftp_handle_remove
|
||||
sftp_init
|
||||
sftp_lstat
|
||||
sftp_mkdir
|
||||
sftp_new
|
||||
sftp_new_channel
|
||||
sftp_open
|
||||
sftp_opendir
|
||||
sftp_read
|
||||
sftp_readdir
|
||||
sftp_readlink
|
||||
sftp_rename
|
||||
sftp_reply_attr
|
||||
sftp_reply_data
|
||||
sftp_reply_handle
|
||||
sftp_reply_name
|
||||
sftp_reply_names
|
||||
sftp_reply_names_add
|
||||
sftp_reply_status
|
||||
sftp_rewind
|
||||
sftp_rmdir
|
||||
sftp_seek
|
||||
sftp_seek64
|
||||
sftp_send_client_message
|
||||
sftp_server_free
|
||||
sftp_server_init
|
||||
sftp_server_new
|
||||
sftp_server_version
|
||||
sftp_setstat
|
||||
sftp_stat
|
||||
sftp_statvfs
|
||||
sftp_statvfs_free
|
||||
sftp_symlink
|
||||
sftp_tell
|
||||
sftp_tell64
|
||||
sftp_unlink
|
||||
sftp_utimes
|
||||
sftp_write
|
||||
ssh_accept
|
||||
ssh_add_channel_callbacks
|
||||
ssh_auth_list
|
||||
ssh_basename
|
||||
ssh_bind_accept
|
||||
ssh_bind_accept_fd
|
||||
ssh_bind_fd_toaccept
|
||||
ssh_bind_free
|
||||
ssh_bind_get_fd
|
||||
ssh_bind_listen
|
||||
ssh_bind_new
|
||||
ssh_bind_options_parse_config
|
||||
ssh_bind_options_set
|
||||
ssh_bind_set_blocking
|
||||
ssh_bind_set_callbacks
|
||||
ssh_bind_set_fd
|
||||
ssh_blocking_flush
|
||||
ssh_buffer_add_data
|
||||
ssh_buffer_free
|
||||
ssh_buffer_get
|
||||
ssh_buffer_get_data
|
||||
ssh_buffer_get_len
|
||||
ssh_buffer_new
|
||||
ssh_buffer_reinit
|
||||
ssh_channel_accept_forward
|
||||
ssh_channel_accept_x11
|
||||
ssh_channel_cancel_forward
|
||||
ssh_channel_change_pty_size
|
||||
ssh_channel_close
|
||||
ssh_channel_free
|
||||
ssh_channel_get_exit_status
|
||||
ssh_channel_get_session
|
||||
ssh_channel_is_closed
|
||||
ssh_channel_is_eof
|
||||
ssh_channel_is_open
|
||||
ssh_channel_listen_forward
|
||||
ssh_channel_new
|
||||
ssh_channel_open_auth_agent
|
||||
ssh_channel_open_forward
|
||||
ssh_channel_open_forward_unix
|
||||
ssh_channel_open_reverse_forward
|
||||
ssh_channel_open_session
|
||||
ssh_channel_open_x11
|
||||
ssh_channel_poll
|
||||
ssh_channel_poll_timeout
|
||||
ssh_channel_read
|
||||
ssh_channel_read_nonblocking
|
||||
ssh_channel_read_timeout
|
||||
ssh_channel_request_auth_agent
|
||||
ssh_channel_request_env
|
||||
ssh_channel_request_exec
|
||||
ssh_channel_request_pty
|
||||
ssh_channel_request_pty_size
|
||||
ssh_channel_request_send_break
|
||||
ssh_channel_request_send_exit_signal
|
||||
ssh_channel_request_send_exit_status
|
||||
ssh_channel_request_send_signal
|
||||
ssh_channel_request_sftp
|
||||
ssh_channel_request_shell
|
||||
ssh_channel_request_subsystem
|
||||
ssh_channel_request_x11
|
||||
ssh_channel_select
|
||||
ssh_channel_send_eof
|
||||
ssh_channel_set_blocking
|
||||
ssh_channel_set_counter
|
||||
ssh_channel_window_size
|
||||
ssh_channel_write
|
||||
ssh_channel_write_stderr
|
||||
ssh_clean_pubkey_hash
|
||||
ssh_connect
|
||||
ssh_connector_free
|
||||
ssh_connector_new
|
||||
ssh_connector_set_in_channel
|
||||
ssh_connector_set_in_fd
|
||||
ssh_connector_set_out_channel
|
||||
ssh_connector_set_out_fd
|
||||
ssh_copyright
|
||||
ssh_dirname
|
||||
ssh_disconnect
|
||||
ssh_dump_knownhost
|
||||
ssh_event_add_connector
|
||||
ssh_event_add_fd
|
||||
ssh_event_add_session
|
||||
ssh_event_dopoll
|
||||
ssh_event_free
|
||||
ssh_event_new
|
||||
ssh_event_remove_connector
|
||||
ssh_event_remove_fd
|
||||
ssh_event_remove_session
|
||||
ssh_execute_message_callbacks
|
||||
ssh_finalize
|
||||
ssh_forward_accept
|
||||
ssh_forward_cancel
|
||||
ssh_forward_listen
|
||||
ssh_free
|
||||
ssh_get_cipher_in
|
||||
ssh_get_cipher_out
|
||||
ssh_get_clientbanner
|
||||
ssh_get_disconnect_message
|
||||
ssh_get_error
|
||||
ssh_get_error_code
|
||||
ssh_get_fd
|
||||
ssh_get_fingerprint_hash
|
||||
ssh_get_hexa
|
||||
ssh_get_hmac_in
|
||||
ssh_get_hmac_out
|
||||
ssh_get_issue_banner
|
||||
ssh_get_kex_algo
|
||||
ssh_get_log_callback
|
||||
ssh_get_log_level
|
||||
ssh_get_log_userdata
|
||||
ssh_get_openssh_version
|
||||
ssh_get_poll_flags
|
||||
ssh_get_pubkey
|
||||
ssh_get_pubkey_hash
|
||||
ssh_get_publickey
|
||||
ssh_get_publickey_hash
|
||||
ssh_get_random
|
||||
ssh_get_server_publickey
|
||||
ssh_get_serverbanner
|
||||
ssh_get_status
|
||||
ssh_get_version
|
||||
ssh_getpass
|
||||
ssh_gssapi_get_creds
|
||||
ssh_gssapi_set_creds
|
||||
ssh_handle_key_exchange
|
||||
ssh_init
|
||||
ssh_is_blocking
|
||||
ssh_is_connected
|
||||
ssh_is_server_known
|
||||
ssh_key_cmp
|
||||
ssh_key_free
|
||||
ssh_key_is_private
|
||||
ssh_key_is_public
|
||||
ssh_key_new
|
||||
ssh_key_type
|
||||
ssh_key_type_from_name
|
||||
ssh_key_type_to_char
|
||||
ssh_known_hosts_parse_line
|
||||
ssh_knownhosts_entry_free
|
||||
ssh_log
|
||||
ssh_message_auth_interactive_request
|
||||
ssh_message_auth_kbdint_is_response
|
||||
ssh_message_auth_password
|
||||
ssh_message_auth_pubkey
|
||||
ssh_message_auth_publickey
|
||||
ssh_message_auth_publickey_state
|
||||
ssh_message_auth_reply_pk_ok
|
||||
ssh_message_auth_reply_pk_ok_simple
|
||||
ssh_message_auth_reply_success
|
||||
ssh_message_auth_set_methods
|
||||
ssh_message_auth_user
|
||||
ssh_message_channel_request_channel
|
||||
ssh_message_channel_request_command
|
||||
ssh_message_channel_request_env_name
|
||||
ssh_message_channel_request_env_value
|
||||
ssh_message_channel_request_open_destination
|
||||
ssh_message_channel_request_open_destination_port
|
||||
ssh_message_channel_request_open_originator
|
||||
ssh_message_channel_request_open_originator_port
|
||||
ssh_message_channel_request_open_reply_accept
|
||||
ssh_message_channel_request_open_reply_accept_channel
|
||||
ssh_message_channel_request_pty_height
|
||||
ssh_message_channel_request_pty_pxheight
|
||||
ssh_message_channel_request_pty_pxwidth
|
||||
ssh_message_channel_request_pty_term
|
||||
ssh_message_channel_request_pty_width
|
||||
ssh_message_channel_request_reply_success
|
||||
ssh_message_channel_request_subsystem
|
||||
ssh_message_channel_request_x11_auth_cookie
|
||||
ssh_message_channel_request_x11_auth_protocol
|
||||
ssh_message_channel_request_x11_screen_number
|
||||
ssh_message_channel_request_x11_single_connection
|
||||
ssh_message_free
|
||||
ssh_message_get
|
||||
ssh_message_global_request_address
|
||||
ssh_message_global_request_port
|
||||
ssh_message_global_request_reply_success
|
||||
ssh_message_reply_default
|
||||
ssh_message_retrieve
|
||||
ssh_message_service_reply_success
|
||||
ssh_message_service_service
|
||||
ssh_message_subtype
|
||||
ssh_message_type
|
||||
ssh_mkdir
|
||||
ssh_new
|
||||
ssh_options_copy
|
||||
ssh_options_get
|
||||
ssh_options_get_port
|
||||
ssh_options_getopt
|
||||
ssh_options_parse_config
|
||||
ssh_options_set
|
||||
ssh_pcap_file_close
|
||||
ssh_pcap_file_free
|
||||
ssh_pcap_file_new
|
||||
ssh_pcap_file_open
|
||||
ssh_pki_copy_cert_to_privkey
|
||||
ssh_pki_export_privkey_base64
|
||||
ssh_pki_export_privkey_file
|
||||
ssh_pki_export_privkey_to_pubkey
|
||||
ssh_pki_export_pubkey_base64
|
||||
ssh_pki_export_pubkey_file
|
||||
ssh_pki_generate
|
||||
ssh_pki_import_cert_base64
|
||||
ssh_pki_import_cert_file
|
||||
ssh_pki_import_privkey_base64
|
||||
ssh_pki_import_privkey_file
|
||||
ssh_pki_import_pubkey_base64
|
||||
ssh_pki_import_pubkey_file
|
||||
ssh_pki_key_ecdsa_name
|
||||
ssh_print_hash
|
||||
ssh_print_hexa
|
||||
ssh_privatekey_type
|
||||
ssh_publickey_to_file
|
||||
ssh_remove_channel_callbacks
|
||||
ssh_scp_accept_request
|
||||
ssh_scp_close
|
||||
ssh_scp_deny_request
|
||||
ssh_scp_free
|
||||
ssh_scp_init
|
||||
ssh_scp_leave_directory
|
||||
ssh_scp_new
|
||||
ssh_scp_pull_request
|
||||
ssh_scp_push_directory
|
||||
ssh_scp_push_file
|
||||
ssh_scp_push_file64
|
||||
ssh_scp_read
|
||||
ssh_scp_request_get_filename
|
||||
ssh_scp_request_get_permissions
|
||||
ssh_scp_request_get_size
|
||||
ssh_scp_request_get_size64
|
||||
ssh_scp_request_get_warning
|
||||
ssh_scp_write
|
||||
ssh_select
|
||||
ssh_send_debug
|
||||
ssh_send_ignore
|
||||
ssh_send_keepalive
|
||||
ssh_server_init_kex
|
||||
ssh_service_request
|
||||
ssh_session_export_known_hosts_entry
|
||||
ssh_session_get_known_hosts_entry
|
||||
ssh_session_has_known_hosts_entry
|
||||
ssh_session_is_known_server
|
||||
ssh_session_update_known_hosts
|
||||
ssh_set_agent_channel
|
||||
ssh_set_agent_socket
|
||||
ssh_set_auth_methods
|
||||
ssh_set_blocking
|
||||
ssh_set_callbacks
|
||||
ssh_set_channel_callbacks
|
||||
ssh_set_counters
|
||||
ssh_set_fd_except
|
||||
ssh_set_fd_toread
|
||||
ssh_set_fd_towrite
|
||||
ssh_set_log_callback
|
||||
ssh_set_log_level
|
||||
ssh_set_log_userdata
|
||||
ssh_set_message_callback
|
||||
ssh_set_pcap_file
|
||||
ssh_set_server_callbacks
|
||||
ssh_silent_disconnect
|
||||
ssh_string_burn
|
||||
ssh_string_copy
|
||||
ssh_string_data
|
||||
ssh_string_fill
|
||||
ssh_string_free
|
||||
ssh_string_free_char
|
||||
ssh_string_from_char
|
||||
ssh_string_get_char
|
||||
ssh_string_len
|
||||
ssh_string_new
|
||||
ssh_string_to_char
|
||||
ssh_threads_get_default
|
||||
ssh_threads_get_noop
|
||||
ssh_threads_get_pthread
|
||||
ssh_threads_set_callbacks
|
||||
ssh_try_publickey_from_file
|
||||
ssh_userauth_agent
|
||||
ssh_userauth_agent_pubkey
|
||||
ssh_userauth_autopubkey
|
||||
ssh_userauth_gssapi
|
||||
ssh_userauth_kbdint
|
||||
ssh_userauth_kbdint_getanswer
|
||||
ssh_userauth_kbdint_getinstruction
|
||||
ssh_userauth_kbdint_getname
|
||||
ssh_userauth_kbdint_getnanswers
|
||||
ssh_userauth_kbdint_getnprompts
|
||||
ssh_userauth_kbdint_getprompt
|
||||
ssh_userauth_kbdint_setanswer
|
||||
ssh_userauth_list
|
||||
ssh_userauth_none
|
||||
ssh_userauth_offer_pubkey
|
||||
ssh_userauth_password
|
||||
ssh_userauth_privatekey_file
|
||||
ssh_userauth_pubkey
|
||||
ssh_userauth_publickey
|
||||
ssh_userauth_publickey_auto
|
||||
ssh_userauth_try_publickey
|
||||
ssh_version
|
||||
ssh_write_knownhost
|
||||
string_burn
|
||||
string_copy
|
||||
string_data
|
||||
string_fill
|
||||
string_free
|
||||
string_from_char
|
||||
string_len
|
||||
string_new
|
||||
string_to_char
|
||||
@@ -1,421 +0,0 @@
|
||||
_ssh_log
|
||||
buffer_free
|
||||
buffer_get
|
||||
buffer_get_len
|
||||
buffer_new
|
||||
channel_accept_x11
|
||||
channel_change_pty_size
|
||||
channel_close
|
||||
channel_forward_accept
|
||||
channel_forward_cancel
|
||||
channel_forward_listen
|
||||
channel_free
|
||||
channel_get_exit_status
|
||||
channel_get_session
|
||||
channel_is_closed
|
||||
channel_is_eof
|
||||
channel_is_open
|
||||
channel_new
|
||||
channel_open_forward
|
||||
channel_open_session
|
||||
channel_poll
|
||||
channel_read
|
||||
channel_read_buffer
|
||||
channel_read_nonblocking
|
||||
channel_request_env
|
||||
channel_request_exec
|
||||
channel_request_pty
|
||||
channel_request_pty_size
|
||||
channel_request_send_signal
|
||||
channel_request_sftp
|
||||
channel_request_shell
|
||||
channel_request_subsystem
|
||||
channel_request_x11
|
||||
channel_select
|
||||
channel_send_eof
|
||||
channel_set_blocking
|
||||
channel_write
|
||||
channel_write_stderr
|
||||
privatekey_free
|
||||
privatekey_from_file
|
||||
publickey_free
|
||||
publickey_from_file
|
||||
publickey_from_privatekey
|
||||
publickey_to_string
|
||||
sftp_async_read
|
||||
sftp_async_read_begin
|
||||
sftp_attributes_free
|
||||
sftp_canonicalize_path
|
||||
sftp_chmod
|
||||
sftp_chown
|
||||
sftp_client_message_free
|
||||
sftp_client_message_get_data
|
||||
sftp_client_message_get_filename
|
||||
sftp_client_message_get_flags
|
||||
sftp_client_message_get_submessage
|
||||
sftp_client_message_get_type
|
||||
sftp_client_message_set_filename
|
||||
sftp_close
|
||||
sftp_closedir
|
||||
sftp_dir_eof
|
||||
sftp_extension_supported
|
||||
sftp_extensions_get_count
|
||||
sftp_extensions_get_data
|
||||
sftp_extensions_get_name
|
||||
sftp_file_set_blocking
|
||||
sftp_file_set_nonblocking
|
||||
sftp_free
|
||||
sftp_fstat
|
||||
sftp_fstatvfs
|
||||
sftp_fsync
|
||||
sftp_get_client_message
|
||||
sftp_get_error
|
||||
sftp_handle
|
||||
sftp_handle_alloc
|
||||
sftp_handle_remove
|
||||
sftp_init
|
||||
sftp_lstat
|
||||
sftp_mkdir
|
||||
sftp_new
|
||||
sftp_new_channel
|
||||
sftp_open
|
||||
sftp_opendir
|
||||
sftp_read
|
||||
sftp_readdir
|
||||
sftp_readlink
|
||||
sftp_rename
|
||||
sftp_reply_attr
|
||||
sftp_reply_data
|
||||
sftp_reply_handle
|
||||
sftp_reply_name
|
||||
sftp_reply_names
|
||||
sftp_reply_names_add
|
||||
sftp_reply_status
|
||||
sftp_rewind
|
||||
sftp_rmdir
|
||||
sftp_seek
|
||||
sftp_seek64
|
||||
sftp_send_client_message
|
||||
sftp_server_free
|
||||
sftp_server_init
|
||||
sftp_server_new
|
||||
sftp_server_version
|
||||
sftp_setstat
|
||||
sftp_stat
|
||||
sftp_statvfs
|
||||
sftp_statvfs_free
|
||||
sftp_symlink
|
||||
sftp_tell
|
||||
sftp_tell64
|
||||
sftp_unlink
|
||||
sftp_utimes
|
||||
sftp_write
|
||||
ssh_accept
|
||||
ssh_add_channel_callbacks
|
||||
ssh_auth_list
|
||||
ssh_basename
|
||||
ssh_bind_accept
|
||||
ssh_bind_accept_fd
|
||||
ssh_bind_fd_toaccept
|
||||
ssh_bind_free
|
||||
ssh_bind_get_fd
|
||||
ssh_bind_listen
|
||||
ssh_bind_new
|
||||
ssh_bind_options_parse_config
|
||||
ssh_bind_options_set
|
||||
ssh_bind_set_blocking
|
||||
ssh_bind_set_callbacks
|
||||
ssh_bind_set_fd
|
||||
ssh_blocking_flush
|
||||
ssh_buffer_add_data
|
||||
ssh_buffer_free
|
||||
ssh_buffer_get
|
||||
ssh_buffer_get_data
|
||||
ssh_buffer_get_len
|
||||
ssh_buffer_new
|
||||
ssh_buffer_reinit
|
||||
ssh_channel_accept_forward
|
||||
ssh_channel_accept_x11
|
||||
ssh_channel_cancel_forward
|
||||
ssh_channel_change_pty_size
|
||||
ssh_channel_close
|
||||
ssh_channel_free
|
||||
ssh_channel_get_exit_status
|
||||
ssh_channel_get_session
|
||||
ssh_channel_is_closed
|
||||
ssh_channel_is_eof
|
||||
ssh_channel_is_open
|
||||
ssh_channel_listen_forward
|
||||
ssh_channel_new
|
||||
ssh_channel_open_auth_agent
|
||||
ssh_channel_open_forward
|
||||
ssh_channel_open_forward_unix
|
||||
ssh_channel_open_reverse_forward
|
||||
ssh_channel_open_session
|
||||
ssh_channel_open_x11
|
||||
ssh_channel_poll
|
||||
ssh_channel_poll_timeout
|
||||
ssh_channel_read
|
||||
ssh_channel_read_nonblocking
|
||||
ssh_channel_read_timeout
|
||||
ssh_channel_request_auth_agent
|
||||
ssh_channel_request_env
|
||||
ssh_channel_request_exec
|
||||
ssh_channel_request_pty
|
||||
ssh_channel_request_pty_size
|
||||
ssh_channel_request_send_break
|
||||
ssh_channel_request_send_exit_signal
|
||||
ssh_channel_request_send_exit_status
|
||||
ssh_channel_request_send_signal
|
||||
ssh_channel_request_sftp
|
||||
ssh_channel_request_shell
|
||||
ssh_channel_request_subsystem
|
||||
ssh_channel_request_x11
|
||||
ssh_channel_select
|
||||
ssh_channel_send_eof
|
||||
ssh_channel_set_blocking
|
||||
ssh_channel_set_counter
|
||||
ssh_channel_window_size
|
||||
ssh_channel_write
|
||||
ssh_channel_write_stderr
|
||||
ssh_clean_pubkey_hash
|
||||
ssh_connect
|
||||
ssh_connector_free
|
||||
ssh_connector_new
|
||||
ssh_connector_set_in_channel
|
||||
ssh_connector_set_in_fd
|
||||
ssh_connector_set_out_channel
|
||||
ssh_connector_set_out_fd
|
||||
ssh_copyright
|
||||
ssh_dirname
|
||||
ssh_disconnect
|
||||
ssh_dump_knownhost
|
||||
ssh_event_add_connector
|
||||
ssh_event_add_fd
|
||||
ssh_event_add_session
|
||||
ssh_event_dopoll
|
||||
ssh_event_free
|
||||
ssh_event_new
|
||||
ssh_event_remove_connector
|
||||
ssh_event_remove_fd
|
||||
ssh_event_remove_session
|
||||
ssh_execute_message_callbacks
|
||||
ssh_finalize
|
||||
ssh_forward_accept
|
||||
ssh_forward_cancel
|
||||
ssh_forward_listen
|
||||
ssh_free
|
||||
ssh_get_cipher_in
|
||||
ssh_get_cipher_out
|
||||
ssh_get_clientbanner
|
||||
ssh_get_disconnect_message
|
||||
ssh_get_error
|
||||
ssh_get_error_code
|
||||
ssh_get_fd
|
||||
ssh_get_fingerprint_hash
|
||||
ssh_get_hexa
|
||||
ssh_get_hmac_in
|
||||
ssh_get_hmac_out
|
||||
ssh_get_issue_banner
|
||||
ssh_get_kex_algo
|
||||
ssh_get_log_callback
|
||||
ssh_get_log_level
|
||||
ssh_get_log_userdata
|
||||
ssh_get_openssh_version
|
||||
ssh_get_poll_flags
|
||||
ssh_get_pubkey
|
||||
ssh_get_pubkey_hash
|
||||
ssh_get_publickey
|
||||
ssh_get_publickey_hash
|
||||
ssh_get_random
|
||||
ssh_get_server_publickey
|
||||
ssh_get_serverbanner
|
||||
ssh_get_status
|
||||
ssh_get_version
|
||||
ssh_getpass
|
||||
ssh_gssapi_get_creds
|
||||
ssh_gssapi_set_creds
|
||||
ssh_handle_key_exchange
|
||||
ssh_init
|
||||
ssh_is_blocking
|
||||
ssh_is_connected
|
||||
ssh_is_server_known
|
||||
ssh_key_cmp
|
||||
ssh_key_free
|
||||
ssh_key_is_private
|
||||
ssh_key_is_public
|
||||
ssh_key_new
|
||||
ssh_key_type
|
||||
ssh_key_type_from_name
|
||||
ssh_key_type_to_char
|
||||
ssh_known_hosts_parse_line
|
||||
ssh_knownhosts_entry_free
|
||||
ssh_log
|
||||
ssh_message_auth_interactive_request
|
||||
ssh_message_auth_kbdint_is_response
|
||||
ssh_message_auth_password
|
||||
ssh_message_auth_pubkey
|
||||
ssh_message_auth_publickey
|
||||
ssh_message_auth_publickey_state
|
||||
ssh_message_auth_reply_pk_ok
|
||||
ssh_message_auth_reply_pk_ok_simple
|
||||
ssh_message_auth_reply_success
|
||||
ssh_message_auth_set_methods
|
||||
ssh_message_auth_user
|
||||
ssh_message_channel_request_channel
|
||||
ssh_message_channel_request_command
|
||||
ssh_message_channel_request_env_name
|
||||
ssh_message_channel_request_env_value
|
||||
ssh_message_channel_request_open_destination
|
||||
ssh_message_channel_request_open_destination_port
|
||||
ssh_message_channel_request_open_originator
|
||||
ssh_message_channel_request_open_originator_port
|
||||
ssh_message_channel_request_open_reply_accept
|
||||
ssh_message_channel_request_open_reply_accept_channel
|
||||
ssh_message_channel_request_pty_height
|
||||
ssh_message_channel_request_pty_pxheight
|
||||
ssh_message_channel_request_pty_pxwidth
|
||||
ssh_message_channel_request_pty_term
|
||||
ssh_message_channel_request_pty_width
|
||||
ssh_message_channel_request_reply_success
|
||||
ssh_message_channel_request_subsystem
|
||||
ssh_message_channel_request_x11_auth_cookie
|
||||
ssh_message_channel_request_x11_auth_protocol
|
||||
ssh_message_channel_request_x11_screen_number
|
||||
ssh_message_channel_request_x11_single_connection
|
||||
ssh_message_free
|
||||
ssh_message_get
|
||||
ssh_message_global_request_address
|
||||
ssh_message_global_request_port
|
||||
ssh_message_global_request_reply_success
|
||||
ssh_message_reply_default
|
||||
ssh_message_retrieve
|
||||
ssh_message_service_reply_success
|
||||
ssh_message_service_service
|
||||
ssh_message_subtype
|
||||
ssh_message_type
|
||||
ssh_mkdir
|
||||
ssh_new
|
||||
ssh_options_copy
|
||||
ssh_options_get
|
||||
ssh_options_get_port
|
||||
ssh_options_getopt
|
||||
ssh_options_parse_config
|
||||
ssh_options_set
|
||||
ssh_pcap_file_close
|
||||
ssh_pcap_file_free
|
||||
ssh_pcap_file_new
|
||||
ssh_pcap_file_open
|
||||
ssh_pki_copy_cert_to_privkey
|
||||
ssh_pki_export_privkey_base64
|
||||
ssh_pki_export_privkey_file
|
||||
ssh_pki_export_privkey_to_pubkey
|
||||
ssh_pki_export_pubkey_base64
|
||||
ssh_pki_export_pubkey_file
|
||||
ssh_pki_generate
|
||||
ssh_pki_import_cert_base64
|
||||
ssh_pki_import_cert_file
|
||||
ssh_pki_import_privkey_base64
|
||||
ssh_pki_import_privkey_file
|
||||
ssh_pki_import_pubkey_base64
|
||||
ssh_pki_import_pubkey_file
|
||||
ssh_pki_key_ecdsa_name
|
||||
ssh_print_hash
|
||||
ssh_print_hexa
|
||||
ssh_privatekey_type
|
||||
ssh_publickey_to_file
|
||||
ssh_remove_channel_callbacks
|
||||
ssh_scp_accept_request
|
||||
ssh_scp_close
|
||||
ssh_scp_deny_request
|
||||
ssh_scp_free
|
||||
ssh_scp_init
|
||||
ssh_scp_leave_directory
|
||||
ssh_scp_new
|
||||
ssh_scp_pull_request
|
||||
ssh_scp_push_directory
|
||||
ssh_scp_push_file
|
||||
ssh_scp_push_file64
|
||||
ssh_scp_read
|
||||
ssh_scp_request_get_filename
|
||||
ssh_scp_request_get_permissions
|
||||
ssh_scp_request_get_size
|
||||
ssh_scp_request_get_size64
|
||||
ssh_scp_request_get_warning
|
||||
ssh_scp_write
|
||||
ssh_select
|
||||
ssh_send_debug
|
||||
ssh_send_ignore
|
||||
ssh_send_keepalive
|
||||
ssh_server_init_kex
|
||||
ssh_service_request
|
||||
ssh_session_export_known_hosts_entry
|
||||
ssh_session_get_known_hosts_entry
|
||||
ssh_session_has_known_hosts_entry
|
||||
ssh_session_is_known_server
|
||||
ssh_session_update_known_hosts
|
||||
ssh_set_agent_channel
|
||||
ssh_set_agent_socket
|
||||
ssh_set_auth_methods
|
||||
ssh_set_blocking
|
||||
ssh_set_callbacks
|
||||
ssh_set_channel_callbacks
|
||||
ssh_set_counters
|
||||
ssh_set_fd_except
|
||||
ssh_set_fd_toread
|
||||
ssh_set_fd_towrite
|
||||
ssh_set_log_callback
|
||||
ssh_set_log_level
|
||||
ssh_set_log_userdata
|
||||
ssh_set_message_callback
|
||||
ssh_set_pcap_file
|
||||
ssh_set_server_callbacks
|
||||
ssh_silent_disconnect
|
||||
ssh_string_burn
|
||||
ssh_string_copy
|
||||
ssh_string_data
|
||||
ssh_string_fill
|
||||
ssh_string_free
|
||||
ssh_string_free_char
|
||||
ssh_string_from_char
|
||||
ssh_string_get_char
|
||||
ssh_string_len
|
||||
ssh_string_new
|
||||
ssh_string_to_char
|
||||
ssh_threads_get_default
|
||||
ssh_threads_get_noop
|
||||
ssh_threads_get_pthread
|
||||
ssh_threads_set_callbacks
|
||||
ssh_try_publickey_from_file
|
||||
ssh_userauth_agent
|
||||
ssh_userauth_agent_pubkey
|
||||
ssh_userauth_autopubkey
|
||||
ssh_userauth_gssapi
|
||||
ssh_userauth_kbdint
|
||||
ssh_userauth_kbdint_getanswer
|
||||
ssh_userauth_kbdint_getinstruction
|
||||
ssh_userauth_kbdint_getname
|
||||
ssh_userauth_kbdint_getnanswers
|
||||
ssh_userauth_kbdint_getnprompts
|
||||
ssh_userauth_kbdint_getprompt
|
||||
ssh_userauth_kbdint_setanswer
|
||||
ssh_userauth_list
|
||||
ssh_userauth_none
|
||||
ssh_userauth_offer_pubkey
|
||||
ssh_userauth_password
|
||||
ssh_userauth_privatekey_file
|
||||
ssh_userauth_pubkey
|
||||
ssh_userauth_publickey
|
||||
ssh_userauth_publickey_auto
|
||||
ssh_userauth_try_publickey
|
||||
ssh_version
|
||||
ssh_write_knownhost
|
||||
string_burn
|
||||
string_copy
|
||||
string_data
|
||||
string_fill
|
||||
string_free
|
||||
string_from_char
|
||||
string_len
|
||||
string_new
|
||||
string_to_char
|
||||
@@ -1,421 +0,0 @@
|
||||
_ssh_log
|
||||
buffer_free
|
||||
buffer_get
|
||||
buffer_get_len
|
||||
buffer_new
|
||||
channel_accept_x11
|
||||
channel_change_pty_size
|
||||
channel_close
|
||||
channel_forward_accept
|
||||
channel_forward_cancel
|
||||
channel_forward_listen
|
||||
channel_free
|
||||
channel_get_exit_status
|
||||
channel_get_session
|
||||
channel_is_closed
|
||||
channel_is_eof
|
||||
channel_is_open
|
||||
channel_new
|
||||
channel_open_forward
|
||||
channel_open_session
|
||||
channel_poll
|
||||
channel_read
|
||||
channel_read_buffer
|
||||
channel_read_nonblocking
|
||||
channel_request_env
|
||||
channel_request_exec
|
||||
channel_request_pty
|
||||
channel_request_pty_size
|
||||
channel_request_send_signal
|
||||
channel_request_sftp
|
||||
channel_request_shell
|
||||
channel_request_subsystem
|
||||
channel_request_x11
|
||||
channel_select
|
||||
channel_send_eof
|
||||
channel_set_blocking
|
||||
channel_write
|
||||
channel_write_stderr
|
||||
privatekey_free
|
||||
privatekey_from_file
|
||||
publickey_free
|
||||
publickey_from_file
|
||||
publickey_from_privatekey
|
||||
publickey_to_string
|
||||
sftp_async_read
|
||||
sftp_async_read_begin
|
||||
sftp_attributes_free
|
||||
sftp_canonicalize_path
|
||||
sftp_chmod
|
||||
sftp_chown
|
||||
sftp_client_message_free
|
||||
sftp_client_message_get_data
|
||||
sftp_client_message_get_filename
|
||||
sftp_client_message_get_flags
|
||||
sftp_client_message_get_submessage
|
||||
sftp_client_message_get_type
|
||||
sftp_client_message_set_filename
|
||||
sftp_close
|
||||
sftp_closedir
|
||||
sftp_dir_eof
|
||||
sftp_extension_supported
|
||||
sftp_extensions_get_count
|
||||
sftp_extensions_get_data
|
||||
sftp_extensions_get_name
|
||||
sftp_file_set_blocking
|
||||
sftp_file_set_nonblocking
|
||||
sftp_free
|
||||
sftp_fstat
|
||||
sftp_fstatvfs
|
||||
sftp_fsync
|
||||
sftp_get_client_message
|
||||
sftp_get_error
|
||||
sftp_handle
|
||||
sftp_handle_alloc
|
||||
sftp_handle_remove
|
||||
sftp_init
|
||||
sftp_lstat
|
||||
sftp_mkdir
|
||||
sftp_new
|
||||
sftp_new_channel
|
||||
sftp_open
|
||||
sftp_opendir
|
||||
sftp_read
|
||||
sftp_readdir
|
||||
sftp_readlink
|
||||
sftp_rename
|
||||
sftp_reply_attr
|
||||
sftp_reply_data
|
||||
sftp_reply_handle
|
||||
sftp_reply_name
|
||||
sftp_reply_names
|
||||
sftp_reply_names_add
|
||||
sftp_reply_status
|
||||
sftp_rewind
|
||||
sftp_rmdir
|
||||
sftp_seek
|
||||
sftp_seek64
|
||||
sftp_send_client_message
|
||||
sftp_server_free
|
||||
sftp_server_init
|
||||
sftp_server_new
|
||||
sftp_server_version
|
||||
sftp_setstat
|
||||
sftp_stat
|
||||
sftp_statvfs
|
||||
sftp_statvfs_free
|
||||
sftp_symlink
|
||||
sftp_tell
|
||||
sftp_tell64
|
||||
sftp_unlink
|
||||
sftp_utimes
|
||||
sftp_write
|
||||
ssh_accept
|
||||
ssh_add_channel_callbacks
|
||||
ssh_auth_list
|
||||
ssh_basename
|
||||
ssh_bind_accept
|
||||
ssh_bind_accept_fd
|
||||
ssh_bind_fd_toaccept
|
||||
ssh_bind_free
|
||||
ssh_bind_get_fd
|
||||
ssh_bind_listen
|
||||
ssh_bind_new
|
||||
ssh_bind_options_parse_config
|
||||
ssh_bind_options_set
|
||||
ssh_bind_set_blocking
|
||||
ssh_bind_set_callbacks
|
||||
ssh_bind_set_fd
|
||||
ssh_blocking_flush
|
||||
ssh_buffer_add_data
|
||||
ssh_buffer_free
|
||||
ssh_buffer_get
|
||||
ssh_buffer_get_data
|
||||
ssh_buffer_get_len
|
||||
ssh_buffer_new
|
||||
ssh_buffer_reinit
|
||||
ssh_channel_accept_forward
|
||||
ssh_channel_accept_x11
|
||||
ssh_channel_cancel_forward
|
||||
ssh_channel_change_pty_size
|
||||
ssh_channel_close
|
||||
ssh_channel_free
|
||||
ssh_channel_get_exit_status
|
||||
ssh_channel_get_session
|
||||
ssh_channel_is_closed
|
||||
ssh_channel_is_eof
|
||||
ssh_channel_is_open
|
||||
ssh_channel_listen_forward
|
||||
ssh_channel_new
|
||||
ssh_channel_open_auth_agent
|
||||
ssh_channel_open_forward
|
||||
ssh_channel_open_forward_unix
|
||||
ssh_channel_open_reverse_forward
|
||||
ssh_channel_open_session
|
||||
ssh_channel_open_x11
|
||||
ssh_channel_poll
|
||||
ssh_channel_poll_timeout
|
||||
ssh_channel_read
|
||||
ssh_channel_read_nonblocking
|
||||
ssh_channel_read_timeout
|
||||
ssh_channel_request_auth_agent
|
||||
ssh_channel_request_env
|
||||
ssh_channel_request_exec
|
||||
ssh_channel_request_pty
|
||||
ssh_channel_request_pty_size
|
||||
ssh_channel_request_send_break
|
||||
ssh_channel_request_send_exit_signal
|
||||
ssh_channel_request_send_exit_status
|
||||
ssh_channel_request_send_signal
|
||||
ssh_channel_request_sftp
|
||||
ssh_channel_request_shell
|
||||
ssh_channel_request_subsystem
|
||||
ssh_channel_request_x11
|
||||
ssh_channel_select
|
||||
ssh_channel_send_eof
|
||||
ssh_channel_set_blocking
|
||||
ssh_channel_set_counter
|
||||
ssh_channel_window_size
|
||||
ssh_channel_write
|
||||
ssh_channel_write_stderr
|
||||
ssh_clean_pubkey_hash
|
||||
ssh_connect
|
||||
ssh_connector_free
|
||||
ssh_connector_new
|
||||
ssh_connector_set_in_channel
|
||||
ssh_connector_set_in_fd
|
||||
ssh_connector_set_out_channel
|
||||
ssh_connector_set_out_fd
|
||||
ssh_copyright
|
||||
ssh_dirname
|
||||
ssh_disconnect
|
||||
ssh_dump_knownhost
|
||||
ssh_event_add_connector
|
||||
ssh_event_add_fd
|
||||
ssh_event_add_session
|
||||
ssh_event_dopoll
|
||||
ssh_event_free
|
||||
ssh_event_new
|
||||
ssh_event_remove_connector
|
||||
ssh_event_remove_fd
|
||||
ssh_event_remove_session
|
||||
ssh_execute_message_callbacks
|
||||
ssh_finalize
|
||||
ssh_forward_accept
|
||||
ssh_forward_cancel
|
||||
ssh_forward_listen
|
||||
ssh_free
|
||||
ssh_get_cipher_in
|
||||
ssh_get_cipher_out
|
||||
ssh_get_clientbanner
|
||||
ssh_get_disconnect_message
|
||||
ssh_get_error
|
||||
ssh_get_error_code
|
||||
ssh_get_fd
|
||||
ssh_get_fingerprint_hash
|
||||
ssh_get_hexa
|
||||
ssh_get_hmac_in
|
||||
ssh_get_hmac_out
|
||||
ssh_get_issue_banner
|
||||
ssh_get_kex_algo
|
||||
ssh_get_log_callback
|
||||
ssh_get_log_level
|
||||
ssh_get_log_userdata
|
||||
ssh_get_openssh_version
|
||||
ssh_get_poll_flags
|
||||
ssh_get_pubkey
|
||||
ssh_get_pubkey_hash
|
||||
ssh_get_publickey
|
||||
ssh_get_publickey_hash
|
||||
ssh_get_random
|
||||
ssh_get_server_publickey
|
||||
ssh_get_serverbanner
|
||||
ssh_get_status
|
||||
ssh_get_version
|
||||
ssh_getpass
|
||||
ssh_gssapi_get_creds
|
||||
ssh_gssapi_set_creds
|
||||
ssh_handle_key_exchange
|
||||
ssh_init
|
||||
ssh_is_blocking
|
||||
ssh_is_connected
|
||||
ssh_is_server_known
|
||||
ssh_key_cmp
|
||||
ssh_key_free
|
||||
ssh_key_is_private
|
||||
ssh_key_is_public
|
||||
ssh_key_new
|
||||
ssh_key_type
|
||||
ssh_key_type_from_name
|
||||
ssh_key_type_to_char
|
||||
ssh_known_hosts_parse_line
|
||||
ssh_knownhosts_entry_free
|
||||
ssh_log
|
||||
ssh_message_auth_interactive_request
|
||||
ssh_message_auth_kbdint_is_response
|
||||
ssh_message_auth_password
|
||||
ssh_message_auth_pubkey
|
||||
ssh_message_auth_publickey
|
||||
ssh_message_auth_publickey_state
|
||||
ssh_message_auth_reply_pk_ok
|
||||
ssh_message_auth_reply_pk_ok_simple
|
||||
ssh_message_auth_reply_success
|
||||
ssh_message_auth_set_methods
|
||||
ssh_message_auth_user
|
||||
ssh_message_channel_request_channel
|
||||
ssh_message_channel_request_command
|
||||
ssh_message_channel_request_env_name
|
||||
ssh_message_channel_request_env_value
|
||||
ssh_message_channel_request_open_destination
|
||||
ssh_message_channel_request_open_destination_port
|
||||
ssh_message_channel_request_open_originator
|
||||
ssh_message_channel_request_open_originator_port
|
||||
ssh_message_channel_request_open_reply_accept
|
||||
ssh_message_channel_request_open_reply_accept_channel
|
||||
ssh_message_channel_request_pty_height
|
||||
ssh_message_channel_request_pty_pxheight
|
||||
ssh_message_channel_request_pty_pxwidth
|
||||
ssh_message_channel_request_pty_term
|
||||
ssh_message_channel_request_pty_width
|
||||
ssh_message_channel_request_reply_success
|
||||
ssh_message_channel_request_subsystem
|
||||
ssh_message_channel_request_x11_auth_cookie
|
||||
ssh_message_channel_request_x11_auth_protocol
|
||||
ssh_message_channel_request_x11_screen_number
|
||||
ssh_message_channel_request_x11_single_connection
|
||||
ssh_message_free
|
||||
ssh_message_get
|
||||
ssh_message_global_request_address
|
||||
ssh_message_global_request_port
|
||||
ssh_message_global_request_reply_success
|
||||
ssh_message_reply_default
|
||||
ssh_message_retrieve
|
||||
ssh_message_service_reply_success
|
||||
ssh_message_service_service
|
||||
ssh_message_subtype
|
||||
ssh_message_type
|
||||
ssh_mkdir
|
||||
ssh_new
|
||||
ssh_options_copy
|
||||
ssh_options_get
|
||||
ssh_options_get_port
|
||||
ssh_options_getopt
|
||||
ssh_options_parse_config
|
||||
ssh_options_set
|
||||
ssh_pcap_file_close
|
||||
ssh_pcap_file_free
|
||||
ssh_pcap_file_new
|
||||
ssh_pcap_file_open
|
||||
ssh_pki_copy_cert_to_privkey
|
||||
ssh_pki_export_privkey_base64
|
||||
ssh_pki_export_privkey_file
|
||||
ssh_pki_export_privkey_to_pubkey
|
||||
ssh_pki_export_pubkey_base64
|
||||
ssh_pki_export_pubkey_file
|
||||
ssh_pki_generate
|
||||
ssh_pki_import_cert_base64
|
||||
ssh_pki_import_cert_file
|
||||
ssh_pki_import_privkey_base64
|
||||
ssh_pki_import_privkey_file
|
||||
ssh_pki_import_pubkey_base64
|
||||
ssh_pki_import_pubkey_file
|
||||
ssh_pki_key_ecdsa_name
|
||||
ssh_print_hash
|
||||
ssh_print_hexa
|
||||
ssh_privatekey_type
|
||||
ssh_publickey_to_file
|
||||
ssh_remove_channel_callbacks
|
||||
ssh_scp_accept_request
|
||||
ssh_scp_close
|
||||
ssh_scp_deny_request
|
||||
ssh_scp_free
|
||||
ssh_scp_init
|
||||
ssh_scp_leave_directory
|
||||
ssh_scp_new
|
||||
ssh_scp_pull_request
|
||||
ssh_scp_push_directory
|
||||
ssh_scp_push_file
|
||||
ssh_scp_push_file64
|
||||
ssh_scp_read
|
||||
ssh_scp_request_get_filename
|
||||
ssh_scp_request_get_permissions
|
||||
ssh_scp_request_get_size
|
||||
ssh_scp_request_get_size64
|
||||
ssh_scp_request_get_warning
|
||||
ssh_scp_write
|
||||
ssh_select
|
||||
ssh_send_debug
|
||||
ssh_send_ignore
|
||||
ssh_send_keepalive
|
||||
ssh_server_init_kex
|
||||
ssh_service_request
|
||||
ssh_session_export_known_hosts_entry
|
||||
ssh_session_get_known_hosts_entry
|
||||
ssh_session_has_known_hosts_entry
|
||||
ssh_session_is_known_server
|
||||
ssh_session_update_known_hosts
|
||||
ssh_set_agent_channel
|
||||
ssh_set_agent_socket
|
||||
ssh_set_auth_methods
|
||||
ssh_set_blocking
|
||||
ssh_set_callbacks
|
||||
ssh_set_channel_callbacks
|
||||
ssh_set_counters
|
||||
ssh_set_fd_except
|
||||
ssh_set_fd_toread
|
||||
ssh_set_fd_towrite
|
||||
ssh_set_log_callback
|
||||
ssh_set_log_level
|
||||
ssh_set_log_userdata
|
||||
ssh_set_message_callback
|
||||
ssh_set_pcap_file
|
||||
ssh_set_server_callbacks
|
||||
ssh_silent_disconnect
|
||||
ssh_string_burn
|
||||
ssh_string_copy
|
||||
ssh_string_data
|
||||
ssh_string_fill
|
||||
ssh_string_free
|
||||
ssh_string_free_char
|
||||
ssh_string_from_char
|
||||
ssh_string_get_char
|
||||
ssh_string_len
|
||||
ssh_string_new
|
||||
ssh_string_to_char
|
||||
ssh_threads_get_default
|
||||
ssh_threads_get_noop
|
||||
ssh_threads_get_pthread
|
||||
ssh_threads_set_callbacks
|
||||
ssh_try_publickey_from_file
|
||||
ssh_userauth_agent
|
||||
ssh_userauth_agent_pubkey
|
||||
ssh_userauth_autopubkey
|
||||
ssh_userauth_gssapi
|
||||
ssh_userauth_kbdint
|
||||
ssh_userauth_kbdint_getanswer
|
||||
ssh_userauth_kbdint_getinstruction
|
||||
ssh_userauth_kbdint_getname
|
||||
ssh_userauth_kbdint_getnanswers
|
||||
ssh_userauth_kbdint_getnprompts
|
||||
ssh_userauth_kbdint_getprompt
|
||||
ssh_userauth_kbdint_setanswer
|
||||
ssh_userauth_list
|
||||
ssh_userauth_none
|
||||
ssh_userauth_offer_pubkey
|
||||
ssh_userauth_password
|
||||
ssh_userauth_privatekey_file
|
||||
ssh_userauth_pubkey
|
||||
ssh_userauth_publickey
|
||||
ssh_userauth_publickey_auto
|
||||
ssh_userauth_try_publickey
|
||||
ssh_version
|
||||
ssh_write_knownhost
|
||||
string_burn
|
||||
string_copy
|
||||
string_data
|
||||
string_fill
|
||||
string_free
|
||||
string_from_char
|
||||
string_len
|
||||
string_new
|
||||
string_to_char
|
||||
@@ -1,4 +1,7 @@
|
||||
set(LIBSSH_PUBLIC_INCLUDE_DIRS ${libssh_SOURCE_DIR}/include)
|
||||
set(LIBSSH_PUBLIC_INCLUDE_DIRS
|
||||
${libssh_SOURCE_DIR}/include
|
||||
CACHE INTERNAL "libssh public include directories"
|
||||
)
|
||||
|
||||
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
||||
${libssh_BINARY_DIR}
|
||||
@@ -15,6 +18,13 @@ if (WIN32)
|
||||
)
|
||||
endif (WIN32)
|
||||
|
||||
if (HAVE_LIBSOCKET)
|
||||
set(LIBSSH_LINK_LIBRARIES
|
||||
${LIBSSH_LINK_LIBRARIES}
|
||||
socket
|
||||
)
|
||||
endif (HAVE_LIBSOCKET)
|
||||
|
||||
if (OPENSSL_CRYPTO_LIBRARY)
|
||||
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
||||
${LIBSSH_PRIVATE_INCLUDE_DIRS}
|
||||
@@ -85,6 +95,16 @@ if (WITH_NACL AND NACL_FOUND)
|
||||
)
|
||||
endif (WITH_NACL AND NACL_FOUND)
|
||||
|
||||
set(LIBSSH_LINK_LIBRARIES
|
||||
${LIBSSH_LINK_LIBRARIES}
|
||||
CACHE INTERNAL "libssh link libraries"
|
||||
)
|
||||
|
||||
set(LIBSSH_SHARED_LIBRARY
|
||||
ssh_shared
|
||||
CACHE INTERNAL "libssh shared library"
|
||||
)
|
||||
|
||||
if (BUILD_STATIC_LIB)
|
||||
set(LIBSSH_STATIC_LIBRARY
|
||||
ssh_static
|
||||
@@ -110,7 +130,6 @@ set(libssh_SRCS
|
||||
error.c
|
||||
getpass.c
|
||||
init.c
|
||||
kdf.c
|
||||
kex.c
|
||||
known_hosts.c
|
||||
knownhosts.c
|
||||
@@ -126,6 +145,7 @@ set(libssh_SRCS
|
||||
pcap.c
|
||||
pki.c
|
||||
pki_container_openssh.c
|
||||
pki_ed25519.c
|
||||
poll.c
|
||||
session.c
|
||||
scp.c
|
||||
@@ -136,11 +156,12 @@ set(libssh_SRCS
|
||||
external/bcrypt_pbkdf.c
|
||||
external/blowfish.c
|
||||
external/chacha.c
|
||||
external/ed25519.c
|
||||
external/fe25519.c
|
||||
external/ge25519.c
|
||||
external/poly1305.c
|
||||
external/sc25519.c
|
||||
chachapoly.c
|
||||
config_parser.c
|
||||
token.c
|
||||
pki_ed25519_common.c
|
||||
)
|
||||
|
||||
if (DEFAULT_C_NO_DEPRECATION_FLAGS)
|
||||
@@ -176,12 +197,6 @@ if (WITH_GCRYPT)
|
||||
gcrypt_missing.c
|
||||
pki_gcrypt.c
|
||||
ecdh_gcrypt.c
|
||||
dh_key.c
|
||||
pki_ed25519.c
|
||||
external/ed25519.c
|
||||
external/fe25519.c
|
||||
external/ge25519.c
|
||||
external/sc25519.c
|
||||
)
|
||||
elseif (WITH_MBEDTLS)
|
||||
set(libssh_SRCS
|
||||
@@ -191,12 +206,6 @@ elseif (WITH_MBEDTLS)
|
||||
mbedcrypto_missing.c
|
||||
pki_mbedcrypto.c
|
||||
ecdh_mbedcrypto.c
|
||||
dh_key.c
|
||||
pki_ed25519.c
|
||||
external/ed25519.c
|
||||
external/fe25519.c
|
||||
external/ge25519.c
|
||||
external/sc25519.c
|
||||
)
|
||||
else (WITH_GCRYPT)
|
||||
set(libssh_SRCS
|
||||
@@ -205,18 +214,7 @@ else (WITH_GCRYPT)
|
||||
pki_crypto.c
|
||||
ecdh_crypto.c
|
||||
libcrypto.c
|
||||
dh_crypto.c
|
||||
)
|
||||
if (NOT HAVE_OPENSSL_ED25519)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
pki_ed25519.c
|
||||
external/ed25519.c
|
||||
external/fe25519.c
|
||||
external/ge25519.c
|
||||
external/sc25519.c
|
||||
)
|
||||
endif (NOT HAVE_OPENSSL_ED25519)
|
||||
if(OPENSSL_VERSION VERSION_LESS "1.1.0")
|
||||
set(libssh_SRCS ${libssh_SRCS} libcrypto-compat.c)
|
||||
endif()
|
||||
@@ -241,17 +239,9 @@ if (WITH_SERVER)
|
||||
${libssh_SRCS}
|
||||
server.c
|
||||
bind.c
|
||||
bind_config.c
|
||||
)
|
||||
endif (WITH_SERVER)
|
||||
|
||||
if (WITH_GEX)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
dh-gex.c
|
||||
)
|
||||
endif (WITH_GEX)
|
||||
|
||||
if (WITH_ZLIB)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
@@ -267,14 +257,17 @@ if (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||
endif (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||
|
||||
if (NOT WITH_NACL)
|
||||
if (NOT HAVE_OPENSSL_ED25519)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
external/curve25519_ref.c
|
||||
)
|
||||
endif (NOT HAVE_OPENSSL_ED25519)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
external/curve25519_ref.c
|
||||
)
|
||||
endif (NOT WITH_NACL)
|
||||
|
||||
include_directories(
|
||||
${LIBSSH_PUBLIC_INCLUDE_DIRS}
|
||||
${LIBSSH_PRIVATE_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
# Set the path to the default map file
|
||||
set(MAP_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.map")
|
||||
|
||||
@@ -306,23 +299,10 @@ if (WITH_SYMBOL_VERSIONING AND HAVE_LD_VERSION_SCRIPT AND ABIMAP_FOUND)
|
||||
)
|
||||
endif (WITH_SYMBOL_VERSIONING AND HAVE_LD_VERSION_SCRIPT AND ABIMAP_FOUND)
|
||||
|
||||
# This gets built as a static library, if -DBUILD_SHARED_LIBS=OFF is passed to
|
||||
# cmake.
|
||||
add_library(ssh ${libssh_SRCS})
|
||||
target_compile_options(ssh
|
||||
PRIVATE
|
||||
${DEFAULT_C_COMPILE_FLAGS}
|
||||
-D_GNU_SOURCE)
|
||||
target_include_directories(ssh
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${libssh_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
PRIVATE ${LIBSSH_PRIVATE_INCLUDE_DIRS})
|
||||
add_library(${LIBSSH_SHARED_LIBRARY} SHARED ${libssh_SRCS})
|
||||
target_compile_options(${LIBSSH_SHARED_LIBRARY} PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
|
||||
target_link_libraries(ssh
|
||||
PRIVATE ${LIBSSH_LINK_LIBRARIES})
|
||||
|
||||
add_library(ssh::ssh ALIAS ssh)
|
||||
target_link_libraries(${LIBSSH_SHARED_LIBRARY} ${LIBSSH_LINK_LIBRARIES})
|
||||
|
||||
if (WITH_SYMBOL_VERSIONING AND HAVE_LD_VERSION_SCRIPT)
|
||||
if (ABIMAP_FOUND)
|
||||
@@ -330,55 +310,45 @@ if (WITH_SYMBOL_VERSIONING AND HAVE_LD_VERSION_SCRIPT)
|
||||
set(MAP_PATH "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_dev.map")
|
||||
endif (ABIMAP_FOUND)
|
||||
|
||||
set_target_properties(ssh
|
||||
set_target_properties(${LIBSSH_SHARED_LIBRARY}
|
||||
PROPERTIES LINK_FLAGS
|
||||
"-Wl,--version-script,\"${MAP_PATH}\"")
|
||||
endif (WITH_SYMBOL_VERSIONING AND HAVE_LD_VERSION_SCRIPT)
|
||||
|
||||
set_target_properties(ssh
|
||||
set_target_properties(
|
||||
${LIBSSH_SHARED_LIBRARY}
|
||||
PROPERTIES
|
||||
VERSION
|
||||
${LIBRARY_VERSION}
|
||||
SOVERSION
|
||||
${LIBRARY_SOVERSION}
|
||||
OUTPUT_NAME
|
||||
ssh
|
||||
DEFINE_SYMBOL
|
||||
LIBSSH_EXPORTS
|
||||
)
|
||||
|
||||
if (WITH_VISIBILITY_HIDDEN)
|
||||
set_target_properties(ssh PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
|
||||
set_target_properties(${LIBSSH_SHARED_LIBRARY} PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
|
||||
endif (WITH_VISIBILITY_HIDDEN)
|
||||
|
||||
if (MINGW)
|
||||
set_target_properties(ssh PROPERTIES LINK_FLAGS "-Wl,--enable-stdcall-fixup")
|
||||
set_target_properties(${LIBSSH_SHARED_LIBRARY} PROPERTIES LINK_FLAGS "-Wl,--enable-stdcall-fixup")
|
||||
endif ()
|
||||
|
||||
|
||||
install(TARGETS ssh
|
||||
EXPORT libssh-config
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
COMPONENT libraries)
|
||||
|
||||
install(EXPORT libssh-config
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
|
||||
install(
|
||||
TARGETS
|
||||
${LIBSSH_SHARED_LIBRARY}
|
||||
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
|
||||
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
|
||||
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
|
||||
COMPONENT libraries
|
||||
)
|
||||
|
||||
if (BUILD_STATIC_LIB)
|
||||
add_library(ssh-static STATIC ${libssh_SRCS})
|
||||
target_compile_options(ssh-static
|
||||
PRIVATE
|
||||
${DEFAULT_C_COMPILE_FLAGS}
|
||||
-D_GNU_SOURCE)
|
||||
|
||||
target_include_directories(ssh-static
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${libssh_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
PRIVATE ${LIBSSH_PRIVATE_INCLUDE_DIRS})
|
||||
target_link_libraries(ssh-static
|
||||
PUBLIC ${LIBSSH_LINK_LIBRARIES})
|
||||
add_library(ssh::static ALIAS ssh-static)
|
||||
add_library(${LIBSSH_STATIC_LIBRARY} STATIC ${libssh_SRCS})
|
||||
target_compile_options(${LIBSSH_STATIC_LIBRARY} PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
|
||||
if (MSVC)
|
||||
set(OUTPUT_SUFFIX static)
|
||||
@@ -386,7 +356,7 @@ if (BUILD_STATIC_LIB)
|
||||
set(OUTPUT_SUFFIX )
|
||||
endif (MSVC)
|
||||
set_target_properties(
|
||||
ssh-static
|
||||
${LIBSSH_STATIC_LIBRARY}
|
||||
PROPERTIES
|
||||
VERSION
|
||||
${LIBRARY_VERSION}
|
||||
@@ -400,12 +370,21 @@ if (BUILD_STATIC_LIB)
|
||||
|
||||
if (WIN32)
|
||||
set_target_properties(
|
||||
ssh-static
|
||||
${LIBSSH_STATIC_LIBRARY}
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS
|
||||
"-DLIBSSH_STATIC"
|
||||
)
|
||||
endif (WIN32)
|
||||
|
||||
if (WITH_STATIC_LIB)
|
||||
install(TARGETS
|
||||
${LIBSSH_STATIC_LIBRARY}
|
||||
DESTINATION
|
||||
${LIB_INSTALL_DIR}/${OUTPUT_SUFFIX}
|
||||
COMPONENT
|
||||
libraries)
|
||||
endif (WITH_STATIC_LIB)
|
||||
endif (BUILD_STATIC_LIB)
|
||||
|
||||
message(STATUS "Threads_FOUND=${Threads_FOUND}")
|
||||
|
||||
@@ -536,7 +536,7 @@ ssh_string ssh_agent_sign_data(ssh_session session,
|
||||
}
|
||||
|
||||
/* Add Flags: SHA2 extension (RFC 8332) if negotiated */
|
||||
if (ssh_key_type_plain(pubkey->type) == SSH_KEYTYPE_RSA) {
|
||||
if (pubkey->type == SSH_KEYTYPE_RSA) {
|
||||
if (session->extensions & SSH_EXT_SIG_RSA_SHA512) {
|
||||
flags |= SSH_AGENT_RSA_SHA2_512;
|
||||
} else if (session->extensions & SSH_EXT_SIG_RSA_SHA256) {
|
||||
|
||||
78
src/auth.c
78
src/auth.c
@@ -25,7 +25,6 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <netinet/in.h>
|
||||
@@ -70,7 +69,7 @@ static int ssh_userauth_request_service(ssh_session session) {
|
||||
int rc;
|
||||
|
||||
rc = ssh_service_request(session, "ssh-userauth");
|
||||
if ((rc != SSH_OK) && (rc != SSH_AGAIN)) {
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"Failed to request \"ssh-userauth\" service");
|
||||
}
|
||||
@@ -283,10 +282,7 @@ end:
|
||||
*
|
||||
* It is also used to communicate the new to the upper levels.
|
||||
*/
|
||||
SSH_PACKET_CALLBACK(ssh_packet_userauth_success)
|
||||
{
|
||||
struct ssh_crypto_struct *crypto = NULL;
|
||||
|
||||
SSH_PACKET_CALLBACK(ssh_packet_userauth_success) {
|
||||
(void)packet;
|
||||
(void)type;
|
||||
(void)user;
|
||||
@@ -298,16 +294,13 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_success)
|
||||
session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
|
||||
session->flags |= SSH_SESSION_FLAG_AUTHENTICATED;
|
||||
|
||||
crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_OUT);
|
||||
if (crypto != NULL && crypto->delayed_compress_out) {
|
||||
if (session->current_crypto && session->current_crypto->delayed_compress_out) {
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Enabling delayed compression OUT");
|
||||
crypto->do_compress_out = 1;
|
||||
session->current_crypto->do_compress_out = 1;
|
||||
}
|
||||
|
||||
crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_IN);
|
||||
if (crypto != NULL && crypto->delayed_compress_in) {
|
||||
if (session->current_crypto && session->current_crypto->delayed_compress_in) {
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Enabling delayed compression IN");
|
||||
crypto->do_compress_in = 1;
|
||||
session->current_crypto->do_compress_in = 1;
|
||||
}
|
||||
|
||||
/* Reset errors by previous authentication methods. */
|
||||
@@ -516,13 +509,26 @@ int ssh_userauth_try_publickey(ssh_session session,
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* Check if the given public key algorithm is allowed */
|
||||
sig_type_c = ssh_key_get_signature_algorithm(session, pubkey->type);
|
||||
if (sig_type_c == NULL) {
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
switch (pubkey->type) {
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
"Invalid key type (unknown)");
|
||||
return SSH_AUTH_DENIED;
|
||||
case SSH_KEYTYPE_ECDSA:
|
||||
sig_type_c = ssh_pki_key_ecdsa_name(pubkey);
|
||||
break;
|
||||
case SSH_KEYTYPE_DSS:
|
||||
case SSH_KEYTYPE_RSA:
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
case SSH_KEYTYPE_DSS_CERT01:
|
||||
case SSH_KEYTYPE_RSA_CERT01:
|
||||
sig_type_c = ssh_key_get_signature_algorithm(session, pubkey->type);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check if the given public key algorithm is allowed */
|
||||
if (!ssh_key_algorithm_allowed(session, sig_type_c)) {
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"The key algorithm '%s' is not allowed to be used by"
|
||||
@@ -614,7 +620,6 @@ int ssh_userauth_publickey(ssh_session session,
|
||||
int rc;
|
||||
const char *sig_type_c = NULL;
|
||||
enum ssh_keytypes_e key_type;
|
||||
enum ssh_digest_e hash_type;
|
||||
|
||||
if (session == NULL) {
|
||||
return SSH_AUTH_ERROR;
|
||||
@@ -640,13 +645,26 @@ int ssh_userauth_publickey(ssh_session session,
|
||||
/* Cert auth requires presenting the cert type name (*-cert@openssh.com) */
|
||||
key_type = privkey->cert != NULL ? privkey->cert_type : privkey->type;
|
||||
|
||||
/* Check if the given public key algorithm is allowed */
|
||||
sig_type_c = ssh_key_get_signature_algorithm(session, key_type);
|
||||
if (sig_type_c == NULL) {
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
switch (key_type) {
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
"Invalid key type (unknown)");
|
||||
return SSH_AUTH_DENIED;
|
||||
case SSH_KEYTYPE_ECDSA:
|
||||
sig_type_c = ssh_pki_key_ecdsa_name(privkey);
|
||||
break;
|
||||
case SSH_KEYTYPE_DSS:
|
||||
case SSH_KEYTYPE_RSA:
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
case SSH_KEYTYPE_DSS_CERT01:
|
||||
case SSH_KEYTYPE_RSA_CERT01:
|
||||
sig_type_c = ssh_key_get_signature_algorithm(session, key_type);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check if the given public key algorithm is allowed */
|
||||
if (!ssh_key_algorithm_allowed(session, sig_type_c)) {
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"The key algorithm '%s' is not allowed to be used by"
|
||||
@@ -683,11 +701,8 @@ int ssh_userauth_publickey(ssh_session session,
|
||||
}
|
||||
ssh_string_free(str);
|
||||
|
||||
/* Get the hash type to be used in the signature based on the key type */
|
||||
hash_type = ssh_key_type_to_hash(session, privkey->type);
|
||||
|
||||
/* sign the buffer with the private key */
|
||||
str = ssh_pki_do_sign(session, session->out_buffer, privkey, hash_type);
|
||||
str = ssh_pki_do_sign(session, session->out_buffer, privkey);
|
||||
if (str == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
@@ -756,15 +771,9 @@ static int ssh_userauth_agent_publickey(ssh_session session,
|
||||
if (rc < 0) {
|
||||
goto fail;
|
||||
}
|
||||
sig_type_c = ssh_key_get_signature_algorithm(session, pubkey->type);
|
||||
|
||||
/* Check if the given public key algorithm is allowed */
|
||||
sig_type_c = ssh_key_get_signature_algorithm(session, pubkey->type);
|
||||
if (sig_type_c == NULL) {
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"Invalid key type (unknown)");
|
||||
SSH_STRING_FREE(pubkey_s);
|
||||
return SSH_AUTH_DENIED;
|
||||
}
|
||||
if (!ssh_key_algorithm_allowed(session, sig_type_c)) {
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"The key algorithm '%s' is not allowed to be used by"
|
||||
@@ -1262,9 +1271,6 @@ int ssh_userauth_password(ssh_session session,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Set the buffer as secure to be explicitly zeroed when freed */
|
||||
ssh_buffer_set_secure(session->out_buffer);
|
||||
|
||||
session->auth.current_method = SSH_AUTH_METHOD_PASSWORD;
|
||||
session->auth.state = SSH_AUTH_STATE_PASSWORD_AUTH_SENT;
|
||||
session->pending_call_state = SSH_PENDING_CALL_AUTH_PASSWORD;
|
||||
|
||||
67
src/bignum.c
67
src/bignum.c
@@ -56,39 +56,70 @@ ssh_string ssh_make_bignum_string(bignum num) {
|
||||
ptr->data[0] = 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
bignum_bn2bin(num, len, ptr->data + pad);
|
||||
#elif HAVE_LIBCRYPTO
|
||||
bignum_bn2bin(num, ptr->data + pad);
|
||||
#elif HAVE_LIBMBEDCRYPTO
|
||||
bignum_bn2bin(num, ptr->data + pad);
|
||||
#endif
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bignum ssh_make_string_bn(ssh_string string)
|
||||
{
|
||||
bignum bn = NULL;
|
||||
size_t len = ssh_string_len(string);
|
||||
bignum ssh_make_string_bn(ssh_string string){
|
||||
bignum bn = NULL;
|
||||
size_t len = ssh_string_len(string);
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
fprintf(stderr, "Importing a %zu bits, %zu bytes object ...\n",
|
||||
len * 8, len);
|
||||
fprintf(stderr, "Importing a %d bits, %d bytes object ...\n",
|
||||
len * 8, len);
|
||||
#endif /* DEBUG_CRYPTO */
|
||||
|
||||
bignum_bin2bn(string->data, len, &bn);
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
bignum_bin2bn(string->data, len, &bn);
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
bn = bignum_bin2bn(string->data, len, NULL);
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
bn = bignum_new();
|
||||
bignum_bin2bn(string->data, len, bn);
|
||||
#endif
|
||||
|
||||
return bn;
|
||||
return bn;
|
||||
}
|
||||
|
||||
void ssh_make_string_bn_inplace(ssh_string string,
|
||||
UNUSED_PARAM(bignum bnout))
|
||||
{
|
||||
UNUSED_VAR(size_t len) = ssh_string_len(string);
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
/* XXX: FIXME as needed for LIBGCRYPT ECDSA codepaths. */
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
bignum_bin2bn(string->data, len, bnout);
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
bignum_bin2bn(string->data, len, bnout);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* prints the bignum on stderr */
|
||||
void ssh_print_bignum(const char *name, const_bignum num)
|
||||
{
|
||||
unsigned char *hex = NULL;
|
||||
if (num != NULL) {
|
||||
bignum_bn2hex(num, &hex);
|
||||
}
|
||||
fprintf(stderr, "%s value: %s\n", name, (hex == NULL) ? "(null)" : (char *) hex);
|
||||
void ssh_print_bignum(const char *which, const bignum num) {
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
SAFE_FREE(hex);
|
||||
unsigned char *hex = NULL;
|
||||
bignum_bn2hex(num, &hex);
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
OPENSSL_free(hex);
|
||||
char *hex = NULL;
|
||||
hex = bignum_bn2hex(num);
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
SAFE_FREE(hex);
|
||||
char *hex = NULL;
|
||||
hex = bignum_bn2hex(num);
|
||||
#endif
|
||||
fprintf(stderr, "%s value: ", which);
|
||||
fprintf(stderr, "%s\n", (hex == NULL) ? "(null)" : (char *) hex);
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
SAFE_FREE(hex);
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
OPENSSL_free(hex);
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
SAFE_FREE(hex);
|
||||
#endif
|
||||
}
|
||||
|
||||
82
src/bind.c
82
src/bind.c
@@ -38,7 +38,6 @@
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/socket.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/token.h"
|
||||
|
||||
/**
|
||||
* @addtogroup libssh_server
|
||||
@@ -131,17 +130,18 @@ static socket_t bind_socket(ssh_bind sshbind, const char *hostname,
|
||||
}
|
||||
|
||||
ssh_bind ssh_bind_new(void) {
|
||||
ssh_bind ptr;
|
||||
ssh_bind ptr;
|
||||
|
||||
ptr = calloc(1, sizeof(struct ssh_bind_struct));
|
||||
if (ptr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ptr->bindfd = SSH_INVALID_SOCKET;
|
||||
ptr->bindport = 22;
|
||||
ptr->common.log_verbosity = 0;
|
||||
ptr = malloc(sizeof(struct ssh_bind_struct));
|
||||
if (ptr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ZERO_STRUCTP(ptr);
|
||||
ptr->bindfd = SSH_INVALID_SOCKET;
|
||||
ptr->bindport= 22;
|
||||
ptr->common.log_verbosity = 0;
|
||||
|
||||
return ptr;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static int ssh_bind_import_keys(ssh_bind sshbind) {
|
||||
@@ -169,7 +169,7 @@ static int ssh_bind_import_keys(ssh_bind sshbind) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (!is_ecdsa_key_type(ssh_key_type(sshbind->ecdsa))) {
|
||||
if (ssh_key_type(sshbind->ecdsa) != SSH_KEYTYPE_ECDSA) {
|
||||
ssh_set_error(sshbind, SSH_FATAL,
|
||||
"The ECDSA host key has the wrong type");
|
||||
ssh_key_free(sshbind->ecdsa);
|
||||
@@ -343,24 +343,12 @@ static int ssh_bind_poll_callback(ssh_poll_handle sshpoll,
|
||||
* @param sshbind the ssh_bind object
|
||||
* @returns a ssh_poll handle suitable for operation
|
||||
*/
|
||||
ssh_poll_handle ssh_bind_get_poll(ssh_bind sshbind)
|
||||
{
|
||||
short events = POLLIN;
|
||||
|
||||
if (sshbind->poll) {
|
||||
return sshbind->poll;
|
||||
}
|
||||
|
||||
#ifdef POLLRDHUP
|
||||
events |= POLLRDHUP;
|
||||
#endif /* POLLRDHUP */
|
||||
|
||||
sshbind->poll = ssh_poll_new(sshbind->bindfd,
|
||||
events,
|
||||
ssh_bind_poll_callback,
|
||||
sshbind);
|
||||
|
||||
ssh_poll_handle ssh_bind_get_poll(ssh_bind sshbind){
|
||||
if(sshbind->poll)
|
||||
return sshbind->poll;
|
||||
sshbind->poll=ssh_poll_new(sshbind->bindfd,POLLIN,
|
||||
ssh_bind_poll_callback,sshbind);
|
||||
return sshbind->poll;
|
||||
}
|
||||
|
||||
void ssh_bind_set_blocking(ssh_bind sshbind, int blocking) {
|
||||
@@ -394,8 +382,6 @@ void ssh_bind_free(ssh_bind sshbind){
|
||||
/* options */
|
||||
SAFE_FREE(sshbind->banner);
|
||||
SAFE_FREE(sshbind->bindaddr);
|
||||
SAFE_FREE(sshbind->config_dir);
|
||||
SAFE_FREE(sshbind->pubkey_accepted_key_types);
|
||||
|
||||
SAFE_FREE(sshbind->dsakey);
|
||||
SAFE_FREE(sshbind->rsakey);
|
||||
@@ -423,25 +409,14 @@ void ssh_bind_free(ssh_bind sshbind){
|
||||
int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
|
||||
int i, rc;
|
||||
|
||||
if (sshbind == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (session == NULL){
|
||||
ssh_set_error(sshbind, SSH_FATAL,"session is null");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* Apply global bind configurations, if it hasn't been applied before */
|
||||
rc = ssh_bind_options_parse_config(sshbind, NULL);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(sshbind, SSH_FATAL,"Could not parse global config");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
session->server = 1;
|
||||
|
||||
/* Copy options from bind to session */
|
||||
/* copy options */
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (sshbind->wanted_methods[i]) {
|
||||
session->opts.wanted_methods[i] = strdup(sshbind->wanted_methods[i]);
|
||||
@@ -461,29 +436,6 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
|
||||
}
|
||||
}
|
||||
|
||||
if (sshbind->pubkey_accepted_key_types != NULL) {
|
||||
if (session->opts.pubkey_accepted_types == NULL) {
|
||||
session->opts.pubkey_accepted_types = strdup(sshbind->pubkey_accepted_key_types);
|
||||
if (session->opts.pubkey_accepted_types == NULL) {
|
||||
ssh_set_error_oom(sshbind);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
} else {
|
||||
char *p;
|
||||
/* If something was set to the session prior to calling this
|
||||
* function, keep only what is allowed by the options set in
|
||||
* sshbind */
|
||||
p = ssh_find_all_matching(sshbind->pubkey_accepted_key_types,
|
||||
session->opts.pubkey_accepted_types);
|
||||
if (p == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
SAFE_FREE(session->opts.pubkey_accepted_types);
|
||||
session->opts.pubkey_accepted_types = p;
|
||||
}
|
||||
}
|
||||
|
||||
session->common.log_verbosity = sshbind->common.log_verbosity;
|
||||
if(sshbind->banner != NULL)
|
||||
session->opts.custombanner = strdup(sshbind->banner);
|
||||
|
||||
@@ -1,638 +0,0 @@
|
||||
/*
|
||||
* bind_config.c - Parse the SSH server configuration file
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2019 by Red Hat, Inc.
|
||||
*
|
||||
* Author: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
*
|
||||
* 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 <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_GLOB_H
|
||||
# include <glob.h>
|
||||
#endif
|
||||
|
||||
#include "libssh/bind.h"
|
||||
#include "libssh/bind_config.h"
|
||||
#include "libssh/config_parser.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/server.h"
|
||||
#include "libssh/options.h"
|
||||
|
||||
#define MAX_LINE_SIZE 1024
|
||||
|
||||
/* Flags used for the parser state */
|
||||
#define PARSING 1
|
||||
#define IN_MATCH (1<<1)
|
||||
|
||||
struct ssh_bind_config_keyword_table_s {
|
||||
const char *name;
|
||||
enum ssh_bind_config_opcode_e opcode;
|
||||
bool allowed_in_match;
|
||||
};
|
||||
|
||||
static struct ssh_bind_config_keyword_table_s
|
||||
ssh_bind_config_keyword_table[] = {
|
||||
{
|
||||
.name = "include",
|
||||
.opcode = BIND_CFG_INCLUDE
|
||||
},
|
||||
{
|
||||
.name = "hostkey",
|
||||
.opcode = BIND_CFG_HOSTKEY
|
||||
},
|
||||
{
|
||||
.name = "listenaddress",
|
||||
.opcode = BIND_CFG_LISTENADDRESS
|
||||
},
|
||||
{
|
||||
.name = "port",
|
||||
.opcode = BIND_CFG_PORT
|
||||
},
|
||||
{
|
||||
.name = "loglevel",
|
||||
.opcode = BIND_CFG_LOGLEVEL,
|
||||
.allowed_in_match = true,
|
||||
},
|
||||
{
|
||||
.name = "ciphers",
|
||||
.opcode = BIND_CFG_CIPHERS
|
||||
},
|
||||
{
|
||||
.name = "macs",
|
||||
.opcode = BIND_CFG_MACS
|
||||
},
|
||||
{
|
||||
.name = "kexalgorithms",
|
||||
.opcode = BIND_CFG_KEXALGORITHMS
|
||||
},
|
||||
{
|
||||
.name = "match",
|
||||
.opcode = BIND_CFG_MATCH,
|
||||
.allowed_in_match = true
|
||||
},
|
||||
{
|
||||
.name = "pubkeyacceptedkeytypes",
|
||||
.opcode = BIND_CFG_PUBKEY_ACCEPTED_KEY_TYPES,
|
||||
.allowed_in_match = true
|
||||
},
|
||||
{
|
||||
.name = "hostkeyalgorithms",
|
||||
.opcode = BIND_CFG_HOSTKEY_ALGORITHMS,
|
||||
.allowed_in_match = true
|
||||
},
|
||||
{
|
||||
.opcode = BIND_CFG_UNKNOWN,
|
||||
}
|
||||
};
|
||||
|
||||
enum ssh_bind_config_match_e {
|
||||
BIND_MATCH_UNKNOWN = -1,
|
||||
BIND_MATCH_ALL,
|
||||
BIND_MATCH_USER,
|
||||
BIND_MATCH_GROUP,
|
||||
BIND_MATCH_HOST,
|
||||
BIND_MATCH_LOCALADDRESS,
|
||||
BIND_MATCH_LOCALPORT,
|
||||
BIND_MATCH_RDOMAIN,
|
||||
BIND_MATCH_ADDRESS,
|
||||
};
|
||||
|
||||
struct ssh_bind_config_match_keyword_table_s {
|
||||
const char *name;
|
||||
enum ssh_bind_config_match_e opcode;
|
||||
};
|
||||
|
||||
static struct ssh_bind_config_match_keyword_table_s
|
||||
ssh_bind_config_match_keyword_table[] = {
|
||||
{
|
||||
.name = "all",
|
||||
.opcode = BIND_MATCH_ALL
|
||||
},
|
||||
{
|
||||
.name = "user",
|
||||
.opcode = BIND_MATCH_USER
|
||||
},
|
||||
{
|
||||
.name = "group",
|
||||
.opcode = BIND_MATCH_GROUP
|
||||
},
|
||||
{
|
||||
.name = "host",
|
||||
.opcode = BIND_MATCH_HOST
|
||||
},
|
||||
{
|
||||
.name = "localaddress",
|
||||
.opcode = BIND_MATCH_LOCALADDRESS
|
||||
},
|
||||
{
|
||||
.name = "localport",
|
||||
.opcode = BIND_MATCH_LOCALPORT
|
||||
},
|
||||
{
|
||||
.name = "rdomain",
|
||||
.opcode = BIND_MATCH_RDOMAIN
|
||||
},
|
||||
{
|
||||
.name = "address",
|
||||
.opcode = BIND_MATCH_ADDRESS
|
||||
},
|
||||
{
|
||||
.opcode = BIND_MATCH_UNKNOWN
|
||||
},
|
||||
};
|
||||
|
||||
static enum ssh_bind_config_opcode_e
|
||||
ssh_bind_config_get_opcode(char *keyword, uint32_t *parser_flags)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; ssh_bind_config_keyword_table[i].name != NULL; i++) {
|
||||
if (strcasecmp(keyword, ssh_bind_config_keyword_table[i].name) == 0) {
|
||||
if ((*parser_flags & IN_MATCH) &&
|
||||
!(ssh_bind_config_keyword_table[i].allowed_in_match))
|
||||
{
|
||||
return BIND_CFG_NOT_ALLOWED_IN_MATCH;
|
||||
}
|
||||
return ssh_bind_config_keyword_table[i].opcode;
|
||||
}
|
||||
}
|
||||
|
||||
return BIND_CFG_UNKNOWN;
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_bind_config_parse_line(ssh_bind bind,
|
||||
const char *line,
|
||||
unsigned int count,
|
||||
uint32_t *parser_flags,
|
||||
uint8_t *seen);
|
||||
|
||||
static void local_parse_file(ssh_bind bind,
|
||||
const char *filename,
|
||||
uint32_t *parser_flags,
|
||||
uint8_t *seen)
|
||||
{
|
||||
FILE *f;
|
||||
char line[MAX_LINE_SIZE] = {0};
|
||||
unsigned int count = 0;
|
||||
int rv;
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if (f == NULL) {
|
||||
SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
|
||||
filename);
|
||||
return;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Reading additional configuration data from %s",
|
||||
filename);
|
||||
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
count++;
|
||||
rv = ssh_bind_config_parse_line(bind, line, count, parser_flags, seen);
|
||||
if (rv < 0) {
|
||||
fclose(f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(HAVE_GLOB) && defined(HAVE_GLOB_GL_FLAGS_MEMBER)
|
||||
static void local_parse_glob(ssh_bind bind,
|
||||
const char *fileglob,
|
||||
uint32_t *parser_flags,
|
||||
uint8_t *seen)
|
||||
{
|
||||
glob_t globbuf = {
|
||||
.gl_flags = 0,
|
||||
};
|
||||
int rt;
|
||||
u_int i;
|
||||
|
||||
rt = glob(fileglob, GLOB_TILDE, NULL, &globbuf);
|
||||
if (rt == GLOB_NOMATCH) {
|
||||
globfree(&globbuf);
|
||||
return;
|
||||
} else if (rt != 0) {
|
||||
SSH_LOG(SSH_LOG_RARE, "Glob error: %s",
|
||||
fileglob);
|
||||
globfree(&globbuf);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < globbuf.gl_pathc; i++) {
|
||||
local_parse_file(bind, globbuf.gl_pathv[i], parser_flags, seen);
|
||||
}
|
||||
|
||||
globfree(&globbuf);
|
||||
}
|
||||
#endif /* HAVE_GLOB HAVE_GLOB_GL_FLAGS_MEMBER */
|
||||
|
||||
static enum ssh_bind_config_match_e
|
||||
ssh_bind_config_get_match_opcode(const char *keyword)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; ssh_bind_config_match_keyword_table[i].name != NULL; i++) {
|
||||
if (strcasecmp(keyword, ssh_bind_config_match_keyword_table[i].name) == 0) {
|
||||
return ssh_bind_config_match_keyword_table[i].opcode;
|
||||
}
|
||||
}
|
||||
|
||||
return BIND_MATCH_UNKNOWN;
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_bind_config_parse_line(ssh_bind bind,
|
||||
const char *line,
|
||||
unsigned int count,
|
||||
uint32_t *parser_flags,
|
||||
uint8_t *seen)
|
||||
{
|
||||
enum ssh_bind_config_opcode_e opcode;
|
||||
const char *p = NULL;
|
||||
char *s = NULL, *x = NULL;
|
||||
char *keyword = NULL;
|
||||
size_t len;
|
||||
|
||||
int rc = 0;
|
||||
|
||||
if (bind == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((line == NULL) || (parser_flags == NULL)) {
|
||||
ssh_set_error_invalid(bind);
|
||||
return -1;
|
||||
}
|
||||
|
||||
x = s = strdup(line);
|
||||
if (s == NULL) {
|
||||
ssh_set_error_oom(bind);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Remove trailing spaces */
|
||||
for (len = strlen(s) - 1; len > 0; len--) {
|
||||
if (! isspace(s[len])) {
|
||||
break;
|
||||
}
|
||||
s[len] = '\0';
|
||||
}
|
||||
|
||||
keyword = ssh_config_get_token(&s);
|
||||
if (keyword == NULL || *keyword == '#' ||
|
||||
*keyword == '\0' || *keyword == '\n') {
|
||||
SAFE_FREE(x);
|
||||
return 0;
|
||||
}
|
||||
|
||||
opcode = ssh_bind_config_get_opcode(keyword, parser_flags);
|
||||
if ((*parser_flags & PARSING) &&
|
||||
opcode != BIND_CFG_HOSTKEY &&
|
||||
opcode != BIND_CFG_INCLUDE &&
|
||||
opcode != BIND_CFG_MATCH &&
|
||||
opcode > BIND_CFG_UNSUPPORTED) { /* Ignore all unknown types here */
|
||||
/* Skip all the options that were already applied */
|
||||
if (seen[opcode] != 0) {
|
||||
SAFE_FREE(x);
|
||||
return 0;
|
||||
}
|
||||
seen[opcode] = 1;
|
||||
}
|
||||
|
||||
switch (opcode) {
|
||||
case BIND_CFG_INCLUDE:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && (*parser_flags & PARSING)) {
|
||||
#if defined(HAVE_GLOB) && defined(HAVE_GLOB_GL_FLAGS_MEMBER)
|
||||
local_parse_glob(bind, p, parser_flags, seen);
|
||||
#else
|
||||
local_parse_file(bind, p, parser_flags, seen);
|
||||
#endif /* HAVE_GLOB */
|
||||
}
|
||||
break;
|
||||
|
||||
case BIND_CFG_HOSTKEY:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && (*parser_flags & PARSING)) {
|
||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HOSTKEY, p);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Failed to set Hostkey value '%s'",
|
||||
count, p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BIND_CFG_LISTENADDRESS:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && (*parser_flags & PARSING)) {
|
||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_BINDADDR, p);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Failed to set ListenAddress value '%s'",
|
||||
count, p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BIND_CFG_PORT:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && (*parser_flags & PARSING)) {
|
||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_BINDPORT_STR, p);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Failed to set Port value '%s'",
|
||||
count, p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BIND_CFG_CIPHERS:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && (*parser_flags & PARSING)) {
|
||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_CIPHERS_C_S, p);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Failed to set C->S Ciphers value '%s'",
|
||||
count, p);
|
||||
break;
|
||||
}
|
||||
|
||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_CIPHERS_S_C, p);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Failed to set S->C Ciphers value '%s'",
|
||||
count, p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BIND_CFG_MACS:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && (*parser_flags & PARSING)) {
|
||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HMAC_C_S, p);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Failed to set C->S MAC value '%s'",
|
||||
count, p);
|
||||
break;
|
||||
}
|
||||
|
||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HMAC_S_C, p);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Failed to set S->C MAC value '%s'",
|
||||
count, p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BIND_CFG_LOGLEVEL:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && (*parser_flags & PARSING)) {
|
||||
int value = -1;
|
||||
|
||||
if (strcasecmp(p, "quiet") == 0) {
|
||||
value = SSH_LOG_NONE;
|
||||
} else if (strcasecmp(p, "fatal") == 0 ||
|
||||
strcasecmp(p, "error")== 0 ||
|
||||
strcasecmp(p, "info") == 0) {
|
||||
value = SSH_LOG_WARN;
|
||||
} else if (strcasecmp(p, "verbose") == 0) {
|
||||
value = SSH_LOG_INFO;
|
||||
} else if (strcasecmp(p, "DEBUG") == 0 ||
|
||||
strcasecmp(p, "DEBUG1") == 0) {
|
||||
value = SSH_LOG_DEBUG;
|
||||
} else if (strcasecmp(p, "DEBUG2") == 0 ||
|
||||
strcasecmp(p, "DEBUG3") == 0) {
|
||||
value = SSH_LOG_TRACE;
|
||||
}
|
||||
if (value != -1) {
|
||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_LOG_VERBOSITY,
|
||||
&value);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Failed to set LogLevel value '%s'",
|
||||
count, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BIND_CFG_KEXALGORITHMS:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && (*parser_flags & PARSING)) {
|
||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_KEY_EXCHANGE, p);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Failed to set KexAlgorithms value '%s'",
|
||||
count, p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BIND_CFG_MATCH: {
|
||||
bool negate;
|
||||
int result = PARSING;
|
||||
size_t args = 0;
|
||||
enum ssh_bind_config_match_e opt;
|
||||
const char *p2 = NULL;
|
||||
|
||||
/* The options set in Match blocks should be applied when a connection
|
||||
* is accepted, and not right away when parsing the file (as it is
|
||||
* currently done). This means the configuration files should be parsed
|
||||
* again or the options set in the Match blocks should be stored and
|
||||
* applied as necessary. */
|
||||
|
||||
/* If this is the first Match block, erase the seen table to allow
|
||||
* options to be overridden. Erasing the seen table was the easiest way
|
||||
* to allow overriding an option, but only for the first occurrence of
|
||||
* an option in a Match block. This is sufficient for the current
|
||||
* implementation which supports only the 'All' criterion, meaning the
|
||||
* options can be applied right away. */
|
||||
if (!(*parser_flags & IN_MATCH)) {
|
||||
memset(seen, 0x00, BIND_CFG_MAX * sizeof(uint8_t));
|
||||
}
|
||||
|
||||
/* In this line the PARSING bit is cleared from the flags */
|
||||
*parser_flags = IN_MATCH;
|
||||
do {
|
||||
p = p2 = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p == NULL || p[0] == '\0') {
|
||||
break;
|
||||
}
|
||||
args++;
|
||||
SSH_LOG(SSH_LOG_TRACE, "line %d: Processing Match keyword '%s'",
|
||||
count, p);
|
||||
|
||||
/* If the option is prefixed with ! the result should be negated */
|
||||
negate = false;
|
||||
if (p[0] == '!') {
|
||||
negate = true;
|
||||
p++;
|
||||
}
|
||||
|
||||
opt = ssh_bind_config_get_match_opcode(p);
|
||||
switch (opt) {
|
||||
case BIND_MATCH_ALL:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if ((args == 1) && (p == NULL || p[0] == '\0')) {
|
||||
/* The "all" keyword does not accept arguments or modifiers
|
||||
*/
|
||||
if (negate == true) {
|
||||
result = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ssh_set_error(bind, SSH_FATAL,
|
||||
"line %d: ERROR - Match all cannot be combined with "
|
||||
"other Match attributes", count);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
case BIND_MATCH_USER:
|
||||
case BIND_MATCH_GROUP:
|
||||
case BIND_MATCH_HOST:
|
||||
case BIND_MATCH_LOCALADDRESS:
|
||||
case BIND_MATCH_LOCALPORT:
|
||||
case BIND_MATCH_RDOMAIN:
|
||||
case BIND_MATCH_ADDRESS:
|
||||
/* Only "All" is supported for now */
|
||||
/* Skip one argument */
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p == NULL || p[0] == '\0') {
|
||||
SSH_LOG(SSH_LOG_WARN, "line %d: Match keyword "
|
||||
"'%s' requires argument\n", count, p2);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
args++;
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Unsupported Match keyword '%s', ignoring\n",
|
||||
count,
|
||||
p2);
|
||||
result = 0;
|
||||
break;
|
||||
case BIND_MATCH_UNKNOWN:
|
||||
default:
|
||||
ssh_set_error(bind, SSH_FATAL,
|
||||
"ERROR - Unknown argument '%s' for Match keyword", p);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
} while (p != NULL && p[0] != '\0');
|
||||
if (args == 0) {
|
||||
ssh_set_error(bind, SSH_FATAL,
|
||||
"ERROR - Match keyword requires an argument");
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
/* This line only sets the PARSING flag if all checks passed */
|
||||
*parser_flags |= result;
|
||||
break;
|
||||
}
|
||||
case BIND_CFG_PUBKEY_ACCEPTED_KEY_TYPES:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && (*parser_flags & PARSING)) {
|
||||
rc = ssh_bind_options_set(bind,
|
||||
SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES, p);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Failed to set PubKeyAcceptedKeyTypes value '%s'",
|
||||
count, p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BIND_CFG_HOSTKEY_ALGORITHMS:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && (*parser_flags & PARSING)) {
|
||||
rc = ssh_bind_options_set(bind,
|
||||
SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS, p);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Failed to set HostkeyAlgorithms value '%s'",
|
||||
count, p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BIND_CFG_NOT_ALLOWED_IN_MATCH:
|
||||
SSH_LOG(SSH_LOG_WARN, "Option not allowed in Match block: %s, line: %d",
|
||||
keyword, count);
|
||||
break;
|
||||
case BIND_CFG_UNKNOWN:
|
||||
SSH_LOG(SSH_LOG_WARN, "Unknown option: %s, line: %d",
|
||||
keyword, count);
|
||||
break;
|
||||
case BIND_CFG_UNSUPPORTED:
|
||||
SSH_LOG(SSH_LOG_WARN, "Unsupported option: %s, line: %d",
|
||||
keyword, count);
|
||||
break;
|
||||
case BIND_CFG_NA:
|
||||
SSH_LOG(SSH_LOG_WARN, "Option not applicable: %s, line: %d",
|
||||
keyword, count);
|
||||
break;
|
||||
default:
|
||||
ssh_set_error(bind, SSH_FATAL, "ERROR - unimplemented opcode: %d",
|
||||
opcode);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
SAFE_FREE(x);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ssh_bind_config_parse_file(ssh_bind bind, const char *filename)
|
||||
{
|
||||
char line[MAX_LINE_SIZE] = {0};
|
||||
unsigned int count = 0;
|
||||
FILE *f;
|
||||
uint32_t parser_flags;
|
||||
int rv;
|
||||
|
||||
/* This local table is used during the parsing of the current file (and
|
||||
* files included recursively in this file) to prevent an option to be
|
||||
* redefined, i.e. the first value set is kept. But this DO NOT prevent the
|
||||
* option to be redefined later by another file. */
|
||||
uint8_t seen[BIND_CFG_MAX] = {0};
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if (f == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Reading configuration data from %s", filename);
|
||||
|
||||
parser_flags = PARSING;
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
count++;
|
||||
rv = ssh_bind_config_parse_line(bind, line, count, &parser_flags, seen);
|
||||
if (rv) {
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
72
src/buffer.c
72
src/buffer.c
@@ -1015,7 +1015,7 @@ int ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
|
||||
}
|
||||
|
||||
if (rc != SSH_ERROR){
|
||||
/* Check if our canary is intact, if not something really bad happened */
|
||||
/* Check if our canary is intact, if not somthing really bad happened */
|
||||
uint32_t canary = va_arg(ap, uint32_t);
|
||||
if (canary != SSH_BUFFER_PACK_END) {
|
||||
abort();
|
||||
@@ -1082,11 +1082,11 @@ int _ssh_buffer_pack(struct ssh_buffer_struct *buffer,
|
||||
*/
|
||||
int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
const char *format,
|
||||
size_t argc,
|
||||
int argc,
|
||||
va_list ap)
|
||||
{
|
||||
int rc = SSH_ERROR;
|
||||
const char *p = format, *last;
|
||||
const char *p, *last;
|
||||
union {
|
||||
uint8_t *byte;
|
||||
uint16_t *word;
|
||||
@@ -1094,32 +1094,24 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
uint64_t *qword;
|
||||
ssh_string *string;
|
||||
char **cstring;
|
||||
bignum *bignum;
|
||||
void **data;
|
||||
} o;
|
||||
size_t len, rlen, max_len;
|
||||
ssh_string tmp_string = NULL;
|
||||
va_list ap_copy;
|
||||
size_t count;
|
||||
int count; /* int for size comparison with argc */
|
||||
|
||||
max_len = ssh_buffer_get_len(buffer);
|
||||
|
||||
/* copy the argument list in case a rollback is needed */
|
||||
va_copy(ap_copy, ap);
|
||||
|
||||
if (argc > 256) {
|
||||
rc = SSH_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (count = 0; *p != '\0'; p++, count++) {
|
||||
for (p = format, count = 0; *p != '\0'; p++, count++) {
|
||||
/* Invalid number of arguments passed */
|
||||
if (count > argc) {
|
||||
if (argc != -1 && count > argc) {
|
||||
rc = SSH_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = SSH_ERROR;
|
||||
switch (*p) {
|
||||
case 'b':
|
||||
o.byte = va_arg(ap, uint8_t *);
|
||||
@@ -1129,38 +1121,20 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
case 'w':
|
||||
o.word = va_arg(ap, uint16_t *);
|
||||
rlen = ssh_buffer_get_data(buffer, o.word, sizeof(uint16_t));
|
||||
if (rlen == 2) {
|
||||
*o.word = ntohs(*o.word);
|
||||
rc = SSH_OK;
|
||||
}
|
||||
*o.word = ntohs(*o.word);
|
||||
rc = rlen==2 ? SSH_OK : SSH_ERROR;
|
||||
break;
|
||||
case 'd':
|
||||
o.dword = va_arg(ap, uint32_t *);
|
||||
rlen = ssh_buffer_get_u32(buffer, o.dword);
|
||||
if (rlen == 4) {
|
||||
*o.dword = ntohl(*o.dword);
|
||||
rc = SSH_OK;
|
||||
}
|
||||
*o.dword = ntohl(*o.dword);
|
||||
rc = rlen==4 ? SSH_OK : SSH_ERROR;
|
||||
break;
|
||||
case 'q':
|
||||
o.qword = va_arg(ap, uint64_t*);
|
||||
rlen = ssh_buffer_get_u64(buffer, o.qword);
|
||||
if (rlen == 8) {
|
||||
*o.qword = ntohll(*o.qword);
|
||||
rc = SSH_OK;
|
||||
}
|
||||
break;
|
||||
case 'B':
|
||||
o.bignum = va_arg(ap, bignum *);
|
||||
*o.bignum = NULL;
|
||||
tmp_string = ssh_buffer_get_ssh_string(buffer);
|
||||
if (tmp_string == NULL) {
|
||||
break;
|
||||
}
|
||||
*o.bignum = ssh_make_string_bn(tmp_string);
|
||||
ssh_string_burn(tmp_string);
|
||||
SSH_STRING_FREE(tmp_string);
|
||||
rc = (*o.bignum != NULL) ? SSH_OK : SSH_ERROR;
|
||||
*o.qword = ntohll(*o.qword);
|
||||
rc = rlen==8 ? SSH_OK : SSH_ERROR;
|
||||
break;
|
||||
case 'S':
|
||||
o.string = va_arg(ap, ssh_string *);
|
||||
@@ -1173,12 +1147,14 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
|
||||
o.cstring = va_arg(ap, char **);
|
||||
*o.cstring = NULL;
|
||||
rlen = ssh_buffer_get_u32(buffer, &u32len);
|
||||
if (rlen != 4){
|
||||
rc = ssh_buffer_get_u32(buffer, &u32len);
|
||||
if (rc != 4){
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
len = ntohl(u32len);
|
||||
if (len > max_len - 1) {
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1234,13 +1210,14 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
break;
|
||||
default:
|
||||
SSH_LOG(SSH_LOG_WARN, "Invalid buffer format %c", *p);
|
||||
rc = SSH_ERROR;
|
||||
}
|
||||
if (rc != SSH_OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc != count) {
|
||||
if (argc != -1 && argc != count) {
|
||||
rc = SSH_ERROR;
|
||||
}
|
||||
|
||||
@@ -1249,7 +1226,11 @@ cleanup:
|
||||
/* Check if our canary is intact, if not something really bad happened */
|
||||
uint32_t canary = va_arg(ap, uint32_t);
|
||||
if (canary != SSH_BUFFER_PACK_END){
|
||||
abort();
|
||||
if (argc == -1){
|
||||
rc = SSH_ERROR;
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1286,10 +1267,6 @@ cleanup:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'B':
|
||||
o.bignum = va_arg(ap_copy, bignum *);
|
||||
bignum_safe_free(*o.bignum);
|
||||
break;
|
||||
case 'S':
|
||||
o.string = va_arg(ap_copy, ssh_string *);
|
||||
if (buffer->secure) {
|
||||
@@ -1336,7 +1313,6 @@ cleanup:
|
||||
* 's': char ** (C string, pulled as SSH string)
|
||||
* 'P': size_t, void ** (len of data, pointer to data)
|
||||
* only pulls data.
|
||||
* 'B': bignum * (pulled as SSH string)
|
||||
* @returns SSH_OK on success
|
||||
* SSH_ERROR on error
|
||||
* @warning when using 'P' with a constant size (e.g. 8), do not
|
||||
@@ -1344,7 +1320,7 @@ cleanup:
|
||||
*/
|
||||
int _ssh_buffer_unpack(struct ssh_buffer_struct *buffer,
|
||||
const char *format,
|
||||
size_t argc,
|
||||
int argc,
|
||||
...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
@@ -109,11 +109,11 @@ static void chacha20_poly1305_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||
out_packet->payload,
|
||||
len - sizeof(uint32_t));
|
||||
|
||||
/* ssh_log_hexdump("poly1305_ctx", poly1305_ctx, sizeof(poly1305_ctx)); */
|
||||
/* ssh_print_hexa("poly1305_ctx", poly1305_ctx, sizeof(poly1305_ctx)); */
|
||||
/* step 4, compute the MAC */
|
||||
poly1305_auth(tag, (uint8_t *)out_packet, len, poly1305_ctx);
|
||||
/* ssh_log_hexdump("poly1305 src", (uint8_t *)out_packet, len);
|
||||
ssh_log_hexdump("poly1305 tag", tag, POLY1305_TAGLEN); */
|
||||
/* ssh_print_hexa("poly1305 src", (uint8_t *)out_packet, len);
|
||||
ssh_print_hexa("poly1305 tag", tag, POLY1305_TAGLEN); */
|
||||
}
|
||||
|
||||
static int chacha20_poly1305_aead_decrypt_length(
|
||||
@@ -159,17 +159,17 @@ static int chacha20_poly1305_aead_decrypt(struct ssh_cipher_struct *cipher,
|
||||
poly1305_ctx,
|
||||
POLY1305_KEYLEN);
|
||||
#if 0
|
||||
ssh_log_hexdump("poly1305_ctx", poly1305_ctx, sizeof(poly1305_ctx));
|
||||
ssh_print_hexa("poly1305_ctx", poly1305_ctx, sizeof(poly1305_ctx));
|
||||
#endif
|
||||
|
||||
poly1305_auth(tag, (uint8_t *)complete_packet, encrypted_size +
|
||||
sizeof(uint32_t), poly1305_ctx);
|
||||
#if 0
|
||||
ssh_log_hexdump("poly1305 src",
|
||||
ssh_print_hexa("poly1305 src",
|
||||
(uint8_t*)complete_packet,
|
||||
encrypted_size + 4);
|
||||
ssh_log_hexdump("poly1305 tag", tag, POLY1305_TAGLEN);
|
||||
ssh_log_hexdump("received tag", mac, POLY1305_TAGLEN);
|
||||
ssh_print_hexa("poly1305 tag", tag, POLY1305_TAGLEN);
|
||||
ssh_print_hexa("received tag", mac, POLY1305_TAGLEN);
|
||||
#endif
|
||||
|
||||
cmp = memcmp(tag, mac, POLY1305_TAGLEN);
|
||||
|
||||
436
src/channels.c
436
src/channels.c
@@ -28,7 +28,6 @@
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <netinet/in.h>
|
||||
@@ -85,11 +84,6 @@ ssh_channel ssh_channel_new(ssh_session session)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check if we have an authenticated session */
|
||||
if (!(session->flags & SSH_SESSION_FLAG_AUTHENTICATED)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
channel = calloc(1, sizeof(struct ssh_channel_struct));
|
||||
if (channel == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
@@ -159,8 +153,8 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf){
|
||||
channel=ssh_channel_from_local(session,channelid);
|
||||
if(channel==NULL){
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Unknown channel id %"PRIu32,
|
||||
(uint32_t) channelid);
|
||||
"Unknown channel id %lu",
|
||||
(long unsigned int) channelid);
|
||||
/* TODO: Set error marking in channel object */
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
@@ -187,9 +181,9 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf){
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL,
|
||||
"Remote window : %"PRIu32", maxpacket : %"PRIu32,
|
||||
(uint32_t) channel->remote_window,
|
||||
(uint32_t) channel->remote_maxpacket);
|
||||
"Remote window : %lu, maxpacket : %lu",
|
||||
(long unsigned int) channel->remote_window,
|
||||
(long unsigned int) channel->remote_maxpacket);
|
||||
|
||||
channel->state = SSH_CHANNEL_STATE_OPEN;
|
||||
channel->flags &= ~SSH_CHANNEL_FLAG_NOT_BOUND;
|
||||
@@ -235,9 +229,9 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_fail){
|
||||
}
|
||||
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"Channel opening failure: channel %u error (%"PRIu32") %s",
|
||||
"Channel opening failure: channel %u error (%lu) %s",
|
||||
channel->local_channel,
|
||||
(uint32_t) code,
|
||||
(long unsigned int) code,
|
||||
error);
|
||||
SAFE_FREE(error);
|
||||
channel->state=SSH_CHANNEL_STATE_OPEN_DENIED;
|
||||
@@ -274,92 +268,75 @@ static int ssh_channel_open_termination(void *c){
|
||||
* @param[in] maxpacket The maximum packet size allowed (like MTU).
|
||||
*
|
||||
* @param[in] payload The buffer containing additional payload for the query.
|
||||
*
|
||||
* @return SSH_OK if successful; SSH_ERROR otherwise.
|
||||
*/
|
||||
static int
|
||||
channel_open(ssh_channel channel,
|
||||
const char *type,
|
||||
int window,
|
||||
int maxpacket,
|
||||
ssh_buffer payload)
|
||||
{
|
||||
ssh_session session = channel->session;
|
||||
int err = SSH_ERROR;
|
||||
int rc;
|
||||
static int channel_open(ssh_channel channel, const char *type, int window,
|
||||
int maxpacket, ssh_buffer payload) {
|
||||
ssh_session session = channel->session;
|
||||
int err=SSH_ERROR;
|
||||
int rc;
|
||||
|
||||
switch (channel->state) {
|
||||
case SSH_CHANNEL_STATE_NOT_OPEN:
|
||||
break;
|
||||
case SSH_CHANNEL_STATE_OPENING:
|
||||
goto pending;
|
||||
case SSH_CHANNEL_STATE_OPEN:
|
||||
case SSH_CHANNEL_STATE_CLOSED:
|
||||
case SSH_CHANNEL_STATE_OPEN_DENIED:
|
||||
goto end;
|
||||
default:
|
||||
ssh_set_error(session, SSH_FATAL, "Bad state in channel_open: %d",
|
||||
channel->state);
|
||||
}
|
||||
|
||||
channel->local_channel = ssh_channel_new_id(session);
|
||||
channel->local_maxpacket = maxpacket;
|
||||
channel->local_window = window;
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL,
|
||||
"Creating a channel %d with %d window and %d max packet",
|
||||
channel->local_channel, window, maxpacket);
|
||||
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bsddd",
|
||||
SSH2_MSG_CHANNEL_OPEN,
|
||||
type,
|
||||
channel->local_channel,
|
||||
channel->local_window,
|
||||
channel->local_maxpacket);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(session);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (payload != NULL) {
|
||||
if (ssh_buffer_add_buffer(session->out_buffer, payload) < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
|
||||
return err;
|
||||
}
|
||||
}
|
||||
channel->state = SSH_CHANNEL_STATE_OPENING;
|
||||
if (ssh_packet_send(session) == SSH_ERROR) {
|
||||
return err;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Sent a SSH_MSG_CHANNEL_OPEN type %s for channel %d",
|
||||
type, channel->local_channel);
|
||||
|
||||
pending:
|
||||
/* wait until channel is opened by server */
|
||||
err = ssh_handle_packets_termination(session,
|
||||
SSH_TIMEOUT_DEFAULT,
|
||||
ssh_channel_open_termination,
|
||||
channel);
|
||||
|
||||
if (session->session_state == SSH_SESSION_STATE_ERROR) {
|
||||
err = SSH_ERROR;
|
||||
}
|
||||
|
||||
end:
|
||||
/* This needs to pass the SSH_AGAIN from the above,
|
||||
* but needs to catch failed channel states */
|
||||
if (channel->state == SSH_CHANNEL_STATE_OPEN) {
|
||||
err = SSH_OK;
|
||||
} else if (err != SSH_AGAIN) {
|
||||
/* Messages were handled correctly, but he channel state is invalid */
|
||||
err = SSH_ERROR;
|
||||
switch(channel->state){
|
||||
case SSH_CHANNEL_STATE_NOT_OPEN:
|
||||
break;
|
||||
case SSH_CHANNEL_STATE_OPENING:
|
||||
goto pending;
|
||||
case SSH_CHANNEL_STATE_OPEN:
|
||||
case SSH_CHANNEL_STATE_CLOSED:
|
||||
case SSH_CHANNEL_STATE_OPEN_DENIED:
|
||||
goto end;
|
||||
default:
|
||||
ssh_set_error(session,SSH_FATAL,"Bad state in channel_open: %d",channel->state);
|
||||
}
|
||||
channel->local_channel = ssh_channel_new_id(session);
|
||||
channel->local_maxpacket = maxpacket;
|
||||
channel->local_window = window;
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL,
|
||||
"Creating a channel %d with %d window and %d max packet",
|
||||
channel->local_channel, window, maxpacket);
|
||||
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bsddd",
|
||||
SSH2_MSG_CHANNEL_OPEN,
|
||||
type,
|
||||
channel->local_channel,
|
||||
channel->local_window,
|
||||
channel->local_maxpacket);
|
||||
if (rc != SSH_OK){
|
||||
ssh_set_error_oom(session);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (payload != NULL) {
|
||||
if (ssh_buffer_add_buffer(session->out_buffer, payload) < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
|
||||
return err;
|
||||
}
|
||||
}
|
||||
channel->state = SSH_CHANNEL_STATE_OPENING;
|
||||
if (ssh_packet_send(session) == SSH_ERROR) {
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Sent a SSH_MSG_CHANNEL_OPEN type %s for channel %d",
|
||||
type, channel->local_channel);
|
||||
pending:
|
||||
/* wait until channel is opened by server */
|
||||
err = ssh_handle_packets_termination(session,
|
||||
SSH_TIMEOUT_DEFAULT,
|
||||
ssh_channel_open_termination,
|
||||
channel);
|
||||
|
||||
if (session->session_state == SSH_SESSION_STATE_ERROR)
|
||||
err = SSH_ERROR;
|
||||
end:
|
||||
if(channel->state == SSH_CHANNEL_STATE_OPEN)
|
||||
err=SSH_OK;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* return channel with corresponding local id, or NULL if not found */
|
||||
@@ -386,7 +363,6 @@ ssh_channel ssh_channel_from_local(ssh_session session, uint32_t id) {
|
||||
* @param session SSH session
|
||||
* @param channel SSH channel
|
||||
* @param minimumsize The minimum acceptable size for the new window.
|
||||
* @return SSH_OK if successful; SSH_ERROR otherwise.
|
||||
*/
|
||||
static int grow_window(ssh_session session, ssh_channel channel, int minimumsize) {
|
||||
uint32_t new_window = minimumsize > WINDOWBASE ? minimumsize : WINDOWBASE;
|
||||
@@ -442,7 +418,7 @@ error:
|
||||
* @param[in] packet The buffer to parse packet from. The read pointer will
|
||||
* be moved after the call.
|
||||
*
|
||||
* @return The related ssh_channel, or NULL if the channel is
|
||||
* @returns The related ssh_channel, or NULL if the channel is
|
||||
* unknown or the packet is invalid.
|
||||
*/
|
||||
static ssh_channel channel_from_msg(ssh_session session, ssh_buffer packet) {
|
||||
@@ -460,8 +436,8 @@ static ssh_channel channel_from_msg(ssh_session session, ssh_buffer packet) {
|
||||
channel = ssh_channel_from_local(session, chan);
|
||||
if (channel == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Server specified invalid channel %"PRIu32,
|
||||
(uint32_t) chan);
|
||||
"Server specified invalid channel %lu",
|
||||
(long unsigned int) chan);
|
||||
}
|
||||
|
||||
return channel;
|
||||
@@ -1019,88 +995,6 @@ error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Open a TCP/IP - UNIX domain socket forwarding channel.
|
||||
*
|
||||
* @param[in] channel An allocated channel.
|
||||
*
|
||||
* @param[in] remotepath The UNIX socket path on the remote machine
|
||||
*
|
||||
* @param[in] sourcehost The numeric IP address of the machine from where the
|
||||
* connection request originates. This is mostly for
|
||||
* logging purposes.
|
||||
*
|
||||
* @param[in] localport The port on the host from where the connection
|
||||
* originated. This is mostly for logging purposes.
|
||||
*
|
||||
* @return SSH_OK on success,
|
||||
* SSH_ERROR if an error occurred,
|
||||
* SSH_AGAIN if in nonblocking mode and call has
|
||||
* to be done again.
|
||||
*
|
||||
* @warning This function does not bind the local port and does not
|
||||
* automatically forward the content of a socket to the channel.
|
||||
* You still have to use channel_read and channel_write for this.
|
||||
* @warning Requires support of OpenSSH for UNIX domain socket forwarding.
|
||||
*/
|
||||
int ssh_channel_open_forward_unix(ssh_channel channel,
|
||||
const char *remotepath,
|
||||
const char *sourcehost,
|
||||
int localport)
|
||||
{
|
||||
ssh_session session = NULL;
|
||||
ssh_buffer payload = NULL;
|
||||
ssh_string str = NULL;
|
||||
int rc = SSH_ERROR;
|
||||
int version;
|
||||
|
||||
if (channel == NULL) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
session = channel->session;
|
||||
|
||||
version = ssh_get_openssh_version(session);
|
||||
if (version == 0) {
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
"We're not connected to an OpenSSH server!");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (remotepath == NULL || sourcehost == NULL) {
|
||||
ssh_set_error_invalid(session);
|
||||
return rc;
|
||||
}
|
||||
|
||||
payload = ssh_buffer_new();
|
||||
if (payload == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_pack(payload,
|
||||
"ssd",
|
||||
remotepath,
|
||||
sourcehost,
|
||||
localport);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = channel_open(channel,
|
||||
"direct-streamlocal@openssh.com",
|
||||
CHANNEL_INITIAL_WINDOW,
|
||||
CHANNEL_MAX_PACKET,
|
||||
payload);
|
||||
|
||||
error:
|
||||
ssh_buffer_free(payload);
|
||||
ssh_string_free(str);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Close and free a channel.
|
||||
@@ -1109,50 +1003,28 @@ error:
|
||||
*
|
||||
* @warning Any data unread on this channel will be lost.
|
||||
*/
|
||||
void ssh_channel_free(ssh_channel channel)
|
||||
{
|
||||
ssh_session session;
|
||||
void ssh_channel_free(ssh_channel channel) {
|
||||
ssh_session session;
|
||||
|
||||
if (channel == NULL) {
|
||||
return;
|
||||
}
|
||||
if (channel == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
session = channel->session;
|
||||
if (session->alive) {
|
||||
bool send_close = false;
|
||||
session = channel->session;
|
||||
if (session->alive && channel->state == SSH_CHANNEL_STATE_OPEN) {
|
||||
ssh_channel_close(channel);
|
||||
}
|
||||
channel->flags |= SSH_CHANNEL_FLAG_FREED_LOCAL;
|
||||
|
||||
switch (channel->state) {
|
||||
case SSH_CHANNEL_STATE_OPEN:
|
||||
send_close = true;
|
||||
break;
|
||||
case SSH_CHANNEL_STATE_CLOSED:
|
||||
if (channel->flags & SSH_CHANNEL_FLAG_CLOSED_REMOTE) {
|
||||
send_close = true;
|
||||
}
|
||||
if (channel->flags & SSH_CHANNEL_FLAG_CLOSED_LOCAL) {
|
||||
send_close = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
send_close = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (send_close) {
|
||||
ssh_channel_close(channel);
|
||||
}
|
||||
}
|
||||
channel->flags |= SSH_CHANNEL_FLAG_FREED_LOCAL;
|
||||
|
||||
/* The idea behind the flags is the following : it is well possible
|
||||
* that a client closes a channel that stills exists on the server side.
|
||||
* We definitively close the channel when we receive a close message *and*
|
||||
* the user closed it.
|
||||
*/
|
||||
if ((channel->flags & SSH_CHANNEL_FLAG_CLOSED_REMOTE) ||
|
||||
(channel->flags & SSH_CHANNEL_FLAG_NOT_BOUND)) {
|
||||
ssh_channel_do_free(channel);
|
||||
}
|
||||
/* The idea behind the flags is the following : it is well possible
|
||||
* that a client closes a channel that stills exists on the server side.
|
||||
* We definitively close the channel when we receive a close message *and*
|
||||
* the user closed it.
|
||||
*/
|
||||
if((channel->flags & SSH_CHANNEL_FLAG_CLOSED_REMOTE)
|
||||
|| (channel->flags & SSH_CHANNEL_FLAG_NOT_BOUND)){
|
||||
ssh_channel_do_free(channel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1170,15 +1042,13 @@ void ssh_channel_do_free(ssh_channel channel)
|
||||
ssh_list_remove(session->channels, it);
|
||||
}
|
||||
|
||||
SSH_BUFFER_FREE(channel->stdout_buffer);
|
||||
SSH_BUFFER_FREE(channel->stderr_buffer);
|
||||
ssh_buffer_free(channel->stdout_buffer);
|
||||
ssh_buffer_free(channel->stderr_buffer);
|
||||
|
||||
if (channel->callbacks != NULL) {
|
||||
ssh_list_free(channel->callbacks);
|
||||
channel->callbacks = NULL;
|
||||
}
|
||||
|
||||
channel->session = NULL;
|
||||
SAFE_FREE(channel);
|
||||
}
|
||||
|
||||
@@ -1216,15 +1086,10 @@ int ssh_channel_send_eof(ssh_channel channel)
|
||||
int rc = SSH_ERROR;
|
||||
int err;
|
||||
|
||||
if (channel == NULL || channel->session == NULL) {
|
||||
if(channel == NULL) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* If the EOF has already been sent we're done here. */
|
||||
if (channel->local_eof != 0) {
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
session = channel->session;
|
||||
|
||||
err = ssh_buffer_pack(session->out_buffer,
|
||||
@@ -1271,57 +1136,52 @@ error:
|
||||
* @see ssh_channel_free()
|
||||
* @see ssh_channel_is_eof()
|
||||
*/
|
||||
int ssh_channel_close(ssh_channel channel)
|
||||
{
|
||||
ssh_session session;
|
||||
int rc = 0;
|
||||
int ssh_channel_close(ssh_channel channel){
|
||||
ssh_session session;
|
||||
int rc = 0;
|
||||
|
||||
if(channel == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if(channel == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* If the channel close has already been sent we're done here. */
|
||||
if (channel->flags & SSH_CHANNEL_FLAG_CLOSED_LOCAL) {
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
session = channel->session;
|
||||
session = channel->session;
|
||||
|
||||
if (channel->local_eof == 0) {
|
||||
rc = ssh_channel_send_eof(channel);
|
||||
if (rc != SSH_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bd",
|
||||
SSH2_MSG_CHANNEL_CLOSE,
|
||||
channel->remote_channel);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_packet_send(session);
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Sent a close on client channel (%d:%d)",
|
||||
channel->local_channel,
|
||||
channel->remote_channel);
|
||||
|
||||
if (rc == SSH_OK) {
|
||||
channel->state = SSH_CHANNEL_STATE_CLOSED;
|
||||
channel->flags |= SSH_CHANNEL_FLAG_CLOSED_LOCAL;
|
||||
}
|
||||
|
||||
rc = ssh_channel_flush(channel);
|
||||
if(rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc != SSH_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bd",
|
||||
SSH2_MSG_CHANNEL_CLOSE,
|
||||
channel->remote_channel);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_packet_send(session);
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Sent a close on client channel (%d:%d)",
|
||||
channel->local_channel,
|
||||
channel->remote_channel);
|
||||
|
||||
if(rc == SSH_OK) {
|
||||
channel->state=SSH_CHANNEL_STATE_CLOSED;
|
||||
}
|
||||
|
||||
rc = ssh_channel_flush(channel);
|
||||
if(rc == SSH_ERROR)
|
||||
goto error;
|
||||
|
||||
return rc;
|
||||
error:
|
||||
ssh_buffer_reinit(session->out_buffer);
|
||||
ssh_buffer_reinit(session->out_buffer);
|
||||
|
||||
return rc;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* this termination function waits for a window growing condition */
|
||||
@@ -1354,9 +1214,9 @@ static int ssh_waitsession_unblocked(void *s){
|
||||
* @brief Flushes a channel (and its session) until the output buffer
|
||||
* is empty, or timeout elapsed.
|
||||
* @param channel SSH channel
|
||||
* @return SSH_OK On success,
|
||||
* SSH_ERROR On error.
|
||||
* SSH_AGAIN Timeout elapsed (or in nonblocking mode).
|
||||
* @returns SSH_OK On success,
|
||||
* SSH_ERROR on error
|
||||
* SSH_AGAIN Timeout elapsed (or in nonblocking mode)
|
||||
*/
|
||||
int ssh_channel_flush(ssh_channel channel){
|
||||
return ssh_blocking_flush(channel->session, SSH_TIMEOUT_DEFAULT);
|
||||
@@ -1964,18 +1824,6 @@ error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Request sftp subsystem on the channel
|
||||
*
|
||||
* @param[in] channel The channel to request the sftp subsystem.
|
||||
*
|
||||
* @return SSH_OK on success,
|
||||
* SSH_ERROR if an error occurred,
|
||||
* SSH_AGAIN if in nonblocking mode and call has
|
||||
* to be done again.
|
||||
*
|
||||
* @note You should use sftp_new() which does this for you.
|
||||
*/
|
||||
int ssh_channel_request_sftp( ssh_channel channel){
|
||||
if(channel == NULL) {
|
||||
return SSH_ERROR;
|
||||
@@ -2540,12 +2388,12 @@ error:
|
||||
*
|
||||
* Example:
|
||||
@code
|
||||
rc = ssh_channel_request_exec(channel, "ps aux");
|
||||
rc = channel_request_exec(channel, "ps aux");
|
||||
if (rc > 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((rc = ssh_channel_read(channel, buffer, sizeof(buffer), 0)) > 0) {
|
||||
while ((rc = channel_read(channel, buffer, sizeof(buffer), 0)) > 0) {
|
||||
if (fwrite(buffer, 1, rc, stdout) != (unsigned int) rc) {
|
||||
return -1;
|
||||
}
|
||||
@@ -3140,8 +2988,8 @@ static int ssh_channel_exit_status_termination(void *c){
|
||||
*
|
||||
* @param[in] channel The channel to get the status from.
|
||||
*
|
||||
* @return The exit status, -1 if no exit status has been returned
|
||||
* (yet), or SSH_ERROR on error.
|
||||
* @returns The exit status, -1 if no exit status has been returned
|
||||
* (yet).
|
||||
* @warning This function may block until a timeout (or never)
|
||||
* if the other side is not willing to close the channel.
|
||||
*
|
||||
@@ -3251,7 +3099,7 @@ static int count_ptrs(ssh_channel *ptrs) {
|
||||
*
|
||||
* @return SSH_OK on a successful operation, SSH_EINTR if the
|
||||
* select(2) syscall was interrupted, then relaunch the
|
||||
* function, or SSH_ERROR on error.
|
||||
* function.
|
||||
*/
|
||||
int ssh_channel_select(ssh_channel *readchans, ssh_channel *writechans,
|
||||
ssh_channel *exceptchans, struct timeval * timeout) {
|
||||
|
||||
19
src/client.c
19
src/client.c
@@ -38,9 +38,6 @@
|
||||
#include "libssh/socket.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/dh.h"
|
||||
#ifdef WITH_GEX
|
||||
#include "libssh/dh-gex.h"
|
||||
#endif /* WITH_GEX */
|
||||
#include "libssh/ecdh.h"
|
||||
#include "libssh/threads.h"
|
||||
#include "libssh/misc.h"
|
||||
@@ -256,12 +253,6 @@ static int dh_handshake(ssh_session session) {
|
||||
case SSH_KEX_DH_GROUP18_SHA512:
|
||||
rc = ssh_client_dh_init(session);
|
||||
break;
|
||||
#ifdef WITH_GEX
|
||||
case SSH_KEX_DH_GEX_SHA1:
|
||||
case SSH_KEX_DH_GEX_SHA256:
|
||||
rc = ssh_client_dhgex_init(session);
|
||||
break;
|
||||
#endif /* WITH_GEX */
|
||||
#ifdef HAVE_ECDH
|
||||
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||
case SSH_KEX_ECDH_SHA2_NISTP384:
|
||||
@@ -279,7 +270,11 @@ static int dh_handshake(ssh_session session) {
|
||||
rc = SSH_ERROR;
|
||||
}
|
||||
|
||||
break;
|
||||
if (rc == SSH_ERROR) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
session->dh_handshake_state = DH_STATE_INIT_SENT;
|
||||
case DH_STATE_INIT_SENT:
|
||||
/* wait until ssh_packet_dh_reply is called */
|
||||
break;
|
||||
@@ -399,7 +394,7 @@ static void ssh_client_connection_callback(ssh_session session)
|
||||
goto error;
|
||||
}
|
||||
set_status(session, 0.4f);
|
||||
SSH_LOG(SSH_LOG_PROTOCOL,
|
||||
SSH_LOG(SSH_LOG_RARE,
|
||||
"SSH server banner: %s", session->serverbanner);
|
||||
|
||||
/* Here we analyze the different protocols the server allows. */
|
||||
@@ -750,7 +745,7 @@ error:
|
||||
}
|
||||
|
||||
const char *ssh_copyright(void) {
|
||||
return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2019 "
|
||||
return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2018 "
|
||||
"Aris Adamantiadis, Andreas Schneider "
|
||||
"and libssh contributors. "
|
||||
"Distributed under the LGPL, please refer to COPYING "
|
||||
|
||||
438
src/config.c
438
src/config.c
@@ -31,9 +31,7 @@
|
||||
# include <glob.h>
|
||||
#endif
|
||||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "libssh/config_parser.h"
|
||||
#include "libssh/config.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/session.h"
|
||||
@@ -108,10 +106,10 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
|
||||
{ "numberofpasswordprompts", SOC_UNSUPPORTED},
|
||||
{ "pkcs11provider", SOC_UNSUPPORTED},
|
||||
{ "preferredauthentications", SOC_UNSUPPORTED},
|
||||
{ "proxyjump", SOC_PROXYJUMP},
|
||||
{ "proxyjump", SOC_UNSUPPORTED},
|
||||
{ "proxyusefdpass", SOC_UNSUPPORTED},
|
||||
{ "pubkeyacceptedtypes", SOC_PUBKEYACCEPTEDTYPES},
|
||||
{ "rekeylimit", SOC_REKEYLIMIT},
|
||||
{ "rekeylimit", SOC_UNSUPPORTED},
|
||||
{ "remotecommand", SOC_UNSUPPORTED},
|
||||
{ "revokedhostkeys", SOC_UNSUPPORTED},
|
||||
{ "rhostsrsaauthentication", SOC_UNSUPPORTED},
|
||||
@@ -147,14 +145,12 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
|
||||
{ "tunnel", SOC_NA},
|
||||
{ "tunneldevice", SOC_NA},
|
||||
{ "xauthlocation", SOC_NA},
|
||||
{ "pubkeyacceptedkeytypes", SOC_PUBKEYACCEPTEDTYPES},
|
||||
{ NULL, SOC_UNKNOWN }
|
||||
};
|
||||
|
||||
enum ssh_config_match_e {
|
||||
MATCH_UNKNOWN = -1,
|
||||
MATCH_ALL,
|
||||
MATCH_FINAL,
|
||||
MATCH_CANONICAL,
|
||||
MATCH_EXEC,
|
||||
MATCH_HOST,
|
||||
@@ -171,13 +167,11 @@ struct ssh_config_match_keyword_table_s {
|
||||
static struct ssh_config_match_keyword_table_s ssh_config_match_keyword_table[] = {
|
||||
{ "all", MATCH_ALL },
|
||||
{ "canonical", MATCH_CANONICAL },
|
||||
{ "final", MATCH_FINAL },
|
||||
{ "exec", MATCH_EXEC },
|
||||
{ "host", MATCH_HOST },
|
||||
{ "originalhost", MATCH_ORIGINALHOST },
|
||||
{ "user", MATCH_USER },
|
||||
{ "localuser", MATCH_LOCALUSER },
|
||||
{ NULL, MATCH_UNKNOWN },
|
||||
};
|
||||
|
||||
static int ssh_config_parse_line(ssh_session session, const char *line,
|
||||
@@ -195,6 +189,102 @@ static enum ssh_config_opcode_e ssh_config_get_opcode(char *keyword) {
|
||||
return SOC_UNKNOWN;
|
||||
}
|
||||
|
||||
static char *ssh_config_get_cmd(char **str) {
|
||||
register char *c;
|
||||
char *r;
|
||||
|
||||
/* Ignore leading spaces */
|
||||
for (c = *str; *c; c++) {
|
||||
if (! isblank(*c)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*c == '\"') {
|
||||
for (r = ++c; *c; c++) {
|
||||
if (*c == '\"') {
|
||||
*c = '\0';
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (r = c; *c; c++) {
|
||||
if (*c == '\n') {
|
||||
*c = '\0';
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
*str = c + 1;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static char *ssh_config_get_token(char **str) {
|
||||
register char *c;
|
||||
char *r;
|
||||
|
||||
c = ssh_config_get_cmd(str);
|
||||
|
||||
for (r = c; *c; c++) {
|
||||
if (isblank(*c) || *c == '=') {
|
||||
*c = '\0';
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
*str = c + 1;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static long ssh_config_get_long(char **str, long notfound) {
|
||||
char *p, *endp;
|
||||
long i;
|
||||
|
||||
p = ssh_config_get_token(str);
|
||||
if (p && *p) {
|
||||
i = strtol(p, &endp, 10);
|
||||
if (p == endp) {
|
||||
return notfound;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
return notfound;
|
||||
}
|
||||
|
||||
static const char *ssh_config_get_str_tok(char **str, const char *def) {
|
||||
char *p;
|
||||
|
||||
p = ssh_config_get_token(str);
|
||||
if (p && *p) {
|
||||
return p;
|
||||
}
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
static int ssh_config_get_yesno(char **str, int notfound) {
|
||||
const char *p;
|
||||
|
||||
p = ssh_config_get_str_tok(str, NULL);
|
||||
if (p == NULL) {
|
||||
return notfound;
|
||||
}
|
||||
|
||||
if (strncasecmp(p, "yes", 3) == 0) {
|
||||
return 1;
|
||||
} else if (strncasecmp(p, "no", 2) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return notfound;
|
||||
}
|
||||
|
||||
static void
|
||||
local_parse_file(ssh_session session,
|
||||
const char *filename,
|
||||
@@ -235,7 +325,7 @@ static void local_parse_glob(ssh_session session,
|
||||
.gl_flags = 0,
|
||||
};
|
||||
int rt;
|
||||
size_t i;
|
||||
u_int i;
|
||||
|
||||
rt = glob(fileglob, GLOB_TILDE, NULL, &globbuf);
|
||||
if (rt == GLOB_NOMATCH) {
|
||||
@@ -274,8 +364,10 @@ static int
|
||||
ssh_config_match(char *value, const char *pattern, bool negate)
|
||||
{
|
||||
int ok, result = 0;
|
||||
char *lowervalue;
|
||||
|
||||
ok = match_pattern_list(value, pattern, strlen(pattern), 0);
|
||||
lowervalue = (value) ? ssh_lowercase(value) : NULL;
|
||||
ok = match_pattern_list(lowervalue, pattern, strlen(pattern), 0);
|
||||
if (ok <= 0 && negate == true) {
|
||||
result = 1;
|
||||
} else if (ok > 0 && negate == false) {
|
||||
@@ -284,99 +376,10 @@ ssh_config_match(char *value, const char *pattern, bool negate)
|
||||
SSH_LOG(SSH_LOG_TRACE, "%s '%s' against pattern '%s'%s (ok=%d)",
|
||||
result == 1 ? "Matched" : "Not matched", value, pattern,
|
||||
negate == true ? " (negated)" : "", ok);
|
||||
SAFE_FREE(lowervalue);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* @brief: Parse the ProxyJump configuration line and if parsing,
|
||||
* stores the result in the configuration option
|
||||
*/
|
||||
static int
|
||||
ssh_config_parse_proxy_jump(ssh_session session, const char *s, bool do_parsing)
|
||||
{
|
||||
char *c = NULL, *cp = NULL, *endp = NULL;
|
||||
char *username = NULL;
|
||||
char *hostname = NULL;
|
||||
char *port = NULL;
|
||||
char *next = NULL;
|
||||
int cmp, rv = SSH_ERROR;
|
||||
bool parse_entry = do_parsing;
|
||||
|
||||
/* Special value none disables the proxy */
|
||||
cmp = strcasecmp(s, "none");
|
||||
if (cmp == 0 && do_parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, s);
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/* This is comma-separated list of [user@]host[:port] entries */
|
||||
c = strdup(s);
|
||||
if (c == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
cp = c;
|
||||
do {
|
||||
endp = strchr(cp, ',');
|
||||
if (endp != NULL) {
|
||||
/* Split out the token */
|
||||
*endp = '\0';
|
||||
}
|
||||
if (parse_entry) {
|
||||
/* We actually care only about the first item */
|
||||
rv = ssh_config_parse_uri(cp, &username, &hostname, &port);
|
||||
/* The rest of the list needs to be passed on */
|
||||
if (endp != NULL) {
|
||||
next = strdup(endp + 1);
|
||||
if (next == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
rv = SSH_ERROR;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* The rest is just sanity-checked to avoid failures later */
|
||||
rv = ssh_config_parse_uri(cp, NULL, NULL, NULL);
|
||||
}
|
||||
if (rv != SSH_OK) {
|
||||
goto out;
|
||||
}
|
||||
parse_entry = 0;
|
||||
if (endp != NULL) {
|
||||
cp = endp + 1;
|
||||
} else {
|
||||
cp = NULL; /* end */
|
||||
}
|
||||
} while (cp != NULL);
|
||||
|
||||
if (hostname != NULL && do_parsing) {
|
||||
char com[512] = {0};
|
||||
|
||||
rv = snprintf(com, sizeof(com), "ssh%s%s%s%s%s%s -W [%%h]:%%p %s",
|
||||
username ? " -l " : "",
|
||||
username ? username : "",
|
||||
port ? " -p " : "",
|
||||
port ? port : "",
|
||||
next ? " -J " : "",
|
||||
next ? next : "",
|
||||
hostname);
|
||||
if (rv < 0 || rv >= (int)sizeof(com)) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Too long ProxyJump configuration line");
|
||||
rv = SSH_ERROR;
|
||||
goto out;
|
||||
}
|
||||
ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, com);
|
||||
}
|
||||
rv = SSH_OK;
|
||||
|
||||
out:
|
||||
SAFE_FREE(username);
|
||||
SAFE_FREE(hostname);
|
||||
SAFE_FREE(port);
|
||||
SAFE_FREE(next);
|
||||
SAFE_FREE(c);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_config_parse_line(ssh_session session,
|
||||
const char *line,
|
||||
@@ -384,15 +387,14 @@ ssh_config_parse_line(ssh_session session,
|
||||
int *parsing)
|
||||
{
|
||||
enum ssh_config_opcode_e opcode;
|
||||
const char *p = NULL, *p2 = NULL;
|
||||
char *s = NULL, *x = NULL;
|
||||
char *keyword = NULL;
|
||||
char *lowerhost = NULL;
|
||||
const char *p;
|
||||
char *s, *x;
|
||||
char *keyword;
|
||||
char *lowerhost;
|
||||
size_t len;
|
||||
int i, rv;
|
||||
int i;
|
||||
uint8_t *seen = session->opts.options_seen;
|
||||
long l;
|
||||
int64_t ll;
|
||||
|
||||
x = s = strdup(line);
|
||||
if (s == NULL) {
|
||||
@@ -447,11 +449,10 @@ ssh_config_parse_line(ssh_session session,
|
||||
int result = 1;
|
||||
size_t args = 0;
|
||||
enum ssh_config_match_e opt;
|
||||
char *localuser = NULL;
|
||||
|
||||
*parsing = 0;
|
||||
do {
|
||||
p = p2 = ssh_config_get_str_tok(&s, NULL);
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p == NULL || p[0] == '\0') {
|
||||
break;
|
||||
}
|
||||
@@ -470,10 +471,8 @@ ssh_config_parse_line(ssh_session session,
|
||||
switch (opt) {
|
||||
case MATCH_ALL:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (args <= 2 && (p == NULL || p[0] == '\0')) {
|
||||
/* The first or second, but last argument. The "all" keyword
|
||||
* can be prefixed with either "final" or "canonical"
|
||||
* keywords which do not have any effect here. */
|
||||
if (args == 1 && (p == NULL || p[0] == '\0')) {
|
||||
/* The first argument and end of line */
|
||||
if (negate == true) {
|
||||
result = 0;
|
||||
}
|
||||
@@ -486,69 +485,16 @@ ssh_config_parse_line(ssh_session session,
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
|
||||
case MATCH_FINAL:
|
||||
case MATCH_CANONICAL:
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Unsupported Match keyword '%s', skipping",
|
||||
count,
|
||||
p);
|
||||
/* Not set any result here -- the result is dependent on the
|
||||
* following matches after this keyword */
|
||||
break;
|
||||
|
||||
case MATCH_EXEC:
|
||||
/* Skip to the end of line as unsupported */
|
||||
p = ssh_config_get_cmd(&s);
|
||||
if (p == NULL || p[0] == '\0') {
|
||||
SSH_LOG(SSH_LOG_WARN, "line %d: Match keyword "
|
||||
"'%s' requires argument", count, p2);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
args++;
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Unsupported Match keyword '%s', ignoring",
|
||||
count,
|
||||
p2);
|
||||
result = 0;
|
||||
break;
|
||||
|
||||
case MATCH_LOCALUSER:
|
||||
/* Here we match only one argument */
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p == NULL || p[0] == '\0') {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"line %d: ERROR - Match user keyword "
|
||||
"requires argument", count);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
localuser = ssh_get_local_username();
|
||||
if (localuser == NULL) {
|
||||
SSH_LOG(SSH_LOG_WARN, "line %d: Can not get local username "
|
||||
"for conditional matching.", count);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
result &= ssh_config_match(localuser, p, negate);
|
||||
SAFE_FREE(localuser);
|
||||
args++;
|
||||
break;
|
||||
|
||||
case MATCH_ORIGINALHOST:
|
||||
case MATCH_LOCALUSER:
|
||||
/* Skip one argument */
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p == NULL || p[0] == '\0') {
|
||||
SSH_LOG(SSH_LOG_WARN, "line %d: Match keyword "
|
||||
"'%s' requires argument", count, p2);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
args++;
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Unsupported Match keyword '%s', ignoring",
|
||||
count,
|
||||
p2);
|
||||
FALL_THROUGH;
|
||||
case MATCH_CANONICAL:
|
||||
SSH_LOG(SSH_LOG_WARN, "line: %d: Unsupported Match keyword "
|
||||
"'%s', Ignoring\n", count, p);
|
||||
result = 0;
|
||||
break;
|
||||
|
||||
@@ -723,25 +669,10 @@ ssh_config_parse_line(ssh_session session,
|
||||
break;
|
||||
case SOC_PROXYCOMMAND:
|
||||
p = ssh_config_get_cmd(&s);
|
||||
/* We share the seen value with the ProxyJump */
|
||||
if (p && *parsing && !seen[SOC_PROXYJUMP]) {
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, p);
|
||||
}
|
||||
break;
|
||||
case SOC_PROXYJUMP:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p == NULL) {
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
/* We share the seen value with the ProxyCommand */
|
||||
rv = ssh_config_parse_proxy_jump(session, p,
|
||||
(*parsing && !seen[SOC_PROXYCOMMAND]));
|
||||
if (rv != SSH_OK) {
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case SOC_GSSAPISERVERIDENTITY:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
@@ -815,141 +746,6 @@ ssh_config_parse_line(ssh_session session,
|
||||
ssh_options_set(session, SSH_OPTIONS_KEY_EXCHANGE, p);
|
||||
}
|
||||
break;
|
||||
case SOC_REKEYLIMIT:
|
||||
/* Parse the data limit */
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p == NULL) {
|
||||
break;
|
||||
} else if (strcmp(p, "default") == 0) {
|
||||
/* Default rekey limits enforced automaticaly */
|
||||
ll = 0;
|
||||
} else {
|
||||
char *endp = NULL;
|
||||
ll = strtoll(p, &endp, 10);
|
||||
if (p == endp || ll < 0) {
|
||||
/* No number or negative */
|
||||
SSH_LOG(SSH_LOG_WARN, "Invalid argument to rekey limit");
|
||||
break;
|
||||
}
|
||||
switch (*endp) {
|
||||
case 'G':
|
||||
if (ll > LLONG_MAX / 1024) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
|
||||
ll = -1;
|
||||
break;
|
||||
}
|
||||
ll = ll * 1024;
|
||||
FALL_THROUGH;
|
||||
case 'M':
|
||||
if (ll > LLONG_MAX / 1024) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
|
||||
ll = -1;
|
||||
break;
|
||||
}
|
||||
ll = ll * 1024;
|
||||
FALL_THROUGH;
|
||||
case 'K':
|
||||
if (ll > LLONG_MAX / 1024) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
|
||||
ll = -1;
|
||||
break;
|
||||
}
|
||||
ll = ll * 1024;
|
||||
endp++;
|
||||
FALL_THROUGH;
|
||||
case '\0':
|
||||
/* just the number */
|
||||
break;
|
||||
default:
|
||||
/* Invalid suffix */
|
||||
ll = -1;
|
||||
break;
|
||||
}
|
||||
if (*endp != ' ' && *endp != '\0') {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"Invalid trailing characters after the rekey limit: %s",
|
||||
endp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ll > -1 && *parsing) {
|
||||
uint64_t v = (uint64_t)ll;
|
||||
ssh_options_set(session, SSH_OPTIONS_REKEY_DATA, &v);
|
||||
}
|
||||
/* Parse the time limit */
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p == NULL) {
|
||||
break;
|
||||
} else if (strcmp(p, "none") == 0) {
|
||||
ll = 0;
|
||||
} else {
|
||||
char *endp = NULL;
|
||||
ll = strtoll(p, &endp, 10);
|
||||
if (p == endp || ll < 0) {
|
||||
/* No number or negative */
|
||||
SSH_LOG(SSH_LOG_WARN, "Invalid argument to rekey limit");
|
||||
break;
|
||||
}
|
||||
switch (*endp) {
|
||||
case 'w':
|
||||
case 'W':
|
||||
if (ll > LLONG_MAX / 7) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
|
||||
ll = -1;
|
||||
break;
|
||||
}
|
||||
ll = ll * 7;
|
||||
FALL_THROUGH;
|
||||
case 'd':
|
||||
case 'D':
|
||||
if (ll > LLONG_MAX / 24) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
|
||||
ll = -1;
|
||||
break;
|
||||
}
|
||||
ll = ll * 24;
|
||||
FALL_THROUGH;
|
||||
case 'h':
|
||||
case 'H':
|
||||
if (ll > LLONG_MAX / 60) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
|
||||
ll = -1;
|
||||
break;
|
||||
}
|
||||
ll = ll * 60;
|
||||
FALL_THROUGH;
|
||||
case 'm':
|
||||
case 'M':
|
||||
if (ll > LLONG_MAX / 60) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
|
||||
ll = -1;
|
||||
break;
|
||||
}
|
||||
ll = ll * 60;
|
||||
FALL_THROUGH;
|
||||
case 's':
|
||||
case 'S':
|
||||
endp++;
|
||||
FALL_THROUGH;
|
||||
case '\0':
|
||||
/* just the number */
|
||||
break;
|
||||
default:
|
||||
/* Invalid suffix */
|
||||
ll = -1;
|
||||
break;
|
||||
}
|
||||
if (*endp != '\0') {
|
||||
SSH_LOG(SSH_LOG_WARN, "Invalid trailing characters after the"
|
||||
" rekey limit: %s", endp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ll > -1 && *parsing) {
|
||||
uint32_t v = (uint32_t)ll;
|
||||
ssh_options_set(session, SSH_OPTIONS_REKEY_TIME, &v);
|
||||
}
|
||||
break;
|
||||
case SOC_GSSAPIAUTHENTICATION:
|
||||
case SOC_KBDINTERACTIVEAUTHENTICATION:
|
||||
case SOC_PASSWORDAUTHENTICATION:
|
||||
|
||||
@@ -1,238 +0,0 @@
|
||||
/*
|
||||
* config_parser.c - Common configuration file parser functions
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* 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 <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "libssh/config_parser.h"
|
||||
#include "libssh/priv.h"
|
||||
|
||||
char *ssh_config_get_cmd(char **str)
|
||||
{
|
||||
register char *c;
|
||||
char *r;
|
||||
|
||||
/* Ignore leading spaces */
|
||||
for (c = *str; *c; c++) {
|
||||
if (! isblank(*c)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*c == '\"') {
|
||||
for (r = ++c; *c; c++) {
|
||||
if (*c == '\"') {
|
||||
*c = '\0';
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (r = c; *c; c++) {
|
||||
if (*c == '\n') {
|
||||
*c = '\0';
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
*str = c + 1;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
char *ssh_config_get_token(char **str)
|
||||
{
|
||||
register char *c;
|
||||
char *r;
|
||||
|
||||
c = ssh_config_get_cmd(str);
|
||||
|
||||
for (r = c; *c; c++) {
|
||||
if (isblank(*c) || *c == '=') {
|
||||
*c = '\0';
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
*str = c + 1;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
long ssh_config_get_long(char **str, long notfound)
|
||||
{
|
||||
char *p, *endp;
|
||||
long i;
|
||||
|
||||
p = ssh_config_get_token(str);
|
||||
if (p && *p) {
|
||||
i = strtol(p, &endp, 10);
|
||||
if (p == endp) {
|
||||
return notfound;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
return notfound;
|
||||
}
|
||||
|
||||
const char *ssh_config_get_str_tok(char **str, const char *def)
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = ssh_config_get_token(str);
|
||||
if (p && *p) {
|
||||
return p;
|
||||
}
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
int ssh_config_get_yesno(char **str, int notfound)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
p = ssh_config_get_str_tok(str, NULL);
|
||||
if (p == NULL) {
|
||||
return notfound;
|
||||
}
|
||||
|
||||
if (strncasecmp(p, "yes", 3) == 0) {
|
||||
return 1;
|
||||
} else if (strncasecmp(p, "no", 2) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return notfound;
|
||||
}
|
||||
|
||||
int ssh_config_parse_uri(const char *tok,
|
||||
char **username,
|
||||
char **hostname,
|
||||
char **port)
|
||||
{
|
||||
char *endp = NULL;
|
||||
long port_n;
|
||||
|
||||
/* Sanitize inputs */
|
||||
if (username != NULL) {
|
||||
*username = NULL;
|
||||
}
|
||||
if (hostname != NULL) {
|
||||
*hostname = NULL;
|
||||
}
|
||||
if (port != NULL) {
|
||||
*port = NULL;
|
||||
}
|
||||
|
||||
/* Username part (optional) */
|
||||
endp = strchr(tok, '@');
|
||||
if (endp != NULL) {
|
||||
/* Zero-length username is not valid */
|
||||
if (tok == endp) {
|
||||
goto error;
|
||||
}
|
||||
if (username != NULL) {
|
||||
*username = strndup(tok, endp - tok);
|
||||
if (*username == NULL) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
tok = endp + 1;
|
||||
/* If there is second @ character, this does not look like our URI */
|
||||
endp = strchr(tok, '@');
|
||||
if (endp != NULL) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hostname */
|
||||
if (*tok == '[') {
|
||||
/* IPv6 address is enclosed with square brackets */
|
||||
tok++;
|
||||
endp = strchr(tok, ']');
|
||||
if (endp == NULL) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
/* Hostnames or aliases expand to the last colon or to the end */
|
||||
endp = strrchr(tok, ':');
|
||||
if (endp == NULL) {
|
||||
endp = strchr(tok, '\0');
|
||||
}
|
||||
}
|
||||
if (tok == endp) {
|
||||
/* Zero-length hostnames are not valid */
|
||||
goto error;
|
||||
}
|
||||
if (hostname != NULL) {
|
||||
*hostname = strndup(tok, endp - tok);
|
||||
if (*hostname == NULL) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
/* Skip also the closing bracket */
|
||||
if (*endp == ']') {
|
||||
endp++;
|
||||
}
|
||||
|
||||
/* Port (optional) */
|
||||
if (*endp != '\0') {
|
||||
char *port_end = NULL;
|
||||
|
||||
/* Verify the port is valid positive number */
|
||||
port_n = strtol(endp + 1, &port_end, 10);
|
||||
if (port_n < 1 || *port_end != '\0') {
|
||||
SSH_LOG(SSH_LOG_WARN, "Failed to parse port number."
|
||||
" The value '%ld' is invalid or there are some"
|
||||
" trailing characters: '%s'", port_n, port_end);
|
||||
goto error;
|
||||
}
|
||||
if (port != NULL) {
|
||||
*port = strdup(endp + 1);
|
||||
if (*port == NULL) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
|
||||
error:
|
||||
if (username != NULL) {
|
||||
SAFE_FREE(*username);
|
||||
}
|
||||
if (hostname != NULL) {
|
||||
SAFE_FREE(*hostname);
|
||||
}
|
||||
if (port != NULL) {
|
||||
SAFE_FREE(*port);
|
||||
}
|
||||
return SSH_ERROR;
|
||||
}
|
||||
543
src/connect.c
543
src/connect.c
@@ -90,55 +90,131 @@
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef gai_strerror
|
||||
char WSAAPI *gai_strerrorA(int code)
|
||||
{
|
||||
static char buf[256];
|
||||
char WSAAPI *gai_strerrorA(int code) {
|
||||
static char buf[256];
|
||||
|
||||
snprintf(buf, sizeof(buf), "Undetermined error code (%d)", code);
|
||||
snprintf(buf, sizeof(buf), "Undetermined error code (%d)", code);
|
||||
|
||||
return buf;
|
||||
return buf;
|
||||
}
|
||||
#endif /* gai_strerror */
|
||||
#endif /* _WIN32 */
|
||||
|
||||
static int ssh_connect_socket_close(socket_t s)
|
||||
{
|
||||
static int ssh_connect_socket_close(socket_t s){
|
||||
#ifdef _WIN32
|
||||
return closesocket(s);
|
||||
return closesocket(s);
|
||||
#else
|
||||
return close(s);
|
||||
return close(s);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int getai(const char *host, int port, struct addrinfo **ai)
|
||||
{
|
||||
const char *service = NULL;
|
||||
struct addrinfo hints;
|
||||
char s_port[10];
|
||||
|
||||
ZERO_STRUCT(hints);
|
||||
static int getai(const char *host, int port, struct addrinfo **ai) {
|
||||
const char *service = NULL;
|
||||
struct addrinfo hints;
|
||||
char s_port[10];
|
||||
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
ZERO_STRUCT(hints);
|
||||
|
||||
if (port == 0) {
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
} else {
|
||||
snprintf(s_port, sizeof(s_port), "%hu", (unsigned short)port);
|
||||
service = s_port;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
if (port == 0) {
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
} else {
|
||||
snprintf(s_port, sizeof(s_port), "%hu", (unsigned short)port);
|
||||
service = s_port;
|
||||
#ifdef AI_NUMERICSERV
|
||||
hints.ai_flags = AI_NUMERICSERV;
|
||||
hints.ai_flags=AI_NUMERICSERV;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (ssh_is_ipaddr(host)) {
|
||||
/* this is an IP address */
|
||||
SSH_LOG(SSH_LOG_PACKET, "host %s matches an IP address", host);
|
||||
hints.ai_flags |= AI_NUMERICHOST;
|
||||
}
|
||||
if (ssh_is_ipaddr(host)) {
|
||||
/* this is an IP address */
|
||||
SSH_LOG(SSH_LOG_PACKET,"host %s matches an IP address",host);
|
||||
hints.ai_flags |= AI_NUMERICHOST;
|
||||
}
|
||||
|
||||
return getaddrinfo(host, service, &hints, ai);
|
||||
return getaddrinfo(host, service, &hints, ai);
|
||||
}
|
||||
|
||||
static int ssh_connect_ai_timeout(ssh_session session, const char *host,
|
||||
int port, struct addrinfo *ai, long timeout, long usec, socket_t s) {
|
||||
int timeout_ms;
|
||||
ssh_pollfd_t fds;
|
||||
int rc = 0;
|
||||
int ret;
|
||||
socklen_t len = sizeof(rc);
|
||||
|
||||
/* I know we're losing some precision. But it's not like poll-like family
|
||||
* type of mechanisms are precise up to the microsecond.
|
||||
*/
|
||||
timeout_ms=timeout * 1000 + usec / 1000;
|
||||
|
||||
rc = ssh_socket_set_nonblocking(s);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to set socket non-blocking for %s:%d", host, port);
|
||||
ssh_connect_socket_close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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 */
|
||||
connect(s, ai->ai_addr, ai->ai_addrlen);
|
||||
freeaddrinfo(ai);
|
||||
|
||||
fds.fd=s;
|
||||
fds.revents=0;
|
||||
fds.events=POLLOUT;
|
||||
#ifdef _WIN32
|
||||
fds.events |= POLLWRNORM;
|
||||
#endif
|
||||
rc = ssh_poll(&fds,1,timeout_ms);
|
||||
|
||||
if (rc == 0) {
|
||||
/* timeout */
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Timeout while connecting to %s:%d", host, port);
|
||||
ssh_connect_socket_close(s);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"poll error: %s", strerror(errno));
|
||||
ssh_connect_socket_close(s);
|
||||
|
||||
return -1;
|
||||
}
|
||||
rc = -1;
|
||||
|
||||
/* Get connect(2) return code. Zero means no error */
|
||||
ret = getsockopt(s, SOL_SOCKET, SO_ERROR,(char *) &rc, &len);
|
||||
if (ret < 0 || rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Connect to %s:%d failed: %s", host, port, strerror(rc));
|
||||
ssh_connect_socket_close(s);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* s is connected ? */
|
||||
SSH_LOG(SSH_LOG_PACKET, "Socket connected with timeout");
|
||||
ret = ssh_socket_set_blocking(s);
|
||||
if (ret < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to set socket as blocking connecting to %s:%d failed: %s",
|
||||
host, port, strerror(errno));
|
||||
ssh_connect_socket_close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static int set_tcp_nodelay(socket_t socket)
|
||||
@@ -152,6 +228,99 @@ static int set_tcp_nodelay(socket_t socket)
|
||||
sizeof(opt));
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Connect to an IPv4 or IPv6 host specified by its IP address or
|
||||
* hostname.
|
||||
*
|
||||
* @returns A file descriptor, < 0 on error.
|
||||
*/
|
||||
socket_t ssh_connect_host(ssh_session session, const char *host,
|
||||
const char *bind_addr, int port, long timeout, long usec) {
|
||||
socket_t s = -1;
|
||||
int rc;
|
||||
struct addrinfo *ai;
|
||||
struct addrinfo *itr;
|
||||
|
||||
rc = getai(host, port, &ai);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to resolve hostname %s (%s)", host, gai_strerror(rc));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (itr = ai; itr != NULL; itr = itr->ai_next){
|
||||
/* create socket */
|
||||
s = socket(itr->ai_family, itr->ai_socktype, itr->ai_protocol);
|
||||
if (s < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Socket create failed: %s", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bind_addr) {
|
||||
struct addrinfo *bind_ai;
|
||||
struct addrinfo *bind_itr;
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Resolving %s", bind_addr);
|
||||
|
||||
rc = getai(bind_addr, 0, &bind_ai);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to resolve bind address %s (%s)",
|
||||
bind_addr,
|
||||
gai_strerror(rc));
|
||||
freeaddrinfo(ai);
|
||||
close(s);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (bind_itr = bind_ai; bind_itr != NULL; bind_itr = bind_itr->ai_next) {
|
||||
if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Binding local address: %s", strerror(errno));
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeaddrinfo(bind_ai);
|
||||
|
||||
/* Cannot bind to any local addresses */
|
||||
if (bind_itr == NULL) {
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout || usec) {
|
||||
socket_t ret = ssh_connect_ai_timeout(session, host, port, itr,
|
||||
timeout, usec, s);
|
||||
|
||||
freeaddrinfo(ai);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (connect(s, itr->ai_addr, itr->ai_addrlen) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Connect failed: %s", strerror(errno));
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
} else {
|
||||
/* We are connected */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo(ai);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
@@ -162,109 +331,102 @@ static int set_tcp_nodelay(socket_t socket)
|
||||
* @warning very ugly !!!
|
||||
*/
|
||||
socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
||||
const char *bind_addr, int port)
|
||||
{
|
||||
socket_t s = -1;
|
||||
int rc;
|
||||
struct addrinfo *ai = NULL;
|
||||
struct addrinfo *itr = NULL;
|
||||
const char *bind_addr, int port) {
|
||||
socket_t s = -1;
|
||||
int rc;
|
||||
struct addrinfo *ai;
|
||||
struct addrinfo *itr;
|
||||
|
||||
rc = getai(host, port, &ai);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to resolve hostname %s (%s)",
|
||||
host, gai_strerror(rc));
|
||||
rc = getai(host, port, &ai);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to resolve hostname %s (%s)", host, gai_strerror(rc));
|
||||
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (itr = ai; itr != NULL; itr = itr->ai_next){
|
||||
/* create socket */
|
||||
s = socket(itr->ai_family, itr->ai_socktype, itr->ai_protocol);
|
||||
if (s < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Socket create failed: %s", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
for (itr = ai; itr != NULL; itr = itr->ai_next) {
|
||||
/* create socket */
|
||||
s = socket(itr->ai_family, itr->ai_socktype, itr->ai_protocol);
|
||||
if (s < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Socket create failed: %s", strerror(errno));
|
||||
continue;
|
||||
if (bind_addr) {
|
||||
struct addrinfo *bind_ai;
|
||||
struct addrinfo *bind_itr;
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Resolving %s", bind_addr);
|
||||
|
||||
rc = getai(bind_addr, 0, &bind_ai);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to resolve bind address %s (%s)",
|
||||
bind_addr,
|
||||
gai_strerror(rc));
|
||||
ssh_connect_socket_close(s);
|
||||
s=-1;
|
||||
break;
|
||||
}
|
||||
|
||||
for (bind_itr = bind_ai; bind_itr != NULL; bind_itr = bind_itr->ai_next) {
|
||||
if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Binding local address: %s", strerror(errno));
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeaddrinfo(bind_ai);
|
||||
|
||||
if (bind_addr) {
|
||||
struct addrinfo *bind_ai;
|
||||
struct addrinfo *bind_itr;
|
||||
/* Cannot bind to any local addresses */
|
||||
if (bind_itr == NULL) {
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Resolving %s", bind_addr);
|
||||
rc = ssh_socket_set_nonblocking(s);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to set socket non-blocking for %s:%d", host, port);
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
rc = getai(bind_addr, 0, &bind_ai);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to resolve bind address %s (%s)",
|
||||
bind_addr,
|
||||
gai_strerror(rc));
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
for (bind_itr = bind_ai;
|
||||
bind_itr != NULL;
|
||||
bind_itr = bind_itr->ai_next)
|
||||
{
|
||||
if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Binding local address: %s", strerror(errno));
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeaddrinfo(bind_ai);
|
||||
|
||||
/* Cannot bind to any local addresses */
|
||||
if (bind_itr == NULL) {
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
rc = ssh_socket_set_nonblocking(s);
|
||||
if (session->opts.nodelay) {
|
||||
/* For winsock, socket options are only effective before connect */
|
||||
rc = set_tcp_nodelay(s);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to set socket non-blocking for %s:%d",
|
||||
host, port);
|
||||
"Failed to set TCP_NODELAY on socket: %s", strerror(errno));
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (session->opts.nodelay) {
|
||||
/* For winsock, socket options are only effective before connect */
|
||||
rc = set_tcp_nodelay(s);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to set TCP_NODELAY on socket: %s",
|
||||
strerror(errno));
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
rc = connect(s, itr->ai_addr, itr->ai_addrlen);
|
||||
if (rc == -1 && (errno != 0) && (errno != EINPROGRESS)) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to connect: %s", strerror(errno));
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
freeaddrinfo(ai);
|
||||
errno = 0;
|
||||
rc = connect(s, itr->ai_addr, itr->ai_addrlen);
|
||||
if (rc == -1 && (errno != 0) && (errno != EINPROGRESS)) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to connect: %s", strerror(errno));
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
return s;
|
||||
break;
|
||||
}
|
||||
|
||||
freeaddrinfo(ai);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -273,13 +435,11 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
||||
* @{
|
||||
*/
|
||||
|
||||
static int ssh_select_cb (socket_t fd, int revents, void *userdata)
|
||||
{
|
||||
fd_set *set = (fd_set *)userdata;
|
||||
if (revents & POLLIN) {
|
||||
FD_SET(fd, set);
|
||||
}
|
||||
return 0;
|
||||
static int ssh_select_cb (socket_t fd, int revents, void *userdata){
|
||||
fd_set *set = (fd_set *)userdata;
|
||||
if(revents & POLLIN)
|
||||
FD_SET(fd, set);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -313,84 +473,73 @@ static int ssh_select_cb (socket_t fd, int revents, void *userdata)
|
||||
* @see select(2)
|
||||
*/
|
||||
int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
|
||||
fd_set *readfds, struct timeval *timeout)
|
||||
{
|
||||
fd_set origfds;
|
||||
socket_t fd;
|
||||
size_t i, j;
|
||||
int rc;
|
||||
int base_tm, tm;
|
||||
struct ssh_timestamp ts;
|
||||
ssh_event event = ssh_event_new();
|
||||
int firstround = 1;
|
||||
fd_set *readfds, struct timeval *timeout) {
|
||||
fd_set origfds;
|
||||
socket_t fd;
|
||||
size_t i, j;
|
||||
int rc;
|
||||
int base_tm, tm;
|
||||
struct ssh_timestamp ts;
|
||||
ssh_event event = ssh_event_new();
|
||||
int firstround=1;
|
||||
|
||||
base_tm = tm = (timeout->tv_sec * 1000) + (timeout->tv_usec / 1000);
|
||||
for (i = 0 ; channels[i] != NULL; ++i) {
|
||||
ssh_event_add_session(event, channels[i]->session);
|
||||
base_tm = tm=timeout->tv_sec * 1000 + timeout->tv_usec/1000;
|
||||
for (i=0 ; channels[i] != NULL; ++i){
|
||||
ssh_event_add_session(event, channels[i]->session);
|
||||
}
|
||||
|
||||
ZERO_STRUCT(origfds);
|
||||
FD_ZERO(&origfds);
|
||||
for (fd = 0; fd < maxfd ; fd++) {
|
||||
if (FD_ISSET(fd, readfds)) {
|
||||
ssh_event_add_fd(event, fd, POLLIN, ssh_select_cb, readfds);
|
||||
FD_SET(fd, &origfds);
|
||||
}
|
||||
}
|
||||
outchannels[0] = NULL;
|
||||
FD_ZERO(readfds);
|
||||
ssh_timestamp_init(&ts);
|
||||
do {
|
||||
/* Poll every channel */
|
||||
j = 0;
|
||||
for (i = 0; channels[i]; i++) {
|
||||
if(ssh_channel_poll(channels[i], 0) != 0) {
|
||||
outchannels[j] = channels[i];
|
||||
j++;
|
||||
} else if(ssh_channel_poll(channels[i], 1) != 0) {
|
||||
outchannels[j] = channels[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
ZERO_STRUCT(origfds);
|
||||
FD_ZERO(&origfds);
|
||||
for (fd = 0; fd < maxfd ; fd++) {
|
||||
if (FD_ISSET(fd, readfds)) {
|
||||
ssh_event_add_fd(event, fd, POLLIN, ssh_select_cb, readfds);
|
||||
FD_SET(fd, &origfds);
|
||||
}
|
||||
}
|
||||
outchannels[0] = NULL;
|
||||
FD_ZERO(readfds);
|
||||
ssh_timestamp_init(&ts);
|
||||
do {
|
||||
/* Poll every channel */
|
||||
j = 0;
|
||||
for (i = 0; channels[i]; i++) {
|
||||
rc = ssh_channel_poll(channels[i], 0);
|
||||
if (rc != 0) {
|
||||
outchannels[j] = channels[i];
|
||||
j++;
|
||||
} else {
|
||||
rc = ssh_channel_poll(channels[i], 1);
|
||||
if (rc != 0) {
|
||||
outchannels[j] = channels[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outchannels[j] = NULL;
|
||||
if (j != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* watch if a user socket was triggered */
|
||||
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;
|
||||
}
|
||||
|
||||
/* since there's nothing, let's fire the polling */
|
||||
rc = ssh_event_dopoll(event,tm);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
tm = ssh_timeout_update(&ts, base_tm);
|
||||
firstround = 0;
|
||||
} while (1);
|
||||
out:
|
||||
outchannels[j] = NULL;
|
||||
if(j != 0)
|
||||
break;
|
||||
/* watch if a user socket was triggered */
|
||||
for (fd = 0; fd < maxfd; fd++) {
|
||||
if (FD_ISSET(fd, &origfds)) {
|
||||
ssh_event_remove_fd(event, fd);
|
||||
if (FD_ISSET(fd, readfds)) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
ssh_event_free(event);
|
||||
return SSH_OK;
|
||||
|
||||
/* If the timeout is elapsed, we should go out */
|
||||
if(!firstround && ssh_timeout_elapsed(&ts, base_tm))
|
||||
goto out;
|
||||
/* since there's nothing, let's fire the polling */
|
||||
rc = ssh_event_dopoll(event,tm);
|
||||
if (rc == SSH_ERROR){
|
||||
goto out;
|
||||
}
|
||||
tm = ssh_timeout_update(&ts, base_tm);
|
||||
firstround=0;
|
||||
} while (1);
|
||||
out:
|
||||
for (fd = 0; fd < maxfd; fd++) {
|
||||
if (FD_ISSET(fd, &origfds)) {
|
||||
ssh_event_remove_fd(event, fd);
|
||||
}
|
||||
}
|
||||
ssh_event_free(event);
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
@@ -267,13 +267,8 @@ static void ssh_connector_fd_in_cb(ssh_connector connector)
|
||||
|
||||
if (connector->out_channel != NULL) {
|
||||
if (r == 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "input fd %d is EOF", connector->in_fd);
|
||||
if (connector->out_channel->local_eof == 0) {
|
||||
rc = ssh_channel_send_eof(connector->out_channel);
|
||||
(void)rc; /* TODO Handle rc? */
|
||||
}
|
||||
connector->in_available = 1; /* Don't poll on it */
|
||||
return;
|
||||
rc = ssh_channel_send_eof(connector->out_channel);
|
||||
(void)rc; /* TODO Handle rc? */
|
||||
} else if (r> 0) {
|
||||
/* loop around ssh_channel_write in case our window reduced due to a race */
|
||||
while (total != r){
|
||||
@@ -294,7 +289,7 @@ static void ssh_connector_fd_in_cb(ssh_connector connector)
|
||||
}
|
||||
} else if (connector->out_fd != SSH_INVALID_SOCKET) {
|
||||
if (r == 0){
|
||||
close(connector->out_fd);
|
||||
close (connector->out_fd);
|
||||
connector->out_fd = SSH_INVALID_SOCKET;
|
||||
} else {
|
||||
/*
|
||||
@@ -646,12 +641,14 @@ int ssh_connector_remove_event(ssh_connector connector) {
|
||||
session = ssh_channel_get_session(connector->in_channel);
|
||||
|
||||
ssh_event_remove_session(connector->event, session);
|
||||
connector->in_channel = NULL;
|
||||
}
|
||||
|
||||
if (connector->out_channel != NULL) {
|
||||
session = ssh_channel_get_session(connector->out_channel);
|
||||
|
||||
ssh_event_remove_session(connector->event, session);
|
||||
connector->out_channel = NULL;
|
||||
}
|
||||
connector->event = NULL;
|
||||
|
||||
|
||||
351
src/curve25519.c
351
src/curve25519.c
@@ -39,240 +39,75 @@
|
||||
#include "libssh/pki.h"
|
||||
#include "libssh/bignum.h"
|
||||
|
||||
#ifdef HAVE_OPENSSL_X25519
|
||||
#include <openssl/err.h>
|
||||
#endif
|
||||
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_client_curve25519_reply);
|
||||
|
||||
static ssh_packet_callback dh_client_callbacks[] = {
|
||||
ssh_packet_client_curve25519_reply
|
||||
};
|
||||
|
||||
static struct ssh_packet_callbacks_struct ssh_curve25519_client_callbacks = {
|
||||
.start = SSH2_MSG_KEX_ECDH_REPLY,
|
||||
.n_callbacks = 1,
|
||||
.callbacks = dh_client_callbacks,
|
||||
.user = NULL
|
||||
};
|
||||
|
||||
static int ssh_curve25519_init(ssh_session session)
|
||||
{
|
||||
int rc;
|
||||
#ifdef HAVE_OPENSSL_X25519
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
size_t pubkey_len = CURVE25519_PUBKEY_SIZE;
|
||||
size_t pkey_len = CURVE25519_PRIVKEY_SIZE;
|
||||
|
||||
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL);
|
||||
if (pctx == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to initialize X25519 context: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_keygen_init(pctx);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to initialize X25519 keygen: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_keygen(pctx, &pkey);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to generate X25519 keys: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (session->server) {
|
||||
rc = EVP_PKEY_get_raw_public_key(pkey,
|
||||
session->next_crypto->curve25519_server_pubkey,
|
||||
&pubkey_len);
|
||||
} else {
|
||||
rc = EVP_PKEY_get_raw_public_key(pkey,
|
||||
session->next_crypto->curve25519_client_pubkey,
|
||||
&pubkey_len);
|
||||
}
|
||||
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to get X25519 raw public key: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
EVP_PKEY_free(pkey);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_get_raw_private_key(pkey,
|
||||
session->next_crypto->curve25519_privkey,
|
||||
&pkey_len);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to get X25519 raw private key: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
EVP_PKEY_free(pkey);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
EVP_PKEY_free(pkey);
|
||||
#else
|
||||
rc = ssh_get_random(session->next_crypto->curve25519_privkey,
|
||||
CURVE25519_PRIVKEY_SIZE, 1);
|
||||
if (rc != 1) {
|
||||
ssh_set_error(session, SSH_FATAL, "PRNG error");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (session->server) {
|
||||
crypto_scalarmult_base(session->next_crypto->curve25519_server_pubkey,
|
||||
session->next_crypto->curve25519_privkey);
|
||||
} else {
|
||||
crypto_scalarmult_base(session->next_crypto->curve25519_client_pubkey,
|
||||
session->next_crypto->curve25519_privkey);
|
||||
}
|
||||
#endif /* HAVE_OPENSSL_X25519 */
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief Starts curve25519-sha256@libssh.org / curve25519-sha256 key exchange
|
||||
*/
|
||||
int ssh_client_curve25519_init(ssh_session session)
|
||||
{
|
||||
int rc;
|
||||
int ssh_client_curve25519_init(ssh_session session){
|
||||
int rc;
|
||||
int ok;
|
||||
|
||||
rc = ssh_curve25519_init(session);
|
||||
if (rc != SSH_OK) {
|
||||
return rc;
|
||||
}
|
||||
ok = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
|
||||
if (!ok) {
|
||||
ssh_set_error(session, SSH_FATAL, "PRNG error");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bdP",
|
||||
SSH2_MSG_KEX_ECDH_INIT,
|
||||
CURVE25519_PUBKEY_SIZE,
|
||||
(size_t)CURVE25519_PUBKEY_SIZE,
|
||||
session->next_crypto->curve25519_client_pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(session);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
crypto_scalarmult_base(session->next_crypto->curve25519_client_pubkey,
|
||||
session->next_crypto->curve25519_privkey);
|
||||
|
||||
/* register the packet callbacks */
|
||||
ssh_packet_set_callbacks(session, &ssh_curve25519_client_callbacks);
|
||||
session->dh_handshake_state = DH_STATE_INIT_SENT;
|
||||
rc = ssh_packet_send(session);
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bdP",
|
||||
SSH2_MSG_KEX_ECDH_INIT,
|
||||
CURVE25519_PUBKEY_SIZE,
|
||||
(size_t)CURVE25519_PUBKEY_SIZE, session->next_crypto->curve25519_client_pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(session);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
return rc;
|
||||
rc = ssh_packet_send(session);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ssh_curve25519_build_k(ssh_session session)
|
||||
{
|
||||
ssh_curve25519_pubkey k;
|
||||
static int ssh_curve25519_build_k(ssh_session session) {
|
||||
ssh_curve25519_pubkey k;
|
||||
|
||||
#ifdef HAVE_OPENSSL_X25519
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
EVP_PKEY *pkey = NULL, *pubkey = NULL;
|
||||
size_t shared_key_len;
|
||||
int rc;
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
session->next_crypto->k = bignum_new();
|
||||
|
||||
pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL,
|
||||
session->next_crypto->curve25519_privkey,
|
||||
CURVE25519_PRIVKEY_SIZE);
|
||||
if (pkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to create X25519 EVP_PKEY: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (session->next_crypto->k == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
session->next_crypto->k = bignum_new();
|
||||
|
||||
pctx = EVP_PKEY_CTX_new(pkey, NULL);
|
||||
if (pctx == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to initialize X25519 context: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
EVP_PKEY_free(pkey);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (session->next_crypto->k == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
rc = EVP_PKEY_derive_init(pctx);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to initialize X25519 key derivation: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
EVP_PKEY_free(pkey);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (session->server)
|
||||
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
|
||||
session->next_crypto->curve25519_client_pubkey);
|
||||
else
|
||||
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
|
||||
session->next_crypto->curve25519_server_pubkey);
|
||||
|
||||
if (session->server) {
|
||||
pubkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL,
|
||||
session->next_crypto->curve25519_client_pubkey,
|
||||
CURVE25519_PUBKEY_SIZE);
|
||||
} else {
|
||||
pubkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL,
|
||||
session->next_crypto->curve25519_server_pubkey,
|
||||
CURVE25519_PUBKEY_SIZE);
|
||||
}
|
||||
if (pubkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to create X25519 public key EVP_PKEY: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
EVP_PKEY_free(pkey);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_derive_set_peer(pctx, pubkey);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to set peer X25519 public key: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
EVP_PKEY_free(pkey);
|
||||
EVP_PKEY_free(pubkey);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_derive(pctx,
|
||||
k,
|
||||
&shared_key_len);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to derive X25519 shared secret: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
EVP_PKEY_free(pkey);
|
||||
EVP_PKEY_free(pubkey);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
#else
|
||||
if (session->server) {
|
||||
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
|
||||
session->next_crypto->curve25519_client_pubkey);
|
||||
} else {
|
||||
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
|
||||
session->next_crypto->curve25519_server_pubkey);
|
||||
}
|
||||
#endif /* HAVE_OPENSSL_X25519 */
|
||||
|
||||
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, &session->next_crypto->shared_secret);
|
||||
if (session->next_crypto->shared_secret == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, &session->next_crypto->k);
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, session->next_crypto->k);
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, session->next_crypto->k);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_log_hexdump("Session server cookie",
|
||||
ssh_print_hexa("Session server cookie",
|
||||
session->next_crypto->server_kex.cookie, 16);
|
||||
ssh_log_hexdump("Session client cookie",
|
||||
ssh_print_hexa("Session client cookie",
|
||||
session->next_crypto->client_kex.cookie, 16);
|
||||
ssh_print_bignum("Shared secret key", session->next_crypto->shared_secret);
|
||||
ssh_print_bignum("Shared secret key", session->next_crypto->k);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
@@ -282,15 +117,11 @@ static int ssh_curve25519_build_k(ssh_session session)
|
||||
* @brief parses a SSH_MSG_KEX_ECDH_REPLY packet and sends back
|
||||
* a SSH_MSG_NEWKEYS
|
||||
*/
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_client_curve25519_reply){
|
||||
int ssh_client_curve25519_reply(ssh_session session, ssh_buffer packet){
|
||||
ssh_string q_s_string = NULL;
|
||||
ssh_string pubkey_blob = NULL;
|
||||
ssh_string signature = NULL;
|
||||
int rc;
|
||||
(void)type;
|
||||
(void)user;
|
||||
|
||||
ssh_packet_remove_callbacks(session, &ssh_curve25519_client_callbacks);
|
||||
|
||||
pubkey_blob = ssh_buffer_get_ssh_string(packet);
|
||||
if (pubkey_blob == NULL) {
|
||||
@@ -340,47 +171,18 @@ static SSH_PACKET_CALLBACK(ssh_packet_client_curve25519_reply){
|
||||
}
|
||||
|
||||
rc=ssh_packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
||||
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
|
||||
return rc;
|
||||
error:
|
||||
session->session_state=SSH_SESSION_STATE_ERROR;
|
||||
return SSH_PACKET_USED;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init);
|
||||
|
||||
static ssh_packet_callback dh_server_callbacks[]= {
|
||||
ssh_packet_server_curve25519_init
|
||||
};
|
||||
|
||||
static struct ssh_packet_callbacks_struct ssh_curve25519_server_callbacks = {
|
||||
.start = SSH2_MSG_KEX_ECDH_INIT,
|
||||
.n_callbacks = 1,
|
||||
.callbacks = dh_server_callbacks,
|
||||
.user = NULL
|
||||
};
|
||||
|
||||
/** @internal
|
||||
* @brief sets up the curve25519-sha256@libssh.org kex callbacks
|
||||
*/
|
||||
void ssh_server_curve25519_init(ssh_session session){
|
||||
/* register the packet callbacks */
|
||||
ssh_packet_set_callbacks(session, &ssh_curve25519_server_callbacks);
|
||||
}
|
||||
|
||||
/** @brief Parse a SSH_MSG_KEXDH_INIT packet (server) and send a
|
||||
* SSH_MSG_KEXDH_REPLY
|
||||
*/
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){
|
||||
int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){
|
||||
/* ECDH keys */
|
||||
ssh_string q_c_string;
|
||||
ssh_string q_s_string;
|
||||
@@ -388,40 +190,37 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){
|
||||
|
||||
/* SSH host keys (rsa,dsa,ecdsa) */
|
||||
ssh_key privkey;
|
||||
enum ssh_digest_e digest = SSH_DIGEST_AUTO;
|
||||
ssh_string sig_blob = NULL;
|
||||
int ok;
|
||||
int rc;
|
||||
(void)type;
|
||||
(void)user;
|
||||
|
||||
ssh_packet_remove_callbacks(session, &ssh_curve25519_server_callbacks);
|
||||
|
||||
/* Extract the client pubkey from the init packet */
|
||||
q_c_string = ssh_buffer_get_ssh_string(packet);
|
||||
if (q_c_string == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL, "No Q_C ECC point in packet");
|
||||
goto error;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (ssh_string_len(q_c_string) != CURVE25519_PUBKEY_SIZE){
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Incorrect size for server Curve25519 public key: %zu",
|
||||
ssh_string_len(q_c_string));
|
||||
ssh_string_free(q_c_string);
|
||||
goto error;
|
||||
ssh_set_error(session, SSH_FATAL, "Incorrect size for server Curve25519 public key: %d",
|
||||
(int)ssh_string_len(q_c_string));
|
||||
ssh_string_free(q_c_string);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
memcpy(session->next_crypto->curve25519_client_pubkey,
|
||||
ssh_string_data(q_c_string), CURVE25519_PUBKEY_SIZE);
|
||||
ssh_string_data(q_c_string), CURVE25519_PUBKEY_SIZE);
|
||||
ssh_string_free(q_c_string);
|
||||
/* Build server's keypair */
|
||||
|
||||
rc = ssh_curve25519_init(session);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL, "Failed to generate curve25519 keys");
|
||||
goto error;
|
||||
ok = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
|
||||
if (!ok) {
|
||||
ssh_set_error(session, SSH_FATAL, "PRNG error");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
crypto_scalarmult_base(session->next_crypto->curve25519_server_pubkey,
|
||||
session->next_crypto->curve25519_privkey);
|
||||
|
||||
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_REPLY);
|
||||
if (rc < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
@@ -436,7 +235,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){
|
||||
}
|
||||
|
||||
/* privkey is not allocated */
|
||||
rc = ssh_get_key_params(session, &privkey, &digest);
|
||||
rc = ssh_get_key_params(session, &privkey);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
@@ -479,7 +278,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){
|
||||
goto error;
|
||||
}
|
||||
/* add signature blob */
|
||||
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey, digest);
|
||||
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
|
||||
if (sig_blob == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
|
||||
goto error;
|
||||
@@ -506,16 +305,12 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){
|
||||
|
||||
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
|
||||
rc = ssh_packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
return rc;
|
||||
error:
|
||||
ssh_buffer_reinit(session->out_buffer);
|
||||
session->session_state=SSH_SESSION_STATE_ERROR;
|
||||
return SSH_PACKET_USED;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
684
src/dh-gex.c
684
src/dh-gex.c
@@ -1,684 +0,0 @@
|
||||
/*
|
||||
* dh-gex.c - diffie-hellman group exchange
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2016 by Aris Adamantiadis <aris@0xbadc0de.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 <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/dh-gex.h"
|
||||
#include "libssh/libssh.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/callbacks.h"
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/session.h"
|
||||
|
||||
/* Minimum, recommanded and maximum size of DH group */
|
||||
#define DH_PMIN 2048
|
||||
#define DH_PREQ 2048
|
||||
#define DH_PMAX 8192
|
||||
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group);
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_reply);
|
||||
|
||||
static ssh_packet_callback dhgex_client_callbacks[] = {
|
||||
ssh_packet_client_dhgex_group, /* SSH_MSG_KEX_DH_GEX_GROUP */
|
||||
NULL, /* SSH_MSG_KEX_DH_GEX_INIT */
|
||||
ssh_packet_client_dhgex_reply /* SSH_MSG_KEX_DH_GEX_REPLY */
|
||||
};
|
||||
|
||||
static struct ssh_packet_callbacks_struct ssh_dhgex_client_callbacks = {
|
||||
.start = SSH2_MSG_KEX_DH_GEX_GROUP,
|
||||
.n_callbacks = 3,
|
||||
.callbacks = dhgex_client_callbacks,
|
||||
.user = NULL
|
||||
};
|
||||
|
||||
/** @internal
|
||||
* @brief initiates a diffie-hellman-group-exchange kex
|
||||
*/
|
||||
int ssh_client_dhgex_init(ssh_session session)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ssh_dh_init_common(session->next_crypto);
|
||||
if (rc != SSH_OK){
|
||||
goto error;
|
||||
}
|
||||
|
||||
session->next_crypto->dh_pmin = DH_PMIN;
|
||||
session->next_crypto->dh_pn = DH_PREQ;
|
||||
session->next_crypto->dh_pmax = DH_PMAX;
|
||||
/* Minimum group size, preferred group size, maximum group size */
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bddd",
|
||||
SSH2_MSG_KEX_DH_GEX_REQUEST,
|
||||
session->next_crypto->dh_pmin,
|
||||
session->next_crypto->dh_pn,
|
||||
session->next_crypto->dh_pmax);
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* register the packet callbacks */
|
||||
ssh_packet_set_callbacks(session, &ssh_dhgex_client_callbacks);
|
||||
session->dh_handshake_state = DH_STATE_REQUEST_SENT;
|
||||
rc = ssh_packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
return rc;
|
||||
error:
|
||||
ssh_dh_cleanup(session->next_crypto);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief handle a DH_GEX_GROUP packet, client side. This packet contains
|
||||
* the group parameters.
|
||||
*/
|
||||
SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group)
|
||||
{
|
||||
int rc;
|
||||
int blen;
|
||||
bignum pmin1 = NULL, one = NULL;
|
||||
bignum_CTX ctx = bignum_ctx_new();
|
||||
bignum modulus = NULL, generator = NULL;
|
||||
const_bignum pubkey;
|
||||
(void) type;
|
||||
(void) user;
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_DH_GEX_GROUP received");
|
||||
|
||||
if (bignum_ctx_invalid(ctx)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (session->dh_handshake_state != DH_STATE_REQUEST_SENT) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Received DH_GEX_GROUP in invalid state");
|
||||
goto error;
|
||||
}
|
||||
one = bignum_new();
|
||||
pmin1 = bignum_new();
|
||||
if (one == NULL || pmin1 == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
rc = ssh_buffer_unpack(packet,
|
||||
"BB",
|
||||
&modulus,
|
||||
&generator);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL, "Invalid DH_GEX_GROUP packet");
|
||||
goto error;
|
||||
}
|
||||
/* basic checks */
|
||||
if (ssh_fips_mode() &&
|
||||
!ssh_dh_is_known_group(modulus, generator)) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"The received DH group is not FIPS approved");
|
||||
goto error;
|
||||
}
|
||||
rc = bignum_set_word(one, 1);
|
||||
if (rc != 1) {
|
||||
goto error;
|
||||
}
|
||||
blen = bignum_num_bits(modulus);
|
||||
if (blen < DH_PMIN || blen > DH_PMAX) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Invalid dh group parameter p: %d not in [%d:%d]",
|
||||
blen,
|
||||
DH_PMIN,
|
||||
DH_PMAX);
|
||||
goto error;
|
||||
}
|
||||
if (bignum_cmp(modulus, one) <= 0) {
|
||||
/* p must be positive and preferably bigger than one */
|
||||
ssh_set_error(session, SSH_FATAL, "Invalid dh group parameter p");
|
||||
}
|
||||
if (!bignum_is_bit_set(modulus, 0)) {
|
||||
/* p must be a prime and therefore not divisible by 2 */
|
||||
ssh_set_error(session, SSH_FATAL, "Invalid dh group parameter p");
|
||||
goto error;
|
||||
}
|
||||
bignum_sub(pmin1, modulus, one);
|
||||
if (bignum_cmp(generator, one) <= 0 ||
|
||||
bignum_cmp(generator, pmin1) > 0) {
|
||||
/* generator must be at least 2 and smaller than p-1*/
|
||||
ssh_set_error(session, SSH_FATAL, "Invalid dh group parameter g");
|
||||
goto error;
|
||||
}
|
||||
bignum_ctx_free(ctx);
|
||||
ctx = NULL;
|
||||
|
||||
/* all checks passed, set parameters (the BNs are copied in openssl backend) */
|
||||
rc = ssh_dh_set_parameters(session->next_crypto->dh_ctx,
|
||||
modulus, generator);
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
bignum_safe_free(modulus);
|
||||
bignum_safe_free(generator);
|
||||
#endif
|
||||
modulus = NULL;
|
||||
generator = NULL;
|
||||
|
||||
/* compute and send DH public parameter */
|
||||
rc = ssh_dh_keypair_gen_keys(session->next_crypto->dh_ctx,
|
||||
DH_CLIENT_KEYPAIR);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_dh_keypair_get_keys(session->next_crypto->dh_ctx,
|
||||
DH_CLIENT_KEYPAIR, NULL, &pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bB",
|
||||
SSH2_MSG_KEX_DH_GEX_INIT,
|
||||
pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
session->dh_handshake_state = DH_STATE_INIT_SENT;
|
||||
|
||||
rc = ssh_packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
bignum_safe_free(one);
|
||||
bignum_safe_free(pmin1);
|
||||
return SSH_PACKET_USED;
|
||||
|
||||
error:
|
||||
bignum_safe_free(modulus);
|
||||
bignum_safe_free(generator);
|
||||
bignum_safe_free(one);
|
||||
bignum_safe_free(pmin1);
|
||||
if(!bignum_ctx_invalid(ctx)) {
|
||||
bignum_ctx_free(ctx);
|
||||
}
|
||||
ssh_dh_cleanup(session->next_crypto);
|
||||
session->session_state = SSH_SESSION_STATE_ERROR;
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_reply)
|
||||
{
|
||||
struct ssh_crypto_struct *crypto=session->next_crypto;
|
||||
int rc;
|
||||
ssh_string pubkey_blob = NULL;
|
||||
bignum server_pubkey = NULL;
|
||||
(void)type;
|
||||
(void)user;
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_DH_GEX_REPLY received");
|
||||
|
||||
ssh_packet_remove_callbacks(session, &ssh_dhgex_client_callbacks);
|
||||
rc = ssh_buffer_unpack(packet,
|
||||
"SBS",
|
||||
&pubkey_blob, &server_pubkey,
|
||||
&crypto->dh_server_signature);
|
||||
if (rc == SSH_ERROR) {
|
||||
ssh_set_error(session, SSH_FATAL, "Invalid DH_GEX_REPLY packet");
|
||||
goto error;
|
||||
}
|
||||
rc = ssh_dh_keypair_set_keys(crypto->dh_ctx, DH_SERVER_KEYPAIR,
|
||||
NULL, server_pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
bignum_safe_free(server_pubkey);
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_dh_import_next_pubkey_blob(session, pubkey_blob);
|
||||
ssh_string_free(pubkey_blob);
|
||||
if (rc != 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_dh_compute_shared_secret(session->next_crypto->dh_ctx,
|
||||
DH_CLIENT_KEYPAIR, DH_SERVER_KEYPAIR,
|
||||
&session->next_crypto->shared_secret);
|
||||
ssh_dh_debug_crypto(session->next_crypto);
|
||||
if (rc == SSH_ERROR) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not generate shared secret");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Send the MSG_NEWKEYS */
|
||||
if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
||||
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
error:
|
||||
ssh_dh_cleanup(session->next_crypto);
|
||||
session->session_state = SSH_SESSION_STATE_ERROR;
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
|
||||
#define MODULI_FILE "/etc/ssh/moduli"
|
||||
/* 2 "Safe" prime; (p-1)/2 is also prime. */
|
||||
#define SAFE_PRIME 2
|
||||
/* 0x04 Probabilistic Miller-Rabin primality tests. */
|
||||
#define PRIM_TEST_REQUIRED 0x04
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Determines if the proposed modulus size is more appropriate than the
|
||||
* current one.
|
||||
*
|
||||
* @returns 1 if it's more appropriate. Returns 0 if same or less appropriate
|
||||
*/
|
||||
static bool dhgroup_better_size(uint32_t pmin,
|
||||
uint32_t pn,
|
||||
uint32_t pmax,
|
||||
size_t current_size,
|
||||
size_t proposed_size)
|
||||
{
|
||||
if (current_size == proposed_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (current_size == pn) {
|
||||
/* can't do better */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (current_size == 0 && proposed_size >= pmin && proposed_size <= pmax) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (proposed_size < pmin || proposed_size > pmax) {
|
||||
/* out of bounds */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (current_size == 0) {
|
||||
/* not in the allowed window */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (proposed_size >= pn && proposed_size < current_size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (proposed_size <= pn && proposed_size > current_size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (proposed_size >= pn && current_size < pn) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* We're in the allowed window but a better match already exists. */
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief returns 1 with 1/n probability
|
||||
* @returns 1 on with P(1/n), 0 with P(n-1/n).
|
||||
*/
|
||||
static bool invn_chance(int n)
|
||||
{
|
||||
uint32_t nounce;
|
||||
ssh_get_random(&nounce, sizeof(nounce), 0);
|
||||
return (nounce % n) == 0;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief retrieves a DH group from an open moduli file.
|
||||
*/
|
||||
static int ssh_retrieve_dhgroup_file(FILE *moduli,
|
||||
uint32_t pmin,
|
||||
uint32_t pn,
|
||||
uint32_t pmax,
|
||||
size_t *best_size,
|
||||
char **best_generator,
|
||||
char **best_modulus)
|
||||
{
|
||||
char timestamp[32] = {0};
|
||||
char generator[32] = {0};
|
||||
char modulus[4096] = {0};
|
||||
size_t type, tests, tries, size, proposed_size;
|
||||
int firstbyte;
|
||||
int rc;
|
||||
size_t line = 0;
|
||||
size_t best_nlines = 0;
|
||||
|
||||
for(;;) {
|
||||
line++;
|
||||
firstbyte = getc(moduli);
|
||||
if (firstbyte == '#'){
|
||||
do {
|
||||
firstbyte = getc(moduli);
|
||||
} while(firstbyte != '\n' && firstbyte != EOF);
|
||||
continue;
|
||||
}
|
||||
if (firstbyte == EOF) {
|
||||
break;
|
||||
}
|
||||
ungetc(firstbyte, moduli);
|
||||
rc = fscanf(moduli,
|
||||
"%31s %zu %zu %zu %zu %31s %4095s\n",
|
||||
timestamp,
|
||||
&type,
|
||||
&tests,
|
||||
&tries,
|
||||
&size,
|
||||
generator,
|
||||
modulus);
|
||||
if (rc != 7){
|
||||
if (rc == EOF) {
|
||||
break;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_INFO, "Invalid moduli entry line %zu", line);
|
||||
do {
|
||||
firstbyte = getc(moduli);
|
||||
} while(firstbyte != '\n' && firstbyte != EOF);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* we only want safe primes that were tested */
|
||||
if (type != SAFE_PRIME || !(tests & PRIM_TEST_REQUIRED)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
proposed_size = size + 1;
|
||||
if (proposed_size != *best_size &&
|
||||
dhgroup_better_size(pmin, pn, pmax, *best_size, proposed_size)) {
|
||||
best_nlines = 0;
|
||||
*best_size = proposed_size;
|
||||
}
|
||||
if (proposed_size == *best_size) {
|
||||
best_nlines++;
|
||||
}
|
||||
|
||||
/* Use reservoir sampling algorithm */
|
||||
if (proposed_size == *best_size && invn_chance(best_nlines)) {
|
||||
SAFE_FREE(*best_generator);
|
||||
SAFE_FREE(*best_modulus);
|
||||
*best_generator = strdup(generator);
|
||||
if (*best_generator == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
*best_modulus = strdup(modulus);
|
||||
if (*best_modulus == NULL) {
|
||||
SAFE_FREE(*best_generator);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (*best_size != 0) {
|
||||
SSH_LOG(SSH_LOG_INFO,
|
||||
"Selected %zu bits modulus out of %zu candidates in %zu lines",
|
||||
*best_size,
|
||||
best_nlines - 1,
|
||||
line);
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_WARNING,
|
||||
"No moduli found for [%u:%u:%u]",
|
||||
pmin,
|
||||
pn,
|
||||
pmax);
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief retrieves a DH group from the moduli file based on bits len parameters
|
||||
* @param[in] pmin minimum group size in bits
|
||||
* @param[in] pn preferred group size
|
||||
* @param[in] pmax maximum group size
|
||||
* @param[out] size size of the chosen modulus
|
||||
* @param[out] p modulus
|
||||
* @param[out] g generator
|
||||
* @return SSH_OK on success, SSH_ERROR otherwise.
|
||||
*/
|
||||
static int ssh_retrieve_dhgroup(uint32_t pmin,
|
||||
uint32_t pn,
|
||||
uint32_t pmax,
|
||||
size_t *size,
|
||||
bignum *p,
|
||||
bignum *g)
|
||||
{
|
||||
FILE *moduli = NULL;
|
||||
char *generator = NULL;
|
||||
char *modulus = NULL;
|
||||
int rc;
|
||||
|
||||
/* In FIPS mode, we can not negotiate arbitrary primes,
|
||||
* but just the approved ones */
|
||||
if (ssh_fips_mode()) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "In FIPS mode, using built-in primes");
|
||||
return ssh_fallback_group(pmax, p, g);
|
||||
}
|
||||
|
||||
moduli = fopen(MODULI_FILE, "r");
|
||||
if (moduli == NULL) {
|
||||
SSH_LOG(SSH_LOG_WARNING,
|
||||
"Unable to open moduli file: %s",
|
||||
strerror(errno));
|
||||
return ssh_fallback_group(pmax, p, g);
|
||||
}
|
||||
|
||||
*size = 0;
|
||||
*p = NULL;
|
||||
*g = NULL;
|
||||
|
||||
rc = ssh_retrieve_dhgroup_file(moduli,
|
||||
pmin,
|
||||
pn,
|
||||
pmax,
|
||||
size,
|
||||
&generator,
|
||||
&modulus);
|
||||
fclose(moduli);
|
||||
if (rc == SSH_ERROR || *size == 0) {
|
||||
goto error;
|
||||
}
|
||||
rc = bignum_hex2bn(generator, g);
|
||||
if (rc == 0) {
|
||||
goto error;
|
||||
}
|
||||
rc = bignum_hex2bn(modulus, p);
|
||||
if (rc == 0) {
|
||||
goto error;
|
||||
}
|
||||
SAFE_FREE(generator);
|
||||
SAFE_FREE(modulus);
|
||||
|
||||
return SSH_OK;
|
||||
|
||||
error:
|
||||
bignum_safe_free(*g);
|
||||
bignum_safe_free(*p);
|
||||
SAFE_FREE(generator);
|
||||
SAFE_FREE(modulus);
|
||||
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_server_dhgex_request);
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_server_dhgex_init);
|
||||
|
||||
static ssh_packet_callback dhgex_server_callbacks[]= {
|
||||
NULL, /* SSH_MSG_KEX_DH_GEX_REQUEST_OLD */
|
||||
NULL, /* SSH_MSG_KEX_DH_GEX_GROUP */
|
||||
ssh_packet_server_dhgex_init, /* SSH_MSG_KEX_DH_GEX_INIT */
|
||||
NULL, /* SSH_MSG_KEX_DH_GEX_REPLY */
|
||||
ssh_packet_server_dhgex_request /* SSH_MSG_GEX_DH_GEX_REQUEST */
|
||||
|
||||
};
|
||||
|
||||
static struct ssh_packet_callbacks_struct ssh_dhgex_server_callbacks = {
|
||||
.start = SSH2_MSG_KEX_DH_GEX_REQUEST_OLD,
|
||||
.n_callbacks = 5,
|
||||
.callbacks = dhgex_server_callbacks,
|
||||
.user = NULL
|
||||
};
|
||||
|
||||
/** @internal
|
||||
* @brief sets up the diffie-hellman-groupx kex callbacks
|
||||
*/
|
||||
void ssh_server_dhgex_init(ssh_session session){
|
||||
/* register the packet callbacks */
|
||||
ssh_packet_set_callbacks(session, &ssh_dhgex_server_callbacks);
|
||||
ssh_dh_init_common(session->next_crypto);
|
||||
session->dh_handshake_state = DH_STATE_INIT;
|
||||
}
|
||||
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_server_dhgex_request)
|
||||
{
|
||||
bignum modulus = NULL, generator = NULL;
|
||||
uint32_t pmin, pn, pmax;
|
||||
size_t size = 0;
|
||||
int rc;
|
||||
|
||||
(void) type;
|
||||
(void) user;
|
||||
|
||||
if (session->dh_handshake_state != DH_STATE_INIT) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Received DH_GEX_REQUEST in invalid state");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Minimum group size, preferred group size, maximum group size */
|
||||
rc = ssh_buffer_unpack(packet, "ddd", &pmin, &pn, &pmax);
|
||||
if (rc != SSH_OK){
|
||||
ssh_set_error_invalid(session);
|
||||
goto error;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_INFO, "dh-gex: DHGEX_REQUEST[%u:%u:%u]", pmin, pn, pmax);
|
||||
|
||||
if (pmin > pn || pn > pmax || pn > DH_PMAX || pmax < DH_PMIN) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Invalid dh-gex arguments [%u:%u:%u]",
|
||||
pmin,
|
||||
pn,
|
||||
pmax);
|
||||
goto error;
|
||||
}
|
||||
session->next_crypto->dh_pmin = pmin;
|
||||
session->next_crypto->dh_pn = pn;
|
||||
session->next_crypto->dh_pmax = pmax;
|
||||
|
||||
/* ensure safe parameters */
|
||||
if (pmin < DH_PMIN) {
|
||||
pmin = DH_PMIN;
|
||||
if (pn < pmin) {
|
||||
pn = pmin;
|
||||
}
|
||||
}
|
||||
rc = ssh_retrieve_dhgroup(pmin,
|
||||
pn,
|
||||
pmax,
|
||||
&size,
|
||||
&modulus,
|
||||
&generator);
|
||||
if (rc == SSH_ERROR) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Couldn't find DH group for [%u:%u:%u]",
|
||||
pmin,
|
||||
pn,
|
||||
pmax);
|
||||
goto error;
|
||||
}
|
||||
rc = ssh_dh_set_parameters(session->next_crypto->dh_ctx,
|
||||
modulus, generator);
|
||||
if (rc != SSH_OK) {
|
||||
bignum_safe_free(generator);
|
||||
bignum_safe_free(modulus);
|
||||
goto error;
|
||||
}
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bBB",
|
||||
SSH2_MSG_KEX_DH_GEX_GROUP,
|
||||
modulus,
|
||||
generator);
|
||||
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
bignum_safe_free(generator);
|
||||
bignum_safe_free(modulus);
|
||||
#endif
|
||||
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_invalid(session);
|
||||
goto error;
|
||||
}
|
||||
|
||||
session->dh_handshake_state = DH_STATE_GROUP_SENT;
|
||||
|
||||
rc = ssh_packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief parse an incoming SSH_MSG_KEX_DH_GEX_INIT packet and complete
|
||||
* Diffie-Hellman key exchange
|
||||
**/
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_server_dhgex_init){
|
||||
(void) type;
|
||||
(void) user;
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Received SSH_MSG_KEX_DHGEX_INIT");
|
||||
ssh_packet_remove_callbacks(session, &ssh_dhgex_server_callbacks);
|
||||
ssh_server_dh_process_init(session, packet);
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
#endif /* WITH_SERVER */
|
||||
286
src/dh_crypto.c
286
src/dh_crypto.c
@@ -1,286 +0,0 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2019 by Simo Sorce - Red Hat, Inc.
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/pki.h"
|
||||
#include "libssh/bignum.h"
|
||||
|
||||
#include "openssl/crypto.h"
|
||||
#include "openssl/dh.h"
|
||||
#include "libcrypto-compat.h"
|
||||
|
||||
extern bignum ssh_dh_generator;
|
||||
extern bignum ssh_dh_group1;
|
||||
extern bignum ssh_dh_group14;
|
||||
extern bignum ssh_dh_group16;
|
||||
extern bignum ssh_dh_group18;
|
||||
|
||||
struct dh_ctx {
|
||||
DH *keypair[2];
|
||||
};
|
||||
|
||||
void ssh_dh_debug_crypto(struct ssh_crypto_struct *c)
|
||||
{
|
||||
#ifdef DEBUG_CRYPTO
|
||||
const_bignum x = NULL, y = NULL, e = NULL, f = NULL;
|
||||
|
||||
ssh_dh_keypair_get_keys(c->dh_ctx, DH_CLIENT_KEYPAIR, &x, &e);
|
||||
ssh_dh_keypair_get_keys(c->dh_ctx, DH_SERVER_KEYPAIR, &y, &f);
|
||||
ssh_print_bignum("x", x);
|
||||
ssh_print_bignum("y", y);
|
||||
ssh_print_bignum("e", e);
|
||||
ssh_print_bignum("f", f);
|
||||
|
||||
ssh_log_hexdump("Session server cookie", c->server_kex.cookie, 16);
|
||||
ssh_log_hexdump("Session client cookie", c->client_kex.cookie, 16);
|
||||
ssh_print_bignum("k", c->shared_secret);
|
||||
|
||||
#else
|
||||
(void)c; /* UNUSED_PARAM */
|
||||
#endif
|
||||
}
|
||||
|
||||
int ssh_dh_keypair_get_keys(struct dh_ctx *ctx, int peer,
|
||||
const_bignum *priv, const_bignum *pub)
|
||||
{
|
||||
if (((peer != DH_CLIENT_KEYPAIR) && (peer != DH_SERVER_KEYPAIR)) ||
|
||||
((priv == NULL) && (pub == NULL)) || (ctx == NULL) ||
|
||||
(ctx->keypair[peer] == NULL)) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
DH_get0_key(ctx->keypair[peer], pub, priv);
|
||||
if (priv && (*priv == NULL || bignum_num_bits(*priv) == 0)) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (pub && (*pub == NULL || bignum_num_bits(*pub) == 0)) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int ssh_dh_keypair_set_keys(struct dh_ctx *ctx, int peer,
|
||||
const bignum priv, const bignum pub)
|
||||
{
|
||||
bignum priv_key = NULL;
|
||||
bignum pub_key = NULL;
|
||||
|
||||
if (((peer != DH_CLIENT_KEYPAIR) && (peer != DH_SERVER_KEYPAIR)) ||
|
||||
((priv == NULL) && (pub == NULL)) || (ctx == NULL) ||
|
||||
(ctx->keypair[peer] == NULL)) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (priv) {
|
||||
priv_key = priv;
|
||||
}
|
||||
if (pub) {
|
||||
pub_key = pub;
|
||||
}
|
||||
(void)DH_set0_key(ctx->keypair[peer], pub_key, priv_key);
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int ssh_dh_get_parameters(struct dh_ctx *ctx,
|
||||
const_bignum *modulus, const_bignum *generator)
|
||||
{
|
||||
if (ctx == NULL || ctx->keypair[0] == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
DH_get0_pqg(ctx->keypair[0], modulus, NULL, generator);
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int ssh_dh_set_parameters(struct dh_ctx *ctx,
|
||||
const bignum modulus, const bignum generator)
|
||||
{
|
||||
size_t i;
|
||||
int rc;
|
||||
|
||||
if ((ctx == NULL) || (modulus == NULL) || (generator == NULL)) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
bignum p = NULL;
|
||||
bignum g = NULL;
|
||||
|
||||
/* when setting modulus or generator,
|
||||
* make sure to invalidate existing keys */
|
||||
DH_free(ctx->keypair[i]);
|
||||
ctx->keypair[i] = DH_new();
|
||||
if (ctx->keypair[i] == NULL) {
|
||||
rc = SSH_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
p = BN_dup(modulus);
|
||||
g = BN_dup(generator);
|
||||
rc = DH_set0_pqg(ctx->keypair[i], p, NULL, g);
|
||||
if (rc != 1) {
|
||||
BN_free(p);
|
||||
BN_free(g);
|
||||
rc = SSH_ERROR;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
rc = SSH_OK;
|
||||
done:
|
||||
if (rc != SSH_OK) {
|
||||
DH_free(ctx->keypair[0]);
|
||||
DH_free(ctx->keypair[1]);
|
||||
ctx->keypair[0] = NULL;
|
||||
ctx->keypair[1] = NULL;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief allocate and initialize ephemeral values used in dh kex
|
||||
*/
|
||||
int ssh_dh_init_common(struct ssh_crypto_struct *crypto)
|
||||
{
|
||||
struct dh_ctx *ctx;
|
||||
int rc;
|
||||
|
||||
ctx = calloc(1, sizeof(*ctx));
|
||||
if (ctx == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
crypto->dh_ctx = ctx;
|
||||
|
||||
switch (crypto->kex_type) {
|
||||
case SSH_KEX_DH_GROUP1_SHA1:
|
||||
rc = ssh_dh_set_parameters(ctx, ssh_dh_group1, ssh_dh_generator);
|
||||
break;
|
||||
case SSH_KEX_DH_GROUP14_SHA1:
|
||||
rc = ssh_dh_set_parameters(ctx, ssh_dh_group14, ssh_dh_generator);
|
||||
break;
|
||||
case SSH_KEX_DH_GROUP16_SHA512:
|
||||
rc = ssh_dh_set_parameters(ctx, ssh_dh_group16, ssh_dh_generator);
|
||||
break;
|
||||
case SSH_KEX_DH_GROUP18_SHA512:
|
||||
rc = ssh_dh_set_parameters(ctx, ssh_dh_group18, ssh_dh_generator);
|
||||
break;
|
||||
default:
|
||||
rc = SSH_OK;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc != SSH_OK) {
|
||||
ssh_dh_cleanup(crypto);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void ssh_dh_cleanup(struct ssh_crypto_struct *crypto)
|
||||
{
|
||||
if (crypto->dh_ctx != NULL) {
|
||||
DH_free(crypto->dh_ctx->keypair[0]);
|
||||
DH_free(crypto->dh_ctx->keypair[1]);
|
||||
free(crypto->dh_ctx);
|
||||
crypto->dh_ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief generates a secret DH parameter of at least DH_SECURITY_BITS
|
||||
* security as well as the corresponding public key.
|
||||
* @param[out] parms a dh_ctx that will hold the new keys.
|
||||
* @param peer Select either client or server key storage. Valid values are:
|
||||
* DH_CLIENT_KEYPAIR or DH_SERVER_KEYPAIR
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR on error
|
||||
*/
|
||||
int ssh_dh_keypair_gen_keys(struct dh_ctx *dh_ctx, int peer)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if ((dh_ctx == NULL) || (dh_ctx->keypair[peer] == NULL)) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
rc = DH_generate_key(dh_ctx->keypair[peer]);
|
||||
if (rc != 1) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief generates a shared secret between the local peer and the remote
|
||||
* peer. The local peer must have been initialized using either the
|
||||
* ssh_dh_keypair_gen_keys() function or by seetting manually both
|
||||
* the private and public keys. The remote peer only needs to have
|
||||
* the remote's peer public key set.
|
||||
* @param[in] local peer identifier (DH_CLIENT_KEYPAIR or DH_SERVER_KEYPAIR)
|
||||
* @param[in] remote peer identifier (DH_CLIENT_KEYPAIR or DH_SERVER_KEYPAIR)
|
||||
* @param[out] dest a new bignum with the shared secret value is returned.
|
||||
* @return SSH_OK on success, SSH_ERROR on error
|
||||
*/
|
||||
int ssh_dh_compute_shared_secret(struct dh_ctx *dh_ctx, int local, int remote,
|
||||
bignum *dest)
|
||||
{
|
||||
unsigned char *kstring = NULL;
|
||||
const_bignum pub_key = NULL;
|
||||
int klen, rc;
|
||||
|
||||
if ((dh_ctx == NULL) ||
|
||||
(dh_ctx->keypair[local] == NULL) ||
|
||||
(dh_ctx->keypair[remote] == NULL)) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
kstring = malloc(DH_size(dh_ctx->keypair[local]));
|
||||
if (kstring == NULL) {
|
||||
rc = SSH_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
rc = ssh_dh_keypair_get_keys(dh_ctx, remote, NULL, &pub_key);
|
||||
if (rc != SSH_OK) {
|
||||
rc = SSH_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
klen = DH_compute_key(kstring, pub_key, dh_ctx->keypair[local]);
|
||||
if (klen == -1) {
|
||||
rc = SSH_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
*dest = BN_bin2bn(kstring, klen, NULL);
|
||||
if (*dest == NULL) {
|
||||
rc = SSH_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
rc = SSH_OK;
|
||||
done:
|
||||
free(kstring);
|
||||
return rc;
|
||||
}
|
||||
375
src/dh_key.c
375
src/dh_key.c
@@ -1,375 +0,0 @@
|
||||
/*
|
||||
* dh-int.c - Diffie-Helman algorithm code against SSH 2
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2018 by Aris Adamantiadis
|
||||
* Copyright (c) 2009-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
* Copyright (c) 2012 by Dmitriy Kuznetsov <dk@yandex.ru>
|
||||
* Copyright (c) 2019 by Simo Sorce <simo@redhat.com>
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/crypto.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/misc.h"
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/pki.h"
|
||||
#include "libssh/bignum.h"
|
||||
|
||||
extern bignum ssh_dh_generator;
|
||||
extern bignum ssh_dh_group1;
|
||||
extern bignum ssh_dh_group14;
|
||||
extern bignum ssh_dh_group16;
|
||||
extern bignum ssh_dh_group18;
|
||||
|
||||
/*
|
||||
* How many bits of security we want for fast DH. DH private key size must be
|
||||
* twice that size.
|
||||
*/
|
||||
#define DH_SECURITY_BITS 512
|
||||
|
||||
struct dh_keypair {
|
||||
bignum priv_key;
|
||||
bignum pub_key;
|
||||
};
|
||||
|
||||
struct dh_ctx {
|
||||
/* 0 is client, 1 is server */
|
||||
struct dh_keypair keypair[2];
|
||||
bignum generator;
|
||||
bignum modulus;
|
||||
};
|
||||
|
||||
void ssh_dh_debug_crypto(struct ssh_crypto_struct *c)
|
||||
{
|
||||
#ifdef DEBUG_CRYPTO
|
||||
const_bignum x = NULL, y = NULL, e = NULL, f = NULL;
|
||||
|
||||
ssh_dh_keypair_get_keys(c->dh_ctx, DH_CLIENT_KEYPAIR, &x, &e);
|
||||
ssh_dh_keypair_get_keys(c->dh_ctx, DH_SERVER_KEYPAIR, &y, &f);
|
||||
ssh_print_bignum("p", c->dh_ctx->modulus);
|
||||
ssh_print_bignum("g", c->dh_ctx->generator);
|
||||
ssh_print_bignum("x", x);
|
||||
ssh_print_bignum("y", y);
|
||||
ssh_print_bignum("e", e);
|
||||
ssh_print_bignum("f", f);
|
||||
|
||||
ssh_log_hexdump("Session server cookie", c->server_kex.cookie, 16);
|
||||
ssh_log_hexdump("Session client cookie", c->client_kex.cookie, 16);
|
||||
ssh_print_bignum("k", c->shared_secret);
|
||||
#else
|
||||
(void)c; /* UNUSED_PARAM */
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ssh_dh_free_modulus(struct dh_ctx *ctx)
|
||||
{
|
||||
if ((ctx->modulus != ssh_dh_group1) &&
|
||||
(ctx->modulus != ssh_dh_group14) &&
|
||||
(ctx->modulus != ssh_dh_group16) &&
|
||||
(ctx->modulus != ssh_dh_group18)) {
|
||||
bignum_safe_free(ctx->modulus);
|
||||
}
|
||||
ctx->modulus = NULL;
|
||||
}
|
||||
|
||||
static void ssh_dh_free_generator(struct dh_ctx *ctx)
|
||||
{
|
||||
if (ctx->generator != ssh_dh_generator) {
|
||||
bignum_safe_free(ctx->generator);
|
||||
}
|
||||
}
|
||||
|
||||
static void ssh_dh_free_dh_keypair(struct dh_keypair *keypair)
|
||||
{
|
||||
bignum_safe_free(keypair->priv_key);
|
||||
bignum_safe_free(keypair->pub_key);
|
||||
}
|
||||
|
||||
static int ssh_dh_init_dh_keypair(struct dh_keypair *keypair)
|
||||
{
|
||||
int rc;
|
||||
|
||||
keypair->priv_key = bignum_new();
|
||||
if (keypair->priv_key == NULL) {
|
||||
rc = SSH_ERROR;
|
||||
goto done;
|
||||
}
|
||||
keypair->pub_key = bignum_new();
|
||||
if (keypair->pub_key == NULL) {
|
||||
rc = SSH_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
rc = SSH_OK;
|
||||
done:
|
||||
if (rc != SSH_OK) {
|
||||
ssh_dh_free_dh_keypair(keypair);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ssh_dh_keypair_get_keys(struct dh_ctx *ctx, int peer,
|
||||
const_bignum *priv, const_bignum *pub)
|
||||
{
|
||||
if (((peer != DH_CLIENT_KEYPAIR) && (peer != DH_SERVER_KEYPAIR)) ||
|
||||
((priv == NULL) && (pub == NULL)) || (ctx == NULL)) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (priv) {
|
||||
/* check that we have something in it */
|
||||
if (bignum_num_bits(ctx->keypair[peer].priv_key)) {
|
||||
*priv = ctx->keypair[peer].priv_key;
|
||||
} else {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (pub) {
|
||||
/* check that we have something in it */
|
||||
if (bignum_num_bits(ctx->keypair[peer].pub_key)) {
|
||||
*pub = ctx->keypair[peer].pub_key;
|
||||
} else {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int ssh_dh_keypair_set_keys(struct dh_ctx *ctx, int peer,
|
||||
bignum priv, bignum pub)
|
||||
{
|
||||
if (((peer != DH_CLIENT_KEYPAIR) && (peer != DH_SERVER_KEYPAIR)) ||
|
||||
((priv == NULL) && (pub == NULL)) || (ctx == NULL)) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (priv) {
|
||||
bignum_safe_free(ctx->keypair[peer].priv_key);
|
||||
ctx->keypair[peer].priv_key = priv;
|
||||
}
|
||||
if (pub) {
|
||||
bignum_safe_free(ctx->keypair[peer].pub_key);
|
||||
ctx->keypair[peer].pub_key = pub;
|
||||
}
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int ssh_dh_get_parameters(struct dh_ctx *ctx,
|
||||
const_bignum *modulus, const_bignum *generator)
|
||||
{
|
||||
if (ctx == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (modulus) {
|
||||
*modulus = ctx->modulus;
|
||||
}
|
||||
if (generator) {
|
||||
*generator = ctx->generator;
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int ssh_dh_set_parameters(struct dh_ctx *ctx,
|
||||
bignum modulus, bignum generator)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if ((ctx == NULL) || ((modulus == NULL) && (generator == NULL))) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
/* when setting modulus or generator,
|
||||
* make sure to invalidate existing keys */
|
||||
ssh_dh_free_dh_keypair(&ctx->keypair[DH_CLIENT_KEYPAIR]);
|
||||
ssh_dh_free_dh_keypair(&ctx->keypair[DH_SERVER_KEYPAIR]);
|
||||
|
||||
rc = ssh_dh_init_dh_keypair(&ctx->keypair[DH_CLIENT_KEYPAIR]);
|
||||
if (rc != SSH_OK) {
|
||||
goto done;
|
||||
}
|
||||
rc = ssh_dh_init_dh_keypair(&ctx->keypair[DH_SERVER_KEYPAIR]);
|
||||
if (rc != SSH_OK) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (modulus) {
|
||||
ssh_dh_free_modulus(ctx);
|
||||
ctx->modulus = modulus;
|
||||
}
|
||||
if (generator) {
|
||||
ssh_dh_free_generator(ctx);
|
||||
ctx->generator = generator;
|
||||
}
|
||||
|
||||
done:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief allocate and initialize ephemeral values used in dh kex
|
||||
*/
|
||||
int ssh_dh_init_common(struct ssh_crypto_struct *crypto)
|
||||
{
|
||||
struct dh_ctx *ctx = NULL;
|
||||
int rc;
|
||||
|
||||
ctx = calloc(1, sizeof(*ctx));
|
||||
if (ctx == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
switch (crypto->kex_type) {
|
||||
case SSH_KEX_DH_GROUP1_SHA1:
|
||||
rc = ssh_dh_set_parameters(ctx, ssh_dh_group1, ssh_dh_generator);
|
||||
break;
|
||||
case SSH_KEX_DH_GROUP14_SHA1:
|
||||
rc = ssh_dh_set_parameters(ctx, ssh_dh_group14, ssh_dh_generator);
|
||||
break;
|
||||
case SSH_KEX_DH_GROUP16_SHA512:
|
||||
rc = ssh_dh_set_parameters(ctx, ssh_dh_group16, ssh_dh_generator);
|
||||
break;
|
||||
case SSH_KEX_DH_GROUP18_SHA512:
|
||||
rc = ssh_dh_set_parameters(ctx, ssh_dh_group18, ssh_dh_generator);
|
||||
break;
|
||||
default:
|
||||
rc = SSH_OK;
|
||||
break;
|
||||
}
|
||||
|
||||
crypto->dh_ctx = ctx;
|
||||
|
||||
if (rc != SSH_OK) {
|
||||
ssh_dh_cleanup(crypto);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void ssh_dh_cleanup(struct ssh_crypto_struct *crypto)
|
||||
{
|
||||
struct dh_ctx *ctx = crypto->dh_ctx;
|
||||
|
||||
if (ctx == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ssh_dh_free_dh_keypair(&ctx->keypair[DH_CLIENT_KEYPAIR]);
|
||||
ssh_dh_free_dh_keypair(&ctx->keypair[DH_SERVER_KEYPAIR]);
|
||||
|
||||
ssh_dh_free_modulus(ctx);
|
||||
ssh_dh_free_generator(ctx);
|
||||
free(ctx);
|
||||
crypto->dh_ctx = NULL;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief generates a secret DH parameter of at least DH_SECURITY_BITS
|
||||
* security as well as the corresponding public key.
|
||||
* @param[out] parms a dh_kex paramters structure with preallocated bignum
|
||||
* where to store the parameters
|
||||
* @return SSH_OK on success, SSH_ERROR on error
|
||||
*/
|
||||
int ssh_dh_keypair_gen_keys(struct dh_ctx *dh_ctx, int peer)
|
||||
{
|
||||
bignum tmp = NULL;
|
||||
bignum_CTX ctx = NULL;
|
||||
int rc = 0;
|
||||
int bits = 0;
|
||||
int p_bits = 0;
|
||||
|
||||
ctx = bignum_ctx_new();
|
||||
if (bignum_ctx_invalid(ctx)){
|
||||
goto error;
|
||||
}
|
||||
tmp = bignum_new();
|
||||
if (tmp == NULL) {
|
||||
goto error;
|
||||
}
|
||||
p_bits = bignum_num_bits(dh_ctx->modulus);
|
||||
/* we need at most DH_SECURITY_BITS */
|
||||
bits = MIN(DH_SECURITY_BITS * 2, p_bits);
|
||||
/* ensure we're not too close of p so rnd()%p stays uniform */
|
||||
if (bits <= p_bits && bits + 64 > p_bits) {
|
||||
bits += 64;
|
||||
}
|
||||
rc = bignum_rand(tmp, bits);
|
||||
if (rc != 1) {
|
||||
goto error;
|
||||
}
|
||||
rc = bignum_mod(dh_ctx->keypair[peer].priv_key, tmp, dh_ctx->modulus, ctx);
|
||||
if (rc != 1) {
|
||||
goto error;
|
||||
}
|
||||
/* Now compute the corresponding public key */
|
||||
rc = bignum_mod_exp(dh_ctx->keypair[peer].pub_key, dh_ctx->generator,
|
||||
dh_ctx->keypair[peer].priv_key, dh_ctx->modulus, ctx);
|
||||
if (rc != 1) {
|
||||
goto error;
|
||||
}
|
||||
bignum_safe_free(tmp);
|
||||
bignum_ctx_free(ctx);
|
||||
return SSH_OK;
|
||||
error:
|
||||
bignum_safe_free(tmp);
|
||||
bignum_ctx_free(ctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief generates a shared secret between the local peer and the remote peer
|
||||
* @param[in] local peer identifier
|
||||
* @param[in] remote peer identifier
|
||||
* @param[out] dest a preallocated bignum where to store parameter
|
||||
* @return SSH_OK on success, SSH_ERROR on error
|
||||
*/
|
||||
int ssh_dh_compute_shared_secret(struct dh_ctx *dh_ctx, int local, int remote,
|
||||
bignum *dest)
|
||||
{
|
||||
int rc;
|
||||
bignum_CTX ctx = bignum_ctx_new();
|
||||
if (bignum_ctx_invalid(ctx)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*dest == NULL) {
|
||||
*dest = bignum_new();
|
||||
if (*dest == NULL) {
|
||||
rc = 0;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
rc = bignum_mod_exp(*dest, dh_ctx->keypair[remote].pub_key,
|
||||
dh_ctx->keypair[local].priv_key,
|
||||
dh_ctx->modulus, ctx);
|
||||
|
||||
done:
|
||||
bignum_ctx_free(ctx);
|
||||
if (rc != 1) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
return SSH_OK;
|
||||
}
|
||||
51
src/ecdh.c
51
src/ecdh.c
@@ -30,32 +30,16 @@
|
||||
|
||||
#ifdef HAVE_ECDH
|
||||
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_client_ecdh_reply);
|
||||
|
||||
static ssh_packet_callback ecdh_client_callbacks[]= {
|
||||
ssh_packet_client_ecdh_reply
|
||||
};
|
||||
|
||||
struct ssh_packet_callbacks_struct ssh_ecdh_client_callbacks = {
|
||||
.start = SSH2_MSG_KEX_ECDH_REPLY,
|
||||
.n_callbacks = 1,
|
||||
.callbacks = ecdh_client_callbacks,
|
||||
.user = NULL
|
||||
};
|
||||
|
||||
/** @internal
|
||||
* @brief parses a SSH_MSG_KEX_ECDH_REPLY packet and sends back
|
||||
* a SSH_MSG_NEWKEYS
|
||||
*/
|
||||
SSH_PACKET_CALLBACK(ssh_packet_client_ecdh_reply){
|
||||
int ssh_client_ecdh_reply(ssh_session session, ssh_buffer packet){
|
||||
ssh_string q_s_string = NULL;
|
||||
ssh_string pubkey_blob = NULL;
|
||||
ssh_string signature = NULL;
|
||||
int rc;
|
||||
(void)type;
|
||||
(void)user;
|
||||
|
||||
ssh_packet_remove_callbacks(session, &ssh_ecdh_client_callbacks);
|
||||
pubkey_blob = ssh_buffer_get_ssh_string(packet);
|
||||
if (pubkey_blob == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL, "No public key in packet");
|
||||
@@ -93,39 +77,10 @@ SSH_PACKET_CALLBACK(ssh_packet_client_ecdh_reply){
|
||||
}
|
||||
|
||||
rc=ssh_packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
||||
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
|
||||
return rc;
|
||||
error:
|
||||
session->session_state=SSH_SESSION_STATE_ERROR;
|
||||
return SSH_PACKET_USED;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
|
||||
static ssh_packet_callback ecdh_server_callbacks[] = {
|
||||
ssh_packet_server_ecdh_init
|
||||
};
|
||||
|
||||
struct ssh_packet_callbacks_struct ssh_ecdh_server_callbacks = {
|
||||
.start = SSH2_MSG_KEX_ECDH_INIT,
|
||||
.n_callbacks = 1,
|
||||
.callbacks = ecdh_server_callbacks,
|
||||
.user = NULL
|
||||
};
|
||||
|
||||
/** @internal
|
||||
* @brief sets up the ecdh kex callbacks
|
||||
*/
|
||||
void ssh_server_ecdh_init(ssh_session session){
|
||||
ssh_packet_set_callbacks(session, &ssh_ecdh_server_callbacks);
|
||||
}
|
||||
|
||||
#endif /* WITH_SERVER */
|
||||
#endif /* HAVE_ECDH */
|
||||
|
||||
@@ -108,10 +108,6 @@ int ssh_client_ecdh_init(ssh_session session){
|
||||
session->next_crypto->ecdh_privkey = key;
|
||||
session->next_crypto->ecdh_client_pubkey = client_pubkey;
|
||||
|
||||
/* register the packet callbacks */
|
||||
ssh_packet_set_callbacks(session, &ssh_ecdh_client_callbacks);
|
||||
session->dh_handshake_state = DH_STATE_INIT_SENT;
|
||||
|
||||
rc = ssh_packet_send(session);
|
||||
|
||||
return rc;
|
||||
@@ -128,6 +124,12 @@ int ecdh_build_k(ssh_session session) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
session->next_crypto->k = bignum_new();
|
||||
if (session->next_crypto->k == NULL) {
|
||||
bignum_ctx_free(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pubkey = EC_POINT_new(group);
|
||||
if (pubkey == NULL) {
|
||||
bignum_ctx_free(ctx);
|
||||
@@ -170,22 +172,18 @@ int ecdh_build_k(ssh_session session) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bignum_bin2bn(buffer, len, &session->next_crypto->shared_secret);
|
||||
bignum_bin2bn(buffer, len, session->next_crypto->k);
|
||||
free(buffer);
|
||||
if (session->next_crypto->shared_secret == NULL) {
|
||||
EC_KEY_free(session->next_crypto->ecdh_privkey);
|
||||
session->next_crypto->ecdh_privkey = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
EC_KEY_free(session->next_crypto->ecdh_privkey);
|
||||
session->next_crypto->ecdh_privkey = NULL;
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_log_hexdump("Session server cookie",
|
||||
ssh_print_hexa("Session server cookie",
|
||||
session->next_crypto->server_kex.cookie, 16);
|
||||
ssh_log_hexdump("Session client cookie",
|
||||
ssh_print_hexa("Session client cookie",
|
||||
session->next_crypto->client_kex.cookie, 16);
|
||||
ssh_print_bignum("Shared secret key", session->next_crypto->shared_secret);
|
||||
ssh_print_bignum("Shared secret key", session->next_crypto->k);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
@@ -193,10 +191,11 @@ int ecdh_build_k(ssh_session session) {
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
|
||||
/** @brief Handle a SSH_MSG_KEXDH_INIT packet (server) and send a
|
||||
/** @brief Parse a SSH_MSG_KEXDH_INIT packet (server) and send a
|
||||
* SSH_MSG_KEXDH_REPLY
|
||||
*/
|
||||
SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
|
||||
int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet){
|
||||
/* ECDH keys */
|
||||
ssh_string q_c_string;
|
||||
ssh_string q_s_string;
|
||||
@@ -206,21 +205,17 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
bignum_CTX ctx;
|
||||
/* SSH host keys (rsa,dsa,ecdsa) */
|
||||
ssh_key privkey;
|
||||
enum ssh_digest_e digest = SSH_DIGEST_AUTO;
|
||||
ssh_string sig_blob = NULL;
|
||||
ssh_string pubkey_blob = NULL;
|
||||
int curve;
|
||||
int len;
|
||||
int rc;
|
||||
(void)type;
|
||||
(void)user;
|
||||
|
||||
ssh_packet_remove_callbacks(session, &ssh_ecdh_server_callbacks);
|
||||
/* Extract the client pubkey from the init packet */
|
||||
q_c_string = ssh_buffer_get_ssh_string(packet);
|
||||
if (q_c_string == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL, "No Q_C ECC point in packet");
|
||||
goto error;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
session->next_crypto->ecdh_client_pubkey = q_c_string;
|
||||
|
||||
@@ -238,7 +233,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
if (ecdh_key == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
BN_CTX_free(ctx);
|
||||
goto error;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
group = EC_KEY_get0_group(ecdh_key);
|
||||
@@ -256,7 +251,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
if (q_s_string == NULL) {
|
||||
EC_KEY_free(ecdh_key);
|
||||
BN_CTX_free(ctx);
|
||||
goto error;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
EC_POINT_point2oct(group,
|
||||
@@ -274,25 +269,25 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
rc = ecdh_build_k(session);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
|
||||
goto error;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* privkey is not allocated */
|
||||
rc = ssh_get_key_params(session, &privkey, &digest);
|
||||
rc = ssh_get_key_params(session, &privkey);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = ssh_make_sessionid(session);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not create a session id");
|
||||
goto error;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey, digest);
|
||||
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
|
||||
if (sig_blob == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
|
||||
goto error;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = ssh_dh_get_next_server_publickey_blob(session, &pubkey_blob);
|
||||
@@ -314,33 +309,26 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEXDH_REPLY sent");
|
||||
rc = ssh_packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* Send the MSG_NEWKEYS */
|
||||
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS);
|
||||
if (rc < 0) {
|
||||
goto error;
|
||||
return SSH_ERROR;;
|
||||
}
|
||||
|
||||
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
|
||||
rc = ssh_packet_send(session);
|
||||
if (rc == SSH_ERROR){
|
||||
goto error;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
error:
|
||||
ssh_buffer_reinit(session->out_buffer);
|
||||
session->session_state = SSH_SESSION_STATE_ERROR;
|
||||
return SSH_PACKET_USED;
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
@@ -106,10 +106,6 @@ int ssh_client_ecdh_init(ssh_session session)
|
||||
session->next_crypto->ecdh_client_pubkey = client_pubkey;
|
||||
client_pubkey = NULL;
|
||||
|
||||
/* register the packet callbacks */
|
||||
ssh_packet_set_callbacks(session, &ssh_ecdh_client_callbacks);
|
||||
session->dh_handshake_state = DH_STATE_INIT_SENT;
|
||||
|
||||
rc = ssh_packet_send(session);
|
||||
|
||||
out:
|
||||
@@ -198,9 +194,8 @@ int ecdh_build_k(ssh_session session)
|
||||
goto out;
|
||||
}
|
||||
|
||||
session->next_crypto->shared_secret = gcry_mpi_new(0);
|
||||
gcry_mpi_point_snatch_get(session->next_crypto->shared_secret,
|
||||
NULL, NULL, point);
|
||||
session->next_crypto->k = gcry_mpi_new(0);
|
||||
gcry_mpi_point_snatch_get(session->next_crypto->k, NULL, NULL, point);
|
||||
#else
|
||||
s = ssh_sexp_extract_mpi(result, "s", GCRYMPI_FMT_USG, GCRYMPI_FMT_USG);
|
||||
if (s == NULL) {
|
||||
@@ -225,7 +220,7 @@ int ecdh_build_k(ssh_session session)
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = gcry_mpi_scan(&session->next_crypto->shared_secret,
|
||||
err = gcry_mpi_scan(&session->next_crypto->k,
|
||||
GCRYMPI_FMT_USG,
|
||||
(const char *)ssh_string_data(s) + 1,
|
||||
k_len / 2,
|
||||
@@ -242,11 +237,11 @@ int ecdh_build_k(ssh_session session)
|
||||
session->next_crypto->ecdh_privkey = NULL;
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_log_hexdump("Session server cookie",
|
||||
ssh_print_hexa("Session server cookie",
|
||||
session->next_crypto->server_kex.cookie, 16);
|
||||
ssh_log_hexdump("Session client cookie",
|
||||
ssh_print_hexa("Session client cookie",
|
||||
session->next_crypto->client_kex.cookie, 16);
|
||||
ssh_print_bignum("Shared secret key", session->next_crypto->shared_secret);
|
||||
ssh_print_bignum("Shared secret key", session->next_crypto->k);
|
||||
#endif
|
||||
|
||||
out:
|
||||
@@ -260,11 +255,10 @@ int ecdh_build_k(ssh_session session)
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
|
||||
|
||||
/** @brief Handle a SSH_MSG_KEXDH_INIT packet (server) and send a
|
||||
/** @brief Parse a SSH_MSG_KEXDH_INIT packet (server) and send a
|
||||
* SSH_MSG_KEXDH_REPLY
|
||||
*/
|
||||
SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet) {
|
||||
gpg_error_t err;
|
||||
/* ECDH keys */
|
||||
ssh_string q_c_string;
|
||||
@@ -273,15 +267,11 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
gcry_sexp_t key = NULL;
|
||||
/* SSH host keys (rsa,dsa,ecdsa) */
|
||||
ssh_key privkey;
|
||||
enum ssh_digest_e digest = SSH_DIGEST_AUTO;
|
||||
ssh_string sig_blob = NULL;
|
||||
ssh_string pubkey_blob = NULL;
|
||||
int rc = SSH_ERROR;
|
||||
const char *curve = NULL;
|
||||
(void)type;
|
||||
(void)user;
|
||||
|
||||
ssh_packet_remove_callbacks(session, &ssh_ecdh_server_callbacks);
|
||||
curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
|
||||
if (curve == NULL) {
|
||||
goto out;
|
||||
@@ -326,7 +316,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
}
|
||||
|
||||
/* privkey is not allocated */
|
||||
rc = ssh_get_key_params(session, &privkey, &digest);
|
||||
rc = ssh_get_key_params(session, &privkey);
|
||||
if (rc != SSH_OK) {
|
||||
goto out;
|
||||
}
|
||||
@@ -337,7 +327,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
goto out;
|
||||
}
|
||||
|
||||
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey, digest);
|
||||
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
|
||||
if (sig_blob == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
|
||||
rc = SSH_ERROR;
|
||||
@@ -386,11 +376,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
out:
|
||||
gcry_sexp_release(param);
|
||||
gcry_sexp_release(key);
|
||||
if (rc == SSH_ERROR) {
|
||||
ssh_buffer_reinit(session->out_buffer);
|
||||
session->session_state = SSH_SESSION_STATE_ERROR;
|
||||
}
|
||||
return SSH_PACKET_USED;
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
@@ -106,9 +106,6 @@ int ssh_client_ecdh_init(ssh_session session)
|
||||
session->next_crypto->ecdh_client_pubkey = client_pubkey;
|
||||
client_pubkey = NULL;
|
||||
|
||||
/* register the packet callbacks */
|
||||
ssh_packet_set_callbacks(session, &ssh_ecdh_client_callbacks);
|
||||
session->dh_handshake_state = DH_STATE_INIT_SENT;
|
||||
rc = ssh_packet_send(session);
|
||||
|
||||
out:
|
||||
@@ -154,16 +151,16 @@ int ecdh_build_k(ssh_session session)
|
||||
goto out;
|
||||
}
|
||||
|
||||
session->next_crypto->shared_secret = malloc(sizeof(mbedtls_mpi));
|
||||
if (session->next_crypto->shared_secret == NULL) {
|
||||
session->next_crypto->k = malloc(sizeof(mbedtls_mpi));
|
||||
if (session->next_crypto->k == NULL) {
|
||||
rc = SSH_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mbedtls_mpi_init(session->next_crypto->shared_secret);
|
||||
mbedtls_mpi_init(session->next_crypto->k);
|
||||
|
||||
rc = mbedtls_ecdh_compute_shared(&grp,
|
||||
session->next_crypto->shared_secret,
|
||||
session->next_crypto->k,
|
||||
&pubkey,
|
||||
&session->next_crypto->ecdh_privkey->d,
|
||||
mbedtls_ctr_drbg_random,
|
||||
@@ -182,21 +179,17 @@ out:
|
||||
}
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
|
||||
SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet)
|
||||
{
|
||||
ssh_string q_c_string = NULL;
|
||||
ssh_string q_s_string = NULL;
|
||||
mbedtls_ecp_group grp;
|
||||
ssh_key privkey = NULL;
|
||||
enum ssh_digest_e digest = SSH_DIGEST_AUTO;
|
||||
ssh_string sig_blob = NULL;
|
||||
ssh_string pubkey_blob = NULL;
|
||||
int rc;
|
||||
mbedtls_ecp_group_id curve;
|
||||
(void)type;
|
||||
(void)user;
|
||||
|
||||
ssh_packet_remove_callbacks(session, &ssh_ecdh_server_callbacks);
|
||||
curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
|
||||
if (curve == MBEDTLS_ECP_DP_NONE) {
|
||||
return SSH_ERROR;
|
||||
@@ -251,7 +244,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
}
|
||||
|
||||
/* privkey is not allocated */
|
||||
rc = ssh_get_key_params(session, &privkey, &digest);
|
||||
rc = ssh_get_key_params(session, &privkey);
|
||||
if (rc == SSH_ERROR) {
|
||||
rc = SSH_ERROR;
|
||||
goto out;
|
||||
@@ -264,7 +257,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
goto out;
|
||||
}
|
||||
|
||||
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey, digest);
|
||||
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
|
||||
if (sig_blob == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
|
||||
rc = SSH_ERROR;
|
||||
@@ -312,11 +305,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
|
||||
out:
|
||||
mbedtls_ecp_group_free(&grp);
|
||||
if (rc == SSH_ERROR) {
|
||||
ssh_buffer_reinit(session->out_buffer);
|
||||
session->session_state = SSH_SESSION_STATE_ERROR;
|
||||
}
|
||||
return SSH_PACKET_USED;
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
16
src/external/ed25519.c
vendored
16
src/external/ed25519.c
vendored
@@ -63,9 +63,9 @@ static void get_hram(unsigned char *hram,
|
||||
const unsigned char *sm,
|
||||
const unsigned char *pk,
|
||||
unsigned char *playground,
|
||||
uint64_t smlen)
|
||||
unsigned long long smlen)
|
||||
{
|
||||
uint64_t i;
|
||||
unsigned long long i;
|
||||
SHA512CTX ctx;
|
||||
for (i = 0;i < 32;++i) playground[i] = sm[i];
|
||||
for (i = 32;i < 64;++i) playground[i] = pk[i-32];
|
||||
@@ -111,9 +111,9 @@ int crypto_sign_ed25519_keypair(unsigned char *pk,
|
||||
}
|
||||
|
||||
int crypto_sign_ed25519(unsigned char *sm,
|
||||
uint64_t *smlen,
|
||||
unsigned long long *smlen,
|
||||
const unsigned char *m,
|
||||
uint64_t mlen,
|
||||
unsigned long long mlen,
|
||||
const unsigned char *sk)
|
||||
{
|
||||
sc25519 sck, scs, scsk;
|
||||
@@ -122,7 +122,7 @@ int crypto_sign_ed25519(unsigned char *sm,
|
||||
unsigned char r[32];
|
||||
unsigned char s[32];
|
||||
unsigned char extsk[64];
|
||||
uint64_t i;
|
||||
unsigned long long i;
|
||||
unsigned char hmg[SHA512_DIGEST_LEN];
|
||||
unsigned char hram[SHA512_DIGEST_LEN];
|
||||
|
||||
@@ -174,9 +174,9 @@ int crypto_sign_ed25519(unsigned char *sm,
|
||||
}
|
||||
|
||||
int crypto_sign_ed25519_open(unsigned char *m,
|
||||
uint64_t *mlen,
|
||||
unsigned long long *mlen,
|
||||
const unsigned char *sm,
|
||||
uint64_t smlen,
|
||||
unsigned long long smlen,
|
||||
const unsigned char *pk)
|
||||
{
|
||||
unsigned int i;
|
||||
@@ -186,7 +186,7 @@ int crypto_sign_ed25519_open(unsigned char *m,
|
||||
sc25519 schram, scs;
|
||||
unsigned char hram[SHA512_DIGEST_LEN];
|
||||
|
||||
*mlen = (uint64_t) -1;
|
||||
*mlen = (unsigned long long) -1;
|
||||
if (smlen < 64) return -1;
|
||||
|
||||
if (ge25519_unpackneg_vartime(&get1, pk)) {
|
||||
|
||||
@@ -99,26 +99,4 @@ char *ssh_gcry_bn2dec(bignum bn) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief generates a random integer between 0 and max
|
||||
* @returns 1 in case of success, 0 otherwise
|
||||
*/
|
||||
int ssh_gcry_rand_range(bignum dest, bignum max)
|
||||
{
|
||||
size_t bits;
|
||||
bignum rnd;
|
||||
int rc;
|
||||
|
||||
bits = bignum_num_bits(max) + 64;
|
||||
rnd = bignum_new();
|
||||
if (rnd == NULL) {
|
||||
return 0;
|
||||
}
|
||||
rc = bignum_rand(rnd, bits);
|
||||
if (rc != 1) {
|
||||
return rc;
|
||||
}
|
||||
gcry_mpi_mod(dest, rnd, max);
|
||||
bignum_safe_free(rnd);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
20
src/gssapi.c
20
src/gssapi.c
@@ -328,10 +328,7 @@ static char *ssh_gssapi_name_to_char(gss_name_t name){
|
||||
"converting name",
|
||||
maj_stat,
|
||||
min_stat);
|
||||
ptr = malloc(buffer.length + 1);
|
||||
if (ptr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ptr=malloc(buffer.length + 1);
|
||||
memcpy(ptr, buffer.value, buffer.length);
|
||||
ptr[buffer.length] = '\0';
|
||||
gss_release_buffer(&min_stat, &buffer);
|
||||
@@ -438,10 +435,8 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server){
|
||||
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
static ssh_buffer ssh_gssapi_build_mic(ssh_session session)
|
||||
{
|
||||
struct ssh_crypto_struct *crypto = NULL;
|
||||
ssh_buffer mic_buffer = NULL;
|
||||
static ssh_buffer ssh_gssapi_build_mic(ssh_session session){
|
||||
ssh_buffer mic_buffer;
|
||||
int rc;
|
||||
|
||||
mic_buffer = ssh_buffer_new();
|
||||
@@ -450,11 +445,10 @@ static ssh_buffer ssh_gssapi_build_mic(ssh_session session)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_BOTH);
|
||||
rc = ssh_buffer_pack(mic_buffer,
|
||||
"dPbsss",
|
||||
crypto->digest_len,
|
||||
(size_t)crypto->digest_len, crypto->session_id,
|
||||
session->current_crypto->digest_len,
|
||||
(size_t)session->current_crypto->digest_len, session->current_crypto->session_id,
|
||||
SSH2_MSG_USERAUTH_REQUEST,
|
||||
session->gssapi->user,
|
||||
"ssh-connection",
|
||||
@@ -797,10 +791,6 @@ static gss_OID ssh_gssapi_oid_from_string(ssh_string oid_s){
|
||||
return NULL;
|
||||
}
|
||||
ret->elements = malloc(len - 2);
|
||||
if (ret->elements == NULL) {
|
||||
SAFE_FREE(ret);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(ret->elements, &data[2], len-2);
|
||||
ret->length = len-2;
|
||||
|
||||
|
||||
25
src/gzip.c
25
src/gzip.c
@@ -55,10 +55,8 @@ static z_stream *initcompress(ssh_session session, int level) {
|
||||
return stream;
|
||||
}
|
||||
|
||||
static ssh_buffer gzip_compress(ssh_session session, ssh_buffer source, int level)
|
||||
{
|
||||
struct ssh_crypto_struct *crypto = NULL;
|
||||
z_stream *zout = NULL;
|
||||
static ssh_buffer gzip_compress(ssh_session session,ssh_buffer source,int level){
|
||||
z_stream *zout = session->current_crypto->compress_out_ctx;
|
||||
void *in_ptr = ssh_buffer_get(source);
|
||||
unsigned long in_size = ssh_buffer_get_len(source);
|
||||
ssh_buffer dest = NULL;
|
||||
@@ -66,13 +64,8 @@ static ssh_buffer gzip_compress(ssh_session session, ssh_buffer source, int leve
|
||||
unsigned long len;
|
||||
int status;
|
||||
|
||||
crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_OUT);
|
||||
if (crypto == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
zout = crypto->compress_out_ctx;
|
||||
if (zout == NULL) {
|
||||
zout = crypto->compress_out_ctx = initcompress(session, level);
|
||||
if(zout == NULL) {
|
||||
zout = session->current_crypto->compress_out_ctx = initcompress(session, level);
|
||||
if (zout == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -150,10 +143,8 @@ static z_stream *initdecompress(ssh_session session) {
|
||||
return stream;
|
||||
}
|
||||
|
||||
static ssh_buffer gzip_decompress(ssh_session session, ssh_buffer source, size_t maxlen)
|
||||
{
|
||||
struct ssh_crypto_struct *crypto = NULL;
|
||||
z_stream *zin = NULL;
|
||||
static ssh_buffer gzip_decompress(ssh_session session, ssh_buffer source, size_t maxlen) {
|
||||
z_stream *zin = session->current_crypto->compress_in_ctx;
|
||||
void *in_ptr = ssh_buffer_get(source);
|
||||
unsigned long in_size = ssh_buffer_get_len(source);
|
||||
unsigned char out_buf[BLOCKSIZE] = {0};
|
||||
@@ -161,10 +152,8 @@ static ssh_buffer gzip_decompress(ssh_session session, ssh_buffer source, size_t
|
||||
unsigned long len;
|
||||
int status;
|
||||
|
||||
crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_IN);
|
||||
zin = crypto->compress_in_ctx;
|
||||
if (zin == NULL) {
|
||||
zin = crypto->compress_in_ctx = initdecompress(session);
|
||||
zin = session->current_crypto->compress_in_ctx = initdecompress(session);
|
||||
if (zin == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
167
src/kdf.c
167
src/kdf.c
@@ -1,167 +0,0 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009 by Aris Adamantiadis
|
||||
* Copyrihgt (c) 2018 Red Hat, Inc.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/crypto.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/misc.h"
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/pki.h"
|
||||
#include "libssh/bignum.h"
|
||||
|
||||
#include "libssh/string.h"
|
||||
|
||||
|
||||
/* The following implements the SSHKDF for crypto backend that
|
||||
* do not have a native implementations */
|
||||
struct ssh_mac_ctx_struct {
|
||||
enum ssh_kdf_digest digest_type;
|
||||
union {
|
||||
SHACTX sha1_ctx;
|
||||
SHA256CTX sha256_ctx;
|
||||
SHA384CTX sha384_ctx;
|
||||
SHA512CTX sha512_ctx;
|
||||
} ctx;
|
||||
};
|
||||
|
||||
static ssh_mac_ctx ssh_mac_ctx_init(enum ssh_kdf_digest type)
|
||||
{
|
||||
ssh_mac_ctx ctx = malloc(sizeof(struct ssh_mac_ctx_struct));
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->digest_type = type;
|
||||
switch(type){
|
||||
case SSH_KDF_SHA1:
|
||||
ctx->ctx.sha1_ctx = sha1_init();
|
||||
return ctx;
|
||||
case SSH_KDF_SHA256:
|
||||
ctx->ctx.sha256_ctx = sha256_init();
|
||||
return ctx;
|
||||
case SSH_KDF_SHA384:
|
||||
ctx->ctx.sha384_ctx = sha384_init();
|
||||
return ctx;
|
||||
case SSH_KDF_SHA512:
|
||||
ctx->ctx.sha512_ctx = sha512_init();
|
||||
return ctx;
|
||||
default:
|
||||
SAFE_FREE(ctx);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void ssh_mac_update(ssh_mac_ctx ctx, const void *data, size_t len)
|
||||
{
|
||||
switch(ctx->digest_type){
|
||||
case SSH_KDF_SHA1:
|
||||
sha1_update(ctx->ctx.sha1_ctx, data, len);
|
||||
break;
|
||||
case SSH_KDF_SHA256:
|
||||
sha256_update(ctx->ctx.sha256_ctx, data, len);
|
||||
break;
|
||||
case SSH_KDF_SHA384:
|
||||
sha384_update(ctx->ctx.sha384_ctx, data, len);
|
||||
break;
|
||||
case SSH_KDF_SHA512:
|
||||
sha512_update(ctx->ctx.sha512_ctx, data, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx)
|
||||
{
|
||||
switch(ctx->digest_type){
|
||||
case SSH_KDF_SHA1:
|
||||
sha1_final(md,ctx->ctx.sha1_ctx);
|
||||
break;
|
||||
case SSH_KDF_SHA256:
|
||||
sha256_final(md,ctx->ctx.sha256_ctx);
|
||||
break;
|
||||
case SSH_KDF_SHA384:
|
||||
sha384_final(md,ctx->ctx.sha384_ctx);
|
||||
break;
|
||||
case SSH_KDF_SHA512:
|
||||
sha512_final(md,ctx->ctx.sha512_ctx);
|
||||
break;
|
||||
}
|
||||
SAFE_FREE(ctx);
|
||||
}
|
||||
|
||||
int sshkdf_derive_key(struct ssh_crypto_struct *crypto,
|
||||
unsigned char *key, size_t key_len,
|
||||
int key_type, unsigned char *output,
|
||||
size_t requested_len)
|
||||
{
|
||||
/* Can't use VLAs with Visual Studio, so allocate the biggest
|
||||
* digest buffer we can possibly need */
|
||||
unsigned char digest[DIGEST_MAX_LEN];
|
||||
size_t output_len = crypto->digest_len;
|
||||
char letter = key_type;
|
||||
ssh_mac_ctx ctx;
|
||||
|
||||
if (DIGEST_MAX_LEN < crypto->digest_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx = ssh_mac_ctx_init(crypto->digest_type);
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssh_mac_update(ctx, key, key_len);
|
||||
ssh_mac_update(ctx, crypto->secret_hash, crypto->digest_len);
|
||||
ssh_mac_update(ctx, &letter, 1);
|
||||
ssh_mac_update(ctx, crypto->session_id, crypto->digest_len);
|
||||
ssh_mac_final(digest, ctx);
|
||||
|
||||
if (requested_len < output_len) {
|
||||
output_len = requested_len;
|
||||
}
|
||||
memcpy(output, digest, output_len);
|
||||
|
||||
while (requested_len > output_len) {
|
||||
ctx = ssh_mac_ctx_init(crypto->digest_type);
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
ssh_mac_update(ctx, key, key_len);
|
||||
ssh_mac_update(ctx, crypto->secret_hash, crypto->digest_len);
|
||||
ssh_mac_update(ctx, output, output_len);
|
||||
ssh_mac_final(digest, ctx);
|
||||
if (requested_len < output_len + crypto->digest_len) {
|
||||
memcpy(output + output_len, digest, requested_len - output_len);
|
||||
} else {
|
||||
memcpy(output + output_len, digest, crypto->digest_len);
|
||||
}
|
||||
output_len += crypto->digest_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -38,7 +38,15 @@
|
||||
#include "libssh/knownhosts.h"
|
||||
/*todo: remove this include */
|
||||
#include "libssh/string.h"
|
||||
#include "libssh/token.h"
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
#include <gcrypt.h>
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rsa.h>
|
||||
#endif /* HAVE_LIBCRYPTO */
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <netinet/in.h>
|
||||
@@ -51,6 +59,23 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Free a token array.
|
||||
*/
|
||||
static void tokens_free(char **tokens) {
|
||||
if (tokens == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
SAFE_FREE(tokens[0]);
|
||||
/* It's not needed to free other pointers because tokens generated by
|
||||
* space_tokenize fit all in one malloc
|
||||
*/
|
||||
SAFE_FREE(tokens);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
@@ -70,63 +95,58 @@
|
||||
* free that value. NULL if no match was found or the file
|
||||
* was not found.
|
||||
*/
|
||||
static struct ssh_tokens_st *ssh_get_knownhost_line(FILE **file,
|
||||
const char *filename,
|
||||
const char **found_type)
|
||||
{
|
||||
char buffer[4096] = {0};
|
||||
char *ptr;
|
||||
struct ssh_tokens_st *tokens;
|
||||
static char **ssh_get_knownhost_line(FILE **file, const char *filename,
|
||||
const char **found_type) {
|
||||
char buffer[4096] = {0};
|
||||
char *ptr;
|
||||
char **tokens;
|
||||
|
||||
if(*file == NULL){
|
||||
*file = fopen(filename,"r");
|
||||
if (*file == NULL) {
|
||||
*file = fopen(filename,"r");
|
||||
if (*file == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), *file)) {
|
||||
ptr = strchr(buffer, '\n');
|
||||
if (ptr) {
|
||||
*ptr = '\0';
|
||||
}
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), *file)) {
|
||||
ptr = strchr(buffer, '\n');
|
||||
if (ptr) {
|
||||
*ptr = '\0';
|
||||
}
|
||||
|
||||
ptr = strchr(buffer,'\r');
|
||||
if (ptr) {
|
||||
*ptr = '\0';
|
||||
}
|
||||
|
||||
if (buffer[0] == '\0' || buffer[0] == '#') {
|
||||
continue; /* skip empty lines */
|
||||
}
|
||||
|
||||
tokens = ssh_tokenize(buffer, ' ');
|
||||
if (tokens == NULL) {
|
||||
fclose(*file);
|
||||
*file = NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (tokens->tokens[0] == NULL ||
|
||||
tokens->tokens[1] == NULL ||
|
||||
tokens->tokens[2] == NULL)
|
||||
{
|
||||
/* it should have at least 3 tokens */
|
||||
ssh_tokens_free(tokens);
|
||||
continue;
|
||||
}
|
||||
|
||||
*found_type = tokens->tokens[1];
|
||||
|
||||
return tokens;
|
||||
ptr = strchr(buffer,'\r');
|
||||
if (ptr) {
|
||||
*ptr = '\0';
|
||||
}
|
||||
|
||||
fclose(*file);
|
||||
*file = NULL;
|
||||
if (buffer[0] == '\0' || buffer[0] == '#') {
|
||||
continue; /* skip empty lines */
|
||||
}
|
||||
|
||||
/* we did not find anything, end of file*/
|
||||
return NULL;
|
||||
tokens = ssh_space_tokenize(buffer);
|
||||
if (tokens == NULL) {
|
||||
fclose(*file);
|
||||
*file = NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(tokens[0] == NULL || tokens[1] == NULL || tokens[2] == NULL) {
|
||||
/* it should have at least 3 tokens */
|
||||
tokens_free(tokens);
|
||||
continue;
|
||||
}
|
||||
|
||||
*found_type = tokens[1];
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
fclose(*file);
|
||||
*file = NULL;
|
||||
|
||||
/* we did not find anything, end of file*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -280,147 +300,143 @@ static int match_hashed_host(const char *host, const char *sourcehash)
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief This function is deprecated
|
||||
* @brief This function is depcrecated
|
||||
*
|
||||
* @deprecated Please use ssh_session_is_known_server()
|
||||
* @see ssh_session_is_known_server()
|
||||
*/
|
||||
int ssh_is_server_known(ssh_session session)
|
||||
{
|
||||
FILE *file = NULL;
|
||||
char *host;
|
||||
char *hostport;
|
||||
const char *type;
|
||||
int match;
|
||||
int i = 0;
|
||||
char *files[3];
|
||||
int ssh_is_server_known(ssh_session session) {
|
||||
FILE *file = NULL;
|
||||
char **tokens;
|
||||
char *host;
|
||||
char *hostport;
|
||||
const char *type;
|
||||
int match;
|
||||
int i=0;
|
||||
char * files[3];
|
||||
int ret = SSH_SERVER_NOT_KNOWN;
|
||||
|
||||
struct ssh_tokens_st *tokens;
|
||||
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");
|
||||
|
||||
int ret = SSH_SERVER_NOT_KNOWN;
|
||||
|
||||
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");
|
||||
|
||||
return SSH_SERVER_FILE_NOT_FOUND;
|
||||
}
|
||||
return SSH_SERVER_FILE_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
if (session->opts.host == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Can't verify host in known hosts if the hostname isn't known");
|
||||
if (session->opts.host == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Can't verify host in known hosts if the hostname isn't known");
|
||||
|
||||
return SSH_SERVER_ERROR;
|
||||
}
|
||||
return SSH_SERVER_ERROR;
|
||||
}
|
||||
|
||||
if (session->current_crypto == NULL){
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"ssh_is_host_known called without cryptographic context");
|
||||
|
||||
return SSH_SERVER_ERROR;
|
||||
}
|
||||
|
||||
host = ssh_lowercase(session->opts.host);
|
||||
hostport = ssh_hostport(host, session->opts.port > 0 ? session->opts.port : 22);
|
||||
if (host == NULL || hostport == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
SAFE_FREE(host);
|
||||
SAFE_FREE(hostport);
|
||||
|
||||
return SSH_SERVER_ERROR;
|
||||
}
|
||||
|
||||
/* Set the list of known hosts files */
|
||||
i = 0;
|
||||
if (session->opts.global_knownhosts != NULL){
|
||||
files[i++] = session->opts.global_knownhosts;
|
||||
}
|
||||
files[i++] = session->opts.knownhosts;
|
||||
files[i] = NULL;
|
||||
i = 0;
|
||||
|
||||
do {
|
||||
tokens = ssh_get_knownhost_line(&file,
|
||||
files[i],
|
||||
&type);
|
||||
|
||||
/* End of file, return the current state or use next file */
|
||||
if (tokens == NULL) {
|
||||
++i;
|
||||
if(files[i] == NULL)
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
match = match_hashed_host(host, tokens->tokens[0]);
|
||||
if (match == 0){
|
||||
match = match_hostname(hostport, tokens->tokens[0],
|
||||
strlen(tokens->tokens[0]));
|
||||
}
|
||||
if (match == 0) {
|
||||
match = match_hostname(host, tokens->tokens[0],
|
||||
strlen(tokens->tokens[0]));
|
||||
}
|
||||
if (match == 0) {
|
||||
match = match_hashed_host(hostport, tokens->tokens[0]);
|
||||
}
|
||||
if (match) {
|
||||
ssh_key pubkey = ssh_dh_get_current_server_publickey(session);
|
||||
const char *pubkey_type = ssh_key_type_to_char(ssh_key_type(pubkey));
|
||||
|
||||
/* We got a match. Now check the key type */
|
||||
if (strcmp(pubkey_type, type) != 0) {
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"ssh_is_server_known: server type [%s] doesn't match the "
|
||||
"type [%s] in known_hosts file",
|
||||
pubkey_type,
|
||||
type);
|
||||
/* Different type. We don't override the known_changed error which is
|
||||
* more important */
|
||||
if (ret != SSH_SERVER_KNOWN_CHANGED)
|
||||
ret = SSH_SERVER_FOUND_OTHER;
|
||||
ssh_tokens_free(tokens);
|
||||
continue;
|
||||
}
|
||||
/* so we know the key type is good. We may get a good key or a bad key. */
|
||||
match = check_public_key(session, tokens->tokens);
|
||||
ssh_tokens_free(tokens);
|
||||
|
||||
if (match < 0) {
|
||||
ret = SSH_SERVER_ERROR;
|
||||
break;
|
||||
} else if (match == 1) {
|
||||
ret = SSH_SERVER_KNOWN_OK;
|
||||
break;
|
||||
} else if(match == 0) {
|
||||
/* We override the status with the wrong key state */
|
||||
ret = SSH_SERVER_KNOWN_CHANGED;
|
||||
}
|
||||
} else {
|
||||
ssh_tokens_free(tokens);
|
||||
}
|
||||
} while (1);
|
||||
|
||||
if ((ret == SSH_SERVER_NOT_KNOWN) &&
|
||||
(session->opts.StrictHostKeyChecking == 0)) {
|
||||
int rv = ssh_session_update_known_hosts(session);
|
||||
if (rv != SSH_OK) {
|
||||
ret = SSH_SERVER_ERROR;
|
||||
} else {
|
||||
ret = SSH_SERVER_KNOWN_OK;
|
||||
}
|
||||
}
|
||||
if (session->current_crypto == NULL){
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"ssh_is_host_known called without cryptographic context");
|
||||
|
||||
return SSH_SERVER_ERROR;
|
||||
}
|
||||
host = ssh_lowercase(session->opts.host);
|
||||
hostport = ssh_hostport(host, session->opts.port > 0 ? session->opts.port : 22);
|
||||
if (host == NULL || hostport == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
SAFE_FREE(host);
|
||||
SAFE_FREE(hostport);
|
||||
if (file != NULL) {
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
/* Return the current state at end of file */
|
||||
return ret;
|
||||
return SSH_SERVER_ERROR;
|
||||
}
|
||||
|
||||
/* set the list of known hosts */
|
||||
i = 0;
|
||||
if (session->opts.global_knownhosts != NULL){
|
||||
files[i++]=session->opts.global_knownhosts;
|
||||
}
|
||||
files[i++] = session->opts.knownhosts;
|
||||
files[i] = NULL;
|
||||
i = 0;
|
||||
|
||||
do {
|
||||
tokens = ssh_get_knownhost_line(&file,
|
||||
files[i],
|
||||
&type);
|
||||
|
||||
/* End of file, return the current state or use next file */
|
||||
if (tokens == NULL) {
|
||||
++i;
|
||||
if(files[i] == NULL)
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
match = match_hashed_host(host, tokens[0]);
|
||||
if (match == 0){
|
||||
match = match_hostname(hostport, tokens[0], strlen(tokens[0]));
|
||||
}
|
||||
if (match == 0) {
|
||||
match = match_hostname(host, tokens[0], strlen(tokens[0]));
|
||||
}
|
||||
if (match == 0) {
|
||||
match = match_hashed_host(hostport, tokens[0]);
|
||||
}
|
||||
if (match) {
|
||||
ssh_key pubkey = ssh_dh_get_current_server_publickey(session);
|
||||
const char *pubkey_type = NULL;
|
||||
|
||||
if (ssh_key_type(pubkey) == SSH_KEYTYPE_ECDSA) {
|
||||
pubkey_type = ssh_pki_key_ecdsa_name(pubkey);
|
||||
} else {
|
||||
pubkey_type = ssh_key_type_to_char(ssh_key_type(pubkey));
|
||||
}
|
||||
|
||||
/* We got a match. Now check the key type */
|
||||
if (strcmp(pubkey_type, type) != 0) {
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"ssh_is_server_known: server type [%s] doesn't match the "
|
||||
"type [%s] in known_hosts file",
|
||||
pubkey_type,
|
||||
type);
|
||||
/* Different type. We don't override the known_changed error which is
|
||||
* more important */
|
||||
if (ret != SSH_SERVER_KNOWN_CHANGED)
|
||||
ret = SSH_SERVER_FOUND_OTHER;
|
||||
tokens_free(tokens);
|
||||
continue;
|
||||
}
|
||||
/* so we know the key type is good. We may get a good key or a bad key. */
|
||||
match = check_public_key(session, tokens);
|
||||
tokens_free(tokens);
|
||||
|
||||
if (match < 0) {
|
||||
ret = SSH_SERVER_ERROR;
|
||||
break;
|
||||
} else if (match == 1) {
|
||||
ret = SSH_SERVER_KNOWN_OK;
|
||||
break;
|
||||
} else if(match == 0) {
|
||||
/* We override the status with the wrong key state */
|
||||
ret = SSH_SERVER_KNOWN_CHANGED;
|
||||
}
|
||||
} else {
|
||||
tokens_free(tokens);
|
||||
}
|
||||
} while (1);
|
||||
|
||||
if ((ret == SSH_SERVER_NOT_KNOWN) &&
|
||||
(session->opts.StrictHostKeyChecking == 0)) {
|
||||
ssh_write_knownhost(session);
|
||||
ret = SSH_SERVER_KNOWN_OK;
|
||||
}
|
||||
|
||||
SAFE_FREE(host);
|
||||
SAFE_FREE(hostport);
|
||||
if (file != NULL) {
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
/* Return the current state at end of file */
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -496,12 +512,10 @@ char * ssh_dump_knownhost(ssh_session session) {
|
||||
* @deprecated Please use ssh_session_update_known_hosts()
|
||||
* @brief This function is deprecated
|
||||
*/
|
||||
int ssh_write_knownhost(ssh_session session)
|
||||
{
|
||||
int ssh_write_knownhost(ssh_session session) {
|
||||
FILE *file;
|
||||
char *buffer = NULL;
|
||||
char *buffer;
|
||||
char *dir;
|
||||
int rc;
|
||||
|
||||
if (session->opts.knownhosts == NULL) {
|
||||
if (ssh_options_apply(session) < 0) {
|
||||
@@ -510,45 +524,33 @@ int ssh_write_knownhost(ssh_session session)
|
||||
}
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
file = fopen(session->opts.knownhosts, "a");
|
||||
if (file == NULL) {
|
||||
if (errno == ENOENT) {
|
||||
dir = ssh_dirname(session->opts.knownhosts);
|
||||
if (dir == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "%s", strerror(errno));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
/* Check if directory exists and create it if not */
|
||||
dir = ssh_dirname(session->opts.knownhosts);
|
||||
if (dir == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "%s", strerror(errno));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = ssh_mkdirs(dir, 0700);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Cannot create %s directory: %s",
|
||||
dir, strerror(errno));
|
||||
SAFE_FREE(dir);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
SAFE_FREE(dir);
|
||||
|
||||
errno = 0;
|
||||
file = fopen(session->opts.knownhosts, "a");
|
||||
if (file == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Couldn't open known_hosts file %s"
|
||||
" for appending: %s",
|
||||
session->opts.knownhosts, strerror(errno));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
} else {
|
||||
if (!ssh_file_readaccess_ok(dir)) {
|
||||
if (ssh_mkdir(dir, 0700) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Couldn't open known_hosts file %s for appending: %s",
|
||||
session->opts.knownhosts, strerror(errno));
|
||||
"Cannot create %s directory.", dir);
|
||||
SAFE_FREE(dir);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
SAFE_FREE(dir);
|
||||
|
||||
rc = ssh_session_export_known_hosts_entry(session, &buffer);
|
||||
if (rc != SSH_OK) {
|
||||
file = fopen(session->opts.knownhosts, "a");
|
||||
if (file == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Couldn't open known_hosts file %s for appending: %s",
|
||||
session->opts.knownhosts, strerror(errno));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
buffer = ssh_dump_knownhost(session);
|
||||
if (buffer == NULL) {
|
||||
fclose(file);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
370
src/knownhosts.c
370
src/knownhosts.c
@@ -42,7 +42,6 @@
|
||||
#include "libssh/pki.h"
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/knownhosts.h"
|
||||
#include "libssh/token.h"
|
||||
|
||||
/**
|
||||
* @addtogroup libssh_session
|
||||
@@ -183,29 +182,6 @@ static int known_hosts_read_line(FILE *fp,
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_known_hosts_entries_compare(struct ssh_knownhosts_entry *k1,
|
||||
struct ssh_knownhosts_entry *k2)
|
||||
{
|
||||
int cmp;
|
||||
|
||||
if (k1 == NULL || k2 == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
cmp = strcmp(k1->hostname, k2->hostname);
|
||||
if (cmp != 0) {
|
||||
return cmp;
|
||||
}
|
||||
|
||||
cmp = ssh_key_cmp(k1->publickey, k2->publickey, SSH_KEY_CMP_PUBLIC);
|
||||
if (cmp != 0) {
|
||||
return cmp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This method reads the known_hosts file referenced by the path
|
||||
* in filename argument, and entries matching the match argument
|
||||
* will be added to the list in entries argument.
|
||||
@@ -242,8 +218,7 @@ static int ssh_known_hosts_read_entries(const char *match,
|
||||
rc == 0;
|
||||
rc = known_hosts_read_line(fp, line, sizeof(line), &len, &lineno)) {
|
||||
struct ssh_knownhosts_entry *entry = NULL;
|
||||
struct ssh_iterator *it = NULL;
|
||||
char *p = NULL;
|
||||
char *p;
|
||||
|
||||
if (line[len] != '\n') {
|
||||
len = strcspn(line, "\n");
|
||||
@@ -258,12 +233,6 @@ static int ssh_known_hosts_read_entries(const char *match,
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Skip lines starting with markers (@cert-authority, @revoked):
|
||||
* we do not completely support them anyway */
|
||||
if (p[0] == '@') {
|
||||
continue;
|
||||
}
|
||||
|
||||
rc = ssh_known_hosts_parse_line(match,
|
||||
line,
|
||||
&entry);
|
||||
@@ -272,24 +241,7 @@ static int ssh_known_hosts_read_entries(const char *match,
|
||||
} else if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Check for duplicates */
|
||||
for (it = ssh_list_get_iterator(*entries);
|
||||
it != NULL;
|
||||
it = it->next) {
|
||||
struct ssh_knownhosts_entry *entry2;
|
||||
int cmp;
|
||||
entry2 = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
|
||||
cmp = ssh_known_hosts_entries_compare(entry, entry2);
|
||||
if (cmp == 0) {
|
||||
ssh_knownhosts_entry_free(entry);
|
||||
entry = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (entry != NULL) {
|
||||
ssh_list_append(*entries, entry);
|
||||
}
|
||||
ssh_list_append(*entries, entry);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
@@ -307,7 +259,7 @@ static char *ssh_session_get_host_port(ssh_session session)
|
||||
if (session->opts.host == NULL) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Can't verify server in known hosts if the host we "
|
||||
"Can't verify server inn known hosts if the host we "
|
||||
"should connect to has not been set");
|
||||
|
||||
return NULL;
|
||||
@@ -410,32 +362,15 @@ struct ssh_list *ssh_known_hosts_get_algorithms(ssh_session session)
|
||||
for (it = ssh_list_get_iterator(entry_list);
|
||||
it != NULL;
|
||||
it = ssh_list_get_iterator(entry_list)) {
|
||||
struct ssh_iterator *it2 = NULL;
|
||||
struct ssh_knownhosts_entry *entry = NULL;
|
||||
const char *algo = NULL;
|
||||
bool present = false;
|
||||
|
||||
entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
|
||||
algo = entry->publickey->type_c;
|
||||
|
||||
/* Check for duplicates */
|
||||
for (it2 = ssh_list_get_iterator(list);
|
||||
it2 != NULL;
|
||||
it2 = it2->next) {
|
||||
char *alg2 = ssh_iterator_value(char *, it2);
|
||||
int cmp = strcmp(alg2, algo);
|
||||
if (cmp == 0) {
|
||||
present = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add to the new list only if it is unique */
|
||||
if (!present) {
|
||||
rc = ssh_list_append(list, algo);
|
||||
if (rc != SSH_OK) {
|
||||
list_error = 1;
|
||||
}
|
||||
rc = ssh_list_append(list, algo);
|
||||
if (rc != SSH_OK) {
|
||||
list_error = 1;
|
||||
}
|
||||
|
||||
ssh_knownhosts_entry_free(entry);
|
||||
@@ -452,146 +387,6 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Returns a static string containing a list of the signature types the
|
||||
* given key type can generate.
|
||||
*
|
||||
* @returns A static cstring containing the signature types the key is able to
|
||||
* generate separated by commas; NULL in case of error
|
||||
*/
|
||||
static const char *ssh_known_host_sigs_from_hostkey_type(enum ssh_keytypes_e type)
|
||||
{
|
||||
switch (type) {
|
||||
case SSH_KEYTYPE_RSA:
|
||||
return "rsa-sha2-512,rsa-sha2-256,ssh-rsa";
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
return "ssh-ed25519";
|
||||
#ifdef HAVE_DSA
|
||||
case SSH_KEYTYPE_DSS:
|
||||
return "ssh-dss";
|
||||
#endif
|
||||
#ifdef HAVE_ECDH
|
||||
case SSH_KEYTYPE_ECDSA_P256:
|
||||
return "ecdsa-sha2-nistp256";
|
||||
case SSH_KEYTYPE_ECDSA_P384:
|
||||
return "ecdsa-sha2-nistp384";
|
||||
case SSH_KEYTYPE_ECDSA_P521:
|
||||
return "ecdsa-sha2-nistp521";
|
||||
#endif
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
default:
|
||||
SSH_LOG(SSH_LOG_WARN, "The given type %d is not a base private key type "
|
||||
"or is unsupported", type);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief Get the host keys algorithms identifiers from the known_hosts files
|
||||
*
|
||||
* This expands the signatures types that can be generated from the keys types
|
||||
* present in the known_hosts files
|
||||
*
|
||||
* @param[in] session The ssh session to use.
|
||||
*
|
||||
* @return A newly allocated cstring containing a list of signature algorithms
|
||||
* that can be generated by the host using the keys listed in the known_hosts
|
||||
* files, NULL on error.
|
||||
*/
|
||||
char *ssh_known_hosts_get_algorithms_names(ssh_session session)
|
||||
{
|
||||
char methods_buffer[256 + 1] = {0};
|
||||
struct ssh_list *entry_list = NULL;
|
||||
struct ssh_iterator *it = NULL;
|
||||
char *host_port = NULL;
|
||||
size_t count;
|
||||
bool needcomma = false;
|
||||
char *names;
|
||||
|
||||
int rc;
|
||||
|
||||
if (session->opts.knownhosts == NULL ||
|
||||
session->opts.global_knownhosts == NULL) {
|
||||
if (ssh_options_apply(session) < 0) {
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
"Can't find a known_hosts file");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
host_port = ssh_session_get_host_port(session);
|
||||
if (host_port == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rc = ssh_known_hosts_read_entries(host_port,
|
||||
session->opts.knownhosts,
|
||||
&entry_list);
|
||||
if (rc != 0) {
|
||||
SAFE_FREE(host_port);
|
||||
ssh_list_free(entry_list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rc = ssh_known_hosts_read_entries(host_port,
|
||||
session->opts.global_knownhosts,
|
||||
&entry_list);
|
||||
SAFE_FREE(host_port);
|
||||
if (rc != 0) {
|
||||
ssh_list_free(entry_list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (entry_list == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
count = ssh_list_count(entry_list);
|
||||
if (count == 0) {
|
||||
ssh_list_free(entry_list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (it = ssh_list_get_iterator(entry_list);
|
||||
it != NULL;
|
||||
it = ssh_list_get_iterator(entry_list))
|
||||
{
|
||||
struct ssh_knownhosts_entry *entry = NULL;
|
||||
const char *algo = NULL;
|
||||
|
||||
entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
|
||||
algo = ssh_known_host_sigs_from_hostkey_type(entry->publickey->type);
|
||||
if (algo == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (needcomma) {
|
||||
strncat(methods_buffer,
|
||||
",",
|
||||
sizeof(methods_buffer) - strlen(methods_buffer) - 1);
|
||||
}
|
||||
|
||||
strncat(methods_buffer,
|
||||
algo,
|
||||
sizeof(methods_buffer) - strlen(methods_buffer) - 1);
|
||||
needcomma = true;
|
||||
|
||||
ssh_knownhosts_entry_free(entry);
|
||||
ssh_list_remove(entry_list, it);
|
||||
}
|
||||
|
||||
ssh_list_free(entry_list);
|
||||
|
||||
names = ssh_remove_duplicates(methods_buffer);
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parse a line from a known_hosts entry into a structure
|
||||
*
|
||||
@@ -639,8 +434,8 @@ int ssh_known_hosts_parse_line(const char *hostname,
|
||||
}
|
||||
|
||||
if (hostname != NULL) {
|
||||
char *host_port = NULL;
|
||||
char *q = NULL;
|
||||
char *match_pattern = NULL;
|
||||
char *q;
|
||||
|
||||
/* Hashed */
|
||||
if (p[0] == '|') {
|
||||
@@ -652,30 +447,13 @@ int ssh_known_hosts_parse_line(const char *hostname,
|
||||
q = strtok(NULL, ",")) {
|
||||
int cmp;
|
||||
|
||||
if (q[0] == '[' && hostname[0] != '[') {
|
||||
/* Corner case: We have standard port so we do not have
|
||||
* hostname in square braces. But the patern is enclosed
|
||||
* in braces with, possibly standard or wildcard, port.
|
||||
* We need to test against [host]:port pair here.
|
||||
*/
|
||||
if (host_port == NULL) {
|
||||
host_port = ssh_hostport(hostname, 22);
|
||||
if (host_port == NULL) {
|
||||
rc = SSH_ERROR;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
cmp = match_hostname(host_port, q, strlen(q));
|
||||
} else {
|
||||
cmp = match_hostname(hostname, q, strlen(q));
|
||||
}
|
||||
cmp = match_hostname(hostname, q, strlen(q));
|
||||
if (cmp == 1) {
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(host_port);
|
||||
SAFE_FREE(match_pattern);
|
||||
|
||||
if (match == 0) {
|
||||
rc = SSH_AGAIN;
|
||||
@@ -779,82 +557,39 @@ enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session)
|
||||
struct ssh_list *entry_list = NULL;
|
||||
struct ssh_iterator *it = NULL;
|
||||
char *host_port = NULL;
|
||||
bool global_known_hosts_found = false;
|
||||
bool known_hosts_found = false;
|
||||
int rc;
|
||||
|
||||
if (session->opts.knownhosts == NULL) {
|
||||
if (ssh_options_apply(session) < 0) {
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
"Cannot find a known_hosts file");
|
||||
"Can't find a known_hosts file");
|
||||
|
||||
return SSH_KNOWN_HOSTS_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
if (session->opts.knownhosts == NULL &&
|
||||
session->opts.global_knownhosts == NULL) {
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
"No path set for a known_hosts file");
|
||||
|
||||
return SSH_KNOWN_HOSTS_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (session->opts.knownhosts != NULL) {
|
||||
known_hosts_found = ssh_file_readaccess_ok(session->opts.knownhosts);
|
||||
if (!known_hosts_found) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Cannot access file %s",
|
||||
session->opts.knownhosts);
|
||||
}
|
||||
}
|
||||
|
||||
if (session->opts.global_knownhosts != NULL) {
|
||||
global_known_hosts_found =
|
||||
ssh_file_readaccess_ok(session->opts.global_knownhosts);
|
||||
if (!global_known_hosts_found) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Cannot access file %s",
|
||||
session->opts.global_knownhosts);
|
||||
}
|
||||
}
|
||||
|
||||
if ((!known_hosts_found) && (!global_known_hosts_found)) {
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
"Cannot find a known_hosts file");
|
||||
|
||||
return SSH_KNOWN_HOSTS_NOT_FOUND;
|
||||
}
|
||||
|
||||
host_port = ssh_session_get_host_port(session);
|
||||
if (host_port == NULL) {
|
||||
return SSH_KNOWN_HOSTS_ERROR;
|
||||
}
|
||||
|
||||
if (known_hosts_found) {
|
||||
rc = ssh_known_hosts_read_entries(host_port,
|
||||
session->opts.knownhosts,
|
||||
&entry_list);
|
||||
if (rc != 0) {
|
||||
SAFE_FREE(host_port);
|
||||
ssh_list_free(entry_list);
|
||||
return SSH_KNOWN_HOSTS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (global_known_hosts_found) {
|
||||
rc = ssh_known_hosts_read_entries(host_port,
|
||||
session->opts.global_knownhosts,
|
||||
&entry_list);
|
||||
if (rc != 0) {
|
||||
SAFE_FREE(host_port);
|
||||
ssh_list_free(entry_list);
|
||||
return SSH_KNOWN_HOSTS_ERROR;
|
||||
}
|
||||
rc = ssh_known_hosts_read_entries(host_port,
|
||||
session->opts.knownhosts,
|
||||
&entry_list);
|
||||
if (rc != 0) {
|
||||
ssh_list_free(entry_list);
|
||||
return SSH_KNOWN_HOSTS_UNKNOWN;
|
||||
}
|
||||
|
||||
rc = ssh_known_hosts_read_entries(host_port,
|
||||
session->opts.global_knownhosts,
|
||||
&entry_list);
|
||||
SAFE_FREE(host_port);
|
||||
if (rc != 0) {
|
||||
ssh_list_free(entry_list);
|
||||
return SSH_KNOWN_HOSTS_UNKNOWN;
|
||||
}
|
||||
|
||||
if (ssh_list_count(entry_list) == 0) {
|
||||
ssh_list_free(entry_list);
|
||||
@@ -979,41 +714,32 @@ int ssh_session_update_known_hosts(ssh_session session)
|
||||
}
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
/* Check if directory exists and create it if not */
|
||||
dir = ssh_dirname(session->opts.knownhosts);
|
||||
if (dir == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "%s", strerror(errno));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = ssh_file_readaccess_ok(dir);
|
||||
if (rc == 0) {
|
||||
rc = ssh_mkdir(dir, 0700);
|
||||
} else {
|
||||
rc = 0;
|
||||
}
|
||||
SAFE_FREE(dir);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Cannot create %s directory.", dir);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
fp = fopen(session->opts.knownhosts, "a");
|
||||
if (fp == NULL) {
|
||||
if (errno == ENOENT) {
|
||||
dir = ssh_dirname(session->opts.knownhosts);
|
||||
if (dir == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "%s", strerror(errno));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = ssh_mkdirs(dir, 0700);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Cannot create %s directory: %s",
|
||||
dir, strerror(errno));
|
||||
SAFE_FREE(dir);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
SAFE_FREE(dir);
|
||||
|
||||
errno = 0;
|
||||
fp = fopen(session->opts.knownhosts, "a");
|
||||
if (fp == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Couldn't open known_hosts file %s"
|
||||
" for appending: %s",
|
||||
session->opts.knownhosts, strerror(errno));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
} else {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Couldn't open known_hosts file %s for appending: %s",
|
||||
session->opts.knownhosts, strerror(errno));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Couldn't open known_hosts file %s for appending: %s",
|
||||
session->opts.knownhosts, strerror(errno));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = ssh_session_export_known_hosts_entry(session, &entry);
|
||||
|
||||
@@ -335,62 +335,3 @@ void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx)
|
||||
OPENSSL_free(ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
void DH_get0_pqg(const DH *dh,
|
||||
const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
|
||||
{
|
||||
if (p) {
|
||||
*p = dh->p;
|
||||
}
|
||||
if (q) {
|
||||
*q = NULL;
|
||||
}
|
||||
if (g) {
|
||||
*g = dh->g;
|
||||
}
|
||||
}
|
||||
|
||||
int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
|
||||
{
|
||||
if (p) {
|
||||
if (dh->p) {
|
||||
BN_free(dh->p);
|
||||
}
|
||||
dh->p = p;
|
||||
}
|
||||
if (g) {
|
||||
if (dh->g) {
|
||||
BN_free(dh->g);
|
||||
}
|
||||
dh->g = g;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void DH_get0_key(const DH *dh,
|
||||
const BIGNUM **pub_key, const BIGNUM **priv_key)
|
||||
{
|
||||
if (pub_key) {
|
||||
*pub_key = dh->pub_key;
|
||||
}
|
||||
if (priv_key) {
|
||||
*priv_key = dh->priv_key;
|
||||
}
|
||||
}
|
||||
|
||||
int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
|
||||
{
|
||||
if (pub_key) {
|
||||
if (dh->pub_key) {
|
||||
BN_free(dh->pub_key);
|
||||
}
|
||||
dh->pub_key = pub_key;
|
||||
}
|
||||
if (priv_key) {
|
||||
if (dh->priv_key) {
|
||||
BN_free(dh->priv_key);
|
||||
}
|
||||
dh->priv_key = priv_key;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -38,12 +38,6 @@ HMAC_CTX *HMAC_CTX_new(void);
|
||||
int HMAC_CTX_reset(HMAC_CTX *ctx);
|
||||
void HMAC_CTX_free(HMAC_CTX *ctx);
|
||||
|
||||
void DH_get0_pqg(const DH *dh,
|
||||
const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
|
||||
int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g);
|
||||
void DH_get0_key(const DH *dh,
|
||||
const BIGNUM **pub_key, const BIGNUM **priv_key);
|
||||
int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key);
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
|
||||
#endif /* LIBCRYPTO_COMPAT_H */
|
||||
|
||||
206
src/libcrypto.c
206
src/libcrypto.c
@@ -43,7 +43,6 @@
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "libcrypto-compat.h"
|
||||
|
||||
#ifdef HAVE_OPENSSL_AES_H
|
||||
@@ -55,6 +54,10 @@
|
||||
#include <openssl/des.h>
|
||||
#endif
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER<0x00907000L)
|
||||
#define OLD_CRYPTO
|
||||
#endif
|
||||
|
||||
#if (defined(HAVE_VALGRIND_VALGRIND_H) && defined(HAVE_OPENSSL_IA32CAP_LOC))
|
||||
#include <valgrind/valgrind.h>
|
||||
#define CAN_DISABLE_AESNI
|
||||
@@ -62,15 +65,15 @@
|
||||
|
||||
#include "libssh/crypto.h"
|
||||
|
||||
#ifdef HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID
|
||||
#include <openssl/kdf.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENSSL_CRYPTO_CTR128_ENCRYPT
|
||||
#include <openssl/modes.h>
|
||||
#endif
|
||||
|
||||
#include "libssh/crypto.h"
|
||||
struct ssh_mac_ctx_struct {
|
||||
enum ssh_mac_e mac_type;
|
||||
union {
|
||||
SHACTX sha1_ctx;
|
||||
SHA256CTX sha256_ctx;
|
||||
SHA384CTX sha384_ctx;
|
||||
SHA512CTX sha512_ctx;
|
||||
} ctx;
|
||||
};
|
||||
|
||||
static int libcrypto_initialized = 0;
|
||||
|
||||
@@ -139,7 +142,7 @@ void sha1_final(unsigned char *md, SHACTX c)
|
||||
EVP_MD_CTX_destroy(c);
|
||||
}
|
||||
|
||||
void sha1(const unsigned char *digest, int len, unsigned char *hash)
|
||||
void sha1(unsigned char *digest, int len, unsigned char *hash)
|
||||
{
|
||||
SHACTX c = sha1_init();
|
||||
if (c != NULL) {
|
||||
@@ -231,7 +234,7 @@ void sha256_final(unsigned char *md, SHA256CTX c)
|
||||
EVP_MD_CTX_destroy(c);
|
||||
}
|
||||
|
||||
void sha256(const unsigned char *digest, int len, unsigned char *hash)
|
||||
void sha256(unsigned char *digest, int len, unsigned char *hash)
|
||||
{
|
||||
SHA256CTX c = sha256_init();
|
||||
if (c != NULL) {
|
||||
@@ -269,7 +272,7 @@ void sha384_final(unsigned char *md, SHA384CTX c)
|
||||
EVP_MD_CTX_destroy(c);
|
||||
}
|
||||
|
||||
void sha384(const unsigned char *digest, int len, unsigned char *hash)
|
||||
void sha384(unsigned char *digest, int len, unsigned char *hash)
|
||||
{
|
||||
SHA384CTX c = sha384_init();
|
||||
if (c != NULL) {
|
||||
@@ -307,7 +310,7 @@ void sha512_final(unsigned char *md, SHA512CTX c)
|
||||
EVP_MD_CTX_destroy(c);
|
||||
}
|
||||
|
||||
void sha512(const unsigned char *digest, int len, unsigned char *hash)
|
||||
void sha512(unsigned char *digest, int len, unsigned char *hash)
|
||||
{
|
||||
SHA512CTX c = sha512_init();
|
||||
if (c != NULL) {
|
||||
@@ -345,80 +348,70 @@ void md5_final(unsigned char *md, MD5CTX c)
|
||||
EVP_MD_CTX_destroy(c);
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID
|
||||
static const EVP_MD *sshkdf_digest_to_md(enum ssh_kdf_digest digest_type)
|
||||
{
|
||||
switch (digest_type) {
|
||||
case SSH_KDF_SHA1:
|
||||
return EVP_sha1();
|
||||
case SSH_KDF_SHA256:
|
||||
return EVP_sha256();
|
||||
case SSH_KDF_SHA384:
|
||||
return EVP_sha384();
|
||||
case SSH_KDF_SHA512:
|
||||
return EVP_sha512();
|
||||
}
|
||||
ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type){
|
||||
ssh_mac_ctx ctx = malloc(sizeof(struct ssh_mac_ctx_struct));
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->mac_type=type;
|
||||
switch(type){
|
||||
case SSH_MAC_SHA1:
|
||||
ctx->ctx.sha1_ctx = sha1_init();
|
||||
return ctx;
|
||||
case SSH_MAC_SHA256:
|
||||
ctx->ctx.sha256_ctx = sha256_init();
|
||||
return ctx;
|
||||
case SSH_MAC_SHA384:
|
||||
ctx->ctx.sha384_ctx = sha384_init();
|
||||
return ctx;
|
||||
case SSH_MAC_SHA512:
|
||||
ctx->ctx.sha512_ctx = sha512_init();
|
||||
return ctx;
|
||||
default:
|
||||
SAFE_FREE(ctx);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int ssh_kdf(struct ssh_crypto_struct *crypto,
|
||||
unsigned char *key, size_t key_len,
|
||||
int key_type, unsigned char *output,
|
||||
size_t requested_len)
|
||||
{
|
||||
EVP_KDF_CTX *ctx = EVP_KDF_CTX_new_id(EVP_KDF_SSHKDF);
|
||||
int rc;
|
||||
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_MD,
|
||||
sshkdf_digest_to_md(crypto->digest_type));
|
||||
if (rc != 1) {
|
||||
goto out;
|
||||
}
|
||||
rc = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KEY, key, key_len);
|
||||
if (rc != 1) {
|
||||
goto out;
|
||||
}
|
||||
rc = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSHKDF_XCGHASH,
|
||||
crypto->secret_hash, crypto->digest_len);
|
||||
if (rc != 1) {
|
||||
goto out;
|
||||
}
|
||||
rc = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSHKDF_TYPE, key_type);
|
||||
if (rc != 1) {
|
||||
goto out;
|
||||
}
|
||||
rc = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSHKDF_SESSION_ID,
|
||||
crypto->session_id, crypto->digest_len);
|
||||
if (rc != 1) {
|
||||
goto out;
|
||||
}
|
||||
rc = EVP_KDF_derive(ctx, output, requested_len);
|
||||
if (rc != 1) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
EVP_KDF_CTX_free(ctx);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
return 0;
|
||||
void ssh_mac_update(ssh_mac_ctx ctx, const void *data, unsigned long len) {
|
||||
switch(ctx->mac_type){
|
||||
case SSH_MAC_SHA1:
|
||||
sha1_update(ctx->ctx.sha1_ctx, data, len);
|
||||
break;
|
||||
case SSH_MAC_SHA256:
|
||||
sha256_update(ctx->ctx.sha256_ctx, data, len);
|
||||
break;
|
||||
case SSH_MAC_SHA384:
|
||||
sha384_update(ctx->ctx.sha384_ctx, data, len);
|
||||
break;
|
||||
case SSH_MAC_SHA512:
|
||||
sha512_update(ctx->ctx.sha512_ctx, data, len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
int ssh_kdf(struct ssh_crypto_struct *crypto,
|
||||
unsigned char *key, size_t key_len,
|
||||
int key_type, unsigned char *output,
|
||||
size_t requested_len)
|
||||
{
|
||||
return sshkdf_derive_key(crypto, key, key_len,
|
||||
key_type, output, requested_len);
|
||||
void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx) {
|
||||
switch(ctx->mac_type){
|
||||
case SSH_MAC_SHA1:
|
||||
sha1_final(md,ctx->ctx.sha1_ctx);
|
||||
break;
|
||||
case SSH_MAC_SHA256:
|
||||
sha256_final(md,ctx->ctx.sha256_ctx);
|
||||
break;
|
||||
case SSH_MAC_SHA384:
|
||||
sha384_final(md,ctx->ctx.sha384_ctx);
|
||||
break;
|
||||
case SSH_MAC_SHA512:
|
||||
sha512_final(md,ctx->ctx.sha512_ctx);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
SAFE_FREE(ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
HMACCTX hmac_init(const void *key, int len, enum ssh_hmac_e type) {
|
||||
HMACCTX ctx = NULL;
|
||||
@@ -428,6 +421,9 @@ HMACCTX hmac_init(const void *key, int len, enum ssh_hmac_e type) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef OLD_CRYPTO
|
||||
HMAC_CTX_reset(ctx); // openssl 0.9.7 requires it.
|
||||
#endif
|
||||
|
||||
switch(type) {
|
||||
case SSH_HMAC_SHA1:
|
||||
@@ -436,6 +432,9 @@ HMACCTX hmac_init(const void *key, int len, enum ssh_hmac_e type) {
|
||||
case SSH_HMAC_SHA256:
|
||||
HMAC_Init_ex(ctx, key, len, EVP_sha256(), NULL);
|
||||
break;
|
||||
case SSH_HMAC_SHA384:
|
||||
HMAC_Init_ex(ctx, key, len, EVP_sha384(), NULL);
|
||||
break;
|
||||
case SSH_HMAC_SHA512:
|
||||
HMAC_Init_ex(ctx, key, len, EVP_sha512(), NULL);
|
||||
break;
|
||||
@@ -457,14 +456,14 @@ void hmac_update(HMACCTX ctx, const void *data, unsigned long len) {
|
||||
void hmac_final(HMACCTX ctx, unsigned char *hashmacbuf, unsigned int *len) {
|
||||
HMAC_Final(ctx,hashmacbuf,len);
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER > 0x10100000L
|
||||
#ifndef OLD_CRYPTO
|
||||
HMAC_CTX_free(ctx);
|
||||
ctx = NULL;
|
||||
#else
|
||||
HMAC_cleanup(ctx);
|
||||
SAFE_FREE(ctx);
|
||||
ctx = NULL;
|
||||
#endif
|
||||
|
||||
SAFE_FREE(ctx);
|
||||
}
|
||||
|
||||
static void evp_cipher_init(struct ssh_cipher_struct *cipher) {
|
||||
@@ -515,12 +514,10 @@ static void evp_cipher_init(struct ssh_cipher_struct *cipher) {
|
||||
case SSH_3DES_CBC:
|
||||
cipher->cipher = EVP_des_ede3_cbc();
|
||||
break;
|
||||
#ifdef WITH_BLOWFISH_CIPHER
|
||||
case SSH_BLOWFISH_CBC:
|
||||
cipher->cipher = EVP_bf_cbc();
|
||||
break;
|
||||
/* ciphers not using EVP */
|
||||
#endif
|
||||
case SSH_AEAD_CHACHA20_POLY1305:
|
||||
SSH_LOG(SSH_LOG_WARNING, "The ChaCha cipher cannot be handled here");
|
||||
break;
|
||||
@@ -551,7 +548,7 @@ static int evp_cipher_set_encrypt_key(struct ssh_cipher_struct *cipher,
|
||||
rc = EVP_CIPHER_CTX_ctrl(cipher->ctx,
|
||||
EVP_CTRL_GCM_SET_IV_FIXED,
|
||||
-1,
|
||||
(uint8_t *)IV);
|
||||
(u_char *)IV);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "EVP_CTRL_GCM_SET_IV_FIXED failed");
|
||||
return SSH_ERROR;
|
||||
@@ -584,7 +581,7 @@ static int evp_cipher_set_decrypt_key(struct ssh_cipher_struct *cipher,
|
||||
rc = EVP_CIPHER_CTX_ctrl(cipher->ctx,
|
||||
EVP_CTRL_GCM_SET_IV_FIXED,
|
||||
-1,
|
||||
(uint8_t *)IV);
|
||||
(u_char *)IV);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "EVP_CTRL_GCM_SET_IV_FIXED failed");
|
||||
return SSH_ERROR;
|
||||
@@ -686,12 +683,8 @@ static int aes_ctr_set_key(struct ssh_cipher_struct *cipher, void *key,
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
aes_ctr_encrypt(struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
void *out,
|
||||
size_t len)
|
||||
{
|
||||
static void aes_ctr_encrypt(struct ssh_cipher_struct *cipher, void *in, void *out,
|
||||
unsigned long len) {
|
||||
unsigned char tmp_buffer[AES_BLOCK_SIZE];
|
||||
unsigned int num=0;
|
||||
/* Some things are special with ctr128 :
|
||||
@@ -740,9 +733,8 @@ evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||
uint64_t seq)
|
||||
{
|
||||
size_t authlen, aadlen;
|
||||
uint8_t lastiv[1];
|
||||
int tmplen = 0;
|
||||
size_t outlen;
|
||||
u_char lastiv[1];
|
||||
int outlen = 0;
|
||||
int rc;
|
||||
|
||||
(void) seq;
|
||||
@@ -763,11 +755,10 @@ evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||
/* Pass over the authenticated data (not encrypted) */
|
||||
rc = EVP_EncryptUpdate(cipher->ctx,
|
||||
NULL,
|
||||
&tmplen,
|
||||
&outlen,
|
||||
(unsigned char *)in,
|
||||
(int)aadlen);
|
||||
outlen = tmplen;
|
||||
if (rc == 0 || outlen != aadlen) {
|
||||
if (rc == 0 || outlen != (int)aadlen) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "Failed to pass authenticated data");
|
||||
return;
|
||||
}
|
||||
@@ -776,10 +767,9 @@ evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||
/* Encrypt the rest of the data */
|
||||
rc = EVP_EncryptUpdate(cipher->ctx,
|
||||
(unsigned char *)out + aadlen,
|
||||
&tmplen,
|
||||
&outlen,
|
||||
(unsigned char *)in + aadlen,
|
||||
(int)len - aadlen);
|
||||
outlen = tmplen;
|
||||
if (rc != 1 || outlen != (int)len - aadlen) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "EVP_EncryptUpdate failed");
|
||||
return;
|
||||
@@ -788,7 +778,7 @@ evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||
/* compute tag */
|
||||
rc = EVP_EncryptFinal(cipher->ctx,
|
||||
NULL,
|
||||
&tmplen);
|
||||
&outlen);
|
||||
if (rc < 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "EVP_EncryptFinal failed: Failed to create a tag");
|
||||
return;
|
||||
@@ -812,7 +802,7 @@ evp_cipher_aead_decrypt(struct ssh_cipher_struct *cipher,
|
||||
uint64_t seq)
|
||||
{
|
||||
size_t authlen, aadlen;
|
||||
uint8_t lastiv[1];
|
||||
u_char lastiv[1];
|
||||
int outlen = 0;
|
||||
int rc = 0;
|
||||
|
||||
@@ -891,7 +881,6 @@ evp_cipher_aead_decrypt(struct ssh_cipher_struct *cipher,
|
||||
* The table of supported ciphers
|
||||
*/
|
||||
static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||
#ifdef WITH_BLOWFISH_CIPHER
|
||||
{
|
||||
.name = "blowfish-cbc",
|
||||
.blocksize = 8,
|
||||
@@ -903,7 +892,6 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||
.decrypt = evp_cipher_decrypt,
|
||||
.cleanup = evp_cipher_cleanup
|
||||
},
|
||||
#endif
|
||||
#ifdef HAS_AES
|
||||
#ifndef BROKEN_AES_CTR
|
||||
/* OpenSSL until 0.9.7c has a broken AES_ctr128_encrypt implementation which
|
||||
@@ -1098,9 +1086,7 @@ int ssh_crypto_init(void)
|
||||
OPENSSL_ia32cap &= ~(1LL << 57);
|
||||
}
|
||||
#endif
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
OpenSSL_add_all_algorithms();
|
||||
#endif
|
||||
|
||||
for (i = 0; ssh_ciphertab[i].name != NULL; i++) {
|
||||
int cmp;
|
||||
@@ -1129,10 +1115,8 @@ void ssh_crypto_finalize(void)
|
||||
return;
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
EVP_cleanup();
|
||||
CRYPTO_cleanup_all_ex_data();
|
||||
#endif
|
||||
|
||||
libcrypto_initialized = 0;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,11 @@
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
#include <gcrypt.h>
|
||||
|
||||
struct ssh_mac_ctx_struct {
|
||||
enum ssh_mac_e mac_type;
|
||||
gcry_md_hd_t ctx;
|
||||
};
|
||||
|
||||
static int libgcrypt_initialized = 0;
|
||||
|
||||
static int alloc_key(struct ssh_cipher_struct *cipher) {
|
||||
@@ -78,7 +83,7 @@ void sha1_final(unsigned char *md, SHACTX c) {
|
||||
gcry_md_close(c);
|
||||
}
|
||||
|
||||
void sha1(const unsigned char *digest, int len, unsigned char *hash) {
|
||||
void sha1(unsigned char *digest, int len, unsigned char *hash) {
|
||||
gcry_md_hash_buffer(GCRY_MD_SHA1, hash, digest, len);
|
||||
}
|
||||
|
||||
@@ -152,7 +157,7 @@ void sha256_final(unsigned char *md, SHACTX c) {
|
||||
gcry_md_close(c);
|
||||
}
|
||||
|
||||
void sha256(const unsigned char *digest, int len, unsigned char *hash){
|
||||
void sha256(unsigned char *digest, int len, unsigned char *hash){
|
||||
gcry_md_hash_buffer(GCRY_MD_SHA256, hash, digest, len);
|
||||
}
|
||||
|
||||
@@ -173,7 +178,7 @@ void sha384_final(unsigned char *md, SHACTX c) {
|
||||
gcry_md_close(c);
|
||||
}
|
||||
|
||||
void sha384(const unsigned char *digest, int len, unsigned char *hash) {
|
||||
void sha384(unsigned char *digest, int len, unsigned char *hash) {
|
||||
gcry_md_hash_buffer(GCRY_MD_SHA384, hash, digest, len);
|
||||
}
|
||||
|
||||
@@ -194,7 +199,7 @@ void sha512_final(unsigned char *md, SHACTX c) {
|
||||
gcry_md_close(c);
|
||||
}
|
||||
|
||||
void sha512(const unsigned char *digest, int len, unsigned char *hash) {
|
||||
void sha512(unsigned char *digest, int len, unsigned char *hash) {
|
||||
gcry_md_hash_buffer(GCRY_MD_SHA512, hash, digest, len);
|
||||
}
|
||||
|
||||
@@ -215,13 +220,57 @@ void md5_final(unsigned char *md, MD5CTX c) {
|
||||
gcry_md_close(c);
|
||||
}
|
||||
|
||||
int ssh_kdf(struct ssh_crypto_struct *crypto,
|
||||
unsigned char *key, size_t key_len,
|
||||
int key_type, unsigned char *output,
|
||||
size_t requested_len)
|
||||
{
|
||||
return sshkdf_derive_key(crypto, key, key_len,
|
||||
key_type, output, requested_len);
|
||||
ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type){
|
||||
ssh_mac_ctx ctx = malloc(sizeof(struct ssh_mac_ctx_struct));
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->mac_type=type;
|
||||
switch(type){
|
||||
case SSH_MAC_SHA1:
|
||||
gcry_md_open(&ctx->ctx, GCRY_MD_SHA1, 0);
|
||||
break;
|
||||
case SSH_MAC_SHA256:
|
||||
gcry_md_open(&ctx->ctx, GCRY_MD_SHA256, 0);
|
||||
break;
|
||||
case SSH_MAC_SHA384:
|
||||
gcry_md_open(&ctx->ctx, GCRY_MD_SHA384, 0);
|
||||
break;
|
||||
case SSH_MAC_SHA512:
|
||||
gcry_md_open(&ctx->ctx, GCRY_MD_SHA512, 0);
|
||||
break;
|
||||
default:
|
||||
SAFE_FREE(ctx);
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void ssh_mac_update(ssh_mac_ctx ctx, const void *data, unsigned long len) {
|
||||
gcry_md_write(ctx->ctx,data,len);
|
||||
}
|
||||
|
||||
void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx) {
|
||||
size_t len = 0;
|
||||
switch(ctx->mac_type){
|
||||
case SSH_MAC_SHA1:
|
||||
len=SHA_DIGEST_LEN;
|
||||
break;
|
||||
case SSH_MAC_SHA256:
|
||||
len=SHA256_DIGEST_LEN;
|
||||
break;
|
||||
case SSH_MAC_SHA384:
|
||||
len=SHA384_DIGEST_LEN;
|
||||
break;
|
||||
case SSH_MAC_SHA512:
|
||||
len=SHA512_DIGEST_LEN;
|
||||
break;
|
||||
}
|
||||
gcry_md_final(ctx->ctx);
|
||||
memcpy(md, gcry_md_read(ctx->ctx, 0), len);
|
||||
gcry_md_close(ctx->ctx);
|
||||
SAFE_FREE(ctx);
|
||||
}
|
||||
|
||||
HMACCTX hmac_init(const void *key, int len, enum ssh_hmac_e type) {
|
||||
@@ -234,6 +283,9 @@ HMACCTX hmac_init(const void *key, int len, enum ssh_hmac_e type) {
|
||||
case SSH_HMAC_SHA256:
|
||||
gcry_md_open(&c, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
|
||||
break;
|
||||
case SSH_HMAC_SHA384:
|
||||
gcry_md_open(&c, GCRY_MD_SHA384, GCRY_MD_FLAG_HMAC);
|
||||
break;
|
||||
case SSH_HMAC_SHA512:
|
||||
gcry_md_open(&c, GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC);
|
||||
break;
|
||||
@@ -259,7 +311,6 @@ void hmac_final(HMACCTX c, unsigned char *hashmacbuf, unsigned int *len) {
|
||||
gcry_md_close(c);
|
||||
}
|
||||
|
||||
#ifdef WITH_BLOWFISH_CIPHER
|
||||
/* the wrapper functions for blowfish */
|
||||
static int blowfish_set_key(struct ssh_cipher_struct *cipher, void *key, void *IV){
|
||||
if (cipher->key == NULL) {
|
||||
@@ -294,7 +345,6 @@ static void blowfish_decrypt(struct ssh_cipher_struct *cipher, void *in,
|
||||
void *out, unsigned long len) {
|
||||
gcry_cipher_decrypt(cipher->key[0], out, len, in, len);
|
||||
}
|
||||
#endif /* WITH_BLOWFISH_CIPHER */
|
||||
|
||||
static int aes_set_key(struct ssh_cipher_struct *cipher, void *key, void *IV) {
|
||||
int mode=GCRY_CIPHER_MODE_CBC;
|
||||
@@ -560,7 +610,6 @@ static void des3_decrypt(struct ssh_cipher_struct *cipher, void *in,
|
||||
|
||||
/* the table of supported ciphers */
|
||||
static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||
#ifdef WITH_BLOWFISH_CIPHER
|
||||
{
|
||||
.name = "blowfish-cbc",
|
||||
.blocksize = 8,
|
||||
@@ -572,7 +621,6 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||
.encrypt = blowfish_encrypt,
|
||||
.decrypt = blowfish_decrypt
|
||||
},
|
||||
#endif /* WITH_BLOWFISH_CIPHER */
|
||||
{
|
||||
.name = "aes128-ctr",
|
||||
.blocksize = 16,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user