mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-04 12:20:42 +09:00
Compare commits
175 Commits
0ef79018b3
...
release-0-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62f7eaf156 | ||
|
|
2462b0fbc7 | ||
|
|
c05666245c | ||
|
|
6db13f776f | ||
|
|
0980117c52 | ||
|
|
3d66164545 | ||
|
|
c087e8704d | ||
|
|
e5801287da | ||
|
|
5b9d92c36f | ||
|
|
edc6b2cef2 | ||
|
|
9590a643ab | ||
|
|
bec9bc1222 | ||
|
|
b3067e362c | ||
|
|
5f99fed07c | ||
|
|
9973de535e | ||
|
|
a7d9f4addd | ||
|
|
a4f4fa3058 | ||
|
|
a9c4877d84 | ||
|
|
284466632e | ||
|
|
aa8381999a | ||
|
|
ac54a26c5d | ||
|
|
fd53ebc7b6 | ||
|
|
df2436b4a6 | ||
|
|
7029d2f4b8 | ||
|
|
3c9c358385 | ||
|
|
82d1627cad | ||
|
|
641e89b14a | ||
|
|
3a61d55f27 | ||
|
|
c4d1d8b684 | ||
|
|
10e27f26be | ||
|
|
9791bc3eeb | ||
|
|
4ad7828797 | ||
|
|
af8315b9ce | ||
|
|
94fdcf7a2a | ||
|
|
59a95fc3a7 | ||
|
|
c1729c36d9 | ||
|
|
23efab0f8f | ||
|
|
e50752a925 | ||
|
|
fd45c1b36b | ||
|
|
5080671581 | ||
|
|
e67fafd60f | ||
|
|
a2a98fb5bc | ||
|
|
e2480fbaba | ||
|
|
23e6b36209 | ||
|
|
541b38b772 | ||
|
|
a85a4cc192 | ||
|
|
54ef77123a | ||
|
|
4c679fd8a6 | ||
|
|
21d918c68a | ||
|
|
544fc28e6b | ||
|
|
601081ebb6 | ||
|
|
22d975a24b | ||
|
|
aeb9f3e389 | ||
|
|
d3a4e01137 | ||
|
|
a1b9ae5048 | ||
|
|
a375ebe29b | ||
|
|
b2f49a6a93 | ||
|
|
99fb5987ce | ||
|
|
be389dd644 | ||
|
|
a6a7922dbd | ||
|
|
608e81bc00 | ||
|
|
7e17838c0b | ||
|
|
84f6945a9c | ||
|
|
3ae187dbe7 | ||
|
|
26989ab001 | ||
|
|
5b2e39cd79 | ||
|
|
13af149ef9 | ||
|
|
3453cafd95 | ||
|
|
fa65fd3dd1 | ||
|
|
ec5fa5cc06 | ||
|
|
8577688174 | ||
|
|
31462a4d72 | ||
|
|
fd2ff2d29c | ||
|
|
0b09bd900f | ||
|
|
abc61fa1cc | ||
|
|
e94bff02ba | ||
|
|
3671c61023 | ||
|
|
2702f3ea3f | ||
|
|
4abd0522b4 | ||
|
|
62b6eb4436 | ||
|
|
4b7eba1eda | ||
|
|
9970b1fd7d | ||
|
|
d703f51861 | ||
|
|
a009702cd6 | ||
|
|
ed268e5948 | ||
|
|
10b4654ad5 | ||
|
|
9d7fc9d50b | ||
|
|
b8bc3a6582 | ||
|
|
07e8d8f1f2 | ||
|
|
34a927716a | ||
|
|
bae4090715 | ||
|
|
403ded1e97 | ||
|
|
6fd8de3376 | ||
|
|
5fe99f8b09 | ||
|
|
af155db080 | ||
|
|
df5a94d445 | ||
|
|
4bfe7f024c | ||
|
|
99ea177eea | ||
|
|
476630841f | ||
|
|
7f59662cad | ||
|
|
e9d6b15926 | ||
|
|
6885d32c05 | ||
|
|
e5c2af6316 | ||
|
|
08a1bebb58 | ||
|
|
6195b133bf | ||
|
|
6e65abbe63 | ||
|
|
bda836d744 | ||
|
|
c8c2647555 | ||
|
|
4ad74765f6 | ||
|
|
b1f93f600e | ||
|
|
28edbe1ef5 | ||
|
|
75cf66a3ee | ||
|
|
5021ed3074 | ||
|
|
3773366a25 | ||
|
|
c6fab4bf84 | ||
|
|
7d1dcb0dff | ||
|
|
d7c1384df0 | ||
|
|
d2bb97c1c6 | ||
|
|
3b6098597d | ||
|
|
964d8fdc11 | ||
|
|
5d339aa9e2 | ||
|
|
af7f69c515 | ||
|
|
ea92d5b230 | ||
|
|
f096e031ed | ||
|
|
a8be476ea9 | ||
|
|
b9f65b5740 | ||
|
|
99a58eb325 | ||
|
|
ed1cba705c | ||
|
|
0b13a6d265 | ||
|
|
74c0201219 | ||
|
|
83c51d1c13 | ||
|
|
c712d30311 | ||
|
|
2144049c7d | ||
|
|
9dd86859e8 | ||
|
|
810fbfb620 | ||
|
|
370d072eba | ||
|
|
56dfa69fc9 | ||
|
|
672f8412f0 | ||
|
|
83ff1ffcc3 | ||
|
|
fb35153b49 | ||
|
|
7539200773 | ||
|
|
254a166c02 | ||
|
|
3e938cb901 | ||
|
|
452b16ede2 | ||
|
|
bd47ff75ba | ||
|
|
0016ded7f9 | ||
|
|
d725b31752 | ||
|
|
c2e86c876c | ||
|
|
028516ba6a | ||
|
|
344b27ac6c | ||
|
|
a700259b01 | ||
|
|
14da14db05 | ||
|
|
474d63f24e | ||
|
|
b3589fbf6c | ||
|
|
dd68bae776 | ||
|
|
4768cf3e85 | ||
|
|
5a95681f01 | ||
|
|
13a3619102 | ||
|
|
c7636edf84 | ||
|
|
27e332b623 | ||
|
|
ebc8544c56 | ||
|
|
0f8e9b839c | ||
|
|
0c02d6effe | ||
|
|
7199b196b0 | ||
|
|
ca83b66066 | ||
|
|
d978f9b58a | ||
|
|
e539eaf9e0 | ||
|
|
b728f44ce9 | ||
|
|
2f0b671a61 | ||
|
|
1fadec37d6 | ||
|
|
2aabbd6245 | ||
|
|
fd6823691b | ||
|
|
b174ad8ae4 | ||
|
|
176778bb1c | ||
|
|
e5bf645010 |
@@ -6,13 +6,20 @@ cmake_minimum_required(VERSION 2.6.0)
|
|||||||
# global needed variables
|
# global needed variables
|
||||||
set(APPLICATION_NAME ${PROJECT_NAME})
|
set(APPLICATION_NAME ${PROJECT_NAME})
|
||||||
|
|
||||||
set(APPLICATION_VERSION "0.4.0")
|
|
||||||
|
|
||||||
set(APPLICATION_VERSION_MAJOR "0")
|
set(APPLICATION_VERSION_MAJOR "0")
|
||||||
set(APPLICATION_VERSION_MINOR "4")
|
set(APPLICATION_VERSION_MINOR "4")
|
||||||
set(APPLICATION_VERSION_PATCH "0")
|
set(APPLICATION_VERSION_PATCH "6")
|
||||||
|
|
||||||
set(LIBRARY_VERSION "4.0.0")
|
set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}")
|
||||||
|
|
||||||
|
# SOVERSION scheme: CURRENT.AGE.REVISION
|
||||||
|
# If there was an incompatible interface change:
|
||||||
|
# Increment CURRENT. Set AGE and REVISION to 0
|
||||||
|
# If there was a compatible interface change:
|
||||||
|
# Increment AGE. Set REVISION to 0
|
||||||
|
# If the source code was changed, but there were no interface changes:
|
||||||
|
# Increment REVISION.
|
||||||
|
set(LIBRARY_VERSION "4.1.3")
|
||||||
set(LIBRARY_SOVERSION "4")
|
set(LIBRARY_SOVERSION "4")
|
||||||
|
|
||||||
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
|
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
|
||||||
@@ -45,12 +52,12 @@ if (WITH_GCRYPT)
|
|||||||
endif (NOT GCRYPT_FOUND)
|
endif (NOT GCRYPT_FOUND)
|
||||||
else (WITH_GCRYPT)
|
else (WITH_GCRYPT)
|
||||||
find_package(OpenSSL)
|
find_package(OpenSSL)
|
||||||
if (NOT CRYPTO_FOUND)
|
if (NOT OPENSSL_FOUND)
|
||||||
find_package(GCrypt)
|
find_package(GCrypt)
|
||||||
if (NOT GCRYPT_FOUND)
|
if (NOT GCRYPT_FOUND)
|
||||||
message(FATAL_ERROR "Could not find OpenSSL or GCrypt")
|
message(FATAL_ERROR "Could not find OpenSSL or GCrypt")
|
||||||
endif (NOT GCRYPT_FOUND)
|
endif (NOT GCRYPT_FOUND)
|
||||||
endif (NOT CRYPTO_FOUND)
|
endif (NOT OPENSSL_FOUND)
|
||||||
endif(WITH_GCRYPT)
|
endif(WITH_GCRYPT)
|
||||||
|
|
||||||
# config.h checks
|
# config.h checks
|
||||||
@@ -61,12 +68,11 @@ configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
|||||||
add_subdirectory(doc)
|
add_subdirectory(doc)
|
||||||
add_subdirectory(include)
|
add_subdirectory(include)
|
||||||
add_subdirectory(libssh)
|
add_subdirectory(libssh)
|
||||||
add_subdirectory(tests)
|
|
||||||
|
|
||||||
# build samples
|
# build samples
|
||||||
include_directories(${CMAKE_SOURCE_DIR}/include)
|
include_directories(${CMAKE_SOURCE_DIR}/include)
|
||||||
|
|
||||||
if (UNIX AND NOT WIN32)
|
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
add_subdirectory(examples)
|
add_subdirectory(examples)
|
||||||
|
endif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
|
|
||||||
endif (UNIX AND NOT WIN32)
|
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING")
|
|||||||
|
|
||||||
### versions
|
### versions
|
||||||
set(CPACK_PACKAGE_VERSION_MAJOR "0")
|
set(CPACK_PACKAGE_VERSION_MAJOR "0")
|
||||||
set(CPACK_PACKAGE_VERSION_MINOR "3")
|
set(CPACK_PACKAGE_VERSION_MINOR "4")
|
||||||
set(CPACK_PACKAGE_VERSION_PATCH "91")
|
set(CPACK_PACKAGE_VERSION_PATCH "6")
|
||||||
set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
|
set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
|
||||||
|
|
||||||
|
|
||||||
@@ -22,16 +22,21 @@ set(CPACK_SOURCE_GENERATOR "TGZ")
|
|||||||
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]svn/;/[.]git/;.gitignore;/build/;tags;cscope.*")
|
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]svn/;/[.]git/;.gitignore;/build/;tags;cscope.*")
|
||||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
|
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
set(CPACK_GENERATOR "ZIP")
|
||||||
|
|
||||||
### nsis generator
|
### nsis generator
|
||||||
set(CPACK_GENERATOR "NSIS")
|
find_package(NSIS)
|
||||||
|
if (HAVE_NSIS)
|
||||||
|
set(CPACK_GENERATOR "${CPACK_GENERATOR};NSIS")
|
||||||
|
set(CPACK_NSIS_DISPLAY_NAME "The SSH Library")
|
||||||
|
set(CPACK_NSIS_COMPRESSOR "/SOLID zlib")
|
||||||
|
set(CPACK_NSIS_MENU_LINKS "http://www.libssh.org/" "libssh homepage")
|
||||||
|
endif (HAVE_NSIS)
|
||||||
|
endif (WIN32)
|
||||||
|
|
||||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY "libssh")
|
set(CPACK_PACKAGE_INSTALL_DIRECTORY "libssh")
|
||||||
|
|
||||||
set(CPACK_NSIS_DISPLAY_NAME "The SSH Library")
|
|
||||||
set(CPACK_NSIS_COMPRESSOR "/SOLID zlib")
|
|
||||||
set(CPACK_NSIS_MENU_LINKS "http://www.libssh.org/" "libssh homepage")
|
|
||||||
|
|
||||||
set(CPACK_PACKAGE_FILE_NAME ${APPLICATION_NAME}-${CPACK_PACKAGE_VERSION})
|
set(CPACK_PACKAGE_FILE_NAME ${APPLICATION_NAME}-${CPACK_PACKAGE_VERSION})
|
||||||
|
|
||||||
set(CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "Libraries")
|
set(CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "Libraries")
|
||||||
|
|||||||
78
ChangeLog
78
ChangeLog
@@ -1,7 +1,83 @@
|
|||||||
ChangeLog
|
ChangeLog
|
||||||
==========
|
==========
|
||||||
|
|
||||||
version 0.4 (released xxxx-xx-xx)
|
version 0.4.6 (released 2010-09-03)
|
||||||
|
* Added a cleanup function to free the ws2_32 library.
|
||||||
|
* Fixed build with gcc 3.4.
|
||||||
|
* Fixed the Windows build on Vista and newer.
|
||||||
|
* Fixed the usage of WSAPoll() on Windows.
|
||||||
|
* Fixed "@deprecated" in doxygen
|
||||||
|
* Fixed some mingw warnings.
|
||||||
|
* Fixed handling of opened channels.
|
||||||
|
* Fixed keepalive problem on older openssh servers.
|
||||||
|
* Fixed testing for big endian on Windows.
|
||||||
|
* Fixed the Windows preprocessor macros and defines.
|
||||||
|
|
||||||
|
version 0.4.5 (released 2010-07-13)
|
||||||
|
* Added option to bind a client to an ip address.
|
||||||
|
* Fixed the ssh socket polling function.
|
||||||
|
* Fixed Windows related bugs in bsd_poll().
|
||||||
|
* Fixed serveral build warnings.
|
||||||
|
|
||||||
|
version 0.4.4 (released 2010-06-01)
|
||||||
|
* Fixed a bug in the expand function for escape sequences.
|
||||||
|
* Fixed a bug in the tilde expand function.
|
||||||
|
* Fixed a bug in setting the options.
|
||||||
|
|
||||||
|
version 0.4.3 (released 2010-05-18)
|
||||||
|
* Added global/keepalive responses.
|
||||||
|
* Added runtime detection of WSAPoll().
|
||||||
|
* Added a select(2) based poll-emulation if poll(2) is not available.
|
||||||
|
* Added a function to expand an escaped string.
|
||||||
|
* Added a function to expand the tilde from a path.
|
||||||
|
* Added a proxycommand support.
|
||||||
|
* Added ssh_privatekey_type public function
|
||||||
|
* Added the possibility to define _OPENSSL_DIR and _ZLIB_DIR.
|
||||||
|
* Fixed sftp_chown.
|
||||||
|
* Fixed sftp_rename on protocol version 3.
|
||||||
|
* Fixed a blocking bug in channel_poll.
|
||||||
|
* Fixed config parsing wich has overwritten user specified values.
|
||||||
|
* Fixed hashed [host]:port format in knownhosts
|
||||||
|
* Fixed Windows build.
|
||||||
|
* Fixed doublefree happening after a negociation error.
|
||||||
|
* Fixed aes*-ctr with <= OpenSSL 0.9.7b.
|
||||||
|
* Fixed some documentation.
|
||||||
|
* Fixed exec example which has broken read usage.
|
||||||
|
* Fixed broken algorithm choice for server.
|
||||||
|
* Fixed a typo that we don't export all symbols.
|
||||||
|
* Removed the unneeded dependency to doxygen.
|
||||||
|
* Build examples only on the Linux plattform.
|
||||||
|
|
||||||
|
version 0.4.2 (released 2010-03-15)
|
||||||
|
* Added owner and group information in sftp attributes.
|
||||||
|
* Added missing SSH_OPTIONS_FD option.
|
||||||
|
* Added printout of owner and group in the sftp example.
|
||||||
|
* Added a prepend function for ssh_list.
|
||||||
|
* Added send back replies to openssh's keepalives.
|
||||||
|
* Fixed documentation in scp code
|
||||||
|
* Fixed longname parsing, this only workings with readdir.
|
||||||
|
* Fixed and added support for several identity files.
|
||||||
|
* Fixed sftp_parse_longname() on Windows.
|
||||||
|
* Fixed a race condition bug in ssh_scp_close()
|
||||||
|
* Remove config support for SSHv1 Cipher variable.
|
||||||
|
* Rename ssh_list_add to ssh_list_append.
|
||||||
|
* Rename ssh_list_get_head to ssh_list_pop_head
|
||||||
|
|
||||||
|
version 0.4.1 (released 2010-02-13)
|
||||||
|
* Added support for aes128-ctr, aes192-ctr and aes256-ctr encryption.
|
||||||
|
* Added an example for exec.
|
||||||
|
* Added private key type detection feature in privatekey_from_file().
|
||||||
|
* Fixed zlib compression fallback.
|
||||||
|
* Fixed kex bug that client preference should be prioritary
|
||||||
|
* Fixed known_hosts file set by the user.
|
||||||
|
* Fixed a memleak in channel_accept().
|
||||||
|
* Fixed underflow when leave_function() are unbalanced
|
||||||
|
* Fixed memory corruption in handle_channel_request_open().
|
||||||
|
* Fixed closing of a file handle case of errors in privatekey_from_file().
|
||||||
|
* Fixed ssh_get_user_home_dir() to be thread safe.
|
||||||
|
* Fixed the doxygen documentation.
|
||||||
|
|
||||||
|
version 0.4.0 (released 2009-12-10)
|
||||||
* Added scp support.
|
* Added scp support.
|
||||||
* Added support for sending signals (RFC 4254, section 6.9).
|
* Added support for sending signals (RFC 4254, section 6.9).
|
||||||
* Added MSVC support.
|
* Added MSVC support.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
include(CheckIncludeFile)
|
include(CheckIncludeFile)
|
||||||
|
include(CheckIncludeFiles)
|
||||||
include(CheckSymbolExists)
|
include(CheckSymbolExists)
|
||||||
include(CheckFunctionExists)
|
include(CheckFunctionExists)
|
||||||
include(CheckLibraryExists)
|
include(CheckLibraryExists)
|
||||||
@@ -16,20 +17,39 @@ set(SYSCONFDIR ${SYSCONF_INSTALL_DIR})
|
|||||||
set(BINARYDIR ${CMAKE_BINARY_DIR})
|
set(BINARYDIR ${CMAKE_BINARY_DIR})
|
||||||
set(SOURCEDIR ${CMAKE_SOURCE_DIR})
|
set(SOURCEDIR ${CMAKE_SOURCE_DIR})
|
||||||
|
|
||||||
if(CMAKE_COMPILER_IS_GNUC)
|
function(COMPILER_DUMPVERSION _OUTPUT_VERSION)
|
||||||
check_c_compiler_flag("-fvisibility=hidden" WITH_VISIBILITY_HIDDEN)
|
execute_process(
|
||||||
endif(CMAKE_COMPILER_IS_GNUC)
|
COMMAND
|
||||||
|
${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1} -dumpversion
|
||||||
|
OUTPUT_VARIABLE _COMPILER_VERSION
|
||||||
|
)
|
||||||
|
|
||||||
|
string(REGEX REPLACE "([0-9])\\.([0-9])(\\.[0-9])?" "\\1\\2"
|
||||||
|
_COMPILER_VERSION ${_COMPILER_VERSION})
|
||||||
|
|
||||||
|
set(${_OUTPUT_VERSION} ${_COMPILER_VERSION} PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
if(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW)
|
||||||
|
compiler_dumpversion(GNUCC_VERSION)
|
||||||
|
if (NOT GNUCC_VERSION EQUAL 34)
|
||||||
|
check_c_compiler_flag("-fvisibility=hidden" WITH_VISIBILITY_HIDDEN)
|
||||||
|
endif (NOT GNUCC_VERSION EQUAL 34)
|
||||||
|
endif(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW)
|
||||||
|
|
||||||
# HEADER FILES
|
# HEADER FILES
|
||||||
check_include_file(argp.h HAVE_ARGP_H)
|
check_include_file(argp.h HAVE_ARGP_H)
|
||||||
check_include_file(pty.h HAVE_PTY_H)
|
check_include_file(pty.h HAVE_PTY_H)
|
||||||
check_include_file(terminos.h HAVE_TERMIOS_H)
|
check_include_file(terminos.h HAVE_TERMIOS_H)
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
check_include_file(wspiapi.h HAVE_WSPIAPI_H)
|
check_include_files("winsock2.h;ws2tcpip.h;wspiapi.h" HAVE_WSPIAPI_H)
|
||||||
if (NOT HAVE_WSPIAPI_H)
|
if (NOT HAVE_WSPIAPI_H)
|
||||||
message(STATUS "WARNING: Without wspiapi.h, this build will only work on Windows XP and newer versions")
|
message(STATUS "WARNING: Without wspiapi.h (or dependencies), this build will only work on Windows XP and newer versions")
|
||||||
endif (NOT HAVE_WSPIAPI_H)
|
endif (NOT HAVE_WSPIAPI_H)
|
||||||
check_include_file(ws2tcpip.h HAVE_WS2TCPIP_H)
|
check_include_files("winsock2.h;ws2tcpip.h" HAVE_WS2TCPIP_H)
|
||||||
|
if (NOT HAVE_WS2TCPIP_H)
|
||||||
|
message(ERROR "WARNING: Does not have ws2tcpip.h or winsock2.h")
|
||||||
|
endif (NOT HAVE_WS2TCPIP_H)
|
||||||
if (HAVE_WSPIAPI_H OR HAVE_WS2TCPIP_H)
|
if (HAVE_WSPIAPI_H OR HAVE_WS2TCPIP_H)
|
||||||
set(HAVE_GETADDRINFO TRUE)
|
set(HAVE_GETADDRINFO TRUE)
|
||||||
set(HAVE_GETHOSTBYNAME TRUE)
|
set(HAVE_GETHOSTBYNAME TRUE)
|
||||||
@@ -49,6 +69,17 @@ check_include_file(openssl/des.h HAVE_OPENSSL_DES_H)
|
|||||||
|
|
||||||
# FUNCTIONS
|
# FUNCTIONS
|
||||||
|
|
||||||
|
check_function_exists(strncpy HAVE_STRNCPY)
|
||||||
|
check_function_exists(vsnprintf HAVE_VSNPRINTF)
|
||||||
|
check_function_exists(snprintf HAVE_SNPRINTF)
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
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)
|
||||||
|
endif (WIN32)
|
||||||
|
|
||||||
if (UNIX)
|
if (UNIX)
|
||||||
# libsocket (Solaris)
|
# libsocket (Solaris)
|
||||||
check_library_exists(socket getaddrinfo "" HAVE_LIBSOCKET)
|
check_library_exists(socket getaddrinfo "" HAVE_LIBSOCKET)
|
||||||
@@ -82,9 +113,9 @@ endif (UNIX)
|
|||||||
set(LIBSSH_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} CACHE INTERNAL "libssh required system libraries")
|
set(LIBSSH_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} CACHE INTERNAL "libssh required system libraries")
|
||||||
|
|
||||||
# LIBRARIES
|
# LIBRARIES
|
||||||
if (CRYPTO_FOUND)
|
if (OPENSSL_FOUND)
|
||||||
set(HAVE_LIBCRYPTO 1)
|
set(HAVE_LIBCRYPTO 1)
|
||||||
endif (CRYPTO_FOUND)
|
endif (OPENSSL_FOUND)
|
||||||
|
|
||||||
if (GCRYPT_FOUND)
|
if (GCRYPT_FOUND)
|
||||||
set(HAVE_LIBGCRYPT 1)
|
set(HAVE_LIBGCRYPT 1)
|
||||||
@@ -104,4 +135,6 @@ if (WITH_DEBUG_CALLTRACE)
|
|||||||
endif (WITH_DEBUG_CALLTRACE)
|
endif (WITH_DEBUG_CALLTRACE)
|
||||||
|
|
||||||
# ENDIAN
|
# ENDIAN
|
||||||
test_big_endian(WORDS_BIGENDIAN)
|
if (NOT WIN32)
|
||||||
|
test_big_endian(WORDS_BIGENDIAN)
|
||||||
|
endif (NOT WIN32)
|
||||||
|
|||||||
@@ -3,27 +3,27 @@
|
|||||||
include(CheckCCompilerFlag)
|
include(CheckCCompilerFlag)
|
||||||
|
|
||||||
if (UNIX AND NOT WIN32)
|
if (UNIX AND NOT WIN32)
|
||||||
if (CMAKE_COMPILER_IS_GNUCC)
|
if (${CMAKE_C_COMPILER_ID} MATCHES GNU)
|
||||||
# add -Wconversion ?
|
# add -Wconversion ?
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -pedantic -Wall -Wextra -Wshadow -Wmissing-prototypes -Wdeclaration-after-statement -Wunused -Wfloat-equal -Wpointer-arith -Wwrite-strings -Wformat-security -Wmissing-format-attribute")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -pedantic -Wall -Wextra -Wshadow -Wmissing-prototypes -Wdeclaration-after-statement -Wunused -Wfloat-equal -Wpointer-arith -Wwrite-strings -Wformat-security -Wmissing-format-attribute")
|
||||||
|
|
||||||
# with -fPIC
|
# with -fPIC
|
||||||
check_c_compiler_flag("-fPIC" WITH_FPIC)
|
check_c_compiler_flag("-fPIC" WITH_FPIC)
|
||||||
if (WITH_FPIC)
|
if (WITH_FPIC)
|
||||||
add_definitions(-fPIC)
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
|
||||||
endif (WITH_FPIC)
|
endif (WITH_FPIC)
|
||||||
|
|
||||||
check_c_compiler_flag("-fstack-protector" WITH_STACK_PROTECTOR)
|
check_c_compiler_flag("-fstack-protector" WITH_STACK_PROTECTOR)
|
||||||
if (WITH_STACK_PROTECTOR)
|
if (WITH_STACK_PROTECTOR)
|
||||||
add_definitions(-fstack-protector)
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector")
|
||||||
endif (WITH_STACK_PROTECTOR)
|
endif (WITH_STACK_PROTECTOR)
|
||||||
|
|
||||||
check_c_compiler_flag("-D_FORTIFY_SOURCE=2" WITH_FORTIFY_SOURCE)
|
check_c_compiler_flag("-D_FORTIFY_SOURCE=2" WITH_FORTIFY_SOURCE)
|
||||||
if (WITH_FORTIFY_SOURCE)
|
if (WITH_FORTIFY_SOURCE)
|
||||||
add_definitions(-D_FORTIFY_SOURCE=2)
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FORTIFY_SOURCE=2")
|
||||||
endif (WITH_FORTIFY_SOURCE)
|
endif (WITH_FORTIFY_SOURCE)
|
||||||
|
|
||||||
endif (CMAKE_COMPILER_IS_GNUCC)
|
endif (${CMAKE_C_COMPILER_ID} MATCHES GNU)
|
||||||
|
|
||||||
if (CMAKE_SIZEOF_VOID_P MATCHES "8")
|
if (CMAKE_SIZEOF_VOID_P MATCHES "8")
|
||||||
# with large file support
|
# with large file support
|
||||||
@@ -48,12 +48,12 @@ if (UNIX AND NOT WIN32)
|
|||||||
endif (CMAKE_SIZEOF_VOID_P MATCHES "8")
|
endif (CMAKE_SIZEOF_VOID_P MATCHES "8")
|
||||||
if (_lfs_CFLAGS)
|
if (_lfs_CFLAGS)
|
||||||
string(REGEX REPLACE "[\r\n]" " " "${_lfs_CFLAGS}" "${${_lfs_CFLAGS}}")
|
string(REGEX REPLACE "[\r\n]" " " "${_lfs_CFLAGS}" "${${_lfs_CFLAGS}}")
|
||||||
add_definitions(${_lfs_CFLAGS})
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_lfs_CFLAGS}")
|
||||||
endif (_lfs_CFLAGS)
|
endif (_lfs_CFLAGS)
|
||||||
|
|
||||||
endif (UNIX AND NOT WIN32)
|
endif (UNIX AND NOT WIN32)
|
||||||
|
|
||||||
# suppress warning about "deprecated" functions
|
# suppress warning about "deprecated" functions
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_CRT_SECURE_NO_WARNINGS")
|
||||||
endif (MSVC)
|
endif (MSVC)
|
||||||
|
|||||||
31
cmake/Modules/FindNSIS.cmake
Normal file
31
cmake/Modules/FindNSIS.cmake
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# - Try to find NSIS
|
||||||
|
# Once done this will define
|
||||||
|
#
|
||||||
|
# NSIS_FOUND - system has NSIS
|
||||||
|
# NSIS_MAKE - NSIS creator executable
|
||||||
|
#
|
||||||
|
# Copyright (c) 2010 Andreas Schneider <mail@cynapses.org>
|
||||||
|
#
|
||||||
|
# Redistribution and use is allowed according to the terms of the New
|
||||||
|
# BSD license.
|
||||||
|
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||||
|
#
|
||||||
|
|
||||||
|
if (NSIS_MAKE)
|
||||||
|
# in cache already
|
||||||
|
set(NSIS_FOUND TRUE)
|
||||||
|
elseif (NSIS_MAKE)
|
||||||
|
find_program(NSIS_MAKE
|
||||||
|
NAMES
|
||||||
|
makensis
|
||||||
|
PATHS
|
||||||
|
${_NSIS_DIR}
|
||||||
|
${_NSIS_DIR}/Bin
|
||||||
|
$ENV{PROGRAMFILES}/NSIS
|
||||||
|
)
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(NSIS DEFAULT_MSG NSIS_MAKE)
|
||||||
|
|
||||||
|
mark_as_advanced(NSIS_MAKE)
|
||||||
|
endif (NSIS_MAKE)
|
||||||
@@ -18,6 +18,10 @@ if (OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIRS)
|
|||||||
# in cache already
|
# in cache already
|
||||||
set(OPENSSL_FOUND TRUE)
|
set(OPENSSL_FOUND TRUE)
|
||||||
else (OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIRS)
|
else (OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIRS)
|
||||||
|
if (WIN32)
|
||||||
|
set(_OPENSSL_DIR $ENV{PROGRAMFILES}/OpenSSL)
|
||||||
|
endif (WIN32)
|
||||||
|
|
||||||
# use pkg-config to get the directories and then use these values
|
# use pkg-config to get the directories and then use these values
|
||||||
# in the FIND_PATH() and FIND_LIBRARY() calls
|
# in the FIND_PATH() and FIND_LIBRARY() calls
|
||||||
if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
|
if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
|
||||||
@@ -34,6 +38,7 @@ else (OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIRS)
|
|||||||
NAMES
|
NAMES
|
||||||
openssl/ssl.h
|
openssl/ssl.h
|
||||||
PATHS
|
PATHS
|
||||||
|
${_OPENSSL_DIR}/include
|
||||||
${_OPENSSL_INCLUDEDIR}
|
${_OPENSSL_INCLUDEDIR}
|
||||||
/usr/include
|
/usr/include
|
||||||
/usr/local/include
|
/usr/local/include
|
||||||
@@ -49,6 +54,7 @@ else (OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIRS)
|
|||||||
ssl
|
ssl
|
||||||
libssl
|
libssl
|
||||||
PATHS
|
PATHS
|
||||||
|
${_OPENSSL_DIR}/lib
|
||||||
${_OPENSSL_LIBDIR}
|
${_OPENSSL_LIBDIR}
|
||||||
/usr/lib
|
/usr/lib
|
||||||
/usr/local/lib
|
/usr/local/lib
|
||||||
@@ -64,6 +70,7 @@ else (OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIRS)
|
|||||||
NAMES
|
NAMES
|
||||||
ssleay32
|
ssleay32
|
||||||
PATHS
|
PATHS
|
||||||
|
${_OPENSSL_DIR}/lib
|
||||||
${_OPENSSL_LIBDIR}
|
${_OPENSSL_LIBDIR}
|
||||||
/usr/lib
|
/usr/lib
|
||||||
/usr/local/lib
|
/usr/local/lib
|
||||||
@@ -79,6 +86,7 @@ else (OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIRS)
|
|||||||
NAMES
|
NAMES
|
||||||
ssleay32MD
|
ssleay32MD
|
||||||
PATHS
|
PATHS
|
||||||
|
${_OPENSSL_DIR}/lib
|
||||||
${_OPENSSL_LIBDIR}
|
${_OPENSSL_LIBDIR}
|
||||||
/usr/lib
|
/usr/lib
|
||||||
/usr/local/lib
|
/usr/local/lib
|
||||||
@@ -99,6 +107,7 @@ else (OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIRS)
|
|||||||
libeay
|
libeay
|
||||||
libeay32
|
libeay32
|
||||||
PATHS
|
PATHS
|
||||||
|
${_OPENSSL_DIR}/lib
|
||||||
${_OPENSSL_LIBDIR}
|
${_OPENSSL_LIBDIR}
|
||||||
/lib
|
/lib
|
||||||
/usr/lib
|
/usr/lib
|
||||||
|
|||||||
@@ -18,11 +18,15 @@ if (ZLIB_LIBRARIES AND ZLIB_INCLUDE_DIRS)
|
|||||||
# in cache already
|
# in cache already
|
||||||
set(ZLIB_FOUND TRUE)
|
set(ZLIB_FOUND TRUE)
|
||||||
else (ZLIB_LIBRARIES AND ZLIB_INCLUDE_DIRS)
|
else (ZLIB_LIBRARIES AND ZLIB_INCLUDE_DIRS)
|
||||||
|
if (WIN32)
|
||||||
|
set(_ZLIB_DIR $ENV{PROGRAMFILES}/GnuWin32)
|
||||||
|
endif (WIN32)
|
||||||
|
|
||||||
find_path(ZLIB_INCLUDE_DIR
|
find_path(ZLIB_INCLUDE_DIR
|
||||||
NAMES
|
NAMES
|
||||||
zlib.h
|
zlib.h
|
||||||
PATHS
|
PATHS
|
||||||
|
${_ZLIB_DIR}/include
|
||||||
/usr/include
|
/usr/include
|
||||||
/usr/local/include
|
/usr/local/include
|
||||||
/opt/local/include
|
/opt/local/include
|
||||||
@@ -36,6 +40,7 @@ else (ZLIB_LIBRARIES AND ZLIB_INCLUDE_DIRS)
|
|||||||
zlib
|
zlib
|
||||||
zlib1
|
zlib1
|
||||||
PATHS
|
PATHS
|
||||||
|
${_ZLIB_DIR}/lib
|
||||||
/usr/lib
|
/usr/lib
|
||||||
/usr/local/lib
|
/usr/local/lib
|
||||||
/opt/local/lib
|
/opt/local/lib
|
||||||
|
|||||||
@@ -1,127 +1,100 @@
|
|||||||
# -helper macro to add a "doc" target with CMake build system.
|
# - Run Doxygen
|
||||||
# and configure doxy.config.in to doxy.config
|
|
||||||
#
|
#
|
||||||
# target "doc" allows building the documentation with doxygen/dot on WIN32 and Linux
|
# Adds a doxygen target that runs doxygen to generate the html
|
||||||
# Creates .chm windows help file if MS HTML help workshop
|
# and optionally the LaTeX API documentation.
|
||||||
# (available from http://msdn.microsoft.com/workshop/author/htmlhelp)
|
# The doxygen target is added to the doc target as dependency.
|
||||||
# is installed with its DLLs in PATH.
|
# i.e.: the API documentation is built with:
|
||||||
|
# make doc
|
||||||
|
#
|
||||||
|
# USAGE: INCLUDE IN PROJECT
|
||||||
|
#
|
||||||
|
# set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
# include(UseDoxygen)
|
||||||
|
# Add the Doxyfile.in and UseDoxygen.cmake files to the projects source directory.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Please note, that the tools, e.g.:
|
# Variables you may define are:
|
||||||
# doxygen, dot, latex, dvips, makeindex, gswin32, etc.
|
# DOXYFILE_OUTPUT_DIR - Path where the Doxygen output is stored. Defaults to "doc".
|
||||||
# must be in path.
|
|
||||||
#
|
#
|
||||||
# Note about Visual Studio Projects:
|
# DOXYFILE_LATEX_DIR - Directory where the Doxygen LaTeX output is stored. Defaults to "latex".
|
||||||
# MSVS has its own path environment which may differ from the shell.
|
#
|
||||||
# See "Menu Tools/Options/Projects/VC++ Directories" in VS 7.1
|
# DOXYFILE_HTML_DIR - Directory where the Doxygen html output is stored. Defaults to "html".
|
||||||
#
|
#
|
||||||
# author Jan Woetzel 2004-2006
|
|
||||||
# www.mip.informatik.uni-kiel.de/~jw
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2009-2010 Tobias Rautenkranz <tobias@rautenkranz.ch>
|
||||||
|
# Copyright (c) 2010 Andreas Schneider <mail@cynapses.org>
|
||||||
|
#
|
||||||
|
# Redistribution and use is allowed according to the terms of the New
|
||||||
|
# BSD license.
|
||||||
|
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||||
|
#
|
||||||
|
|
||||||
FIND_PACKAGE(Doxygen)
|
macro(usedoxygen_set_default name value)
|
||||||
|
if(NOT DEFINED "${name}")
|
||||||
|
set("${name}" "${value}")
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
IF (DOXYGEN_FOUND)
|
find_package(Doxygen)
|
||||||
|
|
||||||
# click+jump in Emacs and Visual Studio (for doxy.config) (jw)
|
if(DOXYGEN_FOUND)
|
||||||
IF (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)")
|
find_file(DOXYFILE_IN
|
||||||
SET(DOXY_WARN_FORMAT "\"$file($line) : $text \"")
|
NAMES
|
||||||
ELSE (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)")
|
doxy.config.in
|
||||||
SET(DOXY_WARN_FORMAT "\"$file:$line: $text \"")
|
PATHS
|
||||||
ENDIF (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)")
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
${CMAKE_ROOT}/Modules/
|
||||||
|
NO_DEFAULT_PATH)
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(DOXYFILE_IN DEFAULT_MSG "DOXYFILE_IN")
|
||||||
|
endif()
|
||||||
|
|
||||||
# we need latex for doxygen because of the formulas
|
if(DOXYGEN_FOUND AND DOXYFILE_IN_FOUND)
|
||||||
FIND_PACKAGE(LATEX)
|
add_custom_target(doxygen ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxy.config)
|
||||||
IF (NOT LATEX_COMPILER)
|
|
||||||
MESSAGE(STATUS "latex command LATEX_COMPILER not found but usually required. You will probably get warnings and user inetraction on doxy run.")
|
|
||||||
ENDIF (NOT LATEX_COMPILER)
|
|
||||||
IF (NOT MAKEINDEX_COMPILER)
|
|
||||||
MESSAGE(STATUS "makeindex command MAKEINDEX_COMPILER not found but usually required.")
|
|
||||||
ENDIF (NOT MAKEINDEX_COMPILER)
|
|
||||||
IF (NOT DVIPS_CONVERTER)
|
|
||||||
MESSAGE(STATUS "dvips command DVIPS_CONVERTER not found but usually required.")
|
|
||||||
ENDIF (NOT DVIPS_CONVERTER)
|
|
||||||
FIND_PROGRAM(DOXYGEN_DOT_EXECUTABLE_PATH NAMES dot)
|
|
||||||
IF (DOXYGEN_DOT_EXECUTABLE_PATH)
|
|
||||||
SET(DOXYGEN_DOT_FOUND "YES")
|
|
||||||
ENDIF (DOXYGEN_DOT_EXECUTABLE_PATH)
|
|
||||||
|
|
||||||
IF (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config.in")
|
usedoxygen_set_default(DOXYFILE_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}")
|
||||||
MESSAGE(STATUS "Generate ${CMAKE_CURRENT_BINARY_DIR}/doxy.config from doxy.config.in")
|
usedoxygen_set_default(DOXYFILE_HTML_DIR "html")
|
||||||
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/doxy.config.in
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/doxy.config
|
|
||||||
@ONLY )
|
|
||||||
# use (configured) doxy.config from (out of place) BUILD tree:
|
|
||||||
SET(DOXY_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/doxy.config")
|
|
||||||
ELSE (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config.in")
|
|
||||||
# use static hand-edited doxy.config from SOURCE tree:
|
|
||||||
SET(DOXY_CONFIG "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config")
|
|
||||||
IF (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config")
|
|
||||||
MESSAGE(STATUS "WARNING: using existing ${CMAKE_CURRENT_SOURCE_DIR}/doxy.config instead of configuring from doxy.config.in file.")
|
|
||||||
ELSE (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config")
|
|
||||||
IF (EXISTS "${CMAKE_MODULE_PATH}/doxy.config.in")
|
|
||||||
# using template doxy.config.in
|
|
||||||
MESSAGE(STATUS "Generate ${CMAKE_CURRENT_BINARY_DIR}/doxy.config from doxy.config.in")
|
|
||||||
CONFIGURE_FILE(${CMAKE_MODULE_PATH}/doxy.config.in
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/doxy.config
|
|
||||||
@ONLY )
|
|
||||||
SET(DOXY_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/doxy.config")
|
|
||||||
ELSE (EXISTS "${CMAKE_MODULE_PATH}/doxy.config.in")
|
|
||||||
# failed completely...
|
|
||||||
MESSAGE(SEND_ERROR "Please create ${CMAKE_CURRENT_SOURCE_DIR}/doxy.config.in (or doxy.config as fallback)")
|
|
||||||
ENDIF(EXISTS "${CMAKE_MODULE_PATH}/doxy.config.in")
|
|
||||||
|
|
||||||
ENDIF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config")
|
set_property(DIRECTORY APPEND PROPERTY
|
||||||
ENDIF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config.in")
|
ADDITIONAL_MAKE_CLEAN_FILES "${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_HTML_DIR}")
|
||||||
|
|
||||||
ADD_CUSTOM_TARGET(doc ${DOXYGEN_EXECUTABLE} ${DOXY_CONFIG} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/doxy.config)
|
set(DOXYFILE_LATEX FALSE)
|
||||||
|
set(DOXYFILE_PDFLATEX FALSE)
|
||||||
|
set(DOXYFILE_DOT FALSE)
|
||||||
|
|
||||||
# create a windows help .chm file using hhc.exe
|
find_package(LATEX)
|
||||||
# HTMLHelp DLL must be in path!
|
if(LATEX_COMPILER AND MAKEINDEX_COMPILER)
|
||||||
# fallback: use hhw.exe interactively
|
set(DOXYFILE_LATEX TRUE)
|
||||||
IF (WIN32)
|
usedoxygen_set_default(DOXYFILE_LATEX_DIR "latex")
|
||||||
FIND_PACKAGE(HTMLHelp)
|
|
||||||
IF (HTML_HELP_COMPILER)
|
|
||||||
SET (TMP "${CMAKE_CURRENT_BINARY_DIR}\\doc\\html\\index.hhp")
|
|
||||||
STRING(REGEX REPLACE "[/]" "\\\\" HHP_FILE ${TMP} )
|
|
||||||
# MESSAGE(SEND_ERROR "DBG HHP_FILE=${HHP_FILE}")
|
|
||||||
ADD_CUSTOM_TARGET(winhelp ${HTML_HELP_COMPILER} ${HHP_FILE})
|
|
||||||
ADD_DEPENDENCIES (winhelp doc)
|
|
||||||
|
|
||||||
IF (NOT TARGET_DOC_SKIP_INSTALL)
|
|
||||||
# install windows help?
|
|
||||||
# determine useful name for output file
|
|
||||||
# should be project and version unique to allow installing
|
|
||||||
# multiple projects into one global directory
|
|
||||||
IF (EXISTS "${PROJECT_BINARY_DIR}/doc/html/index.chm")
|
|
||||||
IF (PROJECT_NAME)
|
|
||||||
SET(OUT "${PROJECT_NAME}")
|
|
||||||
ELSE (PROJECT_NAME)
|
|
||||||
SET(OUT "Documentation") # default
|
|
||||||
ENDIF(PROJECT_NAME)
|
|
||||||
IF (${PROJECT_NAME}_VERSION_MAJOR)
|
|
||||||
SET(OUT "${OUT}-${${PROJECT_NAME}_VERSION_MAJOR}")
|
|
||||||
IF (${PROJECT_NAME}_VERSION_MINOR)
|
|
||||||
SET(OUT "${OUT}.${${PROJECT_NAME}_VERSION_MINOR}")
|
|
||||||
IF (${PROJECT_NAME}_VERSION_PATCH)
|
|
||||||
SET(OUT "${OUT}.${${PROJECT_NAME}_VERSION_PATCH}")
|
|
||||||
ENDIF(${PROJECT_NAME}_VERSION_PATCH)
|
|
||||||
ENDIF(${PROJECT_NAME}_VERSION_MINOR)
|
|
||||||
ENDIF(${PROJECT_NAME}_VERSION_MAJOR)
|
|
||||||
# keep suffix
|
|
||||||
SET(OUT "${OUT}.chm")
|
|
||||||
|
|
||||||
#MESSAGE("DBG ${PROJECT_BINARY_DIR}/doc/html/index.chm \n${OUT}")
|
|
||||||
# create target used by install and package commands
|
|
||||||
INSTALL(FILES "${PROJECT_BINARY_DIR}/doc/html/index.chm"
|
|
||||||
DESTINATION "doc"
|
|
||||||
RENAME "${OUT}"
|
|
||||||
)
|
|
||||||
ENDIF(EXISTS "${PROJECT_BINARY_DIR}/doc/html/index.chm")
|
|
||||||
ENDIF(NOT TARGET_DOC_SKIP_INSTALL)
|
|
||||||
|
|
||||||
ENDIF(HTML_HELP_COMPILER)
|
set_property(DIRECTORY APPEND PROPERTY
|
||||||
# MESSAGE(SEND_ERROR "HTML_HELP_COMPILER=${HTML_HELP_COMPILER}")
|
ADDITIONAL_MAKE_CLEAN_FILES
|
||||||
ENDIF (WIN32)
|
"${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}")
|
||||||
ENDIF(DOXYGEN_FOUND)
|
|
||||||
|
|
||||||
|
if(PDFLATEX_COMPILER)
|
||||||
|
set(DOXYFILE_PDFLATEX TRUE)
|
||||||
|
endif()
|
||||||
|
if(DOXYGEN_DOT_EXECUTABLE)
|
||||||
|
set(DOXYFILE_DOT TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_custom_command(TARGET doxygen
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND ${CMAKE_MAKE_PROGRAM}
|
||||||
|
WORKING_DIRECTORY "${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
configure_file(${DOXYFILE_IN} ${CMAKE_CURRENT_BINARY_DIR}/doxy.config ESCAPE_QUOTES IMMEDIATE @ONLY)
|
||||||
|
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/doxy.trac.in)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doxy.trac.in ${CMAKE_CURRENT_BINARY_DIR}/doxy.trac ESCAPE_QUOTES IMMEDIATE @ONLY)
|
||||||
|
add_custom_target(doxygen-trac ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxy.trac)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
get_target_property(DOC_TARGET doc TYPE)
|
||||||
|
if(NOT DOC_TARGET)
|
||||||
|
add_custom_target(doc)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_dependencies(doc doxygen)
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -37,6 +37,37 @@
|
|||||||
|
|
||||||
/*************************** FUNCTIONS ***************************/
|
/*************************** FUNCTIONS ***************************/
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `snprintf' function. */
|
||||||
|
#cmakedefine HAVE_SNPRINTF 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `_snprintf' function. */
|
||||||
|
#cmakedefine HAVE__SNPRINTF 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `_snprintf_s' function. */
|
||||||
|
#cmakedefine HAVE__SNPRINTF_S 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `vsnprintf' function. */
|
||||||
|
#cmakedefine HAVE_VSNPRINTF 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `_vsnprintf' function. */
|
||||||
|
#cmakedefine HAVE__VSNPRINTF 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `_vsnprintf_s' function. */
|
||||||
|
#cmakedefine HAVE__VSNPRINTF_S 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `snprintf' function. */
|
||||||
|
#cmakedefine HAVE_SNPRINTF 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `_snprintf' function. */
|
||||||
|
#cmakedefine HAVE__SNPRINTF 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `_snprintf_s' function. */
|
||||||
|
#cmakedefine HAVE__SNPRINTF_S 1
|
||||||
|
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `strncpy' function. */
|
||||||
|
#cmakedefine HAVE_STRNCPY 1
|
||||||
|
|
||||||
/* Define to 1 if you have the `cfmakeraw' function. */
|
/* Define to 1 if you have the `cfmakeraw' function. */
|
||||||
#cmakedefine HAVE_CFMAKERAW 1
|
#cmakedefine HAVE_CFMAKERAW 1
|
||||||
|
|
||||||
@@ -94,17 +125,3 @@
|
|||||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||||
#cmakedefine WORDS_BIGENDIAN 1
|
#cmakedefine WORDS_BIGENDIAN 1
|
||||||
|
|
||||||
/************************* MS Windows ***************************/
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
# ifdef _MSC_VER
|
|
||||||
/* On Microsoft compilers define inline to __inline on all others use inline */
|
|
||||||
# undef inline
|
|
||||||
# define inline __inline
|
|
||||||
|
|
||||||
# undef strdup
|
|
||||||
# define strdup _strdup
|
|
||||||
# endif // _MSC_VER
|
|
||||||
#endif /* _WIN32 */
|
|
||||||
|
|
||||||
|
|||||||
1
doc/TracFooter.html
Normal file
1
doc/TracFooter.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<!-- Doxygen TracFooter -->
|
||||||
4
doc/TracHeader.html
Normal file
4
doc/TracHeader.html
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<!-- Doxygen TracHeader -->
|
||||||
|
<style>@import url(/chrome/site/doxygen.css);</style>
|
||||||
|
<style>@import url(/chrome/site/tabs.css);</style>
|
||||||
|
<!-- /Doxygen TracHeader -->
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Doxyfile 1.5.8
|
# Doxyfile 1.5.6
|
||||||
|
|
||||||
# This file describes the settings to be used by the documentation system
|
# This file describes the settings to be used by the documentation system
|
||||||
# doxygen (www.doxygen.org) for a project
|
# doxygen (www.doxygen.org) for a project
|
||||||
@@ -57,8 +57,8 @@ CREATE_SUBDIRS = NO
|
|||||||
# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek,
|
# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek,
|
||||||
# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages),
|
# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages),
|
||||||
# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish,
|
# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish,
|
||||||
# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene,
|
# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish,
|
||||||
# Spanish, Swedish, and Ukrainian.
|
# and Ukrainian.
|
||||||
|
|
||||||
OUTPUT_LANGUAGE = English
|
OUTPUT_LANGUAGE = English
|
||||||
|
|
||||||
@@ -165,6 +165,13 @@ QT_AUTOBRIEF = NO
|
|||||||
|
|
||||||
MULTILINE_CPP_IS_BRIEF = NO
|
MULTILINE_CPP_IS_BRIEF = NO
|
||||||
|
|
||||||
|
# If the DETAILS_AT_TOP tag is set to YES then Doxygen
|
||||||
|
# will output the detailed description near the top, like JavaDoc.
|
||||||
|
# If set to NO, the detailed description appears after the member
|
||||||
|
# documentation.
|
||||||
|
|
||||||
|
DETAILS_AT_TOP = YES
|
||||||
|
|
||||||
# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
|
# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
|
||||||
# member inherits the documentation from any documented member that it
|
# member inherits the documentation from any documented member that it
|
||||||
# re-implements.
|
# re-implements.
|
||||||
@@ -217,17 +224,6 @@ OPTIMIZE_FOR_FORTRAN = NO
|
|||||||
|
|
||||||
OPTIMIZE_OUTPUT_VHDL = NO
|
OPTIMIZE_OUTPUT_VHDL = NO
|
||||||
|
|
||||||
# Doxygen selects the parser to use depending on the extension of the files it parses.
|
|
||||||
# With this tag you can assign which parser to use for a given extension.
|
|
||||||
# Doxygen has a built-in mapping, but you can override or extend it using this tag.
|
|
||||||
# The format is ext=language, where ext is a file extension, and language is one of
|
|
||||||
# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
|
|
||||||
# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
|
|
||||||
# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
|
|
||||||
# use: inc=Fortran f=C
|
|
||||||
|
|
||||||
EXTENSION_MAPPING =
|
|
||||||
|
|
||||||
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
|
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
|
||||||
# to include (a tag file for) the STL sources as input, then you should
|
# to include (a tag file for) the STL sources as input, then you should
|
||||||
# set this tag to YES in order to let doxygen match functions declarations and
|
# set this tag to YES in order to let doxygen match functions declarations and
|
||||||
@@ -237,7 +233,7 @@ EXTENSION_MAPPING =
|
|||||||
|
|
||||||
BUILTIN_STL_SUPPORT = NO
|
BUILTIN_STL_SUPPORT = NO
|
||||||
|
|
||||||
# If you use Microsoft's C++/CLI language, you should set this option to YES to
|
# If you use Microsoft's C++/CLI language, you should set this option to YES to
|
||||||
# enable parsing support.
|
# enable parsing support.
|
||||||
|
|
||||||
CPP_CLI_SUPPORT = NO
|
CPP_CLI_SUPPORT = NO
|
||||||
@@ -280,23 +276,7 @@ SUBGROUPING = YES
|
|||||||
# be useful for C code in case the coding convention dictates that all compound
|
# be useful for C code in case the coding convention dictates that all compound
|
||||||
# types are typedef'ed and only the typedef is referenced, never the tag name.
|
# types are typedef'ed and only the typedef is referenced, never the tag name.
|
||||||
|
|
||||||
TYPEDEF_HIDES_STRUCT = NO
|
TYPEDEF_HIDES_STRUCT = YES
|
||||||
|
|
||||||
# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
|
|
||||||
# determine which symbols to keep in memory and which to flush to disk.
|
|
||||||
# When the cache is full, less often used symbols will be written to disk.
|
|
||||||
# For small to medium size projects (<1000 input files) the default value is
|
|
||||||
# probably good enough. For larger projects a too small cache size can cause
|
|
||||||
# doxygen to be busy swapping symbols to and from disk most of the time
|
|
||||||
# causing a significant performance penality.
|
|
||||||
# If the system has enough physical memory increasing the cache will improve the
|
|
||||||
# performance by keeping more symbols in memory. Note that the value works on
|
|
||||||
# a logarithmic scale so increasing the size by one will rougly double the
|
|
||||||
# memory usage. The cache size is given by this formula:
|
|
||||||
# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
|
|
||||||
# corresponding to a cache size of 2^16 = 65536 symbols
|
|
||||||
|
|
||||||
SYMBOL_CACHE_SIZE = 0
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# Build related configuration options
|
# Build related configuration options
|
||||||
@@ -425,7 +405,7 @@ SORT_GROUP_NAMES = NO
|
|||||||
# sorted by fully-qualified names, including namespaces. If set to
|
# sorted by fully-qualified names, including namespaces. If set to
|
||||||
# NO (the default), the class list will be sorted only by class name,
|
# NO (the default), the class list will be sorted only by class name,
|
||||||
# not including the namespace part.
|
# not including the namespace part.
|
||||||
# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
|
# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
|
||||||
# Note: This option applies only to the class list, not to the
|
# Note: This option applies only to the class list, not to the
|
||||||
# alphabetical list.
|
# alphabetical list.
|
||||||
|
|
||||||
@@ -482,15 +462,14 @@ SHOW_USED_FILES = YES
|
|||||||
|
|
||||||
SHOW_DIRECTORIES = NO
|
SHOW_DIRECTORIES = NO
|
||||||
|
|
||||||
# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
|
# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
|
||||||
# This will remove the Files entry from the Quick Index and from the
|
# This will remove the Files entry from the Quick Index and from the
|
||||||
# Folder Tree View (if specified). The default is YES.
|
# Folder Tree View (if specified). The default is YES.
|
||||||
|
|
||||||
SHOW_FILES = YES
|
SHOW_FILES = YES
|
||||||
|
|
||||||
# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
|
# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
|
||||||
# Namespaces page.
|
# Namespaces page. This will remove the Namespaces entry from the Quick Index
|
||||||
# This will remove the Namespaces entry from the Quick Index
|
|
||||||
# and from the Folder Tree View (if specified). The default is YES.
|
# and from the Folder Tree View (if specified). The default is YES.
|
||||||
|
|
||||||
SHOW_NAMESPACES = YES
|
SHOW_NAMESPACES = YES
|
||||||
@@ -505,15 +484,6 @@ SHOW_NAMESPACES = YES
|
|||||||
|
|
||||||
FILE_VERSION_FILTER =
|
FILE_VERSION_FILTER =
|
||||||
|
|
||||||
# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
|
|
||||||
# doxygen. The layout file controls the global structure of the generated output files
|
|
||||||
# in an output format independent way. The create the layout file that represents
|
|
||||||
# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
|
|
||||||
# file name after the option, if omitted DoxygenLayout.xml will be used as the name
|
|
||||||
# of the layout file.
|
|
||||||
|
|
||||||
LAYOUT_FILE =
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# configuration options related to warning and progress messages
|
# configuration options related to warning and progress messages
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
@@ -575,7 +545,8 @@ WARN_LOGFILE = @CMAKE_CURRENT_BINARY_DIR@/doxy.log
|
|||||||
# with spaces.
|
# with spaces.
|
||||||
|
|
||||||
INPUT = @CMAKE_SOURCE_DIR@/include \
|
INPUT = @CMAKE_SOURCE_DIR@/include \
|
||||||
@CMAKE_SOURCE_DIR@/libssh
|
@CMAKE_SOURCE_DIR@/libssh \
|
||||||
|
@CMAKE_SOURCE_DIR@/doc
|
||||||
|
|
||||||
# This tag can be used to specify the character encoding of the source files
|
# This tag can be used to specify the character encoding of the source files
|
||||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
|
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
|
||||||
@@ -642,18 +613,15 @@ EXCLUDE_SYMBOLS =
|
|||||||
# directories that contain example code fragments that are included (see
|
# directories that contain example code fragments that are included (see
|
||||||
# the \include command).
|
# the \include command).
|
||||||
|
|
||||||
EXAMPLE_PATH = @CMAKE_SOURCE_DIR@/tests \
|
EXAMPLE_PATH = @CMAKE_SOURCE_DIR@/examples
|
||||||
@CMAKE_SOURCE_DIR@
|
|
||||||
|
|
||||||
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
|
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
|
||||||
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
|
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
|
||||||
# and *.h) to filter out the source-files in the directories. If left
|
# and *.h) to filter out the source-files in the directories. If left
|
||||||
# blank all files are included.
|
# blank all files are included.
|
||||||
|
|
||||||
EXAMPLE_PATTERNS = *.cpp \
|
EXAMPLE_PATTERNS = *.c \
|
||||||
*.cc \
|
|
||||||
*.h \
|
*.h \
|
||||||
*.hh \
|
|
||||||
INSTALL \
|
INSTALL \
|
||||||
DEPENDENCIES \
|
DEPENDENCIES \
|
||||||
CHANGELOG \
|
CHANGELOG \
|
||||||
@@ -678,17 +646,14 @@ IMAGE_PATH =
|
|||||||
# by executing (via popen()) the command <filter> <input-file>, where <filter>
|
# by executing (via popen()) the command <filter> <input-file>, where <filter>
|
||||||
# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
|
# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
|
||||||
# input file. Doxygen will then use the output that the filter program writes
|
# input file. Doxygen will then use the output that the filter program writes
|
||||||
# to standard output.
|
# to standard output. If FILTER_PATTERNS is specified, this tag will be
|
||||||
# If FILTER_PATTERNS is specified, this tag will be
|
|
||||||
# ignored.
|
# ignored.
|
||||||
|
|
||||||
INPUT_FILTER =
|
INPUT_FILTER =
|
||||||
|
|
||||||
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
|
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
|
||||||
# basis.
|
# basis. Doxygen will compare the file name with each pattern and apply the
|
||||||
# Doxygen will compare the file name with each pattern and apply the
|
# filter if there is a match. The filters are a list of the form:
|
||||||
# filter if there is a match.
|
|
||||||
# The filters are a list of the form:
|
|
||||||
# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
|
# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
|
||||||
# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
|
# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
|
||||||
# is applied to all files.
|
# is applied to all files.
|
||||||
@@ -735,11 +700,10 @@ REFERENCED_BY_RELATION = YES
|
|||||||
|
|
||||||
REFERENCES_RELATION = YES
|
REFERENCES_RELATION = YES
|
||||||
|
|
||||||
# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
|
# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
|
||||||
# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
|
# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
|
||||||
# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
|
# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
|
||||||
# link to the source code.
|
# link to the source code. Otherwise they will link to the documentstion.
|
||||||
# Otherwise they will link to the documentation.
|
|
||||||
|
|
||||||
REFERENCES_LINK_SOURCE = YES
|
REFERENCES_LINK_SOURCE = YES
|
||||||
|
|
||||||
@@ -828,13 +792,12 @@ HTML_STYLESHEET =
|
|||||||
|
|
||||||
HTML_ALIGN_MEMBERS = YES
|
HTML_ALIGN_MEMBERS = YES
|
||||||
|
|
||||||
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
|
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
|
||||||
# documentation will contain sections that can be hidden and shown after the
|
# will be generated that can be used as input for tools like the
|
||||||
# page has loaded. For this to work a browser that supports
|
# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
|
||||||
# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
|
# of the generated HTML documentation.
|
||||||
# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
|
|
||||||
|
|
||||||
HTML_DYNAMIC_SECTIONS = NO
|
GENERATE_HTMLHELP = NO
|
||||||
|
|
||||||
# If the GENERATE_DOCSET tag is set to YES, additional index files
|
# If the GENERATE_DOCSET tag is set to YES, additional index files
|
||||||
# will be generated that can be used as input for Apple's Xcode 3
|
# will be generated that can be used as input for Apple's Xcode 3
|
||||||
@@ -843,8 +806,7 @@ HTML_DYNAMIC_SECTIONS = NO
|
|||||||
# HTML output directory. Running make will produce the docset in that
|
# HTML output directory. Running make will produce the docset in that
|
||||||
# directory and running "make install" will install the docset in
|
# directory and running "make install" will install the docset in
|
||||||
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
|
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
|
||||||
# it at startup.
|
# it at startup.
|
||||||
# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
|
|
||||||
|
|
||||||
GENERATE_DOCSET = NO
|
GENERATE_DOCSET = NO
|
||||||
|
|
||||||
@@ -862,12 +824,13 @@ DOCSET_FEEDNAME = "Doxygen generated docs"
|
|||||||
|
|
||||||
DOCSET_BUNDLE_ID = org.doxygen.Project
|
DOCSET_BUNDLE_ID = org.doxygen.Project
|
||||||
|
|
||||||
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
|
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
|
||||||
# will be generated that can be used as input for tools like the
|
# documentation will contain sections that can be hidden and shown after the
|
||||||
# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
|
# page has loaded. For this to work a browser that supports
|
||||||
# of the generated HTML documentation.
|
# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
|
||||||
|
# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
|
||||||
|
|
||||||
GENERATE_HTMLHELP = NO
|
HTML_DYNAMIC_SECTIONS = NO
|
||||||
|
|
||||||
# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
|
# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
|
||||||
# be used to specify the file name of the resulting .chm file. You
|
# be used to specify the file name of the resulting .chm file. You
|
||||||
@@ -889,8 +852,8 @@ HHC_LOCATION =
|
|||||||
|
|
||||||
GENERATE_CHI = NO
|
GENERATE_CHI = NO
|
||||||
|
|
||||||
# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
|
# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
|
||||||
# is used to encode HtmlHelp index (hhk), content (hhc) and project file
|
# is used to encode HtmlHelp index (hhk), content (hhc) and project file
|
||||||
# content.
|
# content.
|
||||||
|
|
||||||
CHM_INDEX_ENCODING =
|
CHM_INDEX_ENCODING =
|
||||||
@@ -906,55 +869,6 @@ BINARY_TOC = NO
|
|||||||
|
|
||||||
TOC_EXPAND = NO
|
TOC_EXPAND = NO
|
||||||
|
|
||||||
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
|
|
||||||
# are set, an additional index file will be generated that can be used as input for
|
|
||||||
# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
|
|
||||||
# HTML documentation.
|
|
||||||
|
|
||||||
GENERATE_QHP = NO
|
|
||||||
|
|
||||||
# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
|
|
||||||
# be used to specify the file name of the resulting .qch file.
|
|
||||||
# The path specified is relative to the HTML output folder.
|
|
||||||
|
|
||||||
QCH_FILE =
|
|
||||||
|
|
||||||
# The QHP_NAMESPACE tag specifies the namespace to use when generating
|
|
||||||
# Qt Help Project output. For more information please see
|
|
||||||
# http://doc.trolltech.com/qthelpproject.html#namespace
|
|
||||||
|
|
||||||
QHP_NAMESPACE =
|
|
||||||
|
|
||||||
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
|
|
||||||
# Qt Help Project output. For more information please see
|
|
||||||
# http://doc.trolltech.com/qthelpproject.html#virtual-folders
|
|
||||||
|
|
||||||
QHP_VIRTUAL_FOLDER = doc
|
|
||||||
|
|
||||||
# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
|
|
||||||
# For more information please see
|
|
||||||
# http://doc.trolltech.com/qthelpproject.html#custom-filters
|
|
||||||
|
|
||||||
QHP_CUST_FILTER_NAME =
|
|
||||||
|
|
||||||
# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
|
|
||||||
# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
|
|
||||||
|
|
||||||
QHP_CUST_FILTER_ATTRS =
|
|
||||||
|
|
||||||
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
|
|
||||||
# filter section matches.
|
|
||||||
# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
|
|
||||||
|
|
||||||
QHP_SECT_FILTER_ATTRS =
|
|
||||||
|
|
||||||
# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
|
|
||||||
# be used to specify the location of Qt's qhelpgenerator.
|
|
||||||
# If non-empty doxygen will try to run qhelpgenerator on the generated
|
|
||||||
# .qhp file.
|
|
||||||
|
|
||||||
QHG_LOCATION =
|
|
||||||
|
|
||||||
# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
|
# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
|
||||||
# top of each HTML page. The value NO (the default) enables the index and
|
# top of each HTML page. The value NO (the default) enables the index and
|
||||||
# the value YES disables it.
|
# the value YES disables it.
|
||||||
@@ -966,19 +880,19 @@ DISABLE_INDEX = NO
|
|||||||
|
|
||||||
ENUM_VALUES_PER_LINE = 4
|
ENUM_VALUES_PER_LINE = 4
|
||||||
|
|
||||||
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
|
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
|
||||||
# structure should be generated to display hierarchical information.
|
# structure should be generated to display hierarchical information.
|
||||||
# If the tag value is set to FRAME, a side panel will be generated
|
# If the tag value is set to FRAME, a side panel will be generated
|
||||||
# containing a tree-like index structure (just like the one that
|
# containing a tree-like index structure (just like the one that
|
||||||
# is generated for HTML Help). For this to work a browser that supports
|
# is generated for HTML Help). For this to work a browser that supports
|
||||||
# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
|
# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
|
||||||
# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
|
# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
|
||||||
# probably better off using the HTML help feature. Other possible values
|
# probably better off using the HTML help feature. Other possible values
|
||||||
# for this tag are: HIERARCHIES, which will generate the Groups, Directories,
|
# for this tag are: HIERARCHIES, which will generate the Groups, Directories,
|
||||||
# and Class Hierarchy pages using a tree view instead of an ordered list;
|
# and Class Hiererachy pages using a tree view instead of an ordered list;
|
||||||
# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which
|
# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which
|
||||||
# disables this behavior completely. For backwards compatibility with previous
|
# disables this behavior completely. For backwards compatibility with previous
|
||||||
# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE
|
# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE
|
||||||
# respectively.
|
# respectively.
|
||||||
|
|
||||||
GENERATE_TREEVIEW = NO
|
GENERATE_TREEVIEW = NO
|
||||||
@@ -1004,7 +918,7 @@ FORMULA_FONTSIZE = 10
|
|||||||
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
|
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
|
||||||
# generate Latex output.
|
# generate Latex output.
|
||||||
|
|
||||||
GENERATE_LATEX = NO
|
GENERATE_LATEX = @DOXYFILE_LATEX@
|
||||||
|
|
||||||
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
|
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
|
||||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||||
@@ -1209,10 +1123,8 @@ GENERATE_PERLMOD = NO
|
|||||||
PERLMOD_LATEX = NO
|
PERLMOD_LATEX = NO
|
||||||
|
|
||||||
# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
|
# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
|
||||||
# nicely formatted so it can be parsed by a human reader.
|
# nicely formatted so it can be parsed by a human reader. This is useful
|
||||||
# This is useful
|
# if you want to understand what is going on. On the other hand, if this
|
||||||
# if you want to understand what is going on.
|
|
||||||
# On the other hand, if this
|
|
||||||
# tag is set to NO the size of the Perl module output will be much smaller
|
# tag is set to NO the size of the Perl module output will be much smaller
|
||||||
# and Perl will parse it just the same.
|
# and Perl will parse it just the same.
|
||||||
|
|
||||||
@@ -1299,16 +1211,14 @@ SKIP_FUNCTION_MACROS = YES
|
|||||||
# Optionally an initial location of the external documentation
|
# Optionally an initial location of the external documentation
|
||||||
# can be added for each tagfile. The format of a tag file without
|
# can be added for each tagfile. The format of a tag file without
|
||||||
# this location is as follows:
|
# this location is as follows:
|
||||||
#
|
# TAGFILES = file1 file2 ...
|
||||||
# TAGFILES = file1 file2 ...
|
|
||||||
# Adding location for the tag files is done as follows:
|
# Adding location for the tag files is done as follows:
|
||||||
#
|
# TAGFILES = file1=loc1 "file2 = loc2" ...
|
||||||
# TAGFILES = file1=loc1 "file2 = loc2" ...
|
|
||||||
# where "loc1" and "loc2" can be relative or absolute paths or
|
# where "loc1" and "loc2" can be relative or absolute paths or
|
||||||
# URLs. If a location is present for each tag, the installdox tool
|
# URLs. If a location is present for each tag, the installdox tool
|
||||||
# does not have to be run to correct the links.
|
# does not have to be run to correct the links.
|
||||||
# Note that each tag file must have a unique name
|
# Note that each tag file must have a unique name
|
||||||
# (where the name does NOT include the path)
|
# (where the name does NOT include the path)
|
||||||
# If a tag file is not located in the directory in which doxygen
|
# If a tag file is not located in the directory in which doxygen
|
||||||
# is run, you must also specify the path to the tagfile here.
|
# is run, you must also specify the path to the tagfile here.
|
||||||
|
|
||||||
@@ -1382,11 +1292,6 @@ HAVE_DOT = @DOXYGEN_DOT_FOUND@
|
|||||||
|
|
||||||
DOT_FONTNAME = FreeSans
|
DOT_FONTNAME = FreeSans
|
||||||
|
|
||||||
# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
|
|
||||||
# The default size is 10pt.
|
|
||||||
|
|
||||||
DOT_FONTSIZE = 10
|
|
||||||
|
|
||||||
# By default doxygen will tell dot to use the output directory to look for the
|
# By default doxygen will tell dot to use the output directory to look for the
|
||||||
# FreeSans.ttf font (which doxygen will put there itself). If you specify a
|
# FreeSans.ttf font (which doxygen will put there itself). If you specify a
|
||||||
# different font using DOT_FONTNAME you can set the path where dot
|
# different font using DOT_FONTNAME you can set the path where dot
|
||||||
@@ -1429,7 +1334,7 @@ TEMPLATE_RELATIONS = YES
|
|||||||
# file showing the direct and indirect include dependencies of the file with
|
# file showing the direct and indirect include dependencies of the file with
|
||||||
# other documented files.
|
# other documented files.
|
||||||
|
|
||||||
INCLUDE_GRAPH = YES
|
INCLUDE_GRAPH = NO
|
||||||
|
|
||||||
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
|
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
|
||||||
# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
|
# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
|
||||||
@@ -1444,7 +1349,7 @@ INCLUDED_BY_GRAPH = YES
|
|||||||
# the time of a run. So in most cases it will be better to enable call graphs
|
# the time of a run. So in most cases it will be better to enable call graphs
|
||||||
# for selected functions only using the \callgraph command.
|
# for selected functions only using the \callgraph command.
|
||||||
|
|
||||||
CALL_GRAPH = YES
|
CALL_GRAPH = NO
|
||||||
|
|
||||||
# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
|
# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
|
||||||
# doxygen will generate a caller dependency graph for every global function
|
# doxygen will generate a caller dependency graph for every global function
|
||||||
@@ -1452,7 +1357,7 @@ CALL_GRAPH = YES
|
|||||||
# the time of a run. So in most cases it will be better to enable caller
|
# the time of a run. So in most cases it will be better to enable caller
|
||||||
# graphs for selected functions only using the \callergraph command.
|
# graphs for selected functions only using the \callergraph command.
|
||||||
|
|
||||||
CALLER_GRAPH = YES
|
CALLER_GRAPH = NO
|
||||||
|
|
||||||
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
|
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
|
||||||
# will graphical hierarchy of all classes instead of a textual one.
|
# will graphical hierarchy of all classes instead of a textual one.
|
||||||
@@ -1461,13 +1366,13 @@ GRAPHICAL_HIERARCHY = YES
|
|||||||
|
|
||||||
# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
|
# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
|
||||||
# then doxygen will show the dependencies a directory has on other directories
|
# then doxygen will show the dependencies a directory has on other directories
|
||||||
# in a graphical way. The dependency relations are determined by the #include
|
# in a graphical way. The dependency relations are determined by the #include
|
||||||
# relations between the files in the directories.
|
# relations between the files in the directories.
|
||||||
|
|
||||||
DIRECTORY_GRAPH = YES
|
DIRECTORY_GRAPH = YES
|
||||||
|
|
||||||
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
|
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
|
||||||
# generated by dot. Possible values are png, jpg, or gif
|
# generated by dot. Possible values are png, jpg, or gif
|
||||||
# If left blank png will be used.
|
# If left blank png will be used.
|
||||||
|
|
||||||
DOT_IMAGE_FORMAT = png
|
DOT_IMAGE_FORMAT = png
|
||||||
@@ -1504,10 +1409,10 @@ DOT_GRAPH_MAX_NODES = 50
|
|||||||
MAX_DOT_GRAPH_DEPTH = 0
|
MAX_DOT_GRAPH_DEPTH = 0
|
||||||
|
|
||||||
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
|
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
|
||||||
# background. This is disabled by default, because dot on Windows does not
|
# background. This is enabled by default, which results in a transparent
|
||||||
# seem to support this out of the box. Warning: Depending on the platform used,
|
# background. Warning: Depending on the platform used, enabling this option
|
||||||
# enabling this option may lead to badly anti-aliased labels on the edges of
|
# may lead to badly anti-aliased labels on the edges of a graph (i.e. they
|
||||||
# a graph (i.e. they become hard to read).
|
# become hard to read).
|
||||||
|
|
||||||
DOT_TRANSPARENT = NO
|
DOT_TRANSPARENT = NO
|
||||||
|
|
||||||
@@ -1531,7 +1436,7 @@ GENERATE_LEGEND = YES
|
|||||||
DOT_CLEANUP = YES
|
DOT_CLEANUP = YES
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# Options related to the search engine
|
# Configuration::additions related to the search engine
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
# The SEARCHENGINE tag specifies whether or not a search engine should be
|
# The SEARCHENGINE tag specifies whether or not a search engine should be
|
||||||
|
|||||||
1546
doc/doxy.trac.in
Normal file
1546
doc/doxy.trac.in
Normal file
File diff suppressed because it is too large
Load Diff
12
doc/mainpage.dox
Normal file
12
doc/mainpage.dox
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* @mainpage
|
||||||
|
* This manual documents the libssh C API.
|
||||||
|
*
|
||||||
|
* There are several other places to look for libssh information, such as the
|
||||||
|
* <a href="http://dev.libssh.org/wiki/Tutorial" target="_blank">tutorial</a>
|
||||||
|
* and the specification; those can be found at the <a
|
||||||
|
* href="http://www.libssh.org/" target="_blank">libssh website</a>.
|
||||||
|
*
|
||||||
|
* To be continued...
|
||||||
|
*/
|
||||||
|
|
||||||
@@ -14,10 +14,15 @@ include_directories(
|
|||||||
add_executable(libssh_scp libssh_scp.c ${examples_SRCS})
|
add_executable(libssh_scp libssh_scp.c ${examples_SRCS})
|
||||||
add_executable(scp_download scp_download.c ${examples_SRCS})
|
add_executable(scp_download scp_download.c ${examples_SRCS})
|
||||||
add_executable(samplessh sample.c ${examples_SRCS})
|
add_executable(samplessh sample.c ${examples_SRCS})
|
||||||
|
add_executable(exec exec.c ${examples_SRCS})
|
||||||
|
add_executable(sshnetcat sshnetcat.c ${examples_SRCS})
|
||||||
|
|
||||||
target_link_libraries(libssh_scp ${LIBSSH_SHARED_LIBRARY})
|
target_link_libraries(libssh_scp ${LIBSSH_SHARED_LIBRARY})
|
||||||
target_link_libraries(scp_download ${LIBSSH_SHARED_LIBRARY})
|
target_link_libraries(scp_download ${LIBSSH_SHARED_LIBRARY})
|
||||||
target_link_libraries(samplessh ${LIBSSH_SHARED_LIBRARY})
|
target_link_libraries(samplessh ${LIBSSH_SHARED_LIBRARY})
|
||||||
|
target_link_libraries(exec ${LIBSSH_SHARED_LIBRARY})
|
||||||
|
target_link_libraries(sshnetcat ${LIBSSH_SHARED_LIBRARY})
|
||||||
|
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
${LIBSSH_PUBLIC_INCLUDE_DIRS}
|
${LIBSSH_PUBLIC_INCLUDE_DIRS}
|
||||||
|
|||||||
57
examples/exec.c
Normal file
57
examples/exec.c
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/* simple exec example */
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <libssh/libssh.h>
|
||||||
|
#include "examples_common.h"
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
ssh_session session;
|
||||||
|
ssh_channel channel;
|
||||||
|
char buf[4096];
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
session = connect_ssh("localhost", NULL, 0);
|
||||||
|
if (session == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
channel = channel_new(session);;
|
||||||
|
if (channel == NULL) {
|
||||||
|
ssh_disconnect(session);
|
||||||
|
ssh_finalize();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = channel_open_session(channel);
|
||||||
|
if (rc < 0) {
|
||||||
|
channel_close(channel);
|
||||||
|
ssh_disconnect(session);
|
||||||
|
ssh_finalize();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = channel_request_exec(channel, "ps aux");
|
||||||
|
if (rc < 0) {
|
||||||
|
channel_close(channel);
|
||||||
|
ssh_disconnect(session);
|
||||||
|
ssh_finalize();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (channel_is_open(channel)) {
|
||||||
|
rc = channel_read(channel, buf, sizeof(buf), 0);
|
||||||
|
if(rc > 0){
|
||||||
|
fwrite(buf,1,rc,stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while(rc > 0);
|
||||||
|
|
||||||
|
channel_send_eof(channel);
|
||||||
|
channel_close(channel);
|
||||||
|
|
||||||
|
ssh_disconnect(session);
|
||||||
|
ssh_finalize();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -46,6 +46,8 @@ struct termios terminal;
|
|||||||
char *pcap_file=NULL;
|
char *pcap_file=NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
char *proxycommand;
|
||||||
|
|
||||||
static int auth_callback(const char *prompt, char *buf, size_t len,
|
static int auth_callback(const char *prompt, char *buf, size_t len,
|
||||||
int echo, int verify, void *userdata) {
|
int echo, int verify, void *userdata) {
|
||||||
char *answer = NULL;
|
char *answer = NULL;
|
||||||
@@ -95,6 +97,9 @@ static void usage(){
|
|||||||
" -r : use RSA to verify host public key\n"
|
" -r : use RSA to verify host public key\n"
|
||||||
#ifdef WITH_PCAP
|
#ifdef WITH_PCAP
|
||||||
" -P file : create a pcap debugging file\n"
|
" -P file : create a pcap debugging file\n"
|
||||||
|
#endif
|
||||||
|
#ifndef _WIN32
|
||||||
|
" -T proxycommand : command to execute as a socket proxy\n"
|
||||||
#endif
|
#endif
|
||||||
,
|
,
|
||||||
ssh_version(0));
|
ssh_version(0));
|
||||||
@@ -106,12 +111,17 @@ static int opts(int argc, char **argv){
|
|||||||
// for(i=0;i<argc;i++)
|
// for(i=0;i<argc;i++)
|
||||||
// printf("%d : %s\n",i,argv[i]);
|
// printf("%d : %s\n",i,argv[i]);
|
||||||
/* insert your own arguments here */
|
/* insert your own arguments here */
|
||||||
while((i=getopt(argc,argv,"P:"))!=-1){
|
while((i=getopt(argc,argv,"T:P:"))!=-1){
|
||||||
switch(i){
|
switch(i){
|
||||||
#ifdef WITH_PCAP
|
#ifdef WITH_PCAP
|
||||||
case 'P':
|
case 'P':
|
||||||
pcap_file=optarg;
|
pcap_file=optarg;
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
#ifndef _WIN32
|
||||||
|
case 'T':
|
||||||
|
proxycommand=optarg;
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
fprintf(stderr,"unknown option %c\n",optopt);
|
fprintf(stderr,"unknown option %c\n",optopt);
|
||||||
@@ -432,7 +442,10 @@ static int client(ssh_session session){
|
|||||||
return -1;
|
return -1;
|
||||||
if (ssh_options_set(session, SSH_OPTIONS_HOST ,host) < 0)
|
if (ssh_options_set(session, SSH_OPTIONS_HOST ,host) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
if (proxycommand != NULL){
|
||||||
|
if(ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, proxycommand))
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
ssh_options_parse_config(session, NULL);
|
ssh_options_parse_config(session, NULL);
|
||||||
|
|
||||||
if(ssh_connect(session)){
|
if(ssh_connect(session)){
|
||||||
|
|||||||
@@ -152,10 +152,12 @@ static void do_sftp(ssh_session session){
|
|||||||
}
|
}
|
||||||
/* reading the whole directory, file by file */
|
/* reading the whole directory, file by file */
|
||||||
while((file=sftp_readdir(sftp,dir))){
|
while((file=sftp_readdir(sftp,dir))){
|
||||||
fprintf(stderr, "%30s(%.8o) : %.5d.%.5d : %.10llu bytes\n",
|
fprintf(stderr, "%30s(%.8o) : %s(%.5d) %s(%.5d) : %.10llu bytes\n",
|
||||||
file->name,
|
file->name,
|
||||||
file->permissions,
|
file->permissions,
|
||||||
|
file->owner,
|
||||||
file->uid,
|
file->uid,
|
||||||
|
file->group,
|
||||||
file->gid,
|
file->gid,
|
||||||
(long long unsigned int) file->size);
|
(long long unsigned int) file->size);
|
||||||
sftp_attributes_free(file);
|
sftp_attributes_free(file);
|
||||||
|
|||||||
247
examples/sshnetcat.c
Normal file
247
examples/sshnetcat.c
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2010 Aris Adamantiadis
|
||||||
|
|
||||||
|
This file is part of the SSH Library
|
||||||
|
|
||||||
|
You are free to copy this file, modify it in any way, consider it being public
|
||||||
|
domain. This does not apply to the rest of the library though, but it is
|
||||||
|
allowed to cut-and-paste working code from this file to any license of
|
||||||
|
program.
|
||||||
|
The goal is to show the API in action. It's not a reference on how terminal
|
||||||
|
clients must be made or how a client should react.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <termios.h>
|
||||||
|
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <libssh/callbacks.h>
|
||||||
|
#include <libssh/libssh.h>
|
||||||
|
#include <libssh/sftp.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include "examples_common.h"
|
||||||
|
char *host;
|
||||||
|
const char *desthost="localhost";
|
||||||
|
const char *port="22";
|
||||||
|
|
||||||
|
#ifdef WITH_PCAP
|
||||||
|
#include <libssh/pcap.h>
|
||||||
|
char *pcap_file=NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void usage(){
|
||||||
|
fprintf(stderr,"Usage : sshnetcat [user@]host forwarded_host forwarded_port\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int opts(int argc, char **argv){
|
||||||
|
int i;
|
||||||
|
while((i=getopt(argc,argv,"P:"))!=-1){
|
||||||
|
switch(i){
|
||||||
|
#ifdef WITH_PCAP
|
||||||
|
case 'P':
|
||||||
|
pcap_file=optarg;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
fprintf(stderr,"unknown option %c\n",optopt);
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(optind < argc)
|
||||||
|
host=argv[optind++];
|
||||||
|
if(optind < argc)
|
||||||
|
desthost=argv[optind++];
|
||||||
|
if(optind < argc)
|
||||||
|
port=argv[optind++];
|
||||||
|
if(host==NULL)
|
||||||
|
usage();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void select_loop(ssh_session session,ssh_channel channel){
|
||||||
|
fd_set fds;
|
||||||
|
struct timeval timeout;
|
||||||
|
char buffer[4096];
|
||||||
|
/* channels will be set to the channels to poll.
|
||||||
|
* outchannels will contain the result of the poll
|
||||||
|
*/
|
||||||
|
ssh_channel channels[2], outchannels[2];
|
||||||
|
int lus;
|
||||||
|
int eof=0;
|
||||||
|
int maxfd;
|
||||||
|
int ret;
|
||||||
|
while(channel){
|
||||||
|
do{
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
if(!eof)
|
||||||
|
FD_SET(0,&fds);
|
||||||
|
timeout.tv_sec=30;
|
||||||
|
timeout.tv_usec=0;
|
||||||
|
FD_SET(ssh_get_fd(session),&fds);
|
||||||
|
maxfd=ssh_get_fd(session)+1;
|
||||||
|
channels[0]=channel; // set the first channel we want to read from
|
||||||
|
channels[1]=NULL;
|
||||||
|
ret=ssh_select(channels,outchannels,maxfd,&fds,&timeout);
|
||||||
|
if(ret==EINTR)
|
||||||
|
continue;
|
||||||
|
if(FD_ISSET(0,&fds)){
|
||||||
|
lus=read(0,buffer,sizeof(buffer));
|
||||||
|
if(lus)
|
||||||
|
channel_write(channel,buffer,lus);
|
||||||
|
else {
|
||||||
|
eof=1;
|
||||||
|
channel_send_eof(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(channel && channel_is_closed(channel)){
|
||||||
|
ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",channel_get_exit_status(channel));
|
||||||
|
|
||||||
|
channel_free(channel);
|
||||||
|
channel=NULL;
|
||||||
|
channels[0]=NULL;
|
||||||
|
}
|
||||||
|
if(outchannels[0]){
|
||||||
|
while(channel && channel_is_open(channel) && channel_poll(channel,0)){
|
||||||
|
lus=channel_read(channel,buffer,sizeof(buffer),0);
|
||||||
|
if(lus==-1){
|
||||||
|
fprintf(stderr, "Error reading channel: %s\n",
|
||||||
|
ssh_get_error(session));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(lus==0){
|
||||||
|
ssh_log(session,SSH_LOG_RARE,"EOF received\n");
|
||||||
|
ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",channel_get_exit_status(channel));
|
||||||
|
|
||||||
|
channel_free(channel);
|
||||||
|
channel=channels[0]=NULL;
|
||||||
|
} else
|
||||||
|
write(1,buffer,lus);
|
||||||
|
}
|
||||||
|
while(channel && channel_is_open(channel) && channel_poll(channel,1)){ /* stderr */
|
||||||
|
lus=channel_read(channel,buffer,sizeof(buffer),1);
|
||||||
|
if(lus==-1){
|
||||||
|
fprintf(stderr, "Error reading channel: %s\n",
|
||||||
|
ssh_get_error(session));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(lus==0){
|
||||||
|
ssh_log(session,SSH_LOG_RARE,"EOF received\n");
|
||||||
|
ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",channel_get_exit_status(channel));
|
||||||
|
channel_free(channel);
|
||||||
|
channel=channels[0]=NULL;
|
||||||
|
} else
|
||||||
|
write(2,buffer,lus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(channel && channel_is_closed(channel)){
|
||||||
|
channel_free(channel);
|
||||||
|
channel=NULL;
|
||||||
|
}
|
||||||
|
} while (ret==EINTR || ret==SSH_EINTR);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void forwarding(ssh_session session){
|
||||||
|
ssh_channel channel;
|
||||||
|
int r;
|
||||||
|
channel=channel_new(session);
|
||||||
|
r=channel_open_forward(channel,desthost,atoi(port),"localhost",22);
|
||||||
|
if(r<0) {
|
||||||
|
printf("error forwarding port : %s\n",ssh_get_error(session));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
select_loop(session,channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int client(ssh_session session){
|
||||||
|
int auth=0;
|
||||||
|
char *banner;
|
||||||
|
int state;
|
||||||
|
|
||||||
|
if (ssh_options_set(session, SSH_OPTIONS_HOST ,host) < 0)
|
||||||
|
return -1;
|
||||||
|
ssh_options_parse_config(session, NULL);
|
||||||
|
|
||||||
|
if(ssh_connect(session)){
|
||||||
|
fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
state=verify_knownhost(session);
|
||||||
|
if (state != 0)
|
||||||
|
return -1;
|
||||||
|
ssh_userauth_none(session, NULL);
|
||||||
|
banner=ssh_get_issue_banner(session);
|
||||||
|
if(banner){
|
||||||
|
printf("%s\n",banner);
|
||||||
|
free(banner);
|
||||||
|
}
|
||||||
|
auth=authenticate_console(session);
|
||||||
|
if(auth != SSH_AUTH_SUCCESS){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ssh_log(session, SSH_LOG_FUNCTIONS, "Authentication success");
|
||||||
|
forwarding(session);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_PCAP
|
||||||
|
ssh_pcap_file pcap;
|
||||||
|
void set_pcap(ssh_session session);
|
||||||
|
void set_pcap(ssh_session session){
|
||||||
|
if(!pcap_file)
|
||||||
|
return;
|
||||||
|
pcap=ssh_pcap_file_new();
|
||||||
|
if(ssh_pcap_file_open(pcap,pcap_file) == SSH_ERROR){
|
||||||
|
printf("Error opening pcap file\n");
|
||||||
|
ssh_pcap_file_free(pcap);
|
||||||
|
pcap=NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ssh_set_pcap_file(session,pcap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup_pcap(void);
|
||||||
|
void cleanup_pcap(){
|
||||||
|
ssh_pcap_file_free(pcap);
|
||||||
|
pcap=NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int main(int argc, char **argv){
|
||||||
|
ssh_session session;
|
||||||
|
|
||||||
|
session = ssh_new();
|
||||||
|
|
||||||
|
if(ssh_options_getopt(session, &argc, argv)) {
|
||||||
|
fprintf(stderr, "error parsing command line :%s\n",
|
||||||
|
ssh_get_error(session));
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
opts(argc,argv);
|
||||||
|
#ifdef WITH_PCAP
|
||||||
|
set_pcap(session);
|
||||||
|
#endif
|
||||||
|
client(session);
|
||||||
|
|
||||||
|
ssh_disconnect(session);
|
||||||
|
ssh_free(session);
|
||||||
|
#ifdef WITH_PCAP
|
||||||
|
cleanup_pcap();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ssh_finalize();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -3,7 +3,6 @@ project(libssh-headers C)
|
|||||||
set(libssh_HDRS
|
set(libssh_HDRS
|
||||||
callbacks.h
|
callbacks.h
|
||||||
libssh.h
|
libssh.h
|
||||||
crypto.h
|
|
||||||
ssh2.h
|
ssh2.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,7 @@
|
|||||||
#ifndef BUFFER_H_
|
#ifndef BUFFER_H_
|
||||||
#define BUFFER_H_
|
#define BUFFER_H_
|
||||||
|
|
||||||
/** Describes a buffer state at a moment
|
/* Describes a buffer state */
|
||||||
*/
|
|
||||||
struct ssh_buffer_struct {
|
struct ssh_buffer_struct {
|
||||||
char *data;
|
char *data;
|
||||||
uint32_t used;
|
uint32_t used;
|
||||||
|
|||||||
@@ -50,6 +50,7 @@
|
|||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
/* Visual Studio hasn't inttypes.h so it doesn't know uint32_t */
|
/* Visual Studio hasn't inttypes.h so it doesn't know uint32_t */
|
||||||
|
typedef int int32_t;
|
||||||
typedef unsigned int uint32_t;
|
typedef unsigned int uint32_t;
|
||||||
typedef unsigned short uint16_t;
|
typedef unsigned short uint16_t;
|
||||||
typedef unsigned char uint8_t;
|
typedef unsigned char uint8_t;
|
||||||
@@ -78,7 +79,7 @@
|
|||||||
/* libssh version */
|
/* libssh version */
|
||||||
#define LIBSSH_VERSION_MAJOR 0
|
#define LIBSSH_VERSION_MAJOR 0
|
||||||
#define LIBSSH_VERSION_MINOR 4
|
#define LIBSSH_VERSION_MINOR 4
|
||||||
#define LIBSSH_VERSION_MICRO 0
|
#define LIBSSH_VERSION_MICRO 6
|
||||||
|
|
||||||
#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \
|
#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \
|
||||||
LIBSSH_VERSION_MINOR, \
|
LIBSSH_VERSION_MINOR, \
|
||||||
@@ -118,10 +119,16 @@ typedef struct ssh_string_struct* ssh_string;
|
|||||||
|
|
||||||
/* Socket type */
|
/* Socket type */
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define socket_t SOCKET
|
#ifndef socket_t
|
||||||
#else
|
typedef SOCKET socket_t;
|
||||||
|
#endif /* socket_t */
|
||||||
|
#else /* _WIN32 */
|
||||||
|
#ifndef socket_t
|
||||||
typedef int socket_t;
|
typedef int socket_t;
|
||||||
#endif
|
#endif
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
#define SSH_INVALID_SOCKET ((socket_t) -1)
|
||||||
|
|
||||||
/* the offsets of methods */
|
/* the offsets of methods */
|
||||||
enum ssh_kex_types_e {
|
enum ssh_kex_types_e {
|
||||||
@@ -230,7 +237,7 @@ enum {
|
|||||||
/** Only rare and noteworthy events
|
/** Only rare and noteworthy events
|
||||||
*/
|
*/
|
||||||
SSH_LOG_RARE,
|
SSH_LOG_RARE,
|
||||||
/** High level protocol informations
|
/** High level protocol information
|
||||||
*/
|
*/
|
||||||
SSH_LOG_PROTOCOL,
|
SSH_LOG_PROTOCOL,
|
||||||
/** Lower level protocol infomations, packet level
|
/** Lower level protocol infomations, packet level
|
||||||
@@ -251,6 +258,7 @@ enum ssh_options_e {
|
|||||||
SSH_OPTIONS_USER,
|
SSH_OPTIONS_USER,
|
||||||
SSH_OPTIONS_SSH_DIR,
|
SSH_OPTIONS_SSH_DIR,
|
||||||
SSH_OPTIONS_IDENTITY,
|
SSH_OPTIONS_IDENTITY,
|
||||||
|
SSH_OPTIONS_ADD_IDENTITY,
|
||||||
SSH_OPTIONS_KNOWNHOSTS,
|
SSH_OPTIONS_KNOWNHOSTS,
|
||||||
SSH_OPTIONS_TIMEOUT,
|
SSH_OPTIONS_TIMEOUT,
|
||||||
SSH_OPTIONS_TIMEOUT_USEC,
|
SSH_OPTIONS_TIMEOUT_USEC,
|
||||||
@@ -262,7 +270,9 @@ enum ssh_options_e {
|
|||||||
SSH_OPTIONS_CIPHERS_C_S,
|
SSH_OPTIONS_CIPHERS_C_S,
|
||||||
SSH_OPTIONS_CIPHERS_S_C,
|
SSH_OPTIONS_CIPHERS_S_C,
|
||||||
SSH_OPTIONS_COMPRESSION_C_S,
|
SSH_OPTIONS_COMPRESSION_C_S,
|
||||||
SSH_OPTIONS_COMPRESSION_S_C
|
SSH_OPTIONS_COMPRESSION_S_C,
|
||||||
|
SSH_OPTIONS_PROXYCOMMAND,
|
||||||
|
SSH_OPTIONS_BINDADDR
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@@ -334,10 +344,14 @@ LIBSSH_API void privatekey_free(ssh_private_key prv);
|
|||||||
LIBSSH_API ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
|
LIBSSH_API ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
|
||||||
int type, const char *passphrase);
|
int type, const char *passphrase);
|
||||||
LIBSSH_API void publickey_free(ssh_public_key key);
|
LIBSSH_API void publickey_free(ssh_public_key key);
|
||||||
|
LIBSSH_API int ssh_publickey_to_file(ssh_session session, const char *file,
|
||||||
|
ssh_string pubkey, int type);
|
||||||
LIBSSH_API ssh_string publickey_from_file(ssh_session session, const char *filename,
|
LIBSSH_API ssh_string publickey_from_file(ssh_session session, const char *filename,
|
||||||
int *type);
|
int *type);
|
||||||
LIBSSH_API ssh_public_key publickey_from_privatekey(ssh_private_key prv);
|
LIBSSH_API ssh_public_key publickey_from_privatekey(ssh_private_key prv);
|
||||||
LIBSSH_API ssh_string publickey_to_string(ssh_public_key key);
|
LIBSSH_API ssh_string publickey_to_string(ssh_public_key key);
|
||||||
|
LIBSSH_API int ssh_try_publickey_from_file(ssh_session session, const char *keyfile,
|
||||||
|
ssh_string *publickey, int *type);
|
||||||
|
|
||||||
LIBSSH_API int ssh_auth_list(ssh_session session);
|
LIBSSH_API int ssh_auth_list(ssh_session session);
|
||||||
LIBSSH_API char *ssh_basename (const char *path);
|
LIBSSH_API char *ssh_basename (const char *path);
|
||||||
@@ -382,6 +396,9 @@ LIBSSH_API int ssh_pcap_file_close(ssh_pcap_file pcap);
|
|||||||
LIBSSH_API void ssh_pcap_file_free(ssh_pcap_file pcap);
|
LIBSSH_API void ssh_pcap_file_free(ssh_pcap_file pcap);
|
||||||
LIBSSH_API ssh_pcap_file ssh_pcap_file_new(void);
|
LIBSSH_API ssh_pcap_file ssh_pcap_file_new(void);
|
||||||
LIBSSH_API int ssh_pcap_file_open(ssh_pcap_file pcap, const char *filename);
|
LIBSSH_API int ssh_pcap_file_open(ssh_pcap_file pcap, const char *filename);
|
||||||
|
|
||||||
|
LIBSSH_API int ssh_privatekey_type(ssh_private_key privatekey);
|
||||||
|
|
||||||
LIBSSH_API void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len);
|
LIBSSH_API void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len);
|
||||||
LIBSSH_API int ssh_scp_accept_request(ssh_scp scp);
|
LIBSSH_API int ssh_scp_accept_request(ssh_scp scp);
|
||||||
LIBSSH_API int ssh_scp_close(ssh_scp scp);
|
LIBSSH_API int ssh_scp_close(ssh_scp scp);
|
||||||
|
|||||||
@@ -25,8 +25,12 @@
|
|||||||
/* in misc.c */
|
/* in misc.c */
|
||||||
/* gets the user home dir. */
|
/* gets the user home dir. */
|
||||||
char *ssh_get_user_home_dir(void);
|
char *ssh_get_user_home_dir(void);
|
||||||
|
char *ssh_get_local_username(ssh_session session);
|
||||||
int ssh_file_readaccess_ok(const char *file);
|
int ssh_file_readaccess_ok(const char *file);
|
||||||
|
|
||||||
|
char *ssh_path_expand_tilde(const char *d);
|
||||||
|
char *ssh_path_expand_escape(ssh_session session, const char *s);
|
||||||
|
|
||||||
/* macro for byte ordering */
|
/* macro for byte ordering */
|
||||||
uint64_t ntohll(uint64_t);
|
uint64_t ntohll(uint64_t);
|
||||||
#define htonll(x) ntohll(x)
|
#define htonll(x) ntohll(x)
|
||||||
@@ -46,14 +50,12 @@ struct ssh_iterator {
|
|||||||
struct ssh_list *ssh_list_new(void);
|
struct ssh_list *ssh_list_new(void);
|
||||||
void ssh_list_free(struct ssh_list *list);
|
void ssh_list_free(struct ssh_list *list);
|
||||||
struct ssh_iterator *ssh_list_get_iterator(const struct ssh_list *list);
|
struct ssh_iterator *ssh_list_get_iterator(const struct ssh_list *list);
|
||||||
int ssh_list_add(struct ssh_list *list, const void *data);
|
int ssh_list_append(struct ssh_list *list, const void *data);
|
||||||
|
int ssh_list_prepend(struct ssh_list *list, const void *data);
|
||||||
void ssh_list_remove(struct ssh_list *list, struct ssh_iterator *iterator);
|
void ssh_list_remove(struct ssh_list *list, struct ssh_iterator *iterator);
|
||||||
|
char *ssh_hostport(const char *host, int port);
|
||||||
|
|
||||||
/** @brief fetch the head element of a list and remove it from list
|
const void *_ssh_list_pop_head(struct ssh_list *list);
|
||||||
* @param list the ssh_list to use
|
|
||||||
* @return the first element of the list
|
|
||||||
*/
|
|
||||||
const void *_ssh_list_get_head(struct ssh_list *list);
|
|
||||||
|
|
||||||
#define ssh_iterator_value(type, iterator)\
|
#define ssh_iterator_value(type, iterator)\
|
||||||
((type)((iterator)->data))
|
((type)((iterator)->data))
|
||||||
@@ -61,9 +63,9 @@ const void *_ssh_list_get_head(struct ssh_list *list);
|
|||||||
/** @brief fetch the head element of a list and remove it from list
|
/** @brief fetch the head element of a list and remove it from list
|
||||||
* @param type type of the element to return
|
* @param type type of the element to return
|
||||||
* @param list the ssh_list to use
|
* @param list the ssh_list to use
|
||||||
* @return the first element of the list
|
* @return the first element of the list, or NULL if the list is empty
|
||||||
*/
|
*/
|
||||||
#define ssh_list_get_head(type, ssh_list)\
|
#define ssh_list_pop_head(type, ssh_list)\
|
||||||
((type)_ssh_list_get_head(ssh_list))
|
((type)_ssh_list_pop_head(ssh_list))
|
||||||
|
|
||||||
#endif /* MISC_H_ */
|
#endif /* MISC_H_ */
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#ifdef WITH_PCAP
|
#ifdef WITH_PCAP
|
||||||
typedef struct ssh_pcap_context_struct* ssh_pcap_context;
|
typedef struct ssh_pcap_context_struct* ssh_pcap_context;
|
||||||
|
|
||||||
int ssh_pcap_file_write_packet(ssh_pcap_file pcap, ssh_buffer packet, u_int32_t original_len);
|
int ssh_pcap_file_write_packet(ssh_pcap_file pcap, ssh_buffer packet, uint32_t original_len);
|
||||||
|
|
||||||
ssh_pcap_context ssh_pcap_context_new(ssh_session session);
|
ssh_pcap_context ssh_pcap_context_new(ssh_session session);
|
||||||
void ssh_pcap_context_free(ssh_pcap_context ctx);
|
void ssh_pcap_context_free(ssh_pcap_context ctx);
|
||||||
@@ -18,7 +18,7 @@ enum ssh_pcap_direction{
|
|||||||
};
|
};
|
||||||
void ssh_pcap_context_set_file(ssh_pcap_context, ssh_pcap_file);
|
void ssh_pcap_context_set_file(ssh_pcap_context, ssh_pcap_file);
|
||||||
int ssh_pcap_context_write(ssh_pcap_context,enum ssh_pcap_direction direction, void *data,
|
int ssh_pcap_context_write(ssh_pcap_context,enum ssh_pcap_direction direction, void *data,
|
||||||
u_int32_t len, u_int32_t origlen);
|
uint32_t len, uint32_t origlen);
|
||||||
|
|
||||||
|
|
||||||
#endif /* WITH_PCAP */
|
#endif /* WITH_PCAP */
|
||||||
|
|||||||
@@ -38,9 +38,48 @@ typedef struct ssh_pollfd_struct {
|
|||||||
short revents; /* returned events */
|
short revents; /* returned events */
|
||||||
} ssh_pollfd_t;
|
} ssh_pollfd_t;
|
||||||
|
|
||||||
|
typedef unsigned long int nfds_t;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
#ifndef POLLRDNORM
|
||||||
|
#define POLLRDNORM 0x0100
|
||||||
|
#endif
|
||||||
|
#ifndef POLLRDBAND
|
||||||
|
#define POLLRDBAND 0x0200
|
||||||
|
#endif
|
||||||
|
#ifndef POLLIN
|
||||||
|
#define POLLIN (POLLRDNORM | POLLRDBAND)
|
||||||
|
#endif
|
||||||
|
#ifndef POLLPRI
|
||||||
|
#define POLLPRI 0x0400
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef POLLWRNORM
|
||||||
|
#define POLLWRNORM 0x0010
|
||||||
|
#endif
|
||||||
|
#ifndef POLLOUT
|
||||||
|
#define POLLOUT (POLLWRNORM)
|
||||||
|
#endif
|
||||||
|
#ifndef POLLWRBAND
|
||||||
|
#define POLLWRBAND 0x0020
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef POLLERR
|
||||||
|
#define POLLERR 0x0001
|
||||||
|
#endif
|
||||||
|
#ifndef POLLHUP
|
||||||
|
#define POLLHUP 0x0002
|
||||||
|
#endif
|
||||||
|
#ifndef POLLNVAL
|
||||||
|
#define POLLNVAL 0x0004
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else /* _WIN32 */
|
||||||
|
|
||||||
/* poll.c */
|
/* poll.c */
|
||||||
#ifndef POLLIN
|
#ifndef POLLIN
|
||||||
# define POLLIN 0x001 /* There is data to read. */
|
#define POLLIN 0x001 /* There is data to read. */
|
||||||
#endif
|
#endif
|
||||||
#ifndef POLLPRI
|
#ifndef POLLPRI
|
||||||
#define POLLPRI 0x002 /* There is urgent data to read. */
|
#define POLLPRI 0x002 /* There is urgent data to read. */
|
||||||
@@ -59,9 +98,24 @@ typedef struct ssh_pollfd_struct {
|
|||||||
#define POLLNVAL 0x020 /* Invalid polling request. */
|
#define POLLNVAL 0x020 /* Invalid polling request. */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef unsigned long int nfds_t;
|
#ifndef POLLRDNORM
|
||||||
|
#define POLLRDNORM 0x040 /* mapped to read fds_set */
|
||||||
|
#endif
|
||||||
|
#ifndef POLLRDBAND
|
||||||
|
#define POLLRDBAND 0x080 /* mapped to exception fds_set */
|
||||||
|
#endif
|
||||||
|
#ifndef POLLWRNORM
|
||||||
|
#define POLLWRNORM 0x100 /* mapped to write fds_set */
|
||||||
|
#endif
|
||||||
|
#ifndef POLLWRBAND
|
||||||
|
#define POLLWRBAND 0x200 /* mapped to write fds_set */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* WIN32 */
|
||||||
#endif /* HAVE_POLL */
|
#endif /* HAVE_POLL */
|
||||||
|
|
||||||
|
void ssh_poll_init(void);
|
||||||
|
void ssh_poll_cleanup(void);
|
||||||
int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout);
|
int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout);
|
||||||
typedef struct ssh_poll_ctx_struct *ssh_poll_ctx;
|
typedef struct ssh_poll_ctx_struct *ssh_poll_ctx;
|
||||||
typedef struct ssh_poll_handle_struct *ssh_poll_handle;
|
typedef struct ssh_poll_handle_struct *ssh_poll_handle;
|
||||||
@@ -77,7 +131,7 @@ typedef struct ssh_poll_handle_struct *ssh_poll_handle;
|
|||||||
* @return 0 on success, < 0 if you removed the poll object from
|
* @return 0 on success, < 0 if you removed the poll object from
|
||||||
* it's poll context.
|
* it's poll context.
|
||||||
*/
|
*/
|
||||||
typedef int (*ssh_poll_callback)(ssh_poll_handle p, int fd, int revents,
|
typedef int (*ssh_poll_callback)(ssh_poll_handle p, socket_t fd, int revents,
|
||||||
void *userdata);
|
void *userdata);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -32,18 +32,72 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _WIN32
|
||||||
#define snprintf _snprintf
|
|
||||||
/** Imitate define of inttypes.h */
|
/* Imitate define of inttypes.h */
|
||||||
#define PRIdS "Id"
|
# ifndef PRIdS
|
||||||
#define strcasecmp _stricmp
|
# define PRIdS "Id"
|
||||||
#define strncasecmp _strnicmp
|
# endif
|
||||||
#define strtoull _strtoui64
|
|
||||||
#define isblank(ch) ((ch) == ' ' || (ch) == '\t' || (ch) == '\n' || (ch) == '\r')
|
# ifdef _MSC_VER
|
||||||
#else
|
# include <stdio.h>
|
||||||
|
|
||||||
|
/* On Microsoft compilers define inline to __inline on all others use inline */
|
||||||
|
# undef inline
|
||||||
|
# define inline __inline
|
||||||
|
|
||||||
|
# undef strdup
|
||||||
|
# define strdup _strdup
|
||||||
|
|
||||||
|
# define strcasecmp _stricmp
|
||||||
|
# define strncasecmp _strnicmp
|
||||||
|
# define strtoull _strtoui64
|
||||||
|
# define isblank(ch) ((ch) == ' ' || (ch) == '\t' || (ch) == '\n' || (ch) == '\r')
|
||||||
|
|
||||||
|
# define usleep(X) Sleep(((X)+1000)/1000)
|
||||||
|
|
||||||
|
# undef strtok_r
|
||||||
|
# define strtok_r strtok_s
|
||||||
|
|
||||||
|
# if defined(HAVE__SNPRINTF_S)
|
||||||
|
# undef snprintf
|
||||||
|
# define snprintf(d, n, ...) _snprintf_s((d), (n), _TRUNCATE, __VA_ARGS__)
|
||||||
|
# else /* HAVE__SNPRINTF_S */
|
||||||
|
# if defined(HAVE__SNPRINTF)
|
||||||
|
# undef snprintf
|
||||||
|
# define snprintf _snprintf
|
||||||
|
# else /* HAVE__SNPRINTF */
|
||||||
|
# if !defined(HAVE_SNPRINTF)
|
||||||
|
# error "no snprintf compatible function found"
|
||||||
|
# endif /* HAVE_SNPRINTF */
|
||||||
|
# endif /* HAVE__SNPRINTF */
|
||||||
|
# endif /* HAVE__SNPRINTF_S */
|
||||||
|
|
||||||
|
# if defined(HAVE__VSNPRINTF_S)
|
||||||
|
# undef vsnprintf
|
||||||
|
# define vsnprintf(s, n, f, v) _vsnprintf_s((s), (n), _TRUNCATE, (f), (v))
|
||||||
|
# else /* HAVE__VSNPRINTF_S */
|
||||||
|
# if defined(HAVE__VSNPRINTF)
|
||||||
|
# undef vsnprintf
|
||||||
|
# define vsnprintf _vsnprintf
|
||||||
|
# else
|
||||||
|
# if !defined(HAVE_VSNPRINTF)
|
||||||
|
# error "No vsnprintf compatible function found"
|
||||||
|
# endif /* HAVE_VSNPRINTF */
|
||||||
|
# endif /* HAVE__VSNPRINTF */
|
||||||
|
# endif /* HAVE__VSNPRINTF_S */
|
||||||
|
|
||||||
|
# ifndef HAVE_STRNCPY
|
||||||
|
# define strncpy(d, s, n) strncpy_s((d), (n), (s), _TRUNCATE)
|
||||||
|
# endif
|
||||||
|
# endif /* _MSC_VER */
|
||||||
|
|
||||||
|
#else /* _WIN32 */
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#define PRIdS "zd"
|
#define PRIdS "zd"
|
||||||
#endif
|
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
#include "libssh/libssh.h"
|
#include "libssh/libssh.h"
|
||||||
#include "libssh/callbacks.h"
|
#include "libssh/callbacks.h"
|
||||||
@@ -77,7 +131,7 @@ typedef struct kex_struct {
|
|||||||
|
|
||||||
struct error_struct {
|
struct error_struct {
|
||||||
/* error handling */
|
/* error handling */
|
||||||
int error_code;
|
unsigned int error_code;
|
||||||
char error_buffer[ERROR_BUFFERLEN];
|
char error_buffer[ERROR_BUFFERLEN];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -185,6 +239,11 @@ int match_hostname(const char *host, const char *pattern, unsigned int len);
|
|||||||
|
|
||||||
/* log.c */
|
/* log.c */
|
||||||
|
|
||||||
|
/* misc.c */
|
||||||
|
#ifdef _WIN32
|
||||||
|
int gettimeofday(struct timeval *__p, void *__t);
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
#ifndef __FUNCTION__
|
#ifndef __FUNCTION__
|
||||||
#if defined(__SUNPRO_C)
|
#if defined(__SUNPRO_C)
|
||||||
#define __FUNCTION__ __func__
|
#define __FUNCTION__ __func__
|
||||||
@@ -217,8 +276,8 @@ int match_hostname(const char *host, const char *pattern, unsigned int len);
|
|||||||
|
|
||||||
/* options.c */
|
/* options.c */
|
||||||
|
|
||||||
char *dir_expand_dup(ssh_session session, const char *value, int allowsshdir);
|
|
||||||
int ssh_options_set_algo(ssh_session session, int algo, const char *list);
|
int ssh_options_set_algo(ssh_session session, int algo, const char *list);
|
||||||
|
int ssh_options_apply(ssh_session session);
|
||||||
|
|
||||||
/** Free memory space */
|
/** Free memory space */
|
||||||
#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
|
#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
|
||||||
|
|||||||
@@ -61,9 +61,13 @@ LIBSSH_API ssh_bind ssh_bind_new(void);
|
|||||||
/**
|
/**
|
||||||
* @brief Set the opitons for the current SSH server bind.
|
* @brief Set the opitons for the current SSH server bind.
|
||||||
*
|
*
|
||||||
* @param ssh_bind The ssh server bind to use.
|
* @param sshbind The ssh server bind to use.
|
||||||
*
|
*
|
||||||
* @param options The option structure to set.
|
* @param type The option type to set.
|
||||||
|
*
|
||||||
|
* @param value The option value to set.
|
||||||
|
*
|
||||||
|
* @return 0 on success, < 0 on error.
|
||||||
*/
|
*/
|
||||||
LIBSSH_API int ssh_bind_options_set(ssh_bind sshbind,
|
LIBSSH_API int ssh_bind_options_set(ssh_bind sshbind,
|
||||||
enum ssh_bind_options_e type, const void *value);
|
enum ssh_bind_options_e type, const void *value);
|
||||||
|
|||||||
@@ -102,9 +102,9 @@ struct ssh_session_struct {
|
|||||||
#endif
|
#endif
|
||||||
char *username;
|
char *username;
|
||||||
char *host;
|
char *host;
|
||||||
char *bindaddr; /* TODO: check if needed */
|
char *bindaddr; /* bind the client to an ip addr */
|
||||||
char *xbanner; /* TODO: looks like it is not needed */
|
char *xbanner; /* TODO: looks like it is not needed */
|
||||||
char *identity;
|
struct ssh_list *identity;
|
||||||
char *sshdir;
|
char *sshdir;
|
||||||
char *knownhosts;
|
char *knownhosts;
|
||||||
char *wanted_methods[10];
|
char *wanted_methods[10];
|
||||||
@@ -114,8 +114,9 @@ struct ssh_session_struct {
|
|||||||
socket_t fd;
|
socket_t fd;
|
||||||
int ssh2;
|
int ssh2;
|
||||||
int ssh1;
|
int ssh1;
|
||||||
|
char *ProxyCommand;
|
||||||
};
|
};
|
||||||
|
|
||||||
int ssh_handle_packets(ssh_session session);
|
int ssh_handle_packets(ssh_session session);
|
||||||
|
void ssh_global_request_handle(ssh_session session);
|
||||||
#endif /* SESSION_H_ */
|
#endif /* SESSION_H_ */
|
||||||
|
|||||||
@@ -149,17 +149,16 @@ struct sftp_status_message_struct {
|
|||||||
char *langmsg;
|
char *langmsg;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* don't worry much of these aren't really used */
|
|
||||||
struct sftp_attributes_struct {
|
struct sftp_attributes_struct {
|
||||||
char *name;
|
char *name;
|
||||||
char *longname; /* some weird stuff */
|
char *longname; /* ls -l output on openssh, not reliable else */
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
uint32_t uid;
|
uint32_t uid;
|
||||||
uint32_t gid;
|
uint32_t gid;
|
||||||
char *owner;
|
char *owner; /* set if openssh and version 4 */
|
||||||
char *group;
|
char *group; /* set if openssh and version 4 */
|
||||||
uint32_t permissions;
|
uint32_t permissions;
|
||||||
uint64_t atime64;
|
uint64_t atime64;
|
||||||
uint32_t atime;
|
uint32_t atime;
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ struct socket *ssh_socket_new(ssh_session session);
|
|||||||
void ssh_socket_free(struct socket *s);
|
void ssh_socket_free(struct socket *s);
|
||||||
void ssh_socket_set_fd(struct socket *s, socket_t fd);
|
void ssh_socket_set_fd(struct socket *s, socket_t fd);
|
||||||
socket_t ssh_socket_get_fd(struct socket *s);
|
socket_t ssh_socket_get_fd(struct socket *s);
|
||||||
|
void ssh_socket_cleanup(void);
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
int ssh_socket_unix(struct socket *s, const char *path);
|
int ssh_socket_unix(struct socket *s, const char *path);
|
||||||
#endif
|
#endif
|
||||||
@@ -38,7 +39,7 @@ int ssh_socket_read(struct socket *s, void *buffer, int len);
|
|||||||
int ssh_socket_write(struct socket *s,const void *buffer, int len);
|
int ssh_socket_write(struct socket *s,const void *buffer, int len);
|
||||||
int ssh_socket_is_open(struct socket *s);
|
int ssh_socket_is_open(struct socket *s);
|
||||||
int ssh_socket_fd_isset(struct socket *s, fd_set *set);
|
int ssh_socket_fd_isset(struct socket *s, fd_set *set);
|
||||||
void ssh_socket_fd_set(struct socket *s, fd_set *set, int *fd_max);
|
void ssh_socket_fd_set(struct socket *s, fd_set *set, socket_t *max_fd);
|
||||||
int ssh_socket_completeread(struct socket *s, void *buffer, uint32_t len);
|
int ssh_socket_completeread(struct socket *s, void *buffer, uint32_t len);
|
||||||
int ssh_socket_completewrite(struct socket *s, const void *buffer, uint32_t len);
|
int ssh_socket_completewrite(struct socket *s, const void *buffer, uint32_t len);
|
||||||
int ssh_socket_wait_for_data(struct socket *s, ssh_session session, uint32_t len);
|
int ssh_socket_wait_for_data(struct socket *s, ssh_session session, uint32_t len);
|
||||||
@@ -52,4 +53,10 @@ int ssh_socket_get_status(struct socket *s);
|
|||||||
int ssh_socket_data_available(struct socket *s);
|
int ssh_socket_data_available(struct socket *s);
|
||||||
int ssh_socket_data_writable(struct socket *s);
|
int ssh_socket_data_writable(struct socket *s);
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
void ssh_execute_command(const char *command, socket_t in, socket_t out);
|
||||||
|
socket_t ssh_socket_connect_proxycommand(ssh_session session,
|
||||||
|
const char *command);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* SOCKET_H_ */
|
#endif /* SOCKET_H_ */
|
||||||
|
|||||||
@@ -70,6 +70,11 @@ typedef HMAC_CTX* HMACCTX;
|
|||||||
#define MD5_DIGEST_LEN MD5_DIGEST_LENGTH
|
#define MD5_DIGEST_LEN MD5_DIGEST_LENGTH
|
||||||
|
|
||||||
#include <openssl/bn.h>
|
#include <openssl/bn.h>
|
||||||
|
#include <openssl/opensslv.h>
|
||||||
|
#define OPENSSL_0_9_7b 0x0090702fL
|
||||||
|
#if (OPENSSL_VERSION_NUMBER <= OPENSSL_0_9_7b)
|
||||||
|
#define BROKEN_AES_CTR
|
||||||
|
#endif
|
||||||
typedef BIGNUM* bignum;
|
typedef BIGNUM* bignum;
|
||||||
typedef BN_CTX* bignum_CTX;
|
typedef BN_CTX* bignum_CTX;
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ if (HAVE_LIBSOCKET)
|
|||||||
)
|
)
|
||||||
endif (HAVE_LIBSOCKET)
|
endif (HAVE_LIBSOCKET)
|
||||||
|
|
||||||
if (CRYPTO_LIBRARY)
|
if (OPENSSL_LIBRARIES)
|
||||||
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
||||||
${LIBSSH_PRIVATE_INCLUDE_DIRS}
|
${LIBSSH_PRIVATE_INCLUDE_DIRS}
|
||||||
${OPENSSL_INCLUDE_DIRS}
|
${OPENSSL_INCLUDE_DIRS}
|
||||||
@@ -51,9 +51,9 @@ if (CRYPTO_LIBRARY)
|
|||||||
|
|
||||||
set(LIBSSH_LINK_LIBRARIES
|
set(LIBSSH_LINK_LIBRARIES
|
||||||
${LIBSSH_LINK_LIBRARIES}
|
${LIBSSH_LINK_LIBRARIES}
|
||||||
${CRYPTO_LIBRARY}
|
${OPENSSL_LIBRARIES}
|
||||||
)
|
)
|
||||||
endif (CRYPTO_LIBRARY)
|
endif (OPENSSL_LIBRARIES)
|
||||||
|
|
||||||
if (GCRYPT_LIBRARY)
|
if (GCRYPT_LIBRARY)
|
||||||
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
||||||
|
|||||||
@@ -41,7 +41,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <poll.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
@@ -54,6 +53,7 @@
|
|||||||
#include "libssh/buffer.h"
|
#include "libssh/buffer.h"
|
||||||
#include "libssh/session.h"
|
#include "libssh/session.h"
|
||||||
#include "libssh/keys.h"
|
#include "libssh/keys.h"
|
||||||
|
#include "libssh/poll.h"
|
||||||
|
|
||||||
/* macro to check for "agent failure" message */
|
/* macro to check for "agent failure" message */
|
||||||
#define agent_failed(x) \
|
#define agent_failed(x) \
|
||||||
@@ -85,8 +85,8 @@ static size_t atomicio(struct socket *s, void *buf, size_t n, int do_read) {
|
|||||||
char *b = buf;
|
char *b = buf;
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
ssize_t res;
|
ssize_t res;
|
||||||
struct pollfd pfd;
|
ssh_pollfd_t pfd;
|
||||||
int fd = ssh_socket_get_fd(s);
|
socket_t fd = ssh_socket_get_fd(s);
|
||||||
|
|
||||||
pfd.fd = fd;
|
pfd.fd = fd;
|
||||||
pfd.events = do_read ? POLLIN : POLLOUT;
|
pfd.events = do_read ? POLLIN : POLLOUT;
|
||||||
@@ -107,7 +107,7 @@ static size_t atomicio(struct socket *s, void *buf, size_t n, int do_read) {
|
|||||||
#else
|
#else
|
||||||
if (errno == EAGAIN) {
|
if (errno == EAGAIN) {
|
||||||
#endif
|
#endif
|
||||||
(void) poll(&pfd, 1, -1);
|
(void) ssh_poll(&pfd, 1, -1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
292
libssh/auth.c
292
libssh/auth.c
@@ -35,6 +35,7 @@
|
|||||||
#include "libssh/buffer.h"
|
#include "libssh/buffer.h"
|
||||||
#include "libssh/agent.h"
|
#include "libssh/agent.h"
|
||||||
#include "libssh/keyfiles.h"
|
#include "libssh/keyfiles.h"
|
||||||
|
#include "libssh/misc.h"
|
||||||
#include "libssh/packet.h"
|
#include "libssh/packet.h"
|
||||||
#include "libssh/session.h"
|
#include "libssh/session.h"
|
||||||
#include "libssh/keys.h"
|
#include "libssh/keys.h"
|
||||||
@@ -169,24 +170,33 @@ static int wait_auth_status(ssh_session session, int kbdint) {
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief retrieves available authentication methods for this session
|
||||||
|
* @deprecated
|
||||||
|
* @see ssh_userauth_list
|
||||||
|
*/
|
||||||
int ssh_auth_list(ssh_session session) {
|
int ssh_auth_list(ssh_session session) {
|
||||||
if (session == NULL) {
|
return ssh_userauth_list(session, NULL);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return session->auth_methods;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief retrieves available authentication methods for this session
|
||||||
|
* @param[in] session the SSH session
|
||||||
|
* @param[in] username set to NULL
|
||||||
|
* @returns A bitfield of values SSH_AUTH_METHOD_NONE, SSH_AUTH_METHOD_PASSWORD,
|
||||||
|
SSH_AUTH_METHOD_PUBLICKEY, SSH_AUTH_METHOD_HOSTBASED,
|
||||||
|
SSH_AUTH_METHOD_INTERACTIVE.
|
||||||
|
@warning Other reserved flags may appear in future versions.
|
||||||
|
*/
|
||||||
int ssh_userauth_list(ssh_session session, const char *username) {
|
int ssh_userauth_list(ssh_session session, const char *username) {
|
||||||
if (session == NULL || username == NULL) {
|
if (session == NULL) {
|
||||||
return SSH_AUTH_ERROR;
|
return SSH_AUTH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session->auth_methods == 0) {
|
if (session->auth_methods == 0) {
|
||||||
ssh_userauth_none(session, username);
|
ssh_userauth_none(session, username);
|
||||||
}
|
}
|
||||||
|
return session->auth_methods;
|
||||||
return ssh_auth_list(session);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* use the "none" authentication question */
|
/* use the "none" authentication question */
|
||||||
@@ -224,7 +234,7 @@ int ssh_userauth_none(ssh_session session, const char *username) {
|
|||||||
|
|
||||||
if (username == NULL) {
|
if (username == NULL) {
|
||||||
if (session->username == NULL) {
|
if (session->username == NULL) {
|
||||||
if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
|
if (ssh_options_apply(session) < 0) {
|
||||||
leave_function();
|
leave_function();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -330,7 +340,7 @@ int ssh_userauth_offer_pubkey(ssh_session session, const char *username,
|
|||||||
|
|
||||||
if (username == NULL) {
|
if (username == NULL) {
|
||||||
if (session->username == NULL) {
|
if (session->username == NULL) {
|
||||||
if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
|
if (ssh_options_apply(session) < 0) {
|
||||||
leave_function();
|
leave_function();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -442,7 +452,7 @@ int ssh_userauth_pubkey(ssh_session session, const char *username,
|
|||||||
|
|
||||||
if (username == NULL) {
|
if (username == NULL) {
|
||||||
if (session->username == NULL) {
|
if (session->username == NULL) {
|
||||||
if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
|
if (ssh_options_apply(session) < 0) {
|
||||||
leave_function();
|
leave_function();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -560,7 +570,7 @@ int ssh_userauth_agent_pubkey(ssh_session session, const char *username,
|
|||||||
|
|
||||||
if (username == NULL) {
|
if (username == NULL) {
|
||||||
if (session->username == NULL) {
|
if (session->username == NULL) {
|
||||||
if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
|
if (ssh_options_apply(session) < 0) {
|
||||||
leave_function();
|
leave_function();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -687,7 +697,7 @@ int ssh_userauth_password(ssh_session session, const char *username,
|
|||||||
|
|
||||||
if (username == NULL) {
|
if (username == NULL) {
|
||||||
if (session->username == NULL) {
|
if (session->username == NULL) {
|
||||||
if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
|
if (ssh_options_apply(session) < 0) {
|
||||||
leave_function();
|
leave_function();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -756,42 +766,6 @@ error:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
static const char privKey_1[] = "SSH_DIR/identity";
|
|
||||||
static const char pubKey_1[] = "SSH_DIR/identity.pub";
|
|
||||||
static const char privKey_2[] = "SSH_DIR/id_dsa";
|
|
||||||
static const char pubKey_2[] = "SSH_DIR/id_dsa.pub";
|
|
||||||
static const char privKey_3[] = "SSH_DIR/id_rsa";
|
|
||||||
static const char pubKey_3[] = "SSH_DIR/id_rsa.pub";
|
|
||||||
/** Used different var to allow const char[] declaration */
|
|
||||||
static struct ssh_keys_struct keytab[] = {
|
|
||||||
{ privKey_1, pubKey_1},
|
|
||||||
{ privKey_2, pubKey_2},
|
|
||||||
{ privKey_3, pubKey_3},
|
|
||||||
{0}
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
/* This requires GCC extensions */
|
|
||||||
static struct ssh_keys_struct keytab[] = {
|
|
||||||
{
|
|
||||||
.privatekey = "SSH_DIR/identity",
|
|
||||||
.publickey = "SSH_DIR/identity.pub"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.privatekey = "SSH_DIR/id_dsa",
|
|
||||||
.publickey = "SSH_DIR/id_dsa.pub",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.privatekey = "SSH_DIR/id_rsa",
|
|
||||||
.publickey = "SSH_DIR/id_rsa.pub",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.privatekey = NULL,
|
|
||||||
.publickey = NULL
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Tries to automaticaly authenticate with public key and "none"
|
* @brief Tries to automaticaly authenticate with public key and "none"
|
||||||
*
|
*
|
||||||
@@ -812,16 +786,12 @@ static struct ssh_keys_struct keytab[] = {
|
|||||||
*
|
*
|
||||||
* @see ssh_userauth_kbdint()
|
* @see ssh_userauth_kbdint()
|
||||||
* @see ssh_userauth_password()
|
* @see ssh_userauth_password()
|
||||||
* @see ssh_options_set()
|
|
||||||
*/
|
*/
|
||||||
int ssh_userauth_autopubkey(ssh_session session, const char *passphrase) {
|
int ssh_userauth_autopubkey(ssh_session session, const char *passphrase) {
|
||||||
struct ssh_public_key_struct *publickey;
|
struct ssh_iterator *it;
|
||||||
ssh_string pubkey;
|
|
||||||
ssh_private_key privkey;
|
ssh_private_key privkey;
|
||||||
char *privkeyfile = NULL;
|
ssh_public_key pubkey;
|
||||||
char *id = NULL;
|
ssh_string pubkey_string;
|
||||||
size_t size;
|
|
||||||
unsigned int i = 0;
|
|
||||||
int type = 0;
|
int type = 0;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@@ -837,142 +807,159 @@ int ssh_userauth_autopubkey(ssh_session session, const char *passphrase) {
|
|||||||
/* Try authentication with ssh-agent first */
|
/* Try authentication with ssh-agent first */
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
if (agent_is_running(session)) {
|
if (agent_is_running(session)) {
|
||||||
|
char *privkey_file = NULL;
|
||||||
|
|
||||||
ssh_log(session, SSH_LOG_RARE,
|
ssh_log(session, SSH_LOG_RARE,
|
||||||
"Trying to authenticate with SSH agent keys as user: %s",
|
"Trying to authenticate with SSH agent keys as user: %s",
|
||||||
session->username);
|
session->username);
|
||||||
|
|
||||||
for (publickey = agent_get_first_ident(session, &privkeyfile);
|
for (pubkey = agent_get_first_ident(session, &privkey_file);
|
||||||
publickey != NULL;
|
pubkey != NULL;
|
||||||
publickey = agent_get_next_ident(session, &privkeyfile)) {
|
pubkey = agent_get_next_ident(session, &privkey_file)) {
|
||||||
|
|
||||||
ssh_log(session, SSH_LOG_RARE, "Trying identity %s", privkeyfile);
|
ssh_log(session, SSH_LOG_RARE, "Trying identity %s", privkey_file);
|
||||||
|
|
||||||
pubkey = publickey_to_string(publickey);
|
pubkey_string = publickey_to_string(pubkey);
|
||||||
if (pubkey) {
|
if (pubkey_string) {
|
||||||
rc = ssh_userauth_offer_pubkey(session, NULL, publickey->type, pubkey);
|
rc = ssh_userauth_offer_pubkey(session, NULL, pubkey->type, pubkey_string);
|
||||||
string_free(pubkey);
|
string_free(pubkey_string);
|
||||||
if (rc == SSH_AUTH_ERROR) {
|
if (rc == SSH_AUTH_ERROR) {
|
||||||
SAFE_FREE(id);
|
SAFE_FREE(privkey_file);
|
||||||
SAFE_FREE(privkeyfile);
|
publickey_free(pubkey);
|
||||||
publickey_free(publickey);
|
|
||||||
leave_function();
|
leave_function();
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
} else if (rc != SSH_AUTH_SUCCESS) {
|
} else if (rc != SSH_AUTH_SUCCESS) {
|
||||||
ssh_log(session, SSH_LOG_PACKET, "Public key refused by server\n");
|
ssh_log(session, SSH_LOG_PROTOCOL, "Public key refused by server");
|
||||||
SAFE_FREE(id);
|
SAFE_FREE(privkey_file);
|
||||||
SAFE_FREE(privkeyfile);
|
publickey_free(pubkey);
|
||||||
publickey_free(publickey);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ssh_log(session, SSH_LOG_RARE, "Public key accepted");
|
ssh_log(session, SSH_LOG_RARE, "Public key accepted");
|
||||||
/* pubkey accepted by server ! */
|
/* pubkey accepted by server ! */
|
||||||
rc = ssh_userauth_agent_pubkey(session, NULL, publickey);
|
rc = ssh_userauth_agent_pubkey(session, NULL, pubkey);
|
||||||
if (rc == SSH_AUTH_ERROR) {
|
if (rc == SSH_AUTH_ERROR) {
|
||||||
SAFE_FREE(id);
|
SAFE_FREE(privkey_file);
|
||||||
SAFE_FREE(privkeyfile);
|
publickey_free(pubkey);
|
||||||
publickey_free(publickey);
|
|
||||||
leave_function();
|
leave_function();
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
} else if (rc != SSH_AUTH_SUCCESS) {
|
} else if (rc != SSH_AUTH_SUCCESS) {
|
||||||
ssh_log(session, SSH_LOG_RARE,
|
ssh_log(session, SSH_LOG_RARE,
|
||||||
"Server accepted public key but refused the signature\n"
|
"Server accepted public key but refused the signature ;"
|
||||||
"It might be a bug of libssh\n");
|
" It might be a bug of libssh");
|
||||||
SAFE_FREE(id);
|
SAFE_FREE(privkey_file);
|
||||||
SAFE_FREE(privkeyfile);
|
publickey_free(pubkey);
|
||||||
publickey_free(publickey);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* auth success */
|
/* auth success */
|
||||||
ssh_log(session, SSH_LOG_RARE, "Authentication using %s success\n",
|
ssh_log(session, SSH_LOG_PROTOCOL, "Authentication using %s success",
|
||||||
privkeyfile);
|
privkey_file);
|
||||||
SAFE_FREE(id);
|
SAFE_FREE(privkey_file);
|
||||||
SAFE_FREE(privkeyfile);
|
publickey_free(pubkey);
|
||||||
publickey_free(publickey);
|
|
||||||
|
|
||||||
leave_function();
|
leave_function();
|
||||||
|
|
||||||
return SSH_AUTH_SUCCESS;
|
return SSH_AUTH_SUCCESS;
|
||||||
} /* if pubkey */
|
} /* if pubkey */
|
||||||
SAFE_FREE(id);
|
SAFE_FREE(privkey_file);
|
||||||
SAFE_FREE(privkeyfile);
|
publickey_free(pubkey);
|
||||||
publickey_free(publickey);
|
|
||||||
} /* for each privkey */
|
} /* for each privkey */
|
||||||
} /* if agent is running */
|
} /* if agent is running */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
size = ARRAY_SIZE(keytab);
|
|
||||||
if (session->identity) {
|
|
||||||
ssh_log(session, SSH_LOG_RARE,
|
|
||||||
"Trying identity file %s\n", session->identity);
|
|
||||||
|
|
||||||
id = malloc(strlen(session->identity) + 1 + 4);
|
for (it = ssh_list_get_iterator(session->identity);
|
||||||
if (id == NULL) {
|
it != NULL;
|
||||||
leave_function();
|
it = it->next) {
|
||||||
return SSH_AUTH_ERROR;
|
const char *privkey_file = it->data;
|
||||||
}
|
int privkey_open = 0;
|
||||||
sprintf(id, "%s.pub", session->identity);
|
|
||||||
|
|
||||||
keytab[size - 1].privatekey = session->identity;
|
privkey = NULL;
|
||||||
keytab[size - 1].publickey = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0, pubkey = try_publickey_from_file(session, keytab[i],
|
ssh_log(session, SSH_LOG_PROTOCOL, "Trying to read privatekey %s", privkey_file);
|
||||||
&privkeyfile, &type);
|
|
||||||
i < size;
|
rc = ssh_try_publickey_from_file(session, privkey_file, &pubkey_string, &type);
|
||||||
pubkey = try_publickey_from_file(session, keytab[i++],
|
if (rc == 1) {
|
||||||
&privkeyfile, &type)) {
|
char *publickey_file;
|
||||||
if (pubkey == NULL) {
|
size_t len;
|
||||||
|
|
||||||
|
privkey = privatekey_from_file(session, privkey_file, type, passphrase);
|
||||||
|
if (privkey == NULL) {
|
||||||
|
ssh_log(session, SSH_LOG_RARE,
|
||||||
|
"Reading private key %s failed (bad passphrase ?)",
|
||||||
|
privkey_file);
|
||||||
|
leave_function();
|
||||||
|
return SSH_AUTH_ERROR;
|
||||||
|
}
|
||||||
|
privkey_open = 1;
|
||||||
|
|
||||||
|
pubkey = publickey_from_privatekey(privkey);
|
||||||
|
if (pubkey == NULL) {
|
||||||
|
privatekey_free(privkey);
|
||||||
|
ssh_set_error_oom(session);
|
||||||
|
leave_function();
|
||||||
|
return SSH_AUTH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
pubkey_string = publickey_to_string(pubkey);
|
||||||
|
type = pubkey->type;
|
||||||
|
publickey_free(pubkey);
|
||||||
|
if (pubkey_string == NULL) {
|
||||||
|
ssh_set_error_oom(session);
|
||||||
|
leave_function();
|
||||||
|
return SSH_AUTH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = strlen(privkey_file) + 5;
|
||||||
|
publickey_file = malloc(len);
|
||||||
|
if (publickey_file == NULL) {
|
||||||
|
ssh_set_error_oom(session);
|
||||||
|
leave_function();
|
||||||
|
return SSH_AUTH_ERROR;
|
||||||
|
}
|
||||||
|
snprintf(publickey_file, len, "%s.pub", privkey_file);
|
||||||
|
rc = ssh_publickey_to_file(session, publickey_file, pubkey_string, type);
|
||||||
|
if (rc < 0) {
|
||||||
|
ssh_log(session, SSH_LOG_PACKET,
|
||||||
|
"Could not write public key to file: %s", publickey_file);
|
||||||
|
}
|
||||||
|
SAFE_FREE(publickey_file);
|
||||||
|
} else if (rc < 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = ssh_userauth_offer_pubkey(session, NULL, type, pubkey);
|
rc = ssh_userauth_offer_pubkey(session, NULL, type, pubkey_string);
|
||||||
if (rc == SSH_AUTH_ERROR){
|
if (rc == SSH_AUTH_ERROR){
|
||||||
if (id != NULL) {
|
string_free(pubkey_string);
|
||||||
keytab[size - 1].privatekey = NULL;
|
|
||||||
keytab[size - 1].publickey = NULL;
|
|
||||||
SAFE_FREE(id);
|
|
||||||
}
|
|
||||||
string_free(pubkey);
|
|
||||||
SAFE_FREE(privkeyfile);
|
|
||||||
ssh_log(session, SSH_LOG_RARE, "Publickey authentication error");
|
ssh_log(session, SSH_LOG_RARE, "Publickey authentication error");
|
||||||
leave_function();
|
leave_function();
|
||||||
return rc;
|
return rc;
|
||||||
} else {
|
} else {
|
||||||
if (rc != SSH_AUTH_SUCCESS){
|
if (rc != SSH_AUTH_SUCCESS){
|
||||||
ssh_log(session, SSH_LOG_RARE, "Publickey refused by server");
|
ssh_log(session, SSH_LOG_PROTOCOL, "Publickey refused by server");
|
||||||
string_free(pubkey);
|
string_free(pubkey_string);
|
||||||
pubkey = NULL;
|
|
||||||
SAFE_FREE(privkeyfile);
|
|
||||||
privkeyfile = NULL;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Public key accepted by server! */
|
/* Public key accepted by server! */
|
||||||
ssh_log(session, SSH_LOG_RARE, "Trying to read privatekey %s", privkeyfile);
|
if (!privkey_open) {
|
||||||
privkey = privatekey_from_file(session, privkeyfile, type, passphrase);
|
ssh_log(session, SSH_LOG_PROTOCOL, "Trying to read privatekey %s",
|
||||||
if (privkey == NULL) {
|
privkey_file);
|
||||||
ssh_log(session, SSH_LOG_FUNCTIONS,
|
privkey = privatekey_from_file(session, privkey_file, type, passphrase);
|
||||||
"Reading private key %s failed (bad passphrase ?)",
|
if (privkey == NULL) {
|
||||||
privkeyfile);
|
ssh_log(session, SSH_LOG_RARE,
|
||||||
string_free(pubkey);
|
"Reading private key %s failed (bad passphrase ?)",
|
||||||
pubkey = NULL;
|
privkey_file);
|
||||||
SAFE_FREE(privkeyfile);
|
string_free(pubkey_string);
|
||||||
privkeyfile = NULL;
|
continue; /* continue the loop with other pubkey */
|
||||||
continue; /* continue the loop with other pubkey */
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = ssh_userauth_pubkey(session, NULL, pubkey, privkey);
|
rc = ssh_userauth_pubkey(session, NULL, pubkey_string, privkey);
|
||||||
if (rc == SSH_AUTH_ERROR) {
|
if (rc == SSH_AUTH_ERROR) {
|
||||||
if (id != NULL) {
|
string_free(pubkey_string);
|
||||||
keytab[size - 1].privatekey = NULL;
|
|
||||||
keytab[size - 1].publickey = NULL;
|
|
||||||
SAFE_FREE(id);
|
|
||||||
}
|
|
||||||
string_free(pubkey);
|
|
||||||
SAFE_FREE(privkeyfile);
|
|
||||||
privatekey_free(privkey);
|
privatekey_free(privkey);
|
||||||
leave_function();
|
leave_function();
|
||||||
return rc;
|
return rc;
|
||||||
@@ -980,39 +967,26 @@ int ssh_userauth_autopubkey(ssh_session session, const char *passphrase) {
|
|||||||
if (rc != SSH_AUTH_SUCCESS){
|
if (rc != SSH_AUTH_SUCCESS){
|
||||||
ssh_log(session, SSH_LOG_FUNCTIONS,
|
ssh_log(session, SSH_LOG_FUNCTIONS,
|
||||||
"The server accepted the public key but refused the signature");
|
"The server accepted the public key but refused the signature");
|
||||||
string_free(pubkey);
|
string_free(pubkey_string);
|
||||||
pubkey = NULL;
|
|
||||||
SAFE_FREE(privkeyfile);
|
|
||||||
privkeyfile = NULL;
|
|
||||||
privatekey_free(privkey);
|
privatekey_free(privkey);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* auth success */
|
/* auth success */
|
||||||
ssh_log(session, SSH_LOG_RARE,
|
ssh_log(session, SSH_LOG_PROTOCOL,
|
||||||
"Successfully authenticated using %s", privkeyfile);
|
"Successfully authenticated using %s", privkey_file);
|
||||||
string_free(pubkey);
|
string_free(pubkey_string);
|
||||||
privatekey_free(privkey);
|
privatekey_free(privkey);
|
||||||
SAFE_FREE(privkeyfile);
|
|
||||||
if (id != NULL) {
|
|
||||||
keytab[size - 1].privatekey = NULL;
|
|
||||||
keytab[size - 1].publickey = NULL;
|
|
||||||
SAFE_FREE(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
leave_function();
|
leave_function();
|
||||||
return SSH_AUTH_SUCCESS;
|
return SSH_AUTH_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* at this point, pubkey is NULL and so is privkeyfile */
|
/* at this point, pubkey is NULL and so is privkeyfile */
|
||||||
ssh_log(session, SSH_LOG_FUNCTIONS,
|
ssh_log(session, SSH_LOG_FUNCTIONS,
|
||||||
"Tried every public key, none matched");
|
"Tried every public key, none matched");
|
||||||
ssh_set_error(session,SSH_NO_ERROR,"No public key matched");
|
ssh_set_error(session,SSH_NO_ERROR,"No public key matched");
|
||||||
if (id) {
|
|
||||||
keytab[size - 1].privatekey = NULL;
|
|
||||||
keytab[size - 1].publickey = NULL;
|
|
||||||
SAFE_FREE(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
leave_function();
|
leave_function();
|
||||||
return SSH_AUTH_DENIED;
|
return SSH_AUTH_DENIED;
|
||||||
@@ -1370,7 +1344,7 @@ int ssh_userauth_kbdint(ssh_session session, const char *user,
|
|||||||
/* first time we call. we must ask for a challenge */
|
/* first time we call. we must ask for a challenge */
|
||||||
if (user == NULL) {
|
if (user == NULL) {
|
||||||
if ((user = session->username) == NULL) {
|
if ((user = session->username) == NULL) {
|
||||||
if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
|
if (ssh_options_apply(session) < 0) {
|
||||||
leave_function();
|
leave_function();
|
||||||
return SSH_AUTH_ERROR;
|
return SSH_AUTH_ERROR;
|
||||||
} else {
|
} else {
|
||||||
@@ -1402,7 +1376,7 @@ int ssh_userauth_kbdint(ssh_session session, const char *user,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* If we are at this point, it ss because session->kbdint exists.
|
* If we are at this point, it ss because session->kbdint exists.
|
||||||
* It means the user has set some informations there we need to send
|
* It means the user has set some information there we need to send
|
||||||
* the server and then we need to ack the status (new questions or ok
|
* the server and then we need to ack the status (new questions or ok
|
||||||
* pass in).
|
* pass in).
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -165,8 +165,10 @@ static int channel_open(ssh_channel channel, const char *type_c, int window,
|
|||||||
type_c, channel->local_channel);
|
type_c, channel->local_channel);
|
||||||
|
|
||||||
if (packet_wait(session, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, 1) != SSH_OK) {
|
if (packet_wait(session, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, 1) != SSH_OK) {
|
||||||
leave_function();
|
if(session->in_packet.type != SSH2_MSG_CHANNEL_OPEN_FAILURE) {
|
||||||
return -1;
|
leave_function();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(session->in_packet.type) {
|
switch(session->in_packet.type) {
|
||||||
@@ -552,6 +554,15 @@ static void channel_rcv_request(ssh_session session) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(strcmp(request,"keepalive@openssh.com")==0){
|
||||||
|
SAFE_FREE(request);
|
||||||
|
ssh_log(session, SSH_LOG_PROTOCOL,"Responding to Openssh's keepalive");
|
||||||
|
buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_FAILURE);
|
||||||
|
buffer_add_u32(session->out_buffer, htonl(channel->remote_channel));
|
||||||
|
packet_send(session);
|
||||||
|
leave_function();
|
||||||
|
return;
|
||||||
|
}
|
||||||
/* TODO call message_handle since it handles channel requests as messages */
|
/* TODO call message_handle since it handles channel requests as messages */
|
||||||
/* *but* reset buffer before !! */
|
/* *but* reset buffer before !! */
|
||||||
|
|
||||||
@@ -566,7 +577,7 @@ static void channel_rcv_request(ssh_session session) {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* channel_handle() is called by packet_wait(), for example when there is
|
* channel_handle() is called by packet_wait(), for example when there is
|
||||||
* channel informations to handle.
|
* channel information to handle.
|
||||||
*/
|
*/
|
||||||
void channel_handle(ssh_session session, int type){
|
void channel_handle(ssh_session session, int type){
|
||||||
enter_function();
|
enter_function();
|
||||||
@@ -785,7 +796,7 @@ void channel_free(ssh_channel channel) {
|
|||||||
*
|
*
|
||||||
* @param channel The channel to send the eof to.
|
* @param channel The channel to send the eof to.
|
||||||
*
|
*
|
||||||
* @return SSH_SUCCESS on success\n
|
* @return SSH_OK on success\n
|
||||||
* SSH_ERROR on error\n
|
* SSH_ERROR on error\n
|
||||||
*
|
*
|
||||||
* @see channel_close()
|
* @see channel_close()
|
||||||
@@ -828,7 +839,7 @@ error:
|
|||||||
*
|
*
|
||||||
* @param channel The channel to close.
|
* @param channel The channel to close.
|
||||||
*
|
*
|
||||||
* @return SSH_SUCCESS on success\n
|
* @return SSH_OK on success\n
|
||||||
* SSH_ERROR on error
|
* SSH_ERROR on error
|
||||||
*
|
*
|
||||||
* @see channel_free()
|
* @see channel_free()
|
||||||
@@ -1107,7 +1118,7 @@ error:
|
|||||||
*
|
*
|
||||||
* @param row The number of rows.
|
* @param row The number of rows.
|
||||||
*
|
*
|
||||||
* @return SSH_SUCCESS on success, SSH_ERROR on error.
|
* @return SSH_OK on success, SSH_ERROR on error.
|
||||||
*/
|
*/
|
||||||
int channel_request_pty_size(ssh_channel channel, const char *terminal,
|
int channel_request_pty_size(ssh_channel channel, const char *terminal,
|
||||||
int col, int row) {
|
int col, int row) {
|
||||||
@@ -1158,7 +1169,7 @@ error:
|
|||||||
*
|
*
|
||||||
* @param channel The channel to send the request.
|
* @param channel The channel to send the request.
|
||||||
*
|
*
|
||||||
* @return SSH_SUCCESS on success, SSH_ERROR on error.
|
* @return SSH_OK on success, SSH_ERROR on error.
|
||||||
*
|
*
|
||||||
* @see channel_request_pty_size()
|
* @see channel_request_pty_size()
|
||||||
*/
|
*/
|
||||||
@@ -1219,7 +1230,7 @@ error:
|
|||||||
*
|
*
|
||||||
* @param channel The channel to send the request.
|
* @param channel The channel to send the request.
|
||||||
*
|
*
|
||||||
* @returns SSH_SUCCESS on success, SSH_ERROR on error.
|
* @returns SSH_OK on success, SSH_ERROR on error.
|
||||||
*/
|
*/
|
||||||
int channel_request_shell(ssh_channel channel) {
|
int channel_request_shell(ssh_channel channel) {
|
||||||
#ifdef WITH_SSH1
|
#ifdef WITH_SSH1
|
||||||
@@ -1237,7 +1248,7 @@ int channel_request_shell(ssh_channel channel) {
|
|||||||
*
|
*
|
||||||
* @param subsys The subsystem to request (for example "sftp").
|
* @param subsys The subsystem to request (for example "sftp").
|
||||||
*
|
*
|
||||||
* @return SSH_SUCCESS on success, SSH_ERROR on error.
|
* @return SSH_OK on success, SSH_ERROR on error.
|
||||||
*
|
*
|
||||||
* @warning You normally don't have to call it for sftp, see sftp_new().
|
* @warning You normally don't have to call it for sftp, see sftp_new().
|
||||||
*/
|
*/
|
||||||
@@ -1359,6 +1370,7 @@ static ssh_channel channel_accept(ssh_session session, int channeltype,
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
ssh_message msg = NULL;
|
ssh_message msg = NULL;
|
||||||
|
ssh_channel channel = NULL;
|
||||||
struct ssh_iterator *iterator;
|
struct ssh_iterator *iterator;
|
||||||
int t;
|
int t;
|
||||||
|
|
||||||
@@ -1373,7 +1385,9 @@ static ssh_channel channel_accept(ssh_session session, int channeltype,
|
|||||||
if (ssh_message_type(msg) == SSH_REQUEST_CHANNEL_OPEN &&
|
if (ssh_message_type(msg) == SSH_REQUEST_CHANNEL_OPEN &&
|
||||||
ssh_message_subtype(msg) == channeltype) {
|
ssh_message_subtype(msg) == channeltype) {
|
||||||
ssh_list_remove(session->ssh_message_list, iterator);
|
ssh_list_remove(session->ssh_message_list, iterator);
|
||||||
return ssh_message_channel_request_open_reply_accept(msg);
|
channel = ssh_message_channel_request_open_reply_accept(msg);
|
||||||
|
ssh_message_free(msg);
|
||||||
|
return channel;
|
||||||
}
|
}
|
||||||
iterator = iterator->next;
|
iterator = iterator->next;
|
||||||
}
|
}
|
||||||
@@ -1582,7 +1596,7 @@ error:
|
|||||||
*
|
*
|
||||||
* @param value The value to set.
|
* @param value The value to set.
|
||||||
*
|
*
|
||||||
* @return SSH_SUCCESS on success, SSH_ERROR on error.
|
* @return SSH_OK on success, SSH_ERROR on error.
|
||||||
*
|
*
|
||||||
* @warning Some environement variables may be refused by security reasons.
|
* @warning Some environement variables may be refused by security reasons.
|
||||||
* */
|
* */
|
||||||
@@ -1633,7 +1647,7 @@ error:
|
|||||||
* @param cmd The command to execute
|
* @param cmd The command to execute
|
||||||
* (e.g. "ls ~/ -al | grep -i reports").
|
* (e.g. "ls ~/ -al | grep -i reports").
|
||||||
*
|
*
|
||||||
* @return SSH_SUCCESS on success, SSH_ERROR on error.
|
* @return SSH_OK on success, SSH_ERROR on error.
|
||||||
*
|
*
|
||||||
* @see channel_request_shell()
|
* @see channel_request_shell()
|
||||||
*/
|
*/
|
||||||
@@ -1683,7 +1697,7 @@ error:
|
|||||||
* @param signal The signal to send (without SIG prefix)
|
* @param signal The signal to send (without SIG prefix)
|
||||||
* (e.g. "TERM" or "KILL").
|
* (e.g. "TERM" or "KILL").
|
||||||
*
|
*
|
||||||
* @return SSH_SUCCESS on success, SSH_ERROR on error (including attempt to send signal via SSH-v1 session).
|
* @return SSH_OK on success, SSH_ERROR on error (including attempt to send signal via SSH-v1 session).
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int channel_request_send_signal(ssh_channel channel, const char *signal) {
|
int channel_request_send_signal(ssh_channel channel, const char *signal) {
|
||||||
@@ -1806,7 +1820,7 @@ int channel_read_buffer(ssh_channel channel, ssh_buffer buffer, uint32_t count,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
/* write the ful buffer informations */
|
/* write the ful buffer information */
|
||||||
if (buffer_add_data(buffer, buffer_get_rest(stdbuf),
|
if (buffer_add_data(buffer, buffer_get_rest(stdbuf),
|
||||||
buffer_get_rest_len(stdbuf)) < 0) {
|
buffer_get_rest_len(stdbuf)) < 0) {
|
||||||
leave_function();
|
leave_function();
|
||||||
@@ -1995,9 +2009,10 @@ int channel_poll(ssh_channel channel, int is_stderr){
|
|||||||
stdbuf = channel->stderr_buffer;
|
stdbuf = channel->stderr_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (buffer_get_rest_len(stdbuf) == 0 && channel->remote_eof == 0) {
|
if (buffer_get_rest_len(stdbuf) == 0 && channel->remote_eof == 0) {
|
||||||
if (ssh_handle_packets(channel->session) <= 0) {
|
if (ssh_handle_packets(channel->session) == SSH_ERROR) {
|
||||||
break;
|
leave_function();
|
||||||
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2137,7 +2152,7 @@ static int count_ptrs(ssh_channel *ptrs) {
|
|||||||
*
|
*
|
||||||
* @param timeout Timeout as defined by select(2).
|
* @param timeout Timeout as defined by select(2).
|
||||||
*
|
*
|
||||||
* @return SSH_SUCCESS operation successful\n
|
* @return SSH_OK operation successful\n
|
||||||
* SSH_EINTR select(2) syscall was interrupted, relaunch the function
|
* SSH_EINTR select(2) syscall was interrupted, relaunch the function
|
||||||
*/
|
*/
|
||||||
int channel_select(ssh_channel *readchans, ssh_channel *writechans,
|
int channel_select(ssh_channel *readchans, ssh_channel *writechans,
|
||||||
@@ -2147,7 +2162,7 @@ int channel_select(ssh_channel *readchans, ssh_channel *writechans,
|
|||||||
fd_set rset;
|
fd_set rset;
|
||||||
fd_set wset;
|
fd_set wset;
|
||||||
fd_set eset;
|
fd_set eset;
|
||||||
int fdmax = -1;
|
socket_t max_fd = SSH_INVALID_SOCKET;
|
||||||
int rc;
|
int rc;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -2215,24 +2230,24 @@ int channel_select(ssh_channel *readchans, ssh_channel *writechans,
|
|||||||
|
|
||||||
for (i = 0; readchans[i] != NULL; i++) {
|
for (i = 0; readchans[i] != NULL; i++) {
|
||||||
if (!ssh_socket_fd_isset(readchans[i]->session->socket, &rset)) {
|
if (!ssh_socket_fd_isset(readchans[i]->session->socket, &rset)) {
|
||||||
ssh_socket_fd_set(readchans[i]->session->socket, &rset, &fdmax);
|
ssh_socket_fd_set(readchans[i]->session->socket, &rset, &max_fd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; writechans[i] != NULL; i++) {
|
for (i = 0; writechans[i] != NULL; i++) {
|
||||||
if (!ssh_socket_fd_isset(writechans[i]->session->socket, &wset)) {
|
if (!ssh_socket_fd_isset(writechans[i]->session->socket, &wset)) {
|
||||||
ssh_socket_fd_set(writechans[i]->session->socket, &wset, &fdmax);
|
ssh_socket_fd_set(writechans[i]->session->socket, &wset, &max_fd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; exceptchans[i] != NULL; i++) {
|
for (i = 0; exceptchans[i] != NULL; i++) {
|
||||||
if (!ssh_socket_fd_isset(exceptchans[i]->session->socket, &eset)) {
|
if (!ssh_socket_fd_isset(exceptchans[i]->session->socket, &eset)) {
|
||||||
ssh_socket_fd_set(exceptchans[i]->session->socket, &eset, &fdmax);
|
ssh_socket_fd_set(exceptchans[i]->session->socket, &eset, &max_fd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Here we go */
|
/* Here we go */
|
||||||
rc = select(fdmax, &rset, &wset, &eset, timeout);
|
rc = select(max_fd, &rset, &wset, &eset, timeout);
|
||||||
/* Leave if select was interrupted */
|
/* Leave if select was interrupted */
|
||||||
if (rc == EINTR) {
|
if (rc == EINTR) {
|
||||||
SAFE_FREE(rchans);
|
SAFE_FREE(rchans);
|
||||||
|
|||||||
@@ -26,6 +26,9 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#endif
|
||||||
#include "libssh/priv.h"
|
#include "libssh/priv.h"
|
||||||
#include "libssh/ssh1.h"
|
#include "libssh/ssh1.h"
|
||||||
#include "libssh/buffer.h"
|
#include "libssh/buffer.h"
|
||||||
|
|||||||
@@ -296,6 +296,7 @@ static int dh_handshake(ssh_session session) {
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
session->dh_server_signature = signature;
|
session->dh_server_signature = signature;
|
||||||
|
signature=NULL; /* ownership changed */
|
||||||
if (dh_build_k(session) < 0) {
|
if (dh_build_k(session) < 0) {
|
||||||
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
|
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
|
||||||
rc = SSH_ERROR;
|
rc = SSH_ERROR;
|
||||||
@@ -400,10 +401,6 @@ error:
|
|||||||
string_burn(f);
|
string_burn(f);
|
||||||
string_free(f);
|
string_free(f);
|
||||||
}
|
}
|
||||||
if(pubkey != NULL){
|
|
||||||
string_burn(pubkey);
|
|
||||||
string_free(pubkey);
|
|
||||||
}
|
|
||||||
if(signature != NULL){
|
if(signature != NULL){
|
||||||
string_burn(signature);
|
string_burn(signature);
|
||||||
string_free(signature);
|
string_free(signature);
|
||||||
@@ -484,7 +481,8 @@ int ssh_service_request(ssh_session session, const char *service) {
|
|||||||
int ssh_connect(ssh_session session) {
|
int ssh_connect(ssh_session session) {
|
||||||
int ssh1 = 0;
|
int ssh1 = 0;
|
||||||
int ssh2 = 0;
|
int ssh2 = 0;
|
||||||
int fd = -1;
|
socket_t fd = SSH_INVALID_SOCKET;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (session == NULL) {
|
if (session == NULL) {
|
||||||
ssh_set_error(session, SSH_FATAL, "Invalid session pointer");
|
ssh_set_error(session, SSH_FATAL, "Invalid session pointer");
|
||||||
@@ -500,18 +498,31 @@ int ssh_connect(ssh_session session) {
|
|||||||
leave_function();
|
leave_function();
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
if (session->fd == -1 && session->host == NULL) {
|
if (session->fd == SSH_INVALID_SOCKET && session->host == NULL &&
|
||||||
|
session->ProxyCommand == NULL) {
|
||||||
ssh_set_error(session, SSH_FATAL, "Hostname required");
|
ssh_set_error(session, SSH_FATAL, "Hostname required");
|
||||||
leave_function();
|
leave_function();
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
if (session->fd != -1) {
|
|
||||||
|
ret = ssh_options_apply(session);
|
||||||
|
if (ret < 0) {
|
||||||
|
ssh_set_error(session, SSH_FATAL, "Couldn't apply options");
|
||||||
|
leave_function();
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session->fd != SSH_INVALID_SOCKET) {
|
||||||
fd = session->fd;
|
fd = session->fd;
|
||||||
|
#ifndef _WIN32
|
||||||
|
} else if (session->ProxyCommand != NULL) {
|
||||||
|
fd=ssh_socket_connect_proxycommand(session, session->ProxyCommand);
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
fd = ssh_connect_host(session, session->host, session->bindaddr,
|
fd = ssh_connect_host(session, session->host, session->bindaddr,
|
||||||
session->port, session->timeout, session->timeout_usec);
|
session->port, session->timeout, session->timeout_usec);
|
||||||
}
|
}
|
||||||
if (fd < 0) {
|
if (fd == SSH_INVALID_SOCKET) {
|
||||||
leave_function();
|
leave_function();
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
@@ -699,7 +710,7 @@ error:
|
|||||||
const char *ssh_copyright(void) {
|
const char *ssh_copyright(void) {
|
||||||
return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2008 Aris Adamantiadis "
|
return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2008 Aris Adamantiadis "
|
||||||
"(aris@0xbadc0de.be) Distributed under the LGPL, please refer to COPYING"
|
"(aris@0xbadc0de.be) Distributed under the LGPL, please refer to COPYING"
|
||||||
"file for informations about your rights";
|
"file for information about your rights";
|
||||||
}
|
}
|
||||||
/** @} */
|
/** @} */
|
||||||
/* vim: set ts=2 sw=2 et cindent: */
|
/* vim: set ts=2 sw=2 et cindent: */
|
||||||
|
|||||||
@@ -35,11 +35,11 @@ enum ssh_config_opcode_e {
|
|||||||
SOC_PORT,
|
SOC_PORT,
|
||||||
SOC_USERNAME,
|
SOC_USERNAME,
|
||||||
SOC_IDENTITY,
|
SOC_IDENTITY,
|
||||||
SOC_CIPHER,
|
|
||||||
SOC_CIPHERS,
|
SOC_CIPHERS,
|
||||||
SOC_COMPRESSION,
|
SOC_COMPRESSION,
|
||||||
SOC_TIMEOUT,
|
SOC_TIMEOUT,
|
||||||
SOC_PROTOCOL
|
SOC_PROTOCOL,
|
||||||
|
SOC_PROXYCOMMAND
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ssh_config_keyword_table_s {
|
struct ssh_config_keyword_table_s {
|
||||||
@@ -53,11 +53,11 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
|
|||||||
{ "port", SOC_PORT },
|
{ "port", SOC_PORT },
|
||||||
{ "user", SOC_USERNAME },
|
{ "user", SOC_USERNAME },
|
||||||
{ "identityfile", SOC_IDENTITY },
|
{ "identityfile", SOC_IDENTITY },
|
||||||
{ "cipher", SOC_CIPHER },
|
|
||||||
{ "ciphers", SOC_CIPHERS },
|
{ "ciphers", SOC_CIPHERS },
|
||||||
{ "compression", SOC_COMPRESSION },
|
{ "compression", SOC_COMPRESSION },
|
||||||
{ "connecttimeout", SOC_TIMEOUT },
|
{ "connecttimeout", SOC_TIMEOUT },
|
||||||
{ "protocol", SOC_PROTOCOL },
|
{ "protocol", SOC_PROTOCOL },
|
||||||
|
{ "proxycommand", SOC_PROXYCOMMAND },
|
||||||
{ NULL, SOC_UNSUPPORTED }
|
{ NULL, SOC_UNSUPPORTED }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -199,21 +199,25 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SOC_PORT:
|
case SOC_PORT:
|
||||||
p = ssh_config_get_str(&s, NULL);
|
if (session->port == 22) {
|
||||||
if (p && *parsing) {
|
p = ssh_config_get_str(&s, NULL);
|
||||||
ssh_options_set(session, SSH_OPTIONS_PORT_STR, p);
|
if (p && *parsing) {
|
||||||
|
ssh_options_set(session, SSH_OPTIONS_PORT_STR, p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SOC_USERNAME:
|
case SOC_USERNAME:
|
||||||
p = ssh_config_get_str(&s, NULL);
|
if (session->username == NULL) {
|
||||||
if (p && *parsing) {
|
p = ssh_config_get_str(&s, NULL);
|
||||||
ssh_options_set(session, SSH_OPTIONS_USER, p);
|
if (p && *parsing) {
|
||||||
|
ssh_options_set(session, SSH_OPTIONS_USER, p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SOC_IDENTITY:
|
case SOC_IDENTITY:
|
||||||
p = ssh_config_get_str(&s, NULL);
|
p = ssh_config_get_str(&s, NULL);
|
||||||
if (p && *parsing) {
|
if (p && *parsing) {
|
||||||
ssh_options_set(session, SSH_OPTIONS_IDENTITY, p);
|
ssh_options_set(session, SSH_OPTIONS_ADD_IDENTITY, p);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SOC_CIPHERS:
|
case SOC_CIPHERS:
|
||||||
@@ -227,8 +231,8 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
|
|||||||
i = ssh_config_get_yesno(&s, -1);
|
i = ssh_config_get_yesno(&s, -1);
|
||||||
if (i >= 0 && *parsing) {
|
if (i >= 0 && *parsing) {
|
||||||
if (i) {
|
if (i) {
|
||||||
ssh_options_set(session, SSH_OPTIONS_COMPRESSION_C_S, "zlib");
|
ssh_options_set(session, SSH_OPTIONS_COMPRESSION_C_S, "zlib,none");
|
||||||
ssh_options_set(session, SSH_OPTIONS_COMPRESSION_S_C, "zlib");
|
ssh_options_set(session, SSH_OPTIONS_COMPRESSION_S_C, "zlib,none");
|
||||||
} else {
|
} else {
|
||||||
ssh_options_set(session, SSH_OPTIONS_COMPRESSION_C_S, "none");
|
ssh_options_set(session, SSH_OPTIONS_COMPRESSION_C_S, "none");
|
||||||
ssh_options_set(session, SSH_OPTIONS_COMPRESSION_S_C, "none");
|
ssh_options_set(session, SSH_OPTIONS_COMPRESSION_S_C, "none");
|
||||||
@@ -272,11 +276,19 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
|
|||||||
ssh_options_set(session, SSH_OPTIONS_TIMEOUT, &i);
|
ssh_options_set(session, SSH_OPTIONS_TIMEOUT, &i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case SOC_PROXYCOMMAND:
|
||||||
|
p = ssh_config_get_str(&s, NULL);
|
||||||
|
if (p && *parsing) {
|
||||||
|
ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, p);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case SOC_UNSUPPORTED:
|
case SOC_UNSUPPORTED:
|
||||||
fprintf(stderr, "Unsupported option: %s, line: %d\n", keyword, count);
|
ssh_log(session, SSH_LOG_RARE, "Unsupported option: %s, line: %d\n",
|
||||||
|
keyword, count);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "ERROR - unimplemented opcode: %d\n", opcode);
|
ssh_set_error(session, SSH_FATAL, "ERROR - unimplemented opcode: %d\n",
|
||||||
|
opcode);
|
||||||
SAFE_FREE(x);
|
SAFE_FREE(x);
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -341,7 +341,6 @@ socket_t ssh_connect_host(ssh_session session, const char *host,
|
|||||||
ssh_set_error(session, SSH_FATAL, "Connect failed: %s", strerror(errno));
|
ssh_set_error(session, SSH_FATAL, "Connect failed: %s", strerror(errno));
|
||||||
ssh_connect_socket_close(s);
|
ssh_connect_socket_close(s);
|
||||||
s = -1;
|
s = -1;
|
||||||
leave_function();
|
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
/* We are connected */
|
/* We are connected */
|
||||||
@@ -391,6 +390,7 @@ int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
|
|||||||
fd_set *readfds, struct timeval *timeout) {
|
fd_set *readfds, struct timeval *timeout) {
|
||||||
struct timeval zerotime;
|
struct timeval zerotime;
|
||||||
fd_set localset, localset2;
|
fd_set localset, localset2;
|
||||||
|
socket_t f;
|
||||||
int rep;
|
int rep;
|
||||||
int set;
|
int set;
|
||||||
int i;
|
int i;
|
||||||
@@ -431,8 +431,8 @@ int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
|
|||||||
|
|
||||||
/* Look into the localset for active fd */
|
/* Look into the localset for active fd */
|
||||||
set = 0;
|
set = 0;
|
||||||
for (i = 0; (i < maxfd) && !set; i++) {
|
for (f = 0; (f < maxfd) && !set; f++) {
|
||||||
if (FD_ISSET(i, &localset)) {
|
if (FD_ISSET(f, &localset)) {
|
||||||
set = 1;
|
set = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -494,9 +494,9 @@ int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
|
|||||||
outchannels[j] = NULL;
|
outchannels[j] = NULL;
|
||||||
|
|
||||||
FD_ZERO(&localset2);
|
FD_ZERO(&localset2);
|
||||||
for (i = 0; i < maxfd; i++) {
|
for (f = 0; f < maxfd; f++) {
|
||||||
if (FD_ISSET(i, readfds) && FD_ISSET(i, &localset)) {
|
if (FD_ISSET(f, readfds) && FD_ISSET(i, &localset)) {
|
||||||
FD_SET(i, &localset2);
|
FD_SET(f, &localset2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -831,8 +831,11 @@ int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash) {
|
|||||||
if (session == NULL || hash == NULL) {
|
if (session == NULL || hash == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
*hash = NULL;
|
*hash = NULL;
|
||||||
|
if (session->current_crypto == NULL ||
|
||||||
|
session->current_crypto->server_pubkey == NULL){
|
||||||
|
ssh_set_error(session,SSH_FATAL,"No current cryptographic context");
|
||||||
|
}
|
||||||
|
|
||||||
h = malloc(sizeof(unsigned char *) * MD5_DIGEST_LEN);
|
h = malloc(sizeof(unsigned char *) * MD5_DIGEST_LEN);
|
||||||
if (h == NULL) {
|
if (h == NULL) {
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ int ssh_init(void) {
|
|||||||
int ssh_finalize(void) {
|
int ssh_finalize(void) {
|
||||||
ssh_regex_finalize();
|
ssh_regex_finalize();
|
||||||
ssh_crypto_finalize();
|
ssh_crypto_finalize();
|
||||||
|
ssh_socket_cleanup();
|
||||||
#ifdef HAVE_LIBGCRYPT
|
#ifdef HAVE_LIBGCRYPT
|
||||||
gcry_control(GCRYCTL_TERM_SECMEM);
|
gcry_control(GCRYCTL_TERM_SECMEM);
|
||||||
#elif defined HAVE_LIBCRYPTO
|
#elif defined HAVE_LIBCRYPTO
|
||||||
|
|||||||
72
libssh/kex.c
72
libssh/kex.c
@@ -40,10 +40,11 @@
|
|||||||
#include "libssh/wrapper.h"
|
#include "libssh/wrapper.h"
|
||||||
#include "libssh/keys.h"
|
#include "libssh/keys.h"
|
||||||
#include "libssh/dh.h"
|
#include "libssh/dh.h"
|
||||||
|
#include "libssh/string.h"
|
||||||
|
|
||||||
#ifdef HAVE_LIBGCRYPT
|
#ifdef HAVE_LIBGCRYPT
|
||||||
#define BLOWFISH "blowfish-cbc,"
|
#define BLOWFISH "blowfish-cbc,"
|
||||||
#define AES "aes256-cbc,aes192-cbc,aes128-cbc,"
|
#define AES "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,"
|
||||||
#define DES "3des-cbc"
|
#define DES "3des-cbc"
|
||||||
#elif defined HAVE_LIBCRYPTO
|
#elif defined HAVE_LIBCRYPTO
|
||||||
#ifdef HAVE_OPENSSL_BLOWFISH_H
|
#ifdef HAVE_OPENSSL_BLOWFISH_H
|
||||||
@@ -52,10 +53,15 @@
|
|||||||
#define BLOWFISH ""
|
#define BLOWFISH ""
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_OPENSSL_AES_H
|
#ifdef HAVE_OPENSSL_AES_H
|
||||||
|
#ifdef BROKEN_AES_CTR
|
||||||
#define AES "aes256-cbc,aes192-cbc,aes128-cbc,"
|
#define AES "aes256-cbc,aes192-cbc,aes128-cbc,"
|
||||||
#else
|
#else
|
||||||
|
#define AES "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,"
|
||||||
|
#endif /* BROKEN_AES_CTR */
|
||||||
|
#else
|
||||||
#define AES ""
|
#define AES ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DES "3des-cbc"
|
#define DES "3des-cbc"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -67,7 +73,7 @@
|
|||||||
|
|
||||||
const char *default_methods[] = {
|
const char *default_methods[] = {
|
||||||
"diffie-hellman-group1-sha1",
|
"diffie-hellman-group1-sha1",
|
||||||
"ssh-dss,ssh-rsa",
|
"ssh-rsa,ssh-dss",
|
||||||
AES BLOWFISH DES,
|
AES BLOWFISH DES,
|
||||||
AES BLOWFISH DES,
|
AES BLOWFISH DES,
|
||||||
"hmac-sha1",
|
"hmac-sha1",
|
||||||
@@ -81,7 +87,7 @@ const char *default_methods[] = {
|
|||||||
|
|
||||||
const char *supported_methods[] = {
|
const char *supported_methods[] = {
|
||||||
"diffie-hellman-group1-sha1",
|
"diffie-hellman-group1-sha1",
|
||||||
"ssh-dss,ssh-rsa",
|
"ssh-rsa,ssh-dss",
|
||||||
AES BLOWFISH DES,
|
AES BLOWFISH DES,
|
||||||
AES BLOWFISH DES,
|
AES BLOWFISH DES,
|
||||||
"hmac-sha1",
|
"hmac-sha1",
|
||||||
@@ -194,48 +200,48 @@ char **space_tokenize(const char *chain){
|
|||||||
return tokens;
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find_matching gets 2 parameters : a list of available objects (in_d), separated by colons,*/
|
/* find_matching gets 2 parameters : a list of available objects (available_d), separated by colons,*/
|
||||||
/* and a list of prefered objects (what_d) */
|
/* and a list of preferred objects (preferred_d) */
|
||||||
/* it will return a strduped pointer on the first prefered object found in the available objects list */
|
/* it will return a strduped pointer on the first prefered object found in the available objects list */
|
||||||
|
|
||||||
char *ssh_find_matching(const char *in_d, const char *what_d){
|
char *ssh_find_matching(const char *available_d, const char *preferred_d){
|
||||||
char ** tok_in, **tok_what;
|
char ** tok_available, **tok_preferred;
|
||||||
int i_in, i_what;
|
int i_avail, i_pref;
|
||||||
char *ret;
|
char *ret;
|
||||||
|
|
||||||
if ((in_d == NULL) || (what_d == NULL)) {
|
if ((available_d == NULL) || (preferred_d == NULL)) {
|
||||||
return NULL; /* don't deal with null args */
|
return NULL; /* don't deal with null args */
|
||||||
}
|
}
|
||||||
|
|
||||||
tok_in = tokenize(in_d);
|
tok_available = tokenize(available_d);
|
||||||
if (tok_in == NULL) {
|
if (tok_available == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
tok_what = tokenize(what_d);
|
tok_preferred = tokenize(preferred_d);
|
||||||
if (tok_what == NULL) {
|
if (tok_preferred == NULL) {
|
||||||
SAFE_FREE(tok_in[0]);
|
SAFE_FREE(tok_available[0]);
|
||||||
SAFE_FREE(tok_in);
|
SAFE_FREE(tok_available);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i_in=0; tok_in[i_in]; ++i_in){
|
for(i_pref=0; tok_preferred[i_pref] ; ++i_pref){
|
||||||
for(i_what=0; tok_what[i_what] ; ++i_what){
|
for(i_avail=0; tok_available[i_avail]; ++i_avail){
|
||||||
if(!strcmp(tok_in[i_in],tok_what[i_what])){
|
if(!strcmp(tok_available[i_avail],tok_preferred[i_pref])){
|
||||||
/* match */
|
/* match */
|
||||||
ret=strdup(tok_in[i_in]);
|
ret=strdup(tok_available[i_avail]);
|
||||||
/* free the tokens */
|
/* free the tokens */
|
||||||
free(tok_in[0]);
|
free(tok_available[0]);
|
||||||
free(tok_what[0]);
|
free(tok_preferred[0]);
|
||||||
free(tok_in);
|
free(tok_available);
|
||||||
free(tok_what);
|
free(tok_preferred);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
free(tok_in[0]);
|
free(tok_available[0]);
|
||||||
free(tok_what[0]);
|
free(tok_preferred[0]);
|
||||||
free(tok_in);
|
free(tok_available);
|
||||||
free(tok_what);
|
free(tok_preferred);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,8 +493,8 @@ static int build_session_id1(ssh_session session, ssh_string servern,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_CRYPTO
|
#ifdef DEBUG_CRYPTO
|
||||||
ssh_print_hexa("host modulus",hostn->string,string_len(hostn));
|
ssh_print_hexa("host modulus",string_data(hostn),string_len(hostn));
|
||||||
ssh_print_hexa("server modulus",servern->string,string_len(servern));
|
ssh_print_hexa("server modulus",string_data(servern),string_len(servern));
|
||||||
#endif
|
#endif
|
||||||
md5_update(md5,string_data(hostn),string_len(hostn));
|
md5_update(md5,string_data(hostn),string_len(hostn));
|
||||||
md5_update(md5,string_data(servern),string_len(servern));
|
md5_update(md5,string_data(servern),string_len(servern));
|
||||||
|
|||||||
@@ -59,15 +59,15 @@
|
|||||||
#endif /* HAVE_LIBCRYPTO */
|
#endif /* HAVE_LIBCRYPTO */
|
||||||
|
|
||||||
#define MAXLINESIZE 80
|
#define MAXLINESIZE 80
|
||||||
|
#define RSA_HEADER_BEGIN "-----BEGIN RSA PRIVATE KEY-----"
|
||||||
|
#define RSA_HEADER_END "-----END RSA PRIVATE KEY-----"
|
||||||
|
#define DSA_HEADER_BEGIN "-----BEGIN DSA PRIVATE KEY-----"
|
||||||
|
#define DSA_HEADER_END "-----END DSA PRIVATE KEY-----"
|
||||||
|
|
||||||
#ifdef HAVE_LIBGCRYPT
|
#ifdef HAVE_LIBGCRYPT
|
||||||
|
|
||||||
#define MAX_KEY_SIZE 32
|
#define MAX_KEY_SIZE 32
|
||||||
#define MAX_PASSPHRASE_SIZE 1024
|
#define MAX_PASSPHRASE_SIZE 1024
|
||||||
#define RSA_HEADER_BEGIN "-----BEGIN RSA PRIVATE KEY-----"
|
|
||||||
#define RSA_HEADER_END "-----END RSA PRIVATE KEY-----"
|
|
||||||
#define DSA_HEADER_BEGIN "-----BEGIN DSA PRIVATE KEY-----"
|
|
||||||
#define DSA_HEADER_END "-----END DSA PRIVATE KEY-----"
|
|
||||||
#define ASN1_INTEGER 2
|
#define ASN1_INTEGER 2
|
||||||
#define ASN1_SEQUENCE 48
|
#define ASN1_SEQUENCE 48
|
||||||
#define PKCS5_SALT_LEN 8
|
#define PKCS5_SALT_LEN 8
|
||||||
@@ -611,6 +611,22 @@ static int pem_get_password(char *buf, int size, int rwflag, void *userdata) {
|
|||||||
}
|
}
|
||||||
#endif /* HAVE_LIBCRYPTO */
|
#endif /* HAVE_LIBCRYPTO */
|
||||||
|
|
||||||
|
static int privatekey_type_from_file(FILE *fp) {
|
||||||
|
char buffer[MAXLINESIZE] = {0};
|
||||||
|
|
||||||
|
if (!fgets(buffer, MAXLINESIZE, fp)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
fseek(fp, 0, SEEK_SET);
|
||||||
|
if (strncmp(buffer, DSA_HEADER_BEGIN, strlen(DSA_HEADER_BEGIN)) == 0) {
|
||||||
|
return TYPE_DSS;
|
||||||
|
}
|
||||||
|
if (strncmp(buffer, RSA_HEADER_BEGIN, strlen(RSA_HEADER_BEGIN)) == 0) {
|
||||||
|
return TYPE_RSA;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/** \addtogroup ssh_auth
|
/** \addtogroup ssh_auth
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
@@ -618,7 +634,7 @@ static int pem_get_password(char *buf, int size, int rwflag, void *userdata) {
|
|||||||
/** \brief Reads a SSH private key from a file
|
/** \brief Reads a SSH private key from a file
|
||||||
* \param session SSH Session
|
* \param session SSH Session
|
||||||
* \param filename Filename containing the private key
|
* \param filename Filename containing the private key
|
||||||
* \param type Type of the private key. One of TYPE_DSS or TYPE_RSA.
|
* \param type Type of the private key. One of TYPE_DSS or TYPE_RSA. Pass 0 to automatically detect the type.
|
||||||
* \param passphrase Passphrase to decrypt the private key. Set to null if none is needed or it is unknown.
|
* \param passphrase Passphrase to decrypt the private key. Set to null if none is needed or it is unknown.
|
||||||
* \returns a PRIVATE_KEY object containing the private key, or NULL if it failed.
|
* \returns a PRIVATE_KEY object containing the private key, or NULL if it failed.
|
||||||
* \see privatekey_free()
|
* \see privatekey_free()
|
||||||
@@ -649,10 +665,19 @@ ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
|
|||||||
ssh_log(session, SSH_LOG_RARE, "Trying to read %s, passphase=%s, authcb=%s",
|
ssh_log(session, SSH_LOG_RARE, "Trying to read %s, passphase=%s, authcb=%s",
|
||||||
filename, passphrase ? "true" : "false",
|
filename, passphrase ? "true" : "false",
|
||||||
session->callbacks && session->callbacks->auth_function ? "true" : "false");
|
session->callbacks && session->callbacks->auth_function ? "true" : "false");
|
||||||
|
|
||||||
|
if (type == 0) {
|
||||||
|
type = privatekey_type_from_file(file);
|
||||||
|
if (type == 0) {
|
||||||
|
fclose(file);
|
||||||
|
ssh_set_error(session, SSH_FATAL, "Invalid private key file.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TYPE_DSS:
|
case TYPE_DSS:
|
||||||
if (passphrase == NULL) {
|
if (passphrase == NULL) {
|
||||||
if (session->callbacks->auth_function) {
|
if (session->callbacks && session->callbacks->auth_function) {
|
||||||
auth_cb = session->callbacks->auth_function;
|
auth_cb = session->callbacks->auth_function;
|
||||||
auth_ud = session->callbacks->userdata;
|
auth_ud = session->callbacks->userdata;
|
||||||
|
|
||||||
@@ -731,6 +756,7 @@ ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
fclose(file);
|
||||||
ssh_set_error(session, SSH_FATAL, "Invalid private key type %d", type);
|
ssh_set_error(session, SSH_FATAL, "Invalid private key type %d", type);
|
||||||
return NULL;
|
return NULL;
|
||||||
} /* switch */
|
} /* switch */
|
||||||
@@ -754,6 +780,20 @@ ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
|
|||||||
return privkey;
|
return privkey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief returns the type of a private key
|
||||||
|
* @param privatekey[in] the private key handle
|
||||||
|
* @returns one of TYPE_RSA,TYPE_DSS,TYPE_RSA1
|
||||||
|
* @returns 0 if the type is unknown
|
||||||
|
* @see privatekey_from_file
|
||||||
|
* @see ssh_userauth_offer_pubkey
|
||||||
|
*/
|
||||||
|
int ssh_privatekey_type(ssh_private_key privatekey){
|
||||||
|
if (privatekey==NULL)
|
||||||
|
return 0;
|
||||||
|
return privatekey->type;
|
||||||
|
}
|
||||||
|
|
||||||
/* same that privatekey_from_file() but without any passphrase things. */
|
/* same that privatekey_from_file() but without any passphrase things. */
|
||||||
ssh_private_key _privatekey_from_file(void *session, const char *filename,
|
ssh_private_key _privatekey_from_file(void *session, const char *filename,
|
||||||
int type) {
|
int type) {
|
||||||
@@ -861,6 +901,79 @@ void privatekey_free(ssh_private_key prv) {
|
|||||||
SAFE_FREE(prv);
|
SAFE_FREE(prv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write a public key to a file.
|
||||||
|
*
|
||||||
|
* @param[in] session The ssh session to use.
|
||||||
|
*
|
||||||
|
* @param[in] file The filename to write the key into.
|
||||||
|
*
|
||||||
|
* @param[in] pubkey The public key to write.
|
||||||
|
*
|
||||||
|
* @param[in] type The type of the public key.
|
||||||
|
*
|
||||||
|
* @return 0 on success, -1 on error.
|
||||||
|
*/
|
||||||
|
int ssh_publickey_to_file(ssh_session session, const char *file,
|
||||||
|
ssh_string pubkey, int type) {
|
||||||
|
FILE *fp;
|
||||||
|
char *user;
|
||||||
|
char buffer[1024];
|
||||||
|
char host[256];
|
||||||
|
unsigned char *pubkey_64;
|
||||||
|
size_t len;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
pubkey_64 = bin_to_base64(pubkey->string, string_len(pubkey));
|
||||||
|
if (pubkey_64 == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
user = ssh_get_local_username(session);
|
||||||
|
if (user == NULL) {
|
||||||
|
SAFE_FREE(pubkey_64);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = gethostname(host, sizeof(host));
|
||||||
|
if (rc < 0) {
|
||||||
|
SAFE_FREE(user);
|
||||||
|
SAFE_FREE(pubkey_64);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(buffer, sizeof(buffer), "%s %s %s@%s\n",
|
||||||
|
ssh_type_to_char(type),
|
||||||
|
pubkey_64,
|
||||||
|
user,
|
||||||
|
host);
|
||||||
|
|
||||||
|
SAFE_FREE(pubkey_64);
|
||||||
|
SAFE_FREE(user);
|
||||||
|
|
||||||
|
ssh_log(session, SSH_LOG_RARE, "Trying to write public key file: %s", file);
|
||||||
|
ssh_log(session, SSH_LOG_PACKET, "public key file content: %s", buffer);
|
||||||
|
|
||||||
|
fp = fopen(file, "w+");
|
||||||
|
if (fp == NULL) {
|
||||||
|
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||||
|
"Error opening %s: %s", file, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = strlen(buffer);
|
||||||
|
if (fwrite(buffer, len, 1, fp) != 1 || ferror(fp)) {
|
||||||
|
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||||
|
"Unable to write to %s", file);
|
||||||
|
fclose(fp);
|
||||||
|
unlink(file);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/** \brief Retrieve a public key from a file
|
/** \brief Retrieve a public key from a file
|
||||||
* \param session the SSH session
|
* \param session the SSH session
|
||||||
* \param filename Filename of the key
|
* \param filename Filename of the key
|
||||||
@@ -938,10 +1051,85 @@ ssh_string publickey_from_file(ssh_session session, const char *filename,
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Try to read the public key from a given file.
|
||||||
|
*
|
||||||
|
* @param[in] session The ssh session to use.
|
||||||
|
*
|
||||||
|
* @param[in] keyfile The name of the private keyfile.
|
||||||
|
*
|
||||||
|
* @param[out] publickey A ssh_string to store the public key.
|
||||||
|
*
|
||||||
|
* @param[out] type A pointer to an integer to store the type.
|
||||||
|
*
|
||||||
|
* @return 0 on success, -1 on error or the private key doesn't
|
||||||
|
* exist, 1 if the public key doesn't exist.
|
||||||
|
*/
|
||||||
|
int ssh_try_publickey_from_file(ssh_session session, const char *keyfile,
|
||||||
|
ssh_string *publickey, int *type) {
|
||||||
|
char *pubkey_file;
|
||||||
|
size_t len;
|
||||||
|
ssh_string pubkey_string;
|
||||||
|
int pubkey_type;
|
||||||
|
|
||||||
|
if (session == NULL || keyfile == NULL || publickey == NULL || type == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session->sshdir == NULL) {
|
||||||
|
if (ssh_options_apply(session) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_log(session, SSH_LOG_PACKET, "Trying to open privatekey %s", keyfile);
|
||||||
|
if (!ssh_file_readaccess_ok(keyfile)) {
|
||||||
|
ssh_log(session, SSH_LOG_PACKET, "Failed to open privatekey %s", keyfile);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = strlen(keyfile) + 5;
|
||||||
|
pubkey_file = malloc(len);
|
||||||
|
if (pubkey_file == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
snprintf(pubkey_file, len, "%s.pub", keyfile);
|
||||||
|
|
||||||
|
ssh_log(session, SSH_LOG_PACKET, "Trying to open publickey %s",
|
||||||
|
pubkey_file);
|
||||||
|
if (!ssh_file_readaccess_ok(pubkey_file)) {
|
||||||
|
ssh_log(session, SSH_LOG_PACKET, "Failed to open publickey %s",
|
||||||
|
pubkey_file);
|
||||||
|
SAFE_FREE(pubkey_file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_log(session, SSH_LOG_PACKET, "Success opening public and private key");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We are sure both the private and public key file is readable. We return
|
||||||
|
* the public as a string, and the private filename as an argument
|
||||||
|
*/
|
||||||
|
pubkey_string = publickey_from_file(session, pubkey_file, &pubkey_type);
|
||||||
|
if (pubkey_string == NULL) {
|
||||||
|
ssh_log(session, SSH_LOG_PACKET,
|
||||||
|
"Wasn't able to open public key file %s: %s",
|
||||||
|
pubkey_file,
|
||||||
|
ssh_get_error(session));
|
||||||
|
SAFE_FREE(pubkey_file);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SAFE_FREE(pubkey_file);
|
||||||
|
|
||||||
|
*publickey = pubkey_string;
|
||||||
|
*type = pubkey_type;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
ssh_string try_publickey_from_file(ssh_session session, struct ssh_keys_struct keytab,
|
ssh_string try_publickey_from_file(ssh_session session, struct ssh_keys_struct keytab,
|
||||||
char **privkeyfile, int *type) {
|
char **privkeyfile, int *type) {
|
||||||
char *public;
|
|
||||||
char *private;
|
|
||||||
const char *priv;
|
const char *priv;
|
||||||
const char *pub;
|
const char *pub;
|
||||||
char *new;
|
char *new;
|
||||||
@@ -957,26 +1145,20 @@ ssh_string try_publickey_from_file(ssh_session session, struct ssh_keys_struct k
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (session->sshdir == NULL) {
|
if (session->sshdir == NULL) {
|
||||||
if (ssh_options_set(session, SSH_OPTIONS_SSH_DIR, NULL) < 0) {
|
if (ssh_options_apply(session) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* are them readable ? */
|
ssh_log(session, SSH_LOG_PACKET, "Trying to open publickey %s", pub);
|
||||||
public=dir_expand_dup(session,pub,1);
|
if (!ssh_file_readaccess_ok(pub)) {
|
||||||
private=dir_expand_dup(session,priv,1);
|
ssh_log(session, SSH_LOG_PACKET, "Failed to open publickey %s", pub);
|
||||||
//snprintf(public, sizeof(public), "%s/%s", session->sshdir, pub);
|
|
||||||
//snprintf(private, sizeof(private), "%s/%s", session->sshdir, priv);
|
|
||||||
|
|
||||||
ssh_log(session, SSH_LOG_PACKET, "Trying to open publickey %s", public);
|
|
||||||
if (!ssh_file_readaccess_ok(public)) {
|
|
||||||
ssh_log(session, SSH_LOG_PACKET, "Failed to open publickey %s", public);
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssh_log(session, SSH_LOG_PACKET, "Trying to open privatekey %s", private);
|
ssh_log(session, SSH_LOG_PACKET, "Trying to open privatekey %s", priv);
|
||||||
if (!ssh_file_readaccess_ok(private)) {
|
if (!ssh_file_readaccess_ok(priv)) {
|
||||||
ssh_log(session, SSH_LOG_PACKET, "Failed to open privatekey %s", private);
|
ssh_log(session, SSH_LOG_PACKET, "Failed to open privatekey %s", priv);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -986,26 +1168,24 @@ ssh_string try_publickey_from_file(ssh_session session, struct ssh_keys_struct k
|
|||||||
* We are sure both the private and public key file is readable. We return
|
* We are sure both the private and public key file is readable. We return
|
||||||
* the public as a string, and the private filename as an argument
|
* the public as a string, and the private filename as an argument
|
||||||
*/
|
*/
|
||||||
pubkey = publickey_from_file(session, public, type);
|
pubkey = publickey_from_file(session, pub, type);
|
||||||
if (pubkey == NULL) {
|
if (pubkey == NULL) {
|
||||||
ssh_log(session, SSH_LOG_PACKET,
|
ssh_log(session, SSH_LOG_PACKET,
|
||||||
"Wasn't able to open public key file %s: %s",
|
"Wasn't able to open public key file %s: %s",
|
||||||
public,
|
pub,
|
||||||
ssh_get_error(session));
|
ssh_get_error(session));
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
new = realloc(*privkeyfile, strlen(private) + 1);
|
new = realloc(*privkeyfile, strlen(priv) + 1);
|
||||||
if (new == NULL) {
|
if (new == NULL) {
|
||||||
string_free(pubkey);
|
string_free(pubkey);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
strcpy(new, private);
|
strcpy(new, priv);
|
||||||
*privkeyfile = new;
|
*privkeyfile = new;
|
||||||
error:
|
error:
|
||||||
SAFE_FREE(public);
|
|
||||||
SAFE_FREE(private);
|
|
||||||
return pubkey;
|
return pubkey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1370,7 +1550,6 @@ static int match_hashed_host(ssh_session session, const char *host,
|
|||||||
* if host key is accepted\n
|
* if host key is accepted\n
|
||||||
* SSH_SERVER_ERROR: Some error happened
|
* SSH_SERVER_ERROR: Some error happened
|
||||||
*
|
*
|
||||||
* \see ssh_options_set()
|
|
||||||
* \see ssh_get_pubkey_hash()
|
* \see ssh_get_pubkey_hash()
|
||||||
*
|
*
|
||||||
* \bug There is no current way to remove or modify an entry into the known
|
* \bug There is no current way to remove or modify an entry into the known
|
||||||
@@ -1380,6 +1559,7 @@ int ssh_is_server_known(ssh_session session) {
|
|||||||
FILE *file = NULL;
|
FILE *file = NULL;
|
||||||
char **tokens;
|
char **tokens;
|
||||||
char *host;
|
char *host;
|
||||||
|
char *hostport;
|
||||||
const char *type;
|
const char *type;
|
||||||
int match;
|
int match;
|
||||||
int ret = SSH_SERVER_NOT_KNOWN;
|
int ret = SSH_SERVER_NOT_KNOWN;
|
||||||
@@ -1387,7 +1567,7 @@ int ssh_is_server_known(ssh_session session) {
|
|||||||
enter_function();
|
enter_function();
|
||||||
|
|
||||||
if (session->knownhosts == NULL) {
|
if (session->knownhosts == NULL) {
|
||||||
if (ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, NULL) < 0) {
|
if (ssh_options_apply(session) < 0) {
|
||||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||||
"Can't find a known_hosts file");
|
"Can't find a known_hosts file");
|
||||||
leave_function();
|
leave_function();
|
||||||
@@ -1403,8 +1583,11 @@ int ssh_is_server_known(ssh_session session) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
host = lowercase(session->host);
|
host = lowercase(session->host);
|
||||||
if (host == NULL) {
|
hostport = ssh_hostport(host,session->port);
|
||||||
ssh_set_error(session, SSH_FATAL, "Not enough space!");
|
if (host == NULL || hostport == NULL) {
|
||||||
|
ssh_set_error_oom(session);
|
||||||
|
SAFE_FREE(host);
|
||||||
|
SAFE_FREE(hostport);
|
||||||
leave_function();
|
leave_function();
|
||||||
return SSH_SERVER_ERROR;
|
return SSH_SERVER_ERROR;
|
||||||
}
|
}
|
||||||
@@ -1418,10 +1601,15 @@ int ssh_is_server_known(ssh_session session) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
match = match_hashed_host(session, host, tokens[0]);
|
match = match_hashed_host(session, host, tokens[0]);
|
||||||
|
if (match == 0){
|
||||||
|
match = match_hostname(hostport, tokens[0], strlen(tokens[0]));
|
||||||
|
}
|
||||||
if (match == 0) {
|
if (match == 0) {
|
||||||
match = match_hostname(host, tokens[0], strlen(tokens[0]));
|
match = match_hostname(host, tokens[0], strlen(tokens[0]));
|
||||||
}
|
}
|
||||||
|
if (match == 0) {
|
||||||
|
match = match_hashed_host(session, hostport, tokens[0]);
|
||||||
|
}
|
||||||
if (match) {
|
if (match) {
|
||||||
/* We got a match. Now check the key type */
|
/* We got a match. Now check the key type */
|
||||||
if (strcmp(session->current_crypto->server_pubkey_type, type) != 0) {
|
if (strcmp(session->current_crypto->server_pubkey_type, type) != 0) {
|
||||||
@@ -1452,6 +1640,7 @@ int ssh_is_server_known(ssh_session session) {
|
|||||||
} while (1);
|
} while (1);
|
||||||
|
|
||||||
SAFE_FREE(host);
|
SAFE_FREE(host);
|
||||||
|
SAFE_FREE(hostport);
|
||||||
if (file != NULL) {
|
if (file != NULL) {
|
||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
@@ -1461,10 +1650,15 @@ int ssh_is_server_known(ssh_session session) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** You generaly use it when ssh_is_server_known() answered SSH_SERVER_NOT_KNOWN
|
/**
|
||||||
* \brief write the current server as known in the known hosts file. This will create the known hosts file if it does not exist.
|
* @brief Write the current server as known in the known hosts file.
|
||||||
* \param session ssh session
|
*
|
||||||
* \return 0 on success, -1 on error
|
* This will create the known hosts file if it does not exist. You generaly use
|
||||||
|
* it when ssh_is_server_known() answered SSH_SERVER_NOT_KNOWN.
|
||||||
|
*
|
||||||
|
* @param[in] session The ssh session to use.
|
||||||
|
*
|
||||||
|
* @return SSH_OK on success, SSH_ERROR on error.
|
||||||
*/
|
*/
|
||||||
int ssh_write_knownhost(ssh_session session) {
|
int ssh_write_knownhost(ssh_session session) {
|
||||||
ssh_string pubkey = session->current_crypto->server_pubkey;
|
ssh_string pubkey = session->current_crypto->server_pubkey;
|
||||||
@@ -1472,17 +1666,30 @@ int ssh_write_knownhost(ssh_session session) {
|
|||||||
char buffer[4096] = {0};
|
char buffer[4096] = {0};
|
||||||
FILE *file;
|
FILE *file;
|
||||||
char *dir;
|
char *dir;
|
||||||
|
char *host;
|
||||||
|
char *hostport;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
|
||||||
if (ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, NULL) < 0) {
|
|
||||||
ssh_set_error(session, SSH_FATAL, "Cannot find known_hosts file.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (session->host == NULL) {
|
if (session->host == NULL) {
|
||||||
ssh_set_error(session, SSH_FATAL,
|
ssh_set_error(session, SSH_FATAL,
|
||||||
"Cannot write host in known hosts if the hostname is unknown");
|
"Can't write host in known hosts if the hostname isn't known");
|
||||||
return -1;
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
host = lowercase(session->host);
|
||||||
|
/* If using a nonstandard port, save the host in the [host]:port format */
|
||||||
|
if(session->port != 22){
|
||||||
|
hostport = ssh_hostport(host,session->port);
|
||||||
|
SAFE_FREE(host);
|
||||||
|
host=hostport;
|
||||||
|
hostport=NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session->knownhosts == NULL) {
|
||||||
|
if (ssh_options_apply(session) < 0) {
|
||||||
|
ssh_set_error(session, SSH_FATAL, "Can't find a known_hosts file");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if ~/.ssh exists and create it if not */
|
/* Check if ~/.ssh exists and create it if not */
|
||||||
@@ -1506,6 +1713,7 @@ int ssh_write_knownhost(ssh_session session) {
|
|||||||
ssh_set_error(session, SSH_FATAL,
|
ssh_set_error(session, SSH_FATAL,
|
||||||
"Couldn't open known_hosts file %s for appending: %s",
|
"Couldn't open known_hosts file %s for appending: %s",
|
||||||
session->knownhosts, strerror(errno));
|
session->knownhosts, strerror(errno));
|
||||||
|
SAFE_FREE(host);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1525,6 +1733,7 @@ int ssh_write_knownhost(ssh_session session) {
|
|||||||
key = publickey_from_string(session, pubkey);
|
key = publickey_from_string(session, pubkey);
|
||||||
if (key == NULL) {
|
if (key == NULL) {
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
SAFE_FREE(host);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1533,6 +1742,7 @@ int ssh_write_knownhost(ssh_session session) {
|
|||||||
if (sexp == NULL) {
|
if (sexp == NULL) {
|
||||||
publickey_free(key);
|
publickey_free(key);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
SAFE_FREE(host);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
e = gcry_sexp_nth_mpi(sexp, 1, GCRYMPI_FMT_USG);
|
e = gcry_sexp_nth_mpi(sexp, 1, GCRYMPI_FMT_USG);
|
||||||
@@ -1540,6 +1750,7 @@ int ssh_write_knownhost(ssh_session session) {
|
|||||||
if (e == NULL) {
|
if (e == NULL) {
|
||||||
publickey_free(key);
|
publickey_free(key);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
SAFE_FREE(host);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1548,6 +1759,7 @@ int ssh_write_knownhost(ssh_session session) {
|
|||||||
publickey_free(key);
|
publickey_free(key);
|
||||||
bignum_free(e);
|
bignum_free(e);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
SAFE_FREE(host);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
n = gcry_sexp_nth_mpi(sexp, 1, GCRYMPI_FMT_USG);
|
n = gcry_sexp_nth_mpi(sexp, 1, GCRYMPI_FMT_USG);
|
||||||
@@ -1556,6 +1768,7 @@ int ssh_write_knownhost(ssh_session session) {
|
|||||||
publickey_free(key);
|
publickey_free(key);
|
||||||
bignum_free(e);
|
bignum_free(e);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
SAFE_FREE(host);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1580,12 +1793,13 @@ int ssh_write_knownhost(ssh_session session) {
|
|||||||
#endif
|
#endif
|
||||||
publickey_free(key);
|
publickey_free(key);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
SAFE_FREE(host);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(buffer, sizeof(buffer),
|
snprintf(buffer, sizeof(buffer),
|
||||||
"%s %d %s %s\n",
|
"%s %d %s %s\n",
|
||||||
session->host,
|
host,
|
||||||
rsa_size << 3,
|
rsa_size << 3,
|
||||||
e_string,
|
e_string,
|
||||||
n_string);
|
n_string);
|
||||||
@@ -1605,18 +1819,19 @@ int ssh_write_knownhost(ssh_session session) {
|
|||||||
pubkey_64 = bin_to_base64(pubkey->string, string_len(pubkey));
|
pubkey_64 = bin_to_base64(pubkey->string, string_len(pubkey));
|
||||||
if (pubkey_64 == NULL) {
|
if (pubkey_64 == NULL) {
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
SAFE_FREE(host);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(buffer, sizeof(buffer),
|
snprintf(buffer, sizeof(buffer),
|
||||||
"%s %s %s\n",
|
"%s %s %s\n",
|
||||||
session->host,
|
host,
|
||||||
session->current_crypto->server_pubkey_type,
|
session->current_crypto->server_pubkey_type,
|
||||||
pubkey_64);
|
pubkey_64);
|
||||||
|
|
||||||
SAFE_FREE(pubkey_64);
|
SAFE_FREE(pubkey_64);
|
||||||
}
|
}
|
||||||
|
SAFE_FREE(host);
|
||||||
len = strlen(buffer);
|
len = strlen(buffer);
|
||||||
if (fwrite(buffer, len, 1, file) != 1 || ferror(file)) {
|
if (fwrite(buffer, len, 1, file) != 1 || ferror(file)) {
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
#include "libssh/keys.h"
|
#include "libssh/keys.h"
|
||||||
#include "libssh/dh.h"
|
#include "libssh/dh.h"
|
||||||
#include "libssh/messages.h"
|
#include "libssh/messages.h"
|
||||||
|
#include "libssh/string.h"
|
||||||
|
|
||||||
/** \addtogroup ssh_auth
|
/** \addtogroup ssh_auth
|
||||||
* @{
|
* @{
|
||||||
@@ -130,9 +131,9 @@ ssh_public_key publickey_make_dss(ssh_session session, ssh_buffer buffer) {
|
|||||||
#endif /* HAVE_LIBCRYPTO */
|
#endif /* HAVE_LIBCRYPTO */
|
||||||
|
|
||||||
#ifdef DEBUG_CRYPTO
|
#ifdef DEBUG_CRYPTO
|
||||||
ssh_print_hexa("p", p->string, string_len(p));
|
ssh_print_hexa("p", string_data(p), string_len(p));
|
||||||
ssh_print_hexa("q", q->string, string_len(q));
|
ssh_print_hexa("q", string_data(q), string_len(q));
|
||||||
ssh_print_hexa("g", g->string, string_len(g));
|
ssh_print_hexa("g", string_data(g), string_len(g));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
string_burn(p);
|
string_burn(p);
|
||||||
@@ -206,8 +207,8 @@ ssh_public_key publickey_make_rsa(ssh_session session, ssh_buffer buffer,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DEBUG_CRYPTO
|
#ifdef DEBUG_CRYPTO
|
||||||
ssh_print_hexa("e", e->string, string_len(e));
|
ssh_print_hexa("e", string_data(e), string_len(e));
|
||||||
ssh_print_hexa("n", n->string, string_len(n));
|
ssh_print_hexa("n", string_data(n), string_len(n));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
string_burn(e);
|
string_burn(e);
|
||||||
@@ -974,8 +975,8 @@ SIGNATURE *signature_from_string(ssh_session session, ssh_string signature,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DEBUG_CRYPTO
|
#ifdef DEBUG_CRYPTO
|
||||||
ssh_print_hexa("r", rs->string, 20);
|
ssh_print_hexa("r", string_data(rs), 20);
|
||||||
ssh_print_hexa("s", rs->string + 20, 20);
|
ssh_print_hexa("s", (const unsigned char *)string_data(rs) + 20, 20);
|
||||||
#endif
|
#endif
|
||||||
string_free(rs);
|
string_free(rs);
|
||||||
|
|
||||||
@@ -1024,7 +1025,7 @@ SIGNATURE *signature_from_string(ssh_session session, ssh_string signature,
|
|||||||
|
|
||||||
#ifdef DEBUG_CRYPTO
|
#ifdef DEBUG_CRYPTO
|
||||||
ssh_log(session, SSH_LOG_FUNCTIONS, "len e: %d", len);
|
ssh_log(session, SSH_LOG_FUNCTIONS, "len e: %d", len);
|
||||||
ssh_print_hexa("RSA signature", e->string, len);
|
ssh_print_hexa("RSA signature", string_data(e), len);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LIBGCRYPT
|
#ifdef HAVE_LIBGCRYPT
|
||||||
|
|||||||
@@ -319,7 +319,6 @@ static ssh_message handle_channel_request_open(ssh_session session) {
|
|||||||
|
|
||||||
ssh_log(session, SSH_LOG_PACKET,
|
ssh_log(session, SSH_LOG_PACKET,
|
||||||
"Clients wants to open a %s channel", type_c);
|
"Clients wants to open a %s channel", type_c);
|
||||||
string_free(type);
|
|
||||||
|
|
||||||
buffer_get_u32(session->in_buffer, &sender);
|
buffer_get_u32(session->in_buffer, &sender);
|
||||||
buffer_get_u32(session->in_buffer, &window);
|
buffer_get_u32(session->in_buffer, &window);
|
||||||
@@ -331,6 +330,7 @@ static ssh_message handle_channel_request_open(ssh_session session) {
|
|||||||
|
|
||||||
if (strcmp(type_c,"session") == 0) {
|
if (strcmp(type_c,"session") == 0) {
|
||||||
msg->channel_request_open.type = SSH_CHANNEL_SESSION;
|
msg->channel_request_open.type = SSH_CHANNEL_SESSION;
|
||||||
|
string_free(type);
|
||||||
SAFE_FREE(type_c);
|
SAFE_FREE(type_c);
|
||||||
leave_function();
|
leave_function();
|
||||||
return msg;
|
return msg;
|
||||||
@@ -370,6 +370,7 @@ static ssh_message handle_channel_request_open(ssh_session session) {
|
|||||||
msg->channel_request_open.originator_port = ntohl(originator_port);
|
msg->channel_request_open.originator_port = ntohl(originator_port);
|
||||||
|
|
||||||
msg->channel_request_open.type = SSH_CHANNEL_DIRECT_TCPIP;
|
msg->channel_request_open.type = SSH_CHANNEL_DIRECT_TCPIP;
|
||||||
|
string_free(type);
|
||||||
SAFE_FREE(type_c);
|
SAFE_FREE(type_c);
|
||||||
leave_function();
|
leave_function();
|
||||||
return msg;
|
return msg;
|
||||||
@@ -409,6 +410,7 @@ static ssh_message handle_channel_request_open(ssh_session session) {
|
|||||||
msg->channel_request_open.originator_port = ntohl(originator_port);
|
msg->channel_request_open.originator_port = ntohl(originator_port);
|
||||||
|
|
||||||
msg->channel_request_open.type = SSH_CHANNEL_FORWARDED_TCPIP;
|
msg->channel_request_open.type = SSH_CHANNEL_FORWARDED_TCPIP;
|
||||||
|
string_free(type);
|
||||||
SAFE_FREE(type_c);
|
SAFE_FREE(type_c);
|
||||||
leave_function();
|
leave_function();
|
||||||
return msg;
|
return msg;
|
||||||
@@ -432,12 +434,14 @@ static ssh_message handle_channel_request_open(ssh_session session) {
|
|||||||
msg->channel_request_open.originator_port = ntohl(originator_port);
|
msg->channel_request_open.originator_port = ntohl(originator_port);
|
||||||
|
|
||||||
msg->channel_request_open.type = SSH_CHANNEL_X11;
|
msg->channel_request_open.type = SSH_CHANNEL_X11;
|
||||||
|
string_free(type);
|
||||||
SAFE_FREE(type_c);
|
SAFE_FREE(type_c);
|
||||||
leave_function();
|
leave_function();
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg->channel_request_open.type = SSH_CHANNEL_UNKNOWN;
|
msg->channel_request_open.type = SSH_CHANNEL_UNKNOWN;
|
||||||
|
string_free(type);
|
||||||
SAFE_FREE(type_c);
|
SAFE_FREE(type_c);
|
||||||
|
|
||||||
leave_function();
|
leave_function();
|
||||||
@@ -863,7 +867,7 @@ void message_handle(ssh_session session, uint32_t type){
|
|||||||
if(!session->ssh_message_list){
|
if(!session->ssh_message_list){
|
||||||
session->ssh_message_list=ssh_list_new();
|
session->ssh_message_list=ssh_list_new();
|
||||||
}
|
}
|
||||||
ssh_list_add(session->ssh_message_list,msg);
|
ssh_list_append(session->ssh_message_list,msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
283
libssh/misc.c
283
libssh/misc.c
@@ -35,15 +35,19 @@
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define _WIN32_IE 0x0501 //SHGetSpecialFolderPath
|
#define _WIN32_IE 0x0501 //SHGetSpecialFolderPath
|
||||||
#include <winsock2.h> // Must be the first to include
|
#include <winsock2.h> // Must be the first to include
|
||||||
|
#include <ws2tcpip.h>
|
||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
#else
|
#else
|
||||||
|
/* This is needed for a standard getpwuid_r on opensolaris */
|
||||||
|
#define _POSIX_PTHREAD_SEMANTICS
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "libssh/priv.h"
|
#include "libssh/priv.h"
|
||||||
#include "libssh/misc.h"
|
#include "libssh/misc.h"
|
||||||
|
#include "libssh/session.h"
|
||||||
|
|
||||||
#ifdef HAVE_LIBGCRYPT
|
#ifdef HAVE_LIBGCRYPT
|
||||||
#define GCRYPT_STRING "/gnutls"
|
#define GCRYPT_STRING "/gnutls"
|
||||||
@@ -87,25 +91,48 @@ char *ssh_get_user_home_dir(void) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we have read access on file */
|
/* we have read access on file */
|
||||||
int ssh_file_readaccess_ok(const char *file) {
|
int ssh_file_readaccess_ok(const char *file) {
|
||||||
if (_access(file, 4) < 0) {
|
if (_access(file, 4) < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SSH_USEC_IN_SEC 1000000LL
|
||||||
|
#define SSH_SECONDS_SINCE_1601 11644473600LL
|
||||||
|
|
||||||
|
int gettimeofday(struct timeval *__p, void *__t) {
|
||||||
|
union {
|
||||||
|
unsigned long long ns100; /* time since 1 Jan 1601 in 100ns units */
|
||||||
|
FILETIME ft;
|
||||||
|
} now;
|
||||||
|
|
||||||
|
GetSystemTimeAsFileTime (&now.ft);
|
||||||
|
__p->tv_usec = (long) ((now.ns100 / 10LL) % SSH_USEC_IN_SEC);
|
||||||
|
__p->tv_sec = (long)(((now.ns100 / 10LL ) / SSH_USEC_IN_SEC) - SSH_SECONDS_SINCE_1601);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
#else /* _WIN32 */
|
#else /* _WIN32 */
|
||||||
|
#ifndef NSS_BUFLEN_PASSWD
|
||||||
|
#define NSS_BUFLEN_PASSWD 4096
|
||||||
|
#endif
|
||||||
|
|
||||||
char *ssh_get_user_home_dir(void) {
|
char *ssh_get_user_home_dir(void) {
|
||||||
char *szPath = NULL;
|
char *szPath = NULL;
|
||||||
struct passwd *pwd = NULL;
|
struct passwd pwd;
|
||||||
|
struct passwd *pwdbuf;
|
||||||
|
char buf[NSS_BUFLEN_PASSWD];
|
||||||
|
int rc;
|
||||||
|
|
||||||
pwd = getpwuid(getuid());
|
rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf);
|
||||||
if (pwd == NULL) {
|
if (rc != 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
szPath = strdup(pwd->pw_dir);
|
szPath = strdup(pwd.pw_dir);
|
||||||
|
|
||||||
return szPath;
|
return szPath;
|
||||||
}
|
}
|
||||||
@@ -120,6 +147,20 @@ int ssh_file_readaccess_ok(const char *file) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
char *ssh_hostport(const char *host, int port){
|
||||||
|
char *dest;
|
||||||
|
size_t len;
|
||||||
|
if(host==NULL)
|
||||||
|
return NULL;
|
||||||
|
/* 3 for []:, 5 for 65536 and 1 for nul */
|
||||||
|
len=strlen(host) + 3 + 5 + 1;
|
||||||
|
dest=malloc(len);
|
||||||
|
if(dest==NULL)
|
||||||
|
return NULL;
|
||||||
|
snprintf(dest,len,"[%s]:%d",host,port);
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t ntohll(uint64_t a) {
|
uint64_t ntohll(uint64_t a) {
|
||||||
#ifdef WORDS_BIGENDIAN
|
#ifdef WORDS_BIGENDIAN
|
||||||
return a;
|
return a;
|
||||||
@@ -133,6 +174,52 @@ uint64_t ntohll(uint64_t a) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
char *ssh_get_local_username(ssh_session session) {
|
||||||
|
DWORD size = 0;
|
||||||
|
char *user;
|
||||||
|
|
||||||
|
/* get the size */
|
||||||
|
GetUserName(NULL, &size);
|
||||||
|
|
||||||
|
user = malloc(size);
|
||||||
|
if (user == NULL) {
|
||||||
|
ssh_set_error_oom(session);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetUserName(user, &size)) {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
char *ssh_get_local_username(ssh_session session) {
|
||||||
|
struct passwd pwd;
|
||||||
|
struct passwd *pwdbuf;
|
||||||
|
char buf[NSS_BUFLEN_PASSWD];
|
||||||
|
char *name;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf);
|
||||||
|
if (rc != 0) {
|
||||||
|
ssh_set_error(session, SSH_FATAL,
|
||||||
|
"Couldn't retrieve information for current user!");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = strdup(pwd.pw_name);
|
||||||
|
|
||||||
|
if (name == NULL) {
|
||||||
|
ssh_set_error_oom(session);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check if libssh is the required version or get the version
|
* @brief Check if libssh is the required version or get the version
|
||||||
* string.
|
* string.
|
||||||
@@ -197,7 +284,7 @@ static struct ssh_iterator *ssh_iterator_new(const void *data){
|
|||||||
return iterator;
|
return iterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ssh_list_add(struct ssh_list *list,const void *data){
|
int ssh_list_append(struct ssh_list *list,const void *data){
|
||||||
struct ssh_iterator *iterator=ssh_iterator_new(data);
|
struct ssh_iterator *iterator=ssh_iterator_new(data);
|
||||||
if(!iterator)
|
if(!iterator)
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
@@ -212,6 +299,25 @@ int ssh_list_add(struct ssh_list *list,const void *data){
|
|||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ssh_list_prepend(struct ssh_list *list, const void *data){
|
||||||
|
struct ssh_iterator *it = ssh_iterator_new(data);
|
||||||
|
|
||||||
|
if (it == NULL) {
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list->end == NULL) {
|
||||||
|
/* list is empty */
|
||||||
|
list->root = list->end = it;
|
||||||
|
} else {
|
||||||
|
/* set as new root */
|
||||||
|
it->next = list->root;
|
||||||
|
list->root = it;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SSH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
void ssh_list_remove(struct ssh_list *list, struct ssh_iterator *iterator){
|
void ssh_list_remove(struct ssh_list *list, struct ssh_iterator *iterator){
|
||||||
struct ssh_iterator *ptr,*prev;
|
struct ssh_iterator *ptr,*prev;
|
||||||
prev=NULL;
|
prev=NULL;
|
||||||
@@ -236,7 +342,14 @@ void ssh_list_remove(struct ssh_list *list, struct ssh_iterator *iterator){
|
|||||||
SAFE_FREE(iterator);
|
SAFE_FREE(iterator);
|
||||||
}
|
}
|
||||||
|
|
||||||
const void *_ssh_list_get_head(struct ssh_list *list){
|
/** @internal
|
||||||
|
* @brief Removes the top element of the list and returns the data value attached
|
||||||
|
* to it
|
||||||
|
* @param list the ssh_list
|
||||||
|
* @returns pointer to the element being stored in head, or
|
||||||
|
* NULL if the list is empty.
|
||||||
|
*/
|
||||||
|
const void *_ssh_list_pop_head(struct ssh_list *list){
|
||||||
struct ssh_iterator *iterator=list->root;
|
struct ssh_iterator *iterator=list->root;
|
||||||
const void *data;
|
const void *data;
|
||||||
if(!list->root)
|
if(!list->root)
|
||||||
@@ -381,5 +494,155 @@ int ssh_mkdir(const char *pathname, mode_t mode) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @} */
|
/**
|
||||||
/* vim: set ts=2 sw=2 et cindent: */
|
* @brief Expand a directory starting with a tilde '~'
|
||||||
|
*
|
||||||
|
* @param[in] session The ssh session to use.
|
||||||
|
*
|
||||||
|
* @param[in] d The directory to expand.
|
||||||
|
*
|
||||||
|
* @return The expanded directory, NULL on error.
|
||||||
|
*/
|
||||||
|
char *ssh_path_expand_tilde(const char *d) {
|
||||||
|
char *h, *r;
|
||||||
|
const char *p;
|
||||||
|
size_t ld;
|
||||||
|
size_t lh = 0;
|
||||||
|
|
||||||
|
if (d[0] != '~') {
|
||||||
|
return strdup(d);
|
||||||
|
}
|
||||||
|
d++;
|
||||||
|
|
||||||
|
/* handle ~user/path */
|
||||||
|
p = strchr(d, '/');
|
||||||
|
if (p != NULL && p > d) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
return strdup(d);
|
||||||
|
#else
|
||||||
|
struct passwd *pw;
|
||||||
|
size_t s = p - d;
|
||||||
|
char u[128];
|
||||||
|
|
||||||
|
if (s > sizeof(u)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memcpy(u, d, s);
|
||||||
|
u[s] = '\0';
|
||||||
|
pw = getpwnam(u);
|
||||||
|
if (pw == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ld = strlen(p);
|
||||||
|
h = strdup(pw->pw_dir);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
ld = strlen(d);
|
||||||
|
p = (char *) d;
|
||||||
|
h = ssh_get_user_home_dir();
|
||||||
|
}
|
||||||
|
if (h == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
lh = strlen(h);
|
||||||
|
|
||||||
|
r = malloc(ld + lh + 1);
|
||||||
|
if (r == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lh > 0) {
|
||||||
|
memcpy(r, h, lh);
|
||||||
|
}
|
||||||
|
memcpy(r + lh, p, ld + 1);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *ssh_path_expand_escape(ssh_session session, const char *s) {
|
||||||
|
#define MAX_BUF_SIZE 4096
|
||||||
|
char host[NI_MAXHOST];
|
||||||
|
char buf[MAX_BUF_SIZE];
|
||||||
|
char *r, *x = NULL;
|
||||||
|
const char *p;
|
||||||
|
size_t i, l;
|
||||||
|
|
||||||
|
if (strlen(s) > MAX_BUF_SIZE) {
|
||||||
|
ssh_set_error(session, SSH_FATAL, "string to expand too long");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = ssh_path_expand_tilde(s);
|
||||||
|
if (r == NULL) {
|
||||||
|
ssh_set_error_oom(session);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = r;
|
||||||
|
buf[0] = '\0';
|
||||||
|
|
||||||
|
for (i = 0; *p != '\0'; p++) {
|
||||||
|
if (*p != '%') {
|
||||||
|
buf[i] = *p;
|
||||||
|
i++;
|
||||||
|
if (i > MAX_BUF_SIZE) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
buf[i] = '\0';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
p++;
|
||||||
|
if (*p == '\0') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (*p) {
|
||||||
|
case 'd':
|
||||||
|
x = strdup(session->sshdir);
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
x = ssh_get_local_username(session);
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
if (gethostname(host, sizeof(host) == 0)) {
|
||||||
|
x = strdup(host);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
x = strdup(session->host);
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
x = strdup(session->username);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ssh_set_error(session, SSH_FATAL,
|
||||||
|
"Wrong escape sequence detected");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x == NULL) {
|
||||||
|
ssh_set_error_oom(session);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
i += strlen(x);
|
||||||
|
if (i > MAX_BUF_SIZE) {
|
||||||
|
ssh_set_error(session, SSH_FATAL,
|
||||||
|
"String too long");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
l = strlen(buf);
|
||||||
|
strcat(buf + l, x);
|
||||||
|
buf[i] = '\0';
|
||||||
|
SAFE_FREE(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(r);
|
||||||
|
return strdup(buf);
|
||||||
|
#undef MAX_BUF_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @} */
|
||||||
|
|
||||||
|
/* vim: set ts=4 sw=4 et cindent: */
|
||||||
|
|||||||
404
libssh/options.c
404
libssh/options.c
@@ -39,15 +39,22 @@
|
|||||||
#include "libssh/server.h"
|
#include "libssh/server.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup ssh_session
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Duplicate the options of a session structure.
|
* @brief Duplicate the options of a session structure.
|
||||||
*
|
*
|
||||||
* If you make several sessions with the same options this is useful. You
|
* If you make several sessions with the same options this is useful. You
|
||||||
* cannot use twice the same option structure in ssh_session_connect.
|
* cannot use twice the same option structure in ssh_session_connect.
|
||||||
*
|
*
|
||||||
* @param opt Option structure to copy.
|
* @param src The session to use to copy the options.
|
||||||
*
|
*
|
||||||
* @returns New copied option structure, NULL on error.
|
* @param dest The session to copy the options to.
|
||||||
|
*
|
||||||
|
* @returns 0 on sucess, -1 on error with errno set.
|
||||||
*
|
*
|
||||||
* @see ssh_session_connect()
|
* @see ssh_session_connect()
|
||||||
*/
|
*/
|
||||||
@@ -76,10 +83,29 @@ int ssh_options_copy(ssh_session src, ssh_session *dest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (src->identity) {
|
if (src->identity) {
|
||||||
new->identity = strdup(src->identity);
|
struct ssh_iterator *it;
|
||||||
|
|
||||||
|
new->identity = ssh_list_new();
|
||||||
if (new->identity == NULL) {
|
if (new->identity == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
it = ssh_list_get_iterator(src->identity);
|
||||||
|
while (it) {
|
||||||
|
char *id;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
id = strdup((char *) it->data);
|
||||||
|
if (id == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ssh_list_append(new->identity, id);
|
||||||
|
if (rc < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
it = it->next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src->sshdir) {
|
if (src->sshdir) {
|
||||||
@@ -117,29 +143,6 @@ int ssh_options_copy(ssh_session src, ssh_session *dest) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
static char *get_username_from_uid(ssh_session session, uid_t uid){
|
|
||||||
struct passwd *pwd = NULL;
|
|
||||||
char *name;
|
|
||||||
|
|
||||||
pwd = getpwuid(uid);
|
|
||||||
|
|
||||||
if (pwd == NULL) {
|
|
||||||
ssh_set_error(session, SSH_FATAL, "uid %d doesn't exist !", uid);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
name = strdup(pwd->pw_name);
|
|
||||||
|
|
||||||
if (name == NULL) {
|
|
||||||
ssh_set_error_oom(session);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int ssh_options_set_algo(ssh_session session, int algo,
|
int ssh_options_set_algo(ssh_session session, int algo,
|
||||||
const char *list) {
|
const char *list) {
|
||||||
if (!verify_existing_algo(algo, list)) {
|
if (!verify_existing_algo(algo, list)) {
|
||||||
@@ -159,58 +162,6 @@ int ssh_options_set_algo(ssh_session session, int algo,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *dir_expand_dup(ssh_session session, const char *value, int allowsshdir) {
|
|
||||||
char *new;
|
|
||||||
|
|
||||||
if (value[0] == '~' && value[1] == '/') {
|
|
||||||
char *homedir = ssh_get_user_home_dir();
|
|
||||||
size_t lv, lh;
|
|
||||||
|
|
||||||
if (homedir == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
lv = strlen(value + 1);
|
|
||||||
lh = strlen(homedir);
|
|
||||||
|
|
||||||
new = malloc(lv + lh + 1);
|
|
||||||
if (new == NULL) {
|
|
||||||
ssh_set_error_oom(session);
|
|
||||||
SAFE_FREE(homedir);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
memcpy(new, homedir, lh);
|
|
||||||
SAFE_FREE(homedir);
|
|
||||||
memcpy(new + lh, value + 1, lv + 1);
|
|
||||||
return new;
|
|
||||||
}
|
|
||||||
if (allowsshdir && strncmp(value, "SSH_DIR/", 8) == 0) {
|
|
||||||
size_t lv, ls;
|
|
||||||
if (session->sshdir == NULL) {
|
|
||||||
if (ssh_options_set(session, SSH_OPTIONS_SSH_DIR, NULL) < 0)
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
value += 7;
|
|
||||||
lv = strlen(value);
|
|
||||||
ls = strlen(session->sshdir);
|
|
||||||
|
|
||||||
new = malloc(lv + ls + 1);
|
|
||||||
if (new == NULL) {
|
|
||||||
ssh_set_error_oom(session);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
memcpy(new, session->sshdir, ls);
|
|
||||||
memcpy(new + ls, value, lv + 1);
|
|
||||||
return new;
|
|
||||||
}
|
|
||||||
new = strdup(value);
|
|
||||||
if (new == NULL) {
|
|
||||||
ssh_set_error_oom(session);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return new;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function can set all possible ssh options.
|
* @brief This function can set all possible ssh options.
|
||||||
*
|
*
|
||||||
@@ -219,143 +170,153 @@ char *dir_expand_dup(ssh_session session, const char *value, int allowsshdir) {
|
|||||||
* @param type The option type to set. This could be one of the
|
* @param type The option type to set. This could be one of the
|
||||||
* following:
|
* following:
|
||||||
*
|
*
|
||||||
* SSH_OPTIONS_HOST:
|
* - SSH_OPTIONS_HOST:
|
||||||
* The hostname or ip address to connect to (string).
|
* The hostname or ip address to connect to (string).
|
||||||
*
|
*
|
||||||
* SSH_OPTIONS_PORT:
|
* - SSH_OPTIONS_PORT:
|
||||||
* The port to connect to (integer).
|
* The port to connect to (integer).
|
||||||
*
|
*
|
||||||
* SSH_OPTIONS_PORT_STR:
|
* - SSH_OPTIONS_PORT_STR:
|
||||||
* The port to connect to (string).
|
* The port to connect to (string).
|
||||||
*
|
*
|
||||||
* SSH_OPTIONS_FD:
|
* - SSH_OPTIONS_FD:
|
||||||
* The file descriptor to use (socket_t).
|
* The file descriptor to use (socket_t).\n
|
||||||
*
|
* \n
|
||||||
* If you wish to open the socket yourself for a reason
|
* If you wish to open the socket yourself for a reason
|
||||||
* or another, set the file descriptor. Don't forget to
|
* or another, set the file descriptor. Don't forget to
|
||||||
* set the hostname as the hostname is used as a key in
|
* set the hostname as the hostname is used as a key in
|
||||||
* the known_host mechanism.
|
* the known_host mechanism.
|
||||||
*
|
*
|
||||||
* SSH_OPTIONS_USER:
|
* - SSH_OPTIONS_BINDADDR:
|
||||||
* The username for authentication (string).
|
* The address to bind the client to (string).
|
||||||
*
|
*
|
||||||
|
* - SSH_OPTIONS_USER:
|
||||||
|
* The username for authentication (string).\n
|
||||||
|
* \n
|
||||||
* If the value is NULL, the username is set to the
|
* If the value is NULL, the username is set to the
|
||||||
* default username.
|
* default username.
|
||||||
*
|
*
|
||||||
* SSH_OPTIONS_SSH_DIR:
|
* - SSH_OPTIONS_SSH_DIR:
|
||||||
* Set the ssh directory (format string).
|
* Set the ssh directory (format string).\n
|
||||||
*
|
* \n
|
||||||
* If the value is NULL, the directory is set to the
|
* If the value is NULL, the directory is set to the
|
||||||
* default ssh directory.
|
* default ssh directory.\n
|
||||||
*
|
* \n
|
||||||
* The ssh directory is used for files like known_hosts
|
* The ssh directory is used for files like known_hosts
|
||||||
* and identity (private and public key). It may include
|
* and identity (private and public key). It may include
|
||||||
* "%s" which will be replaced by the user home
|
* "%s" which will be replaced by the user home
|
||||||
* directory.
|
* directory.
|
||||||
*
|
*
|
||||||
* SSH_OPTIONS_KNOWNHOSTS:
|
* - SSH_OPTIONS_KNOWNHOSTS:
|
||||||
* Set the known hosts file name (format string).
|
* Set the known hosts file name (format string).\n
|
||||||
*
|
* \n
|
||||||
* If the value is NULL, the directory is set to the
|
* If the value is NULL, the directory is set to the
|
||||||
* default known hosts file, normally ~/.ssh/known_hosts.
|
* default known hosts file, normally
|
||||||
*
|
* ~/.ssh/known_hosts.\n
|
||||||
|
* \n
|
||||||
* The known hosts file is used to certify remote hosts
|
* The known hosts file is used to certify remote hosts
|
||||||
* are genuine. It may include "%s" which will be
|
* are genuine. It may include "%s" which will be
|
||||||
* replaced by the user home directory.
|
* replaced by the user home directory.
|
||||||
*
|
*
|
||||||
* SSH_OPTIONS_IDENTITY:
|
* - SSH_OPTIONS_IDENTITY:
|
||||||
* Set the identity file name (format string).
|
* Set the identity file name (format string).\n
|
||||||
*
|
* \n
|
||||||
* By default identity, id_dsa and id_rsa are checked.
|
* By default identity, id_dsa and id_rsa are checked.\n
|
||||||
*
|
* \n
|
||||||
* The identity file used authenticate with public key.
|
* The identity file used authenticate with public key.
|
||||||
* It may include "%s" which will be replaced by the
|
* It may include "%s" which will be replaced by the
|
||||||
* user home directory.
|
* user home directory.
|
||||||
*
|
*
|
||||||
* SSH_OPTIONS_TIMEOUT:
|
* - SSH_OPTIONS_TIMEOUT:
|
||||||
* Set a timeout for the connection in seconds (integer).
|
* Set a timeout for the connection in seconds (integer).
|
||||||
*
|
*
|
||||||
* SSH_OPTIONS_TIMEOUT_USEC:
|
* - SSH_OPTIONS_TIMEOUT_USEC:
|
||||||
* Set a timeout for the connection in micro seconds
|
* Set a timeout for the connection in micro seconds
|
||||||
* (integer).
|
* (integer).
|
||||||
*
|
*
|
||||||
* SSH_OPTIONS_SSH1:
|
* - SSH_OPTIONS_SSH1:
|
||||||
* Allow or deny the connection to SSH1 servers
|
* Allow or deny the connection to SSH1 servers
|
||||||
* (integer).
|
* (integer).
|
||||||
*
|
*
|
||||||
* SSH_OPTIONS_SSH2:
|
* - SSH_OPTIONS_SSH2:
|
||||||
* Allow or deny the connection to SSH2 servers
|
* Allow or deny the connection to SSH2 servers
|
||||||
* (integer).
|
* (integer).
|
||||||
*
|
*
|
||||||
* SSH_OPTIONS_LOG_VERBOSITY:
|
* - SSH_OPTIONS_LOG_VERBOSITY:
|
||||||
* Set the session logging verbosity (integer).
|
* Set the session logging verbosity (integer).\n
|
||||||
*
|
* \n
|
||||||
* The verbosity of the messages. Every log smaller or
|
* The verbosity of the messages. Every log smaller or
|
||||||
* equal to verbosity will be shown.
|
* equal to verbosity will be shown.
|
||||||
* SSH_LOG_NOLOG: No logging
|
* - SSH_LOG_NOLOG: No logging
|
||||||
* SSH_LOG_RARE: Rare conditions or warnings
|
* - SSH_LOG_RARE: Rare conditions or warnings
|
||||||
* SSH_LOG_ENTRY: API-accessible entrypoints
|
* - SSH_LOG_ENTRY: API-accessible entrypoints
|
||||||
* SSH_LOG_PACKET: Packet id and size
|
* - SSH_LOG_PACKET: Packet id and size
|
||||||
* SSH_LOG_FUNCTIONS: Function entering and leaving
|
* - SSH_LOG_FUNCTIONS: Function entering and leaving
|
||||||
*
|
|
||||||
* SSH_OPTIONS_LOG_VERBOSITY_STR:
|
|
||||||
* Set the session logging verbosity (string).
|
|
||||||
*
|
*
|
||||||
|
* - SSH_OPTIONS_LOG_VERBOSITY_STR:
|
||||||
|
* Set the session logging verbosity (string).\n
|
||||||
|
* \n
|
||||||
* The verbosity of the messages. Every log smaller or
|
* The verbosity of the messages. Every log smaller or
|
||||||
* equal to verbosity will be shown.
|
* equal to verbosity will be shown.
|
||||||
* SSH_LOG_NOLOG: No logging
|
* - SSH_LOG_NOLOG: No logging
|
||||||
* SSH_LOG_RARE: Rare conditions or warnings
|
* - SSH_LOG_RARE: Rare conditions or warnings
|
||||||
* SSH_LOG_ENTRY: API-accessible entrypoints
|
* - SSH_LOG_ENTRY: API-accessible entrypoints
|
||||||
* SSH_LOG_PACKET: Packet id and size
|
* - SSH_LOG_PACKET: Packet id and size
|
||||||
* SSH_LOG_FUNCTIONS: Function entering and leaving
|
* - SSH_LOG_FUNCTIONS: Function entering and leaving
|
||||||
*
|
* \n
|
||||||
* See the corresponding numbers in libssh.h.
|
* See the corresponding numbers in libssh.h.
|
||||||
*
|
*
|
||||||
* SSH_OPTTIONS_AUTH_CALLBACK:
|
* - SSH_OPTTIONS_AUTH_CALLBACK:
|
||||||
* Set a callback to use your own authentication function
|
* Set a callback to use your own authentication function
|
||||||
* (function pointer).
|
* (function pointer).
|
||||||
*
|
*
|
||||||
* SSH_OPTTIONS_AUTH_USERDATA:
|
* - SSH_OPTTIONS_AUTH_USERDATA:
|
||||||
* Set the user data passed to the authentication function
|
* Set the user data passed to the authentication
|
||||||
* (generic pointer).
|
* function (generic pointer).
|
||||||
*
|
*
|
||||||
* SSH_OPTTIONS_LOG_CALLBACK:
|
* - SSH_OPTTIONS_LOG_CALLBACK:
|
||||||
* Set a callback to use your own logging function
|
* Set a callback to use your own logging function
|
||||||
* (function pointer).
|
* (function pointer).
|
||||||
*
|
*
|
||||||
* SSH_OPTTIONS_LOG_USERDATA:
|
* - SSH_OPTTIONS_LOG_USERDATA:
|
||||||
* Set the user data passed to the logging function
|
* Set the user data passed to the logging function
|
||||||
* (generic pointer).
|
* (generic pointer).
|
||||||
*
|
*
|
||||||
* SSH_OPTTIONS_STATUS_CALLBACK:
|
* - SSH_OPTTIONS_STATUS_CALLBACK:
|
||||||
* Set a callback to show connection status in realtime
|
* Set a callback to show connection status in realtime
|
||||||
* (function pointer).
|
* (function pointer).\n
|
||||||
*
|
* \n
|
||||||
|
* @code
|
||||||
* fn(void *arg, float status)
|
* fn(void *arg, float status)
|
||||||
*
|
* @endcode
|
||||||
|
* \n
|
||||||
* During ssh_connect(), libssh will call the callback
|
* During ssh_connect(), libssh will call the callback
|
||||||
* with status from 0.0 to 1.0.
|
* with status from 0.0 to 1.0.
|
||||||
*
|
*
|
||||||
* SSH_OPTTIONS_STATUS_ARG:
|
* - SSH_OPTTIONS_STATUS_ARG:
|
||||||
* Set the status argument which should be passed to the
|
* Set the status argument which should be passed to the
|
||||||
* status callback (generic pointer).
|
* status callback (generic pointer).
|
||||||
*
|
*
|
||||||
* SSH_OPTIONS_CIPHERS_C_S:
|
* - SSH_OPTIONS_CIPHERS_C_S:
|
||||||
* Set the symmetric cipher client to server (string,
|
* Set the symmetric cipher client to server (string,
|
||||||
* comma-separated list).
|
* comma-separated list).
|
||||||
*
|
*
|
||||||
* SSH_OPTIONS_CIPHERS_S_C:
|
* - SSH_OPTIONS_CIPHERS_S_C:
|
||||||
* Set the symmetric cipher server to client (string,
|
* Set the symmetric cipher server to client (string,
|
||||||
* comma-separated list).
|
* comma-separated list).
|
||||||
*
|
*
|
||||||
* SSH_OPTIONS_COMPRESSION_C_S:
|
* - SSH_OPTIONS_COMPRESSION_C_S:
|
||||||
* Set the compression to use for client to server
|
* Set the compression to use for client to server
|
||||||
* communication (string, "none" or "zlib").
|
* communication (string, "none" or "zlib").
|
||||||
*
|
*
|
||||||
* SSH_OPTIONS_COMPRESSION_S_C:
|
* - SSH_OPTIONS_COMPRESSION_S_C:
|
||||||
* Set the compression to use for server to client
|
* Set the compression to use for server to client
|
||||||
* communication (string, "none" or "zlib").
|
* communication (string, "none" or "zlib").
|
||||||
*
|
*
|
||||||
|
* - SSH_OPTIONS_PROXYCOMMAND:
|
||||||
|
* Set the command to be executed in order to connect to
|
||||||
|
* server.
|
||||||
|
*
|
||||||
* @param value The value to set. This is a generic pointer and the
|
* @param value The value to set. This is a generic pointer and the
|
||||||
* datatype which is used should be set according to the
|
* datatype which is used should be set according to the
|
||||||
* type set.
|
* type set.
|
||||||
@@ -366,6 +327,7 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
|||||||
const void *value) {
|
const void *value) {
|
||||||
char *p, *q;
|
char *p, *q;
|
||||||
long int i;
|
long int i;
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (session == NULL) {
|
if (session == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -429,30 +391,35 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
|||||||
session->port = i & 0xffff;
|
session->port = i & 0xffff;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case SSH_OPTIONS_FD:
|
||||||
|
if (value == NULL) {
|
||||||
|
session->fd = -1;
|
||||||
|
} else {
|
||||||
|
socket_t *x = (socket_t *) value;
|
||||||
|
|
||||||
|
session->fd = *x & 0xffff;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SSH_OPTIONS_BINDADDR:
|
||||||
|
if (value == NULL) {
|
||||||
|
ssh_set_error_invalid(session, __FUNCTION__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
q = strdup(value);
|
||||||
|
if (q == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
SAFE_FREE(session->bindaddr);
|
||||||
|
session->bindaddr = q;
|
||||||
|
break;
|
||||||
case SSH_OPTIONS_USER:
|
case SSH_OPTIONS_USER:
|
||||||
SAFE_FREE(session->username);
|
SAFE_FREE(session->username);
|
||||||
if (value == NULL) { /* set default username */
|
if (value == NULL) { /* set default username */
|
||||||
#ifdef _WIN32
|
q = ssh_get_local_username(session);
|
||||||
DWORD size = 0;
|
|
||||||
GetUserName(NULL, &size); //Get Size
|
|
||||||
q = malloc(size);
|
|
||||||
if (q == NULL) {
|
|
||||||
ssh_set_error_oom(session);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (GetUserName(q, &size)) {
|
|
||||||
session->username = q;
|
|
||||||
} else {
|
|
||||||
SAFE_FREE(q);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#else /* _WIN32 */
|
|
||||||
q = get_username_from_uid(session, getuid());
|
|
||||||
if (q == NULL) {
|
if (q == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
session->username = q;
|
session->username = q;
|
||||||
#endif /* _WIN32 */
|
|
||||||
} else { /* username provided */
|
} else { /* username provided */
|
||||||
session->username = strdup(value);
|
session->username = strdup(value);
|
||||||
if (session->username == NULL) {
|
if (session->username == NULL) {
|
||||||
@@ -464,43 +431,47 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
|||||||
case SSH_OPTIONS_SSH_DIR:
|
case SSH_OPTIONS_SSH_DIR:
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
SAFE_FREE(session->sshdir);
|
SAFE_FREE(session->sshdir);
|
||||||
/* TODO: why ~/.ssh/ instead of ~/.ssh ? */
|
|
||||||
|
|
||||||
session->sshdir = dir_expand_dup(session, "~/.ssh/", 0);
|
session->sshdir = ssh_path_expand_tilde("~/.ssh/");
|
||||||
if (session->sshdir == NULL) {
|
if (session->sshdir == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SAFE_FREE(session->sshdir);
|
SAFE_FREE(session->sshdir);
|
||||||
session->sshdir = dir_expand_dup(session, value, 0);
|
session->sshdir = ssh_path_expand_tilde(value);
|
||||||
if (session->sshdir == NULL) {
|
if (session->sshdir == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SSH_OPTIONS_IDENTITY:
|
case SSH_OPTIONS_IDENTITY:
|
||||||
|
case SSH_OPTIONS_ADD_IDENTITY:
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
ssh_set_error_invalid(session, __FUNCTION__);
|
ssh_set_error_invalid(session, __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
SAFE_FREE(session->identity);
|
q = strdup(value);
|
||||||
session->identity = dir_expand_dup(session, value, 1);
|
if (q == NULL) {
|
||||||
if (session->identity == NULL) {
|
return -1;
|
||||||
|
}
|
||||||
|
rc = ssh_list_prepend(session->identity, q);
|
||||||
|
if (rc < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SSH_OPTIONS_KNOWNHOSTS:
|
case SSH_OPTIONS_KNOWNHOSTS:
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
SAFE_FREE(session->knownhosts);
|
SAFE_FREE(session->knownhosts);
|
||||||
session->knownhosts = dir_expand_dup(session,
|
if (session->sshdir == NULL) {
|
||||||
"SSH_DIR/known_hosts", 1);
|
return -1;
|
||||||
|
}
|
||||||
|
session->knownhosts = ssh_path_expand_escape(session, "%d/known_hosts");
|
||||||
if (session->knownhosts == NULL) {
|
if (session->knownhosts == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SAFE_FREE(session->knownhosts);
|
SAFE_FREE(session->knownhosts);
|
||||||
session->knownhosts = dir_expand_dup(session, value, 1);
|
session->knownhosts = strdup(value);
|
||||||
if (session->knownhosts == NULL) {
|
if (session->knownhosts == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -553,6 +524,7 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
|||||||
|
|
||||||
session->log_verbosity = *x & 0xffff;
|
session->log_verbosity = *x & 0xffff;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case SSH_OPTIONS_LOG_VERBOSITY_STR:
|
case SSH_OPTIONS_LOG_VERBOSITY_STR:
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
session->log_verbosity = 0 & 0xffff;
|
session->log_verbosity = 0 & 0xffff;
|
||||||
@@ -607,16 +579,34 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case SSH_OPTIONS_PROXYCOMMAND:
|
||||||
|
if (value == NULL) {
|
||||||
|
ssh_set_error_invalid(session, __FUNCTION__);
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
SAFE_FREE(session->ProxyCommand);
|
||||||
|
q = strdup(value);
|
||||||
|
if (q == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
session->ProxyCommand = q;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ssh_set_error(session, SSH_REQUEST_DENIED, "Unkown ssh option %d", type);
|
ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
/** @} */
|
||||||
|
|
||||||
#ifdef WITH_SERVER
|
#ifdef WITH_SERVER
|
||||||
|
/**
|
||||||
|
* @addtogroup ssh_server
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
static int ssh_bind_options_set_algo(ssh_bind sshbind, int algo,
|
static int ssh_bind_options_set_algo(ssh_bind sshbind, int algo,
|
||||||
const char *list) {
|
const char *list) {
|
||||||
if (!verify_existing_algo(algo, list)) {
|
if (!verify_existing_algo(algo, list)) {
|
||||||
@@ -817,7 +807,7 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ssh_set_error(sshbind, SSH_REQUEST_DENIED, "Unkown ssh option %d", type);
|
ssh_set_error(sshbind, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1040,19 +1030,91 @@ int ssh_options_parse_config(ssh_session session, const char *filename) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (session->sshdir == NULL) {
|
||||||
|
r = ssh_options_set(session, SSH_OPTIONS_SSH_DIR, NULL);
|
||||||
|
if (r < 0) {
|
||||||
|
ssh_set_error_oom(session);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* set default filename */
|
/* set default filename */
|
||||||
if (filename == NULL) {
|
if (filename == NULL) {
|
||||||
expanded_filename = dir_expand_dup(session, "SSH_DIR/config", 1);
|
expanded_filename = ssh_path_expand_escape(session, "%d/config");
|
||||||
} else {
|
} else {
|
||||||
expanded_filename = dir_expand_dup(session, filename, 1);
|
expanded_filename = ssh_path_expand_escape(session, filename);
|
||||||
}
|
}
|
||||||
if (expanded_filename == NULL)
|
if (expanded_filename == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
r = ssh_config_parse_file(session, expanded_filename);
|
r = ssh_config_parse_file(session, expanded_filename);
|
||||||
|
if (r < 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (filename == NULL) {
|
||||||
|
r = ssh_config_parse_file(session, "/etc/ssh/ssh_config");
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
free(expanded_filename);
|
free(expanded_filename);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @} */
|
int ssh_options_apply(ssh_session session) {
|
||||||
/* vim: set ts=2 sw=2 et cindent: */
|
struct ssh_iterator *it;
|
||||||
|
char *tmp;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (session->sshdir == NULL) {
|
||||||
|
rc = ssh_options_set(session, SSH_OPTIONS_SSH_DIR, NULL);
|
||||||
|
if (rc < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session->username == NULL) {
|
||||||
|
rc = ssh_options_set(session, SSH_OPTIONS_USER, NULL);
|
||||||
|
if (rc < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session->knownhosts == NULL) {
|
||||||
|
tmp = ssh_path_expand_escape(session, "%d/known_hosts");
|
||||||
|
} else {
|
||||||
|
tmp = ssh_path_expand_escape(session, session->knownhosts);
|
||||||
|
}
|
||||||
|
if (tmp == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
free(session->knownhosts);
|
||||||
|
session->knownhosts = tmp;
|
||||||
|
|
||||||
|
if (session->ProxyCommand != NULL) {
|
||||||
|
tmp = ssh_path_expand_escape(session, session->ProxyCommand);
|
||||||
|
if (tmp == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
free(session->ProxyCommand);
|
||||||
|
session->ProxyCommand = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (it = ssh_list_get_iterator(session->identity);
|
||||||
|
it != NULL;
|
||||||
|
it = it->next) {
|
||||||
|
char *id = (char *) it->data;
|
||||||
|
tmp = ssh_path_expand_escape(session, id);
|
||||||
|
if (tmp == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
free(id);
|
||||||
|
it->data = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @} */
|
||||||
|
|
||||||
|
/* vim: set ts=4 sw=4 et cindent: */
|
||||||
|
|||||||
@@ -693,6 +693,9 @@ void packet_parse(ssh_session session) {
|
|||||||
case SSH2_MSG_CHANNEL_OPEN:
|
case SSH2_MSG_CHANNEL_OPEN:
|
||||||
message_handle(session,type);
|
message_handle(session,type);
|
||||||
return;
|
return;
|
||||||
|
case SSH2_MSG_GLOBAL_REQUEST:
|
||||||
|
ssh_global_request_handle(session);
|
||||||
|
return;
|
||||||
default:
|
default:
|
||||||
ssh_log(session, SSH_LOG_RARE, "Received unhandled packet %d", type);
|
ssh_log(session, SSH_LOG_RARE, "Received unhandled packet %d", type);
|
||||||
}
|
}
|
||||||
@@ -779,6 +782,7 @@ static int packet_wait2(ssh_session session, int type, int blocking) {
|
|||||||
ssh_log(session, SSH_LOG_PACKET, "received disconnect packet");
|
ssh_log(session, SSH_LOG_PACKET, "received disconnect packet");
|
||||||
leave_function();
|
leave_function();
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
|
case SSH2_MSG_GLOBAL_REQUEST:
|
||||||
case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
|
case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
|
||||||
case SSH2_MSG_CHANNEL_DATA:
|
case SSH2_MSG_CHANNEL_DATA:
|
||||||
case SSH2_MSG_CHANNEL_EXTENDED_DATA:
|
case SSH2_MSG_CHANNEL_EXTENDED_DATA:
|
||||||
|
|||||||
@@ -30,8 +30,12 @@
|
|||||||
#ifdef WITH_PCAP
|
#ifdef WITH_PCAP
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#else
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#endif
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
|
||||||
@@ -46,13 +50,13 @@
|
|||||||
* Just for information.
|
* Just for information.
|
||||||
*/
|
*/
|
||||||
struct pcap_hdr_s {
|
struct pcap_hdr_s {
|
||||||
u_int32_t magic_number; /* magic number */
|
uint32_t magic_number; /* magic number */
|
||||||
u_int16_t version_major; /* major version number */
|
uint16_t version_major; /* major version number */
|
||||||
u_int16_t version_minor; /* minor version number */
|
uint16_t version_minor; /* minor version number */
|
||||||
int32_t thiszone; /* GMT to local correction */
|
int32_t thiszone; /* GMT to local correction */
|
||||||
u_int32_t sigfigs; /* accuracy of timestamps */
|
uint32_t sigfigs; /* accuracy of timestamps */
|
||||||
u_int32_t snaplen; /* max length of captured packets, in octets */
|
uint32_t snaplen; /* max length of captured packets, in octets */
|
||||||
u_int32_t network; /* data link type */
|
uint32_t network; /* data link type */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PCAP_MAGIC 0xa1b2c3d4
|
#define PCAP_MAGIC 0xa1b2c3d4
|
||||||
@@ -73,10 +77,10 @@ struct pcap_hdr_s {
|
|||||||
* Just for information.
|
* Just for information.
|
||||||
*/
|
*/
|
||||||
struct pcaprec_hdr_s {
|
struct pcaprec_hdr_s {
|
||||||
u_int32_t ts_sec; /* timestamp seconds */
|
uint32_t ts_sec; /* timestamp seconds */
|
||||||
u_int32_t ts_usec; /* timestamp microseconds */
|
uint32_t ts_usec; /* timestamp microseconds */
|
||||||
u_int32_t incl_len; /* number of octets of packet saved in file */
|
uint32_t incl_len; /* number of octets of packet saved in file */
|
||||||
u_int32_t orig_len; /* actual length of packet */
|
uint32_t orig_len; /* actual length of packet */
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @private
|
/** @private
|
||||||
@@ -89,15 +93,15 @@ struct ssh_pcap_context_struct {
|
|||||||
ssh_session session;
|
ssh_session session;
|
||||||
ssh_pcap_file file;
|
ssh_pcap_file file;
|
||||||
int connected;
|
int connected;
|
||||||
/* All of these informations are useful to generate
|
/* All of these information are useful to generate
|
||||||
* the dummy IP and TCP packets
|
* the dummy IP and TCP packets
|
||||||
*/
|
*/
|
||||||
u_int32_t ipsource;
|
uint32_t ipsource;
|
||||||
u_int32_t ipdest;
|
uint32_t ipdest;
|
||||||
u_int16_t portsource;
|
uint16_t portsource;
|
||||||
u_int16_t portdest;
|
uint16_t portdest;
|
||||||
u_int32_t outsequence;
|
uint32_t outsequence;
|
||||||
u_int32_t insequence;
|
uint32_t insequence;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @private
|
/** @private
|
||||||
@@ -106,7 +110,7 @@ struct ssh_pcap_context_struct {
|
|||||||
*/
|
*/
|
||||||
struct ssh_pcap_file_struct {
|
struct ssh_pcap_file_struct {
|
||||||
FILE *output;
|
FILE *output;
|
||||||
u_int16_t ipsequence;
|
uint16_t ipsequence;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -136,7 +140,7 @@ static int ssh_pcap_file_write(ssh_pcap_file pcap, ssh_buffer packet){
|
|||||||
* @brief prepends a packet with the pcap header and writes packet
|
* @brief prepends a packet with the pcap header and writes packet
|
||||||
* on file
|
* on file
|
||||||
*/
|
*/
|
||||||
int ssh_pcap_file_write_packet(ssh_pcap_file pcap, ssh_buffer packet, u_int32_t original_len){
|
int ssh_pcap_file_write_packet(ssh_pcap_file pcap, ssh_buffer packet, uint32_t original_len){
|
||||||
ssh_buffer header=buffer_new();
|
ssh_buffer header=buffer_new();
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
int err;
|
int err;
|
||||||
@@ -282,7 +286,7 @@ static int ssh_pcap_context_connect(ssh_pcap_context ctx){
|
|||||||
* @returns SSH_ERROR an error happened.
|
* @returns SSH_ERROR an error happened.
|
||||||
*/
|
*/
|
||||||
int ssh_pcap_context_write(ssh_pcap_context ctx,enum ssh_pcap_direction direction
|
int ssh_pcap_context_write(ssh_pcap_context ctx,enum ssh_pcap_direction direction
|
||||||
, void *data, u_int32_t len, u_int32_t origlen){
|
, void *data, uint32_t len, uint32_t origlen){
|
||||||
ssh_buffer ip;
|
ssh_buffer ip;
|
||||||
int err;
|
int err;
|
||||||
if(ctx==NULL || ctx->file ==NULL)
|
if(ctx==NULL || ctx->file ==NULL)
|
||||||
|
|||||||
309
libssh/poll.c
309
libssh/poll.c
@@ -3,6 +3,7 @@
|
|||||||
*
|
*
|
||||||
* This file is part of the SSH Library
|
* This file is part of the SSH Library
|
||||||
*
|
*
|
||||||
|
* Copyright (c) 2009-2010 by Andreas Schneider <mail@cynapses.org>
|
||||||
* Copyright (c) 2003-2009 by Aris Adamantiadis
|
* Copyright (c) 2003-2009 by Aris Adamantiadis
|
||||||
* Copyright (c) 2009 Aleksandar Kanchev
|
* Copyright (c) 2009 Aleksandar Kanchev
|
||||||
*
|
*
|
||||||
@@ -24,8 +25,6 @@
|
|||||||
* vim: ts=2 sw=2 et cindent
|
* vim: ts=2 sw=2 et cindent
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* This code is based on glib's gpoll */
|
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -60,177 +59,217 @@ struct ssh_poll_ctx_struct {
|
|||||||
#ifdef HAVE_POLL
|
#ifdef HAVE_POLL
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
|
|
||||||
|
void ssh_poll_init(void) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssh_poll_cleanup(void) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
|
int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
|
||||||
return poll((struct pollfd *) fds, nfds, timeout);
|
return poll((struct pollfd *) fds, nfds, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* HAVE_POLL */
|
#else /* HAVE_POLL */
|
||||||
|
|
||||||
|
typedef int (*poll_fn)(ssh_pollfd_t *, nfds_t, int);
|
||||||
|
static poll_fn ssh_poll_emu;
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) */
|
|
||||||
|
|
||||||
#include <winsock2.h>
|
|
||||||
|
|
||||||
int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
|
|
||||||
return WSAPoll(fds, nfds, timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* _WIN32_WINNT */
|
|
||||||
|
|
||||||
#ifndef STRICT
|
#ifndef STRICT
|
||||||
#define STRICT
|
#define STRICT
|
||||||
#endif
|
#endif /* STRICT */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <time.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <errno.h>
|
#include <winsock2.h>
|
||||||
|
|
||||||
static int poll_rest (HANDLE *handles, int nhandles,
|
#if (_WIN32_WINNT < 0x0600)
|
||||||
ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
|
typedef struct ssh_pollfd_struct WSAPOLLFD;
|
||||||
DWORD ready;
|
|
||||||
ssh_pollfd_t *f;
|
|
||||||
int recursed_result;
|
|
||||||
|
|
||||||
if (nhandles == 0) {
|
|
||||||
/* No handles to wait for, just the timeout */
|
|
||||||
if (timeout == INFINITE) {
|
|
||||||
ready = WAIT_FAILED;
|
|
||||||
} else {
|
|
||||||
SleepEx(timeout, 1);
|
|
||||||
ready = WAIT_TIMEOUT;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Wait for just handles */
|
|
||||||
ready = WaitForMultipleObjectsEx(nhandles, handles, FALSE, timeout, TRUE);
|
|
||||||
#if 0
|
|
||||||
if (ready == WAIT_FAILED) {
|
|
||||||
fprintf(stderr, "WaitForMultipleObjectsEx failed: %d\n", GetLastError());
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
if (ready == WAIT_FAILED) {
|
typedef int (WSAAPI* WSAPoll_FunctionType)(WSAPOLLFD fdarray[],
|
||||||
return -1;
|
ULONG nfds,
|
||||||
} else if (ready == WAIT_TIMEOUT || ready == WAIT_IO_COMPLETION) {
|
INT timeout
|
||||||
return 0;
|
);
|
||||||
} else if (ready >= WAIT_OBJECT_0 && ready < WAIT_OBJECT_0 + nhandles) {
|
|
||||||
for (f = fds; f < &fds[nfds]; f++) {
|
static WSAPoll_FunctionType wsa_poll;
|
||||||
if ((HANDLE) f->fd == handles[ready - WAIT_OBJECT_0]) {
|
|
||||||
f->revents = f->events;
|
int win_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
|
||||||
}
|
if (wsa_poll) {
|
||||||
|
return (wsa_poll)(fds, nfds, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
return SOCKET_ERROR;
|
||||||
* If no timeout and polling several handles, recurse to poll
|
|
||||||
* the rest of them.
|
|
||||||
*/
|
|
||||||
if (timeout == 0 && nhandles > 1) {
|
|
||||||
/* Remove the handle that fired */
|
|
||||||
int i;
|
|
||||||
if (ready < nhandles - 1) {
|
|
||||||
for (i = ready - WAIT_OBJECT_0 + 1; i < nhandles; i++) {
|
|
||||||
handles[i-1] = handles[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nhandles--;
|
|
||||||
recursed_result = poll_rest(handles, nhandles, fds, nfds, 0);
|
|
||||||
if (recursed_result < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return recursed_result + 1;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
|
#define WS2_LIBRARY "ws2_32.dll"
|
||||||
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
|
static HINSTANCE hlib;
|
||||||
ssh_pollfd_t *f;
|
|
||||||
int nhandles = 0;
|
#else /* _WIN32 */
|
||||||
int rc = -1;
|
#include <sys/select.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a poll(2)-emulation using select for systems not providing a native
|
||||||
|
* poll implementation.
|
||||||
|
*
|
||||||
|
* Keep in mind that select is terribly inefficient. The interface is simply not
|
||||||
|
* meant to be used with maximum descriptor value greater, say, 32 or so. With
|
||||||
|
* a value as high as 1024 on Linux you'll pay dearly in every single call.
|
||||||
|
* poll() will be orders of magnitude faster.
|
||||||
|
*/
|
||||||
|
static int bsd_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
|
||||||
|
fd_set readfds, writefds, exceptfds;
|
||||||
|
struct timeval tv, *ptv;
|
||||||
|
socket_t max_fd;
|
||||||
|
int rc;
|
||||||
|
nfds_t i;
|
||||||
|
|
||||||
if (fds == NULL) {
|
if (fds == NULL) {
|
||||||
errno = EFAULT;
|
errno = EFAULT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nfds >= MAXIMUM_WAIT_OBJECTS) {
|
FD_ZERO (&readfds);
|
||||||
errno = EINVAL;
|
FD_ZERO (&writefds);
|
||||||
return -1;
|
FD_ZERO (&exceptfds);
|
||||||
}
|
|
||||||
|
|
||||||
for (f = fds; f < &fds[nfds]; f++) {
|
/* compute fd_sets and find largest descriptor */
|
||||||
if (f->fd > 0) {
|
for (rc = -1, max_fd = 0, i = 0; i < nfds; i++) {
|
||||||
int i;
|
if (fds[i].fd == SSH_INVALID_SOCKET) {
|
||||||
|
continue;
|
||||||
/*
|
|
||||||
* Don't add the same handle several times into the array, as
|
|
||||||
* docs say that is not allowed, even if it actually does seem
|
|
||||||
* to work.
|
|
||||||
*/
|
|
||||||
for (i = 0; i < nhandles; i++) {
|
|
||||||
if (handles[i] == (HANDLE) f->fd) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#ifndef _WIN32
|
||||||
if (i == nhandles) {
|
if (fds[i].fd >= FD_SETSIZE) {
|
||||||
if (nhandles == MAXIMUM_WAIT_OBJECTS) {
|
rc = -1;
|
||||||
break;
|
break;
|
||||||
} else {
|
|
||||||
handles[nhandles++] = (HANDLE) f->fd;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
#endif
|
||||||
|
|
||||||
|
if (fds[i].events & (POLLIN | POLLRDNORM)) {
|
||||||
|
FD_SET (fds[i].fd, &readfds);
|
||||||
|
}
|
||||||
|
if (fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
|
||||||
|
FD_SET (fds[i].fd, &writefds);
|
||||||
|
}
|
||||||
|
if (fds[i].events & (POLLPRI | POLLRDBAND)) {
|
||||||
|
FD_SET (fds[i].fd, &exceptfds);
|
||||||
|
}
|
||||||
|
if (fds[i].fd > max_fd &&
|
||||||
|
(fds[i].events & (POLLIN | POLLOUT | POLLPRI |
|
||||||
|
POLLRDNORM | POLLRDBAND |
|
||||||
|
POLLWRNORM | POLLWRBAND))) {
|
||||||
|
max_fd = fds[i].fd;
|
||||||
|
rc = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeout == -1) {
|
if (max_fd == SSH_INVALID_SOCKET || rc == -1) {
|
||||||
timeout = INFINITE;
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nhandles > 1) {
|
if (timeout < 0) {
|
||||||
/*
|
ptv = NULL;
|
||||||
* First check if one or several of them are immediately
|
|
||||||
* available.
|
|
||||||
*/
|
|
||||||
rc = poll_rest(handles, nhandles, fds, nfds, 0);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If not, and we have a significant timeout, poll again with
|
|
||||||
* timeout then. Note that this will return indication for only
|
|
||||||
* one event, or only for messages. We ignore timeouts less than
|
|
||||||
* ten milliseconds as they are mostly pointless on Windows, the
|
|
||||||
* MsgWaitForMultipleObjectsEx() call will timeout right away
|
|
||||||
* anyway.
|
|
||||||
*/
|
|
||||||
if (rc == 0 && (timeout == INFINITE || timeout >= 10)) {
|
|
||||||
rc = poll_rest(handles, nhandles, fds, nfds, timeout);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
/*
|
ptv = &tv;
|
||||||
* Just polling for one thing, so no need to check first if
|
if (timeout == 0) {
|
||||||
* available immediately
|
tv.tv_sec = 0;
|
||||||
*/
|
tv.tv_usec = 0;
|
||||||
rc = poll_rest(handles, nhandles, fds, nfds, timeout);
|
} else {
|
||||||
|
tv.tv_sec = timeout / 1000;
|
||||||
|
tv.tv_usec = (timeout % 1000) * 1000;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc = select (max_fd + 1, &readfds, &writefds, &exceptfds, ptv);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
for (f = fds; f < &fds[nfds]; f++) {
|
return -1;
|
||||||
f->revents = 0;
|
|
||||||
}
|
|
||||||
errno = EBADF;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (rc = 0, i = 0; i < nfds; i++)
|
||||||
|
if (fds[i].fd >= 0) {
|
||||||
|
fds[i].revents = 0;
|
||||||
|
|
||||||
|
if (FD_ISSET(fds[i].fd, &readfds)) {
|
||||||
|
int save_errno = errno;
|
||||||
|
char data[64] = {0};
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* support for POLLHUP */
|
||||||
|
ret = recv(fds[i].fd, data, 64, MSG_PEEK);
|
||||||
|
#ifdef _WIN32
|
||||||
|
if ((ret == -1) &&
|
||||||
|
(errno == WSAESHUTDOWN || errno == WSAECONNRESET ||
|
||||||
|
errno == WSAECONNABORTED || errno == WSAENETRESET)) {
|
||||||
|
#else
|
||||||
|
if ((ret == -1) &&
|
||||||
|
(errno == ESHUTDOWN || errno == ECONNRESET ||
|
||||||
|
errno == ECONNABORTED || errno == ENETRESET)) {
|
||||||
|
#endif
|
||||||
|
fds[i].revents |= POLLHUP;
|
||||||
|
} else {
|
||||||
|
fds[i].revents |= fds[i].events & (POLLIN | POLLRDNORM);
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = save_errno;
|
||||||
|
}
|
||||||
|
if (FD_ISSET(fds[i].fd, &writefds)) {
|
||||||
|
fds[i].revents |= fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FD_ISSET(fds[i].fd, &exceptfds)) {
|
||||||
|
fds[i].revents |= fds[i].events & (POLLPRI | POLLRDBAND);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fds[i].revents & ~POLLHUP) {
|
||||||
|
rc++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fds[i].revents = POLLNVAL;
|
||||||
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _WIN32_WINNT */
|
void ssh_poll_init(void) {
|
||||||
|
ssh_poll_emu = bsd_poll;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
hlib = LoadLibrary(WS2_LIBRARY);
|
||||||
|
if (hlib != NULL) {
|
||||||
|
wsa_poll = (WSAPoll_FunctionType) (void *) GetProcAddress(hlib, "WSAPoll");
|
||||||
|
}
|
||||||
#endif /* _WIN32 */
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
if (wsa_poll != NULL) {
|
||||||
|
ssh_poll_emu = bsd_poll;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssh_poll_cleanup(void) {
|
||||||
|
ssh_poll_emu = bsd_poll;
|
||||||
|
#ifdef _WIN32
|
||||||
|
wsa_poll = NULL;
|
||||||
|
|
||||||
|
FreeLibrary(hlib);
|
||||||
|
|
||||||
|
hlib = NULL;
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
}
|
||||||
|
|
||||||
|
int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
|
||||||
|
return (ssh_poll_emu)(fds, nfds, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* HAVE_POLL */
|
#endif /* HAVE_POLL */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -403,7 +442,7 @@ void ssh_poll_ctx_free(ssh_poll_ctx ctx) {
|
|||||||
used = ctx->polls_used;
|
used = ctx->polls_used;
|
||||||
for (i = 0; i < used; ) {
|
for (i = 0; i < used; ) {
|
||||||
ssh_poll_handle p = ctx->pollptrs[i];
|
ssh_poll_handle p = ctx->pollptrs[i];
|
||||||
int fd = ctx->pollfds[i].fd;
|
socket_t fd = ctx->pollfds[i].fd;
|
||||||
|
|
||||||
/* force poll object removal */
|
/* force poll object removal */
|
||||||
if (p->cb(p, fd, POLLERR, p->cb_data) < 0) {
|
if (p->cb(p, fd, POLLERR, p->cb_data) < 0) {
|
||||||
@@ -451,7 +490,7 @@ static int ssh_poll_ctx_resize(ssh_poll_ctx ctx, size_t new_size) {
|
|||||||
* @return 0 on success, < 0 on error
|
* @return 0 on success, < 0 on error
|
||||||
*/
|
*/
|
||||||
int ssh_poll_ctx_add(ssh_poll_ctx ctx, ssh_poll_handle p) {
|
int ssh_poll_ctx_add(ssh_poll_ctx ctx, ssh_poll_handle p) {
|
||||||
int fd;
|
socket_t fd;
|
||||||
|
|
||||||
if (p->ctx != NULL) {
|
if (p->ctx != NULL) {
|
||||||
/* already attached to a context */
|
/* already attached to a context */
|
||||||
@@ -530,7 +569,7 @@ int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout) {
|
|||||||
i++;
|
i++;
|
||||||
} else {
|
} else {
|
||||||
ssh_poll_handle p = ctx->pollptrs[i];
|
ssh_poll_handle p = ctx->pollptrs[i];
|
||||||
int fd = ctx->pollfds[i].fd;
|
socket_t fd = ctx->pollfds[i].fd;
|
||||||
int revents = ctx->pollfds[i].revents;
|
int revents = ctx->pollfds[i].revents;
|
||||||
|
|
||||||
if (p->cb(p, fd, revents, p->cb_data) < 0) {
|
if (p->cb(p, fd, revents, p->cb_data) < 0) {
|
||||||
|
|||||||
30
libssh/scp.c
30
libssh/scp.c
@@ -26,11 +26,18 @@
|
|||||||
|
|
||||||
#include "libssh/priv.h"
|
#include "libssh/priv.h"
|
||||||
#include "libssh/scp.h"
|
#include "libssh/scp.h"
|
||||||
|
/** @defgroup ssh_scp SSH-scp
|
||||||
|
* @brief SCP protocol over SSH functions
|
||||||
|
* @addtogroup ssh_scp
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
/** @brief Creates a new scp session
|
/** @brief Creates a new scp session
|
||||||
* @param session the SSH session to use
|
* @param session the SSH session to use
|
||||||
* @param mode one of SSH_SCP_WRITE or SSH_SCP_READ, depending if you need to drop files remotely or read them.
|
* @param mode one of SSH_SCP_WRITE or SSH_SCP_READ, depending if you need to drop files remotely or read them.
|
||||||
* It is not possible to combine read and write.
|
* It is not possible to combine read and write.
|
||||||
|
* @param location The directory in which write or read will be done. Any push or pull will be relative
|
||||||
|
* to this place
|
||||||
* @returns NULL if the creation was impossible.
|
* @returns NULL if the creation was impossible.
|
||||||
* @returns a ssh_scp handle if it worked.
|
* @returns a ssh_scp handle if it worked.
|
||||||
*/
|
*/
|
||||||
@@ -110,11 +117,22 @@ int ssh_scp_init(ssh_scp scp){
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ssh_scp_close(ssh_scp scp){
|
int ssh_scp_close(ssh_scp scp){
|
||||||
|
char buffer[128];
|
||||||
|
int err;
|
||||||
if(scp->channel != NULL){
|
if(scp->channel != NULL){
|
||||||
if(channel_send_eof(scp->channel) == SSH_ERROR){
|
if(channel_send_eof(scp->channel) == SSH_ERROR){
|
||||||
scp->state=SSH_SCP_ERROR;
|
scp->state=SSH_SCP_ERROR;
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
/* avoid situations where data are buffered and
|
||||||
|
* not yet stored on disk. This can happen if the close is sent
|
||||||
|
* before we got the EOF back
|
||||||
|
*/
|
||||||
|
while(!channel_is_eof(scp->channel)){
|
||||||
|
err=channel_read(scp->channel,buffer,sizeof(buffer),0);
|
||||||
|
if(err==SSH_ERROR)
|
||||||
|
break;
|
||||||
|
}
|
||||||
if(channel_close(scp->channel) == SSH_ERROR){
|
if(channel_close(scp->channel) == SSH_ERROR){
|
||||||
scp->state=SSH_SCP_ERROR;
|
scp->state=SSH_SCP_ERROR;
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
@@ -138,6 +156,7 @@ void ssh_scp_free(ssh_scp scp){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @brief creates a directory in a scp in sink mode
|
/** @brief creates a directory in a scp in sink mode
|
||||||
|
* @param scp the scp handle.
|
||||||
* @param dirname Name of the directory being created.
|
* @param dirname Name of the directory being created.
|
||||||
* @param mode Unix permissions for the new directory, e.g. 0755.
|
* @param mode Unix permissions for the new directory, e.g. 0755.
|
||||||
* @returns SSH_OK if the directory was created.
|
* @returns SSH_OK if the directory was created.
|
||||||
@@ -203,6 +222,7 @@ int ssh_scp_push_directory(ssh_scp scp, const char *dirname, int mode){
|
|||||||
|
|
||||||
|
|
||||||
/** @brief initializes the sending of a file to a scp in sink mode
|
/** @brief initializes the sending of a file to a scp in sink mode
|
||||||
|
* @param scp the scp handle.
|
||||||
* @param filename Name of the file being sent. It should not contain any path indicator
|
* @param filename Name of the file being sent. It should not contain any path indicator
|
||||||
* @param size Exact size in bytes of the file being sent.
|
* @param size Exact size in bytes of the file being sent.
|
||||||
* @param mode Unix permissions for the new file, e.g. 0644
|
* @param mode Unix permissions for the new file, e.g. 0644
|
||||||
@@ -285,6 +305,7 @@ int ssh_scp_response(ssh_scp scp, char **response){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Write into a remote scp file
|
/** @brief Write into a remote scp file
|
||||||
|
* @param scp the scp handle.
|
||||||
* @param buffer the buffer to write
|
* @param buffer the buffer to write
|
||||||
* @param len the number of bytes to write
|
* @param len the number of bytes to write
|
||||||
* @returns SSH_OK the write was successful
|
* @returns SSH_OK the write was successful
|
||||||
@@ -331,6 +352,7 @@ int ssh_scp_write(ssh_scp scp, const void *buffer, size_t len){
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief reads a string on a channel, terminated by '\n'
|
* @brief reads a string on a channel, terminated by '\n'
|
||||||
|
* @param scp the scp handle.
|
||||||
* @param buffer pointer to a buffer to place the string
|
* @param buffer pointer to a buffer to place the string
|
||||||
* @param len size of the buffer in bytes. If the string is bigger
|
* @param len size of the buffer in bytes. If the string is bigger
|
||||||
* than len-1, only len-1 bytes are read and the string
|
* than len-1, only len-1 bytes are read and the string
|
||||||
@@ -455,6 +477,7 @@ int ssh_scp_pull_request(ssh_scp scp){
|
|||||||
/**
|
/**
|
||||||
* @brief denies the transfer of a file or creation of a directory
|
* @brief denies the transfer of a file or creation of a directory
|
||||||
* coming from the remote party
|
* coming from the remote party
|
||||||
|
* @param scp the scp handle.
|
||||||
* @param reason nul-terminated string with a human-readable explanation
|
* @param reason nul-terminated string with a human-readable explanation
|
||||||
* of the deny
|
* of the deny
|
||||||
* @returns SSH_OK the message was sent
|
* @returns SSH_OK the message was sent
|
||||||
@@ -481,6 +504,7 @@ int ssh_scp_deny_request(ssh_scp scp, const char *reason){
|
|||||||
/**
|
/**
|
||||||
* @brief accepts transfer of a file or creation of a directory
|
* @brief accepts transfer of a file or creation of a directory
|
||||||
* coming from the remote party
|
* coming from the remote party
|
||||||
|
* @param scp the scp handle.
|
||||||
* @returns SSH_OK the message was sent
|
* @returns SSH_OK the message was sent
|
||||||
* @returns SSH_ERROR Error sending the message, or sending it in a bad state
|
* @returns SSH_ERROR Error sending the message, or sending it in a bad state
|
||||||
*/
|
*/
|
||||||
@@ -503,6 +527,7 @@ int ssh_scp_accept_request(ssh_scp scp){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Read from a remote scp file
|
/** @brief Read from a remote scp file
|
||||||
|
* @param scp the scp handle.
|
||||||
* @param buffer Destination buffer
|
* @param buffer Destination buffer
|
||||||
* @param size Size of the buffer
|
* @param size Size of the buffer
|
||||||
* @returns Number of bytes read
|
* @returns Number of bytes read
|
||||||
@@ -585,7 +610,7 @@ int ssh_scp_integer_mode(const char *mode){
|
|||||||
|
|
||||||
/** @brief Converts a unix mode into a scp string one.
|
/** @brief Converts a unix mode into a scp string one.
|
||||||
* @param mode mode to convert, e.g. 420 or 0644
|
* @param mode mode to convert, e.g. 420 or 0644
|
||||||
* @retuns pointer to a malloc'ed string containing the scp mode,
|
* @returns pointer to a malloc'ed string containing the scp mode,
|
||||||
* e.g. "0644".
|
* e.g. "0644".
|
||||||
*/
|
*/
|
||||||
char *ssh_scp_string_mode(int mode){
|
char *ssh_scp_string_mode(int mode){
|
||||||
@@ -601,3 +626,6 @@ char *ssh_scp_string_mode(int mode){
|
|||||||
const char *ssh_scp_request_get_warning(ssh_scp scp){
|
const char *ssh_scp_request_get_warning(ssh_scp scp){
|
||||||
return scp->warning;
|
return scp->warning;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ ssh_bind ssh_bind_new(void) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ZERO_STRUCTP(ptr);
|
ZERO_STRUCTP(ptr);
|
||||||
ptr->bindfd = -1;
|
ptr->bindfd = SSH_INVALID_SOCKET;
|
||||||
ptr->bindport= 22;
|
ptr->bindport= 22;
|
||||||
ptr->log_verbosity = 0;
|
ptr->log_verbosity = 0;
|
||||||
|
|
||||||
@@ -138,7 +138,7 @@ ssh_bind ssh_bind_new(void) {
|
|||||||
|
|
||||||
int ssh_bind_listen(ssh_bind sshbind) {
|
int ssh_bind_listen(ssh_bind sshbind) {
|
||||||
const char *host;
|
const char *host;
|
||||||
int fd;
|
socket_t fd;
|
||||||
|
|
||||||
if (ssh_init() < 0) {
|
if (ssh_init() < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -185,10 +185,10 @@ void ssh_bind_fd_toaccept(ssh_bind sshbind) {
|
|||||||
int ssh_bind_accept(ssh_bind sshbind, ssh_session session) {
|
int ssh_bind_accept(ssh_bind sshbind, ssh_session session) {
|
||||||
ssh_private_key dsa = NULL;
|
ssh_private_key dsa = NULL;
|
||||||
ssh_private_key rsa = NULL;
|
ssh_private_key rsa = NULL;
|
||||||
int fd = -1;
|
socket_t fd = SSH_INVALID_SOCKET;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (sshbind->bindfd < 0) {
|
if (sshbind->bindfd == SSH_INVALID_SOCKET) {
|
||||||
ssh_set_error(sshbind, SSH_FATAL,
|
ssh_set_error(sshbind, SSH_FATAL,
|
||||||
"Can't accept new clients on a not bound socket.");
|
"Can't accept new clients on a not bound socket.");
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
@@ -219,7 +219,7 @@ int ssh_bind_accept(ssh_bind sshbind, ssh_session session) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fd = accept(sshbind->bindfd, NULL, NULL);
|
fd = accept(sshbind->bindfd, NULL, NULL);
|
||||||
if (fd < 0) {
|
if (fd == SSH_INVALID_SOCKET) {
|
||||||
ssh_set_error(sshbind, SSH_FATAL,
|
ssh_set_error(sshbind, SSH_FATAL,
|
||||||
"Accepting a new connection: %s",
|
"Accepting a new connection: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
@@ -278,9 +278,13 @@ void ssh_bind_free(ssh_bind sshbind){
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sshbind->bindfd >= 0) {
|
if (sshbind->bindfd >= 0) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
closesocket(sshbind->bindfd);
|
||||||
|
#else
|
||||||
close(sshbind->bindfd);
|
close(sshbind->bindfd);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
sshbind->bindfd = -1;
|
sshbind->bindfd = SSH_INVALID_SOCKET;
|
||||||
|
|
||||||
/* options */
|
/* options */
|
||||||
SAFE_FREE(sshbind->banner);
|
SAFE_FREE(sshbind->banner);
|
||||||
@@ -867,7 +871,7 @@ int ssh_execute_message_callbacks(ssh_session session){
|
|||||||
if(!session->ssh_message_list)
|
if(!session->ssh_message_list)
|
||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
if(session->ssh_message_callback){
|
if(session->ssh_message_callback){
|
||||||
while((msg=ssh_list_get_head(ssh_message , session->ssh_message_list)) != NULL){
|
while((msg=ssh_list_pop_head(ssh_message , session->ssh_message_list)) != NULL){
|
||||||
ret=session->ssh_message_callback(session,msg);
|
ret=session->ssh_message_callback(session,msg);
|
||||||
if(ret==1){
|
if(ret==1){
|
||||||
ret = ssh_message_reply_default(msg);
|
ret = ssh_message_reply_default(msg);
|
||||||
@@ -876,7 +880,7 @@ int ssh_execute_message_callbacks(ssh_session session){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while((msg=ssh_list_get_head(ssh_message , session->ssh_message_list)) != NULL){
|
while((msg=ssh_list_pop_head(ssh_message , session->ssh_message_list)) != NULL){
|
||||||
ret = ssh_message_reply_default(msg);
|
ret = ssh_message_reply_default(msg);
|
||||||
if(ret != SSH_OK)
|
if(ret != SSH_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -32,7 +32,8 @@
|
|||||||
#include "libssh/packet.h"
|
#include "libssh/packet.h"
|
||||||
#include "libssh/session.h"
|
#include "libssh/session.h"
|
||||||
#include "libssh/misc.h"
|
#include "libssh/misc.h"
|
||||||
|
#include "libssh/ssh2.h"
|
||||||
|
#include "libssh/buffer.h"
|
||||||
#define FIRST_CHANNEL 42 // why not ? it helps to find bugs.
|
#define FIRST_CHANNEL 42 // why not ? it helps to find bugs.
|
||||||
|
|
||||||
/** \defgroup ssh_session SSH Session
|
/** \defgroup ssh_session SSH Session
|
||||||
@@ -46,6 +47,8 @@
|
|||||||
*/
|
*/
|
||||||
ssh_session ssh_new(void) {
|
ssh_session ssh_new(void) {
|
||||||
ssh_session session;
|
ssh_session session;
|
||||||
|
char *id;
|
||||||
|
int rc;
|
||||||
|
|
||||||
session = malloc(sizeof (struct ssh_session_struct));
|
session = malloc(sizeof (struct ssh_session_struct));
|
||||||
if (session == NULL) {
|
if (session == NULL) {
|
||||||
@@ -95,6 +98,39 @@ ssh_session ssh_new(void) {
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
#endif /* _WIN32 */
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
session->identity = ssh_list_new();
|
||||||
|
if (session->identity == NULL) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
id = strdup("%d/id_rsa");
|
||||||
|
if (id == NULL) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
rc = ssh_list_append(session->identity, id);
|
||||||
|
if (rc == SSH_ERROR) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
id = strdup("%d/id_dsa");
|
||||||
|
if (id == NULL) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
rc = ssh_list_append(session->identity, id);
|
||||||
|
if (rc == SSH_ERROR) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
id = strdup("%d/identity");
|
||||||
|
if (id == NULL) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
rc = ssh_list_append(session->identity, id);
|
||||||
|
if (rc == SSH_ERROR) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
return session;
|
return session;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
@@ -155,19 +191,30 @@ void ssh_free(ssh_session session) {
|
|||||||
privatekey_free(session->rsa_key);
|
privatekey_free(session->rsa_key);
|
||||||
if(session->ssh_message_list){
|
if(session->ssh_message_list){
|
||||||
ssh_message msg;
|
ssh_message msg;
|
||||||
while((msg=ssh_list_get_head(ssh_message ,session->ssh_message_list))
|
while((msg=ssh_list_pop_head(ssh_message ,session->ssh_message_list))
|
||||||
!= NULL){
|
!= NULL){
|
||||||
ssh_message_free(msg);
|
ssh_message_free(msg);
|
||||||
}
|
}
|
||||||
ssh_list_free(session->ssh_message_list);
|
ssh_list_free(session->ssh_message_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (session->identity) {
|
||||||
|
char *id;
|
||||||
|
|
||||||
|
for (id = ssh_list_pop_head(char *, session->identity);
|
||||||
|
id != NULL;
|
||||||
|
id = ssh_list_pop_head(char *, session->identity)) {
|
||||||
|
SAFE_FREE(id);
|
||||||
|
}
|
||||||
|
ssh_list_free(session->identity);
|
||||||
|
}
|
||||||
|
|
||||||
/* options */
|
/* options */
|
||||||
SAFE_FREE(session->username);
|
SAFE_FREE(session->username);
|
||||||
SAFE_FREE(session->host);
|
SAFE_FREE(session->host);
|
||||||
SAFE_FREE(session->identity);
|
|
||||||
SAFE_FREE(session->sshdir);
|
SAFE_FREE(session->sshdir);
|
||||||
SAFE_FREE(session->knownhosts);
|
SAFE_FREE(session->knownhosts);
|
||||||
|
SAFE_FREE(session->ProxyCommand);
|
||||||
|
|
||||||
for (i = 0; i < 10; i++) {
|
for (i = 0; i < 10; i++) {
|
||||||
if (session->wanted_methods[i]) {
|
if (session->wanted_methods[i]) {
|
||||||
@@ -363,5 +410,32 @@ int ssh_get_version(ssh_session session) {
|
|||||||
return session->version;
|
return session->version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* @handle a SSH_MSG_GLOBAL_REQUEST packet
|
||||||
|
* @param session the SSH session
|
||||||
|
*/
|
||||||
|
void ssh_global_request_handle(ssh_session session){
|
||||||
|
ssh_string type;
|
||||||
|
char *type_c;
|
||||||
|
uint32_t needreply;
|
||||||
|
type=buffer_get_ssh_string(session->in_buffer);
|
||||||
|
buffer_get_u32(session->in_buffer,&needreply);
|
||||||
|
if(type==NULL)
|
||||||
|
return;
|
||||||
|
type_c=string_to_char(type);
|
||||||
|
if(!type_c)
|
||||||
|
return;
|
||||||
|
ssh_log(session, SSH_LOG_PROTOCOL,
|
||||||
|
"Received SSH_GLOBAL_REQUEST %s (wantreply=%d)",type_c,needreply);
|
||||||
|
SAFE_FREE(type_c);
|
||||||
|
string_free(type);
|
||||||
|
if(needreply != 0){
|
||||||
|
buffer_add_u8(session->out_buffer,SSH2_MSG_REQUEST_FAILURE);
|
||||||
|
packet_send(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
/* vim: set ts=2 sw=2 et cindent: */
|
/* vim: set ts=2 sw=2 et cindent: */
|
||||||
|
|||||||
@@ -25,9 +25,11 @@
|
|||||||
/* This file contains code written by Nick Zitzmann */
|
/* This file contains code written by Nick Zitzmann */
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
@@ -1111,6 +1113,54 @@ static sftp_attributes sftp_parse_attr_4(sftp_session sftp, ssh_buffer buf,
|
|||||||
return attr;
|
return attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum sftp_longname_field_e {
|
||||||
|
SFTP_LONGNAME_PERM = 0,
|
||||||
|
SFTP_LONGNAME_FIXME,
|
||||||
|
SFTP_LONGNAME_OWNER,
|
||||||
|
SFTP_LONGNAME_GROUP,
|
||||||
|
SFTP_LONGNAME_SIZE,
|
||||||
|
SFTP_LONGNAME_DATE,
|
||||||
|
SFTP_LONGNAME_TIME,
|
||||||
|
SFTP_LONGNAME_NAME,
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *sftp_parse_longname(const char *longname,
|
||||||
|
enum sftp_longname_field_e longname_field) {
|
||||||
|
const char *p, *q;
|
||||||
|
size_t len, field = 0;
|
||||||
|
char *x;
|
||||||
|
|
||||||
|
p = longname;
|
||||||
|
/* Find the beginning of the field which is specified by sftp_longanme_field_e. */
|
||||||
|
while(field != longname_field) {
|
||||||
|
if(isspace(*p)) {
|
||||||
|
field++;
|
||||||
|
p++;
|
||||||
|
while(*p && isspace(*p)) {
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
q = p;
|
||||||
|
while (! isspace(*q)) {
|
||||||
|
q++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* There is no strndup on windows */
|
||||||
|
len = q - p + 1;
|
||||||
|
x = malloc(len);
|
||||||
|
if (x == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(x, len, "%s", p);
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
/* sftp version 0-3 code. It is different from the v4 */
|
/* sftp version 0-3 code. It is different from the v4 */
|
||||||
/* maybe a paste of the draft is better than the code */
|
/* maybe a paste of the draft is better than the code */
|
||||||
/*
|
/*
|
||||||
@@ -1157,6 +1207,19 @@ static sftp_attributes sftp_parse_attr_3(sftp_session sftp, ssh_buffer buf,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
string_free(longname);
|
string_free(longname);
|
||||||
|
|
||||||
|
/* Set owner and group if we talk to openssh and have the longname */
|
||||||
|
if (ssh_get_openssh_version(sftp->session)) {
|
||||||
|
attr->owner = sftp_parse_longname(attr->longname, SFTP_LONGNAME_OWNER);
|
||||||
|
if (attr->owner == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
attr->group = sftp_parse_longname(attr->longname, SFTP_LONGNAME_GROUP);
|
||||||
|
if (attr->group == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer_get_u32(buf, &flags) != sizeof(uint32_t)) {
|
if (buffer_get_u32(buf, &flags) != sizeof(uint32_t)) {
|
||||||
@@ -1254,6 +1317,8 @@ static sftp_attributes sftp_parse_attr_3(sftp_session sftp, ssh_buffer buf,
|
|||||||
string_free(attr->extended_data);
|
string_free(attr->extended_data);
|
||||||
SAFE_FREE(attr->name);
|
SAFE_FREE(attr->name);
|
||||||
SAFE_FREE(attr->longname);
|
SAFE_FREE(attr->longname);
|
||||||
|
SAFE_FREE(attr->owner);
|
||||||
|
SAFE_FREE(attr->group);
|
||||||
SAFE_FREE(attr);
|
SAFE_FREE(attr);
|
||||||
|
|
||||||
ssh_set_error(sftp->session, SSH_FATAL, "Invalid ATTR structure");
|
ssh_set_error(sftp->session, SSH_FATAL, "Invalid ATTR structure");
|
||||||
@@ -2276,8 +2341,9 @@ int sftp_rename(sftp_session sftp, const char *original, const char *newname) {
|
|||||||
if (buffer_add_u32(buffer, id) < 0 ||
|
if (buffer_add_u32(buffer, id) < 0 ||
|
||||||
buffer_add_ssh_string(buffer, oldpath) < 0 ||
|
buffer_add_ssh_string(buffer, oldpath) < 0 ||
|
||||||
buffer_add_ssh_string(buffer, newpath) < 0 ||
|
buffer_add_ssh_string(buffer, newpath) < 0 ||
|
||||||
/* POSIX rename atomically replaces newpath, we should do the same */
|
/* POSIX rename atomically replaces newpath, we should do the same
|
||||||
buffer_add_u32(buffer, SSH_FXF_RENAME_OVERWRITE) < 0) {
|
* only available on >=v4 */
|
||||||
|
sftp->version>=4 ? (buffer_add_u32(buffer, SSH_FXF_RENAME_OVERWRITE) < 0):0) {
|
||||||
ssh_set_error_oom(sftp->session);
|
ssh_set_error_oom(sftp->session);
|
||||||
buffer_free(buffer);
|
buffer_free(buffer);
|
||||||
string_free(oldpath);
|
string_free(oldpath);
|
||||||
@@ -2419,7 +2485,8 @@ int sftp_chown(sftp_session sftp, const char *file, uid_t owner, gid_t group) {
|
|||||||
|
|
||||||
attr.uid = owner;
|
attr.uid = owner;
|
||||||
attr.gid = group;
|
attr.gid = group;
|
||||||
attr.flags = SSH_FILEXFER_ATTR_OWNERGROUP;
|
|
||||||
|
attr.flags = SSH_FILEXFER_ATTR_UIDGID;
|
||||||
|
|
||||||
return sftp_setstat(sftp, file, &attr);
|
return sftp_setstat(sftp, file, &attr);
|
||||||
}
|
}
|
||||||
|
|||||||
108
libssh/socket.c
108
libssh/socket.c
@@ -27,11 +27,13 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
#else
|
#else
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
extern char **environ;
|
||||||
#endif
|
#endif
|
||||||
#include "libssh/priv.h"
|
#include "libssh/priv.h"
|
||||||
#include "libssh/socket.h"
|
#include "libssh/socket.h"
|
||||||
@@ -39,6 +41,7 @@
|
|||||||
#include "libssh/poll.h"
|
#include "libssh/poll.h"
|
||||||
#include "libssh/session.h"
|
#include "libssh/session.h"
|
||||||
|
|
||||||
|
|
||||||
/** \defgroup ssh_socket SSH Sockets
|
/** \defgroup ssh_socket SSH Sockets
|
||||||
* \addtogroup ssh_socket
|
* \addtogroup ssh_socket
|
||||||
* @{
|
* @{
|
||||||
@@ -68,10 +71,21 @@ int ssh_socket_init(void) {
|
|||||||
if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
|
if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
ssh_poll_init();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
|
/**
|
||||||
|
* @brief Cleanup the socket system.
|
||||||
|
*/
|
||||||
|
void ssh_socket_cleanup(void) {
|
||||||
|
ssh_poll_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
* \internal
|
* \internal
|
||||||
* \brief creates a new Socket object
|
* \brief creates a new Socket object
|
||||||
*/
|
*/
|
||||||
@@ -82,7 +96,7 @@ struct socket *ssh_socket_new(ssh_session session) {
|
|||||||
if (s == NULL) {
|
if (s == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
s->fd = -1;
|
s->fd = SSH_INVALID_SOCKET;
|
||||||
s->last_errno = -1;
|
s->last_errno = -1;
|
||||||
s->session = session;
|
s->session = session;
|
||||||
s->in_buffer = buffer_new();
|
s->in_buffer = buffer_new();
|
||||||
@@ -124,20 +138,20 @@ int ssh_socket_unix(struct socket *s, const char *path) {
|
|||||||
snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), "%s", path);
|
snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), "%s", path);
|
||||||
|
|
||||||
s->fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
s->fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
if (s->fd < 0) {
|
if (s->fd == SSH_INVALID_SOCKET) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fcntl(s->fd, F_SETFD, 1) == -1) {
|
if (fcntl(s->fd, F_SETFD, 1) == -1) {
|
||||||
close(s->fd);
|
close(s->fd);
|
||||||
s->fd = -1;
|
s->fd = SSH_INVALID_SOCKET;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connect(s->fd, (struct sockaddr *) &sunaddr,
|
if (connect(s->fd, (struct sockaddr *) &sunaddr,
|
||||||
sizeof(sunaddr)) < 0) {
|
sizeof(sunaddr)) < 0) {
|
||||||
close(s->fd);
|
close(s->fd);
|
||||||
s->fd = -1;
|
s->fd = SSH_INVALID_SOCKET;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +171,7 @@ void ssh_socket_close(struct socket *s){
|
|||||||
close(s->fd);
|
close(s->fd);
|
||||||
s->last_errno = errno;
|
s->last_errno = errno;
|
||||||
#endif
|
#endif
|
||||||
s->fd=-1;
|
s->fd = SSH_INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +193,7 @@ socket_t ssh_socket_get_fd(struct socket *s) {
|
|||||||
* \brief returns nonzero if the socket is open
|
* \brief returns nonzero if the socket is open
|
||||||
*/
|
*/
|
||||||
int ssh_socket_is_open(struct socket *s) {
|
int ssh_socket_is_open(struct socket *s) {
|
||||||
return s->fd != -1;
|
return s->fd != SSH_INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* \internal
|
/* \internal
|
||||||
@@ -237,22 +251,22 @@ static int ssh_socket_unbuffered_write(struct socket *s, const void *buffer,
|
|||||||
* \brief returns nonzero if the current socket is in the fd_set
|
* \brief returns nonzero if the current socket is in the fd_set
|
||||||
*/
|
*/
|
||||||
int ssh_socket_fd_isset(struct socket *s, fd_set *set) {
|
int ssh_socket_fd_isset(struct socket *s, fd_set *set) {
|
||||||
if(s->fd == -1) {
|
if(s->fd == SSH_INVALID_SOCKET) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return FD_ISSET(s->fd,set);
|
return FD_ISSET(s->fd,set);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* \internal
|
/* \internal
|
||||||
* \brief sets the current fd in a fd_set and updates the fd_max
|
* \brief sets the current fd in a fd_set and updates the max_fd
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void ssh_socket_fd_set(struct socket *s, fd_set *set, int *fd_max) {
|
void ssh_socket_fd_set(struct socket *s, fd_set *set, socket_t *max_fd) {
|
||||||
if (s->fd == -1)
|
if (s->fd == SSH_INVALID_SOCKET)
|
||||||
return;
|
return;
|
||||||
FD_SET(s->fd,set);
|
FD_SET(s->fd,set);
|
||||||
if (s->fd >= *fd_max) {
|
if (s->fd >= 0 && s->fd != SSH_INVALID_SOCKET) {
|
||||||
*fd_max = s->fd + 1;
|
*max_fd = s->fd + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,7 +449,7 @@ int ssh_socket_wait_for_data(struct socket *s, ssh_session session, uint32_t len
|
|||||||
if (ssh_socket_is_open(session->socket)) {
|
if (ssh_socket_is_open(session->socket)) {
|
||||||
r = ssh_socket_unbuffered_read(session->socket, buffer, sizeof(buffer));
|
r = ssh_socket_unbuffered_read(session->socket, buffer, sizeof(buffer));
|
||||||
} else {
|
} else {
|
||||||
r =- 1;
|
r = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r <= 0) {
|
if (r <= 0) {
|
||||||
@@ -482,13 +496,15 @@ int ssh_socket_poll(struct socket *s, int *writeable, int *except) {
|
|||||||
if (!s->data_to_write) {
|
if (!s->data_to_write) {
|
||||||
fd->events |= POLLOUT;
|
fd->events |= POLLOUT;
|
||||||
}
|
}
|
||||||
|
/* do not do poll if fd->events is empty, we already know the response */
|
||||||
/* Make the call, and listen for errors */
|
if(fd->events != 0){
|
||||||
rc = ssh_poll(fd, 1, 0);
|
/* Make the call, and listen for errors */
|
||||||
if (rc < 0) {
|
rc = ssh_poll(fd, 1, 0);
|
||||||
ssh_set_error(session, SSH_FATAL, "poll(): %s", strerror(errno));
|
if (rc < 0) {
|
||||||
leave_function();
|
ssh_set_error(session, SSH_FATAL, "poll(): %s", strerror(errno));
|
||||||
return -1;
|
leave_function();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!s->data_to_read) {
|
if (!s->data_to_read) {
|
||||||
@@ -542,7 +558,7 @@ int ssh_socket_nonblocking_flush(struct socket *s) {
|
|||||||
buffer_get_rest_len(s->out_buffer));
|
buffer_get_rest_len(s->out_buffer));
|
||||||
} else {
|
} else {
|
||||||
/* write failed */
|
/* write failed */
|
||||||
w =- 1;
|
w = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (w < 0) {
|
if (w < 0) {
|
||||||
@@ -658,6 +674,54 @@ int ssh_socket_get_status(struct socket *s) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* @brief executes a command and redirect input and outputs
|
||||||
|
* @param command command to execute
|
||||||
|
* @param in input file descriptor
|
||||||
|
* @param out output file descriptor
|
||||||
|
*/
|
||||||
|
void ssh_execute_command(const char *command, socket_t in, socket_t out){
|
||||||
|
const char *args[]={"/bin/sh","-c",command,NULL};
|
||||||
|
/* redirect in and out to stdin, stdout and stderr */
|
||||||
|
dup2(in, 0);
|
||||||
|
dup2(out,1);
|
||||||
|
dup2(out,2);
|
||||||
|
close(in);
|
||||||
|
close(out);
|
||||||
|
execve(args[0],(char * const *)args,(char * const *)environ);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* @brief Open a socket on a ProxyCommand
|
||||||
|
* This call will always be nonblocking.
|
||||||
|
* @param s socket to connect.
|
||||||
|
* @param command Command to execute.
|
||||||
|
* @returns SSH_OK socket is being connected.
|
||||||
|
* @returns SSH_ERROR error while executing the command.
|
||||||
|
*/
|
||||||
|
|
||||||
|
socket_t ssh_socket_connect_proxycommand(ssh_session session,
|
||||||
|
const char *command){
|
||||||
|
socket_t fd[2];
|
||||||
|
int pid;
|
||||||
|
enter_function();
|
||||||
|
socketpair(AF_UNIX,SOCK_STREAM,0,fd);
|
||||||
|
pid = fork();
|
||||||
|
if(pid == 0){
|
||||||
|
ssh_execute_command(command,fd[1],fd[1]);
|
||||||
|
}
|
||||||
|
close(fd[1]);
|
||||||
|
ssh_log(session,SSH_LOG_PROTOCOL,"ProxyCommand connection pipe: [%d,%d]",fd[0],fd[1]);
|
||||||
|
return fd[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
|
||||||
/** @}
|
/** @}
|
||||||
*/
|
*/
|
||||||
/* vim: set ts=2 sw=2 et cindent: */
|
/* vim: set ts=2 sw=2 et cindent: */
|
||||||
|
|||||||
127
libssh/wrapper.c
127
libssh/wrapper.c
@@ -157,29 +157,31 @@ static void blowfish_decrypt(struct crypto_struct *cipher, void *in,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int aes_set_key(struct crypto_struct *cipher, void *key, void *IV) {
|
static int aes_set_key(struct crypto_struct *cipher, void *key, void *IV) {
|
||||||
|
int mode=GCRY_CIPHER_MODE_CBC;
|
||||||
if (cipher->key == NULL) {
|
if (cipher->key == NULL) {
|
||||||
if (alloc_key(cipher) < 0) {
|
if (alloc_key(cipher) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if(strstr(cipher->name,"-ctr"))
|
||||||
|
mode=GCRY_CIPHER_MODE_CTR;
|
||||||
switch (cipher->keysize) {
|
switch (cipher->keysize) {
|
||||||
case 128:
|
case 128:
|
||||||
if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_AES128,
|
if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_AES128,
|
||||||
GCRY_CIPHER_MODE_CBC, 0)) {
|
mode, 0)) {
|
||||||
SAFE_FREE(cipher->key);
|
SAFE_FREE(cipher->key);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 192:
|
case 192:
|
||||||
if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_AES192,
|
if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_AES192,
|
||||||
GCRY_CIPHER_MODE_CBC, 0)) {
|
mode, 0)) {
|
||||||
SAFE_FREE(cipher->key);
|
SAFE_FREE(cipher->key);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 256:
|
case 256:
|
||||||
if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_AES256,
|
if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_AES256,
|
||||||
GCRY_CIPHER_MODE_CBC, 0)) {
|
mode, 0)) {
|
||||||
SAFE_FREE(cipher->key);
|
SAFE_FREE(cipher->key);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -189,9 +191,17 @@ static int aes_set_key(struct crypto_struct *cipher, void *key, void *IV) {
|
|||||||
SAFE_FREE(cipher->key);
|
SAFE_FREE(cipher->key);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (gcry_cipher_setiv(cipher->key[0], IV, 16)) {
|
if(mode == GCRY_CIPHER_MODE_CBC){
|
||||||
SAFE_FREE(cipher->key);
|
if (gcry_cipher_setiv(cipher->key[0], IV, 16)) {
|
||||||
return -1;
|
|
||||||
|
SAFE_FREE(cipher->key);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(gcry_cipher_setctr(cipher->key[0],IV,16)){
|
||||||
|
SAFE_FREE(cipher->key);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,6 +329,39 @@ static struct crypto_struct ssh_ciphertab[] = {
|
|||||||
.cbc_encrypt = blowfish_encrypt,
|
.cbc_encrypt = blowfish_encrypt,
|
||||||
.cbc_decrypt = blowfish_decrypt
|
.cbc_decrypt = blowfish_decrypt
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "aes128-ctr",
|
||||||
|
.blocksize = 16,
|
||||||
|
.keylen = sizeof(gcry_cipher_hd_t),
|
||||||
|
.key = NULL,
|
||||||
|
.keysize = 128,
|
||||||
|
.set_encrypt_key = aes_set_key,
|
||||||
|
.set_decrypt_key = aes_set_key,
|
||||||
|
.cbc_encrypt = aes_encrypt,
|
||||||
|
.cbc_decrypt = aes_encrypt
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "aes192-ctr",
|
||||||
|
.blocksize = 16,
|
||||||
|
.keylen = sizeof(gcry_cipher_hd_t),
|
||||||
|
.key = NULL,
|
||||||
|
.keysize = 192,
|
||||||
|
.set_encrypt_key = aes_set_key,
|
||||||
|
.set_decrypt_key = aes_set_key,
|
||||||
|
.cbc_encrypt = aes_encrypt,
|
||||||
|
.cbc_decrypt = aes_encrypt
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "aes256-ctr",
|
||||||
|
.blocksize = 16,
|
||||||
|
.keylen = sizeof(gcry_cipher_hd_t),
|
||||||
|
.key = NULL,
|
||||||
|
.keysize = 256,
|
||||||
|
.set_encrypt_key = aes_set_key,
|
||||||
|
.set_decrypt_key = aes_set_key,
|
||||||
|
.cbc_encrypt = aes_encrypt,
|
||||||
|
.cbc_decrypt = aes_encrypt
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.name = "aes128-cbc",
|
.name = "aes128-cbc",
|
||||||
.blocksize = 16,
|
.blocksize = 16,
|
||||||
@@ -570,6 +613,30 @@ static void aes_decrypt(struct crypto_struct *cipher, void *in, void *out,
|
|||||||
unsigned long len, void *IV) {
|
unsigned long len, void *IV) {
|
||||||
AES_cbc_encrypt(in, out, len, cipher->key, IV, AES_DECRYPT);
|
AES_cbc_encrypt(in, out, len, cipher->key, IV, AES_DECRYPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef BROKEN_AES_CTR
|
||||||
|
/* OpenSSL until 0.9.7c has a broken AES_ctr128_encrypt implementation which
|
||||||
|
* increments the counter from 2^64 instead of 1. It's better not to use it
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @internal
|
||||||
|
* @brief encrypts/decrypts data with stream cipher AES_ctr128. 128 bits is actually
|
||||||
|
* the size of the CTR counter and incidentally the blocksize, but not the keysize.
|
||||||
|
* @param len[in] must be a multiple of AES128 block size.
|
||||||
|
*/
|
||||||
|
static void aes_ctr128_encrypt(struct crypto_struct *cipher, void *in, void *out,
|
||||||
|
unsigned long len, void *IV) {
|
||||||
|
unsigned char tmp_buffer[128/8];
|
||||||
|
unsigned int num=0;
|
||||||
|
/* Some things are special with ctr128 :
|
||||||
|
* In this case, tmp_buffer is not being used, because it is used to store temporary data
|
||||||
|
* when an encryption is made on lengths that are not multiple of blocksize.
|
||||||
|
* Same for num, which is being used to store the current offset in blocksize in CTR
|
||||||
|
* function.
|
||||||
|
*/
|
||||||
|
AES_ctr128_encrypt(in, out, len, cipher->key, IV, tmp_buffer, &num);
|
||||||
|
}
|
||||||
|
#endif /* BROKEN_AES_CTR */
|
||||||
#endif /* HAS_AES */
|
#endif /* HAS_AES */
|
||||||
|
|
||||||
#ifdef HAS_DES
|
#ifdef HAS_DES
|
||||||
@@ -661,6 +728,41 @@ static struct crypto_struct ssh_ciphertab[] = {
|
|||||||
},
|
},
|
||||||
#endif /* HAS_BLOWFISH */
|
#endif /* HAS_BLOWFISH */
|
||||||
#ifdef HAS_AES
|
#ifdef HAS_AES
|
||||||
|
#ifndef BROKEN_AES_CTR
|
||||||
|
{
|
||||||
|
"aes128-ctr",
|
||||||
|
16,
|
||||||
|
sizeof(AES_KEY),
|
||||||
|
NULL,
|
||||||
|
128,
|
||||||
|
aes_set_encrypt_key,
|
||||||
|
aes_set_encrypt_key,
|
||||||
|
aes_ctr128_encrypt,
|
||||||
|
aes_ctr128_encrypt
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"aes192-ctr",
|
||||||
|
16,
|
||||||
|
sizeof(AES_KEY),
|
||||||
|
NULL,
|
||||||
|
192,
|
||||||
|
aes_set_encrypt_key,
|
||||||
|
aes_set_encrypt_key,
|
||||||
|
aes_ctr128_encrypt,
|
||||||
|
aes_ctr128_encrypt
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"aes256-ctr",
|
||||||
|
16,
|
||||||
|
sizeof(AES_KEY),
|
||||||
|
NULL,
|
||||||
|
256,
|
||||||
|
aes_set_encrypt_key,
|
||||||
|
aes_set_encrypt_key,
|
||||||
|
aes_ctr128_encrypt,
|
||||||
|
aes_ctr128_encrypt
|
||||||
|
},
|
||||||
|
#endif /* BROKEN_AES_CTR */
|
||||||
{
|
{
|
||||||
"aes128-cbc",
|
"aes128-cbc",
|
||||||
16,
|
16,
|
||||||
@@ -907,7 +1009,8 @@ int crypt_set_algorithms_server(ssh_session session){
|
|||||||
/* out */
|
/* out */
|
||||||
server = session->server_kex.methods[SSH_CRYPT_S_C];
|
server = session->server_kex.methods[SSH_CRYPT_S_C];
|
||||||
client = session->client_kex.methods[SSH_CRYPT_S_C];
|
client = session->client_kex.methods[SSH_CRYPT_S_C];
|
||||||
match = ssh_find_matching(client, server);
|
/* That's the client algorithms that are more important */
|
||||||
|
match = ssh_find_matching(server,client);
|
||||||
|
|
||||||
if(!match){
|
if(!match){
|
||||||
ssh_set_error(session,SSH_FATAL,"Crypt_set_algorithms_server : no matching algorithm function found for %s",server);
|
ssh_set_error(session,SSH_FATAL,"Crypt_set_algorithms_server : no matching algorithm function found for %s",server);
|
||||||
@@ -936,7 +1039,7 @@ int crypt_set_algorithms_server(ssh_session session){
|
|||||||
/* in */
|
/* in */
|
||||||
client=session->client_kex.methods[SSH_CRYPT_C_S];
|
client=session->client_kex.methods[SSH_CRYPT_C_S];
|
||||||
server=session->server_kex.methods[SSH_CRYPT_S_C];
|
server=session->server_kex.methods[SSH_CRYPT_S_C];
|
||||||
match=ssh_find_matching(client,server);
|
match=ssh_find_matching(server,client);
|
||||||
if(!match){
|
if(!match){
|
||||||
ssh_set_error(session,SSH_FATAL,"Crypt_set_algorithms_server : no matching algorithm function found for %s",server);
|
ssh_set_error(session,SSH_FATAL,"Crypt_set_algorithms_server : no matching algorithm function found for %s",server);
|
||||||
free(match);
|
free(match);
|
||||||
@@ -964,7 +1067,7 @@ int crypt_set_algorithms_server(ssh_session session){
|
|||||||
/* compression */
|
/* compression */
|
||||||
client=session->client_kex.methods[SSH_CRYPT_C_S];
|
client=session->client_kex.methods[SSH_CRYPT_C_S];
|
||||||
server=session->server_kex.methods[SSH_CRYPT_C_S];
|
server=session->server_kex.methods[SSH_CRYPT_C_S];
|
||||||
match=ssh_find_matching(client,server);
|
match=ssh_find_matching(server,client);
|
||||||
if(match && !strcmp(match,"zlib")){
|
if(match && !strcmp(match,"zlib")){
|
||||||
ssh_log(session,SSH_LOG_PACKET,"enabling C->S compression");
|
ssh_log(session,SSH_LOG_PACKET,"enabling C->S compression");
|
||||||
session->next_crypto->do_compress_in=1;
|
session->next_crypto->do_compress_in=1;
|
||||||
@@ -973,7 +1076,7 @@ int crypt_set_algorithms_server(ssh_session session){
|
|||||||
|
|
||||||
client=session->client_kex.methods[SSH_CRYPT_S_C];
|
client=session->client_kex.methods[SSH_CRYPT_S_C];
|
||||||
server=session->server_kex.methods[SSH_CRYPT_S_C];
|
server=session->server_kex.methods[SSH_CRYPT_S_C];
|
||||||
match=ssh_find_matching(client,server);
|
match=ssh_find_matching(server,client);
|
||||||
if(match && !strcmp(match,"zlib")){
|
if(match && !strcmp(match,"zlib")){
|
||||||
ssh_log(session,SSH_LOG_PACKET,"enabling S->C compression\n");
|
ssh_log(session,SSH_LOG_PACKET,"enabling S->C compression\n");
|
||||||
session->next_crypto->do_compress_out=1;
|
session->next_crypto->do_compress_out=1;
|
||||||
@@ -982,7 +1085,7 @@ int crypt_set_algorithms_server(ssh_session session){
|
|||||||
|
|
||||||
server=session->server_kex.methods[SSH_HOSTKEYS];
|
server=session->server_kex.methods[SSH_HOSTKEYS];
|
||||||
client=session->client_kex.methods[SSH_HOSTKEYS];
|
client=session->client_kex.methods[SSH_HOSTKEYS];
|
||||||
match=ssh_find_matching(client,server);
|
match=ssh_find_matching(server,client);
|
||||||
if(match && !strcmp(match,"ssh-dss"))
|
if(match && !strcmp(match,"ssh-dss"))
|
||||||
session->hostkeys=TYPE_DSS;
|
session->hostkeys=TYPE_DSS;
|
||||||
else if(match && !strcmp(match,"ssh-rsa"))
|
else if(match && !strcmp(match,"ssh-rsa"))
|
||||||
|
|||||||
Reference in New Issue
Block a user