Compare commits

...

109 Commits

Author SHA1 Message Date
Andreas Schneider
a6a7922dbd Update Changelog. 2010-05-31 19:36:32 +02:00
Aris Adamantiadis
608e81bc00 Fix warning for snprintf 2010-05-31 11:52:36 +03:00
Aris Adamantiadis
7e17838c0b Fix unclean null termination in ~ expending 2010-05-31 11:50:52 +03:00
Andreas Schneider
84f6945a9c Increased version numbers. 2010-05-30 11:26:11 +02:00
Andreas Schneider
3ae187dbe7 misc: Make sure the expanded string is null-terminated. 2010-05-30 11:00:38 +02:00
Andreas Schneider
26989ab001 session: Fixed setting up default identity files. 2010-05-28 10:47:37 +02:00
Andreas Schneider
5b2e39cd79 options: Make sure that we have always have default options set. 2010-05-21 10:21:03 +02:00
Andreas Schneider
13af149ef9 options: Set the local username if still not set. 2010-05-21 10:19:06 +02:00
Andreas Schneider
3453cafd95 keyfiles: Fixed possible problem with known_hosts path. 2010-05-21 10:03:13 +02:00
Andreas Schneider
fa65fd3dd1 cmake: Fixed doxygen. 2010-05-18 00:32:43 +02:00
Andreas Schneider
ec5fa5cc06 doxygen: Fixed latex pdf generation. 2010-05-18 00:08:01 +02:00
Andreas Schneider
8577688174 Updated changelog file. 2010-05-17 23:41:15 +02:00
Andreas Schneider
31462a4d72 sftp: Fixed sftp_chown. 2010-05-17 23:38:21 +02:00
Aris Adamantiadis
fd2ff2d29c Fix sftp_rename on sftp3 2010-05-17 20:05:22 +02:00
Aris Adamantiadis
0b09bd900f Typos in last patch 2010-05-14 12:49:24 +02:00
Aris Adamantiadis
abc61fa1cc Fix build on VC7 2010-05-14 12:46:17 +02:00
Aris Adamantiadis
e94bff02ba Respond to keepalives/global requests 2010-05-12 21:58:09 +02:00
Andreas Schneider
3671c61023 build: Fixed build.
I've added a non-existent kex header, sorry.
2010-05-12 19:36:40 +02:00
Andreas Schneider
2702f3ea3f Fixed building libssh with DEBUG_CRYPTO. 2010-05-12 19:25:34 +02:00
Andreas Schneider
4abd0522b4 Increment version and soversion numbers. 2010-05-12 19:00:07 +02:00
Andreas Schneider
62b6eb4436 Updated ChangeLog entries for 0.4.3. 2010-05-12 18:59:29 +02:00
Andreas Schneider
4b7eba1eda Added runtime detection of WSAPoll().
Signed-off-by: Andreas Schneider <mail@cynapses.org>
2010-05-12 18:44:09 +02:00
Andreas Schneider
9970b1fd7d Added the possibility to define _OPENSSL_DIR and _ZLIB_DIR. 2010-05-12 13:57:54 +02:00
Andreas Schneider
d703f51861 Fixed windows include files in pcap support. 2010-05-12 13:39:00 +02:00
Andreas Schneider
a009702cd6 Fixed Windows build warnings. 2010-05-12 13:11:33 +02:00
Andreas Schneider
ed268e5948 Fixed Windows build. 2010-05-12 13:11:33 +02:00
Andreas Schneider
10b4654ad5 Added a select(2) based poll-emulation if poll(2) is not available. 2010-05-12 13:11:33 +02:00
Andreas Schneider
9d7fc9d50b Use the new expand functions.
This implements escape chars for IdentityFile in ssh_config and reads
the system ssh_config.
2010-05-11 09:52:06 +02:00
Andreas Schneider
b8bc3a6582 Added a function to expand an escaped string. 2010-05-11 09:44:29 +02:00
Andreas Schneider
07e8d8f1f2 Added a function to expand the tilde from a path. 2010-05-11 09:44:13 +02:00
Aris Adamantiadis
34a927716a Added code to test proxycommand 2010-05-10 22:40:28 +02:00
Aris Adamantiadis
bae4090715 Backport of the proxycommand feature 2010-05-10 22:32:52 +02:00
Andreas Schneider
403ded1e97 Use configure checks to define vsnprintf and strncpy. 2010-05-10 15:53:57 +02:00
Andreas Schneider
6fd8de3376 Added configure checks for _vsnprintf_s and strncpy. 2010-05-10 15:53:46 +02:00
Andreas Schneider
5fe99f8b09 Fixed building libssh with VC9. 2010-05-10 14:41:20 +02:00
Patrick Spendrin
af155db080 Move ssh_hostport to a location which is global accessible.
Signed-off-by: Andreas Schneider <mail@cynapses.org>
2010-05-10 10:48:13 +02:00
Patrick Spendrin
df5a94d445 The lower function doesn't have the prefix.
Signed-off-by: Andreas Schneider <mail@cynapses.org>
2010-05-10 10:48:03 +02:00
Andreas Schneider
4bfe7f024c Added more defines to use secure VC functions. 2010-05-10 10:45:51 +02:00
Aris Adamantiadis
99ea177eea oops, this file was not intended to be commited 2010-05-07 13:03:35 +02:00
Aris Adamantiadis
476630841f Match hashed [host]:port format knownhosts 2010-05-07 13:02:28 +02:00
Aris Adamantiadis
7f59662cad knownhosts writing cherry-pick
Conflicts:

	libssh/keyfiles.c
	tests/unittests/CMakeLists.txt
