mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-04 12:20:42 +09:00
Compare commits
197 Commits
607dad040b
...
release-0-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6d17ccc15 | ||
|
|
0b0a2d85d0 | ||
|
|
8d7245f54b | ||
|
|
0b1f8a2b0c | ||
|
|
8d676c77b1 | ||
|
|
b1a65dd25f | ||
|
|
e78cc89b52 | ||
|
|
f6586576fb | ||
|
|
3797ca0ec6 | ||
|
|
bfe59d0cdd | ||
|
|
4362d76416 | ||
|
|
da3b2d68a3 | ||
|
|
4638b353d5 | ||
|
|
a9f3a2f103 | ||
|
|
59f0293576 | ||
|
|
7a314d9149 | ||
|
|
a13c9d4182 | ||
|
|
93f79c62ef | ||
|
|
31fdb4ecf6 | ||
|
|
0b564c358f | ||
|
|
fb24e68edd | ||
|
|
b5f095d0b4 | ||
|
|
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
|
||||
set(APPLICATION_NAME ${PROJECT_NAME})
|
||||
|
||||
set(APPLICATION_VERSION "0.4.0")
|
||||
|
||||
set(APPLICATION_VERSION_MAJOR "0")
|
||||
set(APPLICATION_VERSION_MINOR "4")
|
||||
set(APPLICATION_VERSION_PATCH "0")
|
||||
set(APPLICATION_VERSION_PATCH "8")
|
||||
|
||||
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.4")
|
||||
set(LIBRARY_SOVERSION "4")
|
||||
|
||||
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
|
||||
@@ -23,6 +30,7 @@ set(CMAKE_MODULE_PATH
|
||||
# add definitions
|
||||
include(DefineCMakeDefaults)
|
||||
include(DefineCompilerFlags)
|
||||
include(DefinePlatformDefaults)
|
||||
include(DefineInstallationPaths)
|
||||
include(DefineOptions.cmake)
|
||||
include(CPackConfig.cmake)
|
||||
@@ -45,12 +53,12 @@ if (WITH_GCRYPT)
|
||||
endif (NOT GCRYPT_FOUND)
|
||||
else (WITH_GCRYPT)
|
||||
find_package(OpenSSL)
|
||||
if (NOT CRYPTO_FOUND)
|
||||
if (NOT OPENSSL_FOUND)
|
||||
find_package(GCrypt)
|
||||
if (NOT GCRYPT_FOUND)
|
||||
message(FATAL_ERROR "Could not find OpenSSL or GCrypt")
|
||||
endif (NOT GCRYPT_FOUND)
|
||||
endif (NOT CRYPTO_FOUND)
|
||||
endif (NOT OPENSSL_FOUND)
|
||||
endif(WITH_GCRYPT)
|
||||
|
||||
# config.h checks
|
||||
@@ -61,12 +69,11 @@ configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
||||
add_subdirectory(doc)
|
||||
add_subdirectory(include)
|
||||
add_subdirectory(libssh)
|
||||
add_subdirectory(tests)
|
||||
|
||||
# build samples
|
||||
include_directories(${CMAKE_SOURCE_DIR}/include)
|
||||
|
||||
if (UNIX AND NOT WIN32)
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
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
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR "0")
|
||||
set(CPACK_PACKAGE_VERSION_MINOR "3")
|
||||
set(CPACK_PACKAGE_VERSION_PATCH "91")
|
||||
set(CPACK_PACKAGE_VERSION_MINOR "4")
|
||||
set(CPACK_PACKAGE_VERSION_PATCH "8")
|
||||
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_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
|
||||
|
||||
if (WIN32)
|
||||
set(CPACK_GENERATOR "ZIP")
|
||||
|
||||
### nsis generator
|
||||
set(CPACK_GENERATOR "NSIS")
|
||||
### nsis generator
|
||||
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_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_COMPONENT_LIBRARIES_DISPLAY_NAME "Libraries")
|
||||
|
||||
96
ChangeLog
96
ChangeLog
@@ -1,7 +1,101 @@
|
||||
ChangeLog
|
||||
==========
|
||||
|
||||
version 0.4 (released xxxx-xx-xx)
|
||||
version 0.4.8 (released 2011-01-15)
|
||||
* Fixed memory leaks in session signing.
|
||||
* Fixed memory leak in ssh_print_hexa.
|
||||
* Fixed problem with ssh_connect w/ timeout and fd > 1024.
|
||||
* Fixed some warnings on OS/2.
|
||||
* Fixed installation path for OS/2.
|
||||
|
||||
version 0.4.7 (released 2010-12-28)
|
||||
* Fixed a possible memory leak in ssh_get_user_home().
|
||||
* Fixed a memory leak in sftp_xstat.
|
||||
* Fixed uninitialized fd->revents member.
|
||||
* Fixed timout value in ssh_channel_accept().
|
||||
* Fixed length checks in ssh_analyze_banner().
|
||||
* Fixed a possible data overread and crash bug.
|
||||
* Fixed setting max_fd which breaks ssh_select().
|
||||
* Fixed some pedantic build warnings.
|
||||
* Fixed a memory leak with session->bindaddr.
|
||||
|
||||
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 support for sending signals (RFC 4254, section 6.9).
|
||||
* Added MSVC support.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
include(CheckIncludeFile)
|
||||
include(CheckIncludeFiles)
|
||||
include(CheckSymbolExists)
|
||||
include(CheckFunctionExists)
|
||||
include(CheckLibraryExists)
|
||||
@@ -16,20 +17,39 @@ set(SYSCONFDIR ${SYSCONF_INSTALL_DIR})
|
||||
set(BINARYDIR ${CMAKE_BINARY_DIR})
|
||||
set(SOURCEDIR ${CMAKE_SOURCE_DIR})
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUC)
|
||||
check_c_compiler_flag("-fvisibility=hidden" WITH_VISIBILITY_HIDDEN)
|
||||
endif(CMAKE_COMPILER_IS_GNUC)
|
||||
function(COMPILER_DUMPVERSION _OUTPUT_VERSION)
|
||||
execute_process(
|
||||
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 AND NOT OS2)
|
||||
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 AND NOT OS2)
|
||||
|
||||
# HEADER FILES
|
||||
check_include_file(argp.h HAVE_ARGP_H)
|
||||
check_include_file(pty.h HAVE_PTY_H)
|
||||
check_include_file(terminos.h HAVE_TERMIOS_H)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
set(HAVE_GETADDRINFO TRUE)
|
||||
set(HAVE_GETHOSTBYNAME TRUE)
|
||||
@@ -49,6 +69,17 @@ check_include_file(openssl/des.h HAVE_OPENSSL_DES_H)
|
||||
|
||||
# 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)
|
||||
# libsocket (Solaris)
|
||||
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")
|
||||
|
||||
# LIBRARIES
|
||||
if (CRYPTO_FOUND)
|
||||
if (OPENSSL_FOUND)
|
||||
set(HAVE_LIBCRYPTO 1)
|
||||
endif (CRYPTO_FOUND)
|
||||
endif (OPENSSL_FOUND)
|
||||
|
||||
if (GCRYPT_FOUND)
|
||||
set(HAVE_LIBGCRYPT 1)
|
||||
@@ -104,4 +135,6 @@ if (WITH_DEBUG_CALLTRACE)
|
||||
endif (WITH_DEBUG_CALLTRACE)
|
||||
|
||||
# ENDIAN
|
||||
test_big_endian(WORDS_BIGENDIAN)
|
||||
if (NOT WIN32)
|
||||
test_big_endian(WORDS_BIGENDIAN)
|
||||
endif (NOT WIN32)
|
||||
|
||||
@@ -3,27 +3,27 @@
|
||||
include(CheckCCompilerFlag)
|
||||
|
||||
if (UNIX AND NOT WIN32)
|
||||
if (CMAKE_COMPILER_IS_GNUCC)
|
||||
if (${CMAKE_C_COMPILER_ID} MATCHES GNU)
|
||||
# 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")
|
||||
|
||||
# with -fPIC
|
||||
check_c_compiler_flag("-fPIC" WITH_FPIC)
|
||||
if (WITH_FPIC)
|
||||
add_definitions(-fPIC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
|
||||
endif (WITH_FPIC)
|
||||
|
||||
check_c_compiler_flag("-fstack-protector" WITH_STACK_PROTECTOR)
|
||||
if (WITH_STACK_PROTECTOR)
|
||||
add_definitions(-fstack-protector)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector")
|
||||
endif (WITH_STACK_PROTECTOR)
|
||||
|
||||
check_c_compiler_flag("-D_FORTIFY_SOURCE=2" 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 (CMAKE_COMPILER_IS_GNUCC)
|
||||
endif (${CMAKE_C_COMPILER_ID} MATCHES GNU)
|
||||
|
||||
if (CMAKE_SIZEOF_VOID_P MATCHES "8")
|
||||
# with large file support
|
||||
@@ -48,12 +48,12 @@ if (UNIX AND NOT WIN32)
|
||||
endif (CMAKE_SIZEOF_VOID_P MATCHES "8")
|
||||
if (_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 (UNIX AND NOT WIN32)
|
||||
|
||||
# suppress warning about "deprecated" functions
|
||||
if (MSVC)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_CRT_SECURE_NO_WARNINGS")
|
||||
endif (MSVC)
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
if (UNIX)
|
||||
if (WIN32)
|
||||
# Same same
|
||||
set(BIN_INSTALL_DIR "bin" CACHE PATH "-")
|
||||
set(SBIN_INSTALL_DIR "." CACHE PATH "-")
|
||||
set(LIB_INSTALL_DIR "lib" CACHE PATH "-")
|
||||
set(INCLUDE_INSTALL_DIR "include" CACHE PATH "-")
|
||||
set(PLUGIN_INSTALL_DIR "plugins" CACHE PATH "-")
|
||||
set(HTML_INSTALL_DIR "doc/HTML" CACHE PATH "-")
|
||||
set(ICON_INSTALL_DIR "." CACHE PATH "-")
|
||||
set(SOUND_INSTALL_DIR "." CACHE PATH "-")
|
||||
set(LOCALE_INSTALL_DIR "lang" CACHE PATH "-")
|
||||
elseif (UNIX OR OS2)
|
||||
IF (NOT APPLICATION_NAME)
|
||||
MESSAGE(STATUS "${PROJECT_NAME} is used as APPLICATION_NAME")
|
||||
SET(APPLICATION_NAME ${PROJECT_NAME})
|
||||
@@ -90,18 +101,4 @@ if (UNIX)
|
||||
"${SHARE_INSTALL_PREFIX}/info"
|
||||
CACHE PATH "The ${APPLICATION_NAME} info install dir (default prefix/info)"
|
||||
)
|
||||
endif (UNIX)
|
||||
|
||||
if (WIN32)
|
||||
# Same same
|
||||
set(BIN_INSTALL_DIR "bin" CACHE PATH "-")
|
||||
set(SBIN_INSTALL_DIR "." CACHE PATH "-")
|
||||
set(LIB_INSTALL_DIR "lib" CACHE PATH "-")
|
||||
set(INCLUDE_INSTALL_DIR "include" CACHE PATH "-")
|
||||
set(PLUGIN_INSTALL_DIR "plugins" CACHE PATH "-")
|
||||
set(HTML_INSTALL_DIR "doc/HTML" CACHE PATH "-")
|
||||
set(ICON_INSTALL_DIR "." CACHE PATH "-")
|
||||
set(SOUND_INSTALL_DIR "." CACHE PATH "-")
|
||||
set(LOCALE_INSTALL_DIR "lang" CACHE PATH "-")
|
||||
endif (WIN32)
|
||||
|
||||
endif ()
|
||||
|
||||
25
cmake/Modules/DefinePlatformDefaults.cmake
Normal file
25
cmake/Modules/DefinePlatformDefaults.cmake
Normal file
@@ -0,0 +1,25 @@
|
||||
# Set system vars
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
set(LINUX TRUE)
|
||||
endif(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
|
||||
set(FREEBSD TRUE)
|
||||
endif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "OpenBSD")
|
||||
set(OPENBSD TRUE)
|
||||
endif (CMAKE_SYSTEM_NAME MATCHES "OpenBSD")
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "NetBSD")
|
||||
set(NETBSD TRUE)
|
||||
endif (CMAKE_SYSTEM_NAME MATCHES "NetBSD")
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)")
|
||||
set(SOLARIS TRUE)
|
||||
endif (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)")
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "OS2")
|
||||
set(OS2 TRUE)
|
||||
endif (CMAKE_SYSTEM_NAME MATCHES "OS2")
|
||||
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
|
||||
set(OPENSSL_FOUND TRUE)
|
||||
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
|
||||
# in the FIND_PATH() and FIND_LIBRARY() calls
|
||||
if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
|
||||
@@ -34,6 +38,7 @@ else (OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIRS)
|
||||
NAMES
|
||||
openssl/ssl.h
|
||||
PATHS
|
||||
${_OPENSSL_DIR}/include
|
||||
${_OPENSSL_INCLUDEDIR}
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
@@ -47,8 +52,10 @@ else (OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIRS)
|
||||
find_library(SSL_LIBRARY
|
||||
NAMES
|
||||
ssl
|
||||
ssl_dl
|
||||
libssl
|
||||
PATHS
|
||||
${_OPENSSL_DIR}/lib
|
||||
${_OPENSSL_LIBDIR}
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
@@ -64,6 +71,7 @@ else (OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIRS)
|
||||
NAMES
|
||||
ssleay32
|
||||
PATHS
|
||||
${_OPENSSL_DIR}/lib
|
||||
${_OPENSSL_LIBDIR}
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
@@ -79,6 +87,7 @@ else (OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIRS)
|
||||
NAMES
|
||||
ssleay32MD
|
||||
PATHS
|
||||
${_OPENSSL_DIR}/lib
|
||||
${_OPENSSL_LIBDIR}
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
@@ -93,12 +102,14 @@ else (OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIRS)
|
||||
find_library(CRYPTO_LIBRARY
|
||||
NAMES
|
||||
crypto
|
||||
crypto_dl
|
||||
libcrypto
|
||||
eay
|
||||
eay32
|
||||
libeay
|
||||
libeay32
|
||||
PATHS
|
||||
${_OPENSSL_DIR}/lib
|
||||
${_OPENSSL_LIBDIR}
|
||||
/lib
|
||||
/usr/lib
|
||||
|
||||
@@ -18,11 +18,15 @@ if (ZLIB_LIBRARIES AND ZLIB_INCLUDE_DIRS)
|
||||
# in cache already
|
||||
set(ZLIB_FOUND TRUE)
|
||||
else (ZLIB_LIBRARIES AND ZLIB_INCLUDE_DIRS)
|
||||
if (WIN32)
|
||||
set(_ZLIB_DIR $ENV{PROGRAMFILES}/GnuWin32)
|
||||
endif (WIN32)
|
||||
|
||||
find_path(ZLIB_INCLUDE_DIR
|
||||
NAMES
|
||||
zlib.h
|
||||
PATHS
|
||||
${_ZLIB_DIR}/include
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/opt/local/include
|
||||
@@ -36,6 +40,7 @@ else (ZLIB_LIBRARIES AND ZLIB_INCLUDE_DIRS)
|
||||
zlib
|
||||
zlib1
|
||||
PATHS
|
||||
${_ZLIB_DIR}/lib
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/opt/local/lib
|
||||
|
||||
@@ -1,127 +1,100 @@
|
||||
# -helper macro to add a "doc" target with CMake build system.
|
||||
# and configure doxy.config.in to doxy.config
|
||||
# - Run Doxygen
|
||||
#
|
||||
# target "doc" allows building the documentation with doxygen/dot on WIN32 and Linux
|
||||
# Creates .chm windows help file if MS HTML help workshop
|
||||
# (available from http://msdn.microsoft.com/workshop/author/htmlhelp)
|
||||
# is installed with its DLLs in PATH.
|
||||
# Adds a doxygen target that runs doxygen to generate the html
|
||||
# and optionally the LaTeX API documentation.
|
||||
# The doxygen target is added to the doc target as dependency.
|
||||
# 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.:
|
||||
# doxygen, dot, latex, dvips, makeindex, gswin32, etc.
|
||||
# must be in path.
|
||||
# Variables you may define are:
|
||||
# DOXYFILE_OUTPUT_DIR - Path where the Doxygen output is stored. Defaults to "doc".
|
||||
#
|
||||
# Note about Visual Studio Projects:
|
||||
# MSVS has its own path environment which may differ from the shell.
|
||||
# See "Menu Tools/Options/Projects/VC++ Directories" in VS 7.1
|
||||
# DOXYFILE_LATEX_DIR - Directory where the Doxygen LaTeX output is stored. Defaults to "latex".
|
||||
#
|
||||
# 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 (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)")
|
||||
SET(DOXY_WARN_FORMAT "\"$file($line) : $text \"")
|
||||
ELSE (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)")
|
||||
SET(DOXY_WARN_FORMAT "\"$file:$line: $text \"")
|
||||
ENDIF (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)")
|
||||
if(DOXYGEN_FOUND)
|
||||
find_file(DOXYFILE_IN
|
||||
NAMES
|
||||
doxy.config.in
|
||||
PATHS
|
||||
${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
|
||||
FIND_PACKAGE(LATEX)
|
||||
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(DOXYGEN_FOUND AND DOXYFILE_IN_FOUND)
|
||||
add_custom_target(doxygen ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxy.config)
|
||||
|
||||
IF (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config.in")
|
||||
MESSAGE(STATUS "Generate ${CMAKE_CURRENT_BINARY_DIR}/doxy.config from doxy.config.in")
|
||||
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")
|
||||
usedoxygen_set_default(DOXYFILE_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
usedoxygen_set_default(DOXYFILE_HTML_DIR "html")
|
||||
|
||||
ENDIF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config")
|
||||
ENDIF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config.in")
|
||||
set_property(DIRECTORY APPEND PROPERTY
|
||||
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
|
||||
# HTMLHelp DLL must be in path!
|
||||
# fallback: use hhw.exe interactively
|
||||
IF (WIN32)
|
||||
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)
|
||||
find_package(LATEX)
|
||||
if(LATEX_COMPILER AND MAKEINDEX_COMPILER)
|
||||
set(DOXYFILE_LATEX TRUE)
|
||||
usedoxygen_set_default(DOXYFILE_LATEX_DIR "latex")
|
||||
|
||||
ENDIF(HTML_HELP_COMPILER)
|
||||
# MESSAGE(SEND_ERROR "HTML_HELP_COMPILER=${HTML_HELP_COMPILER}")
|
||||
ENDIF (WIN32)
|
||||
ENDIF(DOXYGEN_FOUND)
|
||||
set_property(DIRECTORY APPEND PROPERTY
|
||||
ADDITIONAL_MAKE_CLEAN_FILES
|
||||
"${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}")
|
||||
|
||||
if(PDFLATEX_COMPILER)
|
||||
set(DOXYFILE_PDFLATEX TRUE)
|
||||
endif()
|
||||
if(DOXYGEN_DOT_EXECUTABLE)
|
||||
set(DOXYFILE_DOT TRUE)
|
||||
endif()
|
||||
|
||||
add_custom_command(TARGET doxygen
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_MAKE_PROGRAM}
|
||||
WORKING_DIRECTORY "${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}")
|
||||
endif()
|
||||
|
||||
configure_file(${DOXYFILE_IN} ${CMAKE_CURRENT_BINARY_DIR}/doxy.config ESCAPE_QUOTES IMMEDIATE @ONLY)
|
||||
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/doxy.trac.in)
|
||||
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 ***************************/
|
||||
|
||||
/* 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. */
|
||||
#cmakedefine HAVE_CFMAKERAW 1
|
||||
|
||||
@@ -94,17 +125,3 @@
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||
#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
|
||||
# doxygen (www.doxygen.org) for a project
|
||||
@@ -57,8 +57,8 @@ CREATE_SUBDIRS = NO
|
||||
# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek,
|
||||
# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages),
|
||||
# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish,
|
||||
# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene,
|
||||
# Spanish, Swedish, and Ukrainian.
|
||||
# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish,
|
||||
# and Ukrainian.
|
||||
|
||||
OUTPUT_LANGUAGE = English
|
||||
|
||||
@@ -165,6 +165,13 @@ QT_AUTOBRIEF = 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
|
||||
# member inherits the documentation from any documented member that it
|
||||
# re-implements.
|
||||
@@ -217,17 +224,6 @@ OPTIMIZE_FOR_FORTRAN = 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
|
||||
# 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
|
||||
@@ -237,7 +233,7 @@ EXTENSION_MAPPING =
|
||||
|
||||
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.
|
||||
|
||||
CPP_CLI_SUPPORT = NO
|
||||
@@ -280,23 +276,7 @@ SUBGROUPING = YES
|
||||
# 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.
|
||||
|
||||
TYPEDEF_HIDES_STRUCT = NO
|
||||
|
||||
# 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
|
||||
TYPEDEF_HIDES_STRUCT = YES
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
@@ -425,7 +405,7 @@ SORT_GROUP_NAMES = NO
|
||||
# sorted by fully-qualified names, including namespaces. If set to
|
||||
# NO (the default), the class list will be sorted only by class name,
|
||||
# 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
|
||||
# alphabetical list.
|
||||
|
||||
@@ -482,15 +462,14 @@ SHOW_USED_FILES = YES
|
||||
|
||||
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
|
||||
# Folder Tree View (if specified). The default is YES.
|
||||
|
||||
SHOW_FILES = YES
|
||||
|
||||
# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
|
||||
# Namespaces page.
|
||||
# This will remove the Namespaces entry from the Quick Index
|
||||
# Namespaces page. This will remove the Namespaces entry from the Quick Index
|
||||
# and from the Folder Tree View (if specified). The default is YES.
|
||||
|
||||
SHOW_NAMESPACES = YES
|
||||
@@ -505,15 +484,6 @@ SHOW_NAMESPACES = YES
|
||||
|
||||
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
|
||||
#---------------------------------------------------------------------------
|
||||
@@ -575,7 +545,8 @@ WARN_LOGFILE = @CMAKE_CURRENT_BINARY_DIR@/doxy.log
|
||||
# with spaces.
|
||||
|
||||
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
|
||||
# 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
|
||||
# the \include command).
|
||||
|
||||
EXAMPLE_PATH = @CMAKE_SOURCE_DIR@/tests \
|
||||
@CMAKE_SOURCE_DIR@
|
||||
EXAMPLE_PATH = @CMAKE_SOURCE_DIR@/examples
|
||||
|
||||
# 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
|
||||
# and *.h) to filter out the source-files in the directories. If left
|
||||
# blank all files are included.
|
||||
|
||||
EXAMPLE_PATTERNS = *.cpp \
|
||||
*.cc \
|
||||
EXAMPLE_PATTERNS = *.c \
|
||||
*.h \
|
||||
*.hh \
|
||||
INSTALL \
|
||||
DEPENDENCIES \
|
||||
CHANGELOG \
|
||||
@@ -678,17 +646,14 @@ IMAGE_PATH =
|
||||
# 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
|
||||
# input file. Doxygen will then use the output that the filter program writes
|
||||
# to standard output.
|
||||
# If FILTER_PATTERNS is specified, this tag will be
|
||||
# to standard output. If FILTER_PATTERNS is specified, this tag will be
|
||||
# ignored.
|
||||
|
||||
INPUT_FILTER =
|
||||
|
||||
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
|
||||
# basis.
|
||||
# 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:
|
||||
# basis. 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:
|
||||
# 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
|
||||
# is applied to all files.
|
||||
@@ -735,11 +700,10 @@ REFERENCED_BY_RELATION = YES
|
||||
|
||||
REFERENCES_RELATION = YES
|
||||
|
||||
# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
|
||||
# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
|
||||
# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
|
||||
# link to the source code.
|
||||
# Otherwise they will link to the documentation.
|
||||
# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
|
||||
# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
|
||||
# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
|
||||
# link to the source code. Otherwise they will link to the documentstion.
|
||||
|
||||
REFERENCES_LINK_SOURCE = YES
|
||||
|
||||
@@ -828,13 +792,12 @@ HTML_STYLESHEET =
|
||||
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
|
||||
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
|
||||
# documentation will contain sections that can be hidden and shown after the
|
||||
# page has loaded. For this to work a browser that supports
|
||||
# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
|
||||
# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
|
||||
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
|
||||
# will be generated that can be used as input for tools like the
|
||||
# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
|
||||
# of the generated HTML documentation.
|
||||
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
GENERATE_HTMLHELP = NO
|
||||
|
||||
# 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
|
||||
@@ -843,8 +806,7 @@ HTML_DYNAMIC_SECTIONS = NO
|
||||
# HTML output directory. Running make will produce the docset in that
|
||||
# directory and running "make install" will install the docset in
|
||||
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
|
||||
# it at startup.
|
||||
# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
|
||||
# it at startup.
|
||||
|
||||
GENERATE_DOCSET = NO
|
||||
|
||||
@@ -862,12 +824,13 @@ DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||
|
||||
DOCSET_BUNDLE_ID = org.doxygen.Project
|
||||
|
||||
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
|
||||
# will be generated that can be used as input for tools like the
|
||||
# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
|
||||
# of the generated HTML documentation.
|
||||
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
|
||||
# documentation will contain sections that can be hidden and shown after the
|
||||
# page has loaded. For this to work a browser that supports
|
||||
# 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
|
||||
# be used to specify the file name of the resulting .chm file. You
|
||||
@@ -889,8 +852,8 @@ HHC_LOCATION =
|
||||
|
||||
GENERATE_CHI = NO
|
||||
|
||||
# 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
|
||||
# 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
|
||||
# content.
|
||||
|
||||
CHM_INDEX_ENCODING =
|
||||
@@ -906,55 +869,6 @@ BINARY_TOC = 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
|
||||
# top of each HTML page. The value NO (the default) enables the index and
|
||||
# the value YES disables it.
|
||||
@@ -966,19 +880,19 @@ DISABLE_INDEX = NO
|
||||
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
|
||||
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
|
||||
# structure should be generated to display hierarchical information.
|
||||
# If the tag value is set to FRAME, a side panel will be generated
|
||||
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
|
||||
# structure should be generated to display hierarchical information.
|
||||
# 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
|
||||
# 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+,
|
||||
# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
|
||||
# probably better off using the HTML help feature. Other possible values
|
||||
# for this tag are: HIERARCHIES, which will generate the Groups, Directories,
|
||||
# and Class Hierarchy pages using a tree view instead of an ordered list;
|
||||
# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which
|
||||
# disables this behavior completely. For backwards compatibility with previous
|
||||
# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE
|
||||
# for this tag are: HIERARCHIES, which will generate the Groups, Directories,
|
||||
# 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
|
||||
# disables this behavior completely. For backwards compatibility with previous
|
||||
# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE
|
||||
# respectively.
|
||||
|
||||
GENERATE_TREEVIEW = NO
|
||||
@@ -1004,7 +918,7 @@ FORMULA_FONTSIZE = 10
|
||||
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
|
||||
# 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.
|
||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||
@@ -1209,10 +1123,8 @@ GENERATE_PERLMOD = NO
|
||||
PERLMOD_LATEX = NO
|
||||
|
||||
# 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.
|
||||
# This is useful
|
||||
# if you want to understand what is going on.
|
||||
# On the other hand, if this
|
||||
# nicely formatted so it can be parsed by a human reader. This is useful
|
||||
# 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
|
||||
# and Perl will parse it just the same.
|
||||
|
||||
@@ -1299,16 +1211,14 @@ SKIP_FUNCTION_MACROS = YES
|
||||
# Optionally an initial location of the external documentation
|
||||
# can be added for each tagfile. The format of a tag file without
|
||||
# this location is as follows:
|
||||
#
|
||||
# TAGFILES = file1 file2 ...
|
||||
# TAGFILES = file1 file2 ...
|
||||
# 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
|
||||
# URLs. If a location is present for each tag, the installdox tool
|
||||
# does not have to be run to correct the links.
|
||||
# Note that each tag file must have a unique name
|
||||
# (where the name does NOT include the path)
|
||||
# does not have to be run to correct the links.
|
||||
# Note that each tag file must have a unique name
|
||||
# (where the name does NOT include the path)
|
||||
# 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.
|
||||
|
||||
@@ -1382,11 +1292,6 @@ HAVE_DOT = @DOXYGEN_DOT_FOUND@
|
||||
|
||||
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
|
||||
# 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
|
||||
@@ -1429,7 +1334,7 @@ TEMPLATE_RELATIONS = YES
|
||||
# file showing the direct and indirect include dependencies of the file with
|
||||
# other documented files.
|
||||
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDE_GRAPH = NO
|
||||
|
||||
# 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
|
||||
@@ -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
|
||||
# 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
|
||||
# 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
|
||||
# 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
|
||||
# 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
|
||||
# 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.
|
||||
|
||||
DIRECTORY_GRAPH = YES
|
||||
|
||||
# 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.
|
||||
|
||||
DOT_IMAGE_FORMAT = png
|
||||
@@ -1504,10 +1409,10 @@ DOT_GRAPH_MAX_NODES = 50
|
||||
MAX_DOT_GRAPH_DEPTH = 0
|
||||
|
||||
# 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
|
||||
# seem to support this out of the box. Warning: Depending on the platform used,
|
||||
# enabling this option may lead to badly anti-aliased labels on the edges of
|
||||
# a graph (i.e. they become hard to read).
|
||||
# background. This is enabled by default, which results in a transparent
|
||||
# background. Warning: Depending on the platform used, enabling this option
|
||||
# may lead to badly anti-aliased labels on the edges of a graph (i.e. they
|
||||
# become hard to read).
|
||||
|
||||
DOT_TRANSPARENT = NO
|
||||
|
||||
@@ -1531,7 +1436,7 @@ GENERATE_LEGEND = 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
|
||||
|
||||
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(scp_download scp_download.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(scp_download ${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(
|
||||
${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;
|
||||
#endif
|
||||
|
||||
char *proxycommand;
|
||||
|
||||
static int auth_callback(const char *prompt, char *buf, size_t len,
|
||||
int echo, int verify, void *userdata) {
|
||||
char *answer = NULL;
|
||||
@@ -95,6 +97,9 @@ static void usage(){
|
||||
" -r : use RSA to verify host public key\n"
|
||||
#ifdef WITH_PCAP
|
||||
" -P file : create a pcap debugging file\n"
|
||||
#endif
|
||||
#ifndef _WIN32
|
||||
" -T proxycommand : command to execute as a socket proxy\n"
|
||||
#endif
|
||||
,
|
||||
ssh_version(0));
|
||||
@@ -106,12 +111,17 @@ static int opts(int argc, char **argv){
|
||||
// for(i=0;i<argc;i++)
|
||||
// printf("%d : %s\n",i,argv[i]);
|
||||
/* insert your own arguments here */
|
||||
while((i=getopt(argc,argv,"P:"))!=-1){
|
||||
while((i=getopt(argc,argv,"T:P:"))!=-1){
|
||||
switch(i){
|
||||
#ifdef WITH_PCAP
|
||||
case 'P':
|
||||
pcap_file=optarg;
|
||||
break;
|
||||
#endif
|
||||
#ifndef _WIN32
|
||||
case 'T':
|
||||
proxycommand=optarg;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
fprintf(stderr,"unknown option %c\n",optopt);
|
||||
@@ -432,7 +442,10 @@ static int client(ssh_session session){
|
||||
return -1;
|
||||
if (ssh_options_set(session, SSH_OPTIONS_HOST ,host) < 0)
|
||||
return -1;
|
||||
|
||||
if (proxycommand != NULL){
|
||||
if(ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, proxycommand))
|
||||
return -1;
|
||||
}
|
||||
ssh_options_parse_config(session, NULL);
|
||||
|
||||
if(ssh_connect(session)){
|
||||
|
||||
@@ -152,10 +152,12 @@ static void do_sftp(ssh_session session){
|
||||
}
|
||||
/* reading the whole directory, file by file */
|
||||
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->permissions,
|
||||
file->owner,
|
||||
file->uid,
|
||||
file->group,
|
||||
file->gid,
|
||||
(long long unsigned int) file->size);
|
||||
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
|
||||
callbacks.h
|
||||
libssh.h
|
||||
crypto.h
|
||||
ssh2.h
|
||||
)
|
||||
|
||||
|
||||
@@ -22,8 +22,7 @@
|
||||
#ifndef BUFFER_H_
|
||||
#define BUFFER_H_
|
||||
|
||||
/** Describes a buffer state at a moment
|
||||
*/
|
||||
/* Describes a buffer state */
|
||||
struct ssh_buffer_struct {
|
||||
char *data;
|
||||
uint32_t used;
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#if __GNUC__ >= 4
|
||||
#if __GNUC__ >= 4 && !defined(__OS2__)
|
||||
#define LIBSSH_API __attribute__((visibility("default")))
|
||||
#else
|
||||
#define LIBSSH_API
|
||||
@@ -50,6 +50,7 @@
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/* Visual Studio hasn't inttypes.h so it doesn't know uint32_t */
|
||||
typedef int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned char uint8_t;
|
||||
@@ -78,7 +79,7 @@
|
||||
/* libssh version */
|
||||
#define LIBSSH_VERSION_MAJOR 0
|
||||
#define LIBSSH_VERSION_MINOR 4
|
||||
#define LIBSSH_VERSION_MICRO 0
|
||||
#define LIBSSH_VERSION_MICRO 8
|
||||
|
||||
#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \
|
||||
LIBSSH_VERSION_MINOR, \
|
||||
@@ -118,10 +119,16 @@ typedef struct ssh_string_struct* ssh_string;
|
||||
|
||||
/* Socket type */
|
||||
#ifdef _WIN32
|
||||
#define socket_t SOCKET
|
||||
#else
|
||||
#ifndef socket_t
|
||||
typedef SOCKET socket_t;
|
||||
#endif /* socket_t */
|
||||
#else /* _WIN32 */
|
||||
#ifndef socket_t
|
||||
typedef int socket_t;
|
||||
#endif
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#define SSH_INVALID_SOCKET ((socket_t) -1)
|
||||
|
||||
/* the offsets of methods */
|
||||
enum ssh_kex_types_e {
|
||||
@@ -164,7 +171,7 @@ enum ssh_requests_e {
|
||||
SSH_REQUEST_CHANNEL_OPEN,
|
||||
SSH_REQUEST_CHANNEL,
|
||||
SSH_REQUEST_SERVICE,
|
||||
SSH_REQUEST_GLOBAL,
|
||||
SSH_REQUEST_GLOBAL
|
||||
};
|
||||
|
||||
enum ssh_channel_type_e {
|
||||
@@ -182,7 +189,7 @@ enum ssh_channel_requests_e {
|
||||
SSH_CHANNEL_REQUEST_SHELL,
|
||||
SSH_CHANNEL_REQUEST_ENV,
|
||||
SSH_CHANNEL_REQUEST_SUBSYSTEM,
|
||||
SSH_CHANNEL_REQUEST_WINDOW_CHANGE,
|
||||
SSH_CHANNEL_REQUEST_WINDOW_CHANGE
|
||||
};
|
||||
|
||||
/* status flags */
|
||||
@@ -196,7 +203,7 @@ enum ssh_server_known_e {
|
||||
SSH_SERVER_KNOWN_OK,
|
||||
SSH_SERVER_KNOWN_CHANGED,
|
||||
SSH_SERVER_FOUND_OTHER,
|
||||
SSH_SERVER_FILE_NOT_FOUND,
|
||||
SSH_SERVER_FILE_NOT_FOUND
|
||||
};
|
||||
|
||||
#ifndef MD5_DIGEST_LEN
|
||||
@@ -230,7 +237,7 @@ enum {
|
||||
/** Only rare and noteworthy events
|
||||
*/
|
||||
SSH_LOG_RARE,
|
||||
/** High level protocol informations
|
||||
/** High level protocol information
|
||||
*/
|
||||
SSH_LOG_PROTOCOL,
|
||||
/** Lower level protocol infomations, packet level
|
||||
@@ -251,6 +258,7 @@ enum ssh_options_e {
|
||||
SSH_OPTIONS_USER,
|
||||
SSH_OPTIONS_SSH_DIR,
|
||||
SSH_OPTIONS_IDENTITY,
|
||||
SSH_OPTIONS_ADD_IDENTITY,
|
||||
SSH_OPTIONS_KNOWNHOSTS,
|
||||
SSH_OPTIONS_TIMEOUT,
|
||||
SSH_OPTIONS_TIMEOUT_USEC,
|
||||
@@ -262,7 +270,9 @@ enum ssh_options_e {
|
||||
SSH_OPTIONS_CIPHERS_C_S,
|
||||
SSH_OPTIONS_CIPHERS_S_C,
|
||||
SSH_OPTIONS_COMPRESSION_C_S,
|
||||
SSH_OPTIONS_COMPRESSION_S_C
|
||||
SSH_OPTIONS_COMPRESSION_S_C,
|
||||
SSH_OPTIONS_PROXYCOMMAND,
|
||||
SSH_OPTIONS_BINDADDR
|
||||
};
|
||||
|
||||
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,
|
||||
int type, const char *passphrase);
|
||||
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,
|
||||
int *type);
|
||||
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 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 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 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_privatekey_type(ssh_private_key privatekey);
|
||||
|
||||
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_close(ssh_scp scp);
|
||||
|
||||
@@ -25,8 +25,12 @@
|
||||
/* in misc.c */
|
||||
/* gets the user home dir. */
|
||||
char *ssh_get_user_home_dir(void);
|
||||
char *ssh_get_local_username(ssh_session session);
|
||||
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 */
|
||||
uint64_t ntohll(uint64_t);
|
||||
#define htonll(x) ntohll(x)
|
||||
@@ -46,14 +50,12 @@ struct ssh_iterator {
|
||||
struct ssh_list *ssh_list_new(void);
|
||||
void ssh_list_free(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);
|
||||
char *ssh_hostport(const char *host, int port);
|
||||
|
||||
/** @brief fetch the head element of a list and remove it from 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);
|
||||
const void *_ssh_list_pop_head(struct ssh_list *list);
|
||||
|
||||
#define ssh_iterator_value(type, iterator)\
|
||||
((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
|
||||
* @param type type of the element to return
|
||||
* @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)\
|
||||
((type)_ssh_list_get_head(ssh_list))
|
||||
#define ssh_list_pop_head(type, ssh_list)\
|
||||
((type)_ssh_list_pop_head(ssh_list))
|
||||
|
||||
#endif /* MISC_H_ */
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#ifdef WITH_PCAP
|
||||
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);
|
||||
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);
|
||||
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 */
|
||||
|
||||
@@ -38,9 +38,48 @@ typedef struct ssh_pollfd_struct {
|
||||
short revents; /* returned events */
|
||||
} 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 */
|
||||
#ifndef POLLIN
|
||||
# define POLLIN 0x001 /* There is data to read. */
|
||||
#define POLLIN 0x001 /* There is data to read. */
|
||||
#endif
|
||||
#ifndef POLLPRI
|
||||
#define POLLPRI 0x002 /* There is urgent data to read. */
|
||||
@@ -59,9 +98,24 @@ typedef struct ssh_pollfd_struct {
|
||||
#define POLLNVAL 0x020 /* Invalid polling request. */
|
||||
#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 */
|
||||
|
||||
void ssh_poll_init(void);
|
||||
void ssh_poll_cleanup(void);
|
||||
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_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
|
||||
* 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);
|
||||
|
||||
|
||||
|
||||
@@ -32,18 +32,72 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
/** Imitate define of inttypes.h */
|
||||
#define PRIdS "Id"
|
||||
#define strcasecmp _stricmp
|
||||
#define strncasecmp _strnicmp
|
||||
#define strtoull _strtoui64
|
||||
#define isblank(ch) ((ch) == ' ' || (ch) == '\t' || (ch) == '\n' || (ch) == '\r')
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
|
||||
/* Imitate define of inttypes.h */
|
||||
# ifndef PRIdS
|
||||
# define PRIdS "Id"
|
||||
# endif
|
||||
|
||||
# ifdef _MSC_VER
|
||||
# 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>
|
||||
#define PRIdS "zd"
|
||||
#endif
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#include "libssh/libssh.h"
|
||||
#include "libssh/callbacks.h"
|
||||
@@ -77,7 +131,7 @@ typedef struct kex_struct {
|
||||
|
||||
struct error_struct {
|
||||
/* error handling */
|
||||
int error_code;
|
||||
unsigned int error_code;
|
||||
char error_buffer[ERROR_BUFFERLEN];
|
||||
};
|
||||
|
||||
@@ -185,6 +239,11 @@ int match_hostname(const char *host, const char *pattern, unsigned int len);
|
||||
|
||||
/* log.c */
|
||||
|
||||
/* misc.c */
|
||||
#ifdef _WIN32
|
||||
int gettimeofday(struct timeval *__p, void *__t);
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#ifndef __FUNCTION__
|
||||
#if defined(__SUNPRO_C)
|
||||
#define __FUNCTION__ __func__
|
||||
@@ -217,8 +276,8 @@ int match_hostname(const char *host, const char *pattern, unsigned int len);
|
||||
|
||||
/* 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_apply(ssh_session session);
|
||||
|
||||
/** Free memory space */
|
||||
#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.
|
||||
*
|
||||
* @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,
|
||||
enum ssh_bind_options_e type, const void *value);
|
||||
|
||||
@@ -102,9 +102,9 @@ struct ssh_session_struct {
|
||||
#endif
|
||||
char *username;
|
||||
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 *identity;
|
||||
struct ssh_list *identity;
|
||||
char *sshdir;
|
||||
char *knownhosts;
|
||||
char *wanted_methods[10];
|
||||
@@ -114,8 +114,9 @@ struct ssh_session_struct {
|
||||
socket_t fd;
|
||||
int ssh2;
|
||||
int ssh1;
|
||||
char *ProxyCommand;
|
||||
};
|
||||
|
||||
int ssh_handle_packets(ssh_session session);
|
||||
|
||||
void ssh_global_request_handle(ssh_session session);
|
||||
#endif /* SESSION_H_ */
|
||||
|
||||
@@ -149,17 +149,16 @@ struct sftp_status_message_struct {
|
||||
char *langmsg;
|
||||
};
|
||||
|
||||
/* don't worry much of these aren't really used */
|
||||
struct sftp_attributes_struct {
|
||||
char *name;
|
||||
char *longname; /* some weird stuff */
|
||||
char *longname; /* ls -l output on openssh, not reliable else */
|
||||
uint32_t flags;
|
||||
uint8_t type;
|
||||
uint64_t size;
|
||||
uint32_t uid;
|
||||
uint32_t gid;
|
||||
char *owner;
|
||||
char *group;
|
||||
char *owner; /* set if openssh and version 4 */
|
||||
char *group; /* set if openssh and version 4 */
|
||||
uint32_t permissions;
|
||||
uint64_t atime64;
|
||||
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_set_fd(struct socket *s, socket_t fd);
|
||||
socket_t ssh_socket_get_fd(struct socket *s);
|
||||
void ssh_socket_cleanup(void);
|
||||
#ifndef _WIN32
|
||||
int ssh_socket_unix(struct socket *s, const char *path);
|
||||
#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_is_open(struct socket *s);
|
||||
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_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);
|
||||
@@ -52,4 +53,10 @@ int ssh_socket_get_status(struct socket *s);
|
||||
int ssh_socket_data_available(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_ */
|
||||
|
||||
@@ -70,6 +70,11 @@ typedef HMAC_CTX* HMACCTX;
|
||||
#define MD5_DIGEST_LEN MD5_DIGEST_LENGTH
|
||||
|
||||
#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 BN_CTX* bignum_CTX;
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ if (HAVE_LIBSOCKET)
|
||||
)
|
||||
endif (HAVE_LIBSOCKET)
|
||||
|
||||
if (CRYPTO_LIBRARY)
|
||||
if (OPENSSL_LIBRARIES)
|
||||
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
||||
${LIBSSH_PRIVATE_INCLUDE_DIRS}
|
||||
${OPENSSL_INCLUDE_DIRS}
|
||||
@@ -51,9 +51,9 @@ if (CRYPTO_LIBRARY)
|
||||
|
||||
set(LIBSSH_LINK_LIBRARIES
|
||||
${LIBSSH_LINK_LIBRARIES}
|
||||
${CRYPTO_LIBRARY}
|
||||
${OPENSSL_LIBRARIES}
|
||||
)
|
||||
endif (CRYPTO_LIBRARY)
|
||||
endif (OPENSSL_LIBRARIES)
|
||||
|
||||
if (GCRYPT_LIBRARY)
|
||||
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
@@ -54,6 +53,7 @@
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/keys.h"
|
||||
#include "libssh/poll.h"
|
||||
|
||||
/* macro to check for "agent failure" message */
|
||||
#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;
|
||||
size_t pos = 0;
|
||||
ssize_t res;
|
||||
struct pollfd pfd;
|
||||
int fd = ssh_socket_get_fd(s);
|
||||
ssh_pollfd_t pfd;
|
||||
socket_t fd = ssh_socket_get_fd(s);
|
||||
|
||||
pfd.fd = fd;
|
||||
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
|
||||
if (errno == EAGAIN) {
|
||||
#endif
|
||||
(void) poll(&pfd, 1, -1);
|
||||
(void) ssh_poll(&pfd, 1, -1);
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
|
||||
292
libssh/auth.c
292
libssh/auth.c
@@ -35,6 +35,7 @@
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/agent.h"
|
||||
#include "libssh/keyfiles.h"
|
||||
#include "libssh/misc.h"
|
||||
#include "libssh/packet.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/keys.h"
|
||||
@@ -169,24 +170,33 @@ static int wait_auth_status(ssh_session session, int kbdint) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief retrieves available authentication methods for this session
|
||||
* @deprecated
|
||||
* @see ssh_userauth_list
|
||||
*/
|
||||
int ssh_auth_list(ssh_session session) {
|
||||
if (session == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return session->auth_methods;
|
||||
return ssh_userauth_list(session, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
if (session == NULL || username == NULL) {
|
||||
if (session == NULL) {
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
if (session->auth_methods == 0) {
|
||||
ssh_userauth_none(session, username);
|
||||
}
|
||||
|
||||
return ssh_auth_list(session);
|
||||
return session->auth_methods;
|
||||
}
|
||||
|
||||
/* use the "none" authentication question */
|
||||
@@ -224,7 +234,7 @@ int ssh_userauth_none(ssh_session session, const char *username) {
|
||||
|
||||
if (username == NULL) {
|
||||
if (session->username == NULL) {
|
||||
if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
|
||||
if (ssh_options_apply(session) < 0) {
|
||||
leave_function();
|
||||
return rc;
|
||||
}
|
||||
@@ -330,7 +340,7 @@ int ssh_userauth_offer_pubkey(ssh_session session, const char *username,
|
||||
|
||||
if (username == NULL) {
|
||||
if (session->username == NULL) {
|
||||
if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
|
||||
if (ssh_options_apply(session) < 0) {
|
||||
leave_function();
|
||||
return rc;
|
||||
}
|
||||
@@ -442,7 +452,7 @@ int ssh_userauth_pubkey(ssh_session session, const char *username,
|
||||
|
||||
if (username == NULL) {
|
||||
if (session->username == NULL) {
|
||||
if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
|
||||
if (ssh_options_apply(session) < 0) {
|
||||
leave_function();
|
||||
return rc;
|
||||
}
|
||||
@@ -560,7 +570,7 @@ int ssh_userauth_agent_pubkey(ssh_session session, const char *username,
|
||||
|
||||
if (username == NULL) {
|
||||
if (session->username == NULL) {
|
||||
if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
|
||||
if (ssh_options_apply(session) < 0) {
|
||||
leave_function();
|
||||
return rc;
|
||||
}
|
||||
@@ -687,7 +697,7 @@ int ssh_userauth_password(ssh_session session, const char *username,
|
||||
|
||||
if (username == NULL) {
|
||||
if (session->username == NULL) {
|
||||
if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
|
||||
if (ssh_options_apply(session) < 0) {
|
||||
leave_function();
|
||||
return rc;
|
||||
}
|
||||
@@ -756,42 +766,6 @@ error:
|
||||
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"
|
||||
*
|
||||
@@ -812,16 +786,12 @@ static struct ssh_keys_struct keytab[] = {
|
||||
*
|
||||
* @see ssh_userauth_kbdint()
|
||||
* @see ssh_userauth_password()
|
||||
* @see ssh_options_set()
|
||||
*/
|
||||
int ssh_userauth_autopubkey(ssh_session session, const char *passphrase) {
|
||||
struct ssh_public_key_struct *publickey;
|
||||
ssh_string pubkey;
|
||||
struct ssh_iterator *it;
|
||||
ssh_private_key privkey;
|
||||
char *privkeyfile = NULL;
|
||||
char *id = NULL;
|
||||
size_t size;
|
||||
unsigned int i = 0;
|
||||
ssh_public_key pubkey;
|
||||
ssh_string pubkey_string;
|
||||
int type = 0;
|
||||
int rc;
|
||||
|
||||
@@ -837,142 +807,159 @@ int ssh_userauth_autopubkey(ssh_session session, const char *passphrase) {
|
||||
/* Try authentication with ssh-agent first */
|
||||
#ifndef _WIN32
|
||||
if (agent_is_running(session)) {
|
||||
char *privkey_file = NULL;
|
||||
|
||||
ssh_log(session, SSH_LOG_RARE,
|
||||
"Trying to authenticate with SSH agent keys as user: %s",
|
||||
session->username);
|
||||
|
||||
for (publickey = agent_get_first_ident(session, &privkeyfile);
|
||||
publickey != NULL;
|
||||
publickey = agent_get_next_ident(session, &privkeyfile)) {
|
||||
for (pubkey = agent_get_first_ident(session, &privkey_file);
|
||||
pubkey != NULL;
|
||||
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);
|
||||
if (pubkey) {
|
||||
rc = ssh_userauth_offer_pubkey(session, NULL, publickey->type, pubkey);
|
||||
string_free(pubkey);
|
||||
pubkey_string = publickey_to_string(pubkey);
|
||||
if (pubkey_string) {
|
||||
rc = ssh_userauth_offer_pubkey(session, NULL, pubkey->type, pubkey_string);
|
||||
string_free(pubkey_string);
|
||||
if (rc == SSH_AUTH_ERROR) {
|
||||
SAFE_FREE(id);
|
||||
SAFE_FREE(privkeyfile);
|
||||
publickey_free(publickey);
|
||||
SAFE_FREE(privkey_file);
|
||||
publickey_free(pubkey);
|
||||
leave_function();
|
||||
|
||||
return rc;
|
||||
} else if (rc != SSH_AUTH_SUCCESS) {
|
||||
ssh_log(session, SSH_LOG_PACKET, "Public key refused by server\n");
|
||||
SAFE_FREE(id);
|
||||
SAFE_FREE(privkeyfile);
|
||||
publickey_free(publickey);
|
||||
ssh_log(session, SSH_LOG_PROTOCOL, "Public key refused by server");
|
||||
SAFE_FREE(privkey_file);
|
||||
publickey_free(pubkey);
|
||||
continue;
|
||||
}
|
||||
ssh_log(session, SSH_LOG_RARE, "Public key accepted");
|
||||
/* 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) {
|
||||
SAFE_FREE(id);
|
||||
SAFE_FREE(privkeyfile);
|
||||
publickey_free(publickey);
|
||||
SAFE_FREE(privkey_file);
|
||||
publickey_free(pubkey);
|
||||
leave_function();
|
||||
|
||||
return rc;
|
||||
} else if (rc != SSH_AUTH_SUCCESS) {
|
||||
ssh_log(session, SSH_LOG_RARE,
|
||||
"Server accepted public key but refused the signature\n"
|
||||
"It might be a bug of libssh\n");
|
||||
SAFE_FREE(id);
|
||||
SAFE_FREE(privkeyfile);
|
||||
publickey_free(publickey);
|
||||
"Server accepted public key but refused the signature ;"
|
||||
" It might be a bug of libssh");
|
||||
SAFE_FREE(privkey_file);
|
||||
publickey_free(pubkey);
|
||||
continue;
|
||||
}
|
||||
/* auth success */
|
||||
ssh_log(session, SSH_LOG_RARE, "Authentication using %s success\n",
|
||||
privkeyfile);
|
||||
SAFE_FREE(id);
|
||||
SAFE_FREE(privkeyfile);
|
||||
publickey_free(publickey);
|
||||
ssh_log(session, SSH_LOG_PROTOCOL, "Authentication using %s success",
|
||||
privkey_file);
|
||||
SAFE_FREE(privkey_file);
|
||||
publickey_free(pubkey);
|
||||
|
||||
leave_function();
|
||||
|
||||
return SSH_AUTH_SUCCESS;
|
||||
} /* if pubkey */
|
||||
SAFE_FREE(id);
|
||||
SAFE_FREE(privkeyfile);
|
||||
publickey_free(publickey);
|
||||
SAFE_FREE(privkey_file);
|
||||
publickey_free(pubkey);
|
||||
} /* for each privkey */
|
||||
} /* if agent is running */
|
||||
#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);
|
||||
if (id == NULL) {
|
||||
leave_function();
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
sprintf(id, "%s.pub", session->identity);
|
||||
for (it = ssh_list_get_iterator(session->identity);
|
||||
it != NULL;
|
||||
it = it->next) {
|
||||
const char *privkey_file = it->data;
|
||||
int privkey_open = 0;
|
||||
|
||||
keytab[size - 1].privatekey = session->identity;
|
||||
keytab[size - 1].publickey = id;
|
||||
}
|
||||
privkey = NULL;
|
||||
|
||||
for (i = 0, pubkey = try_publickey_from_file(session, keytab[i],
|
||||
&privkeyfile, &type);
|
||||
i < size;
|
||||
pubkey = try_publickey_from_file(session, keytab[i++],
|
||||
&privkeyfile, &type)) {
|
||||
if (pubkey == NULL) {
|
||||
ssh_log(session, SSH_LOG_PROTOCOL, "Trying to read privatekey %s", privkey_file);
|
||||
|
||||
rc = ssh_try_publickey_from_file(session, privkey_file, &pubkey_string, &type);
|
||||
if (rc == 1) {
|
||||
char *publickey_file;
|
||||
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;
|
||||
}
|
||||
|
||||
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 (id != NULL) {
|
||||
keytab[size - 1].privatekey = NULL;
|
||||
keytab[size - 1].publickey = NULL;
|
||||
SAFE_FREE(id);
|
||||
}
|
||||
string_free(pubkey);
|
||||
SAFE_FREE(privkeyfile);
|
||||
string_free(pubkey_string);
|
||||
ssh_log(session, SSH_LOG_RARE, "Publickey authentication error");
|
||||
leave_function();
|
||||
return rc;
|
||||
} else {
|
||||
if (rc != SSH_AUTH_SUCCESS){
|
||||
ssh_log(session, SSH_LOG_RARE, "Publickey refused by server");
|
||||
string_free(pubkey);
|
||||
pubkey = NULL;
|
||||
SAFE_FREE(privkeyfile);
|
||||
privkeyfile = NULL;
|
||||
ssh_log(session, SSH_LOG_PROTOCOL, "Publickey refused by server");
|
||||
string_free(pubkey_string);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Public key accepted by server! */
|
||||
ssh_log(session, SSH_LOG_RARE, "Trying to read privatekey %s", privkeyfile);
|
||||
privkey = privatekey_from_file(session, privkeyfile, type, passphrase);
|
||||
if (privkey == NULL) {
|
||||
ssh_log(session, SSH_LOG_FUNCTIONS,
|
||||
"Reading private key %s failed (bad passphrase ?)",
|
||||
privkeyfile);
|
||||
string_free(pubkey);
|
||||
pubkey = NULL;
|
||||
SAFE_FREE(privkeyfile);
|
||||
privkeyfile = NULL;
|
||||
continue; /* continue the loop with other pubkey */
|
||||
if (!privkey_open) {
|
||||
ssh_log(session, SSH_LOG_PROTOCOL, "Trying to read privatekey %s",
|
||||
privkey_file);
|
||||
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);
|
||||
string_free(pubkey_string);
|
||||
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 (id != NULL) {
|
||||
keytab[size - 1].privatekey = NULL;
|
||||
keytab[size - 1].publickey = NULL;
|
||||
SAFE_FREE(id);
|
||||
}
|
||||
string_free(pubkey);
|
||||
SAFE_FREE(privkeyfile);
|
||||
string_free(pubkey_string);
|
||||
privatekey_free(privkey);
|
||||
leave_function();
|
||||
return rc;
|
||||
@@ -980,39 +967,26 @@ int ssh_userauth_autopubkey(ssh_session session, const char *passphrase) {
|
||||
if (rc != SSH_AUTH_SUCCESS){
|
||||
ssh_log(session, SSH_LOG_FUNCTIONS,
|
||||
"The server accepted the public key but refused the signature");
|
||||
string_free(pubkey);
|
||||
pubkey = NULL;
|
||||
SAFE_FREE(privkeyfile);
|
||||
privkeyfile = NULL;
|
||||
string_free(pubkey_string);
|
||||
privatekey_free(privkey);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* auth success */
|
||||
ssh_log(session, SSH_LOG_RARE,
|
||||
"Successfully authenticated using %s", privkeyfile);
|
||||
string_free(pubkey);
|
||||
ssh_log(session, SSH_LOG_PROTOCOL,
|
||||
"Successfully authenticated using %s", privkey_file);
|
||||
string_free(pubkey_string);
|
||||
privatekey_free(privkey);
|
||||
SAFE_FREE(privkeyfile);
|
||||
if (id != NULL) {
|
||||
keytab[size - 1].privatekey = NULL;
|
||||
keytab[size - 1].publickey = NULL;
|
||||
SAFE_FREE(id);
|
||||
}
|
||||
|
||||
leave_function();
|
||||
return SSH_AUTH_SUCCESS;
|
||||
}
|
||||
|
||||
/* at this point, pubkey is NULL and so is privkeyfile */
|
||||
ssh_log(session, SSH_LOG_FUNCTIONS,
|
||||
"Tried every public key, none 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();
|
||||
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 */
|
||||
if (user == NULL) {
|
||||
if ((user = session->username) == NULL) {
|
||||
if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
|
||||
if (ssh_options_apply(session) < 0) {
|
||||
leave_function();
|
||||
return SSH_AUTH_ERROR;
|
||||
} 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.
|
||||
* 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
|
||||
* pass in).
|
||||
*/
|
||||
|
||||
@@ -165,8 +165,10 @@ static int channel_open(ssh_channel channel, const char *type_c, int window,
|
||||
type_c, channel->local_channel);
|
||||
|
||||
if (packet_wait(session, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, 1) != SSH_OK) {
|
||||
leave_function();
|
||||
return -1;
|
||||
if(session->in_packet.type != SSH2_MSG_CHANNEL_OPEN_FAILURE) {
|
||||
leave_function();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
switch(session->in_packet.type) {
|
||||
@@ -552,6 +554,15 @@ static void channel_rcv_request(ssh_session session) {
|
||||
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 */
|
||||
/* *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 informations to handle.
|
||||
* channel information to handle.
|
||||
*/
|
||||
void channel_handle(ssh_session session, int type){
|
||||
enter_function();
|
||||
@@ -785,7 +796,7 @@ void channel_free(ssh_channel channel) {
|
||||
*
|
||||
* @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
|
||||
*
|
||||
* @see channel_close()
|
||||
@@ -828,7 +839,7 @@ error:
|
||||
*
|
||||
* @param channel The channel to close.
|
||||
*
|
||||
* @return SSH_SUCCESS on success\n
|
||||
* @return SSH_OK on success\n
|
||||
* SSH_ERROR on error
|
||||
*
|
||||
* @see channel_free()
|
||||
@@ -1107,7 +1118,7 @@ error:
|
||||
*
|
||||
* @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 col, int row) {
|
||||
@@ -1158,7 +1169,7 @@ error:
|
||||
*
|
||||
* @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()
|
||||
*/
|
||||
@@ -1219,7 +1230,7 @@ error:
|
||||
*
|
||||
* @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) {
|
||||
#ifdef WITH_SSH1
|
||||
@@ -1237,7 +1248,7 @@ int channel_request_shell(ssh_channel channel) {
|
||||
*
|
||||
* @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().
|
||||
*/
|
||||
@@ -1359,6 +1370,7 @@ static ssh_channel channel_accept(ssh_session session, int channeltype,
|
||||
};
|
||||
#endif
|
||||
ssh_message msg = NULL;
|
||||
ssh_channel channel = NULL;
|
||||
struct ssh_iterator *iterator;
|
||||
int t;
|
||||
|
||||
@@ -1373,16 +1385,20 @@ static ssh_channel channel_accept(ssh_session session, int channeltype,
|
||||
if (ssh_message_type(msg) == SSH_REQUEST_CHANNEL_OPEN &&
|
||||
ssh_message_subtype(msg) == channeltype) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
if(t>0){
|
||||
#ifdef _WIN32
|
||||
Sleep(50); /* 50ms */
|
||||
Sleep(50); /* 50ms */
|
||||
#else
|
||||
nanosleep(&ts, NULL);
|
||||
nanosleep(&ts, NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -1582,7 +1598,7 @@ error:
|
||||
*
|
||||
* @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.
|
||||
* */
|
||||
@@ -1633,7 +1649,7 @@ error:
|
||||
* @param cmd The command to execute
|
||||
* (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()
|
||||
*/
|
||||
@@ -1683,7 +1699,7 @@ error:
|
||||
* @param signal The signal to send (without SIG prefix)
|
||||
* (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) {
|
||||
@@ -1806,7 +1822,7 @@ int channel_read_buffer(ssh_channel channel, ssh_buffer buffer, uint32_t count,
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
/* write the ful buffer informations */
|
||||
/* write the ful buffer information */
|
||||
if (buffer_add_data(buffer, buffer_get_rest(stdbuf),
|
||||
buffer_get_rest_len(stdbuf)) < 0) {
|
||||
leave_function();
|
||||
@@ -1995,9 +2011,10 @@ int channel_poll(ssh_channel channel, int is_stderr){
|
||||
stdbuf = channel->stderr_buffer;
|
||||
}
|
||||
|
||||
while (buffer_get_rest_len(stdbuf) == 0 && channel->remote_eof == 0) {
|
||||
if (ssh_handle_packets(channel->session) <= 0) {
|
||||
break;
|
||||
if (buffer_get_rest_len(stdbuf) == 0 && channel->remote_eof == 0) {
|
||||
if (ssh_handle_packets(channel->session) == SSH_ERROR) {
|
||||
leave_function();
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2137,7 +2154,7 @@ static int count_ptrs(ssh_channel *ptrs) {
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
int channel_select(ssh_channel *readchans, ssh_channel *writechans,
|
||||
@@ -2147,7 +2164,7 @@ int channel_select(ssh_channel *readchans, ssh_channel *writechans,
|
||||
fd_set rset;
|
||||
fd_set wset;
|
||||
fd_set eset;
|
||||
int fdmax = -1;
|
||||
socket_t max_fd = SSH_INVALID_SOCKET;
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
@@ -2215,24 +2232,24 @@ int channel_select(ssh_channel *readchans, ssh_channel *writechans,
|
||||
|
||||
for (i = 0; readchans[i] != NULL; i++) {
|
||||
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++) {
|
||||
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++) {
|
||||
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 */
|
||||
rc = select(fdmax, &rset, &wset, &eset, timeout);
|
||||
rc = select(max_fd, &rset, &wset, &eset, timeout);
|
||||
/* Leave if select was interrupted */
|
||||
if (rc == EINTR) {
|
||||
SAFE_FREE(rchans);
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#ifndef _WIN32
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/ssh1.h"
|
||||
#include "libssh/buffer.h"
|
||||
|
||||
@@ -110,26 +110,37 @@ static int ssh_analyze_banner(ssh_session session, int *ssh1, int *ssh2) {
|
||||
const char *banner = session->serverbanner;
|
||||
const char *openssh;
|
||||
|
||||
ssh_log(session, SSH_LOG_RARE, "Analyzing banner: %s", banner);
|
||||
|
||||
if (strncmp(banner, "SSH-", 4) != 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Protocol mismatch: %s", banner);
|
||||
return -1;
|
||||
if (banner == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "Invalid banner");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Typical banners e.g. are:
|
||||
* SSH-1.5-blah
|
||||
* SSH-1.99-blah
|
||||
* SSH-2.0-blah
|
||||
*
|
||||
* SSH-1.5-openSSH_5.4
|
||||
* SSH-1.99-openSSH_3.0
|
||||
*
|
||||
* SSH-2.0-something
|
||||
* 012345678901234567890
|
||||
*/
|
||||
if (strlen(banner) < 6 ||
|
||||
strncmp(banner, "SSH-", 4) != 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Protocol mismatch: %s", banner);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssh_log(session, SSH_LOG_RARE, "Analyzing banner: %s", banner);
|
||||
|
||||
switch(banner[4]) {
|
||||
case '1':
|
||||
*ssh1 = 1;
|
||||
if (banner[6] == '9') {
|
||||
*ssh2 = 1;
|
||||
} else {
|
||||
*ssh2 = 0;
|
||||
if (strlen(banner) > 6) {
|
||||
if (banner[6] == '9') {
|
||||
*ssh2 = 1;
|
||||
} else {
|
||||
*ssh2 = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '2':
|
||||
@@ -143,13 +154,21 @@ static int ssh_analyze_banner(ssh_session session, int *ssh1, int *ssh2) {
|
||||
|
||||
openssh = strstr(banner, "OpenSSH");
|
||||
if (openssh != NULL) {
|
||||
int major, minor;
|
||||
major = strtol(openssh + 8, (char **) NULL, 10);
|
||||
minor = strtol(openssh + 10, (char **) NULL, 10);
|
||||
session->openssh = SSH_VERSION_INT(major, minor, 0);
|
||||
ssh_log(session, SSH_LOG_RARE,
|
||||
"We are talking to an OpenSSH server version: %d.%d (%x)",
|
||||
major, minor, session->openssh);
|
||||
int major, minor;
|
||||
|
||||
/*
|
||||
* The banner is typical:
|
||||
* OpenSSH_5.4
|
||||
* 012345678901234567890
|
||||
*/
|
||||
if (strlen(openssh) > 9) {
|
||||
major = strtol(openssh + 8, (char **) NULL, 10);
|
||||
minor = strtol(openssh + 10, (char **) NULL, 10);
|
||||
session->openssh = SSH_VERSION_INT(major, minor, 0);
|
||||
ssh_log(session, SSH_LOG_RARE,
|
||||
"We are talking to an OpenSSH client version: %d.%d (%x)",
|
||||
major, minor, session->openssh);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -296,6 +315,7 @@ static int dh_handshake(ssh_session session) {
|
||||
goto error;
|
||||
}
|
||||
session->dh_server_signature = signature;
|
||||
signature=NULL; /* ownership changed */
|
||||
if (dh_build_k(session) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
|
||||
rc = SSH_ERROR;
|
||||
@@ -400,10 +420,6 @@ error:
|
||||
string_burn(f);
|
||||
string_free(f);
|
||||
}
|
||||
if(pubkey != NULL){
|
||||
string_burn(pubkey);
|
||||
string_free(pubkey);
|
||||
}
|
||||
if(signature != NULL){
|
||||
string_burn(signature);
|
||||
string_free(signature);
|
||||
@@ -484,7 +500,8 @@ int ssh_service_request(ssh_session session, const char *service) {
|
||||
int ssh_connect(ssh_session session) {
|
||||
int ssh1 = 0;
|
||||
int ssh2 = 0;
|
||||
int fd = -1;
|
||||
socket_t fd = SSH_INVALID_SOCKET;
|
||||
int ret;
|
||||
|
||||
if (session == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "Invalid session pointer");
|
||||
@@ -500,18 +517,31 @@ int ssh_connect(ssh_session session) {
|
||||
leave_function();
|
||||
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");
|
||||
leave_function();
|
||||
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;
|
||||
#ifndef _WIN32
|
||||
} else if (session->ProxyCommand != NULL) {
|
||||
fd=ssh_socket_connect_proxycommand(session, session->ProxyCommand);
|
||||
#endif
|
||||
} else {
|
||||
fd = ssh_connect_host(session, session->host, session->bindaddr,
|
||||
session->port, session->timeout, session->timeout_usec);
|
||||
}
|
||||
if (fd < 0) {
|
||||
if (fd == SSH_INVALID_SOCKET) {
|
||||
leave_function();
|
||||
return SSH_ERROR;
|
||||
}
|
||||
@@ -699,7 +729,7 @@ error:
|
||||
const char *ssh_copyright(void) {
|
||||
return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2008 Aris Adamantiadis "
|
||||
"(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: */
|
||||
|
||||
@@ -35,11 +35,11 @@ enum ssh_config_opcode_e {
|
||||
SOC_PORT,
|
||||
SOC_USERNAME,
|
||||
SOC_IDENTITY,
|
||||
SOC_CIPHER,
|
||||
SOC_CIPHERS,
|
||||
SOC_COMPRESSION,
|
||||
SOC_TIMEOUT,
|
||||
SOC_PROTOCOL
|
||||
SOC_PROTOCOL,
|
||||
SOC_PROXYCOMMAND
|
||||
};
|
||||
|
||||
struct ssh_config_keyword_table_s {
|
||||
@@ -53,11 +53,11 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
|
||||
{ "port", SOC_PORT },
|
||||
{ "user", SOC_USERNAME },
|
||||
{ "identityfile", SOC_IDENTITY },
|
||||
{ "cipher", SOC_CIPHER },
|
||||
{ "ciphers", SOC_CIPHERS },
|
||||
{ "compression", SOC_COMPRESSION },
|
||||
{ "connecttimeout", SOC_TIMEOUT },
|
||||
{ "protocol", SOC_PROTOCOL },
|
||||
{ "proxycommand", SOC_PROXYCOMMAND },
|
||||
{ NULL, SOC_UNSUPPORTED }
|
||||
};
|
||||
|
||||
@@ -199,21 +199,25 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
|
||||
}
|
||||
break;
|
||||
case SOC_PORT:
|
||||
p = ssh_config_get_str(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_PORT_STR, p);
|
||||
if (session->port == 22) {
|
||||
p = ssh_config_get_str(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_PORT_STR, p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SOC_USERNAME:
|
||||
p = ssh_config_get_str(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_USER, p);
|
||||
if (session->username == NULL) {
|
||||
p = ssh_config_get_str(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_USER, p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SOC_IDENTITY:
|
||||
p = ssh_config_get_str(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_IDENTITY, p);
|
||||
ssh_options_set(session, SSH_OPTIONS_ADD_IDENTITY, p);
|
||||
}
|
||||
break;
|
||||
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);
|
||||
if (i >= 0 && *parsing) {
|
||||
if (i) {
|
||||
ssh_options_set(session, SSH_OPTIONS_COMPRESSION_C_S, "zlib");
|
||||
ssh_options_set(session, SSH_OPTIONS_COMPRESSION_S_C, "zlib");
|
||||
ssh_options_set(session, SSH_OPTIONS_COMPRESSION_C_S, "zlib,none");
|
||||
ssh_options_set(session, SSH_OPTIONS_COMPRESSION_S_C, "zlib,none");
|
||||
} else {
|
||||
ssh_options_set(session, SSH_OPTIONS_COMPRESSION_C_S, "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);
|
||||
}
|
||||
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:
|
||||
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;
|
||||
default:
|
||||
fprintf(stderr, "ERROR - unimplemented opcode: %d\n", opcode);
|
||||
ssh_set_error(session, SSH_FATAL, "ERROR - unimplemented opcode: %d\n",
|
||||
opcode);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
break;
|
||||
|
||||
@@ -67,10 +67,7 @@
|
||||
#include "libssh/socket.h"
|
||||
#include "libssh/channels.h"
|
||||
#include "libssh/session.h"
|
||||
|
||||
#ifndef HAVE_SELECT
|
||||
#error "Your system must have select()"
|
||||
#endif
|
||||
#include "libssh/poll.h"
|
||||
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
#error "Your system must have getaddrinfo()"
|
||||
@@ -202,29 +199,35 @@ static int getai(ssh_session session, const char *host, int port, struct addrinf
|
||||
|
||||
static int ssh_connect_ai_timeout(ssh_session session, const char *host,
|
||||
int port, struct addrinfo *ai, long timeout, long usec, socket_t s) {
|
||||
struct timeval to;
|
||||
fd_set set;
|
||||
int timeout_ms;
|
||||
ssh_pollfd_t fds;
|
||||
int rc = 0;
|
||||
unsigned int len = sizeof(rc);
|
||||
|
||||
enter_function();
|
||||
|
||||
to.tv_sec = timeout;
|
||||
to.tv_usec = usec;
|
||||
/* I know we're losing some precision. But it's not like poll-like family
|
||||
* type of mechanisms are precise up to the microsecond.
|
||||
*/
|
||||
timeout_ms=timeout * 1000 + usec / 1000;
|
||||
|
||||
sock_set_nonblocking(s);
|
||||
|
||||
ssh_log(session, SSH_LOG_RARE, "Trying to connect to host: %s:%d with "
|
||||
"timeout %ld.%ld", host, port, timeout, usec);
|
||||
"timeout %d ms", host, port, timeout_ms);
|
||||
|
||||
/* The return value is checked later */
|
||||
connect(s, ai->ai_addr, ai->ai_addrlen);
|
||||
freeaddrinfo(ai);
|
||||
|
||||
FD_ZERO(&set);
|
||||
FD_SET(s, &set);
|
||||
fds.fd=s;
|
||||
fds.revents=0;
|
||||
fds.events=POLLOUT;
|
||||
#ifdef _WIN32
|
||||
fds.events |= POLLWRNORM;
|
||||
#endif
|
||||
rc = ssh_poll(&fds,1,timeout_ms);
|
||||
|
||||
rc = select(s + 1, NULL, &set, NULL, &to);
|
||||
if (rc == 0) {
|
||||
/* timeout */
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
@@ -236,7 +239,7 @@ static int ssh_connect_ai_timeout(ssh_session session, const char *host,
|
||||
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Select error: %s", strerror(errno));
|
||||
"poll error: %s", strerror(errno));
|
||||
ssh_connect_socket_close(s);
|
||||
leave_function();
|
||||
return -1;
|
||||
@@ -341,7 +344,6 @@ socket_t ssh_connect_host(ssh_session session, const char *host,
|
||||
ssh_set_error(session, SSH_FATAL, "Connect failed: %s", strerror(errno));
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
leave_function();
|
||||
continue;
|
||||
} else {
|
||||
/* We are connected */
|
||||
@@ -391,6 +393,7 @@ int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
|
||||
fd_set *readfds, struct timeval *timeout) {
|
||||
struct timeval zerotime;
|
||||
fd_set localset, localset2;
|
||||
socket_t f;
|
||||
int rep;
|
||||
int set;
|
||||
int i;
|
||||
@@ -431,8 +434,8 @@ int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
|
||||
|
||||
/* Look into the localset for active fd */
|
||||
set = 0;
|
||||
for (i = 0; (i < maxfd) && !set; i++) {
|
||||
if (FD_ISSET(i, &localset)) {
|
||||
for (f = 0; (f < maxfd) && !set; f++) {
|
||||
if (FD_ISSET(f, &localset)) {
|
||||
set = 1;
|
||||
}
|
||||
}
|
||||
@@ -494,9 +497,9 @@ int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
|
||||
outchannels[j] = NULL;
|
||||
|
||||
FD_ZERO(&localset2);
|
||||
for (i = 0; i < maxfd; i++) {
|
||||
if (FD_ISSET(i, readfds) && FD_ISSET(i, &localset)) {
|
||||
FD_SET(i, &localset2);
|
||||
for (f = 0; f < maxfd; f++) {
|
||||
if (FD_ISSET(f, readfds) && FD_ISSET(i, &localset)) {
|
||||
FD_SET(f, &localset2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -222,6 +222,8 @@ void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len) {
|
||||
return;
|
||||
}
|
||||
printf("%s: %s\n", descr, hexa);
|
||||
|
||||
free(hexa);
|
||||
}
|
||||
|
||||
int dh_generate_x(ssh_session session) {
|
||||
@@ -831,8 +833,11 @@ int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash) {
|
||||
if (session == NULL || hash == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*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);
|
||||
if (h == NULL) {
|
||||
|
||||
@@ -65,6 +65,7 @@ int ssh_init(void) {
|
||||
int ssh_finalize(void) {
|
||||
ssh_regex_finalize();
|
||||
ssh_crypto_finalize();
|
||||
ssh_socket_cleanup();
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_control(GCRYCTL_TERM_SECMEM);
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
|
||||
72
libssh/kex.c
72
libssh/kex.c
@@ -40,10 +40,11 @@
|
||||
#include "libssh/wrapper.h"
|
||||
#include "libssh/keys.h"
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/string.h"
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
#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"
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
#ifdef HAVE_OPENSSL_BLOWFISH_H
|
||||
@@ -52,10 +53,15 @@
|
||||
#define BLOWFISH ""
|
||||
#endif
|
||||
#ifdef HAVE_OPENSSL_AES_H
|
||||
#ifdef BROKEN_AES_CTR
|
||||
#define AES "aes256-cbc,aes192-cbc,aes128-cbc,"
|
||||
#else
|
||||
#define AES "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,"
|
||||
#endif /* BROKEN_AES_CTR */
|
||||
#else
|
||||
#define AES ""
|
||||
#endif
|
||||
|
||||
#define DES "3des-cbc"
|
||||
#endif
|
||||
|
||||
@@ -67,7 +73,7 @@
|
||||
|
||||
const char *default_methods[] = {
|
||||
"diffie-hellman-group1-sha1",
|
||||
"ssh-dss,ssh-rsa",
|
||||
"ssh-rsa,ssh-dss",
|
||||
AES BLOWFISH DES,
|
||||
AES BLOWFISH DES,
|
||||
"hmac-sha1",
|
||||
@@ -81,7 +87,7 @@ const char *default_methods[] = {
|
||||
|
||||
const char *supported_methods[] = {
|
||||
"diffie-hellman-group1-sha1",
|
||||
"ssh-dss,ssh-rsa",
|
||||
"ssh-rsa,ssh-dss",
|
||||
AES BLOWFISH DES,
|
||||
AES BLOWFISH DES,
|
||||
"hmac-sha1",
|
||||
@@ -194,48 +200,48 @@ char **space_tokenize(const char *chain){
|
||||
return tokens;
|
||||
}
|
||||
|
||||
/* find_matching gets 2 parameters : a list of available objects (in_d), separated by colons,*/
|
||||
/* and a list of prefered objects (what_d) */
|
||||
/* find_matching gets 2 parameters : a list of available objects (available_d), separated by colons,*/
|
||||
/* 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 */
|
||||
|
||||
char *ssh_find_matching(const char *in_d, const char *what_d){
|
||||
char ** tok_in, **tok_what;
|
||||
int i_in, i_what;
|
||||
char *ssh_find_matching(const char *available_d, const char *preferred_d){
|
||||
char ** tok_available, **tok_preferred;
|
||||
int i_avail, i_pref;
|
||||
char *ret;
|
||||
|
||||
if ((in_d == NULL) || (what_d == NULL)) {
|
||||
if ((available_d == NULL) || (preferred_d == NULL)) {
|
||||
return NULL; /* don't deal with null args */
|
||||
}
|
||||
|
||||
tok_in = tokenize(in_d);
|
||||
if (tok_in == NULL) {
|
||||
tok_available = tokenize(available_d);
|
||||
if (tok_available == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tok_what = tokenize(what_d);
|
||||
if (tok_what == NULL) {
|
||||
SAFE_FREE(tok_in[0]);
|
||||
SAFE_FREE(tok_in);
|
||||
tok_preferred = tokenize(preferred_d);
|
||||
if (tok_preferred == NULL) {
|
||||
SAFE_FREE(tok_available[0]);
|
||||
SAFE_FREE(tok_available);
|
||||
}
|
||||
|
||||
for(i_in=0; tok_in[i_in]; ++i_in){
|
||||
for(i_what=0; tok_what[i_what] ; ++i_what){
|
||||
if(!strcmp(tok_in[i_in],tok_what[i_what])){
|
||||
/* match */
|
||||
ret=strdup(tok_in[i_in]);
|
||||
/* free the tokens */
|
||||
free(tok_in[0]);
|
||||
free(tok_what[0]);
|
||||
free(tok_in);
|
||||
free(tok_what);
|
||||
return ret;
|
||||
}
|
||||
for(i_pref=0; tok_preferred[i_pref] ; ++i_pref){
|
||||
for(i_avail=0; tok_available[i_avail]; ++i_avail){
|
||||
if(!strcmp(tok_available[i_avail],tok_preferred[i_pref])){
|
||||
/* match */
|
||||
ret=strdup(tok_available[i_avail]);
|
||||
/* free the tokens */
|
||||
free(tok_available[0]);
|
||||
free(tok_preferred[0]);
|
||||
free(tok_available);
|
||||
free(tok_preferred);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(tok_in[0]);
|
||||
free(tok_what[0]);
|
||||
free(tok_in);
|
||||
free(tok_what);
|
||||
free(tok_available[0]);
|
||||
free(tok_preferred[0]);
|
||||
free(tok_available);
|
||||
free(tok_preferred);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -487,8 +493,8 @@ static int build_session_id1(ssh_session session, ssh_string servern,
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("host modulus",hostn->string,string_len(hostn));
|
||||
ssh_print_hexa("server modulus",servern->string,string_len(servern));
|
||||
ssh_print_hexa("host modulus",string_data(hostn),string_len(hostn));
|
||||
ssh_print_hexa("server modulus",string_data(servern),string_len(servern));
|
||||
#endif
|
||||
md5_update(md5,string_data(hostn),string_len(hostn));
|
||||
md5_update(md5,string_data(servern),string_len(servern));
|
||||
|
||||
@@ -59,15 +59,15 @@
|
||||
#endif /* HAVE_LIBCRYPTO */
|
||||
|
||||
#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
|
||||
|
||||
#define MAX_KEY_SIZE 32
|
||||
#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_SEQUENCE 48
|
||||
#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 */
|
||||
|
||||
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
|
||||
* @{
|
||||
*/
|
||||
@@ -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
|
||||
* \param session SSH Session
|
||||
* \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.
|
||||
* \returns a PRIVATE_KEY object containing the private key, or NULL if it failed.
|
||||
* \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",
|
||||
filename, passphrase ? "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) {
|
||||
case TYPE_DSS:
|
||||
if (passphrase == NULL) {
|
||||
if (session->callbacks->auth_function) {
|
||||
if (session->callbacks && session->callbacks->auth_function) {
|
||||
auth_cb = session->callbacks->auth_function;
|
||||
auth_ud = session->callbacks->userdata;
|
||||
|
||||
@@ -731,6 +756,7 @@ ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fclose(file);
|
||||
ssh_set_error(session, SSH_FATAL, "Invalid private key type %d", type);
|
||||
return NULL;
|
||||
} /* switch */
|
||||
@@ -754,6 +780,20 @@ ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
|
||||
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. */
|
||||
ssh_private_key _privatekey_from_file(void *session, const char *filename,
|
||||
int type) {
|
||||
@@ -861,6 +901,79 @@ void privatekey_free(ssh_private_key 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
|
||||
* \param session the SSH session
|
||||
* \param filename Filename of the key
|
||||
@@ -938,10 +1051,85 @@ ssh_string publickey_from_file(ssh_session session, const char *filename,
|
||||
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,
|
||||
char **privkeyfile, int *type) {
|
||||
char *public;
|
||||
char *private;
|
||||
const char *priv;
|
||||
const char *pub;
|
||||
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 (ssh_options_set(session, SSH_OPTIONS_SSH_DIR, NULL) < 0) {
|
||||
if (ssh_options_apply(session) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* are them readable ? */
|
||||
public=dir_expand_dup(session,pub,1);
|
||||
private=dir_expand_dup(session,priv,1);
|
||||
//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);
|
||||
ssh_log(session, SSH_LOG_PACKET, "Trying to open publickey %s", pub);
|
||||
if (!ssh_file_readaccess_ok(pub)) {
|
||||
ssh_log(session, SSH_LOG_PACKET, "Failed to open publickey %s", pub);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ssh_log(session, SSH_LOG_PACKET, "Trying to open privatekey %s", private);
|
||||
if (!ssh_file_readaccess_ok(private)) {
|
||||
ssh_log(session, SSH_LOG_PACKET, "Failed to open privatekey %s", private);
|
||||
ssh_log(session, SSH_LOG_PACKET, "Trying to open privatekey %s", priv);
|
||||
if (!ssh_file_readaccess_ok(priv)) {
|
||||
ssh_log(session, SSH_LOG_PACKET, "Failed to open privatekey %s", priv);
|
||||
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
|
||||
* 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) {
|
||||
ssh_log(session, SSH_LOG_PACKET,
|
||||
"Wasn't able to open public key file %s: %s",
|
||||
public,
|
||||
pub,
|
||||
ssh_get_error(session));
|
||||
goto error;
|
||||
}
|
||||
|
||||
new = realloc(*privkeyfile, strlen(private) + 1);
|
||||
new = realloc(*privkeyfile, strlen(priv) + 1);
|
||||
if (new == NULL) {
|
||||
string_free(pubkey);
|
||||
goto error;
|
||||
}
|
||||
|
||||
strcpy(new, private);
|
||||
strcpy(new, priv);
|
||||
*privkeyfile = new;
|
||||
error:
|
||||
SAFE_FREE(public);
|
||||
SAFE_FREE(private);
|
||||
return pubkey;
|
||||
}
|
||||
|
||||
@@ -1370,7 +1550,6 @@ static int match_hashed_host(ssh_session session, const char *host,
|
||||
* if host key is accepted\n
|
||||
* SSH_SERVER_ERROR: Some error happened
|
||||
*
|
||||
* \see ssh_options_set()
|
||||
* \see ssh_get_pubkey_hash()
|
||||
*
|
||||
* \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;
|
||||
char **tokens;
|
||||
char *host;
|
||||
char *hostport;
|
||||
const char *type;
|
||||
int match;
|
||||
int ret = SSH_SERVER_NOT_KNOWN;
|
||||
@@ -1387,7 +1567,7 @@ int ssh_is_server_known(ssh_session session) {
|
||||
enter_function();
|
||||
|
||||
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,
|
||||
"Can't find a known_hosts file");
|
||||
leave_function();
|
||||
@@ -1403,8 +1583,11 @@ int ssh_is_server_known(ssh_session session) {
|
||||
}
|
||||
|
||||
host = lowercase(session->host);
|
||||
if (host == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "Not enough space!");
|
||||
hostport = ssh_hostport(host,session->port);
|
||||
if (host == NULL || hostport == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
SAFE_FREE(host);
|
||||
SAFE_FREE(hostport);
|
||||
leave_function();
|
||||
return SSH_SERVER_ERROR;
|
||||
}
|
||||
@@ -1418,10 +1601,15 @@ int ssh_is_server_known(ssh_session session) {
|
||||
break;
|
||||
}
|
||||
match = match_hashed_host(session, host, tokens[0]);
|
||||
if (match == 0){
|
||||
match = match_hostname(hostport, tokens[0], strlen(tokens[0]));
|
||||
}
|
||||
if (match == 0) {
|
||||
match = match_hostname(host, tokens[0], strlen(tokens[0]));
|
||||
}
|
||||
|
||||
if (match == 0) {
|
||||
match = match_hashed_host(session, hostport, tokens[0]);
|
||||
}
|
||||
if (match) {
|
||||
/* We got a match. Now check the key type */
|
||||
if (strcmp(session->current_crypto->server_pubkey_type, type) != 0) {
|
||||
@@ -1452,6 +1640,7 @@ int ssh_is_server_known(ssh_session session) {
|
||||
} while (1);
|
||||
|
||||
SAFE_FREE(host);
|
||||
SAFE_FREE(hostport);
|
||||
if (file != NULL) {
|
||||
fclose(file);
|
||||
}
|
||||
@@ -1461,10 +1650,15 @@ int ssh_is_server_known(ssh_session session) {
|
||||
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.
|
||||
* \param session ssh session
|
||||
* \return 0 on success, -1 on error
|
||||
/**
|
||||
* @brief Write the current server as known in the known hosts file.
|
||||
*
|
||||
* 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) {
|
||||
ssh_string pubkey = session->current_crypto->server_pubkey;
|
||||
@@ -1472,17 +1666,30 @@ int ssh_write_knownhost(ssh_session session) {
|
||||
char buffer[4096] = {0};
|
||||
FILE *file;
|
||||
char *dir;
|
||||
char *host;
|
||||
char *hostport;
|
||||
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) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Cannot write host in known hosts if the hostname is unknown");
|
||||
return -1;
|
||||
"Can't write host in known hosts if the hostname isn't known");
|
||||
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 */
|
||||
@@ -1506,6 +1713,7 @@ int ssh_write_knownhost(ssh_session session) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Couldn't open known_hosts file %s for appending: %s",
|
||||
session->knownhosts, strerror(errno));
|
||||
SAFE_FREE(host);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1525,6 +1733,7 @@ int ssh_write_knownhost(ssh_session session) {
|
||||
key = publickey_from_string(session, pubkey);
|
||||
if (key == NULL) {
|
||||
fclose(file);
|
||||
SAFE_FREE(host);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1533,6 +1742,7 @@ int ssh_write_knownhost(ssh_session session) {
|
||||
if (sexp == NULL) {
|
||||
publickey_free(key);
|
||||
fclose(file);
|
||||
SAFE_FREE(host);
|
||||
return -1;
|
||||
}
|
||||
e = gcry_sexp_nth_mpi(sexp, 1, GCRYMPI_FMT_USG);
|
||||
@@ -1540,6 +1750,7 @@ int ssh_write_knownhost(ssh_session session) {
|
||||
if (e == NULL) {
|
||||
publickey_free(key);
|
||||
fclose(file);
|
||||
SAFE_FREE(host);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1548,6 +1759,7 @@ int ssh_write_knownhost(ssh_session session) {
|
||||
publickey_free(key);
|
||||
bignum_free(e);
|
||||
fclose(file);
|
||||
SAFE_FREE(host);
|
||||
return -1;
|
||||
}
|
||||
n = gcry_sexp_nth_mpi(sexp, 1, GCRYMPI_FMT_USG);
|
||||
@@ -1556,6 +1768,7 @@ int ssh_write_knownhost(ssh_session session) {
|
||||
publickey_free(key);
|
||||
bignum_free(e);
|
||||
fclose(file);
|
||||
SAFE_FREE(host);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1580,12 +1793,13 @@ int ssh_write_knownhost(ssh_session session) {
|
||||
#endif
|
||||
publickey_free(key);
|
||||
fclose(file);
|
||||
SAFE_FREE(host);
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"%s %d %s %s\n",
|
||||
session->host,
|
||||
host,
|
||||
rsa_size << 3,
|
||||
e_string,
|
||||
n_string);
|
||||
@@ -1605,18 +1819,19 @@ int ssh_write_knownhost(ssh_session session) {
|
||||
pubkey_64 = bin_to_base64(pubkey->string, string_len(pubkey));
|
||||
if (pubkey_64 == NULL) {
|
||||
fclose(file);
|
||||
SAFE_FREE(host);
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"%s %s %s\n",
|
||||
session->host,
|
||||
host,
|
||||
session->current_crypto->server_pubkey_type,
|
||||
pubkey_64);
|
||||
|
||||
SAFE_FREE(pubkey_64);
|
||||
}
|
||||
|
||||
SAFE_FREE(host);
|
||||
len = strlen(buffer);
|
||||
if (fwrite(buffer, len, 1, file) != 1 || ferror(file)) {
|
||||
fclose(file);
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "libssh/keys.h"
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/messages.h"
|
||||
#include "libssh/string.h"
|
||||
|
||||
/** \addtogroup ssh_auth
|
||||
* @{
|
||||
@@ -130,9 +131,9 @@ ssh_public_key publickey_make_dss(ssh_session session, ssh_buffer buffer) {
|
||||
#endif /* HAVE_LIBCRYPTO */
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("p", p->string, string_len(p));
|
||||
ssh_print_hexa("q", q->string, string_len(q));
|
||||
ssh_print_hexa("g", g->string, string_len(g));
|
||||
ssh_print_hexa("p", string_data(p), string_len(p));
|
||||
ssh_print_hexa("q", string_data(q), string_len(q));
|
||||
ssh_print_hexa("g", string_data(g), string_len(g));
|
||||
#endif
|
||||
|
||||
string_burn(p);
|
||||
@@ -206,8 +207,8 @@ ssh_public_key publickey_make_rsa(ssh_session session, ssh_buffer buffer,
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("e", e->string, string_len(e));
|
||||
ssh_print_hexa("n", n->string, string_len(n));
|
||||
ssh_print_hexa("e", string_data(e), string_len(e));
|
||||
ssh_print_hexa("n", string_data(n), string_len(n));
|
||||
#endif
|
||||
|
||||
string_burn(e);
|
||||
@@ -974,8 +975,8 @@ SIGNATURE *signature_from_string(ssh_session session, ssh_string signature,
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("r", rs->string, 20);
|
||||
ssh_print_hexa("s", rs->string + 20, 20);
|
||||
ssh_print_hexa("r", string_data(rs), 20);
|
||||
ssh_print_hexa("s", (const unsigned char *)string_data(rs) + 20, 20);
|
||||
#endif
|
||||
string_free(rs);
|
||||
|
||||
@@ -1024,7 +1025,7 @@ SIGNATURE *signature_from_string(ssh_session session, ssh_string signature,
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
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
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
@@ -1307,6 +1308,9 @@ ssh_string ssh_do_sign(ssh_session session, ssh_buffer sigbuf,
|
||||
#endif
|
||||
sign->dsa_sign = NULL;
|
||||
break;
|
||||
default:
|
||||
signature_free(sign);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_sexp_release(gcryhash);
|
||||
@@ -1462,6 +1466,9 @@ ssh_string ssh_sign_session_id(ssh_session session, ssh_private_key privatekey)
|
||||
#endif
|
||||
sign->dsa_sign = NULL;
|
||||
break;
|
||||
default:
|
||||
signature_free(sign);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
|
||||
@@ -319,7 +319,6 @@ static ssh_message handle_channel_request_open(ssh_session session) {
|
||||
|
||||
ssh_log(session, SSH_LOG_PACKET,
|
||||
"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, &window);
|
||||
@@ -331,6 +330,7 @@ static ssh_message handle_channel_request_open(ssh_session session) {
|
||||
|
||||
if (strcmp(type_c,"session") == 0) {
|
||||
msg->channel_request_open.type = SSH_CHANNEL_SESSION;
|
||||
string_free(type);
|
||||
SAFE_FREE(type_c);
|
||||
leave_function();
|
||||
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.type = SSH_CHANNEL_DIRECT_TCPIP;
|
||||
string_free(type);
|
||||
SAFE_FREE(type_c);
|
||||
leave_function();
|
||||
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.type = SSH_CHANNEL_FORWARDED_TCPIP;
|
||||
string_free(type);
|
||||
SAFE_FREE(type_c);
|
||||
leave_function();
|
||||
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.type = SSH_CHANNEL_X11;
|
||||
string_free(type);
|
||||
SAFE_FREE(type_c);
|
||||
leave_function();
|
||||
return msg;
|
||||
}
|
||||
|
||||
msg->channel_request_open.type = SSH_CHANNEL_UNKNOWN;
|
||||
string_free(type);
|
||||
SAFE_FREE(type_c);
|
||||
|
||||
leave_function();
|
||||
@@ -863,7 +867,7 @@ void message_handle(ssh_session session, uint32_t type){
|
||||
if(!session->ssh_message_list){
|
||||
session->ssh_message_list=ssh_list_new();
|
||||
}
|
||||
ssh_list_add(session->ssh_message_list,msg);
|
||||
ssh_list_append(session->ssh_message_list,msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
285
libssh/misc.c
285
libssh/misc.c
@@ -35,15 +35,19 @@
|
||||
#ifdef _WIN32
|
||||
#define _WIN32_IE 0x0501 //SHGetSpecialFolderPath
|
||||
#include <winsock2.h> // Must be the first to include
|
||||
#include <ws2tcpip.h>
|
||||
#include <shlobj.h>
|
||||
#include <direct.h>
|
||||
#else
|
||||
/* This is needed for a standard getpwuid_r on opensolaris */
|
||||
#define _POSIX_PTHREAD_SEMANTICS
|
||||
#include <pwd.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/misc.h"
|
||||
#include "libssh/session.h"
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
#define GCRYPT_STRING "/gnutls"
|
||||
@@ -87,25 +91,48 @@ char *ssh_get_user_home_dir(void) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* we have read access on file */
|
||||
int ssh_file_readaccess_ok(const char *file) {
|
||||
/* we have read access on file */
|
||||
int ssh_file_readaccess_ok(const char *file) {
|
||||
if (_access(file, 4) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 */
|
||||
#ifndef NSS_BUFLEN_PASSWD
|
||||
#define NSS_BUFLEN_PASSWD 4096
|
||||
#endif
|
||||
|
||||
char *ssh_get_user_home_dir(void) {
|
||||
char *szPath = NULL;
|
||||
struct passwd *pwd = NULL;
|
||||
struct passwd pwd;
|
||||
struct passwd *pwdbuf;
|
||||
char buf[NSS_BUFLEN_PASSWD];
|
||||
int rc;
|
||||
|
||||
pwd = getpwuid(getuid());
|
||||
if (pwd == NULL) {
|
||||
rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf);
|
||||
if (rc != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
szPath = strdup(pwd->pw_dir);
|
||||
szPath = strdup(pwd.pw_dir);
|
||||
|
||||
return szPath;
|
||||
}
|
||||
@@ -120,6 +147,20 @@ int ssh_file_readaccess_ok(const char *file) {
|
||||
}
|
||||
#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) {
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
return a;
|
||||
@@ -133,6 +174,52 @@ uint64_t ntohll(uint64_t a) {
|
||||
#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
|
||||
* string.
|
||||
@@ -197,7 +284,7 @@ static struct ssh_iterator *ssh_iterator_new(const void *data){
|
||||
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);
|
||||
if(!iterator)
|
||||
return SSH_ERROR;
|
||||
@@ -212,6 +299,25 @@ int ssh_list_add(struct ssh_list *list,const void *data){
|
||||
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){
|
||||
struct ssh_iterator *ptr,*prev;
|
||||
prev=NULL;
|
||||
@@ -236,7 +342,14 @@ void ssh_list_remove(struct ssh_list *list, struct ssh_iterator *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;
|
||||
const void *data;
|
||||
if(!list->root)
|
||||
@@ -381,5 +494,157 @@ int ssh_mkdir(const char *pathname, mode_t mode) {
|
||||
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 = NULL, *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) {
|
||||
SAFE_FREE(h);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (lh > 0) {
|
||||
memcpy(r, h, lh);
|
||||
}
|
||||
SAFE_FREE(h);
|
||||
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"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup ssh_session
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Duplicate the options of a session structure.
|
||||
*
|
||||
* If you make several sessions with the same options this is useful. You
|
||||
* 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()
|
||||
*/
|
||||
@@ -76,10 +83,29 @@ int ssh_options_copy(ssh_session src, ssh_session *dest) {
|
||||
}
|
||||
|
||||
if (src->identity) {
|
||||
new->identity = strdup(src->identity);
|
||||
struct ssh_iterator *it;
|
||||
|
||||
new->identity = ssh_list_new();
|
||||
if (new->identity == NULL) {
|
||||
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) {
|
||||
@@ -117,29 +143,6 @@ int ssh_options_copy(ssh_session src, ssh_session *dest) {
|
||||
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,
|
||||
const char *list) {
|
||||
if (!verify_existing_algo(algo, list)) {
|
||||
@@ -159,58 +162,6 @@ int ssh_options_set_algo(ssh_session session, int algo,
|
||||
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.
|
||||
*
|
||||
@@ -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
|
||||
* following:
|
||||
*
|
||||
* SSH_OPTIONS_HOST:
|
||||
* - SSH_OPTIONS_HOST:
|
||||
* The hostname or ip address to connect to (string).
|
||||
*
|
||||
* SSH_OPTIONS_PORT:
|
||||
* - SSH_OPTIONS_PORT:
|
||||
* The port to connect to (integer).
|
||||
*
|
||||
* SSH_OPTIONS_PORT_STR:
|
||||
* - SSH_OPTIONS_PORT_STR:
|
||||
* The port to connect to (string).
|
||||
*
|
||||
* SSH_OPTIONS_FD:
|
||||
* The file descriptor to use (socket_t).
|
||||
*
|
||||
* - SSH_OPTIONS_FD:
|
||||
* The file descriptor to use (socket_t).\n
|
||||
* \n
|
||||
* If you wish to open the socket yourself for a reason
|
||||
* or another, set the file descriptor. Don't forget to
|
||||
* set the hostname as the hostname is used as a key in
|
||||
* the known_host mechanism.
|
||||
*
|
||||
* SSH_OPTIONS_USER:
|
||||
* The username for authentication (string).
|
||||
* - SSH_OPTIONS_BINDADDR:
|
||||
* 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
|
||||
* default username.
|
||||
*
|
||||
* SSH_OPTIONS_SSH_DIR:
|
||||
* Set the ssh directory (format string).
|
||||
*
|
||||
* - SSH_OPTIONS_SSH_DIR:
|
||||
* Set the ssh directory (format string).\n
|
||||
* \n
|
||||
* 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
|
||||
* and identity (private and public key). It may include
|
||||
* "%s" which will be replaced by the user home
|
||||
* directory.
|
||||
*
|
||||
* SSH_OPTIONS_KNOWNHOSTS:
|
||||
* Set the known hosts file name (format string).
|
||||
*
|
||||
* - SSH_OPTIONS_KNOWNHOSTS:
|
||||
* Set the known hosts file name (format string).\n
|
||||
* \n
|
||||
* 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
|
||||
* are genuine. It may include "%s" which will be
|
||||
* replaced by the user home directory.
|
||||
*
|
||||
* SSH_OPTIONS_IDENTITY:
|
||||
* Set the identity file name (format string).
|
||||
*
|
||||
* By default identity, id_dsa and id_rsa are checked.
|
||||
*
|
||||
* - SSH_OPTIONS_IDENTITY:
|
||||
* Set the identity file name (format string).\n
|
||||
* \n
|
||||
* By default identity, id_dsa and id_rsa are checked.\n
|
||||
* \n
|
||||
* The identity file used authenticate with public key.
|
||||
* It may include "%s" which will be replaced by the
|
||||
* user home directory.
|
||||
*
|
||||
* SSH_OPTIONS_TIMEOUT:
|
||||
* - SSH_OPTIONS_TIMEOUT:
|
||||
* 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
|
||||
* (integer).
|
||||
*
|
||||
* SSH_OPTIONS_SSH1:
|
||||
* - SSH_OPTIONS_SSH1:
|
||||
* Allow or deny the connection to SSH1 servers
|
||||
* (integer).
|
||||
*
|
||||
* SSH_OPTIONS_SSH2:
|
||||
* - SSH_OPTIONS_SSH2:
|
||||
* Allow or deny the connection to SSH2 servers
|
||||
* (integer).
|
||||
*
|
||||
* SSH_OPTIONS_LOG_VERBOSITY:
|
||||
* Set the session logging verbosity (integer).
|
||||
*
|
||||
* - SSH_OPTIONS_LOG_VERBOSITY:
|
||||
* Set the session logging verbosity (integer).\n
|
||||
* \n
|
||||
* The verbosity of the messages. Every log smaller or
|
||||
* equal to verbosity will be shown.
|
||||
* SSH_LOG_NOLOG: No logging
|
||||
* SSH_LOG_RARE: Rare conditions or warnings
|
||||
* SSH_LOG_ENTRY: API-accessible entrypoints
|
||||
* SSH_LOG_PACKET: Packet id and size
|
||||
* SSH_LOG_FUNCTIONS: Function entering and leaving
|
||||
*
|
||||
* SSH_OPTIONS_LOG_VERBOSITY_STR:
|
||||
* Set the session logging verbosity (string).
|
||||
* - SSH_LOG_NOLOG: No logging
|
||||
* - SSH_LOG_RARE: Rare conditions or warnings
|
||||
* - SSH_LOG_ENTRY: API-accessible entrypoints
|
||||
* - SSH_LOG_PACKET: Packet id and size
|
||||
* - SSH_LOG_FUNCTIONS: Function entering and leaving
|
||||
*
|
||||
* - SSH_OPTIONS_LOG_VERBOSITY_STR:
|
||||
* Set the session logging verbosity (string).\n
|
||||
* \n
|
||||
* The verbosity of the messages. Every log smaller or
|
||||
* equal to verbosity will be shown.
|
||||
* SSH_LOG_NOLOG: No logging
|
||||
* SSH_LOG_RARE: Rare conditions or warnings
|
||||
* SSH_LOG_ENTRY: API-accessible entrypoints
|
||||
* SSH_LOG_PACKET: Packet id and size
|
||||
* SSH_LOG_FUNCTIONS: Function entering and leaving
|
||||
*
|
||||
* - SSH_LOG_NOLOG: No logging
|
||||
* - SSH_LOG_RARE: Rare conditions or warnings
|
||||
* - SSH_LOG_ENTRY: API-accessible entrypoints
|
||||
* - SSH_LOG_PACKET: Packet id and size
|
||||
* - SSH_LOG_FUNCTIONS: Function entering and leaving
|
||||
* \n
|
||||
* See the corresponding numbers in libssh.h.
|
||||
*
|
||||
* SSH_OPTTIONS_AUTH_CALLBACK:
|
||||
* - SSH_OPTTIONS_AUTH_CALLBACK:
|
||||
* Set a callback to use your own authentication function
|
||||
* (function pointer).
|
||||
*
|
||||
* SSH_OPTTIONS_AUTH_USERDATA:
|
||||
* Set the user data passed to the authentication function
|
||||
* (generic pointer).
|
||||
* - SSH_OPTTIONS_AUTH_USERDATA:
|
||||
* Set the user data passed to the authentication
|
||||
* function (generic pointer).
|
||||
*
|
||||
* SSH_OPTTIONS_LOG_CALLBACK:
|
||||
* - SSH_OPTTIONS_LOG_CALLBACK:
|
||||
* Set a callback to use your own logging function
|
||||
* (function pointer).
|
||||
*
|
||||
* SSH_OPTTIONS_LOG_USERDATA:
|
||||
* - SSH_OPTTIONS_LOG_USERDATA:
|
||||
* Set the user data passed to the logging function
|
||||
* (generic pointer).
|
||||
*
|
||||
* SSH_OPTTIONS_STATUS_CALLBACK:
|
||||
* - SSH_OPTTIONS_STATUS_CALLBACK:
|
||||
* Set a callback to show connection status in realtime
|
||||
* (function pointer).
|
||||
*
|
||||
* (function pointer).\n
|
||||
* \n
|
||||
* @code
|
||||
* fn(void *arg, float status)
|
||||
*
|
||||
* @endcode
|
||||
* \n
|
||||
* During ssh_connect(), libssh will call the callback
|
||||
* 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
|
||||
* status callback (generic pointer).
|
||||
*
|
||||
* SSH_OPTIONS_CIPHERS_C_S:
|
||||
* - SSH_OPTIONS_CIPHERS_C_S:
|
||||
* Set the symmetric cipher client to server (string,
|
||||
* comma-separated list).
|
||||
*
|
||||
* SSH_OPTIONS_CIPHERS_S_C:
|
||||
* - SSH_OPTIONS_CIPHERS_S_C:
|
||||
* Set the symmetric cipher server to client (string,
|
||||
* comma-separated list).
|
||||
*
|
||||
* SSH_OPTIONS_COMPRESSION_C_S:
|
||||
* - SSH_OPTIONS_COMPRESSION_C_S:
|
||||
* Set the compression to use for client to server
|
||||
* communication (string, "none" or "zlib").
|
||||
*
|
||||
* SSH_OPTIONS_COMPRESSION_S_C:
|
||||
* - SSH_OPTIONS_COMPRESSION_S_C:
|
||||
* Set the compression to use for server to client
|
||||
* 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
|
||||
* datatype which is used should be set according to the
|
||||
* type set.
|
||||
@@ -366,6 +327,7 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
||||
const void *value) {
|
||||
char *p, *q;
|
||||
long int i;
|
||||
int rc;
|
||||
|
||||
if (session == NULL) {
|
||||
return -1;
|
||||
@@ -429,30 +391,35 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
||||
session->port = i & 0xffff;
|
||||
}
|
||||
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:
|
||||
SAFE_FREE(session->username);
|
||||
if (value == NULL) { /* set default username */
|
||||
#ifdef _WIN32
|
||||
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());
|
||||
q = ssh_get_local_username(session);
|
||||
if (q == NULL) {
|
||||
return -1;
|
||||
}
|
||||
session->username = q;
|
||||
#endif /* _WIN32 */
|
||||
} else { /* username provided */
|
||||
session->username = strdup(value);
|
||||
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:
|
||||
if (value == NULL) {
|
||||
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) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
SAFE_FREE(session->sshdir);
|
||||
session->sshdir = dir_expand_dup(session, value, 0);
|
||||
session->sshdir = ssh_path_expand_tilde(value);
|
||||
if (session->sshdir == NULL) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SSH_OPTIONS_IDENTITY:
|
||||
|
||||
case SSH_OPTIONS_ADD_IDENTITY:
|
||||
if (value == NULL) {
|
||||
ssh_set_error_invalid(session, __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
SAFE_FREE(session->identity);
|
||||
session->identity = dir_expand_dup(session, value, 1);
|
||||
if (session->identity == NULL) {
|
||||
q = strdup(value);
|
||||
if (q == NULL) {
|
||||
return -1;
|
||||
}
|
||||
rc = ssh_list_prepend(session->identity, q);
|
||||
if (rc < 0) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case SSH_OPTIONS_KNOWNHOSTS:
|
||||
if (value == NULL) {
|
||||
SAFE_FREE(session->knownhosts);
|
||||
session->knownhosts = dir_expand_dup(session,
|
||||
"SSH_DIR/known_hosts", 1);
|
||||
if (session->sshdir == NULL) {
|
||||
return -1;
|
||||
}
|
||||
session->knownhosts = ssh_path_expand_escape(session, "%d/known_hosts");
|
||||
if (session->knownhosts == NULL) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
SAFE_FREE(session->knownhosts);
|
||||
session->knownhosts = dir_expand_dup(session, value, 1);
|
||||
session->knownhosts = strdup(value);
|
||||
if (session->knownhosts == NULL) {
|
||||
return -1;
|
||||
}
|
||||
@@ -553,6 +524,7 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
||||
|
||||
session->log_verbosity = *x & 0xffff;
|
||||
}
|
||||
break;
|
||||
case SSH_OPTIONS_LOG_VERBOSITY_STR:
|
||||
if (value == NULL) {
|
||||
session->log_verbosity = 0 & 0xffff;
|
||||
@@ -607,16 +579,34 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
||||
return -1;
|
||||
}
|
||||
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:
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
/**
|
||||
* @addtogroup ssh_server
|
||||
* @{
|
||||
*/
|
||||
static int ssh_bind_options_set_algo(ssh_bind sshbind, int algo,
|
||||
const char *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;
|
||||
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;
|
||||
break;
|
||||
}
|
||||
@@ -1040,19 +1030,91 @@ int ssh_options_parse_config(ssh_session session, const char *filename) {
|
||||
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 */
|
||||
if (filename == NULL) {
|
||||
expanded_filename = dir_expand_dup(session, "SSH_DIR/config", 1);
|
||||
expanded_filename = ssh_path_expand_escape(session, "%d/config");
|
||||
} 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;
|
||||
}
|
||||
|
||||
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);
|
||||
return r;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
/* vim: set ts=2 sw=2 et cindent: */
|
||||
int ssh_options_apply(ssh_session session) {
|
||||
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:
|
||||
message_handle(session,type);
|
||||
return;
|
||||
case SSH2_MSG_GLOBAL_REQUEST:
|
||||
ssh_global_request_handle(session);
|
||||
return;
|
||||
default:
|
||||
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");
|
||||
leave_function();
|
||||
return SSH_ERROR;
|
||||
case SSH2_MSG_GLOBAL_REQUEST:
|
||||
case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
|
||||
case SSH2_MSG_CHANNEL_DATA:
|
||||
case SSH2_MSG_CHANNEL_EXTENDED_DATA:
|
||||
|
||||
@@ -30,8 +30,12 @@
|
||||
#ifdef WITH_PCAP
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef _WIN32
|
||||
#include <ws2tcpip.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
@@ -46,13 +50,13 @@
|
||||
* Just for information.
|
||||
*/
|
||||
struct pcap_hdr_s {
|
||||
u_int32_t magic_number; /* magic number */
|
||||
u_int16_t version_major; /* major version number */
|
||||
u_int16_t version_minor; /* minor version number */
|
||||
uint32_t magic_number; /* magic number */
|
||||
uint16_t version_major; /* major version number */
|
||||
uint16_t version_minor; /* minor version number */
|
||||
int32_t thiszone; /* GMT to local correction */
|
||||
u_int32_t sigfigs; /* accuracy of timestamps */
|
||||
u_int32_t snaplen; /* max length of captured packets, in octets */
|
||||
u_int32_t network; /* data link type */
|
||||
uint32_t sigfigs; /* accuracy of timestamps */
|
||||
uint32_t snaplen; /* max length of captured packets, in octets */
|
||||
uint32_t network; /* data link type */
|
||||
};
|
||||
|
||||
#define PCAP_MAGIC 0xa1b2c3d4
|
||||
@@ -73,10 +77,10 @@ struct pcap_hdr_s {
|
||||
* Just for information.
|
||||
*/
|
||||
struct pcaprec_hdr_s {
|
||||
u_int32_t ts_sec; /* timestamp seconds */
|
||||
u_int32_t ts_usec; /* timestamp microseconds */
|
||||
u_int32_t incl_len; /* number of octets of packet saved in file */
|
||||
u_int32_t orig_len; /* actual length of packet */
|
||||
uint32_t ts_sec; /* timestamp seconds */
|
||||
uint32_t ts_usec; /* timestamp microseconds */
|
||||
uint32_t incl_len; /* number of octets of packet saved in file */
|
||||
uint32_t orig_len; /* actual length of packet */
|
||||
};
|
||||
|
||||
/** @private
|
||||
@@ -89,15 +93,15 @@ struct ssh_pcap_context_struct {
|
||||
ssh_session session;
|
||||
ssh_pcap_file file;
|
||||
int connected;
|
||||
/* All of these informations are useful to generate
|
||||
/* All of these information are useful to generate
|
||||
* the dummy IP and TCP packets
|
||||
*/
|
||||
u_int32_t ipsource;
|
||||
u_int32_t ipdest;
|
||||
u_int16_t portsource;
|
||||
u_int16_t portdest;
|
||||
u_int32_t outsequence;
|
||||
u_int32_t insequence;
|
||||
uint32_t ipsource;
|
||||
uint32_t ipdest;
|
||||
uint16_t portsource;
|
||||
uint16_t portdest;
|
||||
uint32_t outsequence;
|
||||
uint32_t insequence;
|
||||
};
|
||||
|
||||
/** @private
|
||||
@@ -106,7 +110,7 @@ struct ssh_pcap_context_struct {
|
||||
*/
|
||||
struct ssh_pcap_file_struct {
|
||||
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
|
||||
* 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();
|
||||
struct timeval now;
|
||||
int err;
|
||||
@@ -282,7 +286,7 @@ static int ssh_pcap_context_connect(ssh_pcap_context ctx){
|
||||
* @returns SSH_ERROR an error happened.
|
||||
*/
|
||||
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;
|
||||
int err;
|
||||
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
|
||||
*
|
||||
* Copyright (c) 2009-2010 by Andreas Schneider <mail@cynapses.org>
|
||||
* Copyright (c) 2003-2009 by Aris Adamantiadis
|
||||
* Copyright (c) 2009 Aleksandar Kanchev
|
||||
*
|
||||
@@ -24,8 +25,6 @@
|
||||
* vim: ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
/* This code is based on glib's gpoll */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
@@ -60,177 +59,217 @@ struct ssh_poll_ctx_struct {
|
||||
#ifdef HAVE_POLL
|
||||
#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) {
|
||||
return poll((struct pollfd *) fds, nfds, timeout);
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
#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
|
||||
#define STRICT
|
||||
#endif
|
||||
#endif /* STRICT */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <windows.h>
|
||||
#include <errno.h>
|
||||
#include <winsock2.h>
|
||||
|
||||
static int poll_rest (HANDLE *handles, int nhandles,
|
||||
ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
|
||||
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());
|
||||
}
|
||||
#if (_WIN32_WINNT < 0x0600)
|
||||
typedef struct ssh_pollfd_struct WSAPOLLFD;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ready == WAIT_FAILED) {
|
||||
return -1;
|
||||
} else if (ready == WAIT_TIMEOUT || ready == WAIT_IO_COMPLETION) {
|
||||
return 0;
|
||||
} else if (ready >= WAIT_OBJECT_0 && ready < WAIT_OBJECT_0 + nhandles) {
|
||||
for (f = fds; f < &fds[nfds]; f++) {
|
||||
if ((HANDLE) f->fd == handles[ready - WAIT_OBJECT_0]) {
|
||||
f->revents = f->events;
|
||||
}
|
||||
typedef int (WSAAPI* WSAPoll_FunctionType)(WSAPOLLFD fdarray[],
|
||||
ULONG nfds,
|
||||
INT timeout
|
||||
);
|
||||
|
||||
static WSAPoll_FunctionType wsa_poll;
|
||||
|
||||
int win_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
|
||||
if (wsa_poll) {
|
||||
return (wsa_poll)(fds, nfds, timeout);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
|
||||
int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
|
||||
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
|
||||
ssh_pollfd_t *f;
|
||||
int nhandles = 0;
|
||||
int rc = -1;
|
||||
#define WS2_LIBRARY "ws2_32.dll"
|
||||
static HINSTANCE hlib;
|
||||
|
||||
#else /* _WIN32 */
|
||||
#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) {
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (nfds >= MAXIMUM_WAIT_OBJECTS) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
FD_ZERO (&readfds);
|
||||
FD_ZERO (&writefds);
|
||||
FD_ZERO (&exceptfds);
|
||||
|
||||
for (f = fds; f < &fds[nfds]; f++) {
|
||||
if (f->fd > 0) {
|
||||
int i;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
/* compute fd_sets and find largest descriptor */
|
||||
for (rc = -1, max_fd = 0, i = 0; i < nfds; i++) {
|
||||
if (fds[i].fd == SSH_INVALID_SOCKET) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == nhandles) {
|
||||
if (nhandles == MAXIMUM_WAIT_OBJECTS) {
|
||||
#ifndef _WIN32
|
||||
if (fds[i].fd >= FD_SETSIZE) {
|
||||
rc = -1;
|
||||
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) {
|
||||
timeout = INFINITE;
|
||||
if (max_fd == SSH_INVALID_SOCKET || rc == -1) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (nhandles > 1) {
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
if (timeout < 0) {
|
||||
ptv = NULL;
|
||||
} else {
|
||||
/*
|
||||
* Just polling for one thing, so no need to check first if
|
||||
* available immediately
|
||||
*/
|
||||
rc = poll_rest(handles, nhandles, fds, nfds, timeout);
|
||||
ptv = &tv;
|
||||
if (timeout == 0) {
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
} else {
|
||||
tv.tv_sec = timeout / 1000;
|
||||
tv.tv_usec = (timeout % 1000) * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
rc = select (max_fd + 1, &readfds, &writefds, &exceptfds, ptv);
|
||||
if (rc < 0) {
|
||||
for (f = fds; f < &fds[nfds]; f++) {
|
||||
f->revents = 0;
|
||||
}
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#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 */
|
||||
|
||||
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 */
|
||||
|
||||
/**
|
||||
@@ -403,7 +442,7 @@ void ssh_poll_ctx_free(ssh_poll_ctx ctx) {
|
||||
used = ctx->polls_used;
|
||||
for (i = 0; i < used; ) {
|
||||
ssh_poll_handle p = ctx->pollptrs[i];
|
||||
int fd = ctx->pollfds[i].fd;
|
||||
socket_t fd = ctx->pollfds[i].fd;
|
||||
|
||||
/* force poll object removal */
|
||||
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
|
||||
*/
|
||||
int ssh_poll_ctx_add(ssh_poll_ctx ctx, ssh_poll_handle p) {
|
||||
int fd;
|
||||
socket_t fd;
|
||||
|
||||
if (p->ctx != NULL) {
|
||||
/* already attached to a context */
|
||||
@@ -530,7 +569,7 @@ int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout) {
|
||||
i++;
|
||||
} else {
|
||||
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;
|
||||
|
||||
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/scp.h"
|
||||
/** @defgroup ssh_scp SSH-scp
|
||||
* @brief SCP protocol over SSH functions
|
||||
* @addtogroup ssh_scp
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Creates a new scp session
|
||||
* @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.
|
||||
* 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 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){
|
||||
char buffer[128];
|
||||
int err;
|
||||
if(scp->channel != NULL){
|
||||
if(channel_send_eof(scp->channel) == SSH_ERROR){
|
||||
scp->state=SSH_SCP_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){
|
||||
scp->state=SSH_SCP_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
|
||||
* @param scp the scp handle.
|
||||
* @param dirname Name of the directory being created.
|
||||
* @param mode Unix permissions for the new directory, e.g. 0755.
|
||||
* @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
|
||||
* @param scp the scp handle.
|
||||
* @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 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
|
||||
* @param scp the scp handle.
|
||||
* @param buffer the buffer to write
|
||||
* @param len the number of bytes to write
|
||||
* @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'
|
||||
* @param scp the scp handle.
|
||||
* @param buffer pointer to a buffer to place the string
|
||||
* @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
|
||||
@@ -455,6 +477,7 @@ int ssh_scp_pull_request(ssh_scp scp){
|
||||
/**
|
||||
* @brief denies the transfer of a file or creation of a directory
|
||||
* coming from the remote party
|
||||
* @param scp the scp handle.
|
||||
* @param reason nul-terminated string with a human-readable explanation
|
||||
* of the deny
|
||||
* @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
|
||||
* coming from the remote party
|
||||
* @param scp the scp handle.
|
||||
* @returns SSH_OK the message was sent
|
||||
* @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
|
||||
* @param scp the scp handle.
|
||||
* @param buffer Destination buffer
|
||||
* @param size Size of the buffer
|
||||
* @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.
|
||||
* @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".
|
||||
*/
|
||||
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){
|
||||
return scp->warning;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ ssh_bind ssh_bind_new(void) {
|
||||
return NULL;
|
||||
}
|
||||
ZERO_STRUCTP(ptr);
|
||||
ptr->bindfd = -1;
|
||||
ptr->bindfd = SSH_INVALID_SOCKET;
|
||||
ptr->bindport= 22;
|
||||
ptr->log_verbosity = 0;
|
||||
|
||||
@@ -138,7 +138,7 @@ ssh_bind ssh_bind_new(void) {
|
||||
|
||||
int ssh_bind_listen(ssh_bind sshbind) {
|
||||
const char *host;
|
||||
int fd;
|
||||
socket_t fd;
|
||||
|
||||
if (ssh_init() < 0) {
|
||||
return -1;
|
||||
@@ -185,10 +185,10 @@ void ssh_bind_fd_toaccept(ssh_bind sshbind) {
|
||||
int ssh_bind_accept(ssh_bind sshbind, ssh_session session) {
|
||||
ssh_private_key dsa = NULL;
|
||||
ssh_private_key rsa = NULL;
|
||||
int fd = -1;
|
||||
socket_t fd = SSH_INVALID_SOCKET;
|
||||
int i;
|
||||
|
||||
if (sshbind->bindfd < 0) {
|
||||
if (sshbind->bindfd == SSH_INVALID_SOCKET) {
|
||||
ssh_set_error(sshbind, SSH_FATAL,
|
||||
"Can't accept new clients on a not bound socket.");
|
||||
return SSH_ERROR;
|
||||
@@ -219,7 +219,7 @@ int ssh_bind_accept(ssh_bind sshbind, ssh_session session) {
|
||||
}
|
||||
|
||||
fd = accept(sshbind->bindfd, NULL, NULL);
|
||||
if (fd < 0) {
|
||||
if (fd == SSH_INVALID_SOCKET) {
|
||||
ssh_set_error(sshbind, SSH_FATAL,
|
||||
"Accepting a new connection: %s",
|
||||
strerror(errno));
|
||||
@@ -246,6 +246,7 @@ int ssh_bind_accept(ssh_bind sshbind, ssh_session session) {
|
||||
if (sshbind->bindaddr == NULL)
|
||||
session->bindaddr = NULL;
|
||||
else {
|
||||
SAFE_FREE(session->bindaddr);
|
||||
session->bindaddr = strdup(sshbind->bindaddr);
|
||||
if (session->bindaddr == NULL) {
|
||||
privatekey_free(dsa);
|
||||
@@ -278,9 +279,13 @@ void ssh_bind_free(ssh_bind sshbind){
|
||||
}
|
||||
|
||||
if (sshbind->bindfd >= 0) {
|
||||
#ifdef _WIN32
|
||||
closesocket(sshbind->bindfd);
|
||||
#else
|
||||
close(sshbind->bindfd);
|
||||
#endif
|
||||
}
|
||||
sshbind->bindfd = -1;
|
||||
sshbind->bindfd = SSH_INVALID_SOCKET;
|
||||
|
||||
/* options */
|
||||
SAFE_FREE(sshbind->banner);
|
||||
@@ -867,7 +872,7 @@ int ssh_execute_message_callbacks(ssh_session session){
|
||||
if(!session->ssh_message_list)
|
||||
return SSH_OK;
|
||||
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);
|
||||
if(ret==1){
|
||||
ret = ssh_message_reply_default(msg);
|
||||
@@ -876,7 +881,7 @@ int ssh_execute_message_callbacks(ssh_session session){
|
||||
}
|
||||
}
|
||||
} 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);
|
||||
if(ret != SSH_OK)
|
||||
return ret;
|
||||
|
||||
@@ -32,7 +32,8 @@
|
||||
#include "libssh/packet.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/misc.h"
|
||||
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/buffer.h"
|
||||
#define FIRST_CHANNEL 42 // why not ? it helps to find bugs.
|
||||
|
||||
/** \defgroup ssh_session SSH Session
|
||||
@@ -46,6 +47,8 @@
|
||||
*/
|
||||
ssh_session ssh_new(void) {
|
||||
ssh_session session;
|
||||
char *id;
|
||||
int rc;
|
||||
|
||||
session = malloc(sizeof (struct ssh_session_struct));
|
||||
if (session == NULL) {
|
||||
@@ -95,6 +98,39 @@ ssh_session ssh_new(void) {
|
||||
goto err;
|
||||
}
|
||||
#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;
|
||||
|
||||
err:
|
||||
@@ -117,6 +153,7 @@ void ssh_free(ssh_session session) {
|
||||
|
||||
SAFE_FREE(session->serverbanner);
|
||||
SAFE_FREE(session->clientbanner);
|
||||
SAFE_FREE(session->bindaddr);
|
||||
SAFE_FREE(session->banner);
|
||||
#ifdef WITH_PCAP
|
||||
if(session->pcap_ctx){
|
||||
@@ -155,19 +192,30 @@ void ssh_free(ssh_session session) {
|
||||
privatekey_free(session->rsa_key);
|
||||
if(session->ssh_message_list){
|
||||
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){
|
||||
ssh_message_free(msg);
|
||||
}
|
||||
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 */
|
||||
SAFE_FREE(session->username);
|
||||
SAFE_FREE(session->host);
|
||||
SAFE_FREE(session->identity);
|
||||
SAFE_FREE(session->sshdir);
|
||||
SAFE_FREE(session->knownhosts);
|
||||
SAFE_FREE(session->ProxyCommand);
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (session->wanted_methods[i]) {
|
||||
@@ -363,5 +411,32 @@ int ssh_get_version(ssh_session session) {
|
||||
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: */
|
||||
|
||||
@@ -25,9 +25,11 @@
|
||||
/* This file contains code written by Nick Zitzmann */
|
||||
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
@@ -1111,6 +1113,54 @@ static sftp_attributes sftp_parse_attr_4(sftp_session sftp, ssh_buffer buf,
|
||||
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 */
|
||||
/* 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;
|
||||
}
|
||||
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)) {
|
||||
@@ -1254,6 +1317,8 @@ static sftp_attributes sftp_parse_attr_3(sftp_session sftp, ssh_buffer buf,
|
||||
string_free(attr->extended_data);
|
||||
SAFE_FREE(attr->name);
|
||||
SAFE_FREE(attr->longname);
|
||||
SAFE_FREE(attr->owner);
|
||||
SAFE_FREE(attr->group);
|
||||
SAFE_FREE(attr);
|
||||
|
||||
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 ||
|
||||
buffer_add_ssh_string(buffer, oldpath) < 0 ||
|
||||
buffer_add_ssh_string(buffer, newpath) < 0 ||
|
||||
/* POSIX rename atomically replaces newpath, we should do the same */
|
||||
buffer_add_u32(buffer, SSH_FXF_RENAME_OVERWRITE) < 0) {
|
||||
/* POSIX rename atomically replaces newpath, we should do the same
|
||||
* only available on >=v4 */
|
||||
sftp->version>=4 ? (buffer_add_u32(buffer, SSH_FXF_RENAME_OVERWRITE) < 0):0) {
|
||||
ssh_set_error_oom(sftp->session);
|
||||
buffer_free(buffer);
|
||||
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.gid = group;
|
||||
attr.flags = SSH_FILEXFER_ATTR_OWNERGROUP;
|
||||
|
||||
attr.flags = SSH_FILEXFER_ATTR_UIDGID;
|
||||
|
||||
return sftp_setstat(sftp, file, &attr);
|
||||
}
|
||||
@@ -3056,7 +3123,10 @@ static sftp_attributes sftp_xstat(sftp_session sftp, const char *path,
|
||||
}
|
||||
|
||||
if (msg->packet_type == SSH_FXP_ATTRS) {
|
||||
return sftp_parse_attr(sftp, msg->payload, 0);
|
||||
sftp_attributes attr = sftp_parse_attr(sftp, msg->payload, 0);
|
||||
sftp_message_free(msg);
|
||||
|
||||
return attr;
|
||||
} else if (msg->packet_type == SSH_FXP_STATUS) {
|
||||
status = parse_status_msg(msg);
|
||||
sftp_message_free(msg);
|
||||
|
||||
112
libssh/socket.c
112
libssh/socket.c
@@ -27,11 +27,13 @@
|
||||
#include <stdio.h>
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
extern char **environ;
|
||||
#endif
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/socket.h"
|
||||
@@ -39,6 +41,7 @@
|
||||
#include "libssh/poll.h"
|
||||
#include "libssh/session.h"
|
||||
|
||||
|
||||
/** \defgroup ssh_socket SSH Sockets
|
||||
* \addtogroup ssh_socket
|
||||
* @{
|
||||
@@ -68,10 +71,21 @@ int ssh_socket_init(void) {
|
||||
if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
ssh_poll_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
|
||||
/**
|
||||
* @brief Cleanup the socket system.
|
||||
*/
|
||||
void ssh_socket_cleanup(void) {
|
||||
ssh_poll_cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* \internal
|
||||
* \brief creates a new Socket object
|
||||
*/
|
||||
@@ -82,7 +96,7 @@ struct socket *ssh_socket_new(ssh_session session) {
|
||||
if (s == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
s->fd = -1;
|
||||
s->fd = SSH_INVALID_SOCKET;
|
||||
s->last_errno = -1;
|
||||
s->session = session;
|
||||
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);
|
||||
|
||||
s->fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (s->fd < 0) {
|
||||
if (s->fd == SSH_INVALID_SOCKET) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fcntl(s->fd, F_SETFD, 1) == -1) {
|
||||
close(s->fd);
|
||||
s->fd = -1;
|
||||
s->fd = SSH_INVALID_SOCKET;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connect(s->fd, (struct sockaddr *) &sunaddr,
|
||||
sizeof(sunaddr)) < 0) {
|
||||
close(s->fd);
|
||||
s->fd = -1;
|
||||
s->fd = SSH_INVALID_SOCKET;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -157,7 +171,7 @@ void ssh_socket_close(struct socket *s){
|
||||
close(s->fd);
|
||||
s->last_errno = errno;
|
||||
#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
|
||||
*/
|
||||
int ssh_socket_is_open(struct socket *s) {
|
||||
return s->fd != -1;
|
||||
return s->fd != SSH_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
/* \internal
|
||||
@@ -237,22 +251,25 @@ static int ssh_socket_unbuffered_write(struct socket *s, const void *buffer,
|
||||
* \brief returns nonzero if the current socket is in the fd_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 FD_ISSET(s->fd,set);
|
||||
}
|
||||
|
||||
/* \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) {
|
||||
if (s->fd == -1)
|
||||
void ssh_socket_fd_set(struct socket *s, fd_set *set, socket_t *max_fd) {
|
||||
if (s->fd == SSH_INVALID_SOCKET)
|
||||
return;
|
||||
FD_SET(s->fd,set);
|
||||
if (s->fd >= *fd_max) {
|
||||
*fd_max = s->fd + 1;
|
||||
|
||||
if (s->fd >= 0 &&
|
||||
s->fd >= *max_fd &&
|
||||
s->fd != SSH_INVALID_SOCKET) {
|
||||
*max_fd = s->fd + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,7 +452,7 @@ int ssh_socket_wait_for_data(struct socket *s, ssh_session session, uint32_t len
|
||||
if (ssh_socket_is_open(session->socket)) {
|
||||
r = ssh_socket_unbuffered_read(session->socket, buffer, sizeof(buffer));
|
||||
} else {
|
||||
r =- 1;
|
||||
r = -1;
|
||||
}
|
||||
|
||||
if (r <= 0) {
|
||||
@@ -475,6 +492,7 @@ int ssh_socket_poll(struct socket *s, int *writeable, int *except) {
|
||||
|
||||
fd->fd = s->fd;
|
||||
fd->events = 0;
|
||||
fd->revents = 0;
|
||||
|
||||
if (!s->data_to_read) {
|
||||
fd->events |= POLLIN;
|
||||
@@ -482,13 +500,15 @@ int ssh_socket_poll(struct socket *s, int *writeable, int *except) {
|
||||
if (!s->data_to_write) {
|
||||
fd->events |= POLLOUT;
|
||||
}
|
||||
|
||||
/* Make the call, and listen for errors */
|
||||
rc = ssh_poll(fd, 1, 0);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "poll(): %s", strerror(errno));
|
||||
leave_function();
|
||||
return -1;
|
||||
/* do not do poll if fd->events is empty, we already know the response */
|
||||
if(fd->events != 0){
|
||||
/* Make the call, and listen for errors */
|
||||
rc = ssh_poll(fd, 1, 0);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "poll(): %s", strerror(errno));
|
||||
leave_function();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!s->data_to_read) {
|
||||
@@ -542,7 +562,7 @@ int ssh_socket_nonblocking_flush(struct socket *s) {
|
||||
buffer_get_rest_len(s->out_buffer));
|
||||
} else {
|
||||
/* write failed */
|
||||
w =- 1;
|
||||
w = -1;
|
||||
}
|
||||
|
||||
if (w < 0) {
|
||||
@@ -658,6 +678,54 @@ int ssh_socket_get_status(struct socket *s) {
|
||||
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: */
|
||||
|
||||
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) {
|
||||
int mode=GCRY_CIPHER_MODE_CBC;
|
||||
if (cipher->key == NULL) {
|
||||
if (alloc_key(cipher) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(strstr(cipher->name,"-ctr"))
|
||||
mode=GCRY_CIPHER_MODE_CTR;
|
||||
switch (cipher->keysize) {
|
||||
case 128:
|
||||
if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_AES128,
|
||||
GCRY_CIPHER_MODE_CBC, 0)) {
|
||||
mode, 0)) {
|
||||
SAFE_FREE(cipher->key);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 192:
|
||||
if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_AES192,
|
||||
GCRY_CIPHER_MODE_CBC, 0)) {
|
||||
mode, 0)) {
|
||||
SAFE_FREE(cipher->key);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 256:
|
||||
if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_AES256,
|
||||
GCRY_CIPHER_MODE_CBC, 0)) {
|
||||
mode, 0)) {
|
||||
SAFE_FREE(cipher->key);
|
||||
return -1;
|
||||
}
|
||||
@@ -189,9 +191,17 @@ static int aes_set_key(struct crypto_struct *cipher, void *key, void *IV) {
|
||||
SAFE_FREE(cipher->key);
|
||||
return -1;
|
||||
}
|
||||
if (gcry_cipher_setiv(cipher->key[0], IV, 16)) {
|
||||
SAFE_FREE(cipher->key);
|
||||
return -1;
|
||||
if(mode == GCRY_CIPHER_MODE_CBC){
|
||||
if (gcry_cipher_setiv(cipher->key[0], IV, 16)) {
|
||||
|
||||
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_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",
|
||||
.blocksize = 16,
|
||||
@@ -570,6 +613,30 @@ static void aes_decrypt(struct crypto_struct *cipher, void *in, void *out,
|
||||
unsigned long len, void *IV) {
|
||||
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 */
|
||||
|
||||
#ifdef HAS_DES
|
||||
@@ -661,6 +728,41 @@ static struct crypto_struct ssh_ciphertab[] = {
|
||||
},
|
||||
#endif /* HAS_BLOWFISH */
|
||||
#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",
|
||||
16,
|
||||
@@ -907,7 +1009,8 @@ int crypt_set_algorithms_server(ssh_session session){
|
||||
/* out */
|
||||
server = session->server_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){
|
||||
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 */
|
||||
client=session->client_kex.methods[SSH_CRYPT_C_S];
|
||||
server=session->server_kex.methods[SSH_CRYPT_S_C];
|
||||
match=ssh_find_matching(client,server);
|
||||
match=ssh_find_matching(server,client);
|
||||
if(!match){
|
||||
ssh_set_error(session,SSH_FATAL,"Crypt_set_algorithms_server : no matching algorithm function found for %s",server);
|
||||
free(match);
|
||||
@@ -964,7 +1067,7 @@ int crypt_set_algorithms_server(ssh_session session){
|
||||
/* compression */
|
||||
client=session->client_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")){
|
||||
ssh_log(session,SSH_LOG_PACKET,"enabling C->S compression");
|
||||
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];
|
||||
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")){
|
||||
ssh_log(session,SSH_LOG_PACKET,"enabling S->C compression\n");
|
||||
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];
|
||||
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"))
|
||||
session->hostkeys=TYPE_DSS;
|
||||
else if(match && !strcmp(match,"ssh-rsa"))
|
||||
|
||||
Reference in New Issue
Block a user