mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-04 20:30:38 +09:00
Compare commits
172 Commits
39a62cef44
...
libssh-0.7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64a2d37c30 | ||
|
|
9d5cf209df | ||
|
|
1039732154 | ||
|
|
7ad80ba1cc | ||
|
|
acb0e4f401 | ||
|
|
3fe7510b26 | ||
|
|
734e3ce674 | ||
|
|
e4c6d591df | ||
|
|
f81ca61612 | ||
|
|
c20b360c96 | ||
|
|
5e061962c5 | ||
|
|
f1d57223db | ||
|
|
b9033ad56a | ||
|
|
e5ff7aa410 | ||
|
|
3837a0547f | ||
|
|
7985acb768 | ||
|
|
acd6a1ca8a | ||
|
|
ddea46f890 | ||
|
|
e5f0e711b0 | ||
|
|
e765c1400a | ||
|
|
7a7c0a54bc | ||
|
|
9c62d6dfcd | ||
|
|
f3f140e65f | ||
|
|
c977a97093 | ||
|
|
743a34ad9f | ||
|
|
0f9e6598ef | ||
|
|
f8007d7147 | ||
|
|
3d70d4f08d | ||
|
|
bade29d3d5 | ||
|
|
399ff6bbde | ||
|
|
c0d9aeda18 | ||
|
|
82b2d31c29 | ||
|
|
74102dfd7a | ||
|
|
d678f6a9ea | ||
|
|
00b8e6d1f0 | ||
|
|
aeb859e130 | ||
|
|
b393f7e5e9 | ||
|
|
2004617fd0 | ||
|
|
c5fe7c5a72 | ||
|
|
fec4dc4eff | ||
|
|
3d0c9cc6b5 | ||
|
|
4d6048ef88 | ||
|
|
3d2d777e26 | ||
|
|
8520adf609 | ||
|
|
c0be59f876 | ||
|
|
2983b21996 | ||
|
|
88ae595583 | ||
|
|
a228c3f728 | ||
|
|
53ed121a9c | ||
|
|
5a1ebdec9d | ||
|
|
bf2a33b21e | ||
|
|
130194aa0e | ||
|
|
1ebfd3834a | ||
|
|
1eeeace975 | ||
|
|
73ebcb3ab8 | ||
|
|
bd7b509278 | ||
|
|
652acbeb21 | ||
|
|
96e04d4691 | ||
|
|
7113074ae4 | ||
|
|
2db325eb74 | ||
|
|
9937d0b552 | ||
|
|
ae3e2a19c8 | ||
|
|
3567524fb2 | ||
|
|
4814c188eb | ||
|
|
a317188cb7 | ||
|
|
1d4151e51f | ||
|
|
c228fa7631 | ||
|
|
9658d36087 | ||
|
|
bbaa3dc869 | ||
|
|
4f10d6cd57 | ||
|
|
2209fcace3 | ||
|
|
a1847660a3 | ||
|
|
e2b48dc662 | ||
|
|
1a5b6ac472 | ||
|
|
0dd7a963a9 | ||
|
|
1642cec280 | ||
|
|
2f1c6668e7 | ||
|
|
fbeecf388c | ||
|
|
7933756b5a | ||
|
|
837e367d2d | ||
|
|
f81c3ada9c | ||
|
|
83663895f4 | ||
|
|
239d0f75b5 | ||
|
|
d88cc720fb | ||
|
|
ee13becf9c | ||
|
|
95b2dbbeca | ||
|
|
02c0a3b99b | ||
|
|
419731a189 | ||
|
|
2ac987bce9 | ||
|
|
0588cbf9d4 | ||
|
|
a7cce77550 | ||
|
|
5e63b40cde | ||
|
|
7b8b5eb4ea | ||
|
|
8dc3d883b8 | ||
|
|
24a3f7020c | ||
|
|
f74d5d5df4 | ||
|
|
7a21187fb9 | ||
|
|
439d3039e3 | ||
|
|
61cbf160a0 | ||
|
|
ce029c0735 | ||
|
|
8a2deeb3cc | ||
|
|
40164c348e | ||
|
|
9d7f873fd3 | ||
|
|
c5d320811b | ||
|
|
410f722ae5 | ||
|
|
8155b3c0a0 | ||
|
|
6836ffa103 | ||
|
|
b62b822100 | ||
|
|
849f5db5d1 | ||
|
|
a6493efcae | ||
|
|
1b0bf852be | ||
|
|
2b3185ec29 | ||
|
|
d63547b18a | ||
|
|
6697f85b50 | ||
|
|
67fe6f56ea | ||
|
|
b5ce15eefa | ||
|
|
a3688ada1a | ||
|
|
219d0bba42 | ||
|
|
bf3d8f3ad4 | ||
|
|
04a5d5bd74 | ||
|
|
2957aaf9f0 | ||
|
|
8360139506 | ||
|
|
0bf78b0b8b | ||
|
|
faca78f547 | ||
|
|
7da587ba6c | ||
|
|
c7aa51240d | ||
|
|
cdf7690e03 | ||
|
|
7b19719022 | ||
|
|
f8d0026c65 | ||
|
|
6b608e70ee | ||
|
|
a69a1af568 | ||
|
|
32b72555ee | ||
|
|
32af6a2390 | ||
|
|
b470dd943f | ||
|
|
69ca977aed | ||
|
|
728a6349b7 | ||
|
|
ec32174abc | ||
|
|
2172cd234a | ||
|
|
0425ac9ad0 | ||
|
|
367558bb21 | ||
|
|
186e7b5ca4 | ||
|
|
2197704693 | ||
|
|
229eb8715d | ||
|
|
1b18a06f8c | ||
|
|
91b513798e | ||
|
|
25234e510a | ||
|
|
d16eac5704 | ||
|
|
46bff47975 | ||
|
|
f718b50b3f | ||
|
|
58b7d0f5d2 | ||
|
|
30d4581be5 | ||
|
|
83387f957f | ||
|
|
f3620bbbad | ||
|
|
b45933d30d | ||
|
|
1613ed556d | ||
|
|
8f5b7b65eb | ||
|
|
053f72c671 | ||
|
|
63a8f333b8 | ||
|
|
57fd8e3187 | ||
|
|
03972b16c9 | ||
|
|
ac7ed82585 | ||
|
|
196c2e9c1f | ||
|
|
1accbcb98b | ||
|
|
342ae10f08 | ||
|
|
eb98a780ed | ||
|
|
64233fa3bb | ||
|
|
cbf5cf4ac3 | ||
|
|
a3f3f9cb76 | ||
|
|
5aeae08be0 | ||
|
|
64a658acaa | ||
|
|
361940a5d7 | ||
|
|
2721cbc8ee |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -3,7 +3,7 @@
|
||||
.*
|
||||
*.swp
|
||||
*~$
|
||||
obj
|
||||
cscope.*
|
||||
tags
|
||||
build
|
||||
/build
|
||||
/obj*
|
||||
|
||||
@@ -8,7 +8,7 @@ set(APPLICATION_NAME ${PROJECT_NAME})
|
||||
|
||||
set(APPLICATION_VERSION_MAJOR "0")
|
||||
set(APPLICATION_VERSION_MINOR "7")
|
||||
set(APPLICATION_VERSION_PATCH "0")
|
||||
set(APPLICATION_VERSION_PATCH "7")
|
||||
|
||||
set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}")
|
||||
|
||||
@@ -19,12 +19,12 @@ set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINO
|
||||
# Increment AGE. Set REVISION to 0
|
||||
# If the source code was changed, but there were no interface changes:
|
||||
# Increment REVISION.
|
||||
set(LIBRARY_VERSION "4.4.0")
|
||||
set(LIBRARY_VERSION "4.4.4")
|
||||
set(LIBRARY_SOVERSION "4")
|
||||
|
||||
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
|
||||
set(CMAKE_MODULE_PATH
|
||||
${CMAKE_SOURCE_DIR}/cmake/Modules
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules
|
||||
)
|
||||
|
||||
# add definitions
|
||||
@@ -84,8 +84,8 @@ add_subdirectory(include)
|
||||
add_subdirectory(src)
|
||||
|
||||
# pkg-config file
|
||||
if (UNIX)
|
||||
configure_file(libssh.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libssh.pc)
|
||||
configure_file(libssh_threads.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libssh_threads.pc)
|
||||
install(
|
||||
FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/libssh.pc
|
||||
@@ -96,6 +96,20 @@ install(
|
||||
pkgconfig
|
||||
)
|
||||
|
||||
if (LIBSSH_THREADS)
|
||||
configure_file(libssh_threads.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libssh_threads.pc)
|
||||
install(
|
||||
FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/libssh.pc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/libssh_threads.pc
|
||||
DESTINATION
|
||||
${LIB_INSTALL_DIR}/pkgconfig
|
||||
COMPONENT
|
||||
pkgconfig
|
||||
)
|
||||
endif (LIBSSH_THREADS)
|
||||
endif (UNIX)
|
||||
|
||||
# cmake config files
|
||||
set(LIBSSH_LIBRARY_NAME ${CMAKE_SHARED_LIBRARY_PREFIX}ssh${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||
set(LIBSSH_THREADS_LIBRARY_NAME ${CMAKE_SHARED_LIBRARY_PREFIX}ssh${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
### general settings
|
||||
set(CPACK_PACKAGE_NAME ${APPLICATION_NAME})
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "The SSH library")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README")
|
||||
set(CPACK_PACKAGE_VENDOR "The SSH Library Development Team")
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY ${CPACK_PACKAGE_NAME})
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING")
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING")
|
||||
|
||||
|
||||
### versions
|
||||
@@ -18,8 +18,8 @@ set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSIO
|
||||
|
||||
|
||||
### source generator
|
||||
set(CPACK_SOURCE_GENERATOR "TGZ")
|
||||
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]svn/;/[.]git/;.gitignore;/build/;/obj/;tags;cscope.*")
|
||||
set(CPACK_SOURCE_GENERATOR "TXZ")
|
||||
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]git/;.gitignore;/build*;/obj*;tags;cscope.*")
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
|
||||
|
||||
if (WIN32)
|
||||
|
||||
48
ChangeLog
48
ChangeLog
@@ -1,7 +1,53 @@
|
||||
ChangeLog
|
||||
==========
|
||||
|
||||
version 0.7.0 (released 2015-05-xx)
|
||||
version 0.7.7 (released 2018-10-29)
|
||||
* 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 a memory leak with OpenSSL
|
||||
|
||||
version 0.7.6 (released 2018-10-16)
|
||||
* Fixed CVE-2018-10933
|
||||
* Added support for OpenSSL 1.1
|
||||
* Added SHA256 support for ssh_get_publickey_hash()
|
||||
* Fixed config parsing
|
||||
* Fixed random memory corruption when importing pubkeys
|
||||
|
||||
version 0.7.5 (released 2017-04-13)
|
||||
* Fixed a memory allocation issue with buffers
|
||||
* Fixed PKI on Windows
|
||||
* Fixed some SSHv1 functions
|
||||
* Fixed config hostname expansion
|
||||
|
||||
version 0.7.4 (released 2017-02-03)
|
||||
* Added id_ed25519 to the default identity list
|
||||
* Fixed sftp EOF packet handling
|
||||
* Fixed ssh_send_banner() to confirm with RFC 4253
|
||||
* Fixed some memory leaks
|
||||
|
||||
version 0.7.3 (released 2016-01-23)
|
||||
* Fixed CVE-2016-0739
|
||||
* Fixed ssh-agent on big endian
|
||||
* Fixed some documentation issues
|
||||
|
||||
version 0.7.2 (released 2015-09-15)
|
||||
* Fixed OpenSSL detection on Windows
|
||||
* Fixed return status for ssh_userauth_agent()
|
||||
* Fixed KEX to prefer hmac-sha2-256
|
||||
* Fixed sftp packet handling
|
||||
* Fixed return values of ssh_key_is_(public|private)
|
||||
* Fixed bug in global success reply
|
||||
|
||||
version 0.7.1 (released 2015-06-30)
|
||||
* Fixed SSH_AUTH_PARTIAL auth with auto public key
|
||||
* Fixed memory leak in session options
|
||||
* Fixed allocation of ed25519 public keys
|
||||
* Fixed channel exit-status and exit-signal
|
||||
* Reintroduce ssh_forward_listen()
|
||||
|
||||
version 0.7.0 (released 2015-05-11)
|
||||
* Added support for ed25519 keys
|
||||
* Added SHA2 algorithms for HMAC
|
||||
* Added improved and more secure buffer handling code
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
include(CheckIncludeFile)
|
||||
include(CheckIncludeFiles)
|
||||
include(CheckSymbolExists)
|
||||
include(CheckFunctionExists)
|
||||
include(CheckLibraryExists)
|
||||
@@ -56,6 +57,7 @@ check_include_file(libutil.h HAVE_LIBUTIL_H)
|
||||
check_include_file(sys/time.h HAVE_SYS_TIME_H)
|
||||
check_include_file(sys/param.h HAVE_SYS_PARAM_H)
|
||||
check_include_file(arpa/inet.h HAVE_ARPA_INET_H)
|
||||
check_include_file(byteswap.h HAVE_BYTESWAP_H)
|
||||
|
||||
if (WIN32)
|
||||
check_include_files("winsock2.h;ws2tcpip.h;wspiapi.h" HAVE_WSPIAPI_H)
|
||||
@@ -65,23 +67,35 @@ if (WIN32)
|
||||
check_include_files("winsock2.h;ws2tcpip.h" HAVE_WS2TCPIP_H)
|
||||
endif (WIN32)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIRS})
|
||||
check_include_file(openssl/aes.h HAVE_OPENSSL_AES_H)
|
||||
if (OPENSSL_FOUND)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
check_include_file(openssl/des.h HAVE_OPENSSL_DES_H)
|
||||
if (NOT HAVE_OPENSSL_DES_H)
|
||||
message(FATAL_ERROR "Could not detect openssl/des.h")
|
||||
endif()
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIRS})
|
||||
check_include_file(openssl/blowfish.h HAVE_OPENSSL_BLOWFISH_H)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
check_include_file(openssl/aes.h HAVE_OPENSSL_AES_H)
|
||||
if (NOT HAVE_OPENSSL_AES_H)
|
||||
message(FATAL_ERROR "Could not detect openssl/aes.h")
|
||||
endif()
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIRS})
|
||||
check_include_file(openssl/des.h HAVE_OPENSSL_DES_H)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
check_include_file(openssl/blowfish.h HAVE_OPENSSL_BLOWFISH_H)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIRS})
|
||||
check_include_file(openssl/ecdh.h HAVE_OPENSSL_ECDH_H)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
check_include_file(openssl/ecdh.h HAVE_OPENSSL_ECDH_H)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIRS})
|
||||
check_include_file(openssl/ec.h HAVE_OPENSSL_EC_H)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
check_include_file(openssl/ec.h HAVE_OPENSSL_EC_H)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIRS})
|
||||
check_include_file(openssl/ecdsa.h HAVE_OPENSSL_ECDSA_H)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
check_include_file(openssl/ecdsa.h HAVE_OPENSSL_ECDSA_H)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_function_exists(CRYPTO_ctr128_encrypt HAVE_OPENSSL_CRYPTO_CTR128_ENCRYPT)
|
||||
endif()
|
||||
|
||||
if (CMAKE_HAVE_PTHREAD_H)
|
||||
set(HAVE_PTHREAD_H 1)
|
||||
@@ -101,16 +115,22 @@ endif (NOT WITH_GCRYPT)
|
||||
|
||||
check_function_exists(isblank HAVE_ISBLANK)
|
||||
check_function_exists(strncpy HAVE_STRNCPY)
|
||||
check_function_exists(vsnprintf HAVE_VSNPRINTF)
|
||||
check_function_exists(snprintf HAVE_SNPRINTF)
|
||||
check_function_exists(strndup HAVE_STRNDUP)
|
||||
check_function_exists(strtoull HAVE_STRTOULL)
|
||||
|
||||
if (NOT WIN32)
|
||||
check_function_exists(vsnprintf HAVE_VSNPRINTF)
|
||||
check_function_exists(snprintf HAVE_SNPRINTF)
|
||||
endif (NOT WIN32)
|
||||
|
||||
if (WIN32)
|
||||
check_function_exists(_strtoui64 HAVE__STRTOUI64)
|
||||
check_symbol_exists(vsnprintf "stdio.h" HAVE_VSNPRINTF)
|
||||
check_symbol_exists(snprintf "stdio.h" HAVE_SNPRINTF)
|
||||
|
||||
check_function_exists(_vsnprintf_s HAVE__VSNPRINTF_S)
|
||||
check_function_exists(_vsnprintf HAVE__VSNPRINTF)
|
||||
check_function_exists(_snprintf HAVE__SNPRINTF)
|
||||
check_function_exists(_snprintf_s HAVE__SNPRINTF_S)
|
||||
check_symbol_exists(_vsnprintf_s "stdio.h" HAVE__VSNPRINTF_S)
|
||||
check_symbol_exists(_vsnprintf "stdio.h" HAVE__VSNPRINTF)
|
||||
check_symbol_exists(_snprintf "stdio.h" HAVE__SNPRINTF)
|
||||
check_symbol_exists(_snprintf_s "stdio.h" HAVE__SNPRINTF_S)
|
||||
|
||||
if (HAVE_WSPIAPI_H OR HAVE_WS2TCPIP_H)
|
||||
check_symbol_exists(ntohll winsock2.h HAVE_NTOHLL)
|
||||
@@ -124,6 +144,8 @@ if (WIN32)
|
||||
set(CMAKE_REQUIRED_LIBRARIES)
|
||||
endif (HAVE_WSPIAPI_H OR HAVE_WS2TCPIP_H)
|
||||
|
||||
check_function_exists(_strtoui64 HAVE__STRTOUI64)
|
||||
|
||||
set(HAVE_SELECT TRUE)
|
||||
else (WIN32)
|
||||
check_function_exists(poll HAVE_POLL)
|
||||
@@ -161,7 +183,6 @@ if (UNIX)
|
||||
|
||||
check_library_exists(util forkpty "" HAVE_LIBUTIL)
|
||||
check_function_exists(cfmakeraw HAVE_CFMAKERAW)
|
||||
check_function_exists(strtoull HAVE_STRTOULL)
|
||||
check_function_exists(__strtoull HAVE___STRTOULL)
|
||||
endif (UNIX)
|
||||
|
||||
|
||||
125
README
125
README
@@ -33,130 +33,11 @@ If you ask yourself how to compile libssh, please read INSTALL before anything.
|
||||
|
||||
http://www.libssh.org
|
||||
|
||||
4* API Changes !
|
||||
4* Contributing
|
||||
-_-_-_-_-_-_-_-_-_
|
||||
|
||||
Changes between 0.4 and 0.5
|
||||
---------------------------
|
||||
|
||||
We use the ssh_ prefix as namespace for every function now. There is a legacy.h
|
||||
which could be used to get the old function names.
|
||||
|
||||
Changes between 0.3 and 0.4
|
||||
---------------------------
|
||||
|
||||
We changed libssh to be typesafe now:
|
||||
|
||||
SSH_SESSION *session -> ssh_session session
|
||||
SFTP_SESSION *sftp -> sftp_session sftp
|
||||
CHANNEL *channel -> ssh_channel channel
|
||||
STRING *string -> ssh_string string
|
||||
...
|
||||
|
||||
The options structure has been removed and there is a new function. This
|
||||
function can set all available options now. You can find the enum in the
|
||||
header file and it is documented. Example:
|
||||
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
|
||||
5* Copyright policy
|
||||
-_-_-_-_-_-_-_-_-_-_
|
||||
|
||||
libssh is a project with distributed copyright ownership, which means we prefer
|
||||
the copyright on parts of libssh to be held by individuals rather than
|
||||
corporations if possible. There are historical legal reasons for this, but one
|
||||
of the best ways to explain it is that it’s much easier to work with
|
||||
individuals who have ownership than corporate legal departments if we ever need
|
||||
to make reasonable compromises with people using and working with libssh.
|
||||
|
||||
We track the ownership of every part of libssh via git, our source code control
|
||||
system, so we know the provenance of every piece of code that is committed to
|
||||
libssh.
|
||||
|
||||
So if possible, if you’re doing libssh changes on behalf of a company who
|
||||
normally owns all the work you do please get them to assign personal copyright
|
||||
ownership of your changes to you as an individual, that makes things very easy
|
||||
for us to work with and avoids bringing corporate legal departments into the
|
||||
picture.
|
||||
|
||||
If you can’t do this we can still accept patches from you owned by your
|
||||
employer under a standard employment contract with corporate copyright
|
||||
ownership. It just requires a simple set-up process first.
|
||||
|
||||
We use a process very similar to the way things are done in the Linux Kernel
|
||||
community, so it should be very easy to get a sign off from your corporate
|
||||
legal department. The only changes we’ve made are to accommodate the license we
|
||||
use, which is LGPLv2 (or later) whereas the Linux kernel uses GPLv2.
|
||||
|
||||
The process is called signing.
|
||||
|
||||
How to sign your work
|
||||
----------------------
|
||||
|
||||
Once you have permission to contribute to libssh from your employer, simply
|
||||
email a copy of the following text from your corporate email address to:
|
||||
|
||||
contributing@libssh.org
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
libssh Developer's Certificate of Origin. Version 1.0
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the appropriate
|
||||
version of the GNU General Public License; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best of
|
||||
my knowledge, is covered under an appropriate open source license
|
||||
and I have the right under that license to submit that work with
|
||||
modifications, whether created in whole or in part by me, under
|
||||
the GNU General Public License, in the appropriate version; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other
|
||||
person who certified (a) or (b) and I have not modified it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution are
|
||||
public and that a record of the contribution (including all
|
||||
metadata and personal information I submit with it, including my
|
||||
sign-off) is maintained indefinitely and may be redistributed
|
||||
consistent with the libssh Team's policies and the requirements of
|
||||
the GNU GPL where they are relevant.
|
||||
|
||||
(e) I am granting this work to this project 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 the option of the project) any later version.
|
||||
|
||||
http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
We will maintain a copy of that email as a record that you have the rights to
|
||||
contribute code to libssh under the required licenses whilst working for the
|
||||
company where the email came from.
|
||||
|
||||
Then when sending in a patch via the normal mechanisms described above, add a
|
||||
line that states:
|
||||
|
||||
|
||||
Signed-off-by: Random J Developer <random@developer.example.org>
|
||||
|
||||
|
||||
using your real name and the email address you sent the original email you used
|
||||
to send the libssh Developer’s Certificate of Origin to us (sorry, no
|
||||
pseudonyms or anonymous contributions.)
|
||||
|
||||
That’s it! Such code can then quite happily contain changes that have copyright
|
||||
messages such as:
|
||||
|
||||
|
||||
(c) Example Corporation.
|
||||
|
||||
|
||||
and can be merged into the libssh codebase in the same way as patches from any
|
||||
other individual. You don’t need to send in a copy of the libssh Developer’s
|
||||
Certificate of Origin for each patch, or inside each patch. Just the sign-off
|
||||
message is all that is required once we’ve received the initial email.
|
||||
Please read the file 'SubmittingPatches' next to this README file. It explains
|
||||
our copyright policy and how you should send patches for upstream inclusion.
|
||||
|
||||
Have fun and happy libssh hacking!
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ find_path(GCRYPT_INCLUDE_DIR
|
||||
gcrypt.h
|
||||
HINTS
|
||||
${_GCRYPT_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
include
|
||||
)
|
||||
|
||||
find_library(GCRYPT_LIBRARY
|
||||
@@ -44,6 +46,8 @@ find_library(GCRYPT_LIBRARY
|
||||
libgcrypt-11
|
||||
HINTS
|
||||
${_GCRYPT_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
)
|
||||
set(GCRYPT_LIBRARIES ${GCRYPT_LIBRARY})
|
||||
|
||||
|
||||
@@ -76,6 +76,9 @@
|
||||
|
||||
/*************************** FUNCTIONS ***************************/
|
||||
|
||||
/* Define to 1 if you have the `CRYPTO_ctr128_encrypt' function. */
|
||||
#cmakedefine HAVE_OPENSSL_CRYPTO_CTR128_ENCRYPT 1
|
||||
|
||||
/* Define to 1 if you have the `snprintf' function. */
|
||||
#cmakedefine HAVE_SNPRINTF 1
|
||||
|
||||
@@ -100,6 +103,9 @@
|
||||
/* Define to 1 if you have the `strncpy' function. */
|
||||
#cmakedefine HAVE_STRNCPY 1
|
||||
|
||||
/* Define to 1 if you have the `strndup' function. */
|
||||
#cmakedefine HAVE_STRNDUP 1
|
||||
|
||||
/* Define to 1 if you have the `cfmakeraw' function. */
|
||||
#cmakedefine HAVE_CFMAKERAW 1
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ If an error has been encountered, it returns a negative value:
|
||||
|
||||
@code
|
||||
char buffer[256];
|
||||
unsigned int nbytes;
|
||||
int nbytes;
|
||||
|
||||
nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
|
||||
while (nbytes > 0)
|
||||
|
||||
@@ -367,7 +367,7 @@ int show_remote_processes(ssh_session session)
|
||||
ssh_channel channel;
|
||||
int rc;
|
||||
char buffer[256];
|
||||
unsigned int nbytes;
|
||||
int nbytes;
|
||||
|
||||
channel = ssh_channel_new(session);
|
||||
if (channel == NULL)
|
||||
@@ -391,7 +391,7 @@ int show_remote_processes(ssh_session session)
|
||||
nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
|
||||
while (nbytes > 0)
|
||||
{
|
||||
if (write(1, buffer, nbytes) != nbytes)
|
||||
if (write(1, buffer, nbytes) != (unsigned int) nbytes)
|
||||
{
|
||||
ssh_channel_close(channel);
|
||||
ssh_channel_free(channel);
|
||||
|
||||
@@ -253,7 +253,7 @@ int sftp_read_sync(ssh_session session, sftp_session sftp)
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
nwritten = write(fd, buf, nbytes);
|
||||
nwritten = write(fd, buffer, nbytes);
|
||||
if (nwritten != nbytes) {
|
||||
fprintf(stderr, "Error writing: %s\n",
|
||||
strerror(errno));
|
||||
@@ -282,7 +282,7 @@ sftp_async_read() waits for the data to come. To open a file in nonblocking mode
|
||||
call sftp_file_set_nonblocking() right after you opened it. Default is blocking mode.
|
||||
|
||||
The example below reads a very big file in asynchronous, nonblocking, mode. Each
|
||||
time the data are not ready yet, a counter is incrementer.
|
||||
time the data is not ready yet, a counter is incremented.
|
||||
|
||||
@code
|
||||
// Good chunk size
|
||||
|
||||
@@ -23,6 +23,7 @@ clients must be made or how a client should react.
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define SSHD_USER "libssh"
|
||||
#define SSHD_PASSWORD "libssh"
|
||||
@@ -36,6 +37,7 @@ clients must be made or how a client should react.
|
||||
#endif
|
||||
|
||||
static int port = 22;
|
||||
static bool authenticated = false;
|
||||
|
||||
#ifdef WITH_PCAP
|
||||
static const char *pcap_file = "debug.server.pcap";
|
||||
@@ -61,11 +63,20 @@ static void cleanup_pcap(void) {
|
||||
#endif
|
||||
|
||||
|
||||
static int auth_password(const char *user, const char *password){
|
||||
if(strcmp(user, SSHD_USER))
|
||||
static int auth_password(const char *user, const char *password)
|
||||
{
|
||||
int cmp;
|
||||
|
||||
cmp = strcmp(user, SSHD_USER);
|
||||
if (cmp != 0) {
|
||||
return 0;
|
||||
if(strcmp(password, SSHD_PASSWORD))
|
||||
}
|
||||
cmp = strcmp(password, SSHD_PASSWORD);
|
||||
if (cmp != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
authenticated = true;
|
||||
return 1; // authenticated
|
||||
}
|
||||
#ifdef HAVE_ARGP_H
|
||||
@@ -200,6 +211,7 @@ static int kbdint_check_response(ssh_session session) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
authenticated = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -328,7 +340,7 @@ int main(int argc, char **argv){
|
||||
|
||||
/* proceed to authentication */
|
||||
auth = authenticate(session);
|
||||
if(!auth){
|
||||
if (!auth || !authenticated) {
|
||||
printf("Authentication error: %s\n", ssh_get_error(session));
|
||||
ssh_disconnect(session);
|
||||
return 1;
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
project(headers C)
|
||||
project(libssh-headers-x C)
|
||||
|
||||
add_subdirectory(libssh)
|
||||
|
||||
@@ -90,6 +90,14 @@ enum ssh_auth_state_e {
|
||||
SSH_AUTH_STATE_GSSAPI_TOKEN,
|
||||
/** We have sent the MIC and expecting to be authenticated */
|
||||
SSH_AUTH_STATE_GSSAPI_MIC_SENT,
|
||||
/** We have offered a pubkey to check if it is supported */
|
||||
SSH_AUTH_STATE_PUBKEY_OFFER_SENT,
|
||||
/** We have sent pubkey and signature expecting to be authenticated */
|
||||
SSH_AUTH_STATE_PUBKEY_AUTH_SENT,
|
||||
/** We have sent a password expecting to be authenticated */
|
||||
SSH_AUTH_STATE_PASSWORD_AUTH_SENT,
|
||||
/** We have sent a request without auth information (method 'none') */
|
||||
SSH_AUTH_STATE_AUTH_NONE_SENT,
|
||||
};
|
||||
|
||||
/** @internal
|
||||
|
||||
@@ -53,6 +53,8 @@ int buffer_add_u32(ssh_buffer buffer, uint32_t data);
|
||||
int buffer_add_u64(ssh_buffer buffer, uint64_t data);
|
||||
int ssh_buffer_add_data(ssh_buffer buffer, const void *data, uint32_t len);
|
||||
|
||||
int ssh_buffer_validate_length(struct ssh_buffer_struct *buffer, size_t len);
|
||||
|
||||
int ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
|
||||
const char *format,
|
||||
int argc,
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
#else /* _MSC_VER */
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -78,7 +79,7 @@
|
||||
/* libssh version */
|
||||
#define LIBSSH_VERSION_MAJOR 0
|
||||
#define LIBSSH_VERSION_MINOR 7
|
||||
#define LIBSSH_VERSION_MICRO 0
|
||||
#define LIBSSH_VERSION_MICRO 7
|
||||
|
||||
#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \
|
||||
LIBSSH_VERSION_MINOR, \
|
||||
@@ -443,7 +444,8 @@ LIBSSH_API int ssh_get_publickey(ssh_session session, ssh_key *key);
|
||||
|
||||
enum ssh_publickey_hash_type {
|
||||
SSH_PUBLICKEY_HASH_SHA1,
|
||||
SSH_PUBLICKEY_HASH_MD5
|
||||
SSH_PUBLICKEY_HASH_MD5,
|
||||
SSH_PUBLICKEY_HASH_SHA256
|
||||
};
|
||||
LIBSSH_API int ssh_get_publickey_hash(const ssh_key key,
|
||||
enum ssh_publickey_hash_type type,
|
||||
@@ -562,6 +564,10 @@ LIBSSH_API int ssh_pki_export_pubkey_file(const ssh_key key,
|
||||
|
||||
LIBSSH_API const char *ssh_pki_key_ecdsa_name(const ssh_key key);
|
||||
|
||||
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);
|
||||
@@ -588,6 +594,7 @@ LIBSSH_API int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socke
|
||||
fd_set *readfds, struct timeval *timeout);
|
||||
LIBSSH_API int ssh_service_request(ssh_session session, const char *service);
|
||||
LIBSSH_API int ssh_set_agent_channel(ssh_session session, ssh_channel channel);
|
||||
LIBSSH_API int ssh_set_agent_socket(ssh_session session, socket_t fd);
|
||||
LIBSSH_API void ssh_set_blocking(ssh_session session, int blocking);
|
||||
LIBSSH_API void ssh_set_counters(ssh_session session, ssh_counter scounter,
|
||||
ssh_counter rcounter);
|
||||
|
||||
@@ -33,15 +33,6 @@ int ssh_analyze_banner(ssh_session session, int server, int *ssh1, int *ssh2);
|
||||
int ssh_is_ipaddr_v4(const char *str);
|
||||
int ssh_is_ipaddr(const char *str);
|
||||
|
||||
#ifndef HAVE_NTOHLL
|
||||
/* macro for byte ordering */
|
||||
uint64_t ntohll(uint64_t);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_HTONLL
|
||||
#define htonll(x) ntohll((x))
|
||||
#endif
|
||||
|
||||
/* list processing */
|
||||
|
||||
struct ssh_list {
|
||||
|
||||
@@ -43,6 +43,12 @@ enum ssh_packet_state_e {
|
||||
PACKET_STATE_PROCESSING
|
||||
};
|
||||
|
||||
enum ssh_packet_filter_result_e {
|
||||
SSH_PACKET_UNKNOWN,
|
||||
SSH_PACKET_ALLOWED,
|
||||
SSH_PACKET_DENIED
|
||||
};
|
||||
|
||||
int packet_send(ssh_session session);
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
|
||||
@@ -43,6 +43,20 @@
|
||||
# endif
|
||||
#endif /* !defined(HAVE_STRTOULL) */
|
||||
|
||||
#if !defined(HAVE_STRNDUP)
|
||||
char *strndup(const char *s, size_t n);
|
||||
#endif /* ! HAVE_STRNDUP */
|
||||
|
||||
#ifdef HAVE_BYTESWAP_H
|
||||
#include <byteswap.h>
|
||||
#endif
|
||||
|
||||
#ifndef bswap_32
|
||||
#define bswap_32(x) \
|
||||
((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
|
||||
(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
/* Imitate define of inttypes.h */
|
||||
@@ -60,11 +74,16 @@
|
||||
|
||||
# ifdef _MSC_VER
|
||||
# include <stdio.h>
|
||||
# include <stdarg.h> /* va_copy define check */
|
||||
|
||||
/* On Microsoft compilers define inline to __inline on all others use inline */
|
||||
# undef inline
|
||||
# define inline __inline
|
||||
|
||||
# ifndef va_copy
|
||||
# define va_copy(dest, src) (dest = src)
|
||||
# endif
|
||||
|
||||
# define strcasecmp _stricmp
|
||||
# define strncasecmp _strnicmp
|
||||
# if ! defined(HAVE_ISBLANK)
|
||||
@@ -131,10 +150,10 @@ int gettimeofday(struct timeval *__p, void *__t);
|
||||
#define ERROR_BUFFERLEN 1024
|
||||
#endif
|
||||
#ifndef CLIENTBANNER1
|
||||
#define CLIENTBANNER1 "SSH-1.5-libssh-" SSH_STRINGIFY(LIBSSH_VERSION)
|
||||
#define CLIENTBANNER1 "SSH-1.5-libssh_" SSH_STRINGIFY(LIBSSH_VERSION)
|
||||
#endif
|
||||
#ifndef CLIENTBANNER2
|
||||
#define CLIENTBANNER2 "SSH-2.0-libssh-" SSH_STRINGIFY(LIBSSH_VERSION)
|
||||
#define CLIENTBANNER2 "SSH-2.0-libssh_" SSH_STRINGIFY(LIBSSH_VERSION)
|
||||
#endif
|
||||
#ifndef KBDINT_MAX_PROMPT
|
||||
#define KBDINT_MAX_PROMPT 256 /* more than openssh's :) */
|
||||
@@ -346,5 +365,25 @@ int match_hostname(const char *host, const char *pattern, unsigned int len);
|
||||
|
||||
#define CLOSE_SOCKET(s) do { if ((s) != SSH_INVALID_SOCKET) { _XCLOSESOCKET(s); (s) = SSH_INVALID_SOCKET;} } while(0)
|
||||
|
||||
#ifndef HAVE_HTONLL
|
||||
# ifdef WORDS_BIGENDIAN
|
||||
# define htonll(x) (x)
|
||||
# else
|
||||
# define htonll(x) \
|
||||
(((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_NTOHLL
|
||||
# ifdef WORDS_BIGENDIAN
|
||||
# define ntohll(x) (x)
|
||||
# else
|
||||
# define ntohll(x) \
|
||||
(((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
void ssh_agent_state_free(void *data);
|
||||
|
||||
#endif /* _LIBSSH_PRIV_H */
|
||||
/* vim: set ts=4 sw=4 et cindent: */
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
project(libssh-library C)
|
||||
|
||||
set(LIBSSH_PUBLIC_INCLUDE_DIRS
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
${libssh_SOURCE_DIR}/include
|
||||
CACHE INTERNAL "libssh public include directories"
|
||||
)
|
||||
|
||||
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
||||
${CMAKE_BINARY_DIR}
|
||||
${libssh_BINARY_DIR}
|
||||
)
|
||||
|
||||
set(LIBSSH_LINK_LIBRARIES
|
||||
@@ -54,7 +54,7 @@ endif (GCRYPT_LIBRARY)
|
||||
if (WITH_ZLIB)
|
||||
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
||||
${LIBSSH_PRIVATE_INCLUDE_DIRS}
|
||||
${ZLIB_INCLUDE_DIRS}
|
||||
${ZLIB_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
set(LIBSSH_LINK_LIBRARIES
|
||||
@@ -124,7 +124,6 @@ set(libssh_SRCS
|
||||
kex.c
|
||||
known_hosts.c
|
||||
legacy.c
|
||||
libcrypto.c
|
||||
log.c
|
||||
match.c
|
||||
messages.c
|
||||
@@ -163,7 +162,11 @@ else (WITH_GCRYPT)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
pki_crypto.c
|
||||
libcrypto.c
|
||||
)
|
||||
if(OPENSSL_VERSION VERSION_LESS "1.1.0")
|
||||
set(libssh_SRCS ${libssh_SRCS} libcrypto-compat.c)
|
||||
endif()
|
||||
endif (WITH_GCRYPT)
|
||||
|
||||
if (WITH_SFTP)
|
||||
@@ -300,6 +303,7 @@ if (WITH_STATIC_LIB)
|
||||
)
|
||||
endif (WITH_STATIC_LIB)
|
||||
|
||||
message(STATUS "Threads_FOUND=${Threads_FOUND}")
|
||||
if (Threads_FOUND)
|
||||
add_subdirectory(threads)
|
||||
endif (Threads_FOUND)
|
||||
|
||||
40
src/agent.c
40
src/agent.c
@@ -185,15 +185,32 @@ int ssh_set_agent_channel(ssh_session session, ssh_channel channel){
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/** @brief sets the SSH agent socket.
|
||||
* The SSH agent will be used to authenticate this client using
|
||||
* the given socket to communicate with the ssh-agent. The caller
|
||||
* is responsible for connecting to the socket prior to calling
|
||||
* this function.
|
||||
* @returns SSH_OK in case of success
|
||||
* SSH_ERROR in case of an error
|
||||
*/
|
||||
int ssh_set_agent_socket(ssh_session session, socket_t fd){
|
||||
if (!session)
|
||||
return SSH_ERROR;
|
||||
if (!session->agent){
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED, "Session has no active agent");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
ssh_socket_set_fd(session->agent->sock, fd);
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
void agent_close(struct ssh_agent_struct *agent) {
|
||||
if (agent == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getenv("SSH_AUTH_SOCK")) {
|
||||
ssh_socket_close(agent->sock);
|
||||
}
|
||||
ssh_socket_close(agent->sock);
|
||||
}
|
||||
|
||||
void agent_free(ssh_agent agent) {
|
||||
@@ -365,6 +382,9 @@ int ssh_agent_get_ident_count(struct ssh_session_struct *session) {
|
||||
ssh_buffer_free(reply);
|
||||
return -1;
|
||||
}
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
type = bswap_32(type);
|
||||
#endif
|
||||
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"Answer type: %d, expected answer: %d",
|
||||
@@ -375,7 +395,7 @@ int ssh_agent_get_ident_count(struct ssh_session_struct *session) {
|
||||
return 0;
|
||||
} else if (type != c2) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Bad authentication reply message type: %d", type);
|
||||
"Bad authentication reply message type: %u", type);
|
||||
ssh_buffer_free(reply);
|
||||
return -1;
|
||||
}
|
||||
@@ -490,8 +510,8 @@ ssh_string ssh_agent_sign_data(ssh_session session,
|
||||
ssh_buffer reply;
|
||||
ssh_string key_blob;
|
||||
ssh_string sig_blob;
|
||||
int type = SSH2_AGENT_FAILURE;
|
||||
int flags = 0;
|
||||
unsigned int type = 0;
|
||||
unsigned int flags = 0;
|
||||
uint32_t dlen;
|
||||
int rc;
|
||||
|
||||
@@ -555,13 +575,19 @@ ssh_string ssh_agent_sign_data(ssh_session session,
|
||||
ssh_buffer_free(reply);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
type = bswap_32(type);
|
||||
#endif
|
||||
|
||||
if (agent_failed(type)) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Agent reports failure in signing the key");
|
||||
ssh_buffer_free(reply);
|
||||
return NULL;
|
||||
} else if (type != SSH2_AGENT_SIGN_RESPONSE) {
|
||||
ssh_set_error(session, SSH_FATAL, "Bad authentication response: %d", type);
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Bad authentication response: %u",
|
||||
type);
|
||||
ssh_buffer_free(reply);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
92
src/auth.c
Normal file → Executable file
92
src/auth.c
Normal file → Executable file
@@ -85,6 +85,10 @@ static int ssh_auth_response_termination(void *user){
|
||||
case SSH_AUTH_STATE_GSSAPI_REQUEST_SENT:
|
||||
case SSH_AUTH_STATE_GSSAPI_TOKEN:
|
||||
case SSH_AUTH_STATE_GSSAPI_MIC_SENT:
|
||||
case SSH_AUTH_STATE_PUBKEY_AUTH_SENT:
|
||||
case SSH_AUTH_STATE_PUBKEY_OFFER_SENT:
|
||||
case SSH_AUTH_STATE_PASSWORD_AUTH_SENT:
|
||||
case SSH_AUTH_STATE_AUTH_NONE_SENT:
|
||||
return 0;
|
||||
default:
|
||||
return 1;
|
||||
@@ -137,6 +141,10 @@ static int ssh_userauth_get_response(ssh_session session) {
|
||||
case SSH_AUTH_STATE_GSSAPI_REQUEST_SENT:
|
||||
case SSH_AUTH_STATE_GSSAPI_TOKEN:
|
||||
case SSH_AUTH_STATE_GSSAPI_MIC_SENT:
|
||||
case SSH_AUTH_STATE_PUBKEY_OFFER_SENT:
|
||||
case SSH_AUTH_STATE_PUBKEY_AUTH_SENT:
|
||||
case SSH_AUTH_STATE_PASSWORD_AUTH_SENT:
|
||||
case SSH_AUTH_STATE_AUTH_NONE_SENT:
|
||||
case SSH_AUTH_STATE_NONE:
|
||||
/* not reached */
|
||||
rc = SSH_AUTH_ERROR;
|
||||
@@ -209,8 +217,8 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_failure){
|
||||
"Access denied. Authentication that can continue: %s",
|
||||
auth_methods);
|
||||
|
||||
session->auth_methods = 0;
|
||||
}
|
||||
session->auth_methods = 0;
|
||||
if (strstr(auth_methods, "password") != NULL) {
|
||||
session->auth_methods |= SSH_AUTH_METHOD_PASSWORD;
|
||||
}
|
||||
@@ -275,21 +283,27 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_success){
|
||||
SSH_PACKET_CALLBACK(ssh_packet_userauth_pk_ok){
|
||||
int rc;
|
||||
|
||||
SSH_LOG(SSH_LOG_TRACE, "Received SSH_USERAUTH_PK_OK/INFO_REQUEST/GSSAPI_RESPONSE");
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Received SSH_USERAUTH_PK_OK/INFO_REQUEST/GSSAPI_RESPONSE");
|
||||
|
||||
if(session->auth_state==SSH_AUTH_STATE_KBDINT_SENT){
|
||||
if (session->auth_state == SSH_AUTH_STATE_KBDINT_SENT) {
|
||||
/* Assuming we are in keyboard-interactive context */
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"keyboard-interactive context, assuming SSH_USERAUTH_INFO_REQUEST");
|
||||
rc=ssh_packet_userauth_info_request(session,type,packet,user);
|
||||
"keyboard-interactive context, "
|
||||
"assuming SSH_USERAUTH_INFO_REQUEST");
|
||||
rc = ssh_packet_userauth_info_request(session, type, packet, user);
|
||||
#ifdef WITH_GSSAPI
|
||||
} else if (session->auth_state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT){
|
||||
} else if (session->auth_state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT) {
|
||||
rc = ssh_packet_userauth_gssapi_response(session, type, packet, user);
|
||||
#endif
|
||||
} else if (session->auth_state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT) {
|
||||
session->auth_state = SSH_AUTH_STATE_PK_OK;
|
||||
SSH_LOG(SSH_LOG_TRACE, "Assuming SSH_USERAUTH_PK_OK");
|
||||
rc = SSH_PACKET_USED;
|
||||
} else {
|
||||
session->auth_state=SSH_AUTH_STATE_PK_OK;
|
||||
SSH_LOG(SSH_LOG_TRACE, "Assuming SSH_USERAUTH_PK_OK");
|
||||
rc=SSH_PACKET_USED;
|
||||
session->auth_state = SSH_AUTH_STATE_ERROR;
|
||||
SSH_LOG(SSH_LOG_TRACE, "SSH_USERAUTH_PK_OK received in wrong state");
|
||||
rc = SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
return rc;
|
||||
@@ -389,7 +403,7 @@ int ssh_userauth_none(ssh_session session, const char *username) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
session->auth_state = SSH_AUTH_STATE_NONE;
|
||||
session->auth_state = SSH_AUTH_STATE_AUTH_NONE_SENT;
|
||||
session->pending_call_state = SSH_PENDING_CALL_AUTH_NONE;
|
||||
rc = packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
@@ -501,7 +515,7 @@ int ssh_userauth_try_publickey(ssh_session session,
|
||||
|
||||
ssh_string_free(pubkey_s);
|
||||
|
||||
session->auth_state = SSH_AUTH_STATE_NONE;
|
||||
session->auth_state = SSH_AUTH_STATE_PUBKEY_OFFER_SENT;
|
||||
session->pending_call_state = SSH_PENDING_CALL_AUTH_OFFER_PUBKEY;
|
||||
rc = packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
@@ -622,7 +636,7 @@ int ssh_userauth_publickey(ssh_session session,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
session->auth_state = SSH_AUTH_STATE_NONE;
|
||||
session->auth_state = SSH_AUTH_STATE_PUBKEY_AUTH_SENT;
|
||||
session->pending_call_state = SSH_PENDING_CALL_AUTH_PUBKEY;
|
||||
rc = packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
@@ -706,7 +720,7 @@ static int ssh_userauth_agent_publickey(ssh_session session,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
session->auth_state = SSH_AUTH_STATE_NONE;
|
||||
session->auth_state = SSH_AUTH_STATE_PUBKEY_AUTH_SENT;
|
||||
session->pending_call_state = SSH_PENDING_CALL_AUTH_AGENT;
|
||||
rc = packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
@@ -740,6 +754,15 @@ struct ssh_agent_state_struct {
|
||||
char *comment;
|
||||
};
|
||||
|
||||
/* Internal function */
|
||||
void ssh_agent_state_free(void *data) {
|
||||
struct ssh_agent_state_struct *state = data;
|
||||
if (state) {
|
||||
ssh_string_free_char(state->comment);
|
||||
ssh_key_free(state->pubkey);
|
||||
free (state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Try to do public key authentication with ssh agent.
|
||||
@@ -786,6 +809,11 @@ int ssh_userauth_agent(ssh_session session,
|
||||
state = session->agent_state;
|
||||
if (state->pubkey == NULL)
|
||||
state->pubkey = ssh_agent_get_first_ident(session, &state->comment);
|
||||
|
||||
if (state->pubkey == NULL) {
|
||||
return SSH_AUTH_DENIED;
|
||||
}
|
||||
|
||||
while (state->pubkey != NULL) {
|
||||
if(state->state == SSH_AGENT_STATE_NONE){
|
||||
SSH_LOG(SSH_LOG_DEBUG,
|
||||
@@ -795,9 +823,8 @@ int ssh_userauth_agent(ssh_session session,
|
||||
state->state == SSH_AGENT_STATE_PUBKEY){
|
||||
rc = ssh_userauth_try_publickey(session, username, state->pubkey);
|
||||
if (rc == SSH_AUTH_ERROR) {
|
||||
ssh_string_free_char(state->comment);
|
||||
ssh_key_free(state->pubkey);
|
||||
SAFE_FREE(session->agent_state);
|
||||
ssh_agent_state_free (state);
|
||||
session->agent_state = NULL;
|
||||
return rc;
|
||||
} else if (rc == SSH_AUTH_AGAIN) {
|
||||
state->state = SSH_AGENT_STATE_PUBKEY;
|
||||
@@ -806,6 +833,7 @@ int ssh_userauth_agent(ssh_session session,
|
||||
SSH_LOG(SSH_LOG_DEBUG,
|
||||
"Public key of %s refused by server", state->comment);
|
||||
ssh_string_free_char(state->comment);
|
||||
state->comment = NULL;
|
||||
ssh_key_free(state->pubkey);
|
||||
state->pubkey = ssh_agent_get_next_ident(session, &state->comment);
|
||||
state->state = SSH_AGENT_STATE_NONE;
|
||||
@@ -821,23 +849,27 @@ int ssh_userauth_agent(ssh_session session,
|
||||
if (rc == SSH_AUTH_AGAIN)
|
||||
return rc;
|
||||
ssh_string_free_char(state->comment);
|
||||
ssh_key_free(state->pubkey);
|
||||
state->comment = NULL;
|
||||
if (rc == SSH_AUTH_ERROR) {
|
||||
SAFE_FREE(session->agent_state);
|
||||
ssh_agent_state_free (session->agent_state);
|
||||
session->agent_state = NULL;
|
||||
return rc;
|
||||
} else if (rc != SSH_AUTH_SUCCESS) {
|
||||
SSH_LOG(SSH_LOG_INFO,
|
||||
"Server accepted public key but refused the signature");
|
||||
ssh_key_free(state->pubkey);
|
||||
state->pubkey = ssh_agent_get_next_ident(session, &state->comment);
|
||||
state->state = SSH_AGENT_STATE_NONE;
|
||||
continue;
|
||||
}
|
||||
SAFE_FREE(session->agent_state);
|
||||
ssh_agent_state_free (session->agent_state);
|
||||
session->agent_state = NULL;
|
||||
return SSH_AUTH_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
SAFE_FREE(session->agent_state);
|
||||
ssh_agent_state_free (session->agent_state);
|
||||
session->agent_state = NULL;
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
@@ -1045,15 +1077,14 @@ int ssh_userauth_publickey_auto(ssh_session session,
|
||||
ssh_key_free(state->privkey);
|
||||
ssh_key_free(state->pubkey);
|
||||
SAFE_FREE(session->auth_auto_state);
|
||||
if (rc == SSH_AUTH_SUCCESS) {
|
||||
SSH_LOG(SSH_LOG_INFO,
|
||||
"Successfully authenticated using %s",
|
||||
privkey_file);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
if (rc == SSH_AUTH_ERROR) {
|
||||
return rc;
|
||||
} else if (rc == SSH_AUTH_SUCCESS) {
|
||||
SSH_LOG(SSH_LOG_INFO,
|
||||
"Successfully authenticated using %s",
|
||||
privkey_file);
|
||||
return rc;
|
||||
} else if (rc == SSH_AUTH_AGAIN){
|
||||
if (rc == SSH_AUTH_AGAIN){
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1146,7 +1177,7 @@ int ssh_userauth_password(ssh_session session,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
session->auth_state = SSH_AUTH_STATE_NONE;
|
||||
session->auth_state = SSH_AUTH_STATE_PASSWORD_AUTH_SENT;
|
||||
session->pending_call_state = SSH_PENDING_CALL_AUTH_OFFER_PUBKEY;
|
||||
rc = packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
@@ -1200,11 +1231,10 @@ int ssh_userauth_agent_pubkey(ssh_session session,
|
||||
ssh_kbdint ssh_kbdint_new(void) {
|
||||
ssh_kbdint kbd;
|
||||
|
||||
kbd = malloc(sizeof(struct ssh_kbdint_struct));
|
||||
kbd = calloc(1, sizeof(struct ssh_kbdint_struct));
|
||||
if (kbd == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ZERO_STRUCTP(kbd);
|
||||
|
||||
return kbd;
|
||||
}
|
||||
|
||||
15
src/auth1.c
15
src/auth1.c
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -117,6 +118,7 @@ static int send_username(ssh_session session, const char *username) {
|
||||
if (packet_send(session) == SSH_ERROR) {
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
return SSH_AUTH_AGAIN;
|
||||
pending:
|
||||
rc = wait_auth1_status(session);
|
||||
switch (rc){
|
||||
@@ -161,12 +163,14 @@ int ssh_userauth1_password(ssh_session session, const char *username,
|
||||
ssh_string pwd = NULL;
|
||||
int rc;
|
||||
|
||||
if (session->pending_call_state == SSH_PENDING_CALL_AUTH_PASSWORD) {
|
||||
goto pending;
|
||||
}
|
||||
|
||||
rc = send_username(session, username);
|
||||
if (rc != SSH_AUTH_DENIED) {
|
||||
return rc;
|
||||
}
|
||||
if (session->pending_call_state == SSH_PENDING_CALL_AUTH_PASSWORD)
|
||||
goto pending;
|
||||
/* we trick a bit here. A known flaw in SSH1 protocol is that it's
|
||||
* easy to guess password sizes.
|
||||
* not that sure ...
|
||||
@@ -219,8 +223,11 @@ int ssh_userauth1_password(ssh_session session, const char *username,
|
||||
}
|
||||
pending:
|
||||
rc = wait_auth1_status(session);
|
||||
if (rc != SSH_AUTH_AGAIN)
|
||||
session->pending_call_state = SSH_PENDING_CALL_NONE;
|
||||
if (rc == SSH_AUTH_ERROR && errno == EAGAIN) {
|
||||
/* Nothing to do */
|
||||
} else if (rc != SSH_AUTH_AGAIN) {
|
||||
session->pending_call_state = SSH_PENDING_CALL_NONE;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -103,5 +103,9 @@ void ssh_print_bignum(const char *which, bignum 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);
|
||||
#endif
|
||||
}
|
||||
|
||||
50
src/buffer.c
50
src/buffer.c
@@ -563,12 +563,15 @@ uint32_t buffer_pass_bytes_end(struct ssh_buffer_struct *buffer, uint32_t len){
|
||||
* @returns 0 if there is not enough data in buffer, len otherwise.
|
||||
*/
|
||||
uint32_t buffer_get_data(struct ssh_buffer_struct *buffer, void *data, uint32_t len){
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Check for a integer overflow first, then check if not enough data is in
|
||||
* the buffer.
|
||||
*/
|
||||
if (buffer->pos + len < len || buffer->pos + len > buffer->used) {
|
||||
return 0;
|
||||
rc = ssh_buffer_validate_length(buffer, len);
|
||||
if (rc != SSH_OK) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(data,buffer->data+buffer->pos,len);
|
||||
buffer->pos+=len;
|
||||
@@ -617,6 +620,24 @@ int buffer_get_u64(struct ssh_buffer_struct *buffer, uint64_t *data){
|
||||
return buffer_get_data(buffer,data,sizeof(uint64_t));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Valdiates that the given length can be obtained from the buffer.
|
||||
*
|
||||
* @param[in] buffer The buffer to read from.
|
||||
*
|
||||
* @param[in] len The length to be checked.
|
||||
*
|
||||
* @return SSH_OK if the length is valid, SSH_ERROR otherwise.
|
||||
*/
|
||||
int ssh_buffer_validate_length(struct ssh_buffer_struct *buffer, size_t len)
|
||||
{
|
||||
if (buffer->pos + len < len || buffer->pos + len > buffer->used) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
@@ -630,13 +651,15 @@ struct ssh_string_struct *buffer_get_ssh_string(struct ssh_buffer_struct *buffer
|
||||
uint32_t stringlen;
|
||||
uint32_t hostlen;
|
||||
struct ssh_string_struct *str = NULL;
|
||||
int rc;
|
||||
|
||||
if (buffer_get_u32(buffer, &stringlen) == 0) {
|
||||
return NULL;
|
||||
}
|
||||
hostlen = ntohl(stringlen);
|
||||
/* verify if there is enough space in buffer to get it */
|
||||
if (buffer->pos + hostlen < hostlen || buffer->pos + hostlen > buffer->used) {
|
||||
rc = ssh_buffer_validate_length(buffer, hostlen);
|
||||
if (rc != SSH_OK) {
|
||||
return NULL; /* it is indeed */
|
||||
}
|
||||
str = ssh_string_new(hostlen);
|
||||
@@ -867,11 +890,13 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
char **cstring;
|
||||
void **data;
|
||||
} o;
|
||||
size_t len, rlen;
|
||||
size_t len, rlen, max_len;
|
||||
uint32_t u32len;
|
||||
va_list ap_copy;
|
||||
int count;
|
||||
|
||||
max_len = ssh_buffer_get_len(buffer);
|
||||
|
||||
/* copy the argument list in case a rollback is needed */
|
||||
va_copy(ap_copy, ap);
|
||||
|
||||
@@ -921,10 +946,16 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
break;
|
||||
}
|
||||
len = ntohl(u32len);
|
||||
if (len > UINT_MAX - 1){
|
||||
if (len > max_len - 1) {
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_validate_length(buffer, len);
|
||||
if (rc != SSH_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
*o.cstring = malloc(len + 1);
|
||||
if (*o.cstring == NULL){
|
||||
rc = SSH_ERROR;
|
||||
@@ -942,6 +973,15 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
break;
|
||||
case 'P':
|
||||
len = va_arg(ap, size_t);
|
||||
if (len > max_len - 1) {
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_validate_length(buffer, len);
|
||||
if (rc != SSH_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
o.data = va_arg(ap, void **);
|
||||
count++;
|
||||
|
||||
@@ -170,6 +170,15 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf){
|
||||
"Received a CHANNEL_OPEN_CONFIRMATION for channel %d:%d",
|
||||
channel->local_channel,
|
||||
channel->remote_channel);
|
||||
|
||||
if (channel->state != SSH_CHANNEL_STATE_OPENING) {
|
||||
SSH_LOG(SSH_LOG_RARE,
|
||||
"SSH2_MSG_CHANNEL_OPEN_CONFIRMATION received in incorrect "
|
||||
"channel state %d",
|
||||
channel->state);
|
||||
goto error;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL,
|
||||
"Remote window : %lu, maxpacket : %lu",
|
||||
(long unsigned int) channel->remote_window,
|
||||
@@ -210,6 +219,14 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_fail){
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
if (channel->state != SSH_CHANNEL_STATE_OPENING) {
|
||||
SSH_LOG(SSH_LOG_RARE,
|
||||
"SSH2_MSG_CHANNEL_OPEN_FAILURE received in incorrect channel "
|
||||
"state %d",
|
||||
channel->state);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"Channel opening failure: channel %u error (%lu) %s",
|
||||
channel->local_channel,
|
||||
@@ -217,6 +234,9 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_fail){
|
||||
error);
|
||||
SAFE_FREE(error);
|
||||
channel->state=SSH_CHANNEL_STATE_OPEN_DENIED;
|
||||
|
||||
error:
|
||||
ssh_set_error(session, SSH_FATAL, "Invalid packet");
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
@@ -664,11 +684,9 @@ SSH_PACKET_CALLBACK(channel_rcv_request) {
|
||||
}
|
||||
|
||||
if (strcmp(request,"exit-status") == 0) {
|
||||
uint32_t exit_status = 0;
|
||||
|
||||
SAFE_FREE(request);
|
||||
rc = ssh_buffer_unpack(packet, "d", &exit_status);
|
||||
SSH_LOG(SSH_LOG_PACKET, "received exit-status %d", channel->exit_status);
|
||||
SAFE_FREE(request);
|
||||
rc = ssh_buffer_unpack(packet, "d", &channel->exit_status);
|
||||
SSH_LOG(SSH_LOG_PACKET, "received exit-status %d", channel->exit_status);
|
||||
|
||||
if(ssh_callbacks_exists(channel->callbacks, channel_exit_status_function)) {
|
||||
channel->callbacks->channel_exit_status_function(channel->session,
|
||||
@@ -714,7 +732,7 @@ SSH_PACKET_CALLBACK(channel_rcv_request) {
|
||||
|
||||
SAFE_FREE(request);
|
||||
|
||||
rc = ssh_buffer_unpack(packet, "sbs",
|
||||
rc = ssh_buffer_unpack(packet, "sbss",
|
||||
&sig, /* signal name */
|
||||
&core_dumped, /* core dumped */
|
||||
&errmsg, /* error message */
|
||||
@@ -1247,7 +1265,7 @@ static int channel_write_common(ssh_channel channel,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (channel->session->session_state == SSH_SESSION_STATE_ERROR) {
|
||||
if (session->session_state == SSH_SESSION_STATE_ERROR) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
#ifdef WITH_SSH1
|
||||
@@ -1278,7 +1296,7 @@ static int channel_write_common(ssh_channel channel,
|
||||
ssh_channel_waitwindow_termination,channel);
|
||||
if (rc == SSH_ERROR ||
|
||||
!ssh_channel_waitwindow_termination(channel) ||
|
||||
channel->session->session_state == SSH_SESSION_STATE_ERROR ||
|
||||
session->session_state == SSH_SESSION_STATE_ERROR ||
|
||||
channel->state == SSH_CHANNEL_STATE_CLOSED)
|
||||
goto out;
|
||||
continue;
|
||||
@@ -2205,6 +2223,11 @@ error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* DEPRECATED */
|
||||
int ssh_forward_listen(ssh_session session, const char *address, int port, int *bound_port) {
|
||||
return ssh_channel_listen_forward(session, address, port, bound_port);
|
||||
}
|
||||
|
||||
/* DEPRECATED */
|
||||
ssh_channel ssh_forward_accept(ssh_session session, int timeout_ms) {
|
||||
return ssh_channel_accept(session, SSH_CHANNEL_FORWARDED_TCPIP, timeout_ms, NULL);
|
||||
@@ -2272,6 +2295,7 @@ error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* DEPRECATED */
|
||||
int ssh_forward_cancel(ssh_session session, const char *address, int port) {
|
||||
return ssh_channel_cancel_forward(session, address, port);
|
||||
}
|
||||
@@ -2685,7 +2709,7 @@ int ssh_channel_read_timeout(ssh_channel channel,
|
||||
if (rc == SSH_ERROR){
|
||||
return rc;
|
||||
}
|
||||
if (channel->session->session_state == SSH_SESSION_STATE_ERROR){
|
||||
if (session->session_state == SSH_SESSION_STATE_ERROR){
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (channel->remote_eof && buffer_get_rest_len(stdbuf) == 0) {
|
||||
@@ -2750,7 +2774,7 @@ int ssh_channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count
|
||||
to_read = ssh_channel_poll(channel, is_stderr);
|
||||
|
||||
if (to_read <= 0) {
|
||||
if (channel->session->session_state == SSH_SESSION_STATE_ERROR){
|
||||
if (session->session_state == SSH_SESSION_STATE_ERROR){
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
|
||||
205
src/client.c
205
src/client.c
@@ -90,52 +90,74 @@ static void socket_callback_connected(int code, int errno_code, void *user){
|
||||
* @param user is a pointer to session
|
||||
* @returns Number of bytes processed, or zero if the banner is not complete.
|
||||
*/
|
||||
static int callback_receive_banner(const void *data, size_t len, void *user) {
|
||||
char *buffer = (char *)data;
|
||||
ssh_session session=(ssh_session) user;
|
||||
char *str = NULL;
|
||||
size_t i;
|
||||
int ret=0;
|
||||
static int callback_receive_banner(const void *data, size_t len, void *user)
|
||||
{
|
||||
char *buffer = (char *)data;
|
||||
ssh_session session=(ssh_session) user;
|
||||
char *str = NULL;
|
||||
size_t i;
|
||||
int ret=0;
|
||||
|
||||
if(session->session_state != SSH_SESSION_STATE_SOCKET_CONNECTED){
|
||||
ssh_set_error(session,SSH_FATAL,"Wrong state in callback_receive_banner : %d",session->session_state);
|
||||
if (session->session_state != SSH_SESSION_STATE_SOCKET_CONNECTED) {
|
||||
ssh_set_error(session,SSH_FATAL,
|
||||
"Wrong state in callback_receive_banner : %d",
|
||||
session->session_state);
|
||||
|
||||
return SSH_ERROR;
|
||||
}
|
||||
for(i=0;i<len;++i){
|
||||
#ifdef WITH_PCAP
|
||||
if(session->pcap_ctx && buffer[i] == '\n'){
|
||||
ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_IN,buffer,i+1,i+1);
|
||||
}
|
||||
#endif
|
||||
if(buffer[i]=='\r') {
|
||||
buffer[i]='\0';
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (buffer[i]=='\n') {
|
||||
buffer[i] = '\0';
|
||||
str = strdup(buffer);
|
||||
if (str == NULL) {
|
||||
return SSH_ERROR;
|
||||
for (i = 0; i < len; ++i) {
|
||||
#ifdef WITH_PCAP
|
||||
if (session->pcap_ctx && buffer[i] == '\n') {
|
||||
ssh_pcap_context_write(session->pcap_ctx,
|
||||
SSH_PCAP_DIR_IN,
|
||||
buffer,i+1,
|
||||
i+1);
|
||||
}
|
||||
/* number of bytes read */
|
||||
ret = i + 1;
|
||||
session->serverbanner = str;
|
||||
session->session_state=SSH_SESSION_STATE_BANNER_RECEIVED;
|
||||
SSH_LOG(SSH_LOG_PACKET,"Received banner: %s",str);
|
||||
session->ssh_connection_callback(session);
|
||||
#endif
|
||||
if (buffer[i] == '\r') {
|
||||
buffer[i] = '\0';
|
||||
}
|
||||
if (buffer[i] == '\n') {
|
||||
int cmp;
|
||||
|
||||
return ret;
|
||||
}
|
||||
if(i>127){
|
||||
/* Too big banner */
|
||||
session->session_state=SSH_SESSION_STATE_ERROR;
|
||||
ssh_set_error(session,SSH_FATAL,"Receiving banner: too large banner");
|
||||
buffer[i] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* The server MAY send other lines of data... */
|
||||
cmp = strncmp(buffer, "SSH-", 4);
|
||||
if (cmp == 0) {
|
||||
str = strdup(buffer);
|
||||
if (str == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
/* number of bytes read */
|
||||
ret = i + 1;
|
||||
session->serverbanner = str;
|
||||
session->session_state = SSH_SESSION_STATE_BANNER_RECEIVED;
|
||||
SSH_LOG(SSH_LOG_PACKET, "Received banner: %s", str);
|
||||
session->ssh_connection_callback(session);
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_DEBUG,
|
||||
"ssh_protocol_version_exchange: %s",
|
||||
buffer);
|
||||
ret = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* According to RFC 4253 the max banner length is 255 */
|
||||
if (i > 255) {
|
||||
/* Too big banner */
|
||||
session->session_state=SSH_SESSION_STATE_ERROR;
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Receiving banner: too large banner");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
@@ -147,46 +169,75 @@ static int callback_receive_banner(const void *data, size_t len, void *user) {
|
||||
*
|
||||
* @return 0 on success, < 0 on error.
|
||||
*/
|
||||
int ssh_send_banner(ssh_session session, int server) {
|
||||
const char *banner = NULL;
|
||||
char buffer[128] = {0};
|
||||
int err=SSH_ERROR;
|
||||
int ssh_send_banner(ssh_session session, int server)
|
||||
{
|
||||
const char *banner = NULL;
|
||||
const char *terminator = NULL;
|
||||
/* The maximum banner length is 255 for SSH2 */
|
||||
char buffer[256] = {0};
|
||||
size_t len;
|
||||
int rc = SSH_ERROR;
|
||||
|
||||
banner = session->version == 1 ? CLIENTBANNER1 : CLIENTBANNER2;
|
||||
banner = session->version == 1 ? CLIENTBANNER1 : CLIENTBANNER2;
|
||||
terminator = session->version == 1 ? "\n" : "\r\n";
|
||||
|
||||
if (server) {
|
||||
if(session->opts.custombanner == NULL){
|
||||
session->serverbanner = strdup(banner);
|
||||
if (server == 1) {
|
||||
if (session->opts.custombanner == NULL){
|
||||
len = strlen(banner);
|
||||
session->serverbanner = strdup(banner);
|
||||
if (session->serverbanner == NULL) {
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
len = strlen(session->opts.custombanner);
|
||||
session->serverbanner = malloc(len + 8 + 1);
|
||||
if(session->serverbanner == NULL) {
|
||||
goto end;
|
||||
}
|
||||
snprintf(session->serverbanner,
|
||||
len + 8 + 1,
|
||||
"SSH-2.0-%s",
|
||||
session->opts.custombanner);
|
||||
}
|
||||
|
||||
snprintf(buffer,
|
||||
sizeof(buffer),
|
||||
"%s%s",
|
||||
session->serverbanner,
|
||||
terminator);
|
||||
} else {
|
||||
session->serverbanner = malloc(strlen(session->opts.custombanner) + 9);
|
||||
if(!session->serverbanner)
|
||||
goto end;
|
||||
strcpy(session->serverbanner, "SSH-2.0-");
|
||||
strcat(session->serverbanner, session->opts.custombanner);
|
||||
}
|
||||
if (session->serverbanner == NULL) {
|
||||
goto end;
|
||||
}
|
||||
snprintf(buffer, 128, "%s\n", session->serverbanner);
|
||||
} else {
|
||||
session->clientbanner = strdup(banner);
|
||||
if (session->clientbanner == NULL) {
|
||||
goto end;
|
||||
}
|
||||
snprintf(buffer, 128, "%s\n", session->clientbanner);
|
||||
}
|
||||
session->clientbanner = strdup(banner);
|
||||
if (session->clientbanner == NULL) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (ssh_socket_write(session->socket, buffer, strlen(buffer)) == SSH_ERROR) {
|
||||
goto end;
|
||||
}
|
||||
/* SSH version 1 has a banner length of 128 only */
|
||||
len = session->version == 1 ? 128 : 0;
|
||||
|
||||
snprintf(buffer,
|
||||
sizeof(buffer) - len,
|
||||
"%s%s",
|
||||
session->clientbanner,
|
||||
terminator);
|
||||
}
|
||||
|
||||
rc = ssh_socket_write(session->socket, buffer, strlen(buffer));
|
||||
if (rc == SSH_ERROR) {
|
||||
goto end;
|
||||
}
|
||||
#ifdef WITH_PCAP
|
||||
if(session->pcap_ctx)
|
||||
ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT,buffer,strlen(buffer),strlen(buffer));
|
||||
if (session->pcap_ctx != NULL) {
|
||||
ssh_pcap_context_write(session->pcap_ctx,
|
||||
SSH_PCAP_DIR_OUT,
|
||||
buffer,
|
||||
strlen(buffer),
|
||||
strlen(buffer));
|
||||
}
|
||||
#endif
|
||||
err=SSH_OK;
|
||||
end:
|
||||
|
||||
return err;
|
||||
rc = SSH_OK;
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
@@ -335,7 +386,13 @@ static void ssh_client_connection_callback(ssh_session session){
|
||||
switch(session->session_state){
|
||||
case SSH_SESSION_STATE_NONE:
|
||||
case SSH_SESSION_STATE_CONNECTING:
|
||||
break;
|
||||
case SSH_SESSION_STATE_SOCKET_CONNECTED:
|
||||
/* If SSHv1 is disabled, we can send the banner immedietly */
|
||||
if (session->opts.ssh1 == 0) {
|
||||
ssh_set_fd_towrite(session);
|
||||
ssh_send_banner(session, 0);
|
||||
}
|
||||
break;
|
||||
case SSH_SESSION_STATE_BANNER_RECEIVED:
|
||||
if (session->serverbanner == NULL) {
|
||||
@@ -381,7 +438,9 @@ static void ssh_client_connection_callback(ssh_session session){
|
||||
#endif
|
||||
ssh_packet_set_default_callbacks(session);
|
||||
session->session_state=SSH_SESSION_STATE_INITIAL_KEX;
|
||||
ssh_send_banner(session, 0);
|
||||
if (session->opts.ssh1 == 1) {
|
||||
ssh_send_banner(session, 0);
|
||||
}
|
||||
set_status(session, 0.5f);
|
||||
break;
|
||||
case SSH_SESSION_STATE_INITIAL_KEX:
|
||||
|
||||
42
src/config.c
42
src/config.c
@@ -50,6 +50,8 @@ enum ssh_config_opcode_e {
|
||||
SOC_GSSAPISERVERIDENTITY,
|
||||
SOC_GSSAPICLIENTIDENTITY,
|
||||
SOC_GSSAPIDELEGATECREDENTIALS,
|
||||
|
||||
SOC_END /* Keep this one last in the list */
|
||||
};
|
||||
|
||||
struct ssh_config_keyword_table_s {
|
||||
@@ -185,7 +187,7 @@ static int ssh_config_get_yesno(char **str, int notfound) {
|
||||
}
|
||||
|
||||
static int ssh_config_parse_line(ssh_session session, const char *line,
|
||||
unsigned int count, int *parsing) {
|
||||
unsigned int count, int *parsing, int seen[]) {
|
||||
enum ssh_config_opcode_e opcode;
|
||||
const char *p;
|
||||
char *s, *x;
|
||||
@@ -216,32 +218,43 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
|
||||
}
|
||||
|
||||
opcode = ssh_config_get_opcode(keyword);
|
||||
if (*parsing == 1 && opcode != SOC_HOST) {
|
||||
if (seen[opcode] != 0) {
|
||||
return 0;
|
||||
}
|
||||
seen[opcode] = 1;
|
||||
}
|
||||
|
||||
switch (opcode) {
|
||||
case SOC_HOST:
|
||||
case SOC_HOST: {
|
||||
int ok = 0;
|
||||
|
||||
*parsing = 0;
|
||||
lowerhost = (session->opts.host) ? ssh_lowercase(session->opts.host) : NULL;
|
||||
for (p = ssh_config_get_str_tok(&s, NULL);
|
||||
p != NULL && p[0] != '\0';
|
||||
p = ssh_config_get_str_tok(&s, NULL)) {
|
||||
char *z = ssh_path_expand_escape(session, p);
|
||||
int ok;
|
||||
|
||||
if (z == NULL) {
|
||||
z = strdup(p);
|
||||
if (ok >= 0) {
|
||||
ok = match_hostname(lowerhost, p, strlen(p));
|
||||
if (ok < 0) {
|
||||
*parsing = 0;
|
||||
} else if (ok > 0) {
|
||||
*parsing = 1;
|
||||
}
|
||||
}
|
||||
ok = match_hostname(lowerhost, z, strlen(z));
|
||||
if (ok) {
|
||||
*parsing = 1;
|
||||
}
|
||||
free(z);
|
||||
}
|
||||
SAFE_FREE(lowerhost);
|
||||
break;
|
||||
}
|
||||
case SOC_HOSTNAME:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, p);
|
||||
char *z = ssh_path_expand_escape(session, p);
|
||||
if (z == NULL) {
|
||||
z = strdup(p);
|
||||
}
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, z);
|
||||
free(z);
|
||||
}
|
||||
break;
|
||||
case SOC_PORT:
|
||||
@@ -378,6 +391,7 @@ int ssh_config_parse_file(ssh_session session, const char *filename) {
|
||||
unsigned int count = 0;
|
||||
FILE *f;
|
||||
int parsing;
|
||||
int seen[SOC_END - SOC_UNSUPPORTED] = {0};
|
||||
|
||||
if ((f = fopen(filename, "r")) == NULL) {
|
||||
return 0;
|
||||
@@ -388,7 +402,7 @@ int ssh_config_parse_file(ssh_session session, const char *filename) {
|
||||
parsing = 1;
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
count++;
|
||||
if (ssh_config_parse_line(session, line, count, &parsing) < 0) {
|
||||
if (ssh_config_parse_line(session, line, count, &parsing, seen) < 0) {
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
|
||||
181
src/dh.c
181
src/dh.c
@@ -227,15 +227,21 @@ void ssh_crypto_finalize(void) {
|
||||
}
|
||||
|
||||
int dh_generate_x(ssh_session session) {
|
||||
int keysize;
|
||||
if (session->next_crypto->kex_type == SSH_KEX_DH_GROUP1_SHA1) {
|
||||
keysize = 1023;
|
||||
} else {
|
||||
keysize = 2047;
|
||||
}
|
||||
session->next_crypto->x = bignum_new();
|
||||
if (session->next_crypto->x == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
bignum_rand(session->next_crypto->x, 128);
|
||||
bignum_rand(session->next_crypto->x, keysize);
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
bignum_rand(session->next_crypto->x, 128, 0, -1);
|
||||
bignum_rand(session->next_crypto->x, keysize, -1, 0);
|
||||
#endif
|
||||
|
||||
/* not harder than this */
|
||||
@@ -248,15 +254,21 @@ int dh_generate_x(ssh_session session) {
|
||||
|
||||
/* used by server */
|
||||
int dh_generate_y(ssh_session session) {
|
||||
session->next_crypto->y = bignum_new();
|
||||
int keysize;
|
||||
if (session->next_crypto->kex_type == SSH_KEX_DH_GROUP1_SHA1) {
|
||||
keysize = 1023;
|
||||
} else {
|
||||
keysize = 2047;
|
||||
}
|
||||
session->next_crypto->y = bignum_new();
|
||||
if (session->next_crypto->y == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
bignum_rand(session->next_crypto->y, 128);
|
||||
bignum_rand(session->next_crypto->y, keysize);
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
bignum_rand(session->next_crypto->y, 128, 0, -1);
|
||||
bignum_rand(session->next_crypto->y, keysize, -1, 0);
|
||||
#endif
|
||||
|
||||
/* not harder than this */
|
||||
@@ -1027,6 +1039,29 @@ int ssh_get_publickey_hash(const ssh_key key,
|
||||
*hlen = SHA_DIGEST_LEN;
|
||||
}
|
||||
break;
|
||||
case SSH_PUBLICKEY_HASH_SHA256:
|
||||
{
|
||||
SHA256CTX ctx;
|
||||
|
||||
h = malloc(SHA256_DIGEST_LEN);
|
||||
if (h == NULL) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctx = sha256_init();
|
||||
if (ctx == NULL) {
|
||||
free(h);
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sha256_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
|
||||
sha256_final(h, ctx);
|
||||
|
||||
*hlen = SHA256_DIGEST_LEN;
|
||||
}
|
||||
break;
|
||||
case SSH_PUBLICKEY_HASH_MD5:
|
||||
{
|
||||
MD5CTX ctx;
|
||||
@@ -1062,6 +1097,38 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Convert a buffer into an unpadded base64 string.
|
||||
* The caller has to free the memory.
|
||||
*
|
||||
* @param hash What should be converted to a base64 string.
|
||||
*
|
||||
* @param len Length of the buffer to convert.
|
||||
*
|
||||
* @return The base64 string or NULL on error.
|
||||
*
|
||||
* @see ssh_string_free_char()
|
||||
*/
|
||||
static char *ssh_get_b64_unpadded(const unsigned char *hash, size_t len)
|
||||
{
|
||||
char *b64_padded = NULL;
|
||||
char *b64_unpadded = NULL;
|
||||
size_t k;
|
||||
|
||||
b64_padded = (char *)bin_to_base64(hash, (int)len);
|
||||
if (b64_padded == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
for (k = strlen(b64_padded); k != 0 && b64_padded[k-1] == '='; k--);
|
||||
|
||||
b64_unpadded = strndup(b64_padded, k);
|
||||
SAFE_FREE(b64_padded);
|
||||
|
||||
return b64_unpadded;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a buffer into a colon separated hex string.
|
||||
* The caller has to free the memory.
|
||||
@@ -1099,6 +1166,110 @@ char *ssh_get_hexa(const unsigned char *what, size_t len) {
|
||||
return hexa;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a hash as a human-readable hex- or base64-string.
|
||||
*
|
||||
* This gets an allocated fingerprint hash. It is a hex strings if the given
|
||||
* hash is a md5 sum. If it is a SHA sum, it will return an unpadded base64
|
||||
* strings. Either way, the output is prepended by the hash-type.
|
||||
*
|
||||
* @param type Which sort of hash is given.
|
||||
*
|
||||
* @param hash What should be converted to a base64 string.
|
||||
*
|
||||
* @param len Length of the buffer to convert.
|
||||
*
|
||||
* @return Returns the allocated fingerprint hash or NULL on error.
|
||||
*
|
||||
* @see ssh_string_free_char()
|
||||
*/
|
||||
char *ssh_get_fingerprint_hash(enum ssh_publickey_hash_type type,
|
||||
unsigned char *hash,
|
||||
size_t len)
|
||||
{
|
||||
const char *prefix = "UNKNOWN";
|
||||
char *fingerprint = NULL;
|
||||
char *str = NULL;
|
||||
size_t str_len;
|
||||
int rc;
|
||||
|
||||
switch (type) {
|
||||
case SSH_PUBLICKEY_HASH_SHA1:
|
||||
case SSH_PUBLICKEY_HASH_SHA256:
|
||||
fingerprint = ssh_get_b64_unpadded(hash, len);
|
||||
break;
|
||||
case SSH_PUBLICKEY_HASH_MD5:
|
||||
fingerprint = ssh_get_hexa(hash, len);
|
||||
break;
|
||||
}
|
||||
if (fingerprint == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case SSH_PUBLICKEY_HASH_MD5:
|
||||
prefix = "MD5";
|
||||
break;
|
||||
case SSH_PUBLICKEY_HASH_SHA1:
|
||||
prefix = "SHA1";
|
||||
break;
|
||||
case SSH_PUBLICKEY_HASH_SHA256:
|
||||
prefix = "SHA256";
|
||||
break;
|
||||
}
|
||||
|
||||
str_len = strlen(prefix);
|
||||
if (str_len + 1 + strlen(fingerprint) + 1 < str_len) {
|
||||
SAFE_FREE(fingerprint);
|
||||
return NULL;
|
||||
}
|
||||
str_len += 1 + strlen(fingerprint) + 1;
|
||||
|
||||
str = malloc(str_len);
|
||||
if (str == NULL) {
|
||||
SAFE_FREE(fingerprint);
|
||||
return NULL;
|
||||
}
|
||||
rc = snprintf(str, str_len, "%s:%s", prefix, fingerprint);
|
||||
SAFE_FREE(fingerprint);
|
||||
if (rc < 0 || rc < (int)(str_len - 1)) {
|
||||
SAFE_FREE(str);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print a hash as a human-readable hex- or base64-string.
|
||||
*
|
||||
* This function prints hex strings if the given hash is a md5 sum.
|
||||
* But prints unpadded base64 strings for sha sums.
|
||||
* Either way, the output is prepended by the hash-type.
|
||||
*
|
||||
* @param type Which sort of hash is given.
|
||||
*
|
||||
* @param hash What should be converted to a base64 string.
|
||||
*
|
||||
* @param len Length of the buffer to convert.
|
||||
*/
|
||||
void ssh_print_hash(enum ssh_publickey_hash_type type,
|
||||
unsigned char *hash,
|
||||
size_t len)
|
||||
{
|
||||
char *fingerprint = NULL;
|
||||
|
||||
fingerprint = ssh_get_fingerprint_hash(type,
|
||||
hash,
|
||||
len);
|
||||
if (fingerprint == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s\n", fingerprint);
|
||||
|
||||
SAFE_FREE(fingerprint);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print a buffer as colon separated hex string.
|
||||
*
|
||||
|
||||
113
src/gssapi.c
113
src/gssapi.c
@@ -120,6 +120,7 @@ static int ssh_gssapi_send_response(ssh_session session, ssh_string oid){
|
||||
ssh_set_error_oom(session);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
session->auth_state = SSH_AUTH_STATE_GSSAPI_TOKEN;
|
||||
|
||||
packet_send(session);
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
@@ -129,11 +130,53 @@ static int ssh_gssapi_send_response(ssh_session session, ssh_string oid){
|
||||
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
static void ssh_gssapi_log_error(int verb, const char *msg, int maj_stat){
|
||||
gss_buffer_desc buffer;
|
||||
OM_uint32 dummy, message_context;
|
||||
gss_display_status(&dummy,maj_stat,GSS_C_GSS_CODE, GSS_C_NO_OID, &message_context, &buffer);
|
||||
SSH_LOG(verb, "GSSAPI(%s): %s", msg, (const char *)buffer.value);
|
||||
static void ssh_gssapi_log_error(int verb,
|
||||
const char *msg,
|
||||
int maj_stat,
|
||||
int min_stat)
|
||||
{
|
||||
gss_buffer_desc msg_maj = {
|
||||
.length = 0,
|
||||
};
|
||||
gss_buffer_desc msg_min = {
|
||||
.length = 0,
|
||||
};
|
||||
OM_uint32 dummy_maj, dummy_min;
|
||||
OM_uint32 message_context = 0;
|
||||
|
||||
dummy_maj = gss_display_status(&dummy_min,
|
||||
maj_stat,
|
||||
GSS_C_GSS_CODE,
|
||||
GSS_C_NO_OID,
|
||||
&message_context,
|
||||
&msg_maj);
|
||||
if (dummy_maj != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
dummy_maj = gss_display_status(&dummy_min,
|
||||
min_stat,
|
||||
GSS_C_MECH_CODE,
|
||||
GSS_C_NO_OID,
|
||||
&message_context,
|
||||
&msg_min);
|
||||
if (dummy_maj != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
SSH_LOG(verb,
|
||||
"GSSAPI(%s): %s - %s",
|
||||
msg,
|
||||
(const char *)msg_maj.value,
|
||||
(const char *)msg_min.value);
|
||||
|
||||
out:
|
||||
if (msg_maj.value) {
|
||||
dummy_maj = gss_release_buffer(&dummy_min, &msg_maj);
|
||||
}
|
||||
if (msg_min.value) {
|
||||
dummy_maj = gss_release_buffer(&dummy_min, &msg_min);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
@@ -212,7 +255,10 @@ int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n
|
||||
(gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &server_name);
|
||||
if (maj_stat != GSS_S_COMPLETE) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "importing name %d, %d", maj_stat, min_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_WARNING, "importing name", maj_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_WARNING,
|
||||
"importing name",
|
||||
maj_stat,
|
||||
min_stat);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -224,7 +270,10 @@ int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n
|
||||
|
||||
if (maj_stat != GSS_S_COMPLETE) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "error acquiring credentials %d, %d", maj_stat, min_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_WARNING, "acquiring creds", maj_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_WARNING,
|
||||
"acquiring creds",
|
||||
maj_stat,
|
||||
min_stat);
|
||||
ssh_auth_reply_default(session,0);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
@@ -266,7 +315,10 @@ static char *ssh_gssapi_name_to_char(gss_name_t name){
|
||||
OM_uint32 maj_stat, min_stat;
|
||||
char *ptr;
|
||||
maj_stat = gss_display_name(&min_stat, name, &buffer, NULL);
|
||||
ssh_gssapi_log_error(SSH_LOG_WARNING, "converting name", maj_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_WARNING,
|
||||
"converting name",
|
||||
maj_stat,
|
||||
min_stat);
|
||||
ptr=malloc(buffer.length + 1);
|
||||
memcpy(ptr, buffer.value, buffer.length);
|
||||
ptr[buffer.length] = '\0';
|
||||
@@ -335,14 +387,20 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server){
|
||||
maj_stat = gss_accept_sec_context(&min_stat, &session->gssapi->ctx, session->gssapi->server_creds,
|
||||
&input_token, input_bindings, &client_name, NULL /*mech_oid*/, &output_token, &ret_flags,
|
||||
NULL /*time*/, &session->gssapi->client_creds);
|
||||
ssh_gssapi_log_error(SSH_LOG_PROTOCOL, "accepting token", maj_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_PROTOCOL,
|
||||
"accepting token",
|
||||
maj_stat,
|
||||
min_stat);
|
||||
ssh_string_free(token);
|
||||
if (client_name != GSS_C_NO_NAME){
|
||||
session->gssapi->client_name = client_name;
|
||||
session->gssapi->canonic_user = ssh_gssapi_name_to_char(client_name);
|
||||
}
|
||||
if (GSS_ERROR(maj_stat)){
|
||||
ssh_gssapi_log_error(SSH_LOG_WARNING, "Gssapi error", maj_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_WARNING,
|
||||
"Gssapi error",
|
||||
maj_stat,
|
||||
min_stat);
|
||||
ssh_auth_reply_default(session,0);
|
||||
ssh_gssapi_free(session);
|
||||
session->gssapi=NULL;
|
||||
@@ -439,8 +497,10 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_mic)
|
||||
mic_token_buf.value = ssh_string_data(mic_token);
|
||||
|
||||
maj_stat = gss_verify_mic(&min_stat, session->gssapi->ctx, &mic_buf, &mic_token_buf, NULL);
|
||||
ssh_gssapi_log_error(SSH_LOG_PROTOCOL, "verifying MIC", maj_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_PROTOCOL, "verifying MIC (min stat)", min_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_PROTOCOL,
|
||||
"verifying MIC",
|
||||
maj_stat,
|
||||
min_stat);
|
||||
if (maj_stat == GSS_S_DEFECTIVE_TOKEN || GSS_ERROR(maj_stat)) {
|
||||
goto error;
|
||||
}
|
||||
@@ -653,8 +713,11 @@ int ssh_gssapi_auth_mic(ssh_session session){
|
||||
&session->gssapi->client.server_name);
|
||||
if (maj_stat != GSS_S_COMPLETE) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "importing name %d, %d", maj_stat, min_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_WARNING, "importing name", maj_stat);
|
||||
return SSH_PACKET_USED;
|
||||
ssh_gssapi_log_error(SSH_LOG_WARNING,
|
||||
"importing name",
|
||||
maj_stat,
|
||||
min_stat);
|
||||
return SSH_AUTH_DENIED;
|
||||
}
|
||||
|
||||
/* copy username */
|
||||
@@ -759,7 +822,10 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_response){
|
||||
0, NULL, &input_token, NULL,
|
||||
&output_token, NULL, NULL);
|
||||
if(GSS_ERROR(maj_stat)){
|
||||
ssh_gssapi_log_error(SSH_LOG_WARNING, "Initializing gssapi context", maj_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_WARNING,
|
||||
"Initializing gssapi context",
|
||||
maj_stat,
|
||||
min_stat);
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
if (output_token.length != 0){
|
||||
@@ -797,7 +863,10 @@ static int ssh_gssapi_send_mic(ssh_session session){
|
||||
maj_stat = gss_get_mic(&min_stat,session->gssapi->ctx, GSS_C_QOP_DEFAULT, &mic_buf, &mic_token_buf);
|
||||
if (GSS_ERROR(maj_stat)){
|
||||
ssh_buffer_free(mic_buffer);
|
||||
ssh_gssapi_log_error(SSH_LOG_PROTOCOL, "generating MIC", maj_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_PROTOCOL,
|
||||
"generating MIC",
|
||||
maj_stat,
|
||||
min_stat);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
@@ -848,10 +917,16 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_client){
|
||||
0, NULL, &input_token, NULL,
|
||||
&output_token, NULL, NULL);
|
||||
|
||||
ssh_gssapi_log_error(SSH_LOG_PROTOCOL, "accepting token", maj_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_PROTOCOL,
|
||||
"accepting token",
|
||||
maj_stat,
|
||||
min_stat);
|
||||
ssh_string_free(token);
|
||||
if (GSS_ERROR(maj_stat)){
|
||||
ssh_gssapi_log_error(SSH_LOG_PROTOCOL, "Gssapi error", maj_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_PROTOCOL,
|
||||
"Gssapi error",
|
||||
maj_stat,
|
||||
min_stat);
|
||||
ssh_gssapi_free(session);
|
||||
session->gssapi=NULL;
|
||||
return SSH_PACKET_USED;
|
||||
@@ -869,8 +944,8 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_client){
|
||||
packet_send(session);
|
||||
}
|
||||
if(maj_stat == GSS_S_COMPLETE){
|
||||
session->auth_state = SSH_AUTH_STATE_NONE;
|
||||
ssh_gssapi_send_mic(session);
|
||||
session->auth_state = SSH_AUTH_STATE_GSSAPI_MIC_SENT;
|
||||
}
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
24
src/kex.c
24
src/kex.c
@@ -42,24 +42,28 @@
|
||||
# define AES "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,"
|
||||
# define DES "3des-cbc"
|
||||
# define DES_SUPPORTED "3des-cbc,des-cbc-ssh1"
|
||||
|
||||
#elif defined(HAVE_LIBCRYPTO)
|
||||
|
||||
# ifdef HAVE_OPENSSL_BLOWFISH_H
|
||||
# define BLOWFISH "blowfish-cbc,"
|
||||
# else
|
||||
# else /* HAVE_OPENSSL_BLOWFISH_H */
|
||||
# define BLOWFISH ""
|
||||
# endif
|
||||
# endif /* HAVE_OPENSSL_BLOWFISH_H */
|
||||
|
||||
# ifdef HAVE_OPENSSL_AES_H
|
||||
# ifdef BROKEN_AES_CTR
|
||||
# define AES "aes256-cbc,aes192-cbc,aes128-cbc,"
|
||||
# else
|
||||
# else /* BROKEN_AES_CTR */
|
||||
# define AES "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,"
|
||||
# endif /* BROKEN_AES_CTR */
|
||||
# else
|
||||
# else /* HAVE_OPENSSL_AES_H */
|
||||
# define AES ""
|
||||
# endif
|
||||
# endif /* HAVE_OPENSSL_AES_H */
|
||||
|
||||
# define DES "3des-cbc"
|
||||
# define DES_SUPPORTED "3des-cbc,des-cbc-ssh1"
|
||||
#endif
|
||||
#endif /* HAVE_LIBCRYPTO */
|
||||
|
||||
#ifdef WITH_ZLIB
|
||||
#define ZLIB "none,zlib,zlib@openssh.com"
|
||||
@@ -90,8 +94,8 @@ static const char *default_methods[] = {
|
||||
HOSTKEYS,
|
||||
AES BLOWFISH DES,
|
||||
AES BLOWFISH DES,
|
||||
"hmac-sha1,hmac-sha2-256,hmac-sha2-512",
|
||||
"hmac-sha1,hmac-sha2-256,hmac-sha2-512",
|
||||
"hmac-sha2-256,hmac-sha2-512,hmac-sha1",
|
||||
"hmac-sha2-256,hmac-sha2-512,hmac-sha1",
|
||||
"none",
|
||||
"none",
|
||||
"",
|
||||
@@ -105,8 +109,8 @@ static const char *supported_methods[] = {
|
||||
HOSTKEYS,
|
||||
AES BLOWFISH DES_SUPPORTED,
|
||||
AES BLOWFISH DES_SUPPORTED,
|
||||
"hmac-sha1,hmac-sha2-256,hmac-sha2-512",
|
||||
"hmac-sha1,hmac-sha2-256,hmac-sha2-512",
|
||||
"hmac-sha2-256,hmac-sha2-512,hmac-sha1",
|
||||
"hmac-sha2-256,hmac-sha2-512,hmac-sha1",
|
||||
ZLIB,
|
||||
ZLIB,
|
||||
"",
|
||||
|
||||
12
src/kex1.c
12
src/kex1.c
@@ -36,6 +36,10 @@
|
||||
#include "libssh/ssh1.h"
|
||||
#include "libssh/wrapper.h"
|
||||
|
||||
#if defined(HAVE_LIBCRYPTO)
|
||||
#include "libcrypto-compat.h"
|
||||
#endif
|
||||
|
||||
/* SSHv1 functions */
|
||||
|
||||
/* makes a STRING contating 3 strings : ssh-rsa1,e and n */
|
||||
@@ -46,6 +50,10 @@ static ssh_string make_rsa1_string(ssh_string e, ssh_string n){
|
||||
ssh_string ret = NULL;
|
||||
|
||||
buffer = ssh_buffer_new();
|
||||
if (buffer == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rsa = ssh_string_from_char("ssh-rsa1");
|
||||
if (rsa == NULL) {
|
||||
goto error;
|
||||
@@ -119,8 +127,8 @@ static int modulus_smaller(ssh_public_key k1, ssh_public_key k2){
|
||||
n2=gcry_sexp_nth_mpi(sexp,1,GCRYMPI_FMT_USG);
|
||||
gcry_sexp_release(sexp);
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
n1=k1->rsa_pub->n;
|
||||
n2=k2->rsa_pub->n;
|
||||
RSA_get0_key(k1->rsa_pub, (const BIGNUM **)&n1, NULL, NULL);
|
||||
RSA_get0_key(k2->rsa_pub, (const BIGNUM **)&n2, NULL, NULL);
|
||||
#endif
|
||||
if(bignum_cmp(n1,n2)<0)
|
||||
res=1;
|
||||
|
||||
318
src/libcrypto-compat.c
Normal file
318
src/libcrypto-compat.c
Normal file
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
* Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <openssl/engine.h>
|
||||
#include "libcrypto-compat.h"
|
||||
|
||||
static void *OPENSSL_zalloc(size_t num)
|
||||
{
|
||||
void *ret = OPENSSL_malloc(num);
|
||||
|
||||
if (ret != NULL)
|
||||
memset(ret, 0, num);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
|
||||
{
|
||||
/* If the fields n and e in r are NULL, the corresponding input
|
||||
* parameters MUST be non-NULL for n and e. d may be
|
||||
* left NULL (in case only the public key is used).
|
||||
*/
|
||||
if ((r->n == NULL && n == NULL)
|
||||
|| (r->e == NULL && e == NULL))
|
||||
return 0;
|
||||
|
||||
if (n != NULL) {
|
||||
BN_free(r->n);
|
||||
r->n = n;
|
||||
}
|
||||
if (e != NULL) {
|
||||
BN_free(r->e);
|
||||
r->e = e;
|
||||
}
|
||||
if (d != NULL) {
|
||||
BN_free(r->d);
|
||||
r->d = d;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q)
|
||||
{
|
||||
/* If the fields p and q in r are NULL, the corresponding input
|
||||
* parameters MUST be non-NULL.
|
||||
*/
|
||||
if ((r->p == NULL && p == NULL)
|
||||
|| (r->q == NULL && q == NULL))
|
||||
return 0;
|
||||
|
||||
if (p != NULL) {
|
||||
BN_free(r->p);
|
||||
r->p = p;
|
||||
}
|
||||
if (q != NULL) {
|
||||
BN_free(r->q);
|
||||
r->q = q;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp)
|
||||
{
|
||||
/* If the fields dmp1, dmq1 and iqmp in r are NULL, the corresponding input
|
||||
* parameters MUST be non-NULL.
|
||||
*/
|
||||
if ((r->dmp1 == NULL && dmp1 == NULL)
|
||||
|| (r->dmq1 == NULL && dmq1 == NULL)
|
||||
|| (r->iqmp == NULL && iqmp == NULL))
|
||||
return 0;
|
||||
|
||||
if (dmp1 != NULL) {
|
||||
BN_free(r->dmp1);
|
||||
r->dmp1 = dmp1;
|
||||
}
|
||||
if (dmq1 != NULL) {
|
||||
BN_free(r->dmq1);
|
||||
r->dmq1 = dmq1;
|
||||
}
|
||||
if (iqmp != NULL) {
|
||||
BN_free(r->iqmp);
|
||||
r->iqmp = iqmp;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void RSA_get0_key(const RSA *r,
|
||||
const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
|
||||
{
|
||||
if (n != NULL)
|
||||
*n = r->n;
|
||||
if (e != NULL)
|
||||
*e = r->e;
|
||||
if (d != NULL)
|
||||
*d = r->d;
|
||||
}
|
||||
|
||||
void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
|
||||
{
|
||||
if (p != NULL)
|
||||
*p = r->p;
|
||||
if (q != NULL)
|
||||
*q = r->q;
|
||||
}
|
||||
|
||||
void RSA_get0_crt_params(const RSA *r,
|
||||
const BIGNUM **dmp1, const BIGNUM **dmq1,
|
||||
const BIGNUM **iqmp)
|
||||
{
|
||||
if (dmp1 != NULL)
|
||||
*dmp1 = r->dmp1;
|
||||
if (dmq1 != NULL)
|
||||
*dmq1 = r->dmq1;
|
||||
if (iqmp != NULL)
|
||||
*iqmp = r->iqmp;
|
||||
}
|
||||
|
||||
void DSA_get0_pqg(const DSA *d,
|
||||
const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
|
||||
{
|
||||
if (p != NULL)
|
||||
*p = d->p;
|
||||
if (q != NULL)
|
||||
*q = d->q;
|
||||
if (g != NULL)
|
||||
*g = d->g;
|
||||
}
|
||||
|
||||
int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
|
||||
{
|
||||
/* If the fields p, q and g in d are NULL, the corresponding input
|
||||
* parameters MUST be non-NULL.
|
||||
*/
|
||||
if ((d->p == NULL && p == NULL)
|
||||
|| (d->q == NULL && q == NULL)
|
||||
|| (d->g == NULL && g == NULL))
|
||||
return 0;
|
||||
|
||||
if (p != NULL) {
|
||||
BN_free(d->p);
|
||||
d->p = p;
|
||||
}
|
||||
if (q != NULL) {
|
||||
BN_free(d->q);
|
||||
d->q = q;
|
||||
}
|
||||
if (g != NULL) {
|
||||
BN_free(d->g);
|
||||
d->g = g;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void DSA_get0_key(const DSA *d,
|
||||
const BIGNUM **pub_key, const BIGNUM **priv_key)
|
||||
{
|
||||
if (pub_key != NULL)
|
||||
*pub_key = d->pub_key;
|
||||
if (priv_key != NULL)
|
||||
*priv_key = d->priv_key;
|
||||
}
|
||||
|
||||
int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
|
||||
{
|
||||
/* If the field pub_key in d is NULL, the corresponding input
|
||||
* parameters MUST be non-NULL. The priv_key field may
|
||||
* be left NULL.
|
||||
*/
|
||||
if (d->pub_key == NULL && pub_key == NULL)
|
||||
return 0;
|
||||
|
||||
if (pub_key != NULL) {
|
||||
BN_free(d->pub_key);
|
||||
d->pub_key = pub_key;
|
||||
}
|
||||
if (priv_key != NULL) {
|
||||
BN_free(d->priv_key);
|
||||
d->priv_key = priv_key;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
|
||||
{
|
||||
if (pr != NULL)
|
||||
*pr = sig->r;
|
||||
if (ps != NULL)
|
||||
*ps = sig->s;
|
||||
}
|
||||
|
||||
int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s)
|
||||
{
|
||||
if (r == NULL || s == NULL)
|
||||
return 0;
|
||||
BN_clear_free(sig->r);
|
||||
BN_clear_free(sig->s);
|
||||
sig->r = r;
|
||||
sig->s = s;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
|
||||
{
|
||||
if (pr != NULL)
|
||||
*pr = sig->r;
|
||||
if (ps != NULL)
|
||||
*ps = sig->s;
|
||||
}
|
||||
|
||||
int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
|
||||
{
|
||||
if (r == NULL || s == NULL)
|
||||
return 0;
|
||||
BN_clear_free(sig->r);
|
||||
BN_clear_free(sig->s);
|
||||
sig->r = r;
|
||||
sig->s = s;
|
||||
return 1;
|
||||
}
|
||||
|
||||
EVP_MD_CTX *EVP_MD_CTX_new(void)
|
||||
{
|
||||
return OPENSSL_zalloc(sizeof(EVP_MD_CTX));
|
||||
}
|
||||
|
||||
static void OPENSSL_clear_free(void *str, size_t num)
|
||||
{
|
||||
if (str == NULL)
|
||||
return;
|
||||
if (num)
|
||||
OPENSSL_cleanse(str, num);
|
||||
OPENSSL_free(str);
|
||||
}
|
||||
|
||||
/* This call frees resources associated with the context */
|
||||
int EVP_MD_CTX_reset(EVP_MD_CTX *ctx)
|
||||
{
|
||||
if (ctx == NULL)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Don't assume ctx->md_data was cleaned in EVP_Digest_Final, because
|
||||
* sometimes only copies of the context are ever finalised.
|
||||
*/
|
||||
if (ctx->digest && ctx->digest->cleanup
|
||||
&& !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_CLEANED))
|
||||
ctx->digest->cleanup(ctx);
|
||||
if (ctx->digest && ctx->digest->ctx_size && ctx->md_data
|
||||
&& !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE)) {
|
||||
OPENSSL_clear_free(ctx->md_data, ctx->digest->ctx_size);
|
||||
}
|
||||
EVP_PKEY_CTX_free(ctx->pctx);
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
ENGINE_finish(ctx->engine);
|
||||
#endif
|
||||
OPENSSL_cleanse(ctx, sizeof(*ctx));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
|
||||
{
|
||||
EVP_MD_CTX_reset(ctx);
|
||||
OPENSSL_free(ctx);
|
||||
}
|
||||
|
||||
HMAC_CTX *HMAC_CTX_new(void)
|
||||
{
|
||||
HMAC_CTX *ctx = OPENSSL_zalloc(sizeof(HMAC_CTX));
|
||||
|
||||
if (ctx != NULL) {
|
||||
if (!HMAC_CTX_reset(ctx)) {
|
||||
HMAC_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static void hmac_ctx_cleanup(HMAC_CTX *ctx)
|
||||
{
|
||||
EVP_MD_CTX_reset(&ctx->i_ctx);
|
||||
EVP_MD_CTX_reset(&ctx->o_ctx);
|
||||
EVP_MD_CTX_reset(&ctx->md_ctx);
|
||||
ctx->md = NULL;
|
||||
ctx->key_length = 0;
|
||||
OPENSSL_cleanse(ctx->key, sizeof(ctx->key));
|
||||
}
|
||||
|
||||
void HMAC_CTX_free(HMAC_CTX *ctx)
|
||||
{
|
||||
if (ctx != NULL) {
|
||||
hmac_ctx_cleanup(ctx);
|
||||
#if OPENSSL_VERSION_NUMBER > 0x10100000L
|
||||
EVP_MD_CTX_free(&ctx->i_ctx);
|
||||
EVP_MD_CTX_free(&ctx->o_ctx);
|
||||
EVP_MD_CTX_free(&ctx->md_ctx);
|
||||
#endif
|
||||
OPENSSL_free(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
int HMAC_CTX_reset(HMAC_CTX *ctx)
|
||||
{
|
||||
HMAC_CTX_init(ctx);
|
||||
return 1;
|
||||
}
|
||||
42
src/libcrypto-compat.h
Normal file
42
src/libcrypto-compat.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifndef LIBCRYPTO_COMPAT_H
|
||||
#define LIBCRYPTO_COMPAT_H
|
||||
|
||||
#include <openssl/opensslv.h>
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/ecdsa.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d);
|
||||
int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q);
|
||||
int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp);
|
||||
void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d);
|
||||
void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q);
|
||||
void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp);
|
||||
|
||||
void DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
|
||||
int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g);
|
||||
void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key);
|
||||
int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key);
|
||||
|
||||
void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps);
|
||||
int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s);
|
||||
|
||||
void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps);
|
||||
int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s);
|
||||
|
||||
int EVP_MD_CTX_reset(EVP_MD_CTX *ctx);
|
||||
EVP_MD_CTX *EVP_MD_CTX_new(void);
|
||||
void EVP_MD_CTX_free(EVP_MD_CTX *ctx);
|
||||
|
||||
HMAC_CTX *HMAC_CTX_new(void);
|
||||
int HMAC_CTX_reset(HMAC_CTX *ctx);
|
||||
void HMAC_CTX_free(HMAC_CTX *ctx);
|
||||
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
|
||||
#endif /* LIBCRYPTO_COMPAT_H */
|
||||
@@ -43,6 +43,8 @@
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/modes.h>
|
||||
#include "libcrypto-compat.h"
|
||||
|
||||
#ifdef HAVE_OPENSSL_AES_H
|
||||
#define HAS_AES
|
||||
@@ -133,18 +135,19 @@ static const EVP_MD *nid_to_evpmd(int nid)
|
||||
void evp(int nid, unsigned char *digest, int len, unsigned char *hash, unsigned int *hlen)
|
||||
{
|
||||
const EVP_MD *evp_md = nid_to_evpmd(nid);
|
||||
EVP_MD_CTX md;
|
||||
EVP_MD_CTX *md = EVP_MD_CTX_new();
|
||||
|
||||
EVP_DigestInit(&md, evp_md);
|
||||
EVP_DigestUpdate(&md, digest, len);
|
||||
EVP_DigestFinal(&md, hash, hlen);
|
||||
EVP_DigestInit(md, evp_md);
|
||||
EVP_DigestUpdate(md, digest, len);
|
||||
EVP_DigestFinal(md, hash, hlen);
|
||||
EVP_MD_CTX_free(md);
|
||||
}
|
||||
|
||||
EVPCTX evp_init(int nid)
|
||||
{
|
||||
const EVP_MD *evp_md = nid_to_evpmd(nid);
|
||||
|
||||
EVPCTX ctx = malloc(sizeof(EVP_MD_CTX));
|
||||
EVPCTX ctx = EVP_MD_CTX_new();
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -162,6 +165,7 @@ void evp_update(EVPCTX ctx, const void *data, unsigned long len)
|
||||
void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen)
|
||||
{
|
||||
EVP_DigestFinal(ctx, md, mdlen);
|
||||
EVP_MD_CTX_free(ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -322,32 +326,33 @@ void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx) {
|
||||
HMACCTX hmac_init(const void *key, int len, enum ssh_hmac_e type) {
|
||||
HMACCTX ctx = NULL;
|
||||
|
||||
ctx = malloc(sizeof(*ctx));
|
||||
ctx = HMAC_CTX_new();
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef OLD_CRYPTO
|
||||
HMAC_CTX_init(ctx); // openssl 0.9.7 requires it.
|
||||
HMAC_CTX_reset(ctx); // openssl 0.9.7 requires it.
|
||||
#endif
|
||||
|
||||
switch(type) {
|
||||
case SSH_HMAC_SHA1:
|
||||
HMAC_Init(ctx, key, len, EVP_sha1());
|
||||
HMAC_Init_ex(ctx, key, len, EVP_sha1(), NULL);
|
||||
break;
|
||||
case SSH_HMAC_SHA256:
|
||||
HMAC_Init(ctx, key, len, EVP_sha256());
|
||||
HMAC_Init_ex(ctx, key, len, EVP_sha256(), NULL);
|
||||
break;
|
||||
case SSH_HMAC_SHA384:
|
||||
HMAC_Init(ctx, key, len, EVP_sha384());
|
||||
HMAC_Init_ex(ctx, key, len, EVP_sha384(), NULL);
|
||||
break;
|
||||
case SSH_HMAC_SHA512:
|
||||
HMAC_Init(ctx, key, len, EVP_sha512());
|
||||
HMAC_Init_ex(ctx, key, len, EVP_sha512(), NULL);
|
||||
break;
|
||||
case SSH_HMAC_MD5:
|
||||
HMAC_Init(ctx, key, len, EVP_md5());
|
||||
HMAC_Init_ex(ctx, key, len, EVP_md5(), NULL);
|
||||
break;
|
||||
default:
|
||||
HMAC_CTX_free(ctx);
|
||||
SAFE_FREE(ctx);
|
||||
ctx = NULL;
|
||||
}
|
||||
@@ -363,7 +368,8 @@ void hmac_final(HMACCTX ctx, unsigned char *hashmacbuf, unsigned int *len) {
|
||||
HMAC_Final(ctx,hashmacbuf,len);
|
||||
|
||||
#ifndef OLD_CRYPTO
|
||||
HMAC_CTX_cleanup(ctx);
|
||||
HMAC_CTX_free(ctx);
|
||||
ctx = NULL;
|
||||
#else
|
||||
HMAC_cleanup(ctx);
|
||||
#endif
|
||||
@@ -455,7 +461,12 @@ static void aes_ctr128_encrypt(struct ssh_cipher_struct *cipher, void *in, void
|
||||
* Same for num, which is being used to store the current offset in blocksize in CTR
|
||||
* function.
|
||||
*/
|
||||
#ifdef HAVE_OPENSSL_CRYPTO_CTR128_ENCRYPT
|
||||
CRYPTO_ctr128_encrypt(in, out, len, cipher->key, cipher->IV, tmp_buffer,
|
||||
&num, (block128_f)AES_encrypt);
|
||||
# else
|
||||
AES_ctr128_encrypt(in, out, len, cipher->key, cipher->IV, tmp_buffer, &num);
|
||||
#endif /* HAVE_OPENSSL_CRYPTO_CTR128_ENCRYPT */
|
||||
}
|
||||
#endif /* BROKEN_AES_CTR */
|
||||
#endif /* HAS_AES */
|
||||
|
||||
@@ -181,7 +181,7 @@ 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) {
|
||||
size_t len;
|
||||
size_t len = 0;
|
||||
switch(ctx->mac_type){
|
||||
case SSH_MAC_SHA1:
|
||||
len=SHA_DIGEST_LEN;
|
||||
|
||||
@@ -649,6 +649,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_request){
|
||||
ssh_message msg = NULL;
|
||||
char *service = NULL;
|
||||
char *method = NULL;
|
||||
int cmp;
|
||||
int rc;
|
||||
|
||||
(void)user;
|
||||
@@ -675,6 +676,13 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_request){
|
||||
service, method,
|
||||
msg->auth_request.username);
|
||||
|
||||
cmp = strcmp(service, "ssh-connection");
|
||||
if (cmp != 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING,
|
||||
"Invalid service request: %s",
|
||||
service);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (strcmp(method, "none") == 0) {
|
||||
msg->auth_request.method = SSH_AUTH_METHOD_NONE;
|
||||
@@ -923,6 +931,15 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){
|
||||
|
||||
goto error;
|
||||
}
|
||||
} else if (session->kbdint->nanswers > 0) {
|
||||
uint32_t n;
|
||||
|
||||
for (n = 0; n < session->kbdint->nanswers; n++) {
|
||||
BURN_STRING(session->kbdint->answers[n]);
|
||||
SAFE_FREE(session->kbdint->answers[n]);
|
||||
}
|
||||
SAFE_FREE(session->kbdint->answers);
|
||||
session->kbdint->nanswers = 0;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET,"kbdint: %d answers",nanswers);
|
||||
@@ -942,7 +959,8 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){
|
||||
" mismatch: p=%u a=%u", session->kbdint->nprompts, nanswers);
|
||||
}
|
||||
session->kbdint->nanswers = nanswers;
|
||||
session->kbdint->answers = malloc(nanswers * sizeof(char *));
|
||||
|
||||
session->kbdint->answers = calloc(1, nanswers * sizeof(char *));
|
||||
if (session->kbdint->answers == NULL) {
|
||||
session->kbdint->nanswers = 0;
|
||||
ssh_set_error_oom(session);
|
||||
@@ -951,7 +969,6 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){
|
||||
|
||||
goto error;
|
||||
}
|
||||
memset(session->kbdint->answers, 0, nanswers * sizeof(char *));
|
||||
|
||||
for (i = 0; i < nanswers; i++) {
|
||||
tmp = buffer_get_ssh_string(packet);
|
||||
@@ -1101,6 +1118,7 @@ int ssh_message_channel_request_open_reply_accept_channel(ssh_message msg, ssh_c
|
||||
chan->remote_maxpacket = msg->channel_request_open.packet_size;
|
||||
chan->remote_window = msg->channel_request_open.window;
|
||||
chan->state = SSH_CHANNEL_STATE_OPEN;
|
||||
chan->flags &= ~SSH_CHANNEL_FLAG_NOT_BOUND;
|
||||
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bdddd",
|
||||
@@ -1355,7 +1373,9 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){
|
||||
msg->global_request.bind_port);
|
||||
session->common.callbacks->global_request_function(session, msg, session->common.callbacks->userdata);
|
||||
} else {
|
||||
ssh_message_reply_default(msg);
|
||||
SAFE_FREE(request);
|
||||
ssh_message_queue(session, msg);
|
||||
return rc;
|
||||
}
|
||||
} else if (strcmp(request, "cancel-tcpip-forward") == 0) {
|
||||
r = ssh_buffer_unpack(packet, "sd",
|
||||
@@ -1374,7 +1394,9 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){
|
||||
if(ssh_callbacks_exists(session->common.callbacks, global_request_function)) {
|
||||
session->common.callbacks->global_request_function(session, msg, session->common.callbacks->userdata);
|
||||
} else {
|
||||
ssh_message_reply_default(msg);
|
||||
SAFE_FREE(request);
|
||||
ssh_message_queue(session, msg);
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "UNKNOWN SSH_MSG_GLOBAL_REQUEST %s %d", request, want_reply);
|
||||
|
||||
61
src/misc.c
61
src/misc.c
@@ -33,9 +33,10 @@
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#ifndef HAVE_CLOCK_GETTIME
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif /* HAVE_CLOCK_GETTIME */
|
||||
#endif /* HAVE_SYS_TIME_H */
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#include <limits.h>
|
||||
@@ -289,23 +290,6 @@ int ssh_is_ipaddr(const char *str) {
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#ifndef HAVE_NTOHLL
|
||||
uint64_t ntohll(uint64_t a) {
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
return a;
|
||||
#else /* WORDS_BIGENDIAN */
|
||||
return (((uint64_t)(a) << 56) | \
|
||||
(((uint64_t)(a) << 40) & 0xff000000000000ULL) | \
|
||||
(((uint64_t)(a) << 24) & 0xff0000000000ULL) | \
|
||||
(((uint64_t)(a) << 8) & 0xff00000000ULL) | \
|
||||
(((uint64_t)(a) >> 8) & 0xff000000ULL) | \
|
||||
(((uint64_t)(a) >> 24) & 0xff0000ULL) | \
|
||||
(((uint64_t)(a) >> 40) & 0xff00ULL) | \
|
||||
((uint64_t)(a) >> 56));
|
||||
#endif /* WORDS_BIGENDIAN */
|
||||
}
|
||||
#endif /* HAVE_NTOHLL */
|
||||
|
||||
char *ssh_lowercase(const char* str) {
|
||||
char *new, *p;
|
||||
|
||||
@@ -862,7 +846,7 @@ int ssh_analyze_banner(ssh_session session, int server, int *ssh1, int *ssh2) {
|
||||
|
||||
openssh = strstr(banner, "OpenSSH");
|
||||
if (openssh != NULL) {
|
||||
int major, minor;
|
||||
unsigned int major, minor;
|
||||
|
||||
/*
|
||||
* The banner is typical:
|
||||
@@ -870,8 +854,22 @@ int ssh_analyze_banner(ssh_session session, int server, int *ssh1, int *ssh2) {
|
||||
* 012345678901234567890
|
||||
*/
|
||||
if (strlen(openssh) > 9) {
|
||||
major = strtol(openssh + 8, (char **) NULL, 10);
|
||||
major = strtoul(openssh + 8, (char **) NULL, 10);
|
||||
if (major < 1 || major > 100) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Invalid major version number: %s",
|
||||
banner);
|
||||
return -1;
|
||||
}
|
||||
minor = strtol(openssh + 10, (char **) NULL, 10);
|
||||
if (minor > 100) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Invalid minor version number: %s",
|
||||
banner);
|
||||
return -1;
|
||||
}
|
||||
session->openssh = SSH_VERSION_INT(major, minor, 0);
|
||||
SSH_LOG(SSH_LOG_RARE,
|
||||
"We are talking to an OpenSSH client version: %d.%d (%x)",
|
||||
@@ -1030,6 +1028,27 @@ int ssh_match_group(const char *group, const char *object)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !defined(HAVE_STRNDUP)
|
||||
char *strndup(const char *s, size_t n)
|
||||
{
|
||||
char *x = NULL;
|
||||
|
||||
if (n + 1 < n) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
x = malloc(n + 1);
|
||||
if (x == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(x, s, n);
|
||||
x[n] = '\0';
|
||||
|
||||
return x;
|
||||
}
|
||||
#endif /* ! HAVE_STRNDUP */
|
||||
|
||||
/** @} */
|
||||
|
||||
/* vim: set ts=4 sw=4 et cindent: */
|
||||
|
||||
@@ -93,12 +93,6 @@ int ssh_options_copy(ssh_session src, ssh_session *dest) {
|
||||
if (src->opts.identity) {
|
||||
struct ssh_iterator *it;
|
||||
|
||||
new->opts.identity = ssh_list_new();
|
||||
if (new->opts.identity == NULL) {
|
||||
ssh_free(new);
|
||||
return -1;
|
||||
}
|
||||
|
||||
it = ssh_list_get_iterator(src->opts.identity);
|
||||
while (it) {
|
||||
char *id;
|
||||
@@ -338,7 +332,7 @@ int ssh_options_set_algo(ssh_session session, int algo,
|
||||
* - SSH_OPTIONS_HOSTKEYS:
|
||||
* Set the preferred server host key types (const char *,
|
||||
* comma-separated list). ex:
|
||||
* "ssh-rsa,ssh-dsa,ecdh-sha2-nistp256"
|
||||
* "ssh-rsa,ssh-dss,ecdh-sha2-nistp256"
|
||||
*
|
||||
* - SSH_OPTIONS_COMPRESSION_C_S:
|
||||
* Set the compression to use for client to server
|
||||
@@ -1356,10 +1350,10 @@ static int ssh_bind_set_key(ssh_bind sshbind, char **key_loc,
|
||||
* with verbosity less than or equal to the
|
||||
* logging verbosity will be shown.
|
||||
* - SSH_LOG_NOLOG: No logging
|
||||
* - SSH_LOG_RARE: Rare conditions or warnings
|
||||
* - SSH_LOG_ENTRY: API-accessible entrypoints
|
||||
* - SSH_LOG_PACKET: Packet id and size
|
||||
* - SSH_LOG_FUNCTIONS: Function entering and leaving
|
||||
* - SSH_LOG_WARNING: Only warnings
|
||||
* - SSH_LOG_PROTOCOL: High level protocol information
|
||||
* - SSH_LOG_PACKET: Lower level protocol infomations, packet level
|
||||
* - SSH_LOG_FUNCTIONS: Every function path
|
||||
*
|
||||
* - SSH_BIND_OPTIONS_LOG_VERBOSITY_STR:
|
||||
* Set the session logging verbosity via a
|
||||
|
||||
788
src/packet.c
788
src/packet.c
@@ -127,6 +127,776 @@ static ssh_packet_callback default_packet_handlers[]= {
|
||||
ssh_packet_channel_failure, // SSH2_MSG_CHANNEL_FAILURE 100
|
||||
};
|
||||
|
||||
/** @internal
|
||||
* @brief check if the received packet is allowed for the current session state
|
||||
* @param session current ssh_session
|
||||
* @returns SSH_PACKET_ALLOWED if the packet is allowed; SSH_PACKET_DENIED
|
||||
* if the packet arrived in wrong state; SSH_PACKET_UNKNOWN if the packet type
|
||||
* is unknown
|
||||
*/
|
||||
static enum ssh_packet_filter_result_e ssh_packet_incoming_filter(ssh_session session)
|
||||
{
|
||||
enum ssh_packet_filter_result_e rc;
|
||||
|
||||
#ifdef DEBUG_PACKET
|
||||
SSH_LOG(SSH_LOG_PACKET, "Filtering packet type %d",
|
||||
session->in_packet.type);
|
||||
#endif
|
||||
|
||||
switch(session->in_packet.type) {
|
||||
case SSH2_MSG_DISCONNECT: // 1
|
||||
/*
|
||||
* States required:
|
||||
* - None
|
||||
*
|
||||
* Transitions:
|
||||
* - session->socket->state = SSH_SOCKET_CLOSED
|
||||
* - session->session_state = SSH_SESSION_STATE_ERROR
|
||||
* */
|
||||
|
||||
/* Always allowed */
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_IGNORE: // 2
|
||||
/*
|
||||
* States required:
|
||||
* - None
|
||||
*
|
||||
* Transitions:
|
||||
* - None
|
||||
* */
|
||||
|
||||
/* Always allowed */
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_UNIMPLEMENTED: // 3
|
||||
/*
|
||||
* States required:
|
||||
* - None
|
||||
*
|
||||
* Transitions:
|
||||
* - None
|
||||
* */
|
||||
|
||||
/* Always allowed */
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_DEBUG: // 4
|
||||
/*
|
||||
* States required:
|
||||
* - None
|
||||
*
|
||||
* Transitions:
|
||||
* - None
|
||||
* */
|
||||
|
||||
/* Always allowed */
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_SERVICE_REQUEST: // 5
|
||||
/* Server only */
|
||||
|
||||
/*
|
||||
* States required:
|
||||
* - session->session_state == SSH_SESSION_STATE_AUTHENTICATING
|
||||
* or session->session_state == SSH_SESSION_STATE_AUTHENTICATED
|
||||
* - session->dh_handshake_state == DH_STATE_FINISHED
|
||||
*
|
||||
* Transitions:
|
||||
* - None
|
||||
* */
|
||||
|
||||
/* If this is a client, reject the message */
|
||||
if (session->client) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((session->session_state != SSH_SESSION_STATE_AUTHENTICATING) &&
|
||||
(session->session_state != SSH_SESSION_STATE_AUTHENTICATED))
|
||||
{
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (session->dh_handshake_state != DH_STATE_FINISHED) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_SERVICE_ACCEPT: // 6
|
||||
/*
|
||||
* States required:
|
||||
* - session->session_state == SSH_SESSION_STATE_AUTHENTICATING
|
||||
* or session->session_state == SSH_SESSION_STATE_AUTHENTICATED
|
||||
* - session->dh_handshake_state == DH_STATE_FINISHED
|
||||
* - session->auth_service_state == SSH_AUTH_SERVICE_SENT
|
||||
*
|
||||
* Transitions:
|
||||
* - auth_service_state = SSH_AUTH_SERVICE_ACCEPTED
|
||||
* */
|
||||
|
||||
if ((session->session_state != SSH_SESSION_STATE_AUTHENTICATING) &&
|
||||
(session->session_state != SSH_SESSION_STATE_AUTHENTICATED))
|
||||
{
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (session->dh_handshake_state != DH_STATE_FINISHED) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
/* TODO check if only auth service can be requested */
|
||||
if (session->auth_service_state != SSH_AUTH_SERVICE_SENT) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_KEXINIT: // 20
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
|
||||
* or session_state == SSH_SESSION_STATE_INITIAL_KEX
|
||||
* - dh_handshake_state == DH_STATE_INIT
|
||||
* or dh_handshake_state == DH_STATE_FINISHED (re-exchange)
|
||||
*
|
||||
* Transitions:
|
||||
* - session->dh_handshake_state = DH_STATE_INIT
|
||||
* - session->session_state = SSH_SESSION_STATE_KEXINIT_RECEIVED
|
||||
*
|
||||
* On server:
|
||||
* - session->session_state = SSH_SESSION_STATE_DH
|
||||
* */
|
||||
|
||||
if ((session->session_state != SSH_SESSION_STATE_AUTHENTICATED) &&
|
||||
(session->session_state != SSH_SESSION_STATE_INITIAL_KEX))
|
||||
{
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((session->dh_handshake_state != DH_STATE_INIT) &&
|
||||
(session->dh_handshake_state != DH_STATE_FINISHED))
|
||||
{
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_NEWKEYS: // 21
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_DH
|
||||
* - dh_handshake_state == DH_STATE_NEWKEYS_SENT
|
||||
*
|
||||
* Transitions:
|
||||
* - session->dh_handshake_state = DH_STATE_FINISHED
|
||||
* - session->session_state = SSH_SESSION_STATE_AUTHENTICATING
|
||||
* if session->flags & SSH_SESSION_FLAG_AUTHENTICATED
|
||||
* - session->session_state = SSH_SESSION_STATE_AUTHENTICATED
|
||||
* */
|
||||
|
||||
/* If DH has not been started, reject message */
|
||||
if (session->session_state != SSH_SESSION_STATE_DH) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Only allowed if dh_handshake_state is in NEWKEYS_SENT state */
|
||||
if (session->dh_handshake_state != DH_STATE_NEWKEYS_SENT) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_KEXDH_INIT: // 30
|
||||
// SSH2_MSG_KEX_ECDH_INIT: // 30
|
||||
// SSH2_MSG_ECMQV_INIT: // 30
|
||||
// SSH2_MSG_KEX_DH_GEX_REQUEST_OLD: // 30
|
||||
|
||||
/* Server only */
|
||||
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_DH
|
||||
* - dh_handshake_state == DH_STATE_INIT
|
||||
*
|
||||
* Transitions:
|
||||
* - session->dh_handshake_state = DH_STATE_INIT_SENT
|
||||
* then calls dh_handshake_server which triggers:
|
||||
* - session->dh_handhsake_state = DH_STATE_NEWKEYS_SENT
|
||||
* */
|
||||
|
||||
if (session->session_state != SSH_SESSION_STATE_DH) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Only allowed if dh_handshake_state is in initial state */
|
||||
if (session->dh_handshake_state != DH_STATE_INIT) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_KEXDH_REPLY: // 31
|
||||
// SSH2_MSG_KEX_ECDH_REPLY: // 31
|
||||
// SSH2_MSG_ECMQV_REPLY: // 31
|
||||
// SSH2_MSG_KEX_DH_GEX_GROUP: // 31
|
||||
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_DH
|
||||
* - dh_handshake_state == DH_STATE_INIT_SENT
|
||||
*
|
||||
* Transitions:
|
||||
* - session->dh_handhsake_state = DH_STATE_NEWKEYS_SENT
|
||||
* */
|
||||
|
||||
if (session->session_state != SSH_SESSION_STATE_DH) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (session->dh_handshake_state != DH_STATE_INIT_SENT) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_KEX_DH_GEX_INIT: // 32
|
||||
/* TODO Not filtered */
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_KEX_DH_GEX_REPLY: // 33
|
||||
/* TODO Not filtered */
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_KEX_DH_GEX_REQUEST: // 34
|
||||
/* TODO Not filtered */
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_USERAUTH_REQUEST: // 50
|
||||
/* Server only */
|
||||
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_AUTHENTICATING
|
||||
* - dh_hanshake_state == DH_STATE_FINISHED
|
||||
*
|
||||
* Transitions:
|
||||
* - if authentication was successful:
|
||||
* - session_state = SSH_SESSION_STATE_AUTHENTICATED
|
||||
* */
|
||||
|
||||
/* If this is a client, reject the message */
|
||||
if (session->client) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (session->dh_handshake_state != DH_STATE_FINISHED) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_USERAUTH_FAILURE: // 51
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_AUTHENTICATING
|
||||
* - dh_hanshake_state == DH_STATE_FINISHED
|
||||
* - session->auth_state == SSH_AUTH_STATE_KBDINT_SENT
|
||||
* or session->auth_state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT
|
||||
* or session->auth_state == SSH_AUTH_STATE_PUBKEY_AUTH_SENT
|
||||
* or session->auth_state == SSH_AUTH_STATE_PASSWORD_AUTH_SENT
|
||||
* or session->auth_state == SSH_AUTH_STATE_GSSAPI_MIC_SENT
|
||||
*
|
||||
* Transitions:
|
||||
* - if unpacking failed:
|
||||
* - session->auth_state = SSH_AUTH_ERROR
|
||||
* - if failure was partial:
|
||||
* - session->auth_state = SSH_AUTH_PARTIAL
|
||||
* - else:
|
||||
* - session->auth_state = SSH_AUTH_STATE_FAILED
|
||||
* */
|
||||
|
||||
/* If this is a server, reject the message */
|
||||
if (session->server) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (session->dh_handshake_state != DH_STATE_FINISHED) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_USERAUTH_SUCCESS: // 52
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_AUTHENTICATING
|
||||
* - dh_hanshake_state == DH_STATE_FINISHED
|
||||
* - session->auth_state == SSH_AUTH_STATE_KBDINT_SENT
|
||||
* or session->auth_state == SSH_AUTH_STATE_PUBKEY_AUTH_SENT
|
||||
* or session->auth_state == SSH_AUTH_STATE_PASSWORD_AUTH_SENT
|
||||
* or session->auth_state == SSH_AUTH_STATE_GSSAPI_MIC_SENT
|
||||
* or session->auth_state == SSH_AUTH_STATE_AUTH_NONE_SENT
|
||||
*
|
||||
* Transitions:
|
||||
* - session->auth_state = SSH_AUTH_STATE_SUCCESS
|
||||
* - session->session_state = SSH_SESSION_STATE_AUTHENTICATED
|
||||
* - session->flags |= SSH_SESSION_FLAG_AUTHENTICATED
|
||||
* - sessions->auth.current_method = SSH_AUTH_METHOD_UNKNOWN
|
||||
* */
|
||||
|
||||
/* If this is a server, reject the message */
|
||||
if (session->server) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (session->dh_handshake_state != DH_STATE_FINISHED) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((session->auth_state != SSH_AUTH_STATE_KBDINT_SENT) &&
|
||||
(session->auth_state != SSH_AUTH_STATE_PUBKEY_AUTH_SENT) &&
|
||||
(session->auth_state != SSH_AUTH_STATE_PASSWORD_AUTH_SENT) &&
|
||||
(session->auth_state != SSH_AUTH_STATE_GSSAPI_MIC_SENT) &&
|
||||
(session->auth_state != SSH_AUTH_STATE_AUTH_NONE_SENT))
|
||||
{
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_USERAUTH_BANNER: // 53
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_AUTHENTICATING
|
||||
*
|
||||
* Transitions:
|
||||
* - None
|
||||
* */
|
||||
|
||||
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_USERAUTH_PK_OK: // 60
|
||||
// SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: // 60
|
||||
// SSH2_MSG_USERAUTH_INFO_REQUEST: // 60
|
||||
// SSH2_MSG_USERAUTH_GSSAPI_RESPONSE: // 60
|
||||
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_AUTHENTICATING
|
||||
* - session->auth_state == SSH_AUTH_STATE_KBDINT_SENT
|
||||
* or
|
||||
* session->auth_state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT
|
||||
* or
|
||||
* session->auth_state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT
|
||||
*
|
||||
* Transitions:
|
||||
* Depending on the current state, the message is treated
|
||||
* differently:
|
||||
* - session->auth_state == SSH_AUTH_STATE_KBDINT_SENT
|
||||
* - session->auth_state = SSH_AUTH_STATE_INFO
|
||||
* - session->auth_state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT
|
||||
* - session->auth_state = SSH_AUTH_STATE_GSSAPI_TOKEN
|
||||
* - session->auth_state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT
|
||||
* - session->auth_state = SSH_AUTH_STATE_PK_OK
|
||||
* */
|
||||
|
||||
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((session->auth_state != SSH_AUTH_STATE_KBDINT_SENT) &&
|
||||
(session->auth_state != SSH_AUTH_STATE_PUBKEY_OFFER_SENT) &&
|
||||
(session->auth_state != SSH_AUTH_STATE_GSSAPI_REQUEST_SENT))
|
||||
{
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_USERAUTH_INFO_RESPONSE: // 61
|
||||
// SSH2_MSG_USERAUTH_GSSAPI_TOKEN: // 61
|
||||
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_AUTHENTICATING
|
||||
* - session_state->auth_state == SSH_SESSION_STATE_GSSAPI_TOKEN
|
||||
* or
|
||||
* session_state->auth_state == SSH_SESSION_STATE_INFO
|
||||
*
|
||||
* Transitions:
|
||||
* - None
|
||||
* */
|
||||
|
||||
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((session->auth_state != SSH_AUTH_STATE_INFO) &&
|
||||
(session->auth_state != SSH_AUTH_STATE_GSSAPI_TOKEN))
|
||||
{
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE: // 63
|
||||
/* TODO Not filtered */
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_USERAUTH_GSSAPI_ERROR: // 64
|
||||
/* TODO Not filtered */
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_USERAUTH_GSSAPI_ERRTOK: // 65
|
||||
/* TODO Not filtered */
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_USERAUTH_GSSAPI_MIC: // 66
|
||||
/* Server only */
|
||||
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_AUTHENTICATING
|
||||
* - session->gssapi->state == SSH_GSSAPI_STATE_RCV_MIC
|
||||
*
|
||||
* Transitions:
|
||||
* Depending on the result of the verification, the states are
|
||||
* changed:
|
||||
* - SSH_AUTH_SUCCESS:
|
||||
* - session->session_state = SSH_SESSION_STATE_AUTHENTICATED
|
||||
* - session->flags != SSH_SESSION_FLAG_AUTHENTICATED
|
||||
* - SSH_AUTH_PARTIAL:
|
||||
* - None
|
||||
* - any other case:
|
||||
* - None
|
||||
* */
|
||||
|
||||
/* If this is a client, reject the message */
|
||||
if (session->client) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (session->dh_handshake_state != DH_STATE_FINISHED) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_GLOBAL_REQUEST: // 80
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
|
||||
*
|
||||
* Transitions:
|
||||
* - None
|
||||
* */
|
||||
|
||||
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_REQUEST_SUCCESS: // 81
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
|
||||
* - session->global_req_state == SSH_CHANNEL_REQ_STATE_PENDING
|
||||
*
|
||||
* Transitions:
|
||||
* - session->global_req_state == SSH_CHANNEL_REQ_STATE_ACCEPTED
|
||||
* */
|
||||
|
||||
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_REQUEST_FAILURE: // 82
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
|
||||
* - session->global_req_state == SSH_CHANNEL_REQ_STATE_PENDING
|
||||
*
|
||||
* Transitions:
|
||||
* - session->global_req_state == SSH_CHANNEL_REQ_STATE_DENIED
|
||||
* */
|
||||
|
||||
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_CHANNEL_OPEN: // 90
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
|
||||
*
|
||||
* Transitions:
|
||||
* - None
|
||||
* */
|
||||
|
||||
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: // 91
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
|
||||
*
|
||||
* Transitions:
|
||||
* - channel->state = SSH_CHANNEL_STATE_OPEN
|
||||
* - channel->flags &= ~SSH_CHANNEL_FLAG_NOT_BOUND
|
||||
* */
|
||||
|
||||
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_CHANNEL_OPEN_FAILURE: // 92
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
|
||||
*
|
||||
* Transitions:
|
||||
* - channel->state = SSH_CHANNEL_STATE_OPEN_DENIED
|
||||
* */
|
||||
|
||||
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_CHANNEL_WINDOW_ADJUST: // 93
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
|
||||
*
|
||||
* Transitions:
|
||||
* - None
|
||||
* */
|
||||
|
||||
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_CHANNEL_DATA: // 94
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
|
||||
*
|
||||
* Transitions:
|
||||
* - None
|
||||
* */
|
||||
|
||||
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_CHANNEL_EXTENDED_DATA: // 95
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
|
||||
*
|
||||
* Transitions:
|
||||
* - None
|
||||
* */
|
||||
|
||||
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_CHANNEL_EOF: // 96
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
|
||||
*
|
||||
* Transitions:
|
||||
* - None
|
||||
* */
|
||||
|
||||
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_CHANNEL_CLOSE: // 97
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
|
||||
*
|
||||
* Transitions:
|
||||
* - channel->state = SSH_CHANNEL_STATE_CLOSED
|
||||
* - channel->flags |= SSH_CHANNEL_FLAG_CLOSED_REMOTE
|
||||
* */
|
||||
|
||||
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_CHANNEL_REQUEST: // 98
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
|
||||
*
|
||||
* Transitions:
|
||||
* - Depends on the request
|
||||
* */
|
||||
|
||||
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_CHANNEL_SUCCESS: // 99
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
|
||||
* - channel->request_state == SSH_CHANNEL_REQ_STATE_PENDING
|
||||
*
|
||||
* Transitions:
|
||||
* - channel->request_state = SSH_CHANNEL_REQ_STATE_ACCEPTED
|
||||
* */
|
||||
|
||||
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
case SSH2_MSG_CHANNEL_FAILURE: // 100
|
||||
/*
|
||||
* States required:
|
||||
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
|
||||
* - channel->request_state == SSH_CHANNEL_REQ_STATE_PENDING
|
||||
*
|
||||
* Transitions:
|
||||
* - channel->request_state = SSH_CHANNEL_REQ_STATE_DENIED
|
||||
* */
|
||||
|
||||
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
|
||||
rc = SSH_PACKET_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = SSH_PACKET_ALLOWED;
|
||||
break;
|
||||
default:
|
||||
/* Unknown message, do not filter */
|
||||
rc = SSH_PACKET_UNKNOWN;
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
#ifdef DEBUG_PACKET
|
||||
if (rc == SSH_PACKET_DENIED) {
|
||||
SSH_LOG(SSH_LOG_PACKET, "REJECTED packet type %d: ",
|
||||
session->in_packet.type);
|
||||
}
|
||||
|
||||
if (rc == SSH_PACKET_UNKNOWN) {
|
||||
SSH_LOG(SSH_LOG_PACKET, "UNKNOWN packet type %d",
|
||||
session->in_packet.type);
|
||||
}
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* in nonblocking mode, socket_read will read as much as it can, and return */
|
||||
/* SSH_OK if it has read at least len bytes, otherwise, SSH_AGAIN. */
|
||||
/* in blocking mode, it will read at least len bytes and will block until it's ok. */
|
||||
@@ -153,6 +923,7 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
|
||||
uint32_t len, compsize, payloadsize;
|
||||
uint8_t padding;
|
||||
size_t processed = 0; /* number of byte processed from the callback */
|
||||
enum ssh_packet_filter_result_e filter_result;
|
||||
|
||||
if(session->current_crypto != NULL) {
|
||||
current_macsize = hmac_digest_len(session->current_crypto->in_hmac);
|
||||
@@ -328,8 +1099,21 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
|
||||
"packet: read type %hhd [len=%d,padding=%hhd,comp=%d,payload=%d]",
|
||||
session->in_packet.type, len, padding, compsize, payloadsize);
|
||||
|
||||
/* Execute callbacks */
|
||||
ssh_packet_process(session, session->in_packet.type);
|
||||
/* Check if the packet is expected */
|
||||
filter_result = ssh_packet_incoming_filter(session);
|
||||
|
||||
switch(filter_result) {
|
||||
case SSH_PACKET_ALLOWED:
|
||||
/* Execute callbacks */
|
||||
ssh_packet_process(session, session->in_packet.type);
|
||||
break;
|
||||
case SSH_PACKET_DENIED:
|
||||
goto error;
|
||||
case SSH_PACKET_UNKNOWN:
|
||||
ssh_packet_send_unimplemented(session, session->recv_seq - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
session->packet_state = PACKET_STATE_INIT;
|
||||
if (processed < receivedlen) {
|
||||
/* Handle a potential packet left in socket buffer */
|
||||
|
||||
16
src/pki.c
16
src/pki.c
@@ -271,7 +271,7 @@ int ssh_key_is_public(const ssh_key k) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (k->flags & SSH_KEY_FLAG_PUBLIC);
|
||||
return (k->flags & SSH_KEY_FLAG_PUBLIC) == SSH_KEY_FLAG_PUBLIC;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -286,7 +286,7 @@ int ssh_key_is_private(const ssh_key k) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (k->flags & SSH_KEY_FLAG_PRIVATE);
|
||||
return (k->flags & SSH_KEY_FLAG_PRIVATE) == SSH_KEY_FLAG_PRIVATE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -955,7 +955,7 @@ int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey)
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
file = fopen(filename, "r");
|
||||
file = fopen(filename, "rb");
|
||||
if (file == NULL) {
|
||||
ssh_pki_log("Error opening %s: %s",
|
||||
filename, strerror(errno));
|
||||
@@ -999,7 +999,7 @@ int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey)
|
||||
key_buf[size] = '\0';
|
||||
|
||||
q = p = key_buf;
|
||||
while (!isspace((int)*p)) p++;
|
||||
while (*p != '\0' && !isspace((int)*p)) p++;
|
||||
*p = '\0';
|
||||
|
||||
type = ssh_key_type_from_name(q);
|
||||
@@ -1008,7 +1008,7 @@ int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey)
|
||||
return SSH_ERROR;
|
||||
}
|
||||
q = ++p;
|
||||
while (!isspace((int)*p)) p++;
|
||||
while (*p != '\0' && !isspace((int)*p)) p++;
|
||||
*p = '\0';
|
||||
|
||||
rc = ssh_pki_import_pubkey_base64(q, type, pkey);
|
||||
@@ -1094,7 +1094,7 @@ error:
|
||||
* @param[out] pkey A pointer to store the newly allocated public key. You
|
||||
* NEED to free the key.
|
||||
*
|
||||
* @return A public key, NULL on error.
|
||||
* @return SSH_OK on success, SSH_ERROR on error.
|
||||
*
|
||||
* @see ssh_key_free()
|
||||
*/
|
||||
@@ -1233,7 +1233,7 @@ int ssh_pki_export_pubkey_file(const ssh_key key,
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
fp = fopen(filename, "w+");
|
||||
fp = fopen(filename, "wb+");
|
||||
if (fp == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
@@ -1584,7 +1584,7 @@ ssh_string ssh_srv_pki_do_sign_sessionid(ssh_session session,
|
||||
const ssh_key privkey)
|
||||
{
|
||||
struct ssh_crypto_struct *crypto;
|
||||
ssh_signature sig;
|
||||
ssh_signature sig = NULL;
|
||||
ssh_string sig_blob;
|
||||
int rc;
|
||||
|
||||
|
||||
292
src/pki_crypto.c
292
src/pki_crypto.c
@@ -31,6 +31,7 @@
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include "libcrypto-compat.h"
|
||||
|
||||
#ifdef HAVE_OPENSSL_EC_H
|
||||
#include <openssl/ec.h>
|
||||
@@ -230,7 +231,10 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
|
||||
}
|
||||
|
||||
switch (key->type) {
|
||||
case SSH_KEYTYPE_DSS:
|
||||
case SSH_KEYTYPE_DSS: {
|
||||
const BIGNUM *p = NULL, *q = NULL, *g = NULL,
|
||||
*pub_key = NULL, *priv_key = NULL;
|
||||
BIGNUM *np, *nq, *ng, *npub_key, *npriv_key;
|
||||
new->dsa = DSA_new();
|
||||
if (new->dsa == NULL) {
|
||||
goto fail;
|
||||
@@ -243,36 +247,54 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
|
||||
* pub_key = public key y = g^x
|
||||
* priv_key = private key x
|
||||
*/
|
||||
new->dsa->p = BN_dup(key->dsa->p);
|
||||
if (new->dsa->p == NULL) {
|
||||
DSA_get0_pqg(key->dsa, &p, &q, &g);
|
||||
np = BN_dup(p);
|
||||
nq = BN_dup(q);
|
||||
ng = BN_dup(g);
|
||||
if (np == NULL || nq == NULL || ng == NULL) {
|
||||
BN_free(np);
|
||||
BN_free(nq);
|
||||
BN_free(ng);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
new->dsa->q = BN_dup(key->dsa->q);
|
||||
if (new->dsa->q == NULL) {
|
||||
rc = DSA_set0_pqg(new->dsa, np, nq, ng);
|
||||
if (rc == 0) {
|
||||
BN_free(np);
|
||||
BN_free(nq);
|
||||
BN_free(ng);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
new->dsa->g = BN_dup(key->dsa->g);
|
||||
if (new->dsa->g == NULL) {
|
||||
DSA_get0_key(key->dsa, &pub_key, &priv_key);
|
||||
npub_key = BN_dup(pub_key);
|
||||
if (npub_key == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
new->dsa->pub_key = BN_dup(key->dsa->pub_key);
|
||||
if (new->dsa->pub_key == NULL) {
|
||||
rc = DSA_set0_key(new->dsa, npub_key, NULL);
|
||||
if (rc == 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!demote && (key->flags & SSH_KEY_FLAG_PRIVATE)) {
|
||||
new->dsa->priv_key = BN_dup(key->dsa->priv_key);
|
||||
if (new->dsa->priv_key == NULL) {
|
||||
npriv_key = BN_dup(priv_key);
|
||||
if (npriv_key == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = DSA_set0_key(new->dsa, NULL, npriv_key);
|
||||
if (rc == 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SSH_KEYTYPE_RSA:
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
case SSH_KEYTYPE_RSA1: {
|
||||
const BIGNUM *n = NULL, *e = NULL, *d = NULL;
|
||||
BIGNUM *nn, *ne, *nd;
|
||||
new->rsa = RSA_new();
|
||||
if (new->rsa == NULL) {
|
||||
goto fail;
|
||||
@@ -288,62 +310,82 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
|
||||
* dmq1 = d mod (q-1)
|
||||
* iqmp = q^-1 mod p
|
||||
*/
|
||||
new->rsa->n = BN_dup(key->rsa->n);
|
||||
if (new->rsa->n == NULL) {
|
||||
RSA_get0_key(key->rsa, &n, &e, &d);
|
||||
nn = BN_dup(n);
|
||||
ne = BN_dup(e);
|
||||
if (nn == NULL || ne == NULL) {
|
||||
BN_free(nn);
|
||||
BN_free(ne);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
new->rsa->e = BN_dup(key->rsa->e);
|
||||
if (new->rsa->e == NULL) {
|
||||
rc = RSA_set0_key(new->rsa, nn, ne, NULL);
|
||||
if (rc == 0) {
|
||||
BN_free(nn);
|
||||
BN_free(ne);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!demote && (key->flags & SSH_KEY_FLAG_PRIVATE)) {
|
||||
new->rsa->d = BN_dup(key->rsa->d);
|
||||
if (new->rsa->d == NULL) {
|
||||
const BIGNUM *p = NULL, *q = NULL, *dmp1 = NULL,
|
||||
*dmq1 = NULL, *iqmp = NULL;
|
||||
BIGNUM *np, *nq, *ndmp1, *ndmq1, *niqmp;
|
||||
|
||||
nd = BN_dup(d);
|
||||
if (nd == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = RSA_set0_key(new->rsa, NULL, NULL, nd);
|
||||
if (rc == 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* p, q, dmp1, dmq1 and iqmp may be NULL in private keys, but the
|
||||
* RSA operations are much faster when these values are available.
|
||||
*/
|
||||
if (key->rsa->p != NULL) {
|
||||
new->rsa->p = BN_dup(key->rsa->p);
|
||||
if (new->rsa->p == NULL) {
|
||||
RSA_get0_factors(key->rsa, &p, &q);
|
||||
if (p != NULL && q != NULL) { /* need to set both of them */
|
||||
np = BN_dup(p);
|
||||
nq = BN_dup(q);
|
||||
if (np == NULL || nq == NULL) {
|
||||
BN_free(np);
|
||||
BN_free(nq);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = RSA_set0_factors(new->rsa, np, nq);
|
||||
if (rc == 0) {
|
||||
BN_free(np);
|
||||
BN_free(nq);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (key->rsa->q != NULL) {
|
||||
new->rsa->q = BN_dup(key->rsa->q);
|
||||
if (new->rsa->q == NULL) {
|
||||
RSA_get0_crt_params(key->rsa, &dmp1, &dmq1, &iqmp);
|
||||
if (dmp1 != NULL || dmq1 != NULL || iqmp != NULL) {
|
||||
ndmp1 = BN_dup(dmp1);
|
||||
ndmq1 = BN_dup(dmq1);
|
||||
niqmp = BN_dup(iqmp);
|
||||
if (ndmp1 == NULL || ndmq1 == NULL || niqmp == NULL) {
|
||||
BN_free(ndmp1);
|
||||
BN_free(ndmq1);
|
||||
BN_free(niqmp);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (key->rsa->dmp1 != NULL) {
|
||||
new->rsa->dmp1 = BN_dup(key->rsa->dmp1);
|
||||
if (new->rsa->dmp1 == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (key->rsa->dmq1 != NULL) {
|
||||
new->rsa->dmq1 = BN_dup(key->rsa->dmq1);
|
||||
if (new->rsa->dmq1 == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (key->rsa->iqmp != NULL) {
|
||||
new->rsa->iqmp = BN_dup(key->rsa->iqmp);
|
||||
if (new->rsa->iqmp == NULL) {
|
||||
rc = RSA_set0_crt_params(new->rsa, ndmp1, ndmq1, niqmp);
|
||||
if (rc == 0) {
|
||||
BN_free(ndmp1);
|
||||
BN_free(ndmq1);
|
||||
BN_free(niqmp);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SSH_KEYTYPE_ECDSA:
|
||||
#ifdef HAVE_OPENSSL_ECC
|
||||
new->ecdsa_nid = key->ecdsa_nid;
|
||||
@@ -466,51 +508,64 @@ int pki_key_compare(const ssh_key k1,
|
||||
enum ssh_keycmp_e what)
|
||||
{
|
||||
switch (k1->type) {
|
||||
case SSH_KEYTYPE_DSS:
|
||||
case SSH_KEYTYPE_DSS: {
|
||||
const BIGNUM *p1, *p2, *q1, *q2, *g1, *g2,
|
||||
*pub_key1, *pub_key2, *priv_key1, *priv_key2;
|
||||
if (DSA_size(k1->dsa) != DSA_size(k2->dsa)) {
|
||||
return 1;
|
||||
}
|
||||
if (bignum_cmp(k1->dsa->p, k2->dsa->p) != 0) {
|
||||
DSA_get0_pqg(k1->dsa, &p1, &q1, &g1);
|
||||
DSA_get0_pqg(k2->dsa, &p2, &q2, &g2);
|
||||
if (bignum_cmp(p1, p2) != 0) {
|
||||
return 1;
|
||||
}
|
||||
if (bignum_cmp(k1->dsa->q, k2->dsa->q) != 0) {
|
||||
if (bignum_cmp(q1, q2) != 0) {
|
||||
return 1;
|
||||
}
|
||||
if (bignum_cmp(k1->dsa->g, k2->dsa->g) != 0) {
|
||||
if (bignum_cmp(g1, g2) != 0) {
|
||||
return 1;
|
||||
}
|
||||
if (bignum_cmp(k1->dsa->pub_key, k2->dsa->pub_key) != 0) {
|
||||
DSA_get0_key(k1->dsa, &pub_key1, &priv_key1);
|
||||
DSA_get0_key(k2->dsa, &pub_key2, &priv_key2);
|
||||
if (bignum_cmp(pub_key1, pub_key2) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (what == SSH_KEY_CMP_PRIVATE) {
|
||||
if (bignum_cmp(k1->dsa->priv_key, k2->dsa->priv_key) != 0) {
|
||||
if (bignum_cmp(priv_key1, priv_key2) != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SSH_KEYTYPE_RSA:
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
case SSH_KEYTYPE_RSA1: {
|
||||
const BIGNUM *e1, *e2, *n1, *n2, *p1, *p2, *q1, *q2;
|
||||
if (RSA_size(k1->rsa) != RSA_size(k2->rsa)) {
|
||||
return 1;
|
||||
}
|
||||
if (bignum_cmp(k1->rsa->e, k2->rsa->e) != 0) {
|
||||
RSA_get0_key(k1->rsa, &n1, &e1, NULL);
|
||||
RSA_get0_key(k2->rsa, &n2, &e2, NULL);
|
||||
if (bignum_cmp(e1, e2) != 0) {
|
||||
return 1;
|
||||
}
|
||||
if (bignum_cmp(k1->rsa->n, k2->rsa->n) != 0) {
|
||||
if (bignum_cmp(n1, n2) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (what == SSH_KEY_CMP_PRIVATE) {
|
||||
if (bignum_cmp(k1->rsa->p, k2->rsa->p) != 0) {
|
||||
RSA_get0_factors(k1->rsa, &p1, &q1);
|
||||
RSA_get0_factors(k2->rsa, &p2, &q2);
|
||||
if (bignum_cmp(p1, p2) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (bignum_cmp(k1->rsa->q, k2->rsa->q) != 0) {
|
||||
if (bignum_cmp(q1, q2) != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SSH_KEYTYPE_ECDSA:
|
||||
#ifdef HAVE_OPENSSL_ECC
|
||||
{
|
||||
@@ -819,19 +874,32 @@ int pki_pubkey_build_dss(ssh_key key,
|
||||
ssh_string q,
|
||||
ssh_string g,
|
||||
ssh_string pubkey) {
|
||||
int rc;
|
||||
BIGNUM *bp, *bq, *bg, *bpub_key;
|
||||
|
||||
key->dsa = DSA_new();
|
||||
if (key->dsa == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
key->dsa->p = make_string_bn(p);
|
||||
key->dsa->q = make_string_bn(q);
|
||||
key->dsa->g = make_string_bn(g);
|
||||
key->dsa->pub_key = make_string_bn(pubkey);
|
||||
if (key->dsa->p == NULL ||
|
||||
key->dsa->q == NULL ||
|
||||
key->dsa->g == NULL ||
|
||||
key->dsa->pub_key == NULL) {
|
||||
bp = make_string_bn(p);
|
||||
bq = make_string_bn(q);
|
||||
bg = make_string_bn(g);
|
||||
bpub_key = make_string_bn(pubkey);
|
||||
if (bp == NULL || bq == NULL ||
|
||||
bg == NULL || bpub_key == NULL) {
|
||||
DSA_free(key->dsa);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = DSA_set0_pqg(key->dsa, bp, bq, bg);
|
||||
if (rc == 0) {
|
||||
DSA_free(key->dsa);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = DSA_set0_key(key->dsa, bpub_key, NULL);
|
||||
if (rc == 0) {
|
||||
DSA_free(key->dsa);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
@@ -842,15 +910,23 @@ int pki_pubkey_build_dss(ssh_key key,
|
||||
int pki_pubkey_build_rsa(ssh_key key,
|
||||
ssh_string e,
|
||||
ssh_string n) {
|
||||
int rc;
|
||||
BIGNUM *be, *bn;
|
||||
|
||||
key->rsa = RSA_new();
|
||||
if (key->rsa == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
key->rsa->e = make_string_bn(e);
|
||||
key->rsa->n = make_string_bn(n);
|
||||
if (key->rsa->e == NULL ||
|
||||
key->rsa->n == NULL) {
|
||||
be = make_string_bn(e);
|
||||
bn = make_string_bn(n);
|
||||
if (be == NULL || bn == NULL) {
|
||||
RSA_free(key->rsa);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = RSA_set0_key(key->rsa, bn, be, NULL);
|
||||
if (rc == 0) {
|
||||
RSA_free(key->rsa);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
@@ -889,23 +965,26 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
|
||||
}
|
||||
|
||||
switch (key->type) {
|
||||
case SSH_KEYTYPE_DSS:
|
||||
p = make_bignum_string(key->dsa->p);
|
||||
case SSH_KEYTYPE_DSS: {
|
||||
const BIGNUM *bp, *bq, *bg, *bpub_key;
|
||||
DSA_get0_pqg(key->dsa, &bp, &bq, &bg);
|
||||
p = make_bignum_string((BIGNUM *)bp);
|
||||
if (p == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
q = make_bignum_string(key->dsa->q);
|
||||
q = make_bignum_string((BIGNUM *)bq);
|
||||
if (q == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
g = make_bignum_string(key->dsa->g);
|
||||
g = make_bignum_string((BIGNUM *)bg);
|
||||
if (g == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
n = make_bignum_string(key->dsa->pub_key);
|
||||
DSA_get0_key(key->dsa, &bpub_key, NULL);
|
||||
n = make_bignum_string((BIGNUM *)bpub_key);
|
||||
if (n == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
@@ -937,14 +1016,17 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
|
||||
n = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
case SSH_KEYTYPE_RSA:
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
e = make_bignum_string(key->rsa->e);
|
||||
case SSH_KEYTYPE_RSA1: {
|
||||
const BIGNUM *be, *bn;
|
||||
RSA_get0_key(key->rsa, &bn, &be, NULL);
|
||||
e = make_bignum_string((BIGNUM *)be);
|
||||
if (e == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
n = make_bignum_string(key->rsa->n);
|
||||
n = make_bignum_string((BIGNUM *)bn);
|
||||
if (n == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
@@ -964,6 +1046,7 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
|
||||
n = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
case SSH_KEYTYPE_ECDSA:
|
||||
#ifdef HAVE_OPENSSL_ECC
|
||||
rc = ssh_buffer_reinit(buffer);
|
||||
@@ -1065,13 +1148,15 @@ int pki_export_pubkey_rsa1(const ssh_key key,
|
||||
char *e;
|
||||
char *n;
|
||||
int rsa_size = RSA_size(key->rsa);
|
||||
const BIGNUM *be, *bn;
|
||||
|
||||
e = bignum_bn2dec(key->rsa->e);
|
||||
RSA_get0_key(key->rsa, &bn, &be, NULL);
|
||||
e = bignum_bn2dec(be);
|
||||
if (e == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
n = bignum_bn2dec(key->rsa->n);
|
||||
n = bignum_bn2dec(bn);
|
||||
if (n == NULL) {
|
||||
OPENSSL_free(e);
|
||||
return SSH_ERROR;
|
||||
@@ -1136,6 +1221,7 @@ static ssh_string pki_dsa_signature_to_blob(const ssh_signature sig)
|
||||
{
|
||||
char buffer[40] = { 0 };
|
||||
ssh_string sig_blob = NULL;
|
||||
const BIGNUM *pr, *ps;
|
||||
|
||||
ssh_string r;
|
||||
int r_len, r_offset_in, r_offset_out;
|
||||
@@ -1143,12 +1229,13 @@ static ssh_string pki_dsa_signature_to_blob(const ssh_signature sig)
|
||||
ssh_string s;
|
||||
int s_len, s_offset_in, s_offset_out;
|
||||
|
||||
r = make_bignum_string(sig->dsa_sig->r);
|
||||
DSA_SIG_get0(sig->dsa_sig, &pr, &ps);
|
||||
r = make_bignum_string((BIGNUM *)pr);
|
||||
if (r == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = make_bignum_string(sig->dsa_sig->s);
|
||||
s = make_bignum_string((BIGNUM *)ps);
|
||||
if (s == NULL) {
|
||||
ssh_string_free(r);
|
||||
return NULL;
|
||||
@@ -1201,13 +1288,15 @@ ssh_string pki_signature_to_blob(const ssh_signature sig)
|
||||
ssh_string s;
|
||||
ssh_buffer b;
|
||||
int rc;
|
||||
const BIGNUM *pr, *ps;
|
||||
|
||||
b = ssh_buffer_new();
|
||||
if (b == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r = make_bignum_string(sig->ecdsa_sig->r);
|
||||
ECDSA_SIG_get0(sig->ecdsa_sig, &pr, &ps);
|
||||
r = make_bignum_string((BIGNUM *)pr);
|
||||
if (r == NULL) {
|
||||
ssh_buffer_free(b);
|
||||
return NULL;
|
||||
@@ -1219,7 +1308,7 @@ ssh_string pki_signature_to_blob(const ssh_signature sig)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = make_bignum_string(sig->ecdsa_sig->s);
|
||||
s = make_bignum_string((BIGNUM *)ps);
|
||||
if (s == NULL) {
|
||||
ssh_buffer_free(b);
|
||||
return NULL;
|
||||
@@ -1324,6 +1413,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
ssh_string s;
|
||||
size_t len;
|
||||
int rc;
|
||||
BIGNUM *pr = NULL, *ps = NULL;
|
||||
|
||||
sig = ssh_signature_new();
|
||||
if (sig == NULL) {
|
||||
@@ -1363,9 +1453,9 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
}
|
||||
ssh_string_fill(r, ssh_string_data(sig_blob), 20);
|
||||
|
||||
sig->dsa_sig->r = make_string_bn(r);
|
||||
pr = make_string_bn(r);
|
||||
ssh_string_free(r);
|
||||
if (sig->dsa_sig->r == NULL) {
|
||||
if (pr == NULL) {
|
||||
ssh_signature_free(sig);
|
||||
return NULL;
|
||||
}
|
||||
@@ -1377,9 +1467,15 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
}
|
||||
ssh_string_fill(s, (char *)ssh_string_data(sig_blob) + 20, 20);
|
||||
|
||||
sig->dsa_sig->s = make_string_bn(s);
|
||||
ps = make_string_bn(s);
|
||||
ssh_string_free(s);
|
||||
if (sig->dsa_sig->s == NULL) {
|
||||
if (ps == NULL) {
|
||||
ssh_signature_free(sig);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rc = DSA_SIG_set0(sig->dsa_sig, pr, ps);
|
||||
if (rc == 0) {
|
||||
ssh_signature_free(sig);
|
||||
return NULL;
|
||||
}
|
||||
@@ -1427,10 +1523,10 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
ssh_print_hexa("r", ssh_string_data(r), ssh_string_len(r));
|
||||
#endif
|
||||
|
||||
make_string_bn_inplace(r, sig->ecdsa_sig->r);
|
||||
pr = make_string_bn(r);
|
||||
ssh_string_burn(r);
|
||||
ssh_string_free(r);
|
||||
if (sig->ecdsa_sig->r == NULL) {
|
||||
if (pr == NULL) {
|
||||
ssh_buffer_free(b);
|
||||
ssh_signature_free(sig);
|
||||
return NULL;
|
||||
@@ -1448,10 +1544,16 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
ssh_print_hexa("s", ssh_string_data(s), ssh_string_len(s));
|
||||
#endif
|
||||
|
||||
make_string_bn_inplace(s, sig->ecdsa_sig->s);
|
||||
ps = make_string_bn(s);
|
||||
ssh_string_burn(s);
|
||||
ssh_string_free(s);
|
||||
if (sig->ecdsa_sig->s == NULL) {
|
||||
if (ps == NULL) {
|
||||
ssh_signature_free(sig);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rc = ECDSA_SIG_set0(sig->ecdsa_sig, pr, ps);
|
||||
if (rc == 0) {
|
||||
ssh_signature_free(sig);
|
||||
return NULL;
|
||||
}
|
||||
@@ -1578,8 +1680,12 @@ ssh_signature pki_do_sign(const ssh_key privkey,
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_bignum("r", sig->dsa_sig->r);
|
||||
ssh_print_bignum("s", sig->dsa_sig->s);
|
||||
{
|
||||
const BIGNUM *pr, *ps;
|
||||
DSA_SIG_get0(sig->dsa_sig, &pr, &ps);
|
||||
ssh_print_bignum("r", (BIGNUM *) pr);
|
||||
ssh_print_bignum("s", (BIGNUM *) ps);
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
@@ -1601,8 +1707,12 @@ ssh_signature pki_do_sign(const ssh_key privkey,
|
||||
}
|
||||
|
||||
# ifdef DEBUG_CRYPTO
|
||||
ssh_print_bignum("r", sig->ecdsa_sig->r);
|
||||
ssh_print_bignum("s", sig->ecdsa_sig->s);
|
||||
{
|
||||
const BIGNUM *pr, *ps;
|
||||
ECDSA_SIG_get0(sig->ecdsa_sig, &pr, &ps);
|
||||
ssh_print_bignum("r", (BIGNUM *) pr);
|
||||
ssh_print_bignum("s", (BIGNUM *) ps);
|
||||
}
|
||||
# endif /* DEBUG_CRYPTO */
|
||||
|
||||
break;
|
||||
|
||||
@@ -35,8 +35,8 @@ int pki_key_generate_ed25519(ssh_key key)
|
||||
goto error;
|
||||
}
|
||||
|
||||
key->ed25519_pubkey = malloc(sizeof (ed25519_privkey));
|
||||
if (key->ed25519_privkey == NULL) {
|
||||
key->ed25519_pubkey = malloc(sizeof (ed25519_pubkey));
|
||||
if (key->ed25519_pubkey == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -199,24 +199,27 @@ int pki_ed25519_key_cmp(const ssh_key k1,
|
||||
*/
|
||||
int pki_ed25519_key_dup(ssh_key new, const ssh_key key)
|
||||
{
|
||||
if (key->ed25519_privkey == NULL || key->ed25519_pubkey == NULL) {
|
||||
if (key->ed25519_privkey == NULL && key->ed25519_pubkey == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
new->ed25519_privkey = malloc(ED25519_SK_LEN);
|
||||
if (new->ed25519_privkey == NULL) {
|
||||
return SSH_ERROR;
|
||||
if (key->ed25519_privkey != NULL) {
|
||||
new->ed25519_privkey = malloc(ED25519_SK_LEN);
|
||||
if (new->ed25519_privkey == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
memcpy(new->ed25519_privkey, key->ed25519_privkey, ED25519_SK_LEN);
|
||||
}
|
||||
|
||||
new->ed25519_pubkey = malloc(ED25519_PK_LEN);
|
||||
if (new->ed25519_privkey == NULL || new->ed25519_pubkey == NULL){
|
||||
SAFE_FREE(new->ed25519_privkey);
|
||||
return SSH_ERROR;
|
||||
if (key->ed25519_pubkey != NULL) {
|
||||
new->ed25519_pubkey = malloc(ED25519_PK_LEN);
|
||||
if (new->ed25519_pubkey == NULL) {
|
||||
SAFE_FREE(new->ed25519_privkey);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
memcpy(new->ed25519_pubkey, key->ed25519_pubkey, ED25519_PK_LEN);
|
||||
}
|
||||
|
||||
memcpy(new->ed25519_privkey, key->ed25519_privkey, ED25519_SK_LEN);
|
||||
memcpy(new->ed25519_pubkey, key->ed25519_pubkey, ED25519_PK_LEN);
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -737,7 +737,7 @@ int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e)
|
||||
ssh_key pki_key_dup(const ssh_key key, int demote)
|
||||
{
|
||||
ssh_key new;
|
||||
gcry_sexp_t sexp;
|
||||
gcry_sexp_t sexp = NULL;
|
||||
gcry_error_t err;
|
||||
const char *tmp = NULL;
|
||||
size_t size;
|
||||
|
||||
@@ -116,7 +116,11 @@ static poll_fn ssh_poll_emu;
|
||||
#else /* _WIN32 */
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
# ifdef HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
# endif
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
|
||||
@@ -746,7 +746,7 @@ int ssh_message_global_request_reply_success(ssh_message msg, uint16_t bound_por
|
||||
if(msg->global_request.type == SSH_GLOBAL_REQUEST_TCPIP_FORWARD
|
||||
&& msg->global_request.bind_port == 0) {
|
||||
rc = ssh_buffer_pack(msg->session->out_buffer, "d", bound_port);
|
||||
if (rc != SSH_ERROR) {
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(msg->session);
|
||||
goto error;
|
||||
}
|
||||
@@ -976,6 +976,7 @@ int ssh_message_auth_interactive_request(ssh_message msg, const char *name,
|
||||
msg->session->kbdint->prompts = NULL;
|
||||
msg->session->kbdint->echo = NULL;
|
||||
}
|
||||
msg->session->auth_state = SSH_AUTH_STATE_INFO;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
#include "libssh/crypto.h"
|
||||
#include "libssh/server.h"
|
||||
#include "libssh/socket.h"
|
||||
#ifdef WITH_SSH1
|
||||
#include "libssh/ssh1.h"
|
||||
#endif /* WITH_SSH1 */
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/agent.h"
|
||||
#include "libssh/packet.h"
|
||||
@@ -115,6 +118,15 @@ ssh_session ssh_new(void) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
id = strdup("%d/id_ed25519");
|
||||
if (id == NULL) {
|
||||
goto err;
|
||||
}
|
||||
rc = ssh_list_append(session->opts.identity, id);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ECC
|
||||
id = strdup("%d/id_ecdsa");
|
||||
if (id == NULL) {
|
||||
@@ -245,6 +257,10 @@ void ssh_free(ssh_session session) {
|
||||
ssh_list_free(session->ssh_message_list);
|
||||
}
|
||||
|
||||
if (session->kbdint != NULL) {
|
||||
ssh_kbdint_free(session->kbdint);
|
||||
}
|
||||
|
||||
if (session->packet_callbacks) {
|
||||
ssh_list_free(session->packet_callbacks);
|
||||
}
|
||||
@@ -261,6 +277,11 @@ void ssh_free(ssh_session session) {
|
||||
ssh_list_free(session->opts.identity);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
ssh_agent_state_free (session->agent_state);
|
||||
#endif
|
||||
session->agent_state = NULL;
|
||||
|
||||
SAFE_FREE(session->auth_auto_state);
|
||||
SAFE_FREE(session->serverbanner);
|
||||
SAFE_FREE(session->clientbanner);
|
||||
@@ -816,13 +837,17 @@ void ssh_socket_exception_callback(int code, int errno_code, void *user){
|
||||
* @return SSH_OK on success, SSH_ERROR otherwise.
|
||||
*/
|
||||
int ssh_send_ignore (ssh_session session, const char *data) {
|
||||
#ifdef WITH_SSH1
|
||||
const int type = session->version == 1 ? SSH_MSG_IGNORE : SSH2_MSG_IGNORE;
|
||||
#else /* WITH_SSH1 */
|
||||
const int type = SSH2_MSG_IGNORE;
|
||||
#endif /* WITH_SSH1 */
|
||||
int rc;
|
||||
|
||||
if (ssh_socket_is_open(session->socket)) {
|
||||
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bs",
|
||||
SSH2_MSG_IGNORE,
|
||||
type,
|
||||
data);
|
||||
if (rc != SSH_OK){
|
||||
ssh_set_error_oom(session);
|
||||
@@ -854,12 +879,22 @@ int ssh_send_debug (ssh_session session, const char *message, int always_display
|
||||
int rc;
|
||||
|
||||
if (ssh_socket_is_open(session->socket)) {
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bbsd",
|
||||
SSH2_MSG_DEBUG,
|
||||
always_display != 0 ? 1 : 0,
|
||||
message,
|
||||
0); /* empty language tag */
|
||||
#ifdef WITH_SSH1
|
||||
if (session->version == 1) {
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bs",
|
||||
SSH_MSG_DEBUG,
|
||||
message);
|
||||
} else
|
||||
#endif /* WITH_SSH1 */
|
||||
{
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bbsd",
|
||||
SSH2_MSG_DEBUG,
|
||||
always_display != 0 ? 1 : 0,
|
||||
message,
|
||||
0); /* empty language tag */
|
||||
}
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
|
||||
50
src/sftp.c
50
src/sftp.c
@@ -315,7 +315,7 @@ sftp_packet sftp_packet_read(sftp_session sftp) {
|
||||
sftp_packet packet = NULL;
|
||||
uint32_t tmp;
|
||||
size_t size;
|
||||
int r;
|
||||
int r, s;
|
||||
|
||||
packet = malloc(sizeof(struct sftp_packet_struct));
|
||||
if (packet == NULL) {
|
||||
@@ -330,26 +330,33 @@ sftp_packet sftp_packet_read(sftp_session sftp) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r=ssh_channel_read(sftp->channel, buffer, 4, 0);
|
||||
if (r < 0) {
|
||||
ssh_buffer_free(packet->payload);
|
||||
SAFE_FREE(packet);
|
||||
return NULL;
|
||||
}
|
||||
r=0;
|
||||
do {
|
||||
// read from channel until 4 bytes have been read or an error occurs
|
||||
s=ssh_channel_read(sftp->channel, buffer+r, 4-r, 0);
|
||||
if (s < 0) {
|
||||
goto error;
|
||||
} else if (s == 0) {
|
||||
int is_eof;
|
||||
|
||||
is_eof = ssh_channel_is_eof(sftp->channel);
|
||||
if (is_eof) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
r += s;
|
||||
}
|
||||
} while (r<4);
|
||||
ssh_buffer_add_data(packet->payload, buffer, r);
|
||||
if (buffer_get_u32(packet->payload, &tmp) != sizeof(uint32_t)) {
|
||||
ssh_set_error(sftp->session, SSH_FATAL, "Short sftp packet!");
|
||||
ssh_buffer_free(packet->payload);
|
||||
SAFE_FREE(packet);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
r=ssh_channel_read(sftp->channel, buffer, 1, 0);
|
||||
if (r <= 0) {
|
||||
/* TODO: check if there are cases where an error needs to be set here */
|
||||
ssh_buffer_free(packet->payload);
|
||||
SAFE_FREE(packet);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
ssh_buffer_add_data(packet->payload, buffer, r);
|
||||
buffer_get_u8(packet->payload, &packet->type);
|
||||
@@ -366,20 +373,20 @@ sftp_packet sftp_packet_read(sftp_session sftp) {
|
||||
|
||||
if(r <= 0) {
|
||||
/* TODO: check if there are cases where an error needs to be set here */
|
||||
ssh_buffer_free(packet->payload);
|
||||
SAFE_FREE(packet);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
if (ssh_buffer_add_data(packet->payload, buffer, r) == SSH_ERROR) {
|
||||
ssh_buffer_free(packet->payload);
|
||||
SAFE_FREE(packet);
|
||||
ssh_set_error_oom(sftp->session);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
size -= r;
|
||||
}
|
||||
|
||||
return packet;
|
||||
error:
|
||||
ssh_buffer_free(packet->payload);
|
||||
SAFE_FREE(packet);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void sftp_set_error(sftp_session sftp, int errnum) {
|
||||
@@ -3070,7 +3077,10 @@ sftp_attributes sftp_fstat(sftp_file file) {
|
||||
}
|
||||
|
||||
if (msg->packet_type == SSH_FXP_ATTRS){
|
||||
return sftp_parse_attr(file->sftp, msg->payload, 0);
|
||||
sftp_attributes attr = sftp_parse_attr(file->sftp, msg->payload, 0);
|
||||
sftp_message_free(msg);
|
||||
|
||||
return attr;
|
||||
} else if (msg->packet_type == SSH_FXP_STATUS) {
|
||||
status = parse_status_msg(msg);
|
||||
sftp_message_free(msg);
|
||||
|
||||
@@ -194,9 +194,8 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) {
|
||||
break;
|
||||
case SSH_FXP_FSTAT:
|
||||
rc = ssh_buffer_unpack(payload,
|
||||
"Sd",
|
||||
&msg->handle,
|
||||
&msg->flags);
|
||||
"S",
|
||||
&msg->handle);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(session);
|
||||
sftp_client_message_free(msg);
|
||||
|
||||
@@ -27,8 +27,9 @@ set(LIBSSH_THREADS_LINK_LIBRARIES
|
||||
${LIBSSH_SHARED_LIBRARY}
|
||||
)
|
||||
|
||||
set(libssh_threads_SRCS
|
||||
)
|
||||
message(STATUS "threads library: Threads_FOUND=${Threads_FOUND}")
|
||||
|
||||
set(libssh_threads_SRCS) # empty SRC
|
||||
|
||||
# build and link pthread
|
||||
if (CMAKE_USE_PTHREADS_INIT)
|
||||
@@ -41,6 +42,8 @@ if (CMAKE_USE_PTHREADS_INIT)
|
||||
${LIBSSH_THREADS_LINK_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
|
||||
message(STATUS "libssh_threads_SRCS=${libssh_threads_SRCS}")
|
||||
endif (CMAKE_USE_PTHREADS_INIT)
|
||||
|
||||
set(LIBSSH_THREADS_LINK_LIBRARIES
|
||||
@@ -54,6 +57,8 @@ include_directories(
|
||||
)
|
||||
|
||||
if (libssh_threads_SRCS)
|
||||
set(LIBSSH_THREADS ON CACHE "libssh threads lib" INTERNAL)
|
||||
|
||||
add_library(${LIBSSH_THREADS_SHARED_LIBRARY} SHARED ${libssh_threads_SRCS})
|
||||
|
||||
target_link_libraries(${LIBSSH_THREADS_SHARED_LIBRARY} ${LIBSSH_THREADS_LINK_LIBRARIES})
|
||||
|
||||
@@ -160,6 +160,10 @@ void crypto_free(struct ssh_crypto_struct *crypto){
|
||||
#ifdef HAVE_ECDH
|
||||
SAFE_FREE(crypto->ecdh_client_pubkey);
|
||||
SAFE_FREE(crypto->ecdh_server_pubkey);
|
||||
if(crypto->ecdh_privkey != NULL){
|
||||
EC_KEY_free(crypto->ecdh_privkey);
|
||||
crypto->ecdh_privkey = NULL;
|
||||
}
|
||||
#endif
|
||||
if(crypto->session_id != NULL){
|
||||
memset(crypto->session_id, '\0', crypto->digest_len);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
project(tests C)
|
||||
project(libssh-tests C)
|
||||
|
||||
if (BSD OR SOLARIS OR OSX)
|
||||
find_package(Argp)
|
||||
@@ -9,9 +9,9 @@ set(TORTURE_LIBRARY torture)
|
||||
include_directories(
|
||||
${LIBSSH_PUBLIC_INCLUDE_DIRS}
|
||||
${CMOCKA_INCLUDE_DIR}
|
||||
${OPENSSL_INCLUDE_DIRS}
|
||||
${GCRYPT_INCLUDE_DIRS}
|
||||
${ZLIB_INCLUDE_DIRS}
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
${GCRYPT_INCLUDE_DIR}
|
||||
${ZLIB_INCLUDE_DIR}
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
@@ -22,12 +22,12 @@ set(TORTURE_LINK_LIBRARIES
|
||||
${LIBSSH_STATIC_LIBRARY}
|
||||
${LIBSSH_LINK_LIBRARIES})
|
||||
|
||||
if (Threads_FOUND)
|
||||
if (LIBSSH_THREADS)
|
||||
set(TORTURE_LINK_LIBRARIES
|
||||
${TORTURE_LINK_LIBRARIES}
|
||||
${LIBSSH_THREADS_STATIC_LIBRARY}
|
||||
${LIBSSH_THREADS_LINK_LIBRARIES})
|
||||
endif ()
|
||||
endif (LIBSSH_THREADS)
|
||||
|
||||
# create test library
|
||||
add_library(${TORTURE_LIBRARY} STATIC cmdline.c torture.c)
|
||||
@@ -44,6 +44,68 @@ set(TEST_TARGET_LIBRARIES
|
||||
add_subdirectory(unittests)
|
||||
|
||||
if (WITH_CLIENT_TESTING)
|
||||
find_package(socket_wrapper 1.1.5 REQUIRED)
|
||||
find_package(nss_wrapper 1.1.2 REQUIRED)
|
||||
find_package(uid_wrapper 1.2.0 REQUIRED)
|
||||
find_package(pam_wrapper 1.0.0 REQUIRED)
|
||||
|
||||
find_program(SSHD_EXECUTABLE
|
||||
NAME
|
||||
sshd
|
||||
PATHS
|
||||
/sbin
|
||||
/usr/sbin
|
||||
/usr/local/sbin)
|
||||
if (NOT SSHD_EXECUTABLE)
|
||||
message(SEND_ERROR "Could not find sshd which is required for client testing")
|
||||
endif()
|
||||
|
||||
find_program(SSH_EXECUTABLE NAMES ssh)
|
||||
if (SSH_EXECUTABLE)
|
||||
execute_process(COMMAND ${SSH_EXECUTABLE} -V ERROR_VARIABLE OPENSSH_VERSION_STR)
|
||||
string(REGEX REPLACE "^OpenSSH_([0-9]).[0-9].*$" "\\1" OPENSSH_VERSION_MAJOR "${OPENSSH_VERSION_STR}")
|
||||
string(REGEX REPLACE "^OpenSSH_[0-9].([0-9]).*$" "\\1" OPENSSH_VERSION_MINOR "${OPENSSH_VERSION_STR}")
|
||||
add_definitions(-DOPENSSH_VERSION_MAJOR=${OPENSSH_VERSION_MAJOR} -DOPENSSH_VERSION_MINOR=${OPENSSH_VERSION_MINOR})
|
||||
endif()
|
||||
|
||||
# chroot_wrapper
|
||||
add_library(chroot_wrapper SHARED chroot_wrapper.c)
|
||||
set(CHROOT_WRAPPER_LIBRARY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}chroot_wrapper${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||
set(TEST_TARGET_LIBRARIES
|
||||
${TEST_TARGET_LIBRARIES}
|
||||
chroot_wrapper
|
||||
)
|
||||
|
||||
# homedir will be used in passwd
|
||||
set(HOMEDIR ${CMAKE_CURRENT_BINARY_DIR}/home)
|
||||
|
||||
### Setup nss_wrapper
|
||||
configure_file(etc/passwd.in ${CMAKE_CURRENT_BINARY_DIR}/etc/passwd @ONLY)
|
||||
configure_file(etc/shadow.in ${CMAKE_CURRENT_BINARY_DIR}/etc/shadow @ONLY)
|
||||
configure_file(etc/group.in ${CMAKE_CURRENT_BINARY_DIR}/etc/group @ONLY)
|
||||
configure_file(etc/hosts.in ${CMAKE_CURRENT_BINARY_DIR}/etc/hosts @ONLY)
|
||||
|
||||
### Setup pam_wrapper
|
||||
configure_file(etc/pam_matrix_passdb.in ${CMAKE_CURRENT_BINARY_DIR}/etc/pam_matrix_passdb @ONLY)
|
||||
configure_file(etc/pam.d/sshd.in ${CMAKE_CURRENT_BINARY_DIR}/etc/pam.d/sshd @ONLY)
|
||||
|
||||
|
||||
set(TORTURE_ENVIRONMENT "LD_PRELOAD=${SOCKET_WRAPPER_LIBRARY}:${NSS_WRAPPER_LIBRARY}:${UID_WRAPPER_LIBRARY}:${PAM_WRAPPER_LIBRARY}:${CHROOT_WRAPPER_LIBRARY}")
|
||||
list(APPEND TORTURE_ENVIRONMENT UID_WRAPPER=1 UID_WRAPPER_ROOT=1)
|
||||
list(APPEND TORTURE_ENVIRONMENT NSS_WRAPPER_PASSWD=${CMAKE_CURRENT_BINARY_DIR}/etc/passwd)
|
||||
list(APPEND TORTURE_ENVIRONMENT NSS_WRAPPER_SHADOW=${CMAKE_CURRENT_BINARY_DIR}/etc/shadow)
|
||||
list(APPEND TORTURE_ENVIRONMENT NSS_WRAPPER_GROUP=${CMAKE_CURRENT_BINARY_DIR}/etc/group)
|
||||
list(APPEND TORTURE_ENVIRONMENT PAM_WRAPPER_SERVICE_DIR=${CMAKE_CURRENT_BINARY_DIR}/etc/pam.d)
|
||||
|
||||
# Give bob some keys
|
||||
file(COPY keys/id_rsa DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
|
||||
file(COPY keys/id_rsa.pub DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
|
||||
|
||||
# Allow to auth with bob his public keys on alice account
|
||||
configure_file(keys/id_rsa.pub ${CMAKE_CURRENT_BINARY_DIR}/home/alice/.ssh/authorized_keys @ONLY)
|
||||
|
||||
message(STATUS "TORTURE_ENVIRONMENT=${TORTURE_ENVIRONMENT}")
|
||||
|
||||
add_subdirectory(client)
|
||||
endif (WITH_CLIENT_TESTING)
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ int benchmarks_sync_sftp_up (ssh_session session, struct argument_s *args,
|
||||
float ms=0.0;
|
||||
unsigned long total=0;
|
||||
sftp_session sftp;
|
||||
sftp_file file;
|
||||
sftp_file file = NULL;
|
||||
|
||||
bytes = args->datasize * 1024 * 1024;
|
||||
sftp = sftp_new(session);
|
||||
@@ -101,7 +101,7 @@ int benchmarks_sync_sftp_down (ssh_session session, struct argument_s *args,
|
||||
float ms=0.0;
|
||||
unsigned long total=0;
|
||||
sftp_session sftp;
|
||||
sftp_file file;
|
||||
sftp_file file = NULL;
|
||||
int r;
|
||||
|
||||
bytes = args->datasize * 1024 * 1024;
|
||||
@@ -163,7 +163,7 @@ int benchmarks_async_sftp_down (ssh_session session, struct argument_s *args,
|
||||
float ms=0.0;
|
||||
unsigned long total=0;
|
||||
sftp_session sftp;
|
||||
sftp_file file;
|
||||
sftp_file file = NULL;
|
||||
int r,i;
|
||||
int warned = 0;
|
||||
unsigned long toread;
|
||||
|
||||
8
tests/chroot_wrapper.c
Normal file
8
tests/chroot_wrapper.c
Normal file
@@ -0,0 +1,8 @@
|
||||
/* silent gcc */
|
||||
int chroot(const char *);
|
||||
|
||||
int chroot(const char *path)
|
||||
{
|
||||
(void)path;
|
||||
return 0;
|
||||
}
|
||||
@@ -1,15 +1,41 @@
|
||||
project(clienttests C)
|
||||
|
||||
add_cmocka_test(torture_algorithms torture_algorithms.c ${TORTURE_LIBRARY})
|
||||
add_cmocka_test(torture_auth torture_auth.c ${TORTURE_LIBRARY})
|
||||
add_cmocka_test(torture_connect torture_connect.c ${TORTURE_LIBRARY})
|
||||
add_cmocka_test(torture_knownhosts torture_knownhosts.c ${TORTURE_LIBRARY})
|
||||
add_cmocka_test(torture_proxycommand torture_proxycommand.c ${TORTURE_LIBRARY})
|
||||
add_cmocka_test(torture_session torture_session.c ${TORTURE_LIBRARY})
|
||||
add_cmocka_test(torture_forward torture_forward.c ${TORTURE_LIBRARY})
|
||||
add_cmocka_test(torture_request_env torture_request_env.c ${TORTURE_LIBRARY})
|
||||
if (WITH_SFTP)
|
||||
add_cmocka_test(torture_sftp_static torture_sftp_static.c ${TORTURE_LIBRARY})
|
||||
add_cmocka_test(torture_sftp_dir torture_sftp_dir.c ${TORTURE_LIBRARY})
|
||||
add_cmocka_test(torture_sftp_read torture_sftp_read.c ${TORTURE_LIBRARY})
|
||||
endif (WITH_SFTP)
|
||||
|
||||
set(LIBSSH_CLIENT_TESTS
|
||||
torture_algorithms
|
||||
torture_knownhosts
|
||||
torture_request_env
|
||||
torture_forward
|
||||
torture_proxycommand)
|
||||
|
||||
if (WITH_SFTP)
|
||||
set(LIBSSH_CLIENT_TESTS
|
||||
${LIBSSH_CLIENT_TESTS}
|
||||
torture_sftp_dir
|
||||
torture_sftp_read)
|
||||
endif (WITH_SFTP)
|
||||
|
||||
foreach(_CLI_TEST ${LIBSSH_CLIENT_TESTS})
|
||||
add_cmocka_test(${_CLI_TEST} ${_CLI_TEST}.c ${TORTURE_LIBRARY})
|
||||
|
||||
if (OSX)
|
||||
set_property(
|
||||
TEST
|
||||
${_CLI_TEST}
|
||||
PROPERTY
|
||||
ENVIRONMENT DYLD_FORCE_FLAT_NAMESPACE=1;DYLD_INSERT_LIBRARIES=${SOCKET_WRAPPER_LIBRARY})
|
||||
else ()
|
||||
set_property(
|
||||
TEST
|
||||
${_CLI_TEST}
|
||||
PROPERTY
|
||||
ENVIRONMENT ${TORTURE_ENVIRONMENT})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
|
||||
@@ -25,11 +25,37 @@
|
||||
#include "libssh/libssh.h"
|
||||
#include "libssh/priv.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
|
||||
static int sshd_setup(void **state)
|
||||
{
|
||||
torture_setup_sshd_server(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sshd_teardown(void **state) {
|
||||
torture_teardown_sshd_server(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setup(void **state) {
|
||||
int verbosity=torture_libssh_verbosity();
|
||||
ssh_session session = ssh_new();
|
||||
struct passwd *pwd;
|
||||
int rc;
|
||||
|
||||
pwd = getpwnam("bob");
|
||||
assert_non_null(pwd);
|
||||
|
||||
rc = setuid(pwd->pw_uid);
|
||||
assert_return_code(rc, errno);
|
||||
|
||||
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
|
||||
*state = session;
|
||||
}
|
||||
|
||||
@@ -40,9 +66,6 @@ static void teardown(void **state) {
|
||||
static void test_algorithm(ssh_session session, const char *algo, const char *hmac) {
|
||||
int rc;
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_CIPHERS_C_S, algo);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
@@ -151,6 +174,7 @@ static void torture_algorithms_3des_cbc_hmac_sha2_512(void **state) {
|
||||
test_algorithm(*state, "3des-cbc", "hmac-sha2-512");
|
||||
}
|
||||
|
||||
#if ((OPENSSH_VERSION_MAJOR == 7 && OPENSSH_VERSION_MINOR < 6) || OPENSSH_VERSION_MAJOR <= 6)
|
||||
static void torture_algorithms_blowfish_cbc_hmac_sha1(void **state) {
|
||||
test_algorithm(*state, "blowfish-cbc", "hmac-sha1");
|
||||
}
|
||||
@@ -162,14 +186,12 @@ static void torture_algorithms_blowfish_cbc_hmac_sha2_256(void **state) {
|
||||
static void torture_algorithms_blowfish_cbc_hmac_sha2_512(void **state) {
|
||||
test_algorithm(*state, "blowfish-cbc", "hmac-sha2-512");
|
||||
}
|
||||
#endif
|
||||
|
||||
static void torture_algorithms_zlib(void **state) {
|
||||
ssh_session session = *state;
|
||||
int rc;
|
||||
|
||||
rc = ssh_options_set(session,SSH_OPTIONS_HOST,"localhost");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_COMPRESSION_C_S, "zlib");
|
||||
#ifdef WITH_ZLIB
|
||||
assert_true(rc == SSH_OK);
|
||||
@@ -207,9 +229,6 @@ static void torture_algorithms_zlib_openssh(void **state) {
|
||||
ssh_session session = *state;
|
||||
int rc;
|
||||
|
||||
rc = ssh_options_set(session,SSH_OPTIONS_HOST,"localhost");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_COMPRESSION_C_S, "zlib@openssh.com");
|
||||
#ifdef WITH_ZLIB
|
||||
assert_true(rc == SSH_OK);
|
||||
@@ -249,9 +268,6 @@ static void torture_algorithms_ecdh_sha2_nistp256(void **state) {
|
||||
ssh_session session = *state;
|
||||
int rc;
|
||||
|
||||
rc = ssh_options_set(session,SSH_OPTIONS_HOST,"localhost");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KEY_EXCHANGE, "ecdh-sha2-nistp256");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
@@ -271,9 +287,6 @@ static void torture_algorithms_dh_group1(void **state) {
|
||||
ssh_session session = *state;
|
||||
int rc;
|
||||
|
||||
rc = ssh_options_set(session,SSH_OPTIONS_HOST,"localhost");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KEY_EXCHANGE, "diffie-hellman-group1-sha1");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
@@ -289,6 +302,7 @@ static void torture_algorithms_dh_group1(void **state) {
|
||||
}
|
||||
int torture_run_tests(void) {
|
||||
int rc;
|
||||
struct torture_state *s = NULL;
|
||||
UnitTest tests[] = {
|
||||
unit_test_setup_teardown(torture_algorithms_aes128_cbc_hmac_sha1, setup, teardown),
|
||||
unit_test_setup_teardown(torture_algorithms_aes128_cbc_hmac_sha2_256, setup, teardown),
|
||||
@@ -311,9 +325,11 @@ int torture_run_tests(void) {
|
||||
unit_test_setup_teardown(torture_algorithms_3des_cbc_hmac_sha1, setup, teardown),
|
||||
unit_test_setup_teardown(torture_algorithms_3des_cbc_hmac_sha2_256, setup, teardown),
|
||||
unit_test_setup_teardown(torture_algorithms_3des_cbc_hmac_sha2_512, setup, teardown),
|
||||
#if ((OPENSSH_VERSION_MAJOR == 7 && OPENSSH_VERSION_MINOR < 6) || OPENSSH_VERSION_MAJOR <= 6)
|
||||
unit_test_setup_teardown(torture_algorithms_blowfish_cbc_hmac_sha1, setup, teardown),
|
||||
unit_test_setup_teardown(torture_algorithms_blowfish_cbc_hmac_sha2_256, setup, teardown),
|
||||
unit_test_setup_teardown(torture_algorithms_blowfish_cbc_hmac_sha2_512, setup, teardown),
|
||||
#endif
|
||||
unit_test_setup_teardown(torture_algorithms_zlib, setup, teardown),
|
||||
unit_test_setup_teardown(torture_algorithms_zlib_openssh, setup, teardown),
|
||||
unit_test_setup_teardown(torture_algorithms_dh_group1,setup,teardown),
|
||||
@@ -324,7 +340,9 @@ int torture_run_tests(void) {
|
||||
|
||||
ssh_init();
|
||||
torture_filter_tests(tests);
|
||||
sshd_setup((void **)&s);
|
||||
rc = run_tests(tests);
|
||||
sshd_teardown((void **)&s);
|
||||
ssh_finalize();
|
||||
|
||||
return rc;
|
||||
|
||||
@@ -24,24 +24,42 @@
|
||||
#include "torture.h"
|
||||
#include <libssh/libssh.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
|
||||
static int sshd_setup(void **state)
|
||||
{
|
||||
torture_setup_sshd_server(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sshd_teardown(void **state) {
|
||||
torture_teardown_sshd_server(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setup(void **state)
|
||||
{
|
||||
ssh_session session;
|
||||
const char *host;
|
||||
const char *user;
|
||||
const char *password;
|
||||
struct passwd *pwd;
|
||||
int rc;
|
||||
|
||||
host = getenv("TORTURE_HOST");
|
||||
if (host == NULL) {
|
||||
host = "localhost";
|
||||
}
|
||||
pwd = getpwnam("bob");
|
||||
assert_non_null(pwd);
|
||||
|
||||
user = getenv("TORTURE_USER");
|
||||
password = getenv("TORTURE_PASSWORD");
|
||||
rc = setuid(pwd->pw_uid);
|
||||
assert_return_code(rc, errno);
|
||||
|
||||
session = torture_ssh_session(host, NULL, user, password);
|
||||
session = torture_ssh_session(TORTURE_SSH_SERVER,
|
||||
NULL,
|
||||
TORTURE_SSH_USER_ALICE,
|
||||
NULL);
|
||||
|
||||
assert_non_null(session);
|
||||
|
||||
*state = session;
|
||||
}
|
||||
|
||||
@@ -60,26 +78,25 @@ static void teardown(void **state)
|
||||
static void torture_ssh_forward(void **state)
|
||||
{
|
||||
ssh_session session = (ssh_session) *state;
|
||||
#if 0
|
||||
ssh_channel c;
|
||||
#endif
|
||||
int dport;
|
||||
int bound_port;
|
||||
int rc;
|
||||
|
||||
rc = ssh_channel_listen_forward(session, "127.0.0.1", 8080, &bound_port);
|
||||
rc = ssh_channel_listen_forward(session, "127.0.0.21", 8080, &bound_port);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
|
||||
#if 0
|
||||
c = ssh_forward_accept(session, 60000);
|
||||
assert_non_null(c);
|
||||
c = ssh_channel_accept_forward(session, 10, &dport);
|
||||
/* We do not get a listener and run into the timeout here */
|
||||
assert_null(c);
|
||||
|
||||
ssh_channel_send_eof(c);
|
||||
ssh_channel_close(c);
|
||||
#endif
|
||||
}
|
||||
|
||||
int torture_run_tests(void) {
|
||||
int rc;
|
||||
struct torture_state *s = NULL;
|
||||
|
||||
UnitTest tests[] = {
|
||||
unit_test_setup_teardown(torture_ssh_forward, setup, teardown),
|
||||
@@ -88,7 +105,9 @@ int torture_run_tests(void) {
|
||||
ssh_init();
|
||||
|
||||
torture_filter_tests(tests);
|
||||
sshd_setup((void **)&s);
|
||||
rc = run_tests(tests);
|
||||
sshd_teardown((void **)&s);
|
||||
|
||||
ssh_finalize();
|
||||
return rc;
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
#include "session.c"
|
||||
#include "known_hosts.c"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#define KNOWNHOSTFILES "libssh_torture_knownhosts"
|
||||
#define BADRSA "AAAAB3NzaC1yc2EAAAADAQABAAABAQChm5" \
|
||||
"a6Av65O8cKtx5YXOnui3wJnYE6A6J/I4kZSAibbn14Jcl+34VJQwv96f25AxNmo" \
|
||||
@@ -44,11 +47,31 @@
|
||||
"h0dSi8VJXI1wes5HTyLsv9VBmU1uCXUUvufoQKfF/OcSH0ufcCpnd62g1/adZcy2" \
|
||||
"WJg=="
|
||||
|
||||
static int sshd_setup(void **state)
|
||||
{
|
||||
torture_setup_sshd_server(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sshd_teardown(void **state) {
|
||||
torture_teardown_sshd_server(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setup(void **state) {
|
||||
int verbosity=torture_libssh_verbosity();
|
||||
ssh_session session = ssh_new();
|
||||
struct passwd *pwd;
|
||||
|
||||
|
||||
pwd = getpwnam("bob");
|
||||
assert_non_null(pwd);
|
||||
setuid(pwd->pw_uid);
|
||||
|
||||
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
|
||||
|
||||
*state = session;
|
||||
}
|
||||
@@ -73,8 +96,6 @@ static void torture_knownhosts_port(void **state) {
|
||||
* the known hosts file. Then check that the entry written is
|
||||
* [localhost]:1234
|
||||
*/
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
|
||||
assert_true(rc == SSH_OK);
|
||||
@@ -92,7 +113,7 @@ static void torture_knownhosts_port(void **state) {
|
||||
assert_false(p == NULL);
|
||||
fclose(file);
|
||||
buffer[sizeof(buffer) - 1] = '\0';
|
||||
assert_true(strstr(buffer,"[localhost]:1234 ") != NULL);
|
||||
assert_true(strstr(buffer,"[127.0.0.10]:1234 ") != NULL);
|
||||
|
||||
ssh_disconnect(session);
|
||||
ssh_free(session);
|
||||
@@ -100,7 +121,7 @@ static void torture_knownhosts_port(void **state) {
|
||||
/* Now, connect back to the ssh server and verify the known host line */
|
||||
*state = session = ssh_new();
|
||||
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
|
||||
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
@@ -116,9 +137,6 @@ static void torture_knownhosts_fail(void **state) {
|
||||
FILE *file;
|
||||
int rc;
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
@@ -127,7 +145,7 @@ static void torture_knownhosts_fail(void **state) {
|
||||
|
||||
file = fopen(KNOWNHOSTFILES, "w");
|
||||
assert_true(file != NULL);
|
||||
fprintf(file, "localhost ssh-rsa %s\n", BADRSA);
|
||||
fprintf(file, TORTURE_SSH_SERVER " ssh-rsa %s\n", BADRSA);
|
||||
fclose(file);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
@@ -142,9 +160,6 @@ static void torture_knownhosts_other(void **state) {
|
||||
FILE *file;
|
||||
int rc;
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
@@ -153,7 +168,7 @@ static void torture_knownhosts_other(void **state) {
|
||||
|
||||
file = fopen(KNOWNHOSTFILES, "w");
|
||||
assert_true(file != NULL);
|
||||
fprintf(file, "localhost ssh-rsa %s\n", BADRSA);
|
||||
fprintf(file, TORTURE_SSH_SERVER " ssh-rsa %s\n", BADRSA);
|
||||
fclose(file);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
@@ -167,9 +182,6 @@ static void torture_knownhosts_other_auto(void **state) {
|
||||
ssh_session session = *state;
|
||||
int rc;
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
@@ -191,7 +203,7 @@ static void torture_knownhosts_other_auto(void **state) {
|
||||
/* connect again and check host key */
|
||||
*state = session = ssh_new();
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
|
||||
@@ -210,9 +222,6 @@ static void torture_knownhosts_conflict(void **state) {
|
||||
FILE *file;
|
||||
int rc;
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
@@ -221,8 +230,8 @@ static void torture_knownhosts_conflict(void **state) {
|
||||
|
||||
file = fopen(KNOWNHOSTFILES, "w");
|
||||
assert_true(file != NULL);
|
||||
fprintf(file, "localhost ssh-rsa %s\n", BADRSA);
|
||||
fprintf(file, "localhost ssh-dss %s\n", BADDSA);
|
||||
fprintf(file, TORTURE_SSH_SERVER " ssh-rsa %s\n", BADRSA);
|
||||
fprintf(file, TORTURE_SSH_SERVER " ssh-dss %s\n", BADDSA);
|
||||
fclose(file);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
@@ -240,7 +249,7 @@ static void torture_knownhosts_conflict(void **state) {
|
||||
/* connect again and check host key */
|
||||
*state = session = ssh_new();
|
||||
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
|
||||
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, "ssh-rsa");
|
||||
assert_true(rc == SSH_OK);
|
||||
@@ -258,16 +267,13 @@ static void torture_knownhosts_precheck(void **state) {
|
||||
int rc;
|
||||
char **kex;
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
file = fopen(KNOWNHOSTFILES, "w");
|
||||
assert_true(file != NULL);
|
||||
fprintf(file, "localhost ssh-rsa %s\n", BADRSA);
|
||||
fprintf(file, "localhost ssh-dss %s\n", BADDSA);
|
||||
fprintf(file, TORTURE_SSH_SERVER " ssh-rsa %s\n", BADRSA);
|
||||
fprintf(file, TORTURE_SSH_SERVER " ssh-dss %s\n", BADDSA);
|
||||
fclose(file);
|
||||
|
||||
kex = ssh_knownhosts_algorithms(session);
|
||||
@@ -282,6 +288,7 @@ static void torture_knownhosts_precheck(void **state) {
|
||||
|
||||
int torture_run_tests(void) {
|
||||
int rc;
|
||||
struct torture_state *s = NULL;
|
||||
UnitTest tests[] = {
|
||||
unit_test_setup_teardown(torture_knownhosts_port, setup, teardown),
|
||||
unit_test_setup_teardown(torture_knownhosts_fail, setup, teardown),
|
||||
@@ -294,7 +301,9 @@ int torture_run_tests(void) {
|
||||
ssh_init();
|
||||
|
||||
torture_filter_tests(tests);
|
||||
sshd_setup((void **)&s);
|
||||
rc = run_tests(tests);
|
||||
sshd_teardown((void **)&s);
|
||||
|
||||
ssh_finalize();
|
||||
return rc;
|
||||
|
||||
@@ -4,8 +4,39 @@
|
||||
#include <libssh/libssh.h>
|
||||
#include "libssh/priv.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
|
||||
static int sshd_setup(void **state)
|
||||
{
|
||||
torture_setup_sshd_server(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sshd_teardown(void **state) {
|
||||
torture_teardown_sshd_server(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setup(void **state) {
|
||||
ssh_session session = ssh_new();
|
||||
int verbosity = torture_libssh_verbosity();
|
||||
struct passwd *pwd;
|
||||
int rc;
|
||||
|
||||
pwd = getpwnam("bob");
|
||||
assert_non_null(pwd);
|
||||
|
||||
rc = setuid(pwd->pw_uid);
|
||||
assert_return_code(rc, errno);
|
||||
|
||||
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
|
||||
|
||||
ssh_options_set(session, SSH_OPTIONS_USER, TORTURE_SSH_USER_ALICE);
|
||||
|
||||
*state = session;
|
||||
}
|
||||
@@ -18,10 +49,7 @@ static void torture_options_set_proxycommand(void **state) {
|
||||
ssh_session session = *state;
|
||||
int rc;
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
assert_true(rc == 0);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, "nc localhost 22");
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, "nc 127.0.0.10 22");
|
||||
assert_true(rc == 0);
|
||||
rc = ssh_connect(session);
|
||||
assert_true(rc == SSH_OK);
|
||||
@@ -31,9 +59,6 @@ static void torture_options_set_proxycommand_notexist(void **state) {
|
||||
ssh_session session = *state;
|
||||
int rc;
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
assert_true(rc == 0);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, "this_command_does_not_exist");
|
||||
assert_true(rc == SSH_OK);
|
||||
rc = ssh_connect(session);
|
||||
@@ -42,6 +67,7 @@ static void torture_options_set_proxycommand_notexist(void **state) {
|
||||
|
||||
int torture_run_tests(void) {
|
||||
int rc;
|
||||
struct torture_state *s = NULL;
|
||||
UnitTest tests[] = {
|
||||
unit_test_setup_teardown(torture_options_set_proxycommand, setup, teardown),
|
||||
unit_test_setup_teardown(torture_options_set_proxycommand_notexist, setup, teardown),
|
||||
@@ -51,7 +77,9 @@ int torture_run_tests(void) {
|
||||
ssh_init();
|
||||
|
||||
torture_filter_tests(tests);
|
||||
sshd_setup((void **)&s);
|
||||
rc = run_tests(tests);
|
||||
sshd_teardown((void **)&s);
|
||||
ssh_finalize();
|
||||
|
||||
return rc;
|
||||
|
||||
@@ -24,22 +24,36 @@
|
||||
#include "torture.h"
|
||||
#include <libssh/libssh.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
|
||||
static int sshd_setup(void **state)
|
||||
{
|
||||
torture_setup_sshd_server(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sshd_teardown(void **state) {
|
||||
torture_teardown_sshd_server(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setup(void **state)
|
||||
{
|
||||
ssh_session session;
|
||||
const char *host;
|
||||
const char *user;
|
||||
const char *password;
|
||||
struct passwd *pwd;
|
||||
|
||||
host = getenv("TORTURE_HOST");
|
||||
if (host == NULL) {
|
||||
host = "localhost";
|
||||
}
|
||||
pwd = getpwnam("bob");
|
||||
assert_non_null(pwd);
|
||||
setuid(pwd->pw_uid);
|
||||
|
||||
user = getenv("TORTURE_USER");
|
||||
password = getenv("TORTURE_PASSWORD");
|
||||
|
||||
session = torture_ssh_session(host, NULL, user, password);
|
||||
session = torture_ssh_session(TORTURE_SSH_SERVER,
|
||||
NULL,
|
||||
TORTURE_SSH_USER_ALICE,
|
||||
NULL);
|
||||
|
||||
assert_false(session == NULL);
|
||||
*state = session;
|
||||
@@ -99,6 +113,7 @@ static void torture_request_env(void **state)
|
||||
|
||||
int torture_run_tests(void) {
|
||||
int rc;
|
||||
struct torture_state *s = NULL;
|
||||
|
||||
UnitTest tests[] = {
|
||||
unit_test_setup_teardown(torture_request_env, setup, teardown),
|
||||
@@ -107,7 +122,9 @@ int torture_run_tests(void) {
|
||||
ssh_init();
|
||||
|
||||
torture_filter_tests(tests);
|
||||
sshd_setup((void **)&s);
|
||||
rc = run_tests(tests);
|
||||
sshd_teardown((void **)&s);
|
||||
|
||||
ssh_finalize();
|
||||
return rc;
|
||||
|
||||
@@ -92,7 +92,12 @@ static void torture_channel_read_error(void **state) {
|
||||
if (rc == SSH_ERROR)
|
||||
break;
|
||||
}
|
||||
assert_true(rc == SSH_ERROR);
|
||||
#if OPENSSH_VERSION_MAJOR == 6 && OPENSSH_VERSION_MINOR >= 7
|
||||
/* With openssh 6.7 this doesn't produce and error anymore */
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
#else
|
||||
assert_int_equal(rc, SSH_ERROR);
|
||||
#endif
|
||||
|
||||
ssh_channel_free(channel);
|
||||
}
|
||||
|
||||
@@ -3,22 +3,36 @@
|
||||
#include "torture.h"
|
||||
#include "sftp.c"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
|
||||
static int sshd_setup(void **state)
|
||||
{
|
||||
torture_setup_sshd_server(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sshd_teardown(void **state) {
|
||||
torture_teardown_sshd_server(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setup(void **state) {
|
||||
ssh_session session;
|
||||
struct torture_sftp *t;
|
||||
const char *host;
|
||||
const char *user;
|
||||
const char *password;
|
||||
struct passwd *pwd;
|
||||
|
||||
host = getenv("TORTURE_HOST");
|
||||
if (host == NULL) {
|
||||
host = "localhost";
|
||||
}
|
||||
pwd = getpwnam("bob");
|
||||
assert_non_null(pwd);
|
||||
setuid(pwd->pw_uid);
|
||||
|
||||
user = getenv("TORTURE_USER");
|
||||
password = getenv("TORTURE_PASSWORD");
|
||||
|
||||
session = torture_ssh_session(host, NULL, user, password);
|
||||
session = torture_ssh_session(TORTURE_SSH_SERVER,
|
||||
NULL,
|
||||
TORTURE_SSH_USER_ALICE,
|
||||
NULL);
|
||||
assert_false(session == NULL);
|
||||
t = torture_sftp_session(session);
|
||||
assert_false(t == NULL);
|
||||
@@ -61,6 +75,7 @@ static void torture_sftp_mkdir(void **state) {
|
||||
|
||||
int torture_run_tests(void) {
|
||||
int rc;
|
||||
struct torture_state *s = NULL;
|
||||
UnitTest tests[] = {
|
||||
unit_test_setup_teardown(torture_sftp_mkdir, setup, teardown)
|
||||
};
|
||||
@@ -68,7 +83,9 @@ int torture_run_tests(void) {
|
||||
ssh_init();
|
||||
|
||||
torture_filter_tests(tests);
|
||||
sshd_setup((void **)&s);
|
||||
rc = run_tests(tests);
|
||||
sshd_teardown((void **)&s);
|
||||
ssh_finalize();
|
||||
|
||||
return rc;
|
||||
|
||||
@@ -3,24 +3,40 @@
|
||||
#include "torture.h"
|
||||
#include "sftp.c"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#define MAX_XFER_BUF_SIZE 16384
|
||||
|
||||
static int sshd_setup(void **state)
|
||||
{
|
||||
torture_setup_sshd_server(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sshd_teardown(void **state) {
|
||||
torture_teardown_sshd_server(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setup(void **state) {
|
||||
ssh_session session;
|
||||
struct torture_sftp *t;
|
||||
const char *host;
|
||||
const char *user;
|
||||
const char *password;
|
||||
struct passwd *pwd;
|
||||
int rc;
|
||||
|
||||
host = getenv("TORTURE_HOST");
|
||||
if (host == NULL) {
|
||||
host = "localhost";
|
||||
}
|
||||
pwd = getpwnam("bob");
|
||||
assert_non_null(pwd);
|
||||
|
||||
user = getenv("TORTURE_USER");
|
||||
password = getenv("TORTURE_PASSWORD");
|
||||
rc = setuid(pwd->pw_uid);
|
||||
assert_return_code(rc, errno);
|
||||
|
||||
session = torture_ssh_session(host, NULL, user, password);
|
||||
session = torture_ssh_session(TORTURE_SSH_SERVER,
|
||||
NULL,
|
||||
TORTURE_SSH_USER_ALICE,
|
||||
NULL);
|
||||
assert_false(session == NULL);
|
||||
t = torture_sftp_session(session);
|
||||
assert_false(t == NULL);
|
||||
@@ -72,6 +88,7 @@ static void torture_sftp_read_blocking(void **state) {
|
||||
|
||||
int torture_run_tests(void) {
|
||||
int rc;
|
||||
struct torture_state *s = NULL;
|
||||
UnitTest tests[] = {
|
||||
unit_test_setup_teardown(torture_sftp_read_blocking, setup, teardown)
|
||||
};
|
||||
@@ -79,7 +96,9 @@ int torture_run_tests(void) {
|
||||
ssh_init();
|
||||
|
||||
torture_filter_tests(tests);
|
||||
sshd_setup((void **)&s);
|
||||
rc = run_tests(tests);
|
||||
sshd_teardown((void **)&s);
|
||||
ssh_finalize();
|
||||
|
||||
return rc;
|
||||
|
||||
@@ -39,6 +39,7 @@ set(CTEST_SOURCE_DIRECTORY "${CTEST_DIRECTORY}/${CTEST_BUILD_NAME}/source")
|
||||
set(CTEST_BINARY_DIRECTORY "${CTEST_DIRECTORY}/${CTEST_BUILD_NAME}/build")
|
||||
|
||||
set(CTEST_MEMORYCHECK_SUPPRESSIONS_FILE ${CMAKE_SOURCE_DIR}/tests/valgrind.supp)
|
||||
set(CTEST_MEMORYCHECK_COMMAND_OPTIONS " --trace-children-skip=sshd")
|
||||
|
||||
find_program(CTEST_GIT_COMMAND NAMES git)
|
||||
find_program(CTEST_COVERAGE_COMMAND NAMES gcov)
|
||||
|
||||
5
tests/etc/group.in
Normal file
5
tests/etc/group.in
Normal file
@@ -0,0 +1,5 @@
|
||||
users:x:1000:
|
||||
sshd:x:65531:
|
||||
nobody:x:65533:
|
||||
nogroup:x:65534:nobody
|
||||
root:x:65532:
|
||||
2
tests/etc/hosts.in
Normal file
2
tests/etc/hosts.in
Normal file
@@ -0,0 +1,2 @@
|
||||
127.0.0.10 server.libssh.site
|
||||
127.0.0.21 client.libssh.site
|
||||
4
tests/etc/pam.d/sshd.in
Normal file
4
tests/etc/pam.d/sshd.in
Normal file
@@ -0,0 +1,4 @@
|
||||
auth required @PAM_WRAPPER_MODULE_DIR@/pam_matrix.so passdb=@CMAKE_CURRENT_BINARY_DIR@/etc/pam_matrix_passdb
|
||||
account required @PAM_WRAPPER_MODULE_DIR@/pam_matrix.so passdb=@CMAKE_CURRENT_BINARY_DIR@/etc/pam_matrix_passdb
|
||||
password required @PAM_WRAPPER_MODULE_DIR@/pam_matrix.so passdb=@CMAKE_CURRENT_BINARY_DIR@/etc/pam_matrix_passdb
|
||||
session required @PAM_WRAPPER_MODULE_DIR@/pam_matrix.so passdb=@CMAKE_CURRENT_BINARY_DIR@/etc/pam_matrix_passdb
|
||||
2
tests/etc/pam_matrix_passdb.in
Normal file
2
tests/etc/pam_matrix_passdb.in
Normal file
@@ -0,0 +1,2 @@
|
||||
bob:secret:sshd
|
||||
alice:secret:sshd
|
||||
5
tests/etc/passwd.in
Normal file
5
tests/etc/passwd.in
Normal file
@@ -0,0 +1,5 @@
|
||||
bob:x:1000:1000:bob gecos:@HOMEDIR@/bob:/bin/false
|
||||
alice:x:1001:1000:alice gecos:@HOMEDIR@/alice:/bin/bash
|
||||
sshd:x:65530:65531:sshd:@HOMEDIR@:/sbin/nologin
|
||||
nobody:x:65533:65534:nobody gecos:@HOMEDIR@:/bin/false
|
||||
root:x:65534:65532:root gecos:@HOMEDIR@:/bin/false
|
||||
2
tests/etc/shadow.in
Normal file
2
tests/etc/shadow.in
Normal file
@@ -0,0 +1,2 @@
|
||||
alice:$6$0jWkA8VP$MvBUvtGy38jWCZ5KtqnZEKQWXvvImDkDhDQII1kTqtAp3/xH31b71c.AjGkBFle.2QwCJQH7OzB/NXiMprusr/::0:::::
|
||||
bob:$6$0jWkA8VP$MvBUvtGy38jWCZ5KtqnZEKQWXvvImDkDhDQII1kTqtAp3/xH31b71c.AjGkBFle.2QwCJQH7OzB/NXiMprusr/::0:::::
|
||||
27
tests/keys/id_rsa
Normal file
27
tests/keys/id_rsa
Normal file
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEAs/fIz+Gy89XjUhXebNq2rs1K0RJEZXDbfcofb13ESDJ9fSbd
|
||||
+RlCUM6i+foEVV23xWdands2Bkn72tGinJadIgOWU+koxp+gRmtJLE/ONiAKJQqR
|
||||
K3eOJNBH6At96NMqJ4Gwv56G4W68uPgDwUVQwVIc6Ec6Rypiz7DE+S++gSvBQIVU
|
||||
Qt7XkPcXOyN5zuj5qDhZM4l6V7Og9LWj4/2IF5acvKjfIMpeqmnp9z6BTYZQtuQU
|
||||
6b1VuEYhXyvM6LkMwndsVGh46kDKMmRQhyA8A6qvLAliMMq88k5gR4AeJeTnqDR/
|
||||
Q120I6PMqYNl6TLTk8/KonOOPDR/XXGb3iF67wIDAQABAoIBAAVoL2dXf5nl1jOU
|
||||
Jp+cnpp33oSTiOyHTIDl/rXI2mnU4oJNFaQzRxPIcYsTIOgzrZ7HsShG+sOLm36C
|
||||
h+EugUARXYXd3nTBPP6AoK0tJKPpqIReYegtal7exxpIphrFpWGUeuv25lSFkDP6
|
||||
d5pp67gzMF0mLrEOq/NTe0eFULLuwa6+IKXU7deiU90pzi4jrjcIWNoGHSw1YYAZ
|
||||
TC8KAxA/tYH9myya5krRCjA9B345DJ9Wd71wX+RZNgbSkIri/6dDTtvsYvqcQKo0
|
||||
OZ3MUDJnKmkfPLP84qZPRoEwUI1gts1WUdoNK6LK7yOJmPL5FMyTwZx3XtDw3gAv
|
||||
TVhI7ikCgYEA5Ay0TCySPQAaC14WtjgIAmTa19mAtOFpbRxToi40WjXk3R6mMqyp
|
||||
biAcNecdZRC6zzgAUp8g1O3Yc1d9fG/3FpM5eUbIer7mMLTRuQQysoJY2Ayw9OEA
|
||||
qPHS/K6LPOD09aZo14fRUqVO8rwMbHtq2yhH8p3FM8WZRe5ms8zpyLUCgYEAygZ3
|
||||
RTMWbgcGdNoaPa5Ms9KRqAxKJLin2fE99KowZeJfvZN24sXExawQdy4BKVYT0H6e
|
||||
MNEIPiEBVA4a1GDk/tyOrEt684IsidROngJaGbqb+SYm6feQAioYu0wkG/I2hS12
|
||||
/Z/aK6wFz5hWzBv/YvJqC7xD1YwZm1QXDyAiL5MCgYAXz8fHqGPAoNEXXMSsVB9p
|
||||
+JPtM9W/jUXP0cRdy8tFnBkAiaG66tJqIEoxyqcEFYIb/vHxrpHkCc2vBXSh2KMJ
|
||||
JWg75IssXeB1N3wqgGi2wOt7659SgmfqPA3WunbpbWfGepC56IGPypj6uW3mqeBX
|
||||
b9ZLW/PqWviNF757iarjfQKBgGxKBPqRxM8bcumF0xUG7dRh5XN3ivKeDFL1Tels
|
||||
pF6odftPJSWvLqdqcLUBctvuaNaUWEUAdvOei3C70sPOYFEAdnWCTBhkyWzj4XQu
|
||||
/I7YCS0Gt0soSQfv+qvCx4Q3U+QVF7ghTDemkMLS/IuR4lXubMt3kcDQxRUOgQG5
|
||||
jrmDAoGALauF7ZyzEnQgsgMVzfm9znl5I2aIsLgdsAv3lINVrvtTKhddp7cdd+2j
|
||||
dwZlaMnLET/3MY/Cvf13vEsS+bdNXjsdQidqBL8pe5PXY/pafBhtduQuvGzlHJA5
|
||||
CEBnwB0SdtsXbzSpOAPZqea4Nz9MkQ8LMsINdPpxCuFhjeYa9Ow=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
1
tests/keys/id_rsa.pub
Normal file
1
tests/keys/id_rsa.pub
Normal file
@@ -0,0 +1 @@
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCz98jP4bLz1eNSFd5s2rauzUrREkRlcNt9yh9vXcRIMn19Jt35GUJQzqL5+gRVXbfFZ1qd2zYGSfva0aKclp0iA5ZT6SjGn6BGa0ksT842IAolCpErd44k0EfoC33o0yongbC/nobhbry4+APBRVDBUhzoRzpHKmLPsMT5L76BK8FAhVRC3teQ9xc7I3nO6PmoOFkziXpXs6D0taPj/YgXlpy8qN8gyl6qaen3PoFNhlC25BTpvVW4RiFfK8zouQzCd2xUaHjqQMoyZFCHIDwDqq8sCWIwyrzyTmBHgB4l5OeoNH9DXbQjo8ypg2XpMtOTz8qic448NH9dcZveIXrv asn@krikkit.cryptomilk.site
|
||||
12
tests/keys/ssh_host_dsa_key
Normal file
12
tests/keys/ssh_host_dsa_key
Normal file
@@ -0,0 +1,12 @@
|
||||
-----BEGIN DSA PRIVATE KEY-----
|
||||
MIIBuwIBAAKBgQD7vBS+d/eJP6wK2VQw+8AIfgCw9IR50utLRkkrWbfDdiM7V+fp
|
||||
tJYKCyqZT9j9ANhqicB2tuqAI6WJBZMaGekxWfI30JxPkHZrrwbdFzlRbjav07lg
|
||||
IKqWgcz81iVPmfn5savEoobiSFjJNMmYcizjKZgGmyNUzlJjzF7u5qD08wIVAPFp
|
||||
6VKuv8VxNjENciUZCdEDRW/lAoGBAN/BFSBRSP9frsHID6e2NeKHqs8JDUWhCTE9
|
||||
/WQKqUUbxO2UU98CfHuf1mNlaSsrOxaBdvTeURcZZc1svhyGr1VG+NbNTDDlzTgA
|
||||
UlrzNML61TYcFXQVxgifUy+Tmh8FRGCa6Ko/EsX4ZWLTto5w1u5cPpgzSbLMco9T
|
||||
AeeNLgYNAoGAJRuawWN3+NezI7+bBe42Kjg4gVUlpS+8TTlYFbwrM1Esab7gvxHB
|
||||
/b2apbk9xIAkkqsnb+EPrXTLUdE2Y7XkEuGLLSTus2UlZKobBGBX/Ioysg5W9Fk/
|
||||
2MhI4YssRb2alar8d+gmAHPaT+D+NDd90PBfY3HqcXFEK+eDTWo1JNICFBLdsuoO
|
||||
6pObeFSOYbr38kJzZ0xG
|
||||
-----END DSA PRIVATE KEY-----
|
||||
1
tests/keys/ssh_host_dsa_key.pub
Normal file
1
tests/keys/ssh_host_dsa_key.pub
Normal file
@@ -0,0 +1 @@
|
||||
ssh-dss AAAAB3NzaC1kc3MAAACBAPu8FL5394k/rArZVDD7wAh+ALD0hHnS60tGSStZt8N2IztX5+m0lgoLKplP2P0A2GqJwHa26oAjpYkFkxoZ6TFZ8jfQnE+QdmuvBt0XOVFuNq/TuWAgqpaBzPzWJU+Z+fmxq8SihuJIWMk0yZhyLOMpmAabI1TOUmPMXu7moPTzAAAAFQDxaelSrr/FcTYxDXIlGQnRA0Vv5QAAAIEA38EVIFFI/1+uwcgPp7Y14oeqzwkNRaEJMT39ZAqpRRvE7ZRT3wJ8e5/WY2VpKys7FoF29N5RFxllzWy+HIavVUb41s1MMOXNOABSWvM0wvrVNhwVdBXGCJ9TL5OaHwVEYJroqj8SxfhlYtO2jnDW7lw+mDNJssxyj1MB540uBg0AAACAJRuawWN3+NezI7+bBe42Kjg4gVUlpS+8TTlYFbwrM1Esab7gvxHB/b2apbk9xIAkkqsnb+EPrXTLUdE2Y7XkEuGLLSTus2UlZKobBGBX/Ioysg5W9Fk/2MhI4YssRb2alar8d+gmAHPaT+D+NDd90PBfY3HqcXFEK+eDTWo1JNI= asn@magrathea
|
||||
5
tests/keys/ssh_host_ecdsa_key
Normal file
5
tests/keys/ssh_host_ecdsa_key
Normal file
@@ -0,0 +1,5 @@
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIB9v2n1oaXvBECf0gDPxTibeUPvvkI1anNWDAIkNjs5JoAoGCCqGSM49
|
||||
AwEHoUQDQgAEqkTqNu7gRegPJRy0WiseJz9NAdBimzyNSzNwI5eAkEqv9D6Y95KL
|
||||
7DBEnDQ2p08iOLw+vN1PKHsCM7b/ONbYVg==
|
||||
-----END EC PRIVATE KEY-----
|
||||
1
tests/keys/ssh_host_ecdsa_key.pub
Normal file
1
tests/keys/ssh_host_ecdsa_key.pub
Normal file
@@ -0,0 +1 @@
|
||||
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKpE6jbu4EXoDyUctForHic/TQHQYps8jUszcCOXgJBKr/Q+mPeSi+wwRJw0NqdPIji8PrzdTyh7AjO2/zjW2FY= asn@magrathea
|
||||
BIN
tests/keys/ssh_host_key
Normal file
BIN
tests/keys/ssh_host_key
Normal file
Binary file not shown.
1
tests/keys/ssh_host_key.pub
Normal file
1
tests/keys/ssh_host_key.pub
Normal file
@@ -0,0 +1 @@
|
||||
2048 65537 25221975523736997039149017470335977198642717886559395625730372192276493838727011206749822289920387480933533054627057418868711378045090730895752530916661328094497437687453813456961487210492465678475508526337829331199296553120728607984859224949182503917312492825658971738208505685553964707412720244524969161284321098487507924676797222812771309962906894332072854924265623785469343453142982185436565166155021228521252914913227554455102103918367844210755391318078654400527927267478149210805219779896806429660492177158822689909493046725157917529664436252598971135251689616517266344945600782273453037452082373553352939812279 asn@magrathea
|
||||
27
tests/keys/ssh_host_rsa_key
Normal file
27
tests/keys/ssh_host_rsa_key
Normal file
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAqzabeU0oKbHDwdlqindABvtzgWCvXdHJ+d2Ew6te2LXjkwju
|
||||
y7u6B7y63NZRy57ccrE4YSeWItVoZn+DWN+guU354Ss/tzQ9/thUmLrvtKNvJwuF
|
||||
F5Ch7Q4BsrXGsb2GSv+7W5tpx3yAqH1TvKQj/MmQVX+/9KtXEnh7/vpiCqoOXQAR
|
||||
zvIIQxoo1aUQBHAkRW7Yw0Ds7AjC9uV1ns4xdBXPQmDk23pWvCq7E+7rOEbKRrjj
|
||||
lApS4lJYy0oEXsFdqUPd+PtT1gG0nIElHFQtsTgUvwYQmJEzrBxv41odwRvxbMjg
|
||||
THPr4SLRRRSuPwICWyvxqPpa7EsfMBnbPEIUzQIDAQABAoIBAEUO15MLvgFjRDQy
|
||||
P7jt9JNcZPBwUQukjLUN1nkd7Dm407wAxGDErXplc3GTuJZK01wngzgcwX/3WA7P
|
||||
q+jy+l8DxqA904tPtRnPo/+elwTjTvgOu3YPzmBRX/n3O9eBPGOP1sBSZU4jN7m+
|
||||
I0JZanKR0nfJ+WD0o0A9/LWRxG3MFIntBamtT6pgee8sAu44IvW0o7tHJabMq02J
|
||||
Z/ndrJmox34wq6SMFANax+N1x9sZa60bL7gEoDWQJNKOaMrbtOaIoTGFIc4hFqoA
|
||||
SzjNqcGsHPWs44cw0mNkUGq37jEvaCwzAp+U80ma1skBhXuJL9sQOxl1v5qW91c/
|
||||
Cnm5WYECgYEA4DPvqbLt+VdyTtmCQ370yiCk4OPPMPzbM65IVKgQL/rN6HdNShTO
|
||||
uLF6P8XC8vNP2OSydJeFt+kMKd7E/4o5LfvEqUGXZJDkB7fLjrOjyZU3bxtIx95x
|
||||
qYGWRcWbd3sHzlBJGuFVSE7GREE+lqhkSu4ry4l/GAKxSymAXgGd/9ECgYEAw37L
|
||||
ppZIavcLE2rZgXHoqMiJzeGzsidJbkHss4k7ubLe8vyBMiv0HC2anxPa2+yNWuF2
|
||||
+pEr84bllh149VKeild24UEBAR2w/P41ggWqiUP7PKllh+huWzG4+KNFbfUP4dd0
|
||||
4LkVgfsCz32qD8qxXNCxJCZ8H2fmjKsYw/oCID0CgYAiuSh3GdUtdtOnTpyUI4d5
|
||||
/pBKnD2skpzIZkehhN3s8GUPidqYjJxvkl0in1hQFErbhp/02rrE/vz5Rx0vjpLI
|
||||
gmO06wmtc5s9bsPB+CR3xfpt5MXi3pqv6/gAGli3qoBM/bY0yY1Rw5GFZK1y2+Wc
|
||||
jUKPJV5fs5sNzwGojYuQ4QKBgQCNNgqOo2Fd+mLCvNyt1wTy3iBEWfL+DcjJ3s7G
|
||||
hKtioKTQqbn87qjercZRf/sH/t/ANLpHlhNETj2KaHGV6v7f+PvDC7xY/QR6SnmG
|
||||
GOetTTCuCcJwIGGOd+UfnHgrS+gT/xjKtoalpBXMoP31eDkTTR+XeEESQm/TTkeO
|
||||
UAm3FQKBgD8Y7CLHpyZZ+eOnxRSPU4m4AWAEp7JOwHDRWWQeUornrXDYgD87d2M9
|
||||
iIAEuOzNggA56Nm3AzBOPRj4HkBh57ToVKPswHwB0oWvrtSjpLkkU6q8xRG3XuJD
|
||||
2AskDaZONzIDoJGfZ3+W7YbKELK7DPtFXL15sOfBmpoEkI9RA5vM
|
||||
-----END RSA PRIVATE KEY-----
|
||||
1
tests/keys/ssh_host_rsa_key.pub
Normal file
1
tests/keys/ssh_host_rsa_key.pub
Normal file
@@ -0,0 +1 @@
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCrNpt5TSgpscPB2WqKd0AG+3OBYK9d0cn53YTDq17YteOTCO7Lu7oHvLrc1lHLntxysThhJ5Yi1Whmf4NY36C5TfnhKz+3ND3+2FSYuu+0o28nC4UXkKHtDgGytcaxvYZK/7tbm2nHfICofVO8pCP8yZBVf7/0q1cSeHv++mIKqg5dABHO8ghDGijVpRAEcCRFbtjDQOzsCML25XWezjF0Fc9CYOTbela8KrsT7us4RspGuOOUClLiUljLSgRewV2pQ934+1PWAbScgSUcVC2xOBS/BhCYkTOsHG/jWh3BG/FsyOBMc+vhItFFFK4/AgJbK/Go+lrsSx8wGds8QhTN asn@magrathea
|
||||
@@ -5,9 +5,9 @@ if (WITH_SERVER AND UNIX AND NOT WIN32)
|
||||
include_directories(
|
||||
${LIBSSH_PUBLIC_INCLUDE_DIRS}
|
||||
${CMOCKA_INCLUDE_DIR}
|
||||
${OPENSSL_INCLUDE_DIRS}
|
||||
${GCRYPT_INCLUDE_DIRS}
|
||||
${ZLIB_INCLUDE_DIRS}
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
${GCRYPT_INCLUDE_DIR}
|
||||
${ZLIB_INCLUDE_DIR}
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
|
||||
370
tests/torture.c
370
tests/torture.c
@@ -28,6 +28,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <dirent.h>
|
||||
@@ -219,10 +220,16 @@ static const char torture_ed25519_testkey_pp[]=
|
||||
"Y3GsmYTDstmicanQ==\n"
|
||||
"-----END OPENSSH PRIVATE KEY-----\n";
|
||||
|
||||
#define TORTURE_SOCKET_DIR "/tmp/test_socket_wrapper_XXXXXX"
|
||||
#define TORTURE_SSHD_PIDFILE "sshd/sshd.pid"
|
||||
#define TORTURE_SSHD_CONFIG "sshd/sshd_config"
|
||||
#define TORTURE_PCAP_FILE "socket_trace.pcap"
|
||||
|
||||
static int verbosity = 0;
|
||||
static const char *pattern = NULL;
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
static int _torture_auth_kbdint(ssh_session session,
|
||||
const char *password) {
|
||||
const char *prompt;
|
||||
@@ -338,6 +345,58 @@ int torture_isdir(const char *path) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int torture_terminate_process(const char *pidfile)
|
||||
{
|
||||
char buf[8] = {0};
|
||||
long int tmp;
|
||||
ssize_t rc;
|
||||
pid_t pid;
|
||||
int fd;
|
||||
int is_running = 1;
|
||||
int count;
|
||||
|
||||
/* read the pidfile */
|
||||
fd = open(pidfile, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = read(fd, buf, sizeof(buf));
|
||||
close(fd);
|
||||
if (rc <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
|
||||
tmp = strtol(buf, NULL, 10);
|
||||
if (tmp == 0 || tmp > 0xFFFF || errno == ERANGE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pid = (pid_t)(tmp & 0xFFFF);
|
||||
|
||||
for (count = 0; count < 10; count++) {
|
||||
/* Make sure the daemon goes away! */
|
||||
kill(pid, SIGTERM);
|
||||
|
||||
usleep(10 * 1000);
|
||||
|
||||
rc = kill(pid, 0);
|
||||
if (rc != 0) {
|
||||
is_running = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_running) {
|
||||
fprintf(stderr,
|
||||
"WARNING: The process server is still running!\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssh_session torture_ssh_session(const char *host,
|
||||
const unsigned int *port,
|
||||
const char *user,
|
||||
@@ -355,11 +414,6 @@ ssh_session torture_ssh_session(const char *host,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_SSH_DIR, "/tmp");
|
||||
if (rc < 0) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (ssh_options_set(session, SSH_OPTIONS_HOST, host) < 0) {
|
||||
goto failed;
|
||||
}
|
||||
@@ -397,10 +451,10 @@ ssh_session torture_ssh_session(const char *host,
|
||||
}
|
||||
|
||||
if (password != NULL) {
|
||||
if (method & SSH_AUTH_METHOD_INTERACTIVE) {
|
||||
rc = _torture_auth_kbdint(session, password);
|
||||
} else if (method & SSH_AUTH_METHOD_PASSWORD) {
|
||||
if (method & SSH_AUTH_METHOD_PASSWORD) {
|
||||
rc = ssh_userauth_password(session, NULL, password);
|
||||
} else if (method & SSH_AUTH_METHOD_INTERACTIVE) {
|
||||
rc = _torture_auth_kbdint(session, password);
|
||||
}
|
||||
} else {
|
||||
rc = ssh_userauth_publickey_auto(session, NULL, NULL);
|
||||
@@ -479,7 +533,7 @@ ssh_bind torture_ssh_bind(const char *addr,
|
||||
return sshbind;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
#ifdef WITH_SFTP
|
||||
|
||||
@@ -541,37 +595,11 @@ void torture_sftp_close(struct torture_sftp *t) {
|
||||
sftp_free(t->sftp);
|
||||
}
|
||||
|
||||
if (t->ssh != NULL) {
|
||||
if (ssh_is_connected(t->ssh)) {
|
||||
ssh_disconnect(t->ssh);
|
||||
}
|
||||
ssh_free(t->ssh);
|
||||
}
|
||||
|
||||
free(t->testdir);
|
||||
free(t);
|
||||
}
|
||||
#endif /* WITH_SFTP */
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
void torture_write_file(const char *filename, const char *data){
|
||||
int fd;
|
||||
int rc;
|
||||
|
||||
assert_non_null(filename);
|
||||
assert_true(filename[0] != '\0');
|
||||
assert_non_null(data);
|
||||
|
||||
fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0755);
|
||||
assert_true(fd >= 0);
|
||||
|
||||
rc = write(fd, data, strlen(data));
|
||||
assert_int_equal(rc, strlen(data));
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static const char *torture_get_testkey_internal(enum ssh_keytypes_e type,
|
||||
int bits,
|
||||
int with_passphrase,
|
||||
@@ -647,6 +675,251 @@ const char *torture_get_testkey_passphrase(void)
|
||||
return TORTURE_TESTKEY_PASSWORD;
|
||||
}
|
||||
|
||||
void torture_setup_socket_dir(void **state)
|
||||
{
|
||||
struct torture_state *s;
|
||||
const char *p;
|
||||
size_t len;
|
||||
char *env = getenv("TORTURE_GENERATE_PCAP");
|
||||
|
||||
s = malloc(sizeof(struct torture_state));
|
||||
assert_non_null(s);
|
||||
|
||||
s->socket_dir = strdup(TORTURE_SOCKET_DIR);
|
||||
assert_non_null(s->socket_dir);
|
||||
|
||||
p = mkdtemp(s->socket_dir);
|
||||
assert_non_null(p);
|
||||
|
||||
/* pcap file */
|
||||
len = strlen(p) + 1 + strlen(TORTURE_PCAP_FILE) + 1;
|
||||
|
||||
s->pcap_file = malloc(len);
|
||||
assert_non_null(s->pcap_file);
|
||||
|
||||
snprintf(s->pcap_file, len, "%s/%s", p, TORTURE_PCAP_FILE);
|
||||
|
||||
/* pid file */
|
||||
len = strlen(p) + 1 + strlen(TORTURE_SSHD_PIDFILE) + 1;
|
||||
|
||||
s->srv_pidfile = malloc(len);
|
||||
assert_non_null(s->srv_pidfile);
|
||||
|
||||
snprintf(s->srv_pidfile, len, "%s/%s", p, TORTURE_SSHD_PIDFILE);
|
||||
|
||||
/* config file */
|
||||
len = strlen(p) + 1 + strlen(TORTURE_SSHD_CONFIG) + 1;
|
||||
|
||||
s->srv_config = malloc(len);
|
||||
assert_non_null(s->srv_config);
|
||||
|
||||
snprintf(s->srv_config, len, "%s/%s", p, TORTURE_SSHD_CONFIG);
|
||||
|
||||
setenv("SOCKET_WRAPPER_DIR", p, 1);
|
||||
setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "170", 1);
|
||||
if (env != NULL && env[0] == '1') {
|
||||
setenv("SOCKET_WRAPPER_PCAP_FILE", s->pcap_file, 1);
|
||||
}
|
||||
|
||||
*state = s;
|
||||
}
|
||||
|
||||
static void torture_setup_create_sshd_config(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
char ed25519_hostkey[1024] = {0};
|
||||
char dsa_hostkey[1024];
|
||||
char rsa_hostkey[1024];
|
||||
char ecdsa_hostkey[1024];
|
||||
char sshd_config[2048];
|
||||
char sshd_path[1024];
|
||||
struct stat sb;
|
||||
const char *sftp_server_locations[] = {
|
||||
"/usr/lib/ssh/sftp-server",
|
||||
"/usr/libexec/sftp-server",
|
||||
"/usr/libexec/openssh/sftp-server",
|
||||
"/usr/lib/openssh/sftp-server", /* Debian */
|
||||
};
|
||||
#ifndef OPENSSH_VERSION_MAJOR
|
||||
#define OPENSSH_VERSION_MAJOR 7U
|
||||
#define OPENSSH_VERSION_MINOR 0U
|
||||
#endif /* OPENSSH_VERSION_MAJOR */
|
||||
const char config_string[]=
|
||||
"Port 22\n"
|
||||
"ListenAddress 127.0.0.10\n"
|
||||
"HostKey %s\n"
|
||||
"HostKey %s\n"
|
||||
"HostKey %s\n"
|
||||
"HostKey %s\n"
|
||||
"\n"
|
||||
"LogLevel DEBUG3\n"
|
||||
"Subsystem sftp %s -l DEBUG2\n"
|
||||
"\n"
|
||||
"PasswordAuthentication yes\n"
|
||||
"KbdInteractiveAuthentication yes\n"
|
||||
"PubkeyAuthentication yes\n"
|
||||
"\n"
|
||||
"StrictModes no\n"
|
||||
"\n"
|
||||
"UsePAM yes\n"
|
||||
"\n"
|
||||
#if (OPENSSH_VERSION_MAJOR == 6 && OPENSSH_VERSION_MINOR >= 7) || (OPENSSH_VERSION_MAJOR >= 7)
|
||||
"HostKeyAlgorithms +ssh-dss\n"
|
||||
# if (OPENSSH_VERSION_MAJOR == 7 && OPENSSH_VERSION_MINOR < 6)
|
||||
"Ciphers +3des-cbc,aes128-cbc,aes192-cbc,aes256-cbc,blowfish-cbc\n"
|
||||
# else /* OPENSSH_VERSION 7.0 - 7.5 */
|
||||
"Ciphers +3des-cbc,aes128-cbc,aes192-cbc,aes256-cbc\n"
|
||||
# endif /* OPENSSH_VERSION 7.0 - 7.6 */
|
||||
"KexAlgorithms +diffie-hellman-group1-sha1"
|
||||
#else /* OPENSSH_VERSION >= 6.7 */
|
||||
"Ciphers 3des-cbc,aes128-cbc,aes192-cbc,aes256-cbc,aes128-ctr,"
|
||||
"aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,"
|
||||
"aes256-gcm@openssh.com,arcfour128,arcfour256,arcfour,"
|
||||
"blowfish-cbc,cast128-cbc,chacha20-poly1305@openssh.com\n"
|
||||
"KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp256,"
|
||||
"ecdh-sha2-nistp384,ecdh-sha2-nistp521,"
|
||||
"diffie-hellman-group-exchange-sha256,"
|
||||
"diffie-hellman-group-exchange-sha1,"
|
||||
"diffie-hellman-group14-sha1,"
|
||||
"diffie-hellman-group1-sha1\n"
|
||||
#endif /* OPENSSH_VERSION >= 6.7 */
|
||||
"\n"
|
||||
"AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES\n"
|
||||
"AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT\n"
|
||||
"AcceptEnv LC_IDENTIFICATION LC_ALL LC_LIBSSH\n"
|
||||
"\n"
|
||||
"PidFile %s\n";
|
||||
size_t sftp_sl_size = ARRAY_SIZE(sftp_server_locations);
|
||||
const char *sftp_server;
|
||||
size_t i;
|
||||
int rc;
|
||||
|
||||
snprintf(sshd_path,
|
||||
sizeof(sshd_path),
|
||||
"%s/sshd",
|
||||
s->socket_dir);
|
||||
|
||||
rc = mkdir(sshd_path, 0755);
|
||||
assert_return_code(rc, errno);
|
||||
|
||||
snprintf(ed25519_hostkey,
|
||||
sizeof(ed25519_hostkey),
|
||||
"%s/sshd/ssh_host_ed25519_key",
|
||||
s->socket_dir);
|
||||
torture_write_file(ed25519_hostkey,
|
||||
torture_get_testkey(SSH_KEYTYPE_ED25519, 0, 0));
|
||||
|
||||
snprintf(dsa_hostkey,
|
||||
sizeof(dsa_hostkey),
|
||||
"%s/sshd/ssh_host_dsa_key",
|
||||
s->socket_dir);
|
||||
torture_write_file(dsa_hostkey, torture_get_testkey(SSH_KEYTYPE_DSS, 0, 0));
|
||||
|
||||
snprintf(rsa_hostkey,
|
||||
sizeof(rsa_hostkey),
|
||||
"%s/sshd/ssh_host_rsa_key",
|
||||
s->socket_dir);
|
||||
torture_write_file(rsa_hostkey, torture_get_testkey(SSH_KEYTYPE_RSA, 0, 0));
|
||||
|
||||
snprintf(ecdsa_hostkey,
|
||||
sizeof(ecdsa_hostkey),
|
||||
"%s/sshd/ssh_host_ecdsa_key",
|
||||
s->socket_dir);
|
||||
torture_write_file(ecdsa_hostkey,
|
||||
torture_get_testkey(SSH_KEYTYPE_ECDSA, 521, 0));
|
||||
|
||||
assert_non_null(s->socket_dir);
|
||||
|
||||
sftp_server = getenv("TORTURE_SFTP_SERVER");
|
||||
if (sftp_server == NULL) {
|
||||
for (i = 0; i < sftp_sl_size; i++) {
|
||||
sftp_server = sftp_server_locations[i];
|
||||
rc = lstat(sftp_server, &sb);
|
||||
if (rc == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert_non_null(sftp_server);
|
||||
|
||||
snprintf(sshd_config, sizeof(sshd_config),
|
||||
config_string,
|
||||
ed25519_hostkey,
|
||||
dsa_hostkey,
|
||||
rsa_hostkey,
|
||||
ecdsa_hostkey,
|
||||
sftp_server,
|
||||
s->srv_pidfile);
|
||||
|
||||
torture_write_file(s->srv_config, sshd_config);
|
||||
}
|
||||
|
||||
void torture_setup_sshd_server(void **state)
|
||||
{
|
||||
struct torture_state *s;
|
||||
char sshd_start_cmd[1024];
|
||||
int rc;
|
||||
|
||||
torture_setup_socket_dir(state);
|
||||
torture_setup_create_sshd_config(state);
|
||||
|
||||
/* Set the default interface for the server */
|
||||
setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "10", 1);
|
||||
setenv("PAM_WRAPPER", "1", 1);
|
||||
|
||||
s = *state;
|
||||
|
||||
snprintf(sshd_start_cmd, sizeof(sshd_start_cmd),
|
||||
"/usr/sbin/sshd -r -f %s -E %s/sshd/daemon.log 2> %s/sshd/cwrap.log",
|
||||
s->srv_config, s->socket_dir, s->socket_dir);
|
||||
|
||||
rc = system(sshd_start_cmd);
|
||||
assert_return_code(rc, errno);
|
||||
|
||||
/* Give the process some time to start */
|
||||
usleep(100 * 1000);
|
||||
|
||||
setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "21", 1);
|
||||
unsetenv("PAM_WRAPPER");
|
||||
}
|
||||
|
||||
void torture_teardown_socket_dir(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
char *env = getenv("TORTURE_SKIP_CLEANUP");
|
||||
int rc;
|
||||
|
||||
if (env != NULL && env[0] == '1') {
|
||||
fprintf(stderr, "[ TORTURE ] >>> Skipping cleanup of %s\n", s->socket_dir);
|
||||
} else {
|
||||
rc = torture_rmdirs(s->socket_dir);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr,
|
||||
"torture_rmdirs(%s) failed: %s",
|
||||
s->socket_dir,
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
free(s->socket_dir);
|
||||
free(s->pcap_file);
|
||||
free(s->srv_pidfile);
|
||||
free(s);
|
||||
}
|
||||
|
||||
void torture_teardown_sshd_server(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
int rc;
|
||||
|
||||
rc = torture_terminate_process(s->srv_pidfile);
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "XXXXXX Failed to terminate sshd\n");
|
||||
}
|
||||
|
||||
torture_teardown_socket_dir(state);
|
||||
}
|
||||
|
||||
int torture_libssh_verbosity(void){
|
||||
return verbosity;
|
||||
}
|
||||
@@ -685,8 +958,29 @@ void _torture_filter_tests(UnitTest *tests, size_t ntests){
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
void torture_write_file(const char *filename, const char *data){
|
||||
int fd;
|
||||
int rc;
|
||||
|
||||
assert_non_null(filename);
|
||||
assert_true(filename[0] != '\0');
|
||||
assert_non_null(data);
|
||||
|
||||
fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0600);
|
||||
assert_true(fd >= 0);
|
||||
|
||||
rc = write(fd, data, strlen(data));
|
||||
assert_int_equal(rc, strlen(data));
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
struct argument_s arguments;
|
||||
char *env = getenv("LIBSSH_VERBOSITY");
|
||||
|
||||
arguments.verbose=0;
|
||||
arguments.pattern=NULL;
|
||||
@@ -694,6 +988,12 @@ int main(int argc, char **argv) {
|
||||
verbosity=arguments.verbose;
|
||||
pattern=arguments.pattern;
|
||||
|
||||
if (verbosity == 0 && env != NULL && env[0] != '\0') {
|
||||
if (env[0] > '0' && env[0] < '9') {
|
||||
verbosity = atoi(env);
|
||||
}
|
||||
}
|
||||
|
||||
return torture_run_tests();
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,10 @@
|
||||
assert_true(code >= 0)
|
||||
#endif /* assert_return_code */
|
||||
|
||||
#define TORTURE_SSH_SERVER "127.0.0.10"
|
||||
|
||||
#define TORTURE_SSH_USER_ALICE "alice"
|
||||
|
||||
#define TORTURE_TESTKEY_PASSWORD "libssh-rocks"
|
||||
|
||||
/* Used by main to communicate with parse_opt. */
|
||||
@@ -60,11 +64,24 @@ struct torture_sftp {
|
||||
char *testdir;
|
||||
};
|
||||
|
||||
struct torture_state {
|
||||
char *socket_dir;
|
||||
char *pcap_file;
|
||||
char *srv_pidfile;
|
||||
char *srv_config;
|
||||
};
|
||||
|
||||
#ifndef ZERO_STRUCT
|
||||
#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
|
||||
#endif
|
||||
|
||||
void torture_cmdline_parse(int argc, char **argv, struct argument_s *arguments);
|
||||
|
||||
int torture_rmdirs(const char *path);
|
||||
int torture_isdir(const char *path);
|
||||
|
||||
int torture_terminate_process(const char *pidfile);
|
||||
|
||||
/*
|
||||
* Returns the verbosity level asked by user
|
||||
*/
|
||||
@@ -94,6 +111,12 @@ void torture_write_file(const char *filename, const char *data);
|
||||
#define torture_filter_tests(tests) _torture_filter_tests(tests, sizeof(tests) / sizeof(tests)[0])
|
||||
void _torture_filter_tests(UnitTest *tests, size_t ntests);
|
||||
|
||||
void torture_setup_socket_dir(void **state);
|
||||
void torture_setup_sshd_server(void **state);
|
||||
|
||||
void torture_teardown_socket_dir(void **state);
|
||||
void torture_teardown_sshd_server(void **state);
|
||||
|
||||
/*
|
||||
* This function must be defined in every unit test file.
|
||||
*/
|
||||
|
||||
@@ -10,15 +10,18 @@ add_cmocka_test(torture_misc torture_misc.c ${TORTURE_LIBRARY})
|
||||
add_cmocka_test(torture_options torture_options.c ${TORTURE_LIBRARY})
|
||||
add_cmocka_test(torture_isipaddr torture_isipaddr.c ${TORTURE_LIBRARY})
|
||||
add_cmocka_test(torture_pki_ed25519 torture_pki_ed25519.c ${TORTURE_LIBRARY})
|
||||
add_cmocka_test(torture_packet_filter torture_packet_filter.c ${TORTURE_LIBRARY})
|
||||
if (UNIX AND NOT WIN32)
|
||||
# requires ssh-keygen
|
||||
add_cmocka_test(torture_keyfiles torture_keyfiles.c ${TORTURE_LIBRARY})
|
||||
add_cmocka_test(torture_pki torture_pki.c ${TORTURE_LIBRARY})
|
||||
# requires pthread
|
||||
add_cmocka_test(torture_rand torture_rand.c ${TORTURE_LIBRARY})
|
||||
# requires /dev/null
|
||||
add_cmocka_test(torture_channel torture_channel.c ${TORTURE_LIBRARY})
|
||||
if (WITH_SERVER AND Threads_FOUND)
|
||||
add_cmocka_test(torture_server_x11 torture_server_x11.c ${TORTURE_LIBRARY})
|
||||
endif (WITH_SERVER AND Threads_FOUND)
|
||||
# requires pthread
|
||||
if (LIBSSH_THREADS)
|
||||
add_cmocka_test(torture_rand torture_rand.c ${TORTURE_LIBRARY})
|
||||
if (WITH_SERVER)
|
||||
add_cmocka_test(torture_server_x11 torture_server_x11.c ${TORTURE_LIBRARY})
|
||||
endif (WITH_SERVER)
|
||||
endif (LIBSSH_THREADS)
|
||||
endif (UNIX AND NOT WIN32)
|
||||
|
||||
500
tests/unittests/torture_packet_filter.c
Normal file
500
tests/unittests/torture_packet_filter.c
Normal file
@@ -0,0 +1,500 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2018 by 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This test checks if the messages accepted by the packet filter were intented
|
||||
* to be accepted.
|
||||
*
|
||||
* The process consists in 2 steps:
|
||||
* - Try the filter with a message type in an arbitrary state
|
||||
* - If the message is accepted by the filter, check if the message is in the
|
||||
* set of accepted states.
|
||||
*
|
||||
* Only the values selected by the flag (COMPARE_*) are considered.
|
||||
* */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define LIBSSH_STATIC
|
||||
|
||||
#include "torture.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/libssh.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/auth.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/packet.h"
|
||||
|
||||
#include "packet.c"
|
||||
|
||||
#define COMPARE_SESSION_STATE 1
|
||||
#define COMPARE_ROLE (1 << 1)
|
||||
#define COMPARE_DH_STATE (1 << 2)
|
||||
#define COMPARE_AUTH_STATE (1 << 3)
|
||||
#define COMPARE_GLOBAL_REQ_STATE (1 << 4)
|
||||
|
||||
#define SESSION_STATE_COUNT 11
|
||||
#define DH_STATE_COUNT 4
|
||||
#define AUTH_STATE_COUNT 14
|
||||
#define GLOBAL_REQ_STATE_COUNT 5
|
||||
#define MESSAGE_COUNT 100 // from 1 to 100
|
||||
|
||||
#define ROLE_CLIENT 0
|
||||
#define ROLE_SERVER 1
|
||||
|
||||
/*
|
||||
* This is the list of currently unfiltered message types.
|
||||
* Only unrecognized types should be in this list.
|
||||
* */
|
||||
static uint8_t unfiltered[] = {
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
||||
22, 23, 24, 25, 26, 27, 28, 29,
|
||||
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
|
||||
54, 55, 56, 57, 58, 59,
|
||||
62,
|
||||
67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
|
||||
83, 84, 85, 86, 87, 88, 89,
|
||||
};
|
||||
|
||||
typedef struct global_state_st {
|
||||
/* If the bit in this flag is zero, the corresponding state is not
|
||||
* considered, working as a wildcard (meaning any value is accepted) */
|
||||
uint32_t flags;
|
||||
uint8_t role;
|
||||
enum ssh_session_state_e session;
|
||||
enum ssh_dh_state_e dh;
|
||||
enum ssh_auth_state_e auth;
|
||||
enum ssh_channel_request_state_e global_req;
|
||||
} global_state;
|
||||
|
||||
static int cmp_state(const void *e1, const void *e2)
|
||||
{
|
||||
global_state *s1 = (global_state *) e1;
|
||||
global_state *s2 = (global_state *) e2;
|
||||
|
||||
/* Compare role (client == 0 or server == 1)*/
|
||||
if (s1->role < s2->role) {
|
||||
return -1;
|
||||
}
|
||||
else if (s1->role > s2->role) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Compare session state */
|
||||
if (s1->session < s2->session) {
|
||||
return -1;
|
||||
}
|
||||
else if (s1->session > s2->session) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Compare DH state */
|
||||
if (s1->dh < s2->dh) {
|
||||
return -1;
|
||||
}
|
||||
else if (s1->dh > s2->dh) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Compare auth */
|
||||
if (s1->auth < s2->auth) {
|
||||
return -1;
|
||||
}
|
||||
else if (s1->auth > s2->auth) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Compare global_req */
|
||||
if (s1->global_req < s2->global_req) {
|
||||
return -1;
|
||||
}
|
||||
else if (s1->global_req > s2->global_req) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* If all equal, they are equal */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmp_state_search(const void *key, const void *array_element)
|
||||
{
|
||||
global_state *s1 = (global_state *) key;
|
||||
global_state *s2 = (global_state *) array_element;
|
||||
|
||||
int result = 0;
|
||||
|
||||
if (s2->flags & COMPARE_ROLE) {
|
||||
/* Compare role (client == 0 or server == 1)*/
|
||||
if (s1->role < s2->role) {
|
||||
return -1;
|
||||
}
|
||||
else if (s1->role > s2->role) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (s2->flags & COMPARE_SESSION_STATE) {
|
||||
/* Compare session state */
|
||||
if (s1->session < s2->session) {
|
||||
result = -1;
|
||||
goto end;
|
||||
}
|
||||
else if (s1->session > s2->session) {
|
||||
result = 1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (s2->flags & COMPARE_DH_STATE) {
|
||||
/* Compare DH state */
|
||||
if (s1->dh < s2->dh) {
|
||||
result = -1;
|
||||
goto end;
|
||||
}
|
||||
else if (s1->dh > s2->dh) {
|
||||
result = 1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (s2->flags & COMPARE_AUTH_STATE) {
|
||||
/* Compare auth */
|
||||
if (s1->auth < s2->auth) {
|
||||
result = -1;
|
||||
goto end;
|
||||
}
|
||||
else if (s1->auth > s2->auth) {
|
||||
result = 1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (s2->flags & COMPARE_GLOBAL_REQ_STATE) {
|
||||
/* Compare global_req */
|
||||
if (s1->global_req < s2->global_req) {
|
||||
result = -1;
|
||||
goto end;
|
||||
}
|
||||
else if (s1->global_req > s2->global_req) {
|
||||
result = 1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
return result;
|
||||
}
|
||||
|
||||
static int is_state_accepted(global_state *tested, global_state *accepted,
|
||||
int accepted_len)
|
||||
{
|
||||
global_state *found = NULL;
|
||||
|
||||
found = bsearch(tested, accepted, accepted_len, sizeof(global_state),
|
||||
cmp_state_search);
|
||||
|
||||
if (found != NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmp_uint8(const void *i, const void *j)
|
||||
{
|
||||
uint8_t e1 = *((uint8_t *)i);
|
||||
uint8_t e2 = *((uint8_t *)j);
|
||||
|
||||
if (e1 < e2) {
|
||||
return -1;
|
||||
}
|
||||
else if (e1 > e2) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_unfiltered(uint8_t msg_type)
|
||||
{
|
||||
uint8_t *found;
|
||||
|
||||
found = bsearch(&msg_type, unfiltered, sizeof(unfiltered)/sizeof(uint8_t),
|
||||
sizeof(uint8_t), cmp_uint8);
|
||||
|
||||
if (found != NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void torture_packet_filter_check_unfiltered(void **state)
|
||||
{
|
||||
ssh_session session;
|
||||
|
||||
int role_c;
|
||||
int auth_c;
|
||||
int session_c;
|
||||
int dh_c;
|
||||
int global_req_c;
|
||||
|
||||
uint8_t msg_type;
|
||||
|
||||
enum ssh_packet_filter_result_e rc;
|
||||
int in_unfiltered;
|
||||
|
||||
session = ssh_new();
|
||||
|
||||
for (msg_type = 1; msg_type <= MESSAGE_COUNT; msg_type++) {
|
||||
session->in_packet.type = msg_type;
|
||||
for (role_c = 0; role_c < 2; role_c++) {
|
||||
session->server = role_c;
|
||||
for (session_c = 0; session_c < SESSION_STATE_COUNT; session_c++) {
|
||||
session->session_state = session_c;
|
||||
for (dh_c = 0; dh_c < DH_STATE_COUNT; dh_c++) {
|
||||
session->dh_handshake_state = dh_c;
|
||||
for (auth_c = 0; auth_c < AUTH_STATE_COUNT; auth_c++) {
|
||||
session->auth_state = auth_c;
|
||||
for (global_req_c = 0;
|
||||
global_req_c < GLOBAL_REQ_STATE_COUNT;
|
||||
global_req_c++)
|
||||
{
|
||||
session->global_req_state = global_req_c;
|
||||
|
||||
rc = ssh_packet_incoming_filter(session);
|
||||
|
||||
if (rc == SSH_PACKET_UNKNOWN) {
|
||||
in_unfiltered = check_unfiltered(msg_type);
|
||||
|
||||
if (!in_unfiltered) {
|
||||
fprintf(stderr, "Message type %d UNFILTERED "
|
||||
"in state: role %d, session %d, dh %d, auth %d\n",
|
||||
msg_type, role_c, session_c, dh_c, auth_c);
|
||||
}
|
||||
assert_int_equal(in_unfiltered, 1);
|
||||
}
|
||||
else {
|
||||
in_unfiltered = check_unfiltered(msg_type);
|
||||
|
||||
if (in_unfiltered) {
|
||||
fprintf(stderr, "Message type %d NOT UNFILTERED "
|
||||
"in state: role %d, session %d, dh %d, auth %d\n",
|
||||
msg_type, role_c, session_c, dh_c, auth_c);
|
||||
}
|
||||
assert_int_equal(in_unfiltered, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ssh_free(session);
|
||||
}
|
||||
|
||||
static int check_message_in_all_states(global_state accepted[],
|
||||
int accepted_count, uint8_t msg_type)
|
||||
{
|
||||
ssh_session session;
|
||||
|
||||
int role_c;
|
||||
int auth_c;
|
||||
int session_c;
|
||||
int dh_c;
|
||||
int global_req_c;
|
||||
|
||||
enum ssh_packet_filter_result_e rc;
|
||||
int in_accepted;
|
||||
|
||||
global_state key;
|
||||
|
||||
session = ssh_new();
|
||||
|
||||
/* Sort the accepted array so that the elements can be searched using
|
||||
* bsearch */
|
||||
qsort(accepted, accepted_count, sizeof(global_state), cmp_state);
|
||||
|
||||
session->in_packet.type = msg_type;
|
||||
|
||||
for (role_c = 0; role_c < 2; role_c++) {
|
||||
session->server = role_c;
|
||||
key.role = role_c;
|
||||
for (session_c = 0; session_c < SESSION_STATE_COUNT; session_c++) {
|
||||
session->session_state = session_c;
|
||||
key.session = session_c;
|
||||
for (dh_c = 0; dh_c < DH_STATE_COUNT; dh_c++) {
|
||||
session->dh_handshake_state = dh_c;
|
||||
key.dh = dh_c;
|
||||
for (auth_c = 0; auth_c < AUTH_STATE_COUNT; auth_c++) {
|
||||
session->auth_state = auth_c;
|
||||
key.auth = auth_c;
|
||||
for (global_req_c = 0;
|
||||
global_req_c < GLOBAL_REQ_STATE_COUNT;
|
||||
global_req_c++)
|
||||
{
|
||||
session->global_req_state = global_req_c;
|
||||
key.global_req = global_req_c;
|
||||
|
||||
rc = ssh_packet_incoming_filter(session);
|
||||
|
||||
if (rc == SSH_PACKET_ALLOWED) {
|
||||
in_accepted = is_state_accepted(&key, accepted,
|
||||
accepted_count);
|
||||
|
||||
if (!in_accepted) {
|
||||
fprintf(stderr, "Message type %d ALLOWED "
|
||||
"in state: role %d, session %d, dh %d, auth %d\n",
|
||||
msg_type, role_c, session_c, dh_c, auth_c);
|
||||
}
|
||||
assert_int_equal(in_accepted, 1);
|
||||
}
|
||||
else if (rc == SSH_PACKET_DENIED) {
|
||||
in_accepted = is_state_accepted(&key, accepted, accepted_count);
|
||||
|
||||
if (in_accepted) {
|
||||
fprintf(stderr, "Message type %d DENIED "
|
||||
"in state: role %d, session %d, dh %d, auth %d\n",
|
||||
msg_type, role_c, session_c, dh_c, auth_c);
|
||||
}
|
||||
assert_int_equal(in_accepted, 0);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "Message type %d UNFILTERED "
|
||||
"in state: role %d, session %d, dh %d, auth %d\n",
|
||||
msg_type, role_c, session_c, dh_c, auth_c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ssh_free(session);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void torture_packet_filter_check_auth_success(void **state)
|
||||
{
|
||||
int rc;
|
||||
|
||||
global_state accepted[] = {
|
||||
{
|
||||
.flags = (COMPARE_SESSION_STATE |
|
||||
COMPARE_ROLE |
|
||||
COMPARE_AUTH_STATE |
|
||||
COMPARE_DH_STATE),
|
||||
.role = ROLE_CLIENT,
|
||||
.session = SSH_SESSION_STATE_AUTHENTICATING,
|
||||
.dh = DH_STATE_FINISHED,
|
||||
.auth = SSH_AUTH_STATE_PUBKEY_AUTH_SENT,
|
||||
},
|
||||
{
|
||||
.flags = (COMPARE_SESSION_STATE |
|
||||
COMPARE_ROLE |
|
||||
COMPARE_AUTH_STATE |
|
||||
COMPARE_DH_STATE),
|
||||
.role = ROLE_CLIENT,
|
||||
.session = SSH_SESSION_STATE_AUTHENTICATING,
|
||||
.dh = DH_STATE_FINISHED,
|
||||
.auth = SSH_AUTH_STATE_PASSWORD_AUTH_SENT,
|
||||
},
|
||||
{
|
||||
.flags = (COMPARE_SESSION_STATE |
|
||||
COMPARE_ROLE |
|
||||
COMPARE_AUTH_STATE |
|
||||
COMPARE_DH_STATE),
|
||||
.role = ROLE_CLIENT,
|
||||
.session = SSH_SESSION_STATE_AUTHENTICATING,
|
||||
.dh = DH_STATE_FINISHED,
|
||||
.auth = SSH_AUTH_STATE_GSSAPI_MIC_SENT,
|
||||
},
|
||||
{
|
||||
.flags = (COMPARE_SESSION_STATE |
|
||||
COMPARE_ROLE |
|
||||
COMPARE_AUTH_STATE |
|
||||
COMPARE_DH_STATE),
|
||||
.role = ROLE_CLIENT,
|
||||
.session = SSH_SESSION_STATE_AUTHENTICATING,
|
||||
.dh = DH_STATE_FINISHED,
|
||||
.auth = SSH_AUTH_STATE_KBDINT_SENT,
|
||||
},
|
||||
{
|
||||
.flags = (COMPARE_SESSION_STATE |
|
||||
COMPARE_ROLE |
|
||||
COMPARE_AUTH_STATE |
|
||||
COMPARE_DH_STATE),
|
||||
.role = ROLE_CLIENT,
|
||||
.session = SSH_SESSION_STATE_AUTHENTICATING,
|
||||
.dh = DH_STATE_FINISHED,
|
||||
.auth = SSH_AUTH_STATE_AUTH_NONE_SENT,
|
||||
}
|
||||
};
|
||||
|
||||
int accepted_count = 5;
|
||||
|
||||
/* Unused */
|
||||
(void) state;
|
||||
|
||||
rc = check_message_in_all_states(accepted, accepted_count,
|
||||
SSH2_MSG_USERAUTH_SUCCESS);
|
||||
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
static void torture_packet_filter_check_channel_open(void **state)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* The only condition to accept a CHANNEL_OPEN is to be authenticated */
|
||||
global_state accepted[] = {
|
||||
{
|
||||
.flags = COMPARE_SESSION_STATE,
|
||||
.session = SSH_SESSION_STATE_AUTHENTICATED,
|
||||
}
|
||||
};
|
||||
|
||||
int accepted_count = 1;
|
||||
|
||||
/* Unused */
|
||||
(void) state;
|
||||
|
||||
rc = check_message_in_all_states(accepted, accepted_count,
|
||||
SSH2_MSG_CHANNEL_OPEN);
|
||||
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
int rc;
|
||||
UnitTest tests[] = {
|
||||
unit_test(torture_packet_filter_check_auth_success),
|
||||
unit_test(torture_packet_filter_check_channel_open),
|
||||
unit_test(torture_packet_filter_check_unfiltered),
|
||||
};
|
||||
|
||||
ssh_init();
|
||||
torture_filter_tests(tests);
|
||||
rc = run_tests(tests);
|
||||
ssh_finalize();
|
||||
return rc;
|
||||
}
|
||||
@@ -212,6 +212,9 @@ static void torture_pki_import_privkey_base64_RSA(void **state) {
|
||||
type = ssh_key_type(key);
|
||||
assert_true(type == SSH_KEYTYPE_RSA);
|
||||
|
||||
rc = ssh_key_is_private(key);
|
||||
assert_true(rc == 1);
|
||||
|
||||
rc = ssh_key_is_public(key);
|
||||
assert_true(rc == 1);
|
||||
|
||||
@@ -281,6 +284,9 @@ static void torture_pki_import_privkey_base64_ECDSA(void **state) {
|
||||
rc = ssh_pki_import_privkey_base64(key_str, passphrase, NULL, NULL, &key);
|
||||
assert_true(rc == 0);
|
||||
|
||||
rc = ssh_key_is_private(key);
|
||||
assert_true(rc == 1);
|
||||
|
||||
free(key_str);
|
||||
ssh_key_free(key);
|
||||
}
|
||||
@@ -300,6 +306,10 @@ static void torture_pki_import_privkey_base64_passphrase(void **state) {
|
||||
NULL,
|
||||
&key);
|
||||
assert_true(rc == 0);
|
||||
|
||||
rc = ssh_key_is_private(key);
|
||||
assert_true(rc == 1);
|
||||
|
||||
ssh_key_free(key);
|
||||
|
||||
/* test if it returns -1 if passphrase is wrong */
|
||||
@@ -329,6 +339,10 @@ static void torture_pki_import_privkey_base64_passphrase(void **state) {
|
||||
NULL,
|
||||
&key);
|
||||
assert_true(rc == 0);
|
||||
|
||||
rc = ssh_key_is_private(key);
|
||||
assert_true(rc == 1);
|
||||
|
||||
ssh_key_free(key);
|
||||
|
||||
/* test if it returns -1 if passphrase is wrong */
|
||||
@@ -358,6 +372,10 @@ static void torture_pki_import_privkey_base64_passphrase(void **state) {
|
||||
NULL,
|
||||
&key);
|
||||
assert_true(rc == 0);
|
||||
|
||||
rc = ssh_key_is_private(key);
|
||||
assert_true(rc == 1);
|
||||
|
||||
ssh_key_free(key);
|
||||
|
||||
/* test if it returns -1 if passphrase is wrong */
|
||||
@@ -388,6 +406,9 @@ static void torture_pki_import_privkey_base64_ed25519(void **state){
|
||||
type = ssh_key_type(key);
|
||||
assert_true(type == SSH_KEYTYPE_ED25519);
|
||||
|
||||
rc = ssh_key_is_private(key);
|
||||
assert_true(rc == 1);
|
||||
|
||||
rc = ssh_key_is_public(key);
|
||||
assert_true(rc == 1);
|
||||
|
||||
@@ -411,6 +432,9 @@ static void torture_pki_pki_publickey_from_privatekey_RSA(void **state) {
|
||||
&key);
|
||||
assert_true(rc == 0);
|
||||
|
||||
rc = ssh_key_is_private(key);
|
||||
assert_true(rc == 1);
|
||||
|
||||
rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
@@ -433,6 +457,9 @@ static void torture_pki_pki_publickey_from_privatekey_DSA(void **state) {
|
||||
&key);
|
||||
assert_true(rc == 0);
|
||||
|
||||
rc = ssh_key_is_private(key);
|
||||
assert_true(rc == 1);
|
||||
|
||||
rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
@@ -455,6 +482,9 @@ static void torture_pki_pki_publickey_from_privatekey_ed25519(void **state){
|
||||
&key);
|
||||
assert_true(rc == 0);
|
||||
|
||||
rc = ssh_key_is_private(key);
|
||||
assert_true(rc == 1);
|
||||
|
||||
rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user