2010-05-07 12:58:56 +02:00
Aris Adamantiadis
e9d6b15926 First implementation of known_hosts with port read
Conflicts:

	include/libssh/misc.h
	libssh/keyfiles.c
	libssh/misc.c
2010-05-07 12:55:33 +02:00
Aris Adamantiadis
6885d32c05 Added ssh_privatekey_type public function 2010-04-28 11:51:02 +02:00
Aris Adamantiadis
e5c2af6316 Fix doublefree happening after a negociation error 2010-04-14 20:56:22 +02:00
Aris Adamantiadis
08a1bebb58 Do not compile aes*-ctr with <=OpenSSL 0.9.7b 2010-04-14 20:43:06 +02:00
Aris Adamantiadis
6195b133bf Fix missing string_data() in crypto debug code 2010-04-14 18:24:23 +02:00
Aris Adamantiadis
6e65abbe63 Fix vsnprintf symbol on older VS2003 compiler 2010-04-06 22:58:43 +02:00
Aris Adamantiadis
bda836d744 Fix building on win32/vs7 2010-04-06 22:23:43 +02:00
Andreas Schneider
c8c2647555 Fixed a typo. 2010-04-04 15:55:49 +02:00
Andreas Schneider
4ad74765f6 Removed the unneeded dependency to doxygen. 2010-04-04 15:00:59 +02:00
Andreas Schneider
b1f93f600e Fixed documentation of ssh_bind_options_set. 2010-04-04 14:07:54 +02:00
Andreas Schneider
28edbe1ef5 Added an improved version of UseDoxygen.cmake which handles trac doc. 2010-04-04 14:07:43 +02:00
Andreas Schneider
75cf66a3ee Added a doxygen configuration for trac. 2010-04-04 14:04:38 +02:00
Andreas Schneider
5021ed3074 Fixed config parsing wich has overwritten user specified values. 2010-04-04 14:02:09 +02:00
Andreas Schneider
3773366a25 Fixed blocking bug in channel_poll.
This is a backport from 514ab6eed2.
2010-04-03 23:29:01 +02:00
Aris Adamantiadis
c6fab4bf84 Fix openssl detection in cmake 2010-03-29 23:06:20 +02:00
Aris Adamantiadis
7d1dcb0dff Fix file inclusion with VS2003 2010-03-29 22:23:47 +02:00
Aris Adamantiadis
d7c1384df0 Fix exec example which has broken read usage 2010-03-28 21:49:17 +02:00
Aris Adamantiadis
d2bb97c1c6 Fixes the broken algorithm choice for server 2010-03-28 21:43:13 +02:00
Aris Adamantiadis
3b6098597d Fix crash when no callback is defined 2010-03-28 21:19:12 +02:00
Andreas Schneider
964d8fdc11 Fixed build warnings on Windows. 2010-03-25 16:47:45 +01:00
Andreas Schneider
5d339aa9e2 Fixed a build warning in ssh_userauth_autopubkey. 2010-03-25 15:32:28 +01:00
Andreas Schneider
af7f69c515 Fixed spelling. 2010-03-25 13:55:50 +01:00
Andreas Schneider
ea92d5b230 Added comments to the so version to increment it correctly in future. 2010-03-25 13:24:59 +01:00
Andreas Schneider
f096e031ed Fixed a typo that we don't export all symbols. 2010-03-25 09:52:05 +01:00
Andreas Schneider
a8be476ea9 Build examples only on the Linux plattform. 2010-03-17 10:09:38 +01:00
Andreas Schneider
b9f65b5740 Added changelog entries for version 0.4.2. 2010-03-15 19:33:49 +01:00
Andreas Schneider
99a58eb325 Increase version number to 0.4.2. 2010-03-15 19:33:11 +01:00
Andreas Schneider
ed1cba705c Fixed a memory leak in ssh_try_publickey_from_file. 2010-03-13 15:00:19 +01:00
Andreas Schneider
0b13a6d265 Added missing SSH_OPTIONS_FD option. 2010-03-13 14:21:57 +01:00
Andreas Schneider
74c0201219 Remove support for SSHv1 Cipher variable. 2010-03-13 13:09:23 +01:00
Andreas Schneider
83c51d1c13 Fixed and added support for several identity files. 2010-03-06 12:33:27 +01:00
Andreas Schneider
c712d30311 Rename ssh_list_add to ssh_list_append. 2010-03-06 12:29:03 +01:00
Andreas Schneider
2144049c7d Added a prepend function for ssh_list. 2010-03-06 12:29:03 +01:00
Aris Adamantiadis
9dd86859e8 renamed ssh_list_get_head to ssh_list_pop_head 2010-03-06 12:28:56 +01:00
Andreas Schneider
810fbfb620 Fixed sftp_parse_longname() on Windows.
There is no strndup function on Windows.
2010-03-02 14:16:21 +01:00
Aris Adamantiadis
370d072eba Fix a race condition bug in ssh_scp_close() 2010-03-01 20:00:29 +01:00
Aris Adamantiadis
56dfa69fc9 Send back replies to openssh's keepalives 2010-03-01 18:41:59 +01:00
Aris Adamantiadis
672f8412f0 Fixed documentation in scp code 2010-02-26 18:49:15 +01:00
Andreas Schneider
83ff1ffcc3 Added printout of owner and group in the sftp example. 2010-02-24 00:26:20 +01:00
Andreas Schneider
fb35153b49 Fixed longname parsing, this only workings with readdir. 2010-02-24 00:25:38 +01:00
Andreas Schneider
7539200773 Added owner and group information in sftp attributes.
Parse the longname which is the output of 'ls -l' and set the owner and
group if we are talking to an openssh server.
2010-02-23 22:52:56 +01:00
Andreas Schneider
254a166c02 Don't add the tests directory to the build. 2010-02-13 13:13:20 +01:00
Andreas Schneider
3e938cb901 Added ChangeLog entries for 0.4.1. 2010-02-13 13:00:10 +01:00
Andreas Schneider
452b16ede2 Set CFLAGS correctly. 2010-02-13 13:00:10 +01:00
Aris Adamantiadis
bd47ff75ba Fix compilation of opensolaris 2010-02-12 10:08:22 +01:00
Andreas Schneider
0016ded7f9 Try zlib compression and fallback to none if not available. 2010-02-11 23:28:37 +01:00
Aris Adamantiadis
d725b31752 Use closesocket in server.c for win32
Resolves #56
2010-02-11 19:54:57 +01:00
Aris Adamantiadis
c2e86c876c aes128-ctr aes192-ctr aes256-ctr for libgcrypt 2010-02-09 22:43:37 +01:00
Aris Adamantiadis
028516ba6a aes192-ctr and aes256-ctr working on libcrypto 2010-02-09 22:43:27 +01:00
Aris Adamantiadis
344b27ac6c Added aes128-ctr support for libcrypto (openssl) 2010-02-09 22:43:13 +01:00
Aris Adamantiadis
a700259b01 KEX bug: client preference should be prioritary 2010-02-09 22:42:53 +01:00
Andreas Schneider
14da14db05 Respect known_hosts file set by the user.
Thanks to contact@leblanc-simon.eu for the patch.
2010-02-07 22:39:35 +01:00
Vic Lee
474d63f24e The ssh_message object needs to be freed after processing in channel_accept().
Signed-off-by: Vic Lee <llyzs@163.com>
Signed-off-by: Andreas Schneider <mail@cynapses.org>
2010-02-01 17:24:50 +01:00
Andreas Schneider
b3589fbf6c Increased version number. 2010-01-29 18:59:55 +01:00
Aris Adamantiadis
dd68bae776 Fix underflow when leave_function() are unbalanced 2010-01-29 18:54:48 +01:00
Vic Lee
4768cf3e85 In handle_channel_request_open(), variable type is freed too early and cause memory corruptions.
Signed-off-by: Vic Lee <llyzs@163.com>
Signed-off-by: Andreas Schneider <mail@cynapses.org>
2010-01-29 18:51:50 +01:00
Vic Lee
5a95681f01 File handle need to be closed in case of errors in privatekey_from_file
Signed-off-by: Vic Lee <llyzs@163.com>
Signed-off-by: Andreas Schneider <mail@cynapses.org>
2009-12-23 09:37:59 +01:00
Andreas Schneider
13a3619102 Added an example for exec. 2009-12-22 18:33:16 +01:00
Vic Lee
c7636edf84 Added private key type detection feature in privatekey_from_file
Signed-off-by: Vic Lee <llyzs@163.com>
Signed-off-by: Andreas Schneider <mail@cynapses.org>
2009-12-22 08:58:05 +01:00
Andreas Schneider
27e332b623 Fixed ssh_get_user_home_dir() to be thread safe. 2009-12-21 12:33:44 +01:00
Andreas Schneider
ebc8544c56 Improved doxygen output of ssh_options_set(). 2009-12-19 00:11:37 +01:00
Andreas Schneider
0f8e9b839c Disabled caller graphs as they are only of internal interest. 2009-12-18 23:55:17 +01:00
Andreas Schneider
0c02d6effe Updated the doxygen file. 2009-12-18 23:49:56 +01:00
Andreas Schneider
7199b196b0 Fixed documentation of buffer struct. 2009-12-18 23:45:34 +01:00
Andreas Schneider
ca83b66066 Fixed documentation of ssh_options_copy(). 2009-12-18 23:45:24 +01:00
Andreas Schneider
d978f9b58a Moved the doxygen mainpage to doc/mainpage.dox 2009-12-18 23:45:09 +01:00
Andreas Schneider
e539eaf9e0 Added a mainpage to doxygen. 2009-12-18 23:11:25 +01:00
Andreas Schneider
b728f44ce9 Fixed the doxygen documentation. 2009-12-18 23:05:03 +01:00
50 changed files with 3476 additions and 932 deletions

View File

@@ -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 "4")
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.1")
set(LIBRARY_SOVERSION "4")
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
@@ -45,12 +52,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 +68,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)

View File

@@ -13,7 +13,7 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING")
### versions
set(CPACK_PACKAGE_VERSION_MAJOR "0")
set(CPACK_PACKAGE_VERSION_MINOR "4")
set(CPACK_PACKAGE_VERSION_PATCH "0")
set(CPACK_PACKAGE_VERSION_PATCH "4")
set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")

View File

@@ -1,6 +1,64 @@
ChangeLog
==========
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).

View File

@@ -1,4 +1,5 @@
include(CheckIncludeFile)
include(CheckIncludeFiles)
include(CheckSymbolExists)
include(CheckFunctionExists)
include(CheckLibraryExists)
@@ -16,25 +17,40 @@ set(SYSCONFDIR ${SYSCONF_INSTALL_DIR})
set(BINARYDIR ${CMAKE_BINARY_DIR})
set(SOURCEDIR ${CMAKE_SOURCE_DIR})
if(CMAKE_COMPILER_IS_GNUC)
if(CMAKE_COMPILER_IS_GNUCC)
check_c_compiler_flag("-fvisibility=hidden" WITH_VISIBILITY_HIDDEN)
endif(CMAKE_COMPILER_IS_GNUC)
endif(CMAKE_COMPILER_IS_GNUCC)
# 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)
endif (HAVE_WSPIAPI_H OR HAVE_WS2TCPIP_H)
check_function_exists(vsnprintf HAVE_VSNPRINTF)
if(NOT HAVE_VSNPRINTF)
check_function_exists(_vsnprintf_s HAVE__VSNPRINTF_S)
check_function_exists(_vsnprintf HAVE__VSNPRINTF)
endif(NOT HAVE_VSNPRINTF)
check_function_exists(snprintf HAVE_SNPRINTF)
if(NOT HAVE_SNPRINTF)
check_function_exists(_snprintf HAVE__SNPRINTF)
check_function_exists(_snprintf_s HAVE__SNPRINTF_S)
endif(NOT HAVE_SNPRINTF)
check_function_exists(strncpy HAVE_STRNCPY)
set(HAVE_SELECT TRUE)
endif (WIN32)
@@ -82,9 +98,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)

View File

@@ -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)

View File

@@ -34,6 +34,7 @@ else (OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIRS)
NAMES
openssl/ssl.h
PATHS
${_OPENSSL_DIR}/include
${_OPENSSL_INCLUDEDIR}
/usr/include
/usr/local/include
@@ -49,6 +50,7 @@ else (OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIRS)
ssl
libssl
PATHS
${_OPENSSL_DIR}/lib
${_OPENSSL_LIBDIR}
/usr/lib
/usr/local/lib
@@ -64,6 +66,7 @@ else (OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIRS)
NAMES
ssleay32
PATHS
${_OPENSSL_DIR}/lib
${_OPENSSL_LIBDIR}
/usr/lib
/usr/local/lib
@@ -79,6 +82,7 @@ else (OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIRS)
NAMES
ssleay32MD
PATHS
${_OPENSSL_DIR}/lib
${_OPENSSL_LIBDIR}
/usr/lib
/usr/local/lib
@@ -99,6 +103,7 @@ else (OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIRS)
libeay
libeay32
PATHS
${_OPENSSL_DIR}/lib
${_OPENSSL_LIBDIR}
/lib
/usr/lib

View File

@@ -23,6 +23,7 @@ else (ZLIB_LIBRARIES AND ZLIB_INCLUDE_DIRS)
NAMES
zlib.h
PATHS
${_ZLIB_DIR}/include
/usr/include
/usr/local/include
/opt/local/include
@@ -36,6 +37,7 @@ else (ZLIB_LIBRARIES AND ZLIB_INCLUDE_DIRS)
zlib
zlib1
PATHS
${_ZLIB_DIR}/lib
/usr/lib
/usr/local/lib
/opt/local/lib

View File

@@ -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()

View File

@@ -37,6 +37,28 @@
/*************************** FUNCTIONS ***************************/
/* Define to 1 if you have the `vsnprintf' function. */
#cmakedefine HAVE_VSNPRINTF
/* Define to 1 if you have the `_vsnprintf' function. */
#cmakedefine HAVE__VSNPRINTF
/* Define to 1 if you have the `_vsnprintf_s' function. */
#cmakedefine HAVE__VSNPRINTF_S
/* Define to 1 if you have the `snprintf' function. */
#cmakedefine HAVE_SNPRINTF
/* Define to 1 if you have the `_snprintf' function. */
#cmakedefine HAVE__SNPRINTF
/* Define to 1 if you have the `_snprintf_s' function. */
#cmakedefine HAVE__SNPRINTF_S
/* Define to 1 if you have the `strncpy' function. */
#cmakedefine HAVE_STRNCPY
/* Define to 1 if you have the `cfmakeraw' function. */
#cmakedefine HAVE_CFMAKERAW 1

1
doc/TracFooter.html Normal file
View File

@@ -0,0 +1 @@
<!-- Doxygen TracFooter -->

4
doc/TracHeader.html Normal file
View 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 -->

View File

@@ -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

File diff suppressed because it is too large Load Diff

12
doc/mainpage.dox Normal file
View 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...
*/

View File

@@ -14,10 +14,12 @@ 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})
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})
include_directories(
${LIBSSH_PUBLIC_INCLUDE_DIRS}

57
examples/exec.c Normal file
View 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;
}

View File

@@ -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)){

View File

@@ -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);

View File

@@ -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;

View File

@@ -79,7 +79,7 @@
/* libssh version */
#define LIBSSH_VERSION_MAJOR 0
#define LIBSSH_VERSION_MINOR 4
#define LIBSSH_VERSION_MICRO 0
#define LIBSSH_VERSION_MICRO 4
#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \
LIBSSH_VERSION_MINOR, \
@@ -231,7 +231,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
@@ -252,6 +252,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,
@@ -263,7 +264,8 @@ 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
};
enum {
@@ -335,10 +337,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);
@@ -383,6 +389,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);

View File

@@ -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_ */

View File

@@ -40,7 +40,7 @@ typedef struct ssh_pollfd_struct {
/* 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 +59,24 @@ typedef struct ssh_pollfd_struct {
#define POLLNVAL 0x020 /* Invalid polling request. */
#endif
#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
typedef unsigned long int nfds_t;
#endif /* HAVE_POLL */
void ssh_poll_init(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;

View File

@@ -33,17 +33,56 @@
#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')
#if _MSC_VER >= 1400
#define strdup _strdup
#endif
#define usleep(X) Sleep(((X)+1000)/1000)
#undef strtok_r
#define strtok_r strtok_s
#ifndef HAVE_SNPRINTF
#ifdef HAVE__SNPRINTF_S
#define snprintf(d, n, ...) _snprintf_s((d), (n), _TRUNCATE, __VA_ARGS__)
#else
#ifdef HAVE__SNPRINTF
#define snprintf _snprintf
#else
#error "no snprintf compatible function found"
#endif /* HAVE__SNPRINTF */
#endif /* HAVE__SNPRINTF_S */
#endif /* HAVE_SNPRINTF */
#ifndef HAVE_VSNPRINTF
#ifdef HAVE__VSNPRINTF_S
#define vsnprintf(s, n, f, v) _vsnprintf_s((s), (n), _TRUNCATE, (f), (v))
#else
#ifdef HAVE__VSNPRINTF
#define vsnprintf _vsnprintf
#else /* HAVE_VSNPRINTF */
#error "No vsnprintf compatible function found"
#endif /* HAVE__VSNPRINTF */
#endif /* HAVE__VSNPRINTF_S */
#endif /* HAVE_VSNPRINTF */
#ifndef HAVE_STRNCPY
#define strncpy(d, s, n) strncpy_s((d), (n), (s), _TRUNCATE)
#endif
#else /* _MSC_VER */
#include <unistd.h>
#define PRIdS "zd"
#endif
#endif /* _MSC_VER */
#include "libssh/libssh.h"
#include "libssh/callbacks.h"
@@ -77,7 +116,7 @@ typedef struct kex_struct {
struct error_struct {
/* error handling */
int error_code;
unsigned int error_code;
char error_buffer[ERROR_BUFFERLEN];
};
@@ -222,8 +261,8 @@ int gettimeofday(struct timeval *__p, void *__t);
/* 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)

View File

@@ -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);

View File

@@ -104,7 +104,7 @@ struct ssh_session_struct {
char *host;
char *bindaddr; /* TODO: check if needed */
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_ */

View File

@@ -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;

View File

@@ -52,4 +52,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_ */

View File

@@ -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;

View File

@@ -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

View File

@@ -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"
@@ -224,7 +225,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 +331,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 +443,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 +561,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 +688,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 +757,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 +777,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 +798,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 +958,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 +1335,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 +1367,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).
*/

View File

@@ -552,6 +552,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_SUCCESS);
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 +575,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();
@@ -1359,6 +1368,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,7 +1383,9 @@ 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;
}
@@ -1806,7 +1818,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 +2007,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;
}
}

View File

@@ -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"

View File

@@ -296,6 +296,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 +401,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);
@@ -485,6 +482,7 @@ int ssh_connect(ssh_session session) {
int ssh1 = 0;
int ssh2 = 0;
int fd = -1;
int ret;
if (session == NULL) {
ssh_set_error(session, SSH_FATAL, "Invalid session pointer");
@@ -500,13 +498,26 @@ int ssh_connect(ssh_session session) {
leave_function();
return SSH_ERROR;
}
if (session->fd == -1 && session->host == NULL) {
if (session->fd == -1 && session->host == NULL &&
session->ProxyCommand == NULL) {
ssh_set_error(session, SSH_FATAL, "Hostname required");
leave_function();
return SSH_ERROR;
}
ret = ssh_options_apply(session);
if (ret < 0) {
ssh_set_error(session, SSH_FATAL, "Couldn't apply options");
leave_function();
return SSH_ERROR;
}
if (session->fd != -1) {
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);
@@ -699,7 +710,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: */

View File

@@ -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,6 +276,12 @@ 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);
break;

View File

@@ -341,7 +341,6 @@ socket_t ssh_connect_host(ssh_session session, const char *host,
ssh_set_error(session, SSH_FATAL, "Connect failed: %s", strerror(errno));
ssh_connect_socket_close(s);
s = -1;
leave_function();
continue;
} else {
/* We are connected */

View File

@@ -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));

View File

@@ -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);

View 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

View File

@@ -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);
}
}

View File

@@ -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"
@@ -112,16 +116,23 @@ int gettimeofday(struct timeval *__p, void *__t) {
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;
}
@@ -136,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;
@@ -149,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.
@@ -213,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;
@@ -228,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;
@@ -252,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)
@@ -397,5 +494,155 @@ 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, *r;
const char *p;
size_t ld;
size_t lh = 0;
if (d[0] != '~') {
return strdup(d);
}
d++;
/* handle ~user/path */
p = strchr(d, '/');
if (p != NULL && p > d) {
#ifdef _WIN32
return strdup(d);
#else
struct passwd *pw;
size_t s = p - d;
char u[128];
if (s > sizeof(u)) {
return NULL;
}
memcpy(u, d, s);
u[s] = '\0';
pw = getpwnam(u);
if (pw == NULL) {
return NULL;
}
ld = strlen(p);
h = strdup(pw->pw_dir);
#endif
} else {
ld = strlen(d);
p = (char *) d;
h = ssh_get_user_home_dir();
}
if (h == NULL) {
return NULL;
}
lh = strlen(h);
r = malloc(ld + lh + 1);
if (r == NULL) {
return NULL;
}
if (lh > 0) {
memcpy(r, h, lh);
}
memcpy(r + lh, p, ld + 1);
return r;
}
char *ssh_path_expand_escape(ssh_session session, const char *s) {
#define MAX_BUF_SIZE 4096
char host[NI_MAXHOST];
char buf[MAX_BUF_SIZE];
char *r, *x = NULL;
const char *p;
size_t i, l;
if (strlen(s) > MAX_BUF_SIZE) {
ssh_set_error(session, SSH_FATAL, "string to expand too long");
return NULL;
}
r = ssh_path_expand_tilde(s);
if (r == NULL) {
ssh_set_error_oom(session);
return NULL;
}
p = r;
buf[0] = '\0';
for (i = 0; *p != '\0'; p++) {
if (*p != '%') {
buf[i] = *p;
i++;
if (i > MAX_BUF_SIZE) {
return NULL;
}
buf[i] = '\0';
continue;
}
p++;
if (*p == '\0') {
break;
}
switch (*p) {
case 'd':
x = strdup(session->sshdir);
break;
case 'u':
x = ssh_get_local_username(session);
break;
case 'l':
if (gethostname(host, sizeof(host) == 0)) {
x = strdup(host);
}
break;
case 'h':
x = strdup(session->host);
break;
case 'r':
x = strdup(session->username);
break;
default:
ssh_set_error(session, SSH_FATAL,
"Wrong escape sequence detected");
return NULL;
}
if (x == NULL) {
ssh_set_error_oom(session);
return NULL;
}
i += strlen(x);
if (i > MAX_BUF_SIZE) {
ssh_set_error(session, SSH_FATAL,
"String too long");
return NULL;
}
l = strlen(buf);
strcat(buf + l, x);
buf[i] = '\0';
SAFE_FREE(x);
}
free(r);
return strdup(buf);
#undef MAX_BUF_SIZE
}
/* @} */
/* vim: set ts=4 sw=4 et cindent: */

View File

@@ -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,150 @@ 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_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 +324,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 +388,23 @@ 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_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 +416,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;
}
@@ -608,16 +564,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)) {
@@ -818,7 +792,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;
}
@@ -1041,19 +1015,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: */

View File

@@ -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:

View File

@@ -30,7 +30,9 @@
#ifdef WITH_PCAP
#include <stdio.h>
#ifndef _WIN32
#ifdef _WIN32
#include <ws2tcpip.h>
#else
#include <sys/time.h>
#include <sys/socket.h>
#endif
@@ -91,7 +93,7 @@ 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
*/
uint32_t ipsource;

View File

@@ -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,176 +59,163 @@ struct ssh_poll_ctx_struct {
#ifdef HAVE_POLL
#include <poll.h>
void ssh_poll_init(void) {
return;
}
int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
return poll((struct pollfd *) fds, nfds, timeout);
}
#else /* HAVE_POLL */
#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
#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;
#define WS2_LIBRARY "ws2_32.dll"
typedef int (*poll_fn)(ssh_pollfd_t *, nfds_t, int);
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());
}
static poll_fn win_poll;
static HINSTANCE hlib;
#else
#include <sys/select.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/time.h>
#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;
}
}
/*
* If no timeout and polling several handles, recurse to poll
* the rest of them.
*/
if (timeout == 0 && nhandles > 1) {
/* Remove the handle that fired */
int i;
if (ready < nhandles - 1) {
for (i = ready - WAIT_OBJECT_0 + 1; i < nhandles; i++) {
handles[i-1] = handles[i];
}
}
nhandles--;
recursed_result = poll_rest(handles, nhandles, fds, nfds, 0);
if (recursed_result < 0) {
return -1;
}
return recursed_result + 1;
}
return 1;
}
return 0;
}
int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
ssh_pollfd_t *f;
int nhandles = 0;
int rc = -1;
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 (max_fd = -1, i = 0; i < nfds; i++) {
if (fds[i].fd < 0) {
continue;
}
if (i == nhandles) {
if (nhandles == MAXIMUM_WAIT_OBJECTS) {
break;
} else {
handles[nhandles++] = (HANDLE) f->fd;
}
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;
}
}
}
if (timeout == -1) {
timeout = INFINITE;
if (max_fd == -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};
/* support for POLLHUP */
#ifdef _WIN32
if ((recv(fds[i].fd, data, 64, MSG_PEEK) == -1) &&
(errno == WSAESHUTDOWN || errno == WSAECONNRESET ||
errno == WSAECONNABORTED || errno == WSAENETRESET)) {
#else
if ((recv(fds[i].fd, data, 64, MSG_PEEK) == -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) {
poll_fn wsa_poll = NULL;
#endif /* _WIN32 */
hlib = LoadLibrary(WS2_LIBRARY);
if (hlib != NULL) {
wsa_poll = (poll_fn) GetProcAddress(hlib, "WSAPoll");
}
if (wsa_poll == NULL) {
win_poll = bsd_poll;
} else {
win_poll = wsa_poll;
}
}
int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
return win_poll(fds, nfds, timeout);
}
#endif /* HAVE_POLL */

View File

@@ -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;
}
/** @} */

View File

@@ -278,7 +278,11 @@ void ssh_bind_free(ssh_bind sshbind){
}
if (sshbind->bindfd >= 0) {
#ifdef _WIN32
closesocket(sshbind->bindfd);
#else
close(sshbind->bindfd);
#endif
}
sshbind->bindfd = -1;
@@ -867,7 +871,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 +880,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;

View File

@@ -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:
@@ -155,19 +191,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 +410,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: */

View File

@@ -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);
}

View File

@@ -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 const 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,6 +71,8 @@ int ssh_socket_init(void) {
if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
return -1;
}
ssh_poll_init();
#endif
return 0;
}
@@ -658,6 +663,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: */

View File

@@ -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"))