Compare commits

...

104 Commits

Author SHA1 Message Date
Andreas Schneider
39802b31fe build: Set libssh version to 0.5.1. 2011-08-09 14:47:33 +02:00
Andreas Schneider
e5a2aef1bf build: Updated ChangeLog. 2011-08-09 14:46:26 +02:00
Einar Floystad Dorum
edb03bd224 Fixed ssh_scp_write so it works when doing recursive copy
There where two issues with ssh_scp_write:
1) It did not write a status message after the last write and OpenSSH
   would then give up after the write finished.
2) OpenSSH would sometimes write a status message, after near ends write.
   If scp_write didn't handle it, and subsequent status message. The remote
   window would shrink to zero and ssh_channel_write would start returning 0.

Signed-off-by: Einar Floystad Dorum <einarfd@mailthief.com>
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 01c4b713dc)
2011-08-08 15:28:08 +02:00
rofl0r
1204f43ea9 client: Fix another source of endless wait.
(cherry picked from commit 35686b4822)
2011-08-07 12:47:23 +02:00
rofl0r
b542bc9e4e channels: Fix an endless loop in case of a channel_open error.
(cherry picked from commit 7ccd9c31b3)
2011-08-07 12:47:17 +02:00
rofl0r
61a97ccede session: Fix timeout handling.
-2 now means to use the timeout specified in options. It wasn't used
earlier and poll only knows -1 and 0 anyway for special meanings.
(cherry picked from commit af85337f5f)
2011-08-07 12:47:09 +02:00
rofl0r
a1ef27c0b8 channels: Fix checking for fatal errors.
We need this that we don't end up in and infinite poll loop.
(cherry picked from commit 563fbe4de8)

Conflicts:

	src/poll.c
2011-08-07 12:46:47 +02:00
rofl0r
fb8f2cd11b channels: Fix ssh_channel_from_local()
It only worked if the first channel in the list was equivalent to we
were looking for.
(cherry picked from commit 39f962c91e)
2011-08-07 12:46:06 +02:00
rofl0r
1d8a9ddf84 misc: Fix ssh_timeout_update().
(cherry picked from commit c31cac93f3)
2011-08-07 12:45:54 +02:00
Andreas Schneider
bea66b6476 examples: Fix permissions of the file we copy.
Thanks to Baptiste Marchand.
(cherry picked from commit 15ebbad146)
2011-08-03 22:23:51 +02:00
Andreas Schneider
a8111934d5 channels: Set the max packet size to 32768.
(cherry picked from commit 790b62bca5)
2011-08-03 22:20:52 +02:00
Aris Adamantiadis
f201e983b0 Workaround ssh_get_user_home_dir on LDAP users 2011-07-13 12:04:04 +02:00
Andreas Schneider
81332e1e27 build: Fix libssh_threads pkg-config.
(cherry picked from commit 269c9fed354f3a8adbc54fccba6287d5b1f166e3)
2011-06-15 18:26:33 +02:00
Andreas Schneider
ea84f50603 cmake: Added pkg-config support for libssh_treads.
(cherry picked from commit 583a7f933a)
2011-06-14 13:47:51 +02:00
Andreas Schneider
ccc94e7ab6 packet: Don't (de)compress empty buffers.
This fixes bug #50.
(cherry picked from commit fb0f125351)
2011-06-11 13:16:21 +02:00
Aris Adamantiadis
4c05be0c1b Fix compilation without server and sftp modes
(cherry picked from commit 809b3adeba)
2011-06-09 12:16:07 +02:00
Andreas Schneider
a493a90c59 build: Check for ntohll().
This function is available on AIX.
(cherry picked from commit 640e3830f2)
2011-06-06 18:57:50 +02:00
Andreas Schneider
4a18df8574 string: Added missing include.
(cherry picked from commit 3fa801a929)
2011-06-06 18:57:11 +02:00
Andreas Schneider
cfa74c1dc6 string: Added missing errno.
(cherry picked from commit d536cc4f39)
2011-06-06 18:51:12 +02:00
milo
de706de8c3 Check for NULL pointers in string.c
(cherry picked from commit 4230509e80)
2011-06-06 18:50:11 +02:00
Andreas Schneider
71fa0dc6bb cmake: Fix static .lib overwriting on Windows.
(cherry picked from commit 1880ef54d2)
2011-06-01 14:53:29 +02:00
Andreas Schneider
914a2d8e41 cmake: Prepare for release. 2011-05-30 12:36:54 +02:00
Andreas Schneider
956b64d348 session: Fix return code of ssh_blocking_flush().
(cherry picked from commit 3c21281bf0)
2011-05-28 18:35:21 +02:00
Aris Adamantiadis
91489cd378 remove "0.5.0 is dev" in the doc
(cherry picked from commit 3bc46c3bf0)
2011-05-27 14:20:02 +02:00
Aris Adamantiadis
615bc3b8f7 Forgot a cast to remove warnings
(cherry picked from commit ac167c9077)
2011-05-27 14:19:54 +02:00
Aris Adamantiadis
5b645419fd Fix bug #5, channel_read_nonblocking that blocks 2011-05-27 14:19:42 +02:00
Mark Riordan
c436e07022 Fix memory leak when compression is used
Signed-off-by: Mark Riordan <mriordan@ipswitch.com>
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit dcea8db6b2)
2011-05-27 11:47:26 +02:00
Andreas Schneider
188fb37801 sftp: Reset eof on seek operations.
This fixes bug #48.
(cherry picked from commit c483418b82)
2011-05-26 11:27:35 +02:00
Andreas Schneider
44fed3eb9b misc: Fix compilation on Windows.
(cherry picked from commit ba03388031)
2011-05-26 11:20:25 +02:00
Andreas Schneider
36abd82a7e cmake: Fix detection of clock_gettime. 2011-05-25 22:13:28 +02:00
Aris Adamantiadis
fd6d0b6897 Replace clock_gettime with gettimeofday when missing
(cherry picked from commit 65282841e2)
2011-05-25 22:00:00 +02:00
Aris Adamantiadis
09b0018b93 Introduced ssh_timeout_elapsed functions
Functions to mesure elapsed time before and after a serie of
calls. Introduces a dependancy to clock_gettime() and librt,
hope this doesn't break anything. Porting to gettimeofday() should
not be too hard.
(cherry picked from commit 59f7647cd9)
2011-05-25 21:59:51 +02:00
Andreas Schneider
2624e603d4 Revert "Use BIO* in _privatekey_from_file [Oliver Stöneberg]"
This reverts commit da8356b477.
2011-05-19 19:47:29 +02:00
Oliver Stöneberg
fd61eda16d keyfiles: Move FILE* into HAVE_LIBGCRYPT code.
(cherry picked from commit c7c563eb8ad01ab5750b5ea4e72031ebd298651c)
2011-05-17 21:00:02 +02:00
Oliver Stöneberg
a6dda5fefd keyfiles: Use BIO* in _privatekey_from_file().
(cherry picked from commit 82df5dc2083a6f7234d1545bd671ee1b5b4680b6)
2011-05-17 20:59:55 +02:00
Oliver Stöneberg
da8356b477 Use BIO* in _privatekey_from_file [Oliver Stöneberg]
_privatekey_from_file: moved FILE* into HAVE_LIBGCRYPT code / added missing #ifdef's to default case of switch [Oliver Stöneberg]
2011-05-17 20:57:58 +02:00
Oliver Stöneberg
e5fb20c17b socket: Fixed use-after-free.
When s->callbacks->exception() was called in ssh_socket_pollcallback()
we had a use after free bug.
(cherry picked from commit 9866763789)
2011-05-17 20:57:38 +02:00
Oliver Stöneberg
c472bd7437 keyfiles: Fixed compilation without defines.
This fixes cppcheck issues.
(cherry picked from commit 7f0761885c)
2011-05-17 20:57:38 +02:00
Oliver Stöneberg
8796756ae5 tests: Fixed some cppcheck warnings.
(cherry picked from commit e3311d03db)
2011-05-17 20:57:38 +02:00
Oliver Stöneberg
9c8f285a98 examples: Use the right cleanup functions.
(cherry picked from commit 525324b2f9)
2011-05-17 20:57:38 +02:00
Oliver Stöneberg
8154e24027 channel: Fixed potential use-after-free in ssh_channel_get_exit_status().
If ssh_channel_get_exit_status() is called more than once and the
connection closed.
(cherry picked from commit 4e153aed8a)
2011-05-17 20:57:38 +02:00
Oliver Stöneberg
629cfbccc4 connect: Set timeout on connect
This also fixes error handling in ssh_poll_ctx_dopoll() and
ssh_handle_packets(), so it won't loop forever on an actual timeout.
(cherry picked from commit 671a982739)
2011-05-17 20:57:38 +02:00
Oliver Stöneberg
c5990791db poll: Removed WSAPoll() support.
It was causing too many issues and the poll emulation is quite stable.
(cherry picked from commit f4f4ce37f0)
2011-05-17 20:57:38 +02:00
Oliver Stöneberg
16241938af doc: Small update to auth.c documentation.
(cherry picked from commit 12b61a6266)
2011-05-17 20:57:38 +02:00
Andreas Schneider
6a8cb38dd3 channel: Improve the request signal documentation.
(cherry picked from commit 32cd45612b)
2011-05-15 13:44:11 +02:00
Oliver Stöneberg
bac2227ee2 Updated privatekey_from_file() to use BIO* as well [Oliver Stöneberg] 2011-05-02 19:46:54 +02:00
Oliver Stöneberg
dcb50cc0c8 Use BIO* in _privatekey_from_file [Oliver Stöneberg]
_privatekey_from_file: moved FILE* into HAVE_LIBGCRYPT code / added missing #ifdef's to default case of switch [Oliver Stöneberg]
2011-05-02 19:17:38 +02:00
milo
f503c4a3e1 Delay the check for kbdint->answers in kbdint_send()
(cherry picked from commit 32ba5204b7)
2011-05-02 18:04:56 +02:00
milo
a56c925da9 Fix segfault when ssh_userauth_kbdint_setanswer() has not been called
(cherry picked from commit b6e712e934)
2011-05-02 17:47:00 +02:00
milo
833cc00014 [socket] fix a segfault at disconnect
(cherry picked from commit 7d2064c289)
2011-05-02 17:41:51 +02:00
milo
09e8cf33d7 [messages] don't queue messages if callback present
(cherry picked from commit 1979c14aac)
2011-05-02 17:40:05 +02:00
milo
a03bb2fbf7 [poll] avoid infinite loop in ssh_poll_ctx_free()
(cherry picked from commit 8092541603)
2011-05-02 17:39:28 +02:00
milo
bb784ec6be [channels] Added ssh_channel_window_size() and avoided reentrancy in channel_write_common()
(cherry picked from commit 7ba0938846)
2011-05-02 17:35:34 +02:00
Andreas Schneider
996c00c81c keyfiles: Fixed the build. 2011-05-01 21:04:55 +02:00
Oliver Stöneberg
30bdca07e9 init: Some initialization fixes.
- Check result of ssh_init() in privatekey_from_base64()
- Moved code from ssh_finalize() to appropriate subroutines
- Only initialize sockets once (caused mismatch of WSAStartup() and
  WSACleanup() calls and potential usage of bsd_poll when win_poll
  should be used)
2011-05-01 19:43:57 +02:00
Oliver Stöneberg
b4b49cf3f6 socket: Fixed poll input event.
(cherry picked from commit 040a543f57)
2011-05-01 19:43:01 +02:00
Oliver Stöneberg
189796e94f examples: Removed unnecessary \n from ssh_log() calls in samplessh.
(cherry picked from commit a73459171b)
2011-05-01 19:42:13 +02:00
Oliver Stöneberg
2431c7d925 examples: Fixed memory leak in samplessh when using commands.
(cherry picked from commit c3849a3cfd)
2011-05-01 19:42:01 +02:00
Andreas Schneider
fc9c61714f poll: Fix poll input events.
bug#38
2011-04-15 19:17:40 +02:00
Andreas Schneider
e096658df3 examples: Fix some memory leaks.
(cherry picked from commit 644145a88c)
2011-04-15 19:06:24 +02:00
Andreas Schneider
b1d58c5454 Fix assertion with Visual Studio because of %zu.
(cherry picked from commit ef658b4bef)
2011-04-15 19:03:02 +02:00
Mark Riordan
ced66eb11f scp: Fix potential infinite loop in ssh_scp_close
Signed-off-by: Mark Riordan <mriordan@ipswitch.com>
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 5939cfe78a)
2011-04-14 14:19:15 +02:00
Andreas Schneider
1b44daddf6 examples: Call correct functions on exit.
(cherry picked from commit 3e7d4534ce)
2011-04-14 14:19:08 +02:00
Aris Adamantiadis
a309c1b38e Fixed missing CRYPTO_cleanup_all_ex_data() in ssh_finalize
(cherry picked from commit 934252d6ca)
2011-04-14 13:40:42 +02:00
Andreas Schneider
e56aaf5f44 wrapper: Fixed a possible NULL pointer dereference.
(cherry picked from commit 94e7d345a7)
2011-04-14 10:18:37 +02:00
Andreas Schneider
632cee4426 server: Fixed a possible NULL pointer dereference.
(cherry picked from commit 7e4916cefc)
2011-04-14 10:18:34 +02:00
Oliver Stöneberg
af25fc35d1 build: Fixed some VS2010 problems.
(cherry picked from commit 166ee451c5)
2011-04-11 11:19:26 +02:00
Oliver Stöneberg
db49b84a44 keys: Fixed issues reported by cppcheck.
(cherry picked from commit 46475dfa2f)
2011-04-11 11:19:18 +02:00
Andreas Schneider
c5f4b8c1c7 cmake: Fixed a typo.
(cherry picked from commit 7150cabafa)
2011-04-08 11:06:16 +02:00
Mark Riordan
6a0daddd8f sftp: Fixed double-free in sftp_unlink().
(cherry picked from commit 29bb718a93)
2011-04-08 11:00:04 +02:00
Aris Adamantiadis
af997b221d Fixed doc of ssh_userauth_list()
(cherry picked from commit 1c062b22bf)
2011-03-28 13:36:51 +02:00
Aris Adamantiadis
9d6855702e Change session state after receiving a Disconnect
(cherry picked from commit 4bc9c96e4e)
2011-03-28 13:36:44 +02:00
Andreas Schneider
daf256e15f cpack: Raise version number. 2011-03-23 08:51:06 +01:00
Aris Adamantiadis
0eddcb4424 Fix the ssh_message_retrieve problem by anihilation 2011-03-23 08:49:34 +01:00
Aris Adamantiadis
b7f6794e03 Implement ssh_blocking_flush()
Based on code from Jan Willamowius
(cherry picked from commit dff4e4e6d3)
2011-03-23 08:49:26 +01:00
Andreas Schneider
cd9fc88151 doc: Improve the doc of ssh_bind_set_callbacks.
(cherry picked from commit 7daa81f3aa)
2011-03-09 18:33:49 +01:00
Andreas Schneider
fbe0f37e1b doc: Improved documentation for server options.
(cherry picked from commit 6754c34711)
2011-03-09 18:33:42 +01:00
Andreas Schneider
c496194614 messages: Added missing config.h include. 2011-03-01 14:08:01 +01:00
Andreas Schneider
ca639ceb63 legacy: Added missing channel_write_stderr. 2011-02-23 12:39:25 +01:00
Andreas Schneider
e85537aac4 legacy: Fixed the symbol export. 2011-02-23 12:32:02 +01:00
milo
e839c9cae6 Reverse commit 076dfb82 for the server side
(cherry picked from commit 32e23a25da)
2011-02-19 10:38:15 +01:00
Andreas Schneider
100e94c18e channel: Fixed uninitialized use of session. 2011-02-19 10:24:57 +01:00
Andreas Schneider
e7f7b4e499 server: Fixed logging function name.
(cherry picked from commit ac8276c70e)
2011-02-18 20:57:37 +01:00
Bernhard R. Link
eca8b53868 channel: Improve ssh_channel_open_reverse_forward documentation.
(cherry picked from commit 23b3c46fd6)
2011-02-18 18:01:45 +01:00
Andreas Schneider
b8767be373 channels: set error for new NULL pointer checks
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 8a83990c16)
2011-02-18 18:01:45 +01:00
Bernhard R. Link
9658eade0b socket: Set errors on return.
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 071b0034db)
2011-02-18 17:54:43 +01:00
Bernhard R. Link
689536ec92 channels: Set errors on return.
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 7ae59c571a)
2011-02-18 17:54:34 +01:00
Bernhard R. Link
3ff2999228 bind: Set errors on return.
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit b1db0e54ad)
2011-02-18 17:54:28 +01:00
Andreas Schneider
4f65104ecc misc: Fixed ssh_is_ipaddr_v4() on Windows.
(cherry picked from commit eea1df3574)
2011-02-13 17:39:18 +01:00
Andreas Schneider
242e1c342c build: Try to fix the build on Solaris.
(cherry picked from commit 9baa491b0b)
2011-02-13 17:39:11 +01:00
Andreas Schneider
935e3b70ae misc: Added working ssh_is_ipaddr for Windows.
(cherry picked from commit cd30a1d4b1)
2011-02-13 12:30:52 +01:00
Andreas Schneider
8d1bfb5a85 tests: Fixed misc and isipaddr test on Windows.
(cherry picked from commit ca941d6985)
2011-02-13 12:30:46 +01:00
Andreas Schneider
2ac664968d torture: Fixed torture on Windows.
(cherry picked from commit cbcd5668f5)
2011-02-13 12:30:33 +01:00
Andreas Schneider
1199ad8f47 misc: Fixed ssh_is_ipaddr on FreeBSD.
(cherry picked from commit d1ddec00d9)
2011-02-13 12:30:17 +01:00
Bernhard R. Link
c12559f8f6 always set error when returning error in auth.c
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 637fc7ea59)
2011-02-12 20:15:07 +01:00
Andreas Schneider
840e1abcdc tests: Added ipv6 tests.
(cherry picked from commit 5d4bd5a21d)
2011-02-12 19:22:02 +01:00
Andreas Schneider
e3594ba0ec tests: Fixed torture_isipaddr.
(cherry picked from commit e8c3f55751)
2011-02-12 19:22:02 +01:00
Andreas Schneider
0d07dc5355 srv_sftp: Set error messages in sftp_get_client_message().
(cherry picked from commit 4d38b4c848)
2011-02-12 19:22:01 +01:00
Andreas Schneider
4170258595 connect: Use ssh_is_ipaddr instead of regex.
(cherry picked from commit 768fbdd92e)
2011-02-12 19:22:01 +01:00
Andreas Schneider
dacfc41d21 misc: Added ssh_is_ipaddr() function.
(cherry picked from commit b313fa944a)
2011-02-12 19:22:01 +01:00
Aris Adamantiadis
5158877b72 Connect: Test the new isipaddr() function
(cherry picked from commit 7acc2fa607)
2011-02-12 19:21:42 +01:00
Bernhard R. Link
a785ba3c4d use ssh_log instead of fprintf in ssh_config_parse_file
ssh_config_parse_file calls "fprintf(stderr," directly thus ignoring
a set log callback. Replacing the print with a call to ssh_log should
fix this.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 8d9d46ca66)
2011-02-12 19:21:17 +01:00
Bernhard R. Link
92dbd4eca2 ssh_connect_host_nonblocking returns SSH_EINTR, not E_INTR, so update documentation
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 8e0e4d8fb3)
2011-02-12 19:21:16 +01:00
Bernhard R. Link
a7144c5b6b proper prototypes
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 8b51d29363)
2011-02-12 19:21:16 +01:00
56 changed files with 1315 additions and 396 deletions

View File

@@ -8,7 +8,7 @@ set(APPLICATION_NAME ${PROJECT_NAME})
set(APPLICATION_VERSION_MAJOR "0") set(APPLICATION_VERSION_MAJOR "0")
set(APPLICATION_VERSION_MINOR "5") set(APPLICATION_VERSION_MINOR "5")
set(APPLICATION_VERSION_PATCH "0") set(APPLICATION_VERSION_PATCH "1")
set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}") set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}")
@@ -19,7 +19,7 @@ set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINO
# Increment AGE. Set REVISION to 0 # Increment AGE. Set REVISION to 0
# If the source code was changed, but there were no interface changes: # If the source code was changed, but there were no interface changes:
# Increment REVISION. # Increment REVISION.
set(LIBRARY_VERSION "4.2.0") set(LIBRARY_VERSION "4.2.1")
set(LIBRARY_SOVERSION "4") set(LIBRARY_SOVERSION "4")
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked # where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
@@ -78,9 +78,11 @@ add_subdirectory(src)
# pkg-config file # pkg-config file
configure_file(libssh.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libssh.pc) configure_file(libssh.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libssh.pc)
configure_file(libssh_threads.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libssh_threads.pc)
install( install(
FILES FILES
${CMAKE_CURRENT_BINARY_DIR}/libssh.pc ${CMAKE_CURRENT_BINARY_DIR}/libssh.pc
${CMAKE_CURRENT_BINARY_DIR}/libssh_threads.pc
DESTINATION DESTINATION
${LIB_INSTALL_DIR}/pkgconfig ${LIB_INSTALL_DIR}/pkgconfig
COMPONENT COMPONENT

View File

@@ -12,8 +12,8 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING")
### versions ### versions
set(CPACK_PACKAGE_VERSION_MAJOR "0") set(CPACK_PACKAGE_VERSION_MAJOR "0")
set(CPACK_PACKAGE_VERSION_MINOR "4") set(CPACK_PACKAGE_VERSION_MINOR "5")
set(CPACK_PACKAGE_VERSION_PATCH "90") set(CPACK_PACKAGE_VERSION_PATCH "1")
set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")

View File

@@ -1,7 +1,22 @@
ChangeLog ChangeLog
========== ==========
version 0.5.0 (released xxxx-xx-xx) version 0.5.1 (released 2011-08-09)
* Added checks for NULL pointers in string.c.
* Set the channel max packet size to 32768.
* Don't (de)compress empty buffers.
* Fixed ssh_scp_write so it works when doing recursive copy.
* Fixed another source of endless wait.
* Fixed an endless loop in case of a channel_open error.
* Fixed session timeout handling.
* Fixed ssh_channel_from_local() loop.
* Fixed permissions of scp example when we copy a file.
* Workaround ssh_get_user_home_dir on LDAP users.
* Added pkg-config support for libssh_threads.
* Fixed compilation without server and sftp modes.
* Fix static .lib overwriting on Windows.
version 0.5.0 (released 2011-06-01)
* Added ssh_ prefix to all functions. * Added ssh_ prefix to all functions.
* Added complete Windows support. * Added complete Windows support.
* Added improved server support. * Added improved server support.
@@ -10,6 +25,8 @@ version 0.5.0 (released xxxx-xx-xx)
* Added a multiplatform ssh_getpass() function. * Added a multiplatform ssh_getpass() function.
* Added a tutorial. * Added a tutorial.
* Added a lot of documentation. * Added a lot of documentation.
* Fixed a lot of bugs.
* Fixed several memory leaks.
version 0.4.8 (released 2011-01-15) version 0.4.8 (released 2011-01-15)
* Fixed memory leaks in session signing. * Fixed memory leaks in session signing.

View File

@@ -43,7 +43,8 @@ endif(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW AND NOT OS2)
# HEADER FILES # HEADER FILES
check_include_file(argp.h HAVE_ARGP_H) check_include_file(argp.h HAVE_ARGP_H)
check_include_file(pty.h HAVE_PTY_H) check_include_file(pty.h HAVE_PTY_H)
check_include_file(terminos.h HAVE_TERMIOS_H) check_include_file(termios.h HAVE_TERMIOS_H)
if (WIN32) if (WIN32)
check_include_file(wspiapi.h HAVE_WSPIAPI_H) check_include_file(wspiapi.h HAVE_WSPIAPI_H)
if (NOT HAVE_WSPIAPI_H) if (NOT HAVE_WSPIAPI_H)
@@ -91,23 +92,34 @@ if (UNIX)
if (HAVE_LIBSOCKET) if (HAVE_LIBSOCKET)
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} socket) set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} socket)
endif (HAVE_LIBSOCKET) endif (HAVE_LIBSOCKET)
# libresolv # libresolv
check_library_exists(resolv hstrerror "" HAVE_LIBRESOLV) check_library_exists(resolv hstrerror "" HAVE_LIBRESOLV)
if (HAVE_LIBRESOLV) if (HAVE_LIBRESOLV)
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} resolv) set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} resolv)
endif (HAVE_LIBRESOLV) endif (HAVE_LIBRESOLV)
check_library_exists(rt nanosleep "" HAVE_LIBRT)
# libnsl/inet_pton (Solaris)
check_library_exists(nsl inet_pton "" HAVE_LIBNSL)
if (HAVE_LIBNSL)
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} nsl)
endif (HAVE_LIBNSL)
# librt # librt
if (HAVE_LIBRT) check_library_exists(rt nanosleep "" HAVE_LIBRT)
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} rt)
endif (HAVE_LIBRT)
endif (NOT LINUX) endif (NOT LINUX)
check_library_exists(rt clock_gettime "" HAVE_CLOCK_GETTIME)
if (HAVE_LIBRT OR HAVE_CLOCK_GETTIME)
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} rt)
endif (HAVE_LIBRT OR HAVE_CLOCK_GETTIME)
check_function_exists(getaddrinfo HAVE_GETADDRINFO) check_function_exists(getaddrinfo HAVE_GETADDRINFO)
check_function_exists(poll HAVE_POLL) check_function_exists(poll HAVE_POLL)
check_function_exists(select HAVE_SELECT) check_function_exists(select HAVE_SELECT)
check_function_exists(cfmakeraw HAVE_CFMAKERAW) check_function_exists(cfmakeraw HAVE_CFMAKERAW)
check_function_exists(regcomp HAVE_REGCOMP) check_function_exists(regcomp HAVE_REGCOMP)
check_function_exists(ntohll HAVE_NTOHLL)
endif (UNIX) endif (UNIX)
set(LIBSSH_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} CACHE INTERNAL "libssh required system libraries") set(LIBSSH_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} CACHE INTERNAL "libssh required system libraries")

View File

@@ -77,6 +77,12 @@
/* Define to 1 if you have the `regcomp' function. */ /* Define to 1 if you have the `regcomp' function. */
#cmakedefine HAVE_REGCOMP 1 #cmakedefine HAVE_REGCOMP 1
/* Define to 1 if you have the `clock_gettime' function. */
#cmakedefine HAVE_CLOCK_GETTIME 1
/* Define to 1 if you have the `ntohll' function. */
#cmakedefine HAVE_NTOHLL 1
/*************************** LIBRARIES ***************************/ /*************************** LIBRARIES ***************************/
/* Define to 1 if you have the `crypto' library (-lcrypto). */ /* Define to 1 if you have the `crypto' library (-lcrypto). */

View File

@@ -22,8 +22,8 @@ This tutorial concentrates for its main part on the "client" side of libssh.
To learn how to accept incoming SSH connexions (how to write a SSH server), To learn how to accept incoming SSH connexions (how to write a SSH server),
you'll have to jump to the end of this document. you'll have to jump to the end of this document.
This tutorial describes libssh version 0.5.0. This version is the development This tutorial describes libssh version 0.5.0. This version is a little different
version and is *not* published yet. However, the examples should work with from the 0.4.X series. However, the examples should work with
little changes on versions like 0.4.2 and later. little changes on versions like 0.4.2 and later.

View File

@@ -157,7 +157,7 @@ int authenticate_console(ssh_session session){
banner = ssh_get_issue_banner(session); banner = ssh_get_issue_banner(session);
if (banner) { if (banner) {
printf("%s\n",banner); printf("%s\n",banner);
free(banner); ssh_string_free_char(banner);
} }
return rc; return rc;

View File

@@ -32,22 +32,25 @@ ssh_session connect_ssh(const char *host, const char *user,int verbosity){
if(user != NULL){ if(user != NULL){
if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0) { if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0) {
ssh_disconnect(session); ssh_free(session);
return NULL; return NULL;
} }
} }
if (ssh_options_set(session, SSH_OPTIONS_HOST, host) < 0) { if (ssh_options_set(session, SSH_OPTIONS_HOST, host) < 0) {
ssh_free(session);
return NULL; return NULL;
} }
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity); ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
if(ssh_connect(session)){ if(ssh_connect(session)){
fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session)); fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
ssh_disconnect(session); ssh_disconnect(session);
ssh_free(session);
return NULL; return NULL;
} }
if(verify_knownhost(session)<0){ if(verify_knownhost(session)<0){
ssh_disconnect(session); ssh_disconnect(session);
ssh_free(session);
return NULL; return NULL;
} }
auth=authenticate_console(session); auth=authenticate_console(session);
@@ -59,5 +62,6 @@ ssh_session connect_ssh(const char *host, const char *user,int verbosity){
fprintf(stderr,"Error while authenticating : %s\n",ssh_get_error(session)); fprintf(stderr,"Error while authenticating : %s\n",ssh_get_error(session));
} }
ssh_disconnect(session); ssh_disconnect(session);
ssh_free(session);
return NULL; return NULL;
} }

View File

@@ -13,6 +13,7 @@ int main(void) {
session = connect_ssh("localhost", NULL, 0); session = connect_ssh("localhost", NULL, 0);
if (session == NULL) { if (session == NULL) {
ssh_finalize();
return 1; return 1;
} }
@@ -20,6 +21,7 @@ int main(void) {
if (channel == NULL) { if (channel == NULL) {
ssh_disconnect(session); ssh_disconnect(session);
ssh_free(session); ssh_free(session);
ssh_finalize();
return 1; return 1;
} }
@@ -48,7 +50,9 @@ int main(void) {
ssh_channel_send_eof(channel); ssh_channel_send_eof(channel);
ssh_channel_close(channel); ssh_channel_close(channel);
ssh_channel_free(channel); ssh_channel_free(channel);
ssh_disconnect(session);
ssh_free(session); ssh_free(session);
ssh_finalize();
return 0; return 0;
failed: failed:
@@ -56,6 +60,7 @@ failed:
ssh_channel_free(channel); ssh_channel_free(channel);
ssh_disconnect(session); ssh_disconnect(session);
ssh_free(session); ssh_free(session);
ssh_finalize();
return 1; return 1;
} }

View File

@@ -48,7 +48,7 @@ int verify_knownhost(ssh_session session){
case SSH_SERVER_KNOWN_CHANGED: case SSH_SERVER_KNOWN_CHANGED:
fprintf(stderr,"Host key for server changed : server's one is now :\n"); fprintf(stderr,"Host key for server changed : server's one is now :\n");
ssh_print_hexa("Public key hash",hash, hlen); ssh_print_hexa("Public key hash",hash, hlen);
free(hash); ssh_clean_pubkey_hash(&hash);
fprintf(stderr,"For security reason, connection will be stopped\n"); fprintf(stderr,"For security reason, connection will be stopped\n");
return -1; return -1;
case SSH_SERVER_FOUND_OTHER: case SSH_SERVER_FOUND_OTHER:
@@ -65,20 +65,23 @@ int verify_knownhost(ssh_session session){
hexa = ssh_get_hexa(hash, hlen); hexa = ssh_get_hexa(hash, hlen);
fprintf(stderr,"The server is unknown. Do you trust the host key ?\n"); fprintf(stderr,"The server is unknown. Do you trust the host key ?\n");
fprintf(stderr, "Public key hash: %s\n", hexa); fprintf(stderr, "Public key hash: %s\n", hexa);
free(hexa); ssh_string_free_char(hexa);
if (fgets(buf, sizeof(buf), stdin) == NULL) { if (fgets(buf, sizeof(buf), stdin) == NULL) {
ssh_clean_pubkey_hash(&hash);
return -1; return -1;
} }
if(strncasecmp(buf,"yes",3)!=0){ if(strncasecmp(buf,"yes",3)!=0){
ssh_clean_pubkey_hash(&hash);
return -1; return -1;
} }
fprintf(stderr,"This new key will be written on disk for further usage. do you agree ?\n"); fprintf(stderr,"This new key will be written on disk for further usage. do you agree ?\n");
if (fgets(buf, sizeof(buf), stdin) == NULL) { if (fgets(buf, sizeof(buf), stdin) == NULL) {
ssh_clean_pubkey_hash(&hash);
return -1; return -1;
} }
if(strncasecmp(buf,"yes",3)==0){ if(strncasecmp(buf,"yes",3)==0){
if (ssh_write_knownhost(session) < 0) { if (ssh_write_knownhost(session) < 0) {
free(hash); ssh_clean_pubkey_hash(&hash);
fprintf(stderr, "error %s\n", strerror(errno)); fprintf(stderr, "error %s\n", strerror(errno));
return -1; return -1;
} }
@@ -86,10 +89,10 @@ int verify_knownhost(ssh_session session){
break; break;
case SSH_SERVER_ERROR: case SSH_SERVER_ERROR:
free(hash); ssh_clean_pubkey_hash(&hash);
fprintf(stderr,"%s",ssh_get_error(session)); fprintf(stderr,"%s",ssh_get_error(session));
return -1; return -1;
} }
free(hash); ssh_clean_pubkey_hash(&hash);
return 0; return 0;
} }

View File

@@ -182,7 +182,7 @@ static int do_copy(struct location *src, struct location *dest, int recursive){
fd=fileno(src->file); fd=fileno(src->file);
fstat(fd,&s); fstat(fd,&s);
size=s.st_size; size=s.st_size;
mode = s.st_mode & S_IFMT; mode = s.st_mode & ~S_IFMT;
filename=ssh_basename(src->path); filename=ssh_basename(src->path);
} else { } else {
size=0; size=0;

View File

@@ -16,7 +16,7 @@ program.
#include <libssh/libsshpp.hpp> #include <libssh/libsshpp.hpp>
int main(int argc, const char **argv){ int main(int argc, const char **argv){
ssh::Session session,s2; ssh::Session session;
try { try {
if(argc>1) if(argc>1)
session.setOption(SSH_OPTIONS_HOST,argv[1]); session.setOption(SSH_OPTIONS_HOST,argv[1]);
@@ -24,10 +24,10 @@ int main(int argc, const char **argv){
session.setOption(SSH_OPTIONS_HOST,"localhost"); session.setOption(SSH_OPTIONS_HOST,"localhost");
session.connect(); session.connect();
session.userauthAutopubkey(); session.userauthAutopubkey();
session.disconnect();
} catch (ssh::SshException e){ } catch (ssh::SshException e){
std::cout << "Error during connection : "; std::cout << "Error during connection : ";
std::cout << e.getError() << std::endl; std::cout << e.getError() << std::endl;
} }
//s2=session;
return 0; return 0;
} }

View File

@@ -246,7 +246,7 @@ static void select_loop(ssh_session session,ssh_channel channel){
// we already looked for input from stdin. Now, we are looking for input from the channel // we already looked for input from stdin. Now, we are looking for input from the channel
if(channel && ssh_channel_is_closed(channel)){ if(channel && ssh_channel_is_closed(channel)){
ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",ssh_channel_get_exit_status(channel)); ssh_log(session,SSH_LOG_RARE,"exit-status : %d",ssh_channel_get_exit_status(channel));
ssh_channel_free(channel); ssh_channel_free(channel);
channel=NULL; channel=NULL;
@@ -261,8 +261,8 @@ static void select_loop(ssh_session session,ssh_channel channel){
return; return;
} }
if(lus==0){ if(lus==0){
ssh_log(session,SSH_LOG_RARE,"EOF received\n"); ssh_log(session,SSH_LOG_RARE,"EOF received");
ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",ssh_channel_get_exit_status(channel)); ssh_log(session,SSH_LOG_RARE,"exit-status : %d",ssh_channel_get_exit_status(channel));
ssh_channel_free(channel); ssh_channel_free(channel);
channel=channels[0]=NULL; channel=channels[0]=NULL;
@@ -280,8 +280,8 @@ static void select_loop(ssh_session session,ssh_channel channel){
return; return;
} }
if(lus==0){ if(lus==0){
ssh_log(session,SSH_LOG_RARE,"EOF received\n"); ssh_log(session,SSH_LOG_RARE,"EOF received");
ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",ssh_channel_get_exit_status(channel)); ssh_log(session,SSH_LOG_RARE,"exit-status : %d",ssh_channel_get_exit_status(channel));
ssh_channel_free(channel); ssh_channel_free(channel);
channel=channels[0]=NULL; channel=channels[0]=NULL;
} else } else
@@ -338,7 +338,7 @@ static void select_loop(ssh_session session,ssh_channel channel){
} }
} }
if(channel && ssh_channel_is_closed(channel)){ if(channel && ssh_channel_is_closed(channel)){
ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",ssh_channel_get_exit_status(channel)); ssh_log(session,SSH_LOG_RARE,"exit-status : %d",ssh_channel_get_exit_status(channel));
ssh_channel_free(channel); ssh_channel_free(channel);
channel=NULL; channel=NULL;
@@ -353,8 +353,8 @@ static void select_loop(ssh_session session,ssh_channel channel){
return; return;
} }
if(lus==0){ if(lus==0){
ssh_log(session,SSH_LOG_RARE,"EOF received\n"); ssh_log(session,SSH_LOG_RARE,"EOF received");
ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",ssh_channel_get_exit_status(channel)); ssh_log(session,SSH_LOG_RARE,"exit-status : %d",ssh_channel_get_exit_status(channel));
ssh_channel_free(channel); ssh_channel_free(channel);
channel=channels[0]=NULL; channel=channels[0]=NULL;
@@ -372,8 +372,8 @@ static void select_loop(ssh_session session,ssh_channel channel){
return; return;
} }
if(lus==0){ if(lus==0){
ssh_log(session,SSH_LOG_RARE,"EOF received\n"); ssh_log(session,SSH_LOG_RARE,"EOF received");
ssh_log(session,SSH_LOG_RARE,"exit-status : %d\n",ssh_channel_get_exit_status(channel)); ssh_log(session,SSH_LOG_RARE,"exit-status : %d",ssh_channel_get_exit_status(channel));
ssh_channel_free(channel); ssh_channel_free(channel);
channel=channels[0]=NULL; channel=channels[0]=NULL;
} else } else
@@ -431,8 +431,11 @@ static void batch_shell(ssh_session session){
ssh_channel channel; ssh_channel channel;
char buffer[1024]; char buffer[1024];
int i,s=0; int i,s=0;
for(i=0;i<MAXCMD && cmds[i];++i) for(i=0;i<MAXCMD && cmds[i];++i) {
s+=snprintf(buffer+s,sizeof(buffer)-s,"%s ",cmds[i]); s+=snprintf(buffer+s,sizeof(buffer)-s,"%s ",cmds[i]);
free(cmds[i]);
cmds[i] = NULL;
}
channel=ssh_channel_new(session); channel=ssh_channel_new(session);
ssh_channel_open_session(channel); ssh_channel_open_session(channel);
if(ssh_channel_request_exec(channel,buffer)){ if(ssh_channel_request_exec(channel,buffer)){

View File

@@ -64,16 +64,21 @@ static void create_files(ssh_session session){
} }
if(ssh_channel_open_session(channel) != SSH_OK){ if(ssh_channel_open_session(channel) != SSH_OK){
fprintf(stderr,"Error creating channel: %s\n",ssh_get_error(session)); fprintf(stderr,"Error creating channel: %s\n",ssh_get_error(session));
ssh_channel_free(channel);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if(ssh_channel_request_exec(channel,createcommand) != SSH_OK){ if(ssh_channel_request_exec(channel,createcommand) != SSH_OK){
fprintf(stderr,"Error executing command: %s\n",ssh_get_error(session)); fprintf(stderr,"Error executing command: %s\n",ssh_get_error(session));
ssh_channel_close(channel);
ssh_channel_free(channel);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
while(!ssh_channel_is_eof(channel)){ while(!ssh_channel_is_eof(channel)){
ssh_channel_read(channel,buffer,1,1); ssh_channel_read(channel,buffer,1,1);
if (write(1,buffer,1) < 0) { if (write(1,buffer,1) < 0) {
fprintf(stderr, "Error writing to buffer\n"); fprintf(stderr, "Error writing to buffer\n");
ssh_channel_close(channel);
ssh_channel_free(channel);
return; return;
} }
} }
@@ -91,6 +96,7 @@ static int fetch_files(ssh_session session){
ssh_scp scp=ssh_scp_new(session, SSH_SCP_READ | SSH_SCP_RECURSIVE, "/tmp/libssh_tests/*"); ssh_scp scp=ssh_scp_new(session, SSH_SCP_READ | SSH_SCP_RECURSIVE, "/tmp/libssh_tests/*");
if(ssh_scp_init(scp) != SSH_OK){ if(ssh_scp_init(scp) != SSH_OK){
fprintf(stderr,"error initializing scp: %s\n",ssh_get_error(session)); fprintf(stderr,"error initializing scp: %s\n",ssh_get_error(session));
ssh_scp_free(scp);
return -1; return -1;
} }
printf("Trying to download 3 files (a,b,d) and 1 directory (c)\n"); printf("Trying to download 3 files (a,b,d) and 1 directory (c)\n");
@@ -108,12 +114,16 @@ static int fetch_files(ssh_session session){
r=ssh_scp_read(scp,buffer,sizeof(buffer)); r=ssh_scp_read(scp,buffer,sizeof(buffer));
if(r==SSH_ERROR){ if(r==SSH_ERROR){
fprintf(stderr,"Error reading scp: %s\n",ssh_get_error(session)); fprintf(stderr,"Error reading scp: %s\n",ssh_get_error(session));
ssh_scp_close(scp);
ssh_scp_free(scp);
return -1; return -1;
} }
printf("done\n"); printf("done\n");
break; break;
case SSH_ERROR: case SSH_ERROR:
fprintf(stderr,"Error: %s\n",ssh_get_error(session)); fprintf(stderr,"Error: %s\n",ssh_get_error(session));
ssh_scp_close(scp);
ssh_scp_free(scp);
return -1; return -1;
case SSH_SCP_REQUEST_WARNING: case SSH_SCP_REQUEST_WARNING:
fprintf(stderr,"Warning: %s\n",ssh_scp_request_get_warning(scp)); fprintf(stderr,"Warning: %s\n",ssh_scp_request_get_warning(scp));
@@ -134,6 +144,8 @@ static int fetch_files(ssh_session session){
} }
} while (1); } while (1);
end: end:
ssh_scp_close(scp);
ssh_scp_free(scp);
return 0; return 0;
} }
@@ -147,6 +159,7 @@ int main(int argc, char **argv){
create_files(session); create_files(session);
fetch_files(session); fetch_files(session);
ssh_disconnect(session); ssh_disconnect(session);
ssh_free(session);
ssh_finalize(); ssh_finalize();
return 0; return 0;
} }

View File

@@ -86,7 +86,7 @@ LIBSSH_API ssh_string publickey_from_file(ssh_session session, const char *filen
int *type); int *type);
LIBSSH_API ssh_public_key publickey_from_privatekey(ssh_private_key prv); LIBSSH_API ssh_public_key publickey_from_privatekey(ssh_private_key prv);
LIBSSH_API ssh_string publickey_to_string(ssh_public_key key); LIBSSH_API ssh_string publickey_to_string(ssh_public_key key);
LIBSSH_API ssh_message ssh_message_retrieve(ssh_session session, uint32_t packettype);
LIBSSH_API void string_burn(ssh_string str); LIBSSH_API void string_burn(ssh_string str);
LIBSSH_API ssh_string string_copy(ssh_string str); LIBSSH_API ssh_string string_copy(ssh_string str);
LIBSSH_API void *string_data(ssh_string str); LIBSSH_API void *string_data(ssh_string str);

View File

@@ -79,7 +79,7 @@
/* libssh version */ /* libssh version */
#define LIBSSH_VERSION_MAJOR 0 #define LIBSSH_VERSION_MAJOR 0
#define LIBSSH_VERSION_MINOR 5 #define LIBSSH_VERSION_MINOR 5
#define LIBSSH_VERSION_MICRO 0 #define LIBSSH_VERSION_MICRO 1
#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \ #define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \
LIBSSH_VERSION_MINOR, \ LIBSSH_VERSION_MINOR, \
@@ -323,6 +323,7 @@ enum ssh_scp_request_types {
SSH_SCP_REQUEST_WARNING SSH_SCP_REQUEST_WARNING
}; };
LIBSSH_API int ssh_blocking_flush(ssh_session session, int timeout);
LIBSSH_API ssh_channel ssh_channel_accept_x11(ssh_channel channel, int timeout_ms); LIBSSH_API ssh_channel ssh_channel_accept_x11(ssh_channel channel, int timeout_ms);
LIBSSH_API int ssh_channel_change_pty_size(ssh_channel channel,int cols,int rows); LIBSSH_API int ssh_channel_change_pty_size(ssh_channel channel,int cols,int rows);
LIBSSH_API int ssh_channel_close(ssh_channel channel); LIBSSH_API int ssh_channel_close(ssh_channel channel);
@@ -356,6 +357,7 @@ LIBSSH_API int ssh_channel_select(ssh_channel *readchans, ssh_channel *writechan
timeval * timeout); timeval * timeout);
LIBSSH_API void ssh_channel_set_blocking(ssh_channel channel, int blocking); LIBSSH_API void ssh_channel_set_blocking(ssh_channel channel, int blocking);
LIBSSH_API int ssh_channel_write(ssh_channel channel, const void *data, uint32_t len); LIBSSH_API int ssh_channel_write(ssh_channel channel, const void *data, uint32_t len);
LIBSSH_API uint32_t ssh_channel_window_size(ssh_channel channel);
LIBSSH_API int ssh_try_publickey_from_file(ssh_session session, const char *keyfile, LIBSSH_API int ssh_try_publickey_from_file(ssh_session session, const char *keyfile,
ssh_string *publickey, int *type); ssh_string *publickey, int *type);

View File

@@ -31,6 +31,8 @@ int ssh_file_readaccess_ok(const char *file);
char *ssh_path_expand_tilde(const char *d); char *ssh_path_expand_tilde(const char *d);
char *ssh_path_expand_escape(ssh_session session, const char *s); char *ssh_path_expand_escape(ssh_session session, const char *s);
int ssh_analyze_banner(ssh_session session, int server, int *ssh1, int *ssh2); int ssh_analyze_banner(ssh_session session, int server, int *ssh1, int *ssh2);
int ssh_is_ipaddr_v4(const char *str);
int ssh_is_ipaddr(const char *str);
/* macro for byte ordering */ /* macro for byte ordering */
uint64_t ntohll(uint64_t); uint64_t ntohll(uint64_t);
@@ -48,6 +50,11 @@ struct ssh_iterator {
const void *data; const void *data;
}; };
struct ssh_timestamp {
long seconds;
long useconds;
};
struct ssh_list *ssh_list_new(void); struct ssh_list *ssh_list_new(void);
void ssh_list_free(struct ssh_list *list); void ssh_list_free(struct ssh_list *list);
struct ssh_iterator *ssh_list_get_iterator(const struct ssh_list *list); struct ssh_iterator *ssh_list_get_iterator(const struct ssh_list *list);
@@ -70,4 +77,8 @@ const void *_ssh_list_pop_head(struct ssh_list *list);
#define ssh_list_pop_head(type, ssh_list)\ #define ssh_list_pop_head(type, ssh_list)\
((type)_ssh_list_pop_head(ssh_list)) ((type)_ssh_list_pop_head(ssh_list))
void ssh_timestamp_init(struct ssh_timestamp *ts);
int ssh_timeout_elapsed(struct ssh_timestamp *ts, int timeout);
int ssh_timeout_update(struct ssh_timestamp *ts, int timeout);
#endif /* MISC_H_ */ #endif /* MISC_H_ */

View File

@@ -172,8 +172,6 @@ void ssh_packet_set_callbacks(ssh_session session, ssh_packet_callbacks callback
void ssh_packet_set_default_callbacks(ssh_session session); void ssh_packet_set_default_callbacks(ssh_session session);
void ssh_packet_process(ssh_session session, uint8_t type); void ssh_packet_process(ssh_session session, uint8_t type);
/* connect.c */ /* connect.c */
int ssh_regex_init(void);
void ssh_regex_finalize(void);
socket_t ssh_connect_host(ssh_session session, const char *host,const char socket_t ssh_connect_host(ssh_session session, const char *host,const char
*bind_addr, int port, long timeout, long usec); *bind_addr, int port, long timeout, long usec);
socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host, socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,

View File

@@ -87,10 +87,63 @@ LIBSSH_API ssh_bind ssh_bind_new(void);
* *
* @param sshbind The ssh server bind to configure. * @param sshbind The ssh server bind to configure.
* *
* @param type Option to set up. * @param type The option type to set. This could be one of the
* @param value Value to set. * following:
* @returns SSH_OK No error. *
* @returns SSH_ERROR Invalid option or parameter. * - SSH_BIND_OPTIONS_BINDADDR
* The ip address to bind (const char *).
*
* - SSH_BIND_OPTIONS_BINDPORT
* The port to bind (unsigned int).
*
* - SSH_BIND_OPTIONS_BINDPORT_STR
* The port to bind (const char *).
*
* - SSH_BIND_OPTIONS_HOSTKEY
* This specifies the file containing the private host key used
* by SSHv1. (const char *).
*
* - SSH_BIND_OPTIONS_DSAKEY
* This specifies the file containing the private host dsa key
* used by SSHv2. (const char *).
*
* - SSH_BIND_OPTIONS_RSAKEY
* This specifies the file containing the private host dsa key
* used by SSHv2. (const char *).
*
* - SSH_BIND_OPTIONS_BANNER
* That the server banner (version string) for SSH.
* (const char *).
*
* - SSH_BIND_OPTIONS_LOG_VERBOSITY
* Set the session logging verbosity (int).\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_BIND_OPTIONS_LOG_VERBOSITY_STR
* Set the session logging verbosity (const char *).\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
* \n
* See the corresponding numbers in libssh.h.
*
* @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.
*
* @returns SSH_OK on success, SSH_ERROR on invalid option or parameter.
*/ */
LIBSSH_API int ssh_bind_options_set(ssh_bind sshbind, LIBSSH_API int ssh_bind_options_set(ssh_bind sshbind,
enum ssh_bind_options_e type, const void *value); enum ssh_bind_options_e type, const void *value);
@@ -104,6 +157,26 @@ LIBSSH_API int ssh_bind_options_set(ssh_bind sshbind,
*/ */
LIBSSH_API int ssh_bind_listen(ssh_bind ssh_bind_o); LIBSSH_API int ssh_bind_listen(ssh_bind ssh_bind_o);
/**
* @brief Set the callback for this bind.
*
* @param[in] sshbind The bind to set the callback on.
*
* @param[in] callbacks An already set up ssh_bind_callbacks instance.
*
* @param[in] userdata A pointer to private data to pass to the callbacks.
*
* @return SSH_OK on success, SSH_ERROR if an error occured.
*
* @code
* struct ssh_callbacks_struct cb = {
* .userdata = data,
* .auth_function = my_auth_function
* };
* ssh_callbacks_init(&cb);
* ssh_bind_set_callbacks(session, &cb);
* @endcode
*/
LIBSSH_API int ssh_bind_set_callbacks(ssh_bind sshbind, ssh_bind_callbacks callbacks, LIBSSH_API int ssh_bind_set_callbacks(ssh_bind sshbind, ssh_bind_callbacks callbacks,
void *userdata); void *userdata);
@@ -230,6 +303,8 @@ LIBSSH_API int ssh_channel_write_stderr(ssh_channel channel,
/* deprecated functions */ /* deprecated functions */
SSH_DEPRECATED LIBSSH_API int ssh_accept(ssh_session session); SSH_DEPRECATED LIBSSH_API int ssh_accept(ssh_session session);
SSH_DEPRECATED LIBSSH_API int channel_write_stderr(ssh_channel channel,
const void *data, uint32_t len);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -53,6 +53,7 @@ void ssh_socket_set_write_wontblock(ssh_socket s);
void ssh_socket_set_read_wontblock(ssh_socket s); void ssh_socket_set_read_wontblock(ssh_socket s);
void ssh_socket_set_except(ssh_socket s); void ssh_socket_set_except(ssh_socket s);
int ssh_socket_get_status(ssh_socket s); int ssh_socket_get_status(ssh_socket s);
int ssh_socket_buffered_write_bytes(ssh_socket s);
int ssh_socket_data_available(ssh_socket s); int ssh_socket_data_available(ssh_socket s);
int ssh_socket_data_writable(ssh_socket s); int ssh_socket_data_writable(ssh_socket s);

5
libssh_threads.pc.cmake Normal file
View File

@@ -0,0 +1,5 @@
Name: ${APPLICATION_NAME}_threads
Description: The SSH Library Thread Extension
Version: ${APPLICATION_VERSION}
Libs: -L${LIB_INSTALL_DIR} -lssh_threads
Cflags: -I${INCLUDE_INSTALL_DIR}

View File

@@ -184,6 +184,11 @@ install(
if (WITH_STATIC_LIB) if (WITH_STATIC_LIB)
add_library(${LIBSSH_STATIC_LIBRARY} STATIC ${libssh_SRCS}) add_library(${LIBSSH_STATIC_LIBRARY} STATIC ${libssh_SRCS})
if (MSVC)
set(OUTPUT_SUFFIX static)
else (MSVC)
set(OUTPUT_SUFFIX )
endif (MSVC)
set_target_properties( set_target_properties(
${LIBSSH_STATIC_LIBRARY} ${LIBSSH_STATIC_LIBRARY}
PROPERTIES PROPERTIES
@@ -193,6 +198,8 @@ if (WITH_STATIC_LIB)
${LIBRARY_SOVERSION} ${LIBRARY_SOVERSION}
OUTPUT_NAME OUTPUT_NAME
ssh ssh
ARCHIVE_OUTPUT_DIRECTORY
${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_SUFFIX}
) )
if (WIN32) if (WIN32)
@@ -208,7 +215,7 @@ if (WITH_STATIC_LIB)
TARGETS TARGETS
${LIBSSH_STATIC_LIBRARY} ${LIBSSH_STATIC_LIBRARY}
DESTINATION DESTINATION
${LIB_INSTALL_DIR} ${LIB_INSTALL_DIR}/${OUTPUT_SUFFIX}
COMPONENT COMPONENT
libraries libraries
) )

View File

@@ -62,23 +62,23 @@
* again is necessary * again is necessary
*/ */
static int ask_userauth(ssh_session session) { static int ask_userauth(ssh_session session) {
int rc = 0; int rc = 0;
enter_function(); enter_function();
do { do {
rc=ssh_service_request(session,"ssh-userauth"); rc = ssh_service_request(session,"ssh-userauth");
if(ssh_is_blocking(session)){ if (ssh_is_blocking(session)) {
if(rc==SSH_AGAIN) if(rc == SSH_AGAIN)
ssh_handle_packets(session,-1); ssh_handle_packets(session, -2);
} else { } else {
/* nonblocking */ /* nonblocking */
ssh_handle_packets(session,0); ssh_handle_packets(session, 0);
rc=ssh_service_request(session,"ssh-userauth"); rc = ssh_service_request(session, "ssh-userauth");
break; break;
} }
} while(rc==SSH_AGAIN); } while (rc == SSH_AGAIN);
leave_function(); leave_function();
return rc; return rc;
} }
/** /**
@@ -254,7 +254,7 @@ static int wait_auth_status(ssh_session session) {
enter_function(); enter_function();
if(ssh_is_blocking(session)){ if(ssh_is_blocking(session)){
if(ssh_handle_packets_termination(session,-1,auth_status_termination, if(ssh_handle_packets_termination(session, -2, auth_status_termination,
session) == SSH_ERROR){ session) == SSH_ERROR){
leave_function(); leave_function();
return SSH_AUTH_ERROR; return SSH_AUTH_ERROR;
@@ -308,7 +308,7 @@ int ssh_auth_list(ssh_session session) {
/** /**
* @brief retrieves available authentication methods for this session * @brief retrieves available authentication methods for this session
* @param[in] session the SSH session * @param[in] session the SSH session
* @param[in] username set to NULL * @param[in] username Deprecated, set to NULL.
* @returns A bitfield of values SSH_AUTH_METHOD_NONE, SSH_AUTH_METHOD_PASSWORD, * @returns A bitfield of values SSH_AUTH_METHOD_NONE, SSH_AUTH_METHOD_PASSWORD,
SSH_AUTH_METHOD_PUBLICKEY, SSH_AUTH_METHOD_HOSTBASED, SSH_AUTH_METHOD_PUBLICKEY, SSH_AUTH_METHOD_HOSTBASED,
SSH_AUTH_METHOD_INTERACTIVE. SSH_AUTH_METHOD_INTERACTIVE.
@@ -345,7 +345,7 @@ int ssh_userauth_list(ssh_session session, const char *username) {
* SSH_AUTH_DENIED: Authentication failed: use another method\n * SSH_AUTH_DENIED: Authentication failed: use another method\n
* SSH_AUTH_PARTIAL: You've been partially authenticated, you still * SSH_AUTH_PARTIAL: You've been partially authenticated, you still
* have to use another method\n * have to use another method\n
* SSH_AUTH_SUCCESS: Authentication success * SSH_AUTH_SUCCESS: Authentication success\n
* SSH_AUTH_AGAIN: In nonblocking mode, you've got to call this again * SSH_AUTH_AGAIN: In nonblocking mode, you've got to call this again
* later. * later.
*/ */
@@ -384,6 +384,7 @@ int ssh_userauth_none(ssh_session session, const char *username) {
} }
if (user == NULL) { if (user == NULL) {
ssh_set_error_oom(session);
leave_function(); leave_function();
return rc; return rc;
} }
@@ -415,10 +416,12 @@ int ssh_userauth_none(ssh_session session, const char *username) {
method = ssh_string_from_char("none"); method = ssh_string_from_char("none");
if (method == NULL) { if (method == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
service = ssh_string_from_char("ssh-connection"); service = ssh_string_from_char("ssh-connection");
if (service == NULL) { if (service == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
@@ -519,6 +522,7 @@ int ssh_userauth_offer_pubkey(ssh_session session, const char *username,
} }
if (user == NULL) { if (user == NULL) {
ssh_set_error_oom(session);
leave_function(); leave_function();
return rc; return rc;
} }
@@ -531,14 +535,17 @@ int ssh_userauth_offer_pubkey(ssh_session session, const char *username,
service = ssh_string_from_char("ssh-connection"); service = ssh_string_from_char("ssh-connection");
if (service == NULL) { if (service == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
method = ssh_string_from_char("publickey"); method = ssh_string_from_char("publickey");
if (method == NULL) { if (method == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
algo = ssh_string_from_char(ssh_type_to_char(type)); algo = ssh_string_from_char(ssh_type_to_char(type));
if (algo == NULL) { if (algo == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
@@ -549,6 +556,7 @@ int ssh_userauth_offer_pubkey(ssh_session session, const char *username,
buffer_add_u8(session->out_buffer, 0) < 0 || buffer_add_u8(session->out_buffer, 0) < 0 ||
buffer_add_ssh_string(session->out_buffer, algo) < 0 || buffer_add_ssh_string(session->out_buffer, algo) < 0 ||
buffer_add_ssh_string(session->out_buffer, publickey) < 0) { buffer_add_ssh_string(session->out_buffer, publickey) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
@@ -640,6 +648,7 @@ int ssh_userauth_pubkey(ssh_session session, const char *username,
} }
if (user == NULL) { if (user == NULL) {
ssh_set_error_oom(session);
leave_function(); leave_function();
return rc; return rc;
} }
@@ -652,24 +661,32 @@ int ssh_userauth_pubkey(ssh_session session, const char *username,
service = ssh_string_from_char("ssh-connection"); service = ssh_string_from_char("ssh-connection");
if (service == NULL) { if (service == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
method = ssh_string_from_char("publickey"); method = ssh_string_from_char("publickey");
if (method == NULL) { if (method == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
algo = ssh_string_from_char(ssh_type_to_char(privatekey->type)); algo = ssh_string_from_char(ssh_type_to_char(privatekey->type));
if (algo == NULL) { if (algo == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
if (publickey == NULL) { if (publickey == NULL) {
pk = publickey_from_privatekey(privatekey); pk = publickey_from_privatekey(privatekey);
if (pk == NULL) { if (pk == NULL) {
/* most likely oom, and publickey_from_privatekey does not
* return any more information */
ssh_set_error_oom(session);
goto error; goto error;
} }
pkstr = publickey_to_string(pk); pkstr = publickey_to_string(pk);
publickey_free(pk); publickey_free(pk);
if (pkstr == NULL) { if (pkstr == NULL) {
/* same as above */
ssh_set_error_oom(session);
goto error; goto error;
} }
} }
@@ -682,6 +699,7 @@ int ssh_userauth_pubkey(ssh_session session, const char *username,
buffer_add_u8(session->out_buffer, 1) < 0 || buffer_add_u8(session->out_buffer, 1) < 0 ||
buffer_add_ssh_string(session->out_buffer, algo) < 0 || buffer_add_ssh_string(session->out_buffer, algo) < 0 ||
buffer_add_ssh_string(session->out_buffer, (publickey == NULL ? pkstr : publickey)) < 0) { buffer_add_ssh_string(session->out_buffer, (publickey == NULL ? pkstr : publickey)) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
@@ -694,6 +712,7 @@ int ssh_userauth_pubkey(ssh_session session, const char *username,
sign = ssh_do_sign(session,session->out_buffer, privatekey); sign = ssh_do_sign(session,session->out_buffer, privatekey);
if (sign) { if (sign) {
if (buffer_add_ssh_string(session->out_buffer,sign) < 0) { if (buffer_add_ssh_string(session->out_buffer,sign) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
ssh_string_free(sign); ssh_string_free(sign);
@@ -737,7 +756,9 @@ error:
* SSH_AUTH_DENIED: Authentication failed: use another method.\n * SSH_AUTH_DENIED: Authentication failed: use another method.\n
* SSH_AUTH_PARTIAL: You've been partially authenticated, you still * SSH_AUTH_PARTIAL: You've been partially authenticated, you still
* have to use another method.\n * have to use another method.\n
* SSH_AUTH_SUCCESS: Authentication successful. * SSH_AUTH_SUCCESS: Authentication successful.\n
* SSH_AUTH_AGAIN: In nonblocking mode, you've got to call this again
* later.
* *
* @see publickey_from_file() * @see publickey_from_file()
* @see privatekey_from_file() * @see privatekey_from_file()
@@ -756,6 +777,7 @@ int ssh_userauth_privatekey_file(ssh_session session, const char *username,
pubkeyfile = malloc(strlen(filename) + 1 + 4); pubkeyfile = malloc(strlen(filename) + 1 + 4);
if (pubkeyfile == NULL) { if (pubkeyfile == NULL) {
ssh_set_error_oom(session);
leave_function(); leave_function();
return SSH_AUTH_ERROR; return SSH_AUTH_ERROR;
} }
@@ -837,6 +859,7 @@ int ssh_userauth_agent_pubkey(ssh_session session, const char *username,
} }
if (user == NULL) { if (user == NULL) {
ssh_set_error_oom(session);
leave_function(); leave_function();
return rc; return rc;
} }
@@ -849,18 +872,22 @@ int ssh_userauth_agent_pubkey(ssh_session session, const char *username,
service = ssh_string_from_char("ssh-connection"); service = ssh_string_from_char("ssh-connection");
if (service == NULL) { if (service == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
method = ssh_string_from_char("publickey"); method = ssh_string_from_char("publickey");
if (method == NULL) { if (method == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
algo = ssh_string_from_char(ssh_type_to_char(publickey->type)); algo = ssh_string_from_char(ssh_type_to_char(publickey->type));
if (algo == NULL) { if (algo == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
key = publickey_to_string(publickey); key = publickey_to_string(publickey);
if (key == NULL) { if (key == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
@@ -872,6 +899,7 @@ int ssh_userauth_agent_pubkey(ssh_session session, const char *username,
buffer_add_u8(session->out_buffer, 1) < 0 || buffer_add_u8(session->out_buffer, 1) < 0 ||
buffer_add_ssh_string(session->out_buffer, algo) < 0 || buffer_add_ssh_string(session->out_buffer, algo) < 0 ||
buffer_add_ssh_string(session->out_buffer, key) < 0) { buffer_add_ssh_string(session->out_buffer, key) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
@@ -879,6 +907,7 @@ int ssh_userauth_agent_pubkey(ssh_session session, const char *username,
if (sign) { if (sign) {
if (buffer_add_ssh_string(session->out_buffer, sign) < 0) { if (buffer_add_ssh_string(session->out_buffer, sign) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
ssh_string_free(sign); ssh_string_free(sign);
@@ -929,7 +958,7 @@ error:
* SSH_AUTH_DENIED: Authentication failed: use another method.\n * SSH_AUTH_DENIED: Authentication failed: use another method.\n
* SSH_AUTH_PARTIAL: You've been partially authenticated, you still * SSH_AUTH_PARTIAL: You've been partially authenticated, you still
* have to use another method.\n * have to use another method.\n
* SSH_AUTH_SUCCESS: Authentication successful. * SSH_AUTH_SUCCESS: Authentication successful.\n
* SSH_AUTH_AGAIN: In nonblocking mode, you've got to call this again * SSH_AUTH_AGAIN: In nonblocking mode, you've got to call this again
* later. * later.
* *
@@ -968,6 +997,7 @@ int ssh_userauth_password(ssh_session session, const char *username,
} }
if (user == NULL) { if (user == NULL) {
ssh_set_error_oom(session);
leave_function(); leave_function();
return rc; return rc;
} }
@@ -1000,14 +1030,17 @@ int ssh_userauth_password(ssh_session session, const char *username,
service = ssh_string_from_char("ssh-connection"); service = ssh_string_from_char("ssh-connection");
if (service == NULL) { if (service == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
method = ssh_string_from_char("password"); method = ssh_string_from_char("password");
if (method == NULL) { if (method == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
pwd = ssh_string_from_char(password); pwd = ssh_string_from_char(password);
if (pwd == NULL) { if (pwd == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
@@ -1017,6 +1050,7 @@ int ssh_userauth_password(ssh_session session, const char *username,
buffer_add_ssh_string(session->out_buffer, method) < 0 || buffer_add_ssh_string(session->out_buffer, method) < 0 ||
buffer_add_u8(session->out_buffer, 0) < 0 || buffer_add_u8(session->out_buffer, 0) < 0 ||
buffer_add_ssh_string(session->out_buffer, pwd) < 0) { buffer_add_ssh_string(session->out_buffer, pwd) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
@@ -1374,18 +1408,22 @@ static int kbdauth_init(ssh_session session, const char *user,
usr = ssh_string_from_char(user); usr = ssh_string_from_char(user);
if (usr == NULL) { if (usr == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
sub = (submethods ? ssh_string_from_char(submethods) : ssh_string_from_char("")); sub = (submethods ? ssh_string_from_char(submethods) : ssh_string_from_char(""));
if (sub == NULL) { if (sub == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
service = ssh_string_from_char("ssh-connection"); service = ssh_string_from_char("ssh-connection");
if (service == NULL) { if (service == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
method = ssh_string_from_char("keyboard-interactive"); method = ssh_string_from_char("keyboard-interactive");
if (method == NULL) { if (method == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
@@ -1395,6 +1433,7 @@ static int kbdauth_init(ssh_session session, const char *user,
buffer_add_ssh_string(session->out_buffer, method) < 0 || buffer_add_ssh_string(session->out_buffer, method) < 0 ||
buffer_add_u32(session->out_buffer, 0) < 0 || buffer_add_u32(session->out_buffer, 0) < 0 ||
buffer_add_ssh_string(session->out_buffer, sub) < 0) { buffer_add_ssh_string(session->out_buffer, sub) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
@@ -1562,23 +1601,30 @@ static int kbdauth_send(ssh_session session) {
enter_function(); enter_function();
if(session==NULL || session->kbdint == NULL) {
return rc;
}
if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_INFO_RESPONSE) < 0 || if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_INFO_RESPONSE) < 0 ||
buffer_add_u32(session->out_buffer, buffer_add_u32(session->out_buffer,
htonl(session->kbdint->nprompts)) < 0) { htonl(session->kbdint->nprompts)) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
for (i = 0; i < session->kbdint->nprompts; i++) { for (i = 0; i < session->kbdint->nprompts; i++) {
if (session->kbdint->answers[i]) { if (session->kbdint->answers && session->kbdint->answers[i]) {
answer = ssh_string_from_char(session->kbdint->answers[i]); answer = ssh_string_from_char(session->kbdint->answers[i]);
} else { } else {
answer = ssh_string_from_char(""); answer = ssh_string_from_char("");
} }
if (answer == NULL) { if (answer == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
if (buffer_add_ssh_string(session->out_buffer, answer) < 0) { if (buffer_add_ssh_string(session->out_buffer, answer) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
@@ -1622,7 +1668,9 @@ error:
* have to use another method\n * have to use another method\n
* SSH_AUTH_SUCCESS: Authentication success\n * SSH_AUTH_SUCCESS: Authentication success\n
* SSH_AUTH_INFO: The server asked some questions. Use * SSH_AUTH_INFO: The server asked some questions. Use
* ssh_userauth_kbdint_getnprompts() and such. * ssh_userauth_kbdint_getnprompts() and such.\n
* SSH_AUTH_AGAIN: In nonblocking mode, you've got to call this again
* later.
* *
* @see ssh_userauth_kbdint_getnprompts() * @see ssh_userauth_kbdint_getnprompts()
* @see ssh_userauth_kbdint_getname() * @see ssh_userauth_kbdint_getname()
@@ -1635,7 +1683,7 @@ int ssh_userauth_kbdint(ssh_session session, const char *user,
int rc = SSH_AUTH_ERROR; int rc = SSH_AUTH_ERROR;
if (session->version == 1) { if (session->version == 1) {
/* No keyb-interactive for ssh1 */ ssh_set_error(session, SSH_NO_ERROR, "No keyboard-interactive for ssh1");
return SSH_AUTH_DENIED; return SSH_AUTH_DENIED;
} }
@@ -1688,8 +1736,12 @@ int ssh_userauth_kbdint(ssh_session session, const char *user,
* @returns The number of prompts. * @returns The number of prompts.
*/ */
int ssh_userauth_kbdint_getnprompts(ssh_session session) { int ssh_userauth_kbdint_getnprompts(ssh_session session) {
if(session==NULL || session->kbdint == NULL) if(session==NULL)
return SSH_ERROR; return SSH_ERROR;
if(session->kbdint == NULL) {
ssh_set_error_invalid(session, __FUNCTION__);
return SSH_ERROR;
}
return session->kbdint->nprompts; return session->kbdint->nprompts;
} }
@@ -1704,8 +1756,12 @@ int ssh_userauth_kbdint_getnprompts(ssh_session session) {
* @returns The name of the message block. Do not free it. * @returns The name of the message block. Do not free it.
*/ */
const char *ssh_userauth_kbdint_getname(ssh_session session) { const char *ssh_userauth_kbdint_getname(ssh_session session) {
if(session==NULL || session->kbdint == NULL) if(session==NULL)
return NULL; return NULL;
if(session->kbdint == NULL) {
ssh_set_error_invalid(session, __FUNCTION__);
return NULL;
}
return session->kbdint->name; return session->kbdint->name;
} }
@@ -1721,8 +1777,12 @@ const char *ssh_userauth_kbdint_getname(ssh_session session) {
*/ */
const char *ssh_userauth_kbdint_getinstruction(ssh_session session) { const char *ssh_userauth_kbdint_getinstruction(ssh_session session) {
if(session==NULL || session->kbdint == NULL) if(session==NULL)
return NULL; return NULL;
if(session->kbdint == NULL) {
ssh_set_error_invalid(session, __FUNCTION__);
return NULL;
}
return session->kbdint->instruction; return session->kbdint->instruction;
} }
@@ -1744,9 +1804,14 @@ const char *ssh_userauth_kbdint_getinstruction(ssh_session session) {
*/ */
const char *ssh_userauth_kbdint_getprompt(ssh_session session, unsigned int i, const char *ssh_userauth_kbdint_getprompt(ssh_session session, unsigned int i,
char *echo) { char *echo) {
if(session==NULL || session->kbdint == NULL) if(session==NULL)
return NULL; return NULL;
if (i > session->kbdint->nprompts) { if(session->kbdint == NULL) {
ssh_set_error_invalid(session, __FUNCTION__);
return NULL;
}
if (i > session->kbdint->nprompts) {
ssh_set_error_invalid(session, __FUNCTION__);
return NULL; return NULL;
} }
@@ -1773,14 +1838,18 @@ const char *ssh_userauth_kbdint_getprompt(ssh_session session, unsigned int i,
*/ */
int ssh_userauth_kbdint_setanswer(ssh_session session, unsigned int i, int ssh_userauth_kbdint_setanswer(ssh_session session, unsigned int i,
const char *answer) { const char *answer) {
if (session == NULL || answer == NULL || session->kbdint == NULL || if (session == NULL)
return -1;
if (answer == NULL || session->kbdint == NULL ||
i > session->kbdint->nprompts) { i > session->kbdint->nprompts) {
ssh_set_error_invalid(session, __FUNCTION__);
return -1; return -1;
} }
if (session->kbdint->answers == NULL) { if (session->kbdint->answers == NULL) {
session->kbdint->answers = malloc(sizeof(char*) * session->kbdint->nprompts); session->kbdint->answers = malloc(sizeof(char*) * session->kbdint->nprompts);
if (session->kbdint->answers == NULL) { if (session->kbdint->answers == NULL) {
ssh_set_error_oom(session);
return -1; return -1;
} }
memset(session->kbdint->answers, 0, sizeof(char *) * session->kbdint->nprompts); memset(session->kbdint->answers, 0, sizeof(char *) * session->kbdint->nprompts);
@@ -1793,6 +1862,7 @@ int ssh_userauth_kbdint_setanswer(ssh_session session, unsigned int i,
session->kbdint->answers[i] = strdup(answer); session->kbdint->answers[i] = strdup(answer);
if (session->kbdint->answers[i] == NULL) { if (session->kbdint->answers[i] == NULL) {
ssh_set_error_oom(session);
return -1; return -1;
} }

View File

@@ -38,7 +38,7 @@ static int wait_auth1_status(ssh_session session) {
enter_function(); enter_function();
/* wait for a packet */ /* wait for a packet */
while(session->auth_state == SSH_AUTH_STATE_NONE) while(session->auth_state == SSH_AUTH_STATE_NONE)
if (ssh_handle_packets(session,-1) != SSH_OK) if (ssh_handle_packets(session, -2) != SSH_OK)
break; break;
ssh_log(session,SSH_LOG_PROTOCOL,"Auth state : %d",session->auth_state); ssh_log(session,SSH_LOG_PROTOCOL,"Auth state : %d",session->auth_state);
leave_function(); leave_function();

View File

@@ -160,6 +160,7 @@ int ssh_bind_listen(ssh_bind sshbind) {
socket_t fd; socket_t fd;
if (ssh_init() < 0) { if (ssh_init() < 0) {
ssh_set_error(sshbind, SSH_FATAL, "ssh_init() failed");
return -1; return -1;
} }
@@ -185,28 +186,13 @@ int ssh_bind_listen(ssh_bind sshbind) {
return 0; return 0;
} }
/**
* @brief set the bind callbacks for ssh_bind
* @code
* struct ssh_callbacks_struct cb = {
* .userdata = data,
* .auth_function = my_auth_function
* };
* ssh_callbacks_init(&cb);
* ssh_set_callbacks(session, &cb);
* @endcode
* @param sshbind the ssh_bind structure to set
* @param callbacks a ssh_bind_callbacks instance already set up. Do
* use ssh_callbacks_init() to initialize it.
* @param userdata userdata to be used with each callback called
* within callbacks.
* @returns SSH_OK on success,
* SSH_ERROR on error.
*/
int ssh_bind_set_callbacks(ssh_bind sshbind, ssh_bind_callbacks callbacks, int ssh_bind_set_callbacks(ssh_bind sshbind, ssh_bind_callbacks callbacks,
void *userdata){ void *userdata){
if (sshbind == NULL || callbacks == NULL) { if (sshbind == NULL) {
return SSH_ERROR;
}
if (callbacks == NULL) {
ssh_set_error_invalid(sshbind, __FUNCTION__);
return SSH_ERROR; return SSH_ERROR;
} }
if(callbacks->size <= 0 || callbacks->size > 1024 * sizeof(void *)){ if(callbacks->size <= 0 || callbacks->size > 1024 * sizeof(void *)){
@@ -378,6 +364,8 @@ int ssh_bind_accept(ssh_bind sshbind, ssh_session session) {
ssh_socket_free(session->socket); ssh_socket_free(session->socket);
session->socket = ssh_socket_new(session); session->socket = ssh_socket_new(session);
if (session->socket == NULL) { if (session->socket == NULL) {
/* perhaps it may be better to copy the error from session to sshbind */
ssh_set_error_oom(sshbind);
privatekey_free(dsa); privatekey_free(dsa);
privatekey_free(rsa); privatekey_free(rsa);
return SSH_ERROR; return SSH_ERROR;

View File

@@ -48,6 +48,14 @@
#define WINDOWBASE 128000 #define WINDOWBASE 128000
#define WINDOWLIMIT (WINDOWBASE/2) #define WINDOWLIMIT (WINDOWBASE/2)
/*
* All implementations MUST be able to process packets with an
* uncompressed payload length of 32768 bytes or less and a total packet
* size of 35000 bytes or less.
*/
#define CHANNEL_MAX_PACKET 32768
#define CHANNEL_INITIAL_WINDOW 64000
/** /**
* @defgroup libssh_channel The SSH channel functions * @defgroup libssh_channel The SSH channel functions
* @ingroup libssh * @ingroup libssh
@@ -71,18 +79,21 @@ ssh_channel ssh_channel_new(ssh_session session) {
channel = malloc(sizeof(struct ssh_channel_struct)); channel = malloc(sizeof(struct ssh_channel_struct));
if (channel == NULL) { if (channel == NULL) {
ssh_set_error_oom(session);
return NULL; return NULL;
} }
memset(channel,0,sizeof(struct ssh_channel_struct)); memset(channel,0,sizeof(struct ssh_channel_struct));
channel->stdout_buffer = ssh_buffer_new(); channel->stdout_buffer = ssh_buffer_new();
if (channel->stdout_buffer == NULL) { if (channel->stdout_buffer == NULL) {
ssh_set_error_oom(session);
SAFE_FREE(channel); SAFE_FREE(channel);
return NULL; return NULL;
} }
channel->stderr_buffer = ssh_buffer_new(); channel->stderr_buffer = ssh_buffer_new();
if (channel->stderr_buffer == NULL) { if (channel->stderr_buffer == NULL) {
ssh_set_error_oom(session);
ssh_buffer_free(channel->stdout_buffer); ssh_buffer_free(channel->stdout_buffer);
SAFE_FREE(channel); SAFE_FREE(channel);
return NULL; return NULL;
@@ -243,6 +254,7 @@ static int channel_open(ssh_channel channel, const char *type_c, int window,
type = ssh_string_from_char(type_c); type = ssh_string_from_char(type_c);
if (type == NULL) { if (type == NULL) {
ssh_set_error_oom(session);
leave_function(); leave_function();
return err; return err;
} }
@@ -252,6 +264,7 @@ static int channel_open(ssh_channel channel, const char *type_c, int window,
buffer_add_u32(session->out_buffer, htonl(channel->local_channel)) < 0 || buffer_add_u32(session->out_buffer, htonl(channel->local_channel)) < 0 ||
buffer_add_u32(session->out_buffer, htonl(channel->local_window)) < 0 || buffer_add_u32(session->out_buffer, htonl(channel->local_window)) < 0 ||
buffer_add_u32(session->out_buffer, htonl(channel->local_maxpacket)) < 0) { buffer_add_u32(session->out_buffer, htonl(channel->local_maxpacket)) < 0) {
ssh_set_error_oom(session);
ssh_string_free(type); ssh_string_free(type);
leave_function(); leave_function();
return err; return err;
@@ -261,6 +274,7 @@ static int channel_open(ssh_channel channel, const char *type_c, int window,
if (payload != NULL) { if (payload != NULL) {
if (buffer_add_buffer(session->out_buffer, payload) < 0) { if (buffer_add_buffer(session->out_buffer, payload) < 0) {
ssh_set_error_oom(session);
leave_function(); leave_function();
return err; return err;
} }
@@ -278,7 +292,11 @@ static int channel_open(ssh_channel channel, const char *type_c, int window,
/* Todo: fix this into a correct loop */ /* Todo: fix this into a correct loop */
/* wait until channel is opened by server */ /* wait until channel is opened by server */
while(channel->state == SSH_CHANNEL_STATE_NOT_OPEN){ while(channel->state == SSH_CHANNEL_STATE_NOT_OPEN){
ssh_handle_packets(session,-1); ssh_handle_packets(session, -2);
if (session->session_state == SSH_SESSION_STATE_ERROR) {
err = SSH_ERROR;
break;
}
} }
if(channel->state == SSH_CHANNEL_STATE_OPEN) if(channel->state == SSH_CHANNEL_STATE_OPEN)
err=SSH_OK; err=SSH_OK;
@@ -286,24 +304,25 @@ static int channel_open(ssh_channel channel, const char *type_c, int window,
return err; return err;
} }
/* get ssh channel from local session? */ /* return channel with corresponding local id, or NULL if not found */
ssh_channel ssh_channel_from_local(ssh_session session, uint32_t id) { ssh_channel ssh_channel_from_local(ssh_session session, uint32_t id) {
ssh_channel initchan = session->channels; ssh_channel initchan = session->channels;
ssh_channel channel; ssh_channel channel = initchan;
/* We assume we are always the local */ for (;;) {
if (initchan == NULL) { if (channel == NULL) {
return NULL; return NULL;
} }
if (channel->local_channel == id) {
for (channel = initchan; channel->local_channel != id; return channel;
channel=channel->next) { }
if (channel->next == initchan) { if (channel->next == initchan) {
return NULL; return NULL;
}
channel = channel->next;
} }
}
return channel; return NULL;
} }
/** /**
@@ -331,6 +350,7 @@ static int grow_window(ssh_session session, ssh_channel channel, int minimumsize
if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_WINDOW_ADJUST) < 0 || if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_WINDOW_ADJUST) < 0 ||
buffer_add_u32(session->out_buffer, htonl(channel->remote_channel)) < 0 || buffer_add_u32(session->out_buffer, htonl(channel->remote_channel)) < 0 ||
buffer_add_u32(session->out_buffer, htonl(new_window - channel->local_window)) < 0) { buffer_add_u32(session->out_buffer, htonl(new_window - channel->local_window)) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
@@ -467,7 +487,7 @@ SSH_PACKET_CALLBACK(channel_rcv_data){
len = ssh_string_len(str); len = ssh_string_len(str);
ssh_log(session, SSH_LOG_PROTOCOL, ssh_log(session, SSH_LOG_PROTOCOL,
"Channel receiving %zu bytes data in %d (local win=%d remote win=%d)", "Channel receiving %" PRIdS " bytes data in %d (local win=%d remote win=%d)",
len, len,
is_stderr, is_stderr,
channel->local_window, channel->local_window,
@@ -476,7 +496,7 @@ SSH_PACKET_CALLBACK(channel_rcv_data){
/* What shall we do in this case? Let's accept it anyway */ /* What shall we do in this case? Let's accept it anyway */
if (len > channel->local_window) { if (len > channel->local_window) {
ssh_log(session, SSH_LOG_RARE, ssh_log(session, SSH_LOG_RARE,
"Data packet too big for our window(%zu vs %d)", "Data packet too big for our window(%" PRIdS " vs %d)",
len, len,
channel->local_window); channel->local_window);
} }
@@ -799,7 +819,18 @@ SSH_PACKET_CALLBACK(channel_rcv_request) {
*/ */
int channel_default_bufferize(ssh_channel channel, void *data, int len, int channel_default_bufferize(ssh_channel channel, void *data, int len,
int is_stderr) { int is_stderr) {
ssh_session session = channel->session; ssh_session session;
if(channel == NULL) {
return -1;
}
session = channel->session;
if(data == NULL) {
ssh_set_error_invalid(session, __FUNCTION__);
return -1;
}
ssh_log(session, SSH_LOG_RARE, ssh_log(session, SSH_LOG_RARE,
"placing %d bytes into channel buffer (stderr=%d)", len, is_stderr); "placing %d bytes into channel buffer (stderr=%d)", len, is_stderr);
@@ -814,6 +845,7 @@ int channel_default_bufferize(ssh_channel channel, void *data, int len,
} }
if (buffer_add_data(channel->stdout_buffer, data, len) < 0) { if (buffer_add_data(channel->stdout_buffer, data, len) < 0) {
ssh_set_error_oom(session);
ssh_buffer_free(channel->stdout_buffer); ssh_buffer_free(channel->stdout_buffer);
channel->stdout_buffer = NULL; channel->stdout_buffer = NULL;
return -1; return -1;
@@ -829,6 +861,7 @@ int channel_default_bufferize(ssh_channel channel, void *data, int len,
} }
if (buffer_add_data(channel->stderr_buffer, data, len) < 0) { if (buffer_add_data(channel->stderr_buffer, data, len) < 0) {
ssh_set_error_oom(session);
ssh_buffer_free(channel->stderr_buffer); ssh_buffer_free(channel->stderr_buffer);
channel->stderr_buffer = NULL; channel->stderr_buffer = NULL;
return -1; return -1;
@@ -857,7 +890,11 @@ int ssh_channel_open_session(ssh_channel channel) {
} }
#endif #endif
return channel_open(channel,"session",64000,32000,NULL); return channel_open(channel,
"session",
CHANNEL_INITIAL_WINDOW,
CHANNEL_MAX_PACKET,
NULL);
} }
/** /**
@@ -869,11 +906,12 @@ int ssh_channel_open_session(ssh_channel channel) {
* *
* @param[in] remoteport The remote port. * @param[in] remoteport The remote port.
* *
* @param[in] sourcehost The source host (your local computer). It's optional * @param[in] sourcehost The numeric IP address of the machine from where the
* and for logging purpose. * connection request originates. This is mostly for
* logging purposes.
* *
* @param[in] localport The source port (your local computer). It's optional * @param[in] localport The port on the host from where the connection
* and for logging purpose. * originated. This is mostly for logging purposes.
* *
* @return SSH_OK on success, SSH_ERROR if an error occured. * @return SSH_OK on success, SSH_ERROR if an error occured.
* *
@@ -883,39 +921,59 @@ int ssh_channel_open_session(ssh_channel channel) {
*/ */
int ssh_channel_open_forward(ssh_channel channel, const char *remotehost, int ssh_channel_open_forward(ssh_channel channel, const char *remotehost,
int remoteport, const char *sourcehost, int localport) { int remoteport, const char *sourcehost, int localport) {
ssh_session session = channel->session; ssh_session session;
ssh_buffer payload = NULL; ssh_buffer payload = NULL;
ssh_string str = NULL; ssh_string str = NULL;
int rc = SSH_ERROR; int rc = SSH_ERROR;
if (channel == NULL) {
return rc;
}
session = channel->session;
enter_function(); enter_function();
if(remotehost == NULL || sourcehost == NULL) {
ssh_set_error_invalid(session, __FUNCTION__);
return rc;
}
payload = ssh_buffer_new(); payload = ssh_buffer_new();
if (payload == NULL) { if (payload == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
str = ssh_string_from_char(remotehost); str = ssh_string_from_char(remotehost);
if (str == NULL) { if (str == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
if (buffer_add_ssh_string(payload, str) < 0 || if (buffer_add_ssh_string(payload, str) < 0 ||
buffer_add_u32(payload,htonl(remoteport)) < 0) { buffer_add_u32(payload,htonl(remoteport)) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
ssh_string_free(str); ssh_string_free(str);
str = ssh_string_from_char(sourcehost); str = ssh_string_from_char(sourcehost);
if (str == NULL) { if (str == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
if (buffer_add_ssh_string(payload, str) < 0 || if (buffer_add_ssh_string(payload, str) < 0 ||
buffer_add_u32(payload,htonl(localport)) < 0) { buffer_add_u32(payload,htonl(localport)) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
rc = channel_open(channel, "direct-tcpip", 64000, 32000, payload); rc = channel_open(channel,
"direct-tcpip",
CHANNEL_INITIAL_WINDOW,
CHANNEL_MAX_PACKET,
payload);
error: error:
ssh_buffer_free(payload); ssh_buffer_free(payload);
@@ -988,9 +1046,11 @@ int ssh_channel_send_eof(ssh_channel channel){
enter_function(); enter_function();
if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_EOF) < 0) { if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_EOF) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
if (buffer_add_u32(session->out_buffer,htonl(channel->remote_channel)) < 0) { if (buffer_add_u32(session->out_buffer,htonl(channel->remote_channel)) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
rc = packet_send(session); rc = packet_send(session);
@@ -1040,6 +1100,7 @@ int ssh_channel_close(ssh_channel channel){
if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_CLOSE) < 0 || if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_CLOSE) < 0 ||
buffer_add_u32(session->out_buffer, htonl(channel->remote_channel)) < 0) { buffer_add_u32(session->out_buffer, htonl(channel->remote_channel)) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
@@ -1064,15 +1125,28 @@ error:
int channel_write_common(ssh_channel channel, const void *data, int channel_write_common(ssh_channel channel, const void *data,
uint32_t len, int is_stderr) { uint32_t len, int is_stderr) {
ssh_session session = channel->session; ssh_session session;
int origlen = len; int origlen = len;
size_t effectivelen; size_t effectivelen;
/* handle the max packet len from remote side, be nice */ size_t maxpacketlen;
/* 10 bytes for the headers */
size_t maxpacketlen = channel->remote_maxpacket - 10; if(channel == NULL || data == NULL) {
return -1;
}
session = channel->session;
if(data == NULL) {
ssh_set_error_invalid(session, __FUNCTION__);
return -1;
}
enter_function(); enter_function();
/*
* Handle the max packet len from remote side, be nice
* 10 bytes for the headers
*/
maxpacketlen = channel->remote_maxpacket - 10;
if (channel->local_eof) { if (channel->local_eof) {
ssh_set_error(session, SSH_REQUEST_DENIED, ssh_set_error(session, SSH_REQUEST_DENIED,
"Can't write to channel %d:%d after EOF was sent", "Can't write to channel %d:%d after EOF was sent",
@@ -1102,15 +1176,12 @@ int channel_write_common(ssh_channel channel, const void *data,
"Remote window is %d bytes. going to write %d bytes", "Remote window is %d bytes. going to write %d bytes",
channel->remote_window, channel->remote_window,
len); len);
ssh_log(session, SSH_LOG_PROTOCOL,
"Waiting for a growing window message...");
/* What happens when the channel window is zero? */ /* What happens when the channel window is zero? */
while(channel->remote_window == 0) { if(channel->remote_window == 0) {
/* parse every incoming packet */ /* nothing can be written */
if (ssh_handle_packets(session,-1) == SSH_ERROR) { ssh_log(session, SSH_LOG_PROTOCOL,
leave_function(); "Wait for a growing window message...");
return SSH_ERROR; return 0;
}
} }
effectivelen = len > channel->remote_window ? channel->remote_window : len; effectivelen = len > channel->remote_window ? channel->remote_window : len;
} else { } else {
@@ -1121,16 +1192,19 @@ int channel_write_common(ssh_channel channel, const void *data,
SSH2_MSG_CHANNEL_EXTENDED_DATA : SSH2_MSG_CHANNEL_DATA) < 0 || SSH2_MSG_CHANNEL_EXTENDED_DATA : SSH2_MSG_CHANNEL_DATA) < 0 ||
buffer_add_u32(session->out_buffer, buffer_add_u32(session->out_buffer,
htonl(channel->remote_channel)) < 0) { htonl(channel->remote_channel)) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
/* stderr message has an extra field */ /* stderr message has an extra field */
if (is_stderr && if (is_stderr &&
buffer_add_u32(session->out_buffer, htonl(SSH2_EXTENDED_DATA_STDERR)) < 0) { buffer_add_u32(session->out_buffer, htonl(SSH2_EXTENDED_DATA_STDERR)) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
/* append payload data */ /* append payload data */
if (buffer_add_u32(session->out_buffer, htonl(effectivelen)) < 0 || if (buffer_add_u32(session->out_buffer, htonl(effectivelen)) < 0 ||
buffer_add_data(session->out_buffer, data, effectivelen) < 0) { buffer_add_data(session->out_buffer, data, effectivelen) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
@@ -1156,6 +1230,10 @@ error:
return SSH_ERROR; return SSH_ERROR;
} }
uint32_t ssh_channel_window_size(ssh_channel channel) {
return channel->remote_window;
}
/** /**
* @brief Blocking write on a channel. * @brief Blocking write on a channel.
* *
@@ -1313,6 +1391,7 @@ static int channel_request(ssh_channel channel, const char *request,
req = ssh_string_from_char(request); req = ssh_string_from_char(request);
if (req == NULL) { if (req == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
@@ -1320,6 +1399,7 @@ static int channel_request(ssh_channel channel, const char *request,
buffer_add_u32(session->out_buffer, htonl(channel->remote_channel)) < 0 || buffer_add_u32(session->out_buffer, htonl(channel->remote_channel)) < 0 ||
buffer_add_ssh_string(session->out_buffer, req) < 0 || buffer_add_ssh_string(session->out_buffer, req) < 0 ||
buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1) < 0) { buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
ssh_string_free(req); ssh_string_free(req);
@@ -1327,6 +1407,7 @@ static int channel_request(ssh_channel channel, const char *request,
if (buffer != NULL) { if (buffer != NULL) {
if (buffer_add_data(session->out_buffer, buffer_get_rest(buffer), if (buffer_add_data(session->out_buffer, buffer_get_rest(buffer),
buffer_get_rest_len(buffer)) < 0) { buffer_get_rest_len(buffer)) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
} }
@@ -1344,7 +1425,12 @@ static int channel_request(ssh_channel channel, const char *request,
return SSH_OK; return SSH_OK;
} }
while(channel->request_state == SSH_CHANNEL_REQ_STATE_PENDING){ while(channel->request_state == SSH_CHANNEL_REQ_STATE_PENDING){
ssh_handle_packets(session,-1); ssh_handle_packets(session, -2);
if(session->session_state == SSH_SESSION_STATE_ERROR) {
channel->request_state = SSH_CHANNEL_REQ_STATE_ERROR;
break;
}
} }
/* we received something */ /* we received something */
switch (channel->request_state){ switch (channel->request_state){
@@ -1409,11 +1495,13 @@ int ssh_channel_request_pty_size(ssh_channel channel, const char *terminal,
#endif #endif
buffer = ssh_buffer_new(); buffer = ssh_buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
term = ssh_string_from_char(terminal); term = ssh_string_from_char(terminal);
if (term == NULL) { if (term == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
@@ -1424,6 +1512,7 @@ int ssh_channel_request_pty_size(ssh_channel channel, const char *terminal,
buffer_add_u32(buffer, 0) < 0 || buffer_add_u32(buffer, 0) < 0 ||
buffer_add_u32(buffer, htonl(1)) < 0 || /* Add a 0byte string */ buffer_add_u32(buffer, htonl(1)) < 0 || /* Add a 0byte string */
buffer_add_u8(buffer, 0) < 0) { buffer_add_u8(buffer, 0) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
@@ -1481,6 +1570,7 @@ int ssh_channel_change_pty_size(ssh_channel channel, int cols, int rows) {
buffer = ssh_buffer_new(); buffer = ssh_buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
@@ -1488,6 +1578,7 @@ int ssh_channel_change_pty_size(ssh_channel channel, int cols, int rows) {
buffer_add_u32(buffer, htonl(rows)) < 0 || buffer_add_u32(buffer, htonl(rows)) < 0 ||
buffer_add_u32(buffer, 0) < 0 || buffer_add_u32(buffer, 0) < 0 ||
buffer_add_u32(buffer, 0) < 0) { buffer_add_u32(buffer, 0) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
@@ -1533,15 +1624,18 @@ int ssh_channel_request_subsystem(ssh_channel channel, const char *subsys) {
buffer = ssh_buffer_new(); buffer = ssh_buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
subsystem = ssh_string_from_char(subsys); subsystem = ssh_string_from_char(subsys);
if (subsystem == NULL) { if (subsystem == NULL) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
if (buffer_add_ssh_string(buffer, subsystem) < 0) { if (buffer_add_ssh_string(buffer, subsystem) < 0) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
@@ -1601,11 +1695,13 @@ int ssh_channel_request_x11(ssh_channel channel, int single_connection, const ch
buffer = ssh_buffer_new(); buffer = ssh_buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
p = ssh_string_from_char(protocol ? protocol : "MIT-MAGIC-COOKIE-1"); p = ssh_string_from_char(protocol ? protocol : "MIT-MAGIC-COOKIE-1");
if (p == NULL) { if (p == NULL) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
@@ -1615,6 +1711,7 @@ int ssh_channel_request_x11(ssh_channel channel, int single_connection, const ch
c = generate_cookie(); c = generate_cookie();
} }
if (c == NULL) { if (c == NULL) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
@@ -1622,6 +1719,7 @@ int ssh_channel_request_x11(ssh_channel channel, int single_connection, const ch
buffer_add_ssh_string(buffer, p) < 0 || buffer_add_ssh_string(buffer, p) < 0 ||
buffer_add_ssh_string(buffer, c) < 0 || buffer_add_ssh_string(buffer, c) < 0 ||
buffer_add_u32(buffer, htonl(screen_number)) < 0) { buffer_add_u32(buffer, htonl(screen_number)) < 0) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
@@ -1649,7 +1747,7 @@ static ssh_channel ssh_channel_accept(ssh_session session, int channeltype,
for (t = timeout_ms; t >= 0; t -= 50) for (t = timeout_ms; t >= 0; t -= 50)
{ {
ssh_handle_packets(session,50); ssh_handle_packets(session, 50);
if (session->ssh_message_list) { if (session->ssh_message_list) {
iterator = ssh_list_get_iterator(session->ssh_message_list); iterator = ssh_list_get_iterator(session->ssh_message_list);
@@ -1674,6 +1772,7 @@ static ssh_channel ssh_channel_accept(ssh_session session, int channeltype,
} }
} }
ssh_set_error(session, SSH_NO_ERROR, "No channel request of this type from server");
return NULL; return NULL;
} }
@@ -1771,12 +1870,14 @@ static int global_request(ssh_session session, const char *request,
} }
req = ssh_string_from_char(request); req = ssh_string_from_char(request);
if (req == NULL) { if (req == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
if (buffer_add_u8(session->out_buffer, SSH2_MSG_GLOBAL_REQUEST) < 0 || if (buffer_add_u8(session->out_buffer, SSH2_MSG_GLOBAL_REQUEST) < 0 ||
buffer_add_ssh_string(session->out_buffer, req) < 0 || buffer_add_ssh_string(session->out_buffer, req) < 0 ||
buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1) < 0) { buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
ssh_string_free(req); ssh_string_free(req);
@@ -1785,6 +1886,7 @@ static int global_request(ssh_session session, const char *request,
if (buffer != NULL) { if (buffer != NULL) {
if (buffer_add_data(session->out_buffer, buffer_get_rest(buffer), if (buffer_add_data(session->out_buffer, buffer_get_rest(buffer),
buffer_get_rest_len(buffer)) < 0) { buffer_get_rest_len(buffer)) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
} }
@@ -1802,7 +1904,7 @@ static int global_request(ssh_session session, const char *request,
return SSH_OK; return SSH_OK;
} }
while(session->global_req_state == SSH_CHANNEL_REQ_STATE_PENDING){ while(session->global_req_state == SSH_CHANNEL_REQ_STATE_PENDING){
rc=ssh_handle_packets(session,-1); rc=ssh_handle_packets(session, -2);
if(rc==SSH_ERROR){ if(rc==SSH_ERROR){
session->global_req_state = SSH_CHANNEL_REQ_STATE_ERROR; session->global_req_state = SSH_CHANNEL_REQ_STATE_ERROR;
break; break;
@@ -1863,16 +1965,19 @@ int ssh_forward_listen(ssh_session session, const char *address, int port, int *
buffer = ssh_buffer_new(); buffer = ssh_buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
addr = ssh_string_from_char(address ? address : ""); addr = ssh_string_from_char(address ? address : "");
if (addr == NULL) { if (addr == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
if (buffer_add_ssh_string(buffer, addr) < 0 || if (buffer_add_ssh_string(buffer, addr) < 0 ||
buffer_add_u32(buffer, htonl(port)) < 0) { buffer_add_u32(buffer, htonl(port)) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
@@ -1922,16 +2027,19 @@ int ssh_forward_cancel(ssh_session session, const char *address, int port) {
buffer = ssh_buffer_new(); buffer = ssh_buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
addr = ssh_string_from_char(address ? address : ""); addr = ssh_string_from_char(address ? address : "");
if (addr == NULL) { if (addr == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
if (buffer_add_ssh_string(buffer, addr) < 0 || if (buffer_add_ssh_string(buffer, addr) < 0 ||
buffer_add_u32(buffer, htonl(port)) < 0) { buffer_add_u32(buffer, htonl(port)) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
@@ -1963,25 +2071,30 @@ int ssh_channel_request_env(ssh_channel channel, const char *name, const char *v
buffer = ssh_buffer_new(); buffer = ssh_buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
str = ssh_string_from_char(name); str = ssh_string_from_char(name);
if (str == NULL) { if (str == NULL) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
if (buffer_add_ssh_string(buffer, str) < 0) { if (buffer_add_ssh_string(buffer, str) < 0) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
ssh_string_free(str); ssh_string_free(str);
str = ssh_string_from_char(value); str = ssh_string_from_char(value);
if (str == NULL) { if (str == NULL) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
if (buffer_add_ssh_string(buffer, str) < 0) { if (buffer_add_ssh_string(buffer, str) < 0) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
@@ -2033,15 +2146,18 @@ int ssh_channel_request_exec(ssh_channel channel, const char *cmd) {
buffer = ssh_buffer_new(); buffer = ssh_buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
command = ssh_string_from_char(cmd); command = ssh_string_from_char(cmd);
if (command == NULL) { if (command == NULL) {
goto error; goto error;
ssh_set_error_oom(channel->session);
} }
if (buffer_add_ssh_string(buffer, command) < 0) { if (buffer_add_ssh_string(buffer, command) < 0) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
@@ -2061,10 +2177,26 @@ error:
* In such a case this request will be silently ignored. * In such a case this request will be silently ignored.
* Only SSH-v2 is supported (I'm not sure about SSH-v1). * Only SSH-v2 is supported (I'm not sure about SSH-v1).
* *
* OpenSSH doesn't support signals yet, see:
* https://bugzilla.mindrot.org/show_bug.cgi?id=1424
*
* @param[in] channel The channel to send signal. * @param[in] channel The channel to send signal.
* *
* @param[in] sig The signal to send (without SIG prefix) * @param[in] sig The signal to send (without SIG prefix)
* (e.g. "TERM" or "KILL"). * \n\n
* SIGABRT -> ABRT \n
* SIGALRM -> ALRM \n
* SIGFPE -> FPE \n
* SIGHUP -> HUP \n
* SIGILL -> ILL \n
* SIGINT -> INT \n
* SIGKILL -> KILL \n
* SIGPIPE -> PIPE \n
* SIGQUIT -> QUIT \n
* SIGSEGV -> SEGV \n
* SIGTERM -> TERM \n
* SIGUSR1 -> USR1 \n
* SIGUSR2 -> USR2 \n
* *
* @return SSH_OK on success, SSH_ERROR if an error occured * @return SSH_OK on success, SSH_ERROR if an error occured
* (including attempts to send signal via SSH-v1 session). * (including attempts to send signal via SSH-v1 session).
@@ -2082,15 +2214,18 @@ int ssh_channel_request_send_signal(ssh_channel channel, const char *sig) {
buffer = ssh_buffer_new(); buffer = ssh_buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
encoded_signal = ssh_string_from_char(sig); encoded_signal = ssh_string_from_char(sig);
if (encoded_signal == NULL) { if (encoded_signal == NULL) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
if (buffer_add_ssh_string(buffer, encoded_signal) < 0) { if (buffer_add_ssh_string(buffer, encoded_signal) < 0) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
@@ -2142,7 +2277,10 @@ int channel_read_buffer(ssh_channel channel, ssh_buffer buffer, uint32_t count,
leave_function(); leave_function();
return r; return r;
} }
buffer_add_data(buffer,buffer_tmp,r); if(buffer_add_data(buffer,buffer_tmp,r) < 0){
ssh_set_error_oom(session);
r = SSH_ERROR;
}
leave_function(); leave_function();
return r; return r;
} }
@@ -2150,7 +2288,7 @@ int channel_read_buffer(ssh_channel channel, ssh_buffer buffer, uint32_t count,
leave_function(); leave_function();
return 0; return 0;
} }
ssh_handle_packets(channel->session, -1); ssh_handle_packets(channel->session, -2);
} while (r == 0); } while (r == 0);
} }
while(total < count){ while(total < count){
@@ -2163,7 +2301,11 @@ int channel_read_buffer(ssh_channel channel, ssh_buffer buffer, uint32_t count,
leave_function(); leave_function();
return total; return total;
} }
buffer_add_data(buffer,buffer_tmp,r); if(buffer_add_data(buffer,buffer_tmp,r) < 0){
ssh_set_error_oom(session);
leave_function();
return SSH_ERROR;
}
total += r; total += r;
} }
leave_function(); leave_function();
@@ -2244,7 +2386,7 @@ int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_std
break; break;
} }
ssh_handle_packets(session,-1); ssh_handle_packets(session, -2);
} }
len = buffer_get_rest_len(stdbuf); len = buffer_get_rest_len(stdbuf);
@@ -2288,7 +2430,7 @@ int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_std
int ssh_channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count, int ssh_channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count,
int is_stderr) { int is_stderr) {
ssh_session session = channel->session; ssh_session session = channel->session;
uint32_t to_read; int to_read;
int rc; int rc;
enter_function(); enter_function();
@@ -2300,8 +2442,8 @@ int ssh_channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count
return to_read; /* may be an error code */ return to_read; /* may be an error code */
} }
if (to_read > count) { if (to_read > (int)count) {
to_read = count; to_read = (int)count;
} }
rc = ssh_channel_read(channel, dest, to_read, is_stderr); rc = ssh_channel_read(channel, dest, to_read, is_stderr);
@@ -2334,7 +2476,7 @@ int ssh_channel_poll(ssh_channel channel, int is_stderr){
} }
if (buffer_get_rest_len(stdbuf) == 0 && channel->remote_eof == 0) { if (buffer_get_rest_len(stdbuf) == 0 && channel->remote_eof == 0) {
if (ssh_handle_packets(channel->session,0)==SSH_ERROR) { if (ssh_handle_packets(channel->session, 0)==SSH_ERROR) {
leave_function(); leave_function();
return SSH_ERROR; return SSH_ERROR;
} }
@@ -2379,9 +2521,9 @@ int ssh_channel_get_exit_status(ssh_channel channel) {
return -1; return -1;
} }
while (channel->remote_eof == 0 || channel->exit_status == -1) { while ((channel->remote_eof == 0 || channel->exit_status == -1) && channel->session->alive) {
/* Parse every incoming packet */ /* Parse every incoming packet */
if (ssh_handle_packets(channel->session,-1) != SSH_OK) { if (ssh_handle_packets(channel->session, -2) != SSH_OK) {
return -1; return -1;
} }
/* XXX We should actually wait for a close packet and not a close /* XXX We should actually wait for a close packet and not a close
@@ -2416,7 +2558,7 @@ static int channel_protocol_select(ssh_channel *rchans, ssh_channel *wchans,
chan = rchans[i]; chan = rchans[i];
while (ssh_channel_is_open(chan) && ssh_socket_data_available(chan->session->socket)) { while (ssh_channel_is_open(chan) && ssh_socket_data_available(chan->session->socket)) {
ssh_handle_packets(chan->session,-1); ssh_handle_packets(chan->session, -2);
} }
if ((chan->stdout_buffer && buffer_get_rest_len(chan->stdout_buffer) > 0) || if ((chan->stdout_buffer && buffer_get_rest_len(chan->stdout_buffer) > 0) ||
@@ -2659,30 +2801,39 @@ int ssh_channel_open_reverse_forward(ssh_channel channel, const char *remotehost
payload = ssh_buffer_new(); payload = ssh_buffer_new();
if (payload == NULL) { if (payload == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
str = ssh_string_from_char(remotehost); str = ssh_string_from_char(remotehost);
if (str == NULL) { if (str == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
if (buffer_add_ssh_string(payload, str) < 0 || if (buffer_add_ssh_string(payload, str) < 0 ||
buffer_add_u32(payload,htonl(remoteport)) < 0) { buffer_add_u32(payload,htonl(remoteport)) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
ssh_string_free(str); ssh_string_free(str);
str = ssh_string_from_char(sourcehost); str = ssh_string_from_char(sourcehost);
if (str == NULL) { if (str == NULL) {
ssh_set_error_oom(session);
goto error; goto error;
} }
if (buffer_add_ssh_string(payload, str) < 0 || if (buffer_add_ssh_string(payload, str) < 0 ||
buffer_add_u32(payload,htonl(localport)) < 0) { buffer_add_u32(payload,htonl(localport)) < 0) {
ssh_set_error_oom(session);
goto error; goto error;
} }
rc = channel_open(channel, "forwarded-tcpip", 64000, 32000, payload); rc = channel_open(channel,
"forwarded-tcpip",
CHANNEL_INITIAL_WINDOW,
CHANNEL_MAX_PACKET,
payload);
error: error:
ssh_buffer_free(payload); ssh_buffer_free(payload);
@@ -2717,10 +2868,12 @@ int ssh_channel_request_send_exit_status(ssh_channel channel, int exit_status) {
buffer = ssh_buffer_new(); buffer = ssh_buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
if (buffer_add_u32(buffer, ntohl(exit_status)) < 0) { if (buffer_add_u32(buffer, ntohl(exit_status)) < 0) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
@@ -2754,6 +2907,15 @@ int ssh_channel_request_send_exit_signal(ssh_channel channel, const char *sig, i
ssh_string tmp = NULL; ssh_string tmp = NULL;
int rc = SSH_ERROR; int rc = SSH_ERROR;
if(channel == NULL) {
return rc;
}
if(sig == NULL || errmsg == NULL || lang == NULL) {
ssh_set_error_invalid(channel->session, __FUNCTION__);
return rc;
}
#ifdef WITH_SSH1 #ifdef WITH_SSH1
if (channel->version == 1) { if (channel->version == 1) {
return SSH_ERROR; // TODO: Add support for SSH-v1 if possible. return SSH_ERROR; // TODO: Add support for SSH-v1 if possible.
@@ -2762,36 +2924,44 @@ int ssh_channel_request_send_exit_signal(ssh_channel channel, const char *sig, i
buffer = ssh_buffer_new(); buffer = ssh_buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
tmp = ssh_string_from_char(sig); tmp = ssh_string_from_char(sig);
if (tmp == NULL) { if (tmp == NULL) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
if (buffer_add_ssh_string(buffer, tmp) < 0) { if (buffer_add_ssh_string(buffer, tmp) < 0) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
if (buffer_add_u8(buffer, core?1:0) < 0) { if (buffer_add_u8(buffer, core?1:0) < 0) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
ssh_string_free(tmp); ssh_string_free(tmp);
tmp = ssh_string_from_char(errmsg); tmp = ssh_string_from_char(errmsg);
if (tmp == NULL) { if (tmp == NULL) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
if (buffer_add_ssh_string(buffer, tmp) < 0) { if (buffer_add_ssh_string(buffer, tmp) < 0) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
ssh_string_free(tmp); ssh_string_free(tmp);
tmp = ssh_string_from_char(lang); tmp = ssh_string_from_char(lang);
if (tmp == NULL) { if (tmp == NULL) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }
if (buffer_add_ssh_string(buffer, tmp) < 0) { if (buffer_add_ssh_string(buffer, tmp) < 0) {
ssh_set_error_oom(channel->session);
goto error; goto error;
} }

View File

@@ -232,7 +232,7 @@ SSH_PACKET_CALLBACK(ssh_packet_data1){
} }
ssh_log(session, SSH_LOG_PROTOCOL, ssh_log(session, SSH_LOG_PROTOCOL,
"Adding %zu bytes data in %d", "Adding %" PRIdS " bytes data in %d",
ssh_string_len(str), is_stderr); ssh_string_len(str), is_stderr);
if (channel_default_bufferize(channel, ssh_string_data(str), ssh_string_len(str), if (channel_default_bufferize(channel, ssh_string_data(str), ssh_string_len(str),

View File

@@ -673,8 +673,6 @@ int ssh_connect(ssh_session session) {
} else { } else {
ret=ssh_socket_connect(session->socket, session->host, session->port, ret=ssh_socket_connect(session->socket, session->host, session->port,
session->bindaddr); session->bindaddr);
/*, session->timeout * 1000 + session->timeout_usec); */
} }
if (ret == SSH_ERROR) { if (ret == SSH_ERROR) {
leave_function(); leave_function();
@@ -686,11 +684,21 @@ int ssh_connect(ssh_session session) {
session->alive = 1; session->alive = 1;
ssh_log(session,SSH_LOG_PROTOCOL,"Socket connecting, now waiting for the callbacks to work"); ssh_log(session,SSH_LOG_PROTOCOL,"Socket connecting, now waiting for the callbacks to work");
pending: pending:
session->pending_call_state=SSH_PENDING_CALL_CONNECT; session->pending_call_state=SSH_PENDING_CALL_CONNECT;
if(ssh_is_blocking(session)) if(ssh_is_blocking(session)) {
ssh_handle_packets_termination(session,-1,ssh_connect_termination,session); int timeout = (session->timeout * 1000) + (session->timeout_usec / 1000);
if (timeout == 0) {
timeout = 10 * 1000;
}
ssh_log(session,SSH_LOG_PACKET,"ssh_connect: Actual timeout : %d", timeout);
ssh_handle_packets_termination(session, timeout, ssh_connect_termination, session);
if(!ssh_connect_termination(session)){
ssh_set_error(session,SSH_FATAL,"Timeout connecting to %s",session->host);
session->session_state = SSH_SESSION_STATE_ERROR;
}
}
else else
ssh_handle_packets_termination(session,0,ssh_connect_termination, session); ssh_handle_packets_termination(session, 0, ssh_connect_termination, session);
ssh_log(session,SSH_LOG_PACKET,"ssh_connect: Actual state : %d",session->session_state); ssh_log(session,SSH_LOG_PACKET,"ssh_connect: Actual state : %d",session->session_state);
if(!ssh_is_blocking(session) && !ssh_connect_termination(session)){ if(!ssh_is_blocking(session) && !ssh_connect_termination(session)){
leave_function(); leave_function();

View File

@@ -327,9 +327,7 @@ int ssh_config_parse_file(ssh_session session, const char *filename) {
return 0; return 0;
} }
if (session->log_verbosity) { ssh_log(session, SSH_LOG_RARE, "Reading configuration data from %s", filename);
fprintf(stderr, "Reading configuration data from %s\n", filename);
}
parsing = 1; parsing = 1;
while (fgets(line, sizeof(line), f)) { while (fgets(line, sizeof(line), f)) {

View File

@@ -21,12 +21,17 @@
* MA 02111-1307, USA. * MA 02111-1307, USA.
*/ */
#include "config.h"
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "libssh/libssh.h"
#include "libssh/misc.h"
#ifdef _WIN32 #ifdef _WIN32
/* /*
* Only use Windows API functions available on Windows 2000 SP4 or later. * Only use Windows API functions available on Windows 2000 SP4 or later.
@@ -78,14 +83,6 @@
#error "Your system must have getaddrinfo()" #error "Your system must have getaddrinfo()"
#endif #endif
#ifdef HAVE_REGCOMP
/* don't declare gnu extended regexp's */
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE
#endif
#include <regex.h>
#endif /* HAVE_REGCOMP */
#ifdef _WIN32 #ifdef _WIN32
void ssh_sock_set_nonblocking(socket_t sock) { void ssh_sock_set_nonblocking(socket_t sock) {
u_long nonblocking = 1; u_long nonblocking = 1;
@@ -118,53 +115,6 @@ void ssh_sock_set_blocking(socket_t sock) {
#endif /* _WIN32 */ #endif /* _WIN32 */
#ifdef HAVE_REGCOMP
#define IPEXPR "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"
static regex_t *ip_regex = NULL;
/** @internal
* @brief initializes and compile the regexp to be used for IP matching
* @returns -1 on error (and error message is set)
* @returns 0 on success
*/
int ssh_regex_init(){
if(ip_regex==NULL){
int err;
regex_t *regex=malloc(sizeof (regex_t));
ZERO_STRUCTP(regex);
err = regcomp(regex, IPEXPR, REG_EXTENDED | REG_NOSUB);
if(err != 0){
char buffer[128];
regerror(err,regex,buffer,sizeof(buffer));
fprintf(stderr,"Error while compiling regular expression : %s\n",buffer);
SAFE_FREE(regex);
return -1;
}
ip_regex=regex;
}
return 0;
}
/** @internal
* @brief clean up the IP regexp
*/
void ssh_regex_finalize(){
if(ip_regex){
regfree(ip_regex);
SAFE_FREE(ip_regex);
}
}
#else /* HAVE_REGCOMP */
int ssh_regex_init(){
return 0;
}
void ssh_regex_finalize(){
}
#endif
static int ssh_connect_socket_close(socket_t s){ static int ssh_connect_socket_close(socket_t s){
#ifdef _WIN32 #ifdef _WIN32
return closesocket(s); return closesocket(s);
@@ -194,13 +144,13 @@ static int getai(ssh_session session, const char *host, int port, struct addrinf
hints.ai_flags=AI_NUMERICSERV; hints.ai_flags=AI_NUMERICSERV;
#endif #endif
} }
#ifdef HAVE_REGCOMP
if(regexec(ip_regex,host,0,NULL,0) == 0){ if (ssh_is_ipaddr(host)) {
/* this is an IP address */ /* this is an IP address */
ssh_log(session,SSH_LOG_PACKET,"host %s matches an IP address",host); ssh_log(session,SSH_LOG_PACKET,"host %s matches an IP address",host);
hints.ai_flags |= AI_NUMERICHOST; hints.ai_flags |= AI_NUMERICHOST;
} }
#endif
return getaddrinfo(host, service, &hints, ai); return getaddrinfo(host, service, &hints, ai);
} }
@@ -472,7 +422,7 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
* *
* @param[in] timeout A timeout for the select. * @param[in] timeout A timeout for the select.
* *
* @return -1 if an error occured. E_INTR if it was interrupted, in * @return -1 if an error occured. SSH_EINTR if it was interrupted, in
* that case, just restart it. * that case, just restart it.
* *
* @warning libssh is not threadsafe here. That means that if a signal is caught * @warning libssh is not threadsafe here. That means that if a signal is caught

View File

@@ -140,6 +140,7 @@ int ssh_crypto_init(void) {
} }
bignum_bin2bn(p_value, P_LEN, p); bignum_bin2bn(p_value, P_LEN, p);
OpenSSL_add_all_algorithms(); OpenSSL_add_all_algorithms();
#endif #endif
ssh_crypto_initialized = 1; ssh_crypto_initialized = 1;
@@ -154,8 +155,13 @@ void ssh_crypto_finalize(void) {
g = NULL; g = NULL;
bignum_free(p); bignum_free(p);
p = NULL; p = NULL;
#ifdef HAVE_LIBGCRYPT
gcry_control(GCRYCTL_TERM_SECMEM);
#elif defined HAVE_LIBCRYPTO
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
#endif
ssh_crypto_initialized=0; ssh_crypto_initialized=0;
} }
} }

View File

@@ -57,8 +57,6 @@ int ssh_init(void) {
return -1; return -1;
if(ssh_socket_init()) if(ssh_socket_init())
return -1; return -1;
if(ssh_regex_init())
return -1;
return 0; return 0;
} }
@@ -73,18 +71,12 @@ int ssh_init(void) {
@returns 0 otherwise @returns 0 otherwise
*/ */
int ssh_finalize(void) { int ssh_finalize(void) {
ssh_threads_finalize();
ssh_regex_finalize();
ssh_crypto_finalize(); ssh_crypto_finalize();
ssh_socket_cleanup(); ssh_socket_cleanup();
#ifdef HAVE_LIBGCRYPT /* It is important to finalize threading after CRYPTO because
gcry_control(GCRYCTL_TERM_SECMEM); * it still depends on it */
#elif defined HAVE_LIBCRYPTO ssh_threads_finalize();
EVP_cleanup();
#endif
#ifdef _WIN32
WSACleanup();
#endif
return 0; return 0;
} }

View File

@@ -761,7 +761,7 @@ SSH_PACKET_CALLBACK(ssh_packet_publickey1){
} }
bits = ssh_string_len(enc_session) * 8 - 7; bits = ssh_string_len(enc_session) * 8 - 7;
ssh_log(session, SSH_LOG_PROTOCOL, "%d bits, %zu bytes encrypted session", ssh_log(session, SSH_LOG_PROTOCOL, "%d bits, %" PRIdS " bytes encrypted session",
bits, ssh_string_len(enc_session)); bits, ssh_string_len(enc_session));
bits = htons(bits); bits = htons(bits);
/* the encrypted mpint */ /* the encrypted mpint */
@@ -814,14 +814,14 @@ int ssh_get_kex1(ssh_session session) {
ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_PUBLIC_KEY"); ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_PUBLIC_KEY");
/* Here the callback is called */ /* Here the callback is called */
while(session->session_state==SSH_SESSION_STATE_INITIAL_KEX){ while(session->session_state==SSH_SESSION_STATE_INITIAL_KEX){
ssh_handle_packets(session,-1); ssh_handle_packets(session, -2);
} }
if(session->session_state==SSH_SESSION_STATE_ERROR) if(session->session_state==SSH_SESSION_STATE_ERROR)
goto error; goto error;
ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_SUCCESS"); ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_SUCCESS");
/* Waiting for SSH_SMSG_SUCCESS */ /* Waiting for SSH_SMSG_SUCCESS */
while(session->session_state==SSH_SESSION_STATE_KEXINIT_RECEIVED){ while(session->session_state==SSH_SESSION_STATE_KEXINIT_RECEIVED){
ssh_handle_packets(session,-1); ssh_handle_packets(session, -2);
} }
if(session->session_state==SSH_SESSION_STATE_ERROR) if(session->session_state==SSH_SESSION_STATE_ERROR)
goto error; goto error;

View File

@@ -677,11 +677,15 @@ ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
#elif defined HAVE_LIBCRYPTO #elif defined HAVE_LIBCRYPTO
DSA *dsa = NULL; DSA *dsa = NULL;
RSA *rsa = NULL; RSA *rsa = NULL;
BIO *bio = NULL;
#endif #endif
/* TODO Implement to read both DSA and RSA at once. */ /* TODO Implement to read both DSA and RSA at once. */
/* needed for openssl initialization */ /* needed for openssl initialization */
ssh_init(); if (ssh_init() < 0) {
return NULL;
}
ssh_log(session, SSH_LOG_RARE, "Trying to open %s", filename); ssh_log(session, SSH_LOG_RARE, "Trying to open %s", filename);
file = fopen(filename,"r"); file = fopen(filename,"r");
if (file == NULL) { if (file == NULL) {
@@ -690,6 +694,15 @@ ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
return NULL; return NULL;
} }
#ifdef HAVE_LIBCRYPTO
bio = BIO_new_file(filename,"r");
if (bio == NULL) {
fclose(file);
ssh_set_error(session, SSH_FATAL, "Could not create BIO.");
return NULL;
}
#endif
ssh_log(session, SSH_LOG_RARE, "Trying to read %s, passphase=%s, authcb=%s", ssh_log(session, SSH_LOG_RARE, "Trying to read %s, passphase=%s, authcb=%s",
filename, passphrase ? "true" : "false", filename, passphrase ? "true" : "false",
session->callbacks && session->callbacks->auth_function ? "true" : "false"); session->callbacks && session->callbacks->auth_function ? "true" : "false");
@@ -726,15 +739,16 @@ ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
ssh_set_error(session, SSH_FATAL, "Parsing private key %s", filename); ssh_set_error(session, SSH_FATAL, "Parsing private key %s", filename);
#elif defined HAVE_LIBCRYPTO #elif defined HAVE_LIBCRYPTO
if (session->callbacks && session->callbacks->auth_function) { if (session->callbacks && session->callbacks->auth_function) {
dsa = PEM_read_DSAPrivateKey(file, NULL, pem_get_password, session); dsa = PEM_read_bio_DSAPrivateKey(bio, NULL, pem_get_password, session);
} else { /* authcb */ } else { /* authcb */
/* openssl uses its own callback to get the passphrase here */ /* openssl uses its own callback to get the passphrase here */
dsa = PEM_read_DSAPrivateKey(file, NULL, NULL, NULL); dsa = PEM_read_bio_DSAPrivateKey(bio, NULL, NULL, NULL);
} /* authcb */ } /* authcb */
} else { /* passphrase */ } else { /* passphrase */
dsa = PEM_read_DSAPrivateKey(file, NULL, NULL, (void *) passphrase); dsa = PEM_read_bio_DSAPrivateKey(bio, NULL, NULL, (void *) passphrase);
} }
BIO_free(bio);
fclose(file); fclose(file);
if (dsa == NULL) { if (dsa == NULL) {
ssh_set_error(session, SSH_FATAL, ssh_set_error(session, SSH_FATAL,
@@ -766,15 +780,16 @@ ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
ssh_set_error(session,SSH_FATAL, "Parsing private key %s", filename); ssh_set_error(session,SSH_FATAL, "Parsing private key %s", filename);
#elif defined HAVE_LIBCRYPTO #elif defined HAVE_LIBCRYPTO
if (session->callbacks && session->callbacks->auth_function) { if (session->callbacks && session->callbacks->auth_function) {
rsa = PEM_read_RSAPrivateKey(file, NULL, pem_get_password, session); rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, pem_get_password, session);
} else { /* authcb */ } else { /* authcb */
/* openssl uses its own callback to get the passphrase here */ /* openssl uses its own callback to get the passphrase here */
rsa = PEM_read_RSAPrivateKey(file, NULL, NULL, NULL); rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
} /* authcb */ } /* authcb */
} else { /* passphrase */ } else { /* passphrase */
rsa = PEM_read_RSAPrivateKey(file, NULL, NULL, (void *) passphrase); rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, (void *) passphrase);
} }
BIO_free(bio);
fclose(file); fclose(file);
if (rsa == NULL) { if (rsa == NULL) {
@@ -786,6 +801,9 @@ ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
} }
break; break;
default: default:
#ifdef HAVE_LIBCRYPTO
BIO_free(bio);
#endif
fclose(file); fclose(file);
ssh_set_error(session, SSH_FATAL, "Invalid private key type %d", type); ssh_set_error(session, SSH_FATAL, "Invalid private key type %d", type);
return NULL; return NULL;
@@ -828,22 +846,31 @@ enum ssh_keytypes_e ssh_privatekey_type(ssh_private_key privatekey){
ssh_private_key _privatekey_from_file(void *session, const char *filename, ssh_private_key _privatekey_from_file(void *session, const char *filename,
int type) { int type) {
ssh_private_key privkey = NULL; ssh_private_key privkey = NULL;
FILE *file = NULL;
#ifdef HAVE_LIBGCRYPT #ifdef HAVE_LIBGCRYPT
FILE *file = NULL;
gcry_sexp_t dsa = NULL; gcry_sexp_t dsa = NULL;
gcry_sexp_t rsa = NULL; gcry_sexp_t rsa = NULL;
int valid; int valid;
#elif defined HAVE_LIBCRYPTO #elif defined HAVE_LIBCRYPTO
DSA *dsa = NULL; DSA *dsa = NULL;
RSA *rsa = NULL; RSA *rsa = NULL;
BIO *bio = NULL;
#endif #endif
#ifdef HAVE_LIBGCRYPT
file = fopen(filename,"r"); file = fopen(filename,"r");
if (file == NULL) { if (file == NULL) {
ssh_set_error(session, SSH_REQUEST_DENIED, ssh_set_error(session, SSH_REQUEST_DENIED,
"Error opening %s: %s", filename, strerror(errno)); "Error opening %s: %s", filename, strerror(errno));
return NULL; return NULL;
} }
#elif defined HAVE_LIBCRYPTO
bio = BIO_new_file(filename,"r");
if (bio == NULL) {
ssh_set_error(session, SSH_FATAL, "Could not create BIO.");
return NULL;
}
#endif
switch (type) { switch (type) {
case SSH_KEYTYPE_DSS: case SSH_KEYTYPE_DSS:
@@ -855,14 +882,16 @@ ssh_private_key _privatekey_from_file(void *session, const char *filename,
if (!valid) { if (!valid) {
ssh_set_error(session, SSH_FATAL, "Parsing private key %s", filename); ssh_set_error(session, SSH_FATAL, "Parsing private key %s", filename);
#elif defined HAVE_LIBCRYPTO #elif defined HAVE_LIBCRYPTO
dsa = PEM_read_DSAPrivateKey(file, NULL, NULL, NULL); dsa = PEM_read_bio_DSAPrivateKey(bio, NULL, NULL, NULL);
fclose(file); BIO_free(bio);
if (dsa == NULL) { if (dsa == NULL) {
ssh_set_error(session, SSH_FATAL, ssh_set_error(session, SSH_FATAL,
"Parsing private key %s: %s", "Parsing private key %s: %s",
filename, ERR_error_string(ERR_get_error(), NULL)); filename, ERR_error_string(ERR_get_error(), NULL));
#else
{
#endif #endif
return NULL; return NULL;
} }
@@ -876,19 +905,26 @@ ssh_private_key _privatekey_from_file(void *session, const char *filename,
if (!valid) { if (!valid) {
ssh_set_error(session, SSH_FATAL, "Parsing private key %s", filename); ssh_set_error(session, SSH_FATAL, "Parsing private key %s", filename);
#elif defined HAVE_LIBCRYPTO #elif defined HAVE_LIBCRYPTO
rsa = PEM_read_RSAPrivateKey(file, NULL, NULL, NULL); rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
fclose(file); BIO_free(bio);
if (rsa == NULL) { if (rsa == NULL) {
ssh_set_error(session, SSH_FATAL, ssh_set_error(session, SSH_FATAL,
"Parsing private key %s: %s", "Parsing private key %s: %s",
filename, ERR_error_string(ERR_get_error(), NULL)); filename, ERR_error_string(ERR_get_error(), NULL));
#else
{
#endif #endif
return NULL; return NULL;
} }
break; break;
default: default:
#ifdef HAVE_LIBGCRYPT
fclose(file);
#elif defined HAVE_LIBCRYPTO
BIO_free(bio);
#endif
ssh_set_error(session, SSH_FATAL, "Invalid private key type %d", type); ssh_set_error(session, SSH_FATAL, "Invalid private key type %d", type);
return NULL; return NULL;
} }

View File

@@ -597,7 +597,9 @@ error:
ssh_string_free(n); ssh_string_free(n);
return rc; return rc;
#if defined(HAVE_LIBGCRYPT) || defined(HAVE_LIBCRYPTO)
} }
#endif
#ifdef HAVE_LIBGCRYPT #ifdef HAVE_LIBGCRYPT
static int rsa_public_to_string(gcry_sexp_t key, ssh_buffer buffer) { static int rsa_public_to_string(gcry_sexp_t key, ssh_buffer buffer) {
@@ -665,7 +667,9 @@ error:
ssh_string_free(n); ssh_string_free(n);
return rc; return rc;
#if defined(HAVE_LIBGCRYPT) || defined(HAVE_LIBCRYPTO)
} }
#endif
/** /**
* @brief Convert a public_key object into a a SSH string. * @brief Convert a public_key object into a a SSH string.

View File

@@ -24,7 +24,9 @@
* compatibility * compatibility
*/ */
#include <libssh/libssh.h> #include "config.h"
#include <libssh/priv.h>
#include <libssh/server.h> #include <libssh/server.h>
#include <libssh/buffer.h> #include <libssh/buffer.h>
@@ -240,4 +242,18 @@ char *string_to_char(ssh_string str){
int ssh_accept(ssh_session session) { int ssh_accept(ssh_session session) {
return ssh_handle_key_exchange(session); return ssh_handle_key_exchange(session);
} }
int channel_write_stderr(ssh_channel channel, const void *data, uint32_t len) {
return ssh_channel_write(channel, data, len);
}
/** @deprecated
* @brief Interface previously exported by error.
*/
ssh_message ssh_message_retrieve(ssh_session session, uint32_t packettype){
(void) packettype;
ssh_set_error(session, SSH_FATAL, "ssh_message_retrieve: obsolete libssh call");
return NULL;
}
#endif /* WITH_SERVER */ #endif /* WITH_SERVER */

View File

@@ -21,6 +21,8 @@
* MA 02111-1307, USA. * MA 02111-1307, USA.
*/ */
#include "config.h"
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@@ -67,6 +69,51 @@ static ssh_message ssh_message_new(ssh_session session){
return msg; return msg;
} }
#ifndef WITH_SERVER
/* Reduced version of the reply default that only reply with
* SSH_MSG_UNIMPLEMENTED
*/
static int ssh_message_reply_default(ssh_message msg) {
ssh_log(msg->session, SSH_LOG_FUNCTIONS, "Reporting unknown packet");
if (buffer_add_u8(msg->session->out_buffer, SSH2_MSG_UNIMPLEMENTED) < 0)
goto error;
if (buffer_add_u32(msg->session->out_buffer,
htonl(msg->session->recv_seq-1)) < 0)
goto error;
return packet_send(msg->session);
error:
return SSH_ERROR;
}
#endif
static int ssh_execute_message_callback(ssh_session session, ssh_message msg) {
int ret;
if(session->ssh_message_callback != NULL) {
ret = session->ssh_message_callback(session, msg,
session->ssh_message_callback_data);
if(ret == 1) {
ret = ssh_message_reply_default(msg);
ssh_message_free(msg);
if(ret != SSH_OK) {
return ret;
}
} else {
ssh_message_free(msg);
}
} else {
ret = ssh_message_reply_default(msg);
ssh_message_free(msg);
if(ret != SSH_OK) {
return ret;
}
}
return SSH_OK;
}
/** /**
* @internal * @internal
* *
@@ -77,12 +124,16 @@ static ssh_message ssh_message_new(ssh_session session){
* @param[in] message The message to add to the queue. * @param[in] message The message to add to the queue.
*/ */
void ssh_message_queue(ssh_session session, ssh_message message){ void ssh_message_queue(ssh_session session, ssh_message message){
if(message){ if(message) {
if(session->ssh_message_list == NULL){ if(session->ssh_message_list == NULL) {
session->ssh_message_list=ssh_list_new(); if(session->ssh_message_callback != NULL) {
ssh_execute_message_callback(session, message);
return;
}
session->ssh_message_list = ssh_list_new();
}
ssh_list_append(session->ssh_message_list, message);
} }
ssh_list_append(session->ssh_message_list, message);
}
} }
/** /**
@@ -130,7 +181,7 @@ ssh_message ssh_message_get(ssh_session session) {
session->ssh_message_list = ssh_list_new(); session->ssh_message_list = ssh_list_new();
} }
do { do {
if (ssh_handle_packets(session,-1) == SSH_ERROR) { if (ssh_handle_packets(session, -2) == SSH_ERROR) {
leave_function(); leave_function();
return NULL; return NULL;
} }

View File

@@ -22,14 +22,22 @@
* MA 02111-1307, USA. * MA 02111-1307, USA.
*/ */
#include "config.h"
#ifndef _WIN32 #ifndef _WIN32
/* This is needed for a standard getpwuid_r on opensolaris */ /* This is needed for a standard getpwuid_r on opensolaris */
#define _POSIX_PTHREAD_SEMANTICS #define _POSIX_PTHREAD_SEMANTICS
#include <pwd.h> #include <pwd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#endif
#include "config.h" #ifndef HAVE_CLOCK_GETTIME
#include <sys/time.h>
#endif /* HAVE_CLOCK_GETTIME */
#endif /* _WIN32 */
#include <limits.h> #include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@@ -37,6 +45,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <ctype.h> #include <ctype.h>
#include <time.h>
#ifdef _WIN32 #ifdef _WIN32
@@ -136,7 +145,7 @@ char *ssh_get_local_username(ssh_session session) {
/* get the size */ /* get the size */
GetUserName(NULL, &size); GetUserName(NULL, &size);
user = malloc(size); user = (char *) malloc(size);
if (user == NULL) { if (user == NULL) {
ssh_set_error_oom(session); ssh_set_error_oom(session);
return NULL; return NULL;
@@ -148,6 +157,49 @@ char *ssh_get_local_username(ssh_session session) {
return NULL; return NULL;
} }
int ssh_is_ipaddr_v4(const char *str) {
struct sockaddr_storage ss;
int sslen = sizeof(ss);
int rc = SOCKET_ERROR;
/* WSAStringToAddressA thinks that 0.0.0 is a valid IP */
if (strlen(str) < 7) {
return 0;
}
rc = WSAStringToAddressA((LPSTR) str,
AF_INET,
NULL,
(struct sockaddr*)&ss,
&sslen);
if (rc == 0) {
return 1;
}
return 0;
}
int ssh_is_ipaddr(const char *str) {
int rc = SOCKET_ERROR;
if (strchr(str, ':')) {
struct sockaddr_storage ss;
int sslen = sizeof(ss);
/* TODO link-local (IP:v6:addr%ifname). */
rc = WSAStringToAddressA((LPSTR) str,
AF_INET6,
NULL,
(struct sockaddr*)&ss,
&sslen);
if (rc == 0) {
return 1;
}
}
return ssh_is_ipaddr_v4(str);
}
#else /* _WIN32 */ #else /* _WIN32 */
#ifndef NSS_BUFLEN_PASSWD #ifndef NSS_BUFLEN_PASSWD
@@ -163,7 +215,8 @@ char *ssh_get_user_home_dir(void) {
rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf); rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf);
if (rc != 0) { if (rc != 0) {
return NULL; szPath=getenv("HOME");
return szPath ? strdup(szPath) : NULL;
} }
szPath = strdup(pwd.pw_dir); szPath = strdup(pwd.pw_dir);
@@ -203,20 +256,51 @@ char *ssh_get_local_username(ssh_session session) {
return name; return name;
} }
int ssh_is_ipaddr_v4(const char *str) {
int rc = -1;
struct in_addr dest;
rc = inet_pton(AF_INET, str, &dest);
if (rc > 0) {
return 1;
}
return 0;
}
int ssh_is_ipaddr(const char *str) {
int rc = -1;
if (strchr(str, ':')) {
struct in6_addr dest6;
/* TODO link-local (IP:v6:addr%ifname). */
rc = inet_pton(AF_INET6, str, &dest6);
if (rc > 0) {
return 1;
}
}
return ssh_is_ipaddr_v4(str);
}
#endif /* _WIN32 */ #endif /* _WIN32 */
#ifndef HAVE_NTOHLL
uint64_t ntohll(uint64_t a) { uint64_t ntohll(uint64_t a) {
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
return a; return a;
#else #else /* WORDS_BIGENDIAN */
uint32_t low = (uint32_t)(a & 0xffffffff); uint32_t low = (uint32_t)(a & 0xffffffff);
uint32_t high = (uint32_t)(a >> 32); uint32_t high = (uint32_t)(a >> 32);
low = ntohl(low); low = ntohl(low);
high = ntohl(high); high = ntohl(high);
return ((((uint64_t) low) << 32) | ( high)); return ((((uint64_t) low) << 32) | ( high));
#endif #endif /* WORDS_BIGENDIAN */
} }
#endif /* HAVE_NTOHLL */
char *ssh_lowercase(const char* str) { char *ssh_lowercase(const char* str) {
char *new, *p; char *new, *p;
@@ -779,6 +863,99 @@ int ssh_analyze_banner(ssh_session session, int server, int *ssh1, int *ssh2) {
return 0; return 0;
} }
/* try the Monotonic clock if possible for perfs reasons */
#ifdef _POSIX_MONOTONIC_CLOCK
#define CLOCK CLOCK_MONOTONIC
#else
#define CLOCK CLOCK_REALTIME
#endif
/**
* @internal
* @brief initializes a timestamp to the current time
* @param[out] ts pointer to an allocated ssh_timestamp structure
*/
void ssh_timestamp_init(struct ssh_timestamp *ts){
#ifdef HAVE_CLOCK_GETTIME
struct timespec tp;
clock_gettime(CLOCK, &tp);
ts->useconds = tp.tv_nsec / 1000;
#else
struct timeval tp;
gettimeofday(&tp, NULL);
ts->useconds = tp.tv_usec;
#endif
ts->seconds = tp.tv_sec;
}
#undef CLOCK
/**
* @internal
* @brief gets the time difference between two timestamps in ms
* @param[in] old older value
* @param[in] new newer value
* @returns difference in milliseconds
*/
static int ssh_timestamp_difference(struct ssh_timestamp *old,
struct ssh_timestamp *new){
long seconds, usecs, msecs;
seconds = new->seconds - old->seconds;
usecs = new->useconds - old->useconds;
if (usecs < 0){
seconds--;
usecs += 1000000;
}
msecs = seconds * 1000 + usecs/1000;
return msecs;
}
/**
* @internal
* @brief Checks if a timeout is elapsed, in function of a previous
* timestamp and an assigned timeout
* @param[in] ts pointer to an existing timestamp
* @param[in] timeout timeout in milliseconds. Negative values mean infinite
* timeout
* @returns 1 if timeout is elapsed
* 0 otherwise
*/
int ssh_timeout_elapsed(struct ssh_timestamp *ts, int timeout) {
struct ssh_timestamp now;
if(timeout < 0)
return 0; // -1 means infinite timeout
if(timeout == 0)
return 1; // 0 means no timeout
ssh_timestamp_init(&now);
if(ssh_timestamp_difference(ts,&now) >= timeout)
return 1;
else
return 0;
}
/**
* @brief updates a timeout value so it reflects the remaining time
* @param[in] ts pointer to an existing timestamp
* @param[in] timeout timeout in milliseconds. Negative values mean infinite
* timeout
* @returns remaining time in milliseconds, 0 if elapsed, -1 if never,
* -2 if option-set-timeout.
*/
int ssh_timeout_update(struct ssh_timestamp *ts, int timeout){
struct ssh_timestamp now;
int ms, ret;
if (timeout <= 0) {
return timeout;
}
ssh_timestamp_init(&now);
ms = ssh_timestamp_difference(ts,&now);
if(ms < 0)
ms = 0;
ret = timeout - ms;
return ret >= 0 ? ret: 0;
}
/** @} */ /** @} */
/* vim: set ts=4 sw=4 et cindent: */ /* vim: set ts=4 sw=4 et cindent: */

View File

@@ -255,7 +255,9 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
"After padding, %d bytes left in buffer", "After padding, %d bytes left in buffer",
buffer_get_rest_len(session->in_buffer)); buffer_get_rest_len(session->in_buffer));
#if defined(HAVE_LIBZ) && defined(WITH_LIBZ) #if defined(HAVE_LIBZ) && defined(WITH_LIBZ)
if (session->current_crypto && session->current_crypto->do_compress_in) { if (session->current_crypto
&& session->current_crypto->do_compress_in
&& buffer_get_rest_len(session->in_buffer)) {
ssh_log(session, SSH_LOG_PACKET, "Decompressing in_buffer ..."); ssh_log(session, SSH_LOG_PACKET, "Decompressing in_buffer ...");
if (decompress_buffer(session, session->in_buffer,MAX_PACKET_LEN) < 0) { if (decompress_buffer(session, session->in_buffer,MAX_PACKET_LEN) < 0) {
goto error; goto error;
@@ -457,7 +459,9 @@ static int packet_send2(ssh_session session) {
"Writing on the wire a packet having %u bytes before", currentlen); "Writing on the wire a packet having %u bytes before", currentlen);
#if defined(HAVE_LIBZ) && defined(WITH_LIBZ) #if defined(HAVE_LIBZ) && defined(WITH_LIBZ)
if (session->current_crypto && session->current_crypto->do_compress_out) { if (session->current_crypto
&& session->current_crypto->do_compress_out
&& buffer_get_rest_len(session->out_buffer)) {
ssh_log(session, SSH_LOG_PACKET, "Compressing out_buffer ..."); ssh_log(session, SSH_LOG_PACKET, "Compressing out_buffer ...");
if (compress_buffer(session,session->out_buffer) < 0) { if (compress_buffer(session,session->out_buffer) < 0) {
goto error; goto error;

View File

@@ -125,7 +125,7 @@ struct ssh_pcap_file_struct {
ssh_pcap_file ssh_pcap_file_new(){ ssh_pcap_file ssh_pcap_file_new(){
struct ssh_pcap_file_struct *pcap; struct ssh_pcap_file_struct *pcap;
pcap = malloc(sizeof(struct ssh_pcap_file_struct)); pcap = (struct ssh_pcap_file_struct *) malloc(sizeof(struct ssh_pcap_file_struct));
if (pcap == NULL) { if (pcap == NULL) {
return NULL; return NULL;
} }
@@ -228,7 +228,7 @@ void ssh_pcap_file_free(ssh_pcap_file pcap){
*/ */
ssh_pcap_context ssh_pcap_context_new(ssh_session session){ ssh_pcap_context ssh_pcap_context_new(ssh_session session){
ssh_pcap_context ctx=malloc(sizeof(struct ssh_pcap_context_struct)); ssh_pcap_context ctx = (struct ssh_pcap_context_struct *) malloc(sizeof(struct ssh_pcap_context_struct));
if(ctx==NULL){ if(ctx==NULL){
ssh_set_error_oom(session); ssh_set_error_oom(session);
return NULL; return NULL;

View File

@@ -105,29 +105,6 @@ static poll_fn ssh_poll_emu;
#include <time.h> #include <time.h>
#include <windows.h> #include <windows.h>
#include <winsock2.h> #include <winsock2.h>
#if (_WIN32_WINNT < 0x0600)
typedef struct ssh_pollfd_struct WSAPOLLFD;
#endif
typedef int (WSAAPI* WSAPoll_FunctionType)(WSAPOLLFD fdarray[],
ULONG nfds,
INT timeout
);
static WSAPoll_FunctionType wsa_poll;
int win_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
if (wsa_poll) {
return (wsa_poll)((WSAPOLLFD *) fds, nfds, timeout);
}
return SOCKET_ERROR;
}
#define WS2_LIBRARY "ws2_32.dll"
static HINSTANCE hlib;
#else /* _WIN32 */ #else /* _WIN32 */
#include <sys/select.h> #include <sys/select.h>
#include <sys/socket.h> #include <sys/socket.h>
@@ -261,30 +238,10 @@ static int bsd_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
void ssh_poll_init(void) { void ssh_poll_init(void) {
ssh_poll_emu = bsd_poll; ssh_poll_emu = bsd_poll;
#ifdef _WIN32
hlib = LoadLibrary(WS2_LIBRARY);
if (hlib != NULL) {
wsa_poll = (WSAPoll_FunctionType) (void *) GetProcAddress(hlib, "WSAPoll");
}
#endif /* _WIN32 */
if (wsa_poll == NULL) {
ssh_poll_emu = bsd_poll;
} else {
ssh_poll_emu = win_poll;
}
} }
void ssh_poll_cleanup(void) { void ssh_poll_cleanup(void) {
ssh_poll_emu = bsd_poll; ssh_poll_emu = bsd_poll;
#ifdef _WIN32
wsa_poll = NULL;
FreeLibrary(hlib);
hlib = NULL;
#endif /* _WIN32 */
} }
int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) { int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
@@ -298,8 +255,9 @@ int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
* *
* @param fd Socket that will be polled. * @param fd Socket that will be polled.
* @param events Poll events that will be monitored for the socket. i.e. * @param events Poll events that will be monitored for the socket. i.e.
* POLLIN, POLLPRI, POLLOUT, POLLERR, POLLHUP, POLLNVAL * POLLIN, POLLPRI, POLLOUT
* @param cb Function to be called if any of the events are set. * @param cb Function to be called if any of the events are set.
*
* @param userdata Userdata to be passed to the callback function. NULL if * @param userdata Userdata to be passed to the callback function. NULL if
* not needed. * not needed.
* *
@@ -490,8 +448,13 @@ void ssh_poll_ctx_free(ssh_poll_ctx ctx) {
socket_t fd = ctx->pollfds[i].fd; socket_t fd = ctx->pollfds[i].fd;
/* force poll object removal */ /* force poll object removal */
if (p->cb(p, fd, POLLERR, p->cb_data) < 0) { if (p->cb && p->cb(p, fd, POLLERR, p->cb_data) < 0) {
used = ctx->polls_used; if(ctx->polls_used < used) {
used = ctx->polls_used;
} else {
/* nothing to do */
i++;
}
} else { } else {
i++; i++;
} }
@@ -622,6 +585,7 @@ void ssh_poll_ctx_remove(ssh_poll_ctx ctx, ssh_poll_handle p) {
* the poll() function. * the poll() function.
* @returns SSH_OK No error. * @returns SSH_OK No error.
* SSH_ERROR Error happened during the poll. * SSH_ERROR Error happened during the poll.
* SSH_AGAIN Timeout occured
*/ */
int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout) { int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout) {
@@ -636,19 +600,24 @@ int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout) {
rc = ssh_poll(ctx->pollfds, ctx->polls_used, timeout); rc = ssh_poll(ctx->pollfds, ctx->polls_used, timeout);
if(rc < 0) if(rc < 0)
rc=SSH_ERROR; return SSH_ERROR;
if(rc <= 0) if (rc == 0)
return rc; return SSH_AGAIN;
used = ctx->polls_used; used = ctx->polls_used;
for (i = 0; i < used && rc > 0; ) { for (i = 0; i < used && rc > 0; ) {
if (!ctx->pollfds[i].revents) { if (!ctx->pollfds[i].revents) {
i++; i++;
} else { } else {
int ret;
p = ctx->pollptrs[i]; p = ctx->pollptrs[i];
fd = ctx->pollfds[i].fd; fd = ctx->pollfds[i].fd;
revents = ctx->pollfds[i].revents; revents = ctx->pollfds[i].revents;
if (p->cb(p, fd, revents, p->cb_data) < 0) { if (p->cb && (ret = p->cb(p, fd, revents, p->cb_data)) < 0) {
if (ret == -2) {
return -1;
}
/* the poll was removed, reload the used counter and start again */ /* the poll was removed, reload the used counter and start again */
used = ctx->polls_used; used = ctx->polls_used;
i=0; i=0;

View File

@@ -148,7 +148,7 @@ int ssh_scp_close(ssh_scp scp){
*/ */
while(!ssh_channel_is_eof(scp->channel)){ while(!ssh_channel_is_eof(scp->channel)){
err=ssh_channel_read(scp->channel,buffer,sizeof(buffer),0); err=ssh_channel_read(scp->channel,buffer,sizeof(buffer),0);
if(err==SSH_ERROR) if(err==SSH_ERROR || err==0)
break; break;
} }
if(ssh_channel_close(scp->channel) == SSH_ERROR){ if(ssh_channel_close(scp->channel) == SSH_ERROR){
@@ -380,8 +380,8 @@ int ssh_scp_response(ssh_scp scp, char **response){
*/ */
int ssh_scp_write(ssh_scp scp, const void *buffer, size_t len){ int ssh_scp_write(ssh_scp scp, const void *buffer, size_t len){
int w; int w;
//int r; int r;
//uint8_t code; uint8_t code;
if(scp==NULL) if(scp==NULL)
return SSH_ERROR; return SSH_ERROR;
if(scp->state != SSH_SCP_WRITE_WRITING){ if(scp->state != SSH_SCP_WRITE_WRITING){
@@ -400,19 +400,27 @@ int ssh_scp_write(ssh_scp scp, const void *buffer, size_t len){
//return=channel_get_exit_status(scp->channel); //return=channel_get_exit_status(scp->channel);
return SSH_ERROR; return SSH_ERROR;
} }
/* Far end sometimes send a status message, which we need to read
* and handle */
r = ssh_channel_poll(scp->channel,0);
if(r > 0){
r = ssh_channel_read(scp->channel, &code, 1, 0);
if(r == SSH_ERROR){
return SSH_ERROR;
}
if(code == 1 || code == 2){
ssh_set_error(scp->session,SSH_REQUEST_DENIED, "SCP: Error: status code %i received", code);
return SSH_ERROR;
}
}
/* Check if we arrived at end of file */ /* Check if we arrived at end of file */
if(scp->processed == scp->filelen) { if(scp->processed == scp->filelen) {
/* r=channel_read(scp->channel,&code,1,0); code = 0;
if(r==SSH_ERROR){ w = ssh_channel_write(scp->channel, &code, 1);
scp->state=SSH_SCP_ERROR; if(w == SSH_ERROR){
scp->state = SSH_SCP_ERROR;
return SSH_ERROR; return SSH_ERROR;
} }
if(code != 0){
ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code);
scp->state=SSH_SCP_ERROR;
return SSH_ERROR;
}
*/
scp->processed=scp->filelen=0; scp->processed=scp->filelen=0;
scp->state=SSH_SCP_WRITE_INITED; scp->state=SSH_SCP_WRITE_INITED;
} }

View File

@@ -104,7 +104,7 @@ static int server_set_kex(ssh_session session) {
} }
} }
server->methods = malloc(10 * sizeof(char **)); server->methods = (char **) malloc(10 * sizeof(char **));
if (server->methods == NULL) { if (server->methods == NULL) {
return -1; return -1;
} }
@@ -479,8 +479,8 @@ int ssh_handle_key_exchange(ssh_session session) {
* loop until SSH_SESSION_STATE_BANNER_RECEIVED or * loop until SSH_SESSION_STATE_BANNER_RECEIVED or
* SSH_SESSION_STATE_ERROR * SSH_SESSION_STATE_ERROR
*/ */
ssh_handle_packets(session,-1); ssh_handle_packets(session, -2);
ssh_log(session,SSH_LOG_PACKET, "ssh_accept: Actual state : %d", ssh_log(session,SSH_LOG_PACKET, "ssh_handle_key_exchange: Actual state : %d",
session->session_state); session->session_state);
} }
@@ -616,10 +616,13 @@ static int ssh_message_service_request_reply_default(ssh_message msg) {
int ssh_message_service_reply_success(ssh_message msg) { int ssh_message_service_reply_success(ssh_message msg) {
struct ssh_string_struct *service; struct ssh_string_struct *service;
ssh_session session=msg->session; ssh_session session;
if (msg == NULL) { if (msg == NULL) {
return SSH_ERROR; return SSH_ERROR;
} }
session = msg->session;
ssh_log(session, SSH_LOG_PACKET, ssh_log(session, SSH_LOG_PACKET,
"Sending a SERVICE_ACCEPT for service %s", msg->service_request.service); "Sending a SERVICE_ACCEPT for service %s", msg->service_request.service);
if (buffer_add_u8(session->out_buffer, SSH2_MSG_SERVICE_ACCEPT) < 0) { if (buffer_add_u8(session->out_buffer, SSH2_MSG_SERVICE_ACCEPT) < 0) {

View File

@@ -297,6 +297,40 @@ int ssh_is_blocking(ssh_session session){
return (session->flags&SSH_SESSION_FLAG_BLOCKING) ? 1 : 0; return (session->flags&SSH_SESSION_FLAG_BLOCKING) ? 1 : 0;
} }
/**
* @brief Blocking flush of the outgoing buffer
* @param[in] session The SSH session
* @param[in] timeout Set an upper limit on the time for which this function
* will block, in milliseconds. Specifying a negative value
* means an infinite timeout. This parameter is passed to
* the poll() function.
* @returns SSH_OK on success, SSH_AGAIN if timeout occurred,
* SSH_ERROR otherwise.
*/
int ssh_blocking_flush(ssh_session session, int timeout){
ssh_socket s;
struct ssh_timestamp ts;
int rc = SSH_OK;
if(session==NULL)
return SSH_ERROR;
enter_function();
s=session->socket;
ssh_timestamp_init(&ts);
while (ssh_socket_buffered_write_bytes(s) > 0 && session->alive) {
rc=ssh_handle_packets(session, timeout);
if(ssh_timeout_elapsed(&ts,timeout)){
rc=SSH_AGAIN;
break;
}
timeout = ssh_timeout_update(&ts, timeout);
}
leave_function();
return rc;
}
/** /**
* @brief Check if we are connected. * @brief Check if we are connected.
* *
@@ -370,6 +404,17 @@ void ssh_set_fd_except(ssh_session session) {
ssh_socket_set_except(session->socket); ssh_socket_set_except(session->socket);
} }
static int ssh_make_milliseconds(long sec, long usec) {
int res = usec ? (usec / 1000) : 0;
res += (sec * 1000);
if (res == 0) {
res = 10 * 1000; /* use a reasonable default value in case
* SSH_OPTIONS_TIMEOUT is not set in options. */
}
return res;
}
/** /**
* @internal * @internal
* *
@@ -381,33 +426,56 @@ void ssh_set_fd_except(ssh_session session) {
* @param[in] session The session handle to use. * @param[in] session The session handle to use.
* *
* @param[in] timeout Set an upper limit on the time for which this function * @param[in] timeout Set an upper limit on the time for which this function
* will block, in milliseconds. Specifying a negative value * will block, in milliseconds. Specifying -1
* means an infinite timeout. This parameter is passed to * means an infinite timeout.
* the poll() function. * Specifying -2 means to use the timeout specified in
* options. 0 means poll will return immediately. This
* parameter is passed to the poll() function.
* *
* @return SSH_OK on success, SSH_ERROR otherwise. * @return SSH_OK on success, SSH_ERROR otherwise.
*/ */
int ssh_handle_packets(ssh_session session, int timeout) { int ssh_handle_packets(ssh_session session, int timeout) {
ssh_poll_handle spoll_in,spoll_out; ssh_poll_handle spoll_in,spoll_out;
ssh_poll_ctx ctx; ssh_poll_ctx ctx;
if(session==NULL || session->socket==NULL) int tm = timeout;
return SSH_ERROR; int rc;
enter_function();
spoll_in=ssh_socket_get_poll_handle_in(session->socket); if (session == NULL || session->socket == NULL) {
spoll_out=ssh_socket_get_poll_handle_out(session->socket); return SSH_ERROR;
ctx=ssh_poll_get_ctx(spoll_in); }
if(ctx==NULL){ enter_function();
ctx=ssh_poll_get_default_ctx(session);
ssh_poll_ctx_add(ctx,spoll_in); spoll_in = ssh_socket_get_poll_handle_in(session->socket);
if(spoll_in != spoll_out) spoll_out = ssh_socket_get_poll_handle_out(session->socket);
ssh_poll_ctx_add(ctx,spoll_out); if (session->server) {
} ssh_poll_add_events(spoll_in, POLLIN);
ssh_poll_ctx_dopoll(ctx,timeout); }
leave_function(); ctx = ssh_poll_get_ctx(spoll_in);
if (session->session_state != SSH_SESSION_STATE_ERROR)
return SSH_OK; if (!ctx) {
else ctx = ssh_poll_get_default_ctx(session);
return SSH_ERROR; ssh_poll_ctx_add(ctx, spoll_in);
if (spoll_in != spoll_out) {
ssh_poll_ctx_add(ctx, spoll_out);
}
}
if (timeout == -2) {
tm = ssh_make_milliseconds(session->timeout, session->timeout_usec);
}
rc = ssh_poll_ctx_dopoll(ctx, tm);
if (rc == SSH_ERROR) {
session->session_state = SSH_SESSION_STATE_ERROR;
}
leave_function();
if (session->session_state == SSH_SESSION_STATE_ERROR) {
return SSH_ERROR;
}
return SSH_OK;
} }
/** /**
@@ -432,17 +500,19 @@ int ssh_handle_packets(ssh_session session, int timeout) {
int ssh_handle_packets_termination(ssh_session session, int timeout, int ssh_handle_packets_termination(ssh_session session, int timeout,
ssh_termination_function fct, void *user){ ssh_termination_function fct, void *user){
int ret = SSH_ERROR; int ret = SSH_ERROR;
struct ssh_timestamp ts;
ssh_timestamp_init(&ts);
while(!fct(user)){ while(!fct(user)){
ret = ssh_handle_packets(session, timeout); ret = ssh_handle_packets(session, timeout);
if(ret == SSH_ERROR) if(ret == SSH_ERROR)
return SSH_ERROR; return SSH_ERROR;
if(timeout == 0){ if(fct(user)) {
if(fct(user)) return SSH_OK;
return SSH_OK; } else if (ssh_timeout_elapsed(&ts, timeout)) {
else return SSH_AGAIN;
return SSH_AGAIN;
} }
/* TODO: verify that total timeout has not expired and then return SSH_AGAIN */ timeout = ssh_timeout_update(&ts,timeout);
} }
return ret; return ret;
} }
@@ -552,6 +622,7 @@ SSH_PACKET_CALLBACK(ssh_packet_disconnect_callback){
ssh_socket_close(session->socket); ssh_socket_close(session->socket);
session->alive = 0; session->alive = 0;
session->session_state= SSH_SESSION_STATE_ERROR;
/* TODO: handle a graceful disconnect */ /* TODO: handle a graceful disconnect */
return SSH_PACKET_USED; return SSH_PACKET_USED;
} }

View File

@@ -1817,7 +1817,7 @@ ssize_t sftp_read(sftp_file handle, void *buf, size_t count) {
if (ssh_string_len(datastring) > count) { if (ssh_string_len(datastring) > count) {
ssh_set_error(sftp->session, SSH_FATAL, ssh_set_error(sftp->session, SSH_FATAL,
"Received a too big DATA packet from sftp server: " "Received a too big DATA packet from sftp server: "
"%zu and asked for %zu", "%" PRIdS " and asked for %" PRIdS,
ssh_string_len(datastring), count); ssh_string_len(datastring), count);
ssh_string_free(datastring); ssh_string_free(datastring);
return -1; return -1;
@@ -1938,7 +1938,7 @@ int sftp_async_read(sftp_file file, void *data, uint32_t size, uint32_t id){
if (ssh_string_len(datastring) > size) { if (ssh_string_len(datastring) > size) {
ssh_set_error(sftp->session, SSH_FATAL, ssh_set_error(sftp->session, SSH_FATAL,
"Received a too big DATA packet from sftp server: " "Received a too big DATA packet from sftp server: "
"%zu and asked for %u", "%" PRIdS " and asked for %u",
ssh_string_len(datastring), size); ssh_string_len(datastring), size);
ssh_string_free(datastring); ssh_string_free(datastring);
sftp_leave_function(); sftp_leave_function();
@@ -2054,6 +2054,7 @@ int sftp_seek(sftp_file file, uint32_t new_offset) {
} }
file->offset = new_offset; file->offset = new_offset;
file->eof = 0;
return 0; return 0;
} }
@@ -2064,6 +2065,7 @@ int sftp_seek64(sftp_file file, uint64_t new_offset) {
} }
file->offset = new_offset; file->offset = new_offset;
file->eof = 0;
return 0; return 0;
} }
@@ -2080,6 +2082,7 @@ uint64_t sftp_tell64(sftp_file file) {
/* Rewinds the position of the file pointer to the beginning of the file.*/ /* Rewinds the position of the file pointer to the beginning of the file.*/
void sftp_rewind(sftp_file file) { void sftp_rewind(sftp_file file) {
file->offset = 0; file->offset = 0;
file->eof = 0;
} }
/* code written by Nick */ /* code written by Nick */
@@ -2109,10 +2112,12 @@ int sftp_unlink(sftp_session sftp, const char *file) {
ssh_set_error_oom(sftp->session); ssh_set_error_oom(sftp->session);
ssh_buffer_free(buffer); ssh_buffer_free(buffer);
ssh_string_free(filename); ssh_string_free(filename);
return -1;
} }
if (sftp_packet_write(sftp, SSH_FXP_REMOVE, buffer) < 0) { if (sftp_packet_write(sftp, SSH_FXP_REMOVE, buffer) < 0) {
ssh_buffer_free(buffer); ssh_buffer_free(buffer);
ssh_string_free(filename); ssh_string_free(filename);
return -1;
} }
ssh_string_free(filename); ssh_string_free(filename);
ssh_buffer_free(buffer); ssh_buffer_free(buffer);

View File

@@ -37,6 +37,7 @@
#include "libssh/misc.h" #include "libssh/misc.h"
sftp_client_message sftp_get_client_message(sftp_session sftp) { sftp_client_message sftp_get_client_message(sftp_session sftp) {
ssh_session session = sftp->session;
sftp_packet packet; sftp_packet packet;
sftp_client_message msg; sftp_client_message msg;
ssh_buffer payload; ssh_buffer payload;
@@ -44,12 +45,14 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) {
msg = malloc(sizeof (struct sftp_client_message_struct)); msg = malloc(sizeof (struct sftp_client_message_struct));
if (msg == NULL) { if (msg == NULL) {
ssh_set_error_oom(session);
return NULL; return NULL;
} }
ZERO_STRUCTP(msg); ZERO_STRUCTP(msg);
packet = sftp_packet_read(sftp); packet = sftp_packet_read(sftp);
if (packet == NULL) { if (packet == NULL) {
ssh_set_error_oom(session);
sftp_client_message_free(msg); sftp_client_message_free(msg);
return NULL; return NULL;
} }
@@ -65,6 +68,7 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) {
case SSH_FXP_READDIR: case SSH_FXP_READDIR:
msg->handle = buffer_get_ssh_string(payload); msg->handle = buffer_get_ssh_string(payload);
if (msg->handle == NULL) { if (msg->handle == NULL) {
ssh_set_error_oom(session);
sftp_client_message_free(msg); sftp_client_message_free(msg);
return NULL; return NULL;
} }
@@ -72,6 +76,7 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) {
case SSH_FXP_READ: case SSH_FXP_READ:
msg->handle = buffer_get_ssh_string(payload); msg->handle = buffer_get_ssh_string(payload);
if (msg->handle == NULL) { if (msg->handle == NULL) {
ssh_set_error_oom(session);
sftp_client_message_free(msg); sftp_client_message_free(msg);
return NULL; return NULL;
} }
@@ -81,12 +86,14 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) {
case SSH_FXP_WRITE: case SSH_FXP_WRITE:
msg->handle = buffer_get_ssh_string(payload); msg->handle = buffer_get_ssh_string(payload);
if (msg->handle == NULL) { if (msg->handle == NULL) {
ssh_set_error_oom(session);
sftp_client_message_free(msg); sftp_client_message_free(msg);
return NULL; return NULL;
} }
buffer_get_u64(payload, &msg->offset); buffer_get_u64(payload, &msg->offset);
msg->data = buffer_get_ssh_string(payload); msg->data = buffer_get_ssh_string(payload);
if (msg->data == NULL) { if (msg->data == NULL) {
ssh_set_error_oom(session);
sftp_client_message_free(msg); sftp_client_message_free(msg);
return NULL; return NULL;
} }
@@ -98,12 +105,14 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) {
case SSH_FXP_REALPATH: case SSH_FXP_REALPATH:
tmp = buffer_get_ssh_string(payload); tmp = buffer_get_ssh_string(payload);
if (tmp == NULL) { if (tmp == NULL) {
ssh_set_error_oom(session);
sftp_client_message_free(msg); sftp_client_message_free(msg);
return NULL; return NULL;
} }
msg->filename = ssh_string_to_char(tmp); msg->filename = ssh_string_to_char(tmp);
ssh_string_free(tmp); ssh_string_free(tmp);
if (msg->filename == NULL) { if (msg->filename == NULL) {
ssh_set_error_oom(session);
sftp_client_message_free(msg); sftp_client_message_free(msg);
return NULL; return NULL;
} }
@@ -112,17 +121,20 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) {
case SSH_FXP_SYMLINK: case SSH_FXP_SYMLINK:
tmp = buffer_get_ssh_string(payload); tmp = buffer_get_ssh_string(payload);
if (tmp == NULL) { if (tmp == NULL) {
ssh_set_error_oom(session);
sftp_client_message_free(msg); sftp_client_message_free(msg);
return NULL; return NULL;
} }
msg->filename = ssh_string_to_char(tmp); msg->filename = ssh_string_to_char(tmp);
ssh_string_free(tmp); ssh_string_free(tmp);
if (msg->filename == NULL) { if (msg->filename == NULL) {
ssh_set_error_oom(session);
sftp_client_message_free(msg); sftp_client_message_free(msg);
return NULL; return NULL;
} }
msg->data = buffer_get_ssh_string(payload); msg->data = buffer_get_ssh_string(payload);
if (msg->data == NULL) { if (msg->data == NULL) {
ssh_set_error_oom(session);
sftp_client_message_free(msg); sftp_client_message_free(msg);
return NULL; return NULL;
} }
@@ -131,17 +143,20 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) {
case SSH_FXP_SETSTAT: case SSH_FXP_SETSTAT:
tmp = buffer_get_ssh_string(payload); tmp = buffer_get_ssh_string(payload);
if (tmp == NULL) { if (tmp == NULL) {
ssh_set_error_oom(session);
sftp_client_message_free(msg); sftp_client_message_free(msg);
return NULL; return NULL;
} }
msg->filename=ssh_string_to_char(tmp); msg->filename=ssh_string_to_char(tmp);
ssh_string_free(tmp); ssh_string_free(tmp);
if (msg->filename == NULL) { if (msg->filename == NULL) {
ssh_set_error_oom(session);
sftp_client_message_free(msg); sftp_client_message_free(msg);
return NULL; return NULL;
} }
msg->attr = sftp_parse_attr(sftp, payload, 0); msg->attr = sftp_parse_attr(sftp, payload, 0);
if (msg->attr == NULL) { if (msg->attr == NULL) {
ssh_set_error_oom(session);
sftp_client_message_free(msg); sftp_client_message_free(msg);
return NULL; return NULL;
} }
@@ -149,11 +164,13 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) {
case SSH_FXP_FSETSTAT: case SSH_FXP_FSETSTAT:
msg->handle = buffer_get_ssh_string(payload); msg->handle = buffer_get_ssh_string(payload);
if (msg->handle == NULL) { if (msg->handle == NULL) {
ssh_set_error_oom(session);
sftp_client_message_free(msg); sftp_client_message_free(msg);
return NULL; return NULL;
} }
msg->attr = sftp_parse_attr(sftp, payload, 0); msg->attr = sftp_parse_attr(sftp, payload, 0);
if (msg->attr == NULL) { if (msg->attr == NULL) {
ssh_set_error_oom(session);
sftp_client_message_free(msg); sftp_client_message_free(msg);
return NULL; return NULL;
} }
@@ -162,12 +179,14 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) {
case SSH_FXP_STAT: case SSH_FXP_STAT:
tmp = buffer_get_ssh_string(payload); tmp = buffer_get_ssh_string(payload);
if (tmp == NULL) { if (tmp == NULL) {
ssh_set_error_oom(session);
sftp_client_message_free(msg); sftp_client_message_free(msg);
return NULL; return NULL;
} }
msg->filename = ssh_string_to_char(tmp); msg->filename = ssh_string_to_char(tmp);
ssh_string_free(tmp); ssh_string_free(tmp);
if (msg->filename == NULL) { if (msg->filename == NULL) {
ssh_set_error_oom(session);
sftp_client_message_free(msg); sftp_client_message_free(msg);
return NULL; return NULL;
} }
@@ -178,31 +197,38 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) {
case SSH_FXP_OPEN: case SSH_FXP_OPEN:
tmp=buffer_get_ssh_string(payload); tmp=buffer_get_ssh_string(payload);
if (tmp == NULL) { if (tmp == NULL) {
ssh_set_error_oom(session);
sftp_client_message_free(msg); sftp_client_message_free(msg);
return NULL; return NULL;
} }
msg->filename = ssh_string_to_char(tmp); msg->filename = ssh_string_to_char(tmp);
ssh_string_free(tmp); ssh_string_free(tmp);
if (msg->filename == NULL) { if (msg->filename == NULL) {
ssh_set_error_oom(session);
sftp_client_message_free(msg); sftp_client_message_free(msg);
return NULL; return NULL;
} }
buffer_get_u32(payload,&msg->flags); buffer_get_u32(payload,&msg->flags);
msg->attr = sftp_parse_attr(sftp, payload, 0); msg->attr = sftp_parse_attr(sftp, payload, 0);
if (msg->attr == NULL) { if (msg->attr == NULL) {
ssh_set_error_oom(session);
sftp_client_message_free(msg); sftp_client_message_free(msg);
return NULL; return NULL;
} }
case SSH_FXP_FSTAT: case SSH_FXP_FSTAT:
msg->handle = buffer_get_ssh_string(payload); msg->handle = buffer_get_ssh_string(payload);
if (msg->handle == NULL) { if (msg->handle == NULL) {
ssh_set_error_oom(session);
sftp_client_message_free(msg); sftp_client_message_free(msg);
return NULL; return NULL;
} }
buffer_get_u32(payload, &msg->flags); buffer_get_u32(payload, &msg->flags);
break; break;
default: default:
fprintf(stderr, "Received unhandled sftp message %d\n", msg->type); ssh_set_error(sftp->session, SSH_FATAL,
"Received unhandled sftp message %d\n", msg->type);
sftp_client_message_free(msg);
return NULL;
} }
msg->flags = ntohl(msg->flags); msg->flags = ntohl(msg->flags);

View File

@@ -91,6 +91,8 @@ struct ssh_socket_struct {
ssh_poll_handle poll_out; ssh_poll_handle poll_out;
}; };
static int sockets_initialized = 0;
static int ssh_socket_unbuffered_read(ssh_socket s, void *buffer, uint32_t len); static int ssh_socket_unbuffered_read(ssh_socket s, void *buffer, uint32_t len);
static int ssh_socket_unbuffered_write(ssh_socket s, const void *buffer, static int ssh_socket_unbuffered_write(ssh_socket s, const void *buffer,
uint32_t len); uint32_t len);
@@ -100,16 +102,20 @@ static int ssh_socket_unbuffered_write(ssh_socket s, const void *buffer,
* \brief inits the socket system (windows specific) * \brief inits the socket system (windows specific)
*/ */
int ssh_socket_init(void) { int ssh_socket_init(void) {
if (sockets_initialized == 0) {
#ifdef _WIN32 #ifdef _WIN32
struct WSAData wsaData; struct WSAData wsaData;
/* Initiates use of the Winsock DLL by a process. */ /* Initiates use of the Winsock DLL by a process. */
if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) { if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
return -1; return -1;
} }
#endif #endif
ssh_poll_init(); ssh_poll_init();
sockets_initialized = 1;
}
return 0; return 0;
} }
@@ -118,7 +124,13 @@ int ssh_socket_init(void) {
* @brief Cleanup the socket system. * @brief Cleanup the socket system.
*/ */
void ssh_socket_cleanup(void) { void ssh_socket_cleanup(void) {
if (sockets_initialized == 1) {
ssh_poll_cleanup(); ssh_poll_cleanup();
#ifdef _WIN32
WSACleanup();
#endif
sockets_initialized = 0;
}
} }
@@ -131,6 +143,7 @@ ssh_socket ssh_socket_new(ssh_session session) {
s = malloc(sizeof(struct ssh_socket_struct)); s = malloc(sizeof(struct ssh_socket_struct));
if (s == NULL) { if (s == NULL) {
ssh_set_error_oom(session);
return NULL; return NULL;
} }
s->fd_in = SSH_INVALID_SOCKET; s->fd_in = SSH_INVALID_SOCKET;
@@ -140,11 +153,13 @@ ssh_socket ssh_socket_new(ssh_session session) {
s->session = session; s->session = session;
s->in_buffer = ssh_buffer_new(); s->in_buffer = ssh_buffer_new();
if (s->in_buffer == NULL) { if (s->in_buffer == NULL) {
ssh_set_error_oom(session);
SAFE_FREE(s); SAFE_FREE(s);
return NULL; return NULL;
} }
s->out_buffer=ssh_buffer_new(); s->out_buffer=ssh_buffer_new();
if (s->out_buffer == NULL) { if (s->out_buffer == NULL) {
ssh_set_error_oom(session);
ssh_buffer_free(s->in_buffer); ssh_buffer_free(s->in_buffer);
SAFE_FREE(s); SAFE_FREE(s);
return NULL; return NULL;
@@ -215,7 +230,7 @@ int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int r
/* Check if we are in a connecting state */ /* Check if we are in a connecting state */
if(s->state==SSH_SOCKET_CONNECTING){ if(s->state==SSH_SOCKET_CONNECTING){
s->state=SSH_SOCKET_ERROR; s->state=SSH_SOCKET_ERROR;
getsockopt(fd,SOL_SOCKET,SO_ERROR,(void *)&err,&errlen); getsockopt(fd,SOL_SOCKET,SO_ERROR,(char *)&err,&errlen);
s->last_errno=err; s->last_errno=err;
ssh_socket_close(s); ssh_socket_close(s);
if(s->callbacks && s->callbacks->connected) if(s->callbacks && s->callbacks->connected)
@@ -231,20 +246,34 @@ int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int r
s->read_wontblock=1; s->read_wontblock=1;
r=ssh_socket_unbuffered_read(s,buffer,sizeof(buffer)); r=ssh_socket_unbuffered_read(s,buffer,sizeof(buffer));
if(r<0){ if(r<0){
if(p != NULL) if(p != NULL) {
ssh_poll_set_events(p,ssh_poll_get_events(p) & ~POLLIN); ssh_poll_remove_events(p, POLLIN);
}
if(s->callbacks && s->callbacks->exception){ if(s->callbacks && s->callbacks->exception){
s->callbacks->exception( s->callbacks->exception(
SSH_SOCKET_EXCEPTION_ERROR, SSH_SOCKET_EXCEPTION_ERROR,
s->last_errno,s->callbacks->userdata); s->last_errno,s->callbacks->userdata);
/* p may have been freed, so don't use it
* anymore in this function */
p = NULL;
return -2;
} }
} }
if(r==0){ if(r==0){
ssh_poll_set_events(p,ssh_poll_get_events(p) & ~POLLIN); if(p != NULL) {
ssh_poll_remove_events(p, POLLIN);
}
if(p != NULL) {
ssh_poll_remove_events(p, POLLIN);
}
if(s->callbacks && s->callbacks->exception){ if(s->callbacks && s->callbacks->exception){
s->callbacks->exception( s->callbacks->exception(
SSH_SOCKET_EXCEPTION_EOF, SSH_SOCKET_EXCEPTION_EOF,
0,s->callbacks->userdata); 0,s->callbacks->userdata);
/* p may have been freed, so don't use it
* anymore in this function */
p = NULL;
return -2;
} }
} }
if(r>0){ if(r>0){
@@ -255,6 +284,9 @@ int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int r
buffer_get_rest_len(s->in_buffer), buffer_get_rest_len(s->in_buffer),
s->callbacks->userdata); s->callbacks->userdata);
buffer_pass_bytes(s->in_buffer,r); buffer_pass_bytes(s->in_buffer,r);
/* p may have been freed, so don't use it
* anymore in this function */
p = NULL;
} }
} }
} }
@@ -267,7 +299,7 @@ int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int r
if(s->state == SSH_SOCKET_CONNECTING){ if(s->state == SSH_SOCKET_CONNECTING){
ssh_log(s->session,SSH_LOG_PACKET,"Received POLLOUT in connecting state"); ssh_log(s->session,SSH_LOG_PACKET,"Received POLLOUT in connecting state");
s->state = SSH_SOCKET_CONNECTED; s->state = SSH_SOCKET_CONNECTED;
ssh_poll_set_events(p,POLLOUT | POLLIN | POLLERR); ssh_poll_set_events(p,POLLOUT | POLLIN);
ssh_sock_set_blocking(ssh_socket_get_fd_in(s)); ssh_sock_set_blocking(ssh_socket_get_fd_in(s));
if(s->callbacks && s->callbacks->connected) if(s->callbacks && s->callbacks->connected)
s->callbacks->connected(SSH_SOCKET_CONNECTED_OK,0,s->callbacks->userdata); s->callbacks->connected(SSH_SOCKET_CONNECTED_OK,0,s->callbacks->userdata);
@@ -275,7 +307,9 @@ int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int r
} }
/* So, we can write data */ /* So, we can write data */
s->write_wontblock=1; s->write_wontblock=1;
ssh_poll_remove_events(p,POLLOUT); if(p != NULL) {
ssh_poll_remove_events(p, POLLOUT);
}
/* If buffered data is pending, write it */ /* If buffered data is pending, write it */
if(buffer_get_rest_len(s->out_buffer) > 0){ if(buffer_get_rest_len(s->out_buffer) > 0){
@@ -340,16 +374,24 @@ int ssh_socket_unix(ssh_socket s, const char *path) {
fd = socket(AF_UNIX, SOCK_STREAM, 0); fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd == SSH_INVALID_SOCKET) { if (fd == SSH_INVALID_SOCKET) {
ssh_set_error(s->session, SSH_FATAL,
"Error from socket(AF_UNIX, SOCK_STREAM, 0): %s",
strerror(errno));
return -1; return -1;
} }
if (fcntl(fd, F_SETFD, 1) == -1) { if (fcntl(fd, F_SETFD, 1) == -1) {
ssh_set_error(s->session, SSH_FATAL,
"Error from fcntl(fd, F_SETFD, 1): %s",
strerror(errno));
close(fd); close(fd);
return -1; return -1;
} }
if (connect(fd, (struct sockaddr *) &sunaddr, if (connect(fd, (struct sockaddr *) &sunaddr,
sizeof(sunaddr)) < 0) { sizeof(sunaddr)) < 0) {
ssh_set_error(s->session, SSH_FATAL, "Error from connect(): %s",
strerror(errno));
close(fd); close(fd);
return -1; return -1;
} }
@@ -544,6 +586,7 @@ int ssh_socket_write(ssh_socket s, const void *buffer, int len) {
enter_function(); enter_function();
if(len > 0) { if(len > 0) {
if (buffer_add_data(s->out_buffer, buffer, len) < 0) { if (buffer_add_data(s->out_buffer, buffer, len) < 0) {
ssh_set_error_oom(s->session);
return SSH_ERROR; return SSH_ERROR;
} }
ssh_socket_nonblocking_flush(s); ssh_socket_nonblocking_flush(s);
@@ -632,6 +675,18 @@ int ssh_socket_data_writable(ssh_socket s) {
return s->write_wontblock; return s->write_wontblock;
} }
/** @internal
* @brief returns the number of outgoing bytes currently buffered
* @param s the socket
* @returns numbers of bytes buffered, or 0 if the socket isn't connected
*/
int ssh_socket_buffered_write_bytes(ssh_socket s){
if(s==NULL || s->out_buffer == NULL)
return 0;
return buffer_get_rest_len(s->out_buffer);
}
int ssh_socket_get_status(ssh_socket s) { int ssh_socket_get_status(ssh_socket s) {
int r = 0; int r = 0;
@@ -665,8 +720,11 @@ int ssh_socket_connect(ssh_socket s, const char *host, int port, const char *bin
socket_t fd; socket_t fd;
ssh_session session=s->session; ssh_session session=s->session;
enter_function(); enter_function();
if(s->state != SSH_SOCKET_NONE) if(s->state != SSH_SOCKET_NONE) {
ssh_set_error(s->session, SSH_FATAL,
"ssh_socket_connect called on socket not unconnected");
return SSH_ERROR; return SSH_ERROR;
}
fd=ssh_connect_host_nonblocking(s->session,host,bind_addr,port); fd=ssh_connect_host_nonblocking(s->session,host,bind_addr,port);
ssh_log(session,SSH_LOG_PROTOCOL,"Nonblocking connection socket: %d",fd); ssh_log(session,SSH_LOG_PROTOCOL,"Nonblocking connection socket: %d",fd);
if(fd == SSH_INVALID_SOCKET) if(fd == SSH_INVALID_SOCKET)
@@ -744,7 +802,7 @@ int ssh_socket_connect_proxycommand(ssh_socket s, const char *command){
s->state=SSH_SOCKET_CONNECTED; s->state=SSH_SOCKET_CONNECTED;
s->fd_is_socket=0; s->fd_is_socket=0;
/* POLLOUT is the event to wait for in a nonblocking connect */ /* POLLOUT is the event to wait for in a nonblocking connect */
ssh_poll_set_events(ssh_socket_get_poll_handle_in(s),POLLIN | POLLERR); ssh_poll_set_events(ssh_socket_get_poll_handle_in(s),POLLIN);
ssh_poll_set_events(ssh_socket_get_poll_handle_out(s),POLLOUT); ssh_poll_set_events(ssh_socket_get_poll_handle_out(s),POLLOUT);
if(s->callbacks && s->callbacks->connected) if(s->callbacks && s->callbacks->connected)
s->callbacks->connected(SSH_SOCKET_CONNECTED_OK,0,s->callbacks->userdata); s->callbacks->connected(SSH_SOCKET_CONNECTED_OK,0,s->callbacks->userdata);

View File

@@ -21,6 +21,7 @@
* MA 02111-1307, USA. * MA 02111-1307, USA.
*/ */
#include <errno.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -91,8 +92,15 @@ int ssh_string_fill(struct ssh_string_struct *s, const void *data, size_t len) {
* @note The nul byte is not copied nor counted in the ouput string. * @note The nul byte is not copied nor counted in the ouput string.
*/ */
struct ssh_string_struct *ssh_string_from_char(const char *what) { struct ssh_string_struct *ssh_string_from_char(const char *what) {
struct ssh_string_struct *ptr = NULL; struct ssh_string_struct *ptr;
size_t len = strlen(what); size_t len;
if(what == NULL) {
errno = EINVAL;
return NULL;
}
len = strlen(what);
ptr = malloc(4 + len); ptr = malloc(4 + len);
if (ptr == NULL) { if (ptr == NULL) {
@@ -133,7 +141,7 @@ size_t ssh_string_len(struct ssh_string_struct *s) {
char *ssh_string_to_char(struct ssh_string_struct *s) { char *ssh_string_to_char(struct ssh_string_struct *s) {
size_t len; size_t len;
char *new; char *new;
if(s==NULL) if(s==NULL || s->string == NULL)
return NULL; return NULL;
len = ntohl(s->size) + 1; len = ntohl(s->size) + 1;
new = malloc(len); new = malloc(len);
@@ -164,7 +172,12 @@ void ssh_string_free_char(char *s) {
* @return Newly allocated copy of the string, NULL on error. * @return Newly allocated copy of the string, NULL on error.
*/ */
struct ssh_string_struct *ssh_string_copy(struct ssh_string_struct *s) { struct ssh_string_struct *ssh_string_copy(struct ssh_string_struct *s) {
struct ssh_string_struct *new = malloc(ntohl(s->size) + 4); struct ssh_string_struct *new;
if(s == NULL || s->string == NULL) {
return NULL;
}
new = malloc(ntohl(s->size) + 4);
if (new == NULL) { if (new == NULL) {
return NULL; return NULL;

View File

@@ -92,7 +92,7 @@ static void libcrypto_lock_callback(int mode, int i, const char *file, int line)
} }
} }
static int libcrypto_thread_init(){ static int libcrypto_thread_init(void){
int n=CRYPTO_num_locks(); int n=CRYPTO_num_locks();
int i; int i;
if(user_callbacks == &ssh_threads_noop) if(user_callbacks == &ssh_threads_noop)
@@ -109,7 +109,7 @@ static int libcrypto_thread_init(){
return SSH_OK; return SSH_OK;
} }
static void libcrypto_thread_finalize(){ static void libcrypto_thread_finalize(void){
int n=CRYPTO_num_locks(); int n=CRYPTO_num_locks();
int i; int i;
if (libcrypto_mutexes==NULL) if (libcrypto_mutexes==NULL)

View File

@@ -86,6 +86,12 @@ install(
if (WITH_STATIC_LIB) if (WITH_STATIC_LIB)
add_library(${LIBSSH_THREADS_STATIC_LIBRARY} STATIC ${libssh_threads_SRCS}) add_library(${LIBSSH_THREADS_STATIC_LIBRARY} STATIC ${libssh_threads_SRCS})
if (MSVC)
set(OUTPUT_SUFFIX static)
else (MSVC)
set(OUTPUT_SUFFIX )
endif (MSVC)
set_target_properties( set_target_properties(
${LIBSSH_THREADS_STATIC_LIBRARY} ${LIBSSH_THREADS_STATIC_LIBRARY}
PROPERTIES PROPERTIES
@@ -93,15 +99,26 @@ if (WITH_STATIC_LIB)
${LIBRARY_VERSION} ${LIBRARY_VERSION}
SOVERSION SOVERSION
${LIBRARY_SOVERSION} ${LIBRARY_SOVERSION}
COMPILE_FLAGS OUTPUT_NAME
"-DLIBSSH_STATIC" ssh_threads
ARCHIVE_OUTPUT_DIRECTORY
${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_SUFFIX}
) )
if (WIN32)
set_target_properties(
${LIBSSH_THREADS_STATIC_LIBRARY}
PROPERTIES
COMPILE_FLAGS
"-DLIBSSH_STATIC"
)
endif (WIN32)
install( install(
TARGETS TARGETS
${LIBSSH_THREADS_STATIC_LIBRARY} ${LIBSSH_THREADS_STATIC_LIBRARY}
DESTINATION DESTINATION
${LIB_INSTALL_DIR} ${LIB_INSTALL_DIR}/${OUTPUT_SUFFIX}
COMPONENT COMPONENT
libraries libraries
) )

View File

@@ -38,6 +38,10 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#ifdef WITH_LIBZ
#include <zlib.h>
#endif
#include "libssh/priv.h" #include "libssh/priv.h"
#include "libssh/session.h" #include "libssh/session.h"
#include "libssh/crypto.h" #include "libssh/crypto.h"
@@ -82,7 +86,7 @@ static void cipher_free(struct crypto_struct *cipher) {
} }
struct ssh_crypto_struct *crypto_new(void) { struct ssh_crypto_struct *crypto_new(void) {
struct ssh_crypto_struct *crypto; struct ssh_crypto_struct *crypto;
crypto = malloc(sizeof(struct ssh_crypto_struct)); crypto = malloc(sizeof(struct ssh_crypto_struct));
if (crypto == NULL) { if (crypto == NULL) {
@@ -108,6 +112,18 @@ void crypto_free(struct ssh_crypto_struct *crypto){
bignum_free(crypto->y); bignum_free(crypto->y);
bignum_free(crypto->k); bignum_free(crypto->k);
/* lot of other things */ /* lot of other things */
#ifdef WITH_LIBZ
if (crypto->compress_out_ctx &&
(deflateEnd(crypto->compress_out_ctx) != 0)) {
inflateEnd(crypto->compress_out_ctx);
}
if (crypto->compress_in_ctx &&
(deflateEnd(crypto->compress_in_ctx) != 0)) {
inflateEnd(crypto->compress_in_ctx);
}
#endif
/* i'm lost in my own code. good work */ /* i'm lost in my own code. good work */
memset(crypto,0,sizeof(*crypto)); memset(crypto,0,sizeof(*crypto));
@@ -219,11 +235,15 @@ int crypt_set_algorithms_server(ssh_session session){
int i = 0; int i = 0;
struct crypto_struct *ssh_ciphertab=ssh_get_ciphertab(); struct crypto_struct *ssh_ciphertab=ssh_get_ciphertab();
if (session == NULL) {
return SSH_ERROR;
}
/* we must scan the kex entries to find crypto algorithms and set their appropriate structure */ /* we must scan the kex entries to find crypto algorithms and set their appropriate structure */
enter_function(); enter_function();
/* out */ /* out */
server = session->server_kex.methods[SSH_CRYPT_S_C]; server = session->server_kex.methods[SSH_CRYPT_S_C];
if(session && session->client_kex.methods) { if(session->client_kex.methods) {
client = session->client_kex.methods[SSH_CRYPT_S_C]; client = session->client_kex.methods[SSH_CRYPT_S_C];
} else { } else {
ssh_log(session,SSH_LOG_PROTOCOL, "Client KEX empty"); ssh_log(session,SSH_LOG_PROTOCOL, "Client KEX empty");

View File

@@ -75,12 +75,12 @@ int benchmarks_ping_latency (const char *host, float *average){
} }
if(!found) if(!found)
goto parseerror; goto parseerror;
fclose(fd); pclose(fd);
return 0; return 0;
parseerror: parseerror:
fprintf(stderr,"Parse error : couldn't locate average in %s",line); fprintf(stderr,"Parse error : couldn't locate average in %s",line);
fclose(fd); pclose(fd);
return -1; return -1;
} }

View File

@@ -21,13 +21,15 @@
* MA 02111-1307, USA. * MA 02111-1307, USA.
*/ */
#include <sys/types.h> #include "config.h"
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#ifndef _WIN32 #ifndef _WIN32
# include <sys/types.h>
# include <sys/stat.h>
# include <dirent.h>
# include <errno.h>
# include <unistd.h> # include <unistd.h>
#endif #endif
@@ -35,6 +37,7 @@
static int verbosity = 0; static int verbosity = 0;
#ifndef _WIN32
static int _torture_auth_kbdint(ssh_session session, static int _torture_auth_kbdint(ssh_session session,
const char *password) { const char *password) {
const char *prompt; const char *prompt;
@@ -129,6 +132,7 @@ int torture_rmdirs(const char *path) {
rewinddir(d); rewinddir(d);
} }
} else { } else {
closedir(d);
return -1; return -1;
} }
@@ -146,10 +150,6 @@ int torture_isdir(const char *path) {
return 0; return 0;
} }
int torture_libssh_verbosity(void){
return verbosity;
}
ssh_session torture_ssh_session(const char *host, ssh_session torture_ssh_session(const char *host,
const char *user, const char *user,
const char *password) { const char *password) {
@@ -216,6 +216,8 @@ failed:
return NULL; return NULL;
} }
#ifdef WITH_SFTP
struct torture_sftp *torture_sftp_session(ssh_session session) { struct torture_sftp *torture_sftp_session(ssh_session session) {
struct torture_sftp *t; struct torture_sftp *t;
char template[] = "/tmp/ssh_torture_XXXXXX"; char template[] = "/tmp/ssh_torture_XXXXXX";
@@ -258,6 +260,7 @@ failed:
} }
ssh_disconnect(t->ssh); ssh_disconnect(t->ssh);
ssh_free(t->ssh); ssh_free(t->ssh);
free(t);
return NULL; return NULL;
} }
@@ -281,6 +284,14 @@ void torture_sftp_close(struct torture_sftp *t) {
free(t->testdir); free(t->testdir);
free(t); free(t);
} }
#endif /* WITH_SFTP */
#endif /* _WIN32 */
int torture_libssh_verbosity(void){
return verbosity;
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
struct argument_s arguments; struct argument_s arguments;

View File

@@ -6,6 +6,7 @@ add_cmockery_test(torture_init torture_init.c ${TORTURE_LIBRARY})
add_cmockery_test(torture_list torture_list.c ${TORTURE_LIBRARY}) add_cmockery_test(torture_list torture_list.c ${TORTURE_LIBRARY})
add_cmockery_test(torture_misc torture_misc.c ${TORTURE_LIBRARY}) add_cmockery_test(torture_misc torture_misc.c ${TORTURE_LIBRARY})
add_cmockery_test(torture_options torture_options.c ${TORTURE_LIBRARY}) add_cmockery_test(torture_options torture_options.c ${TORTURE_LIBRARY})
add_cmockery_test(torture_isipaddr torture_isipaddr.c ${TORTURE_LIBRARY})
if (UNIX AND NOT WIN32) if (UNIX AND NOT WIN32)
# requires ssh-keygen # requires ssh-keygen
add_cmockery_test(torture_keyfiles torture_keyfiles.c ${TORTURE_LIBRARY}) add_cmockery_test(torture_keyfiles torture_keyfiles.c ${TORTURE_LIBRARY})

View File

@@ -0,0 +1,55 @@
#define LIBSSH_STATIC
#include "torture.h"
#include "misc.c"
#include "error.c"
/*
* Test the behavior of ssh_is_ipaddr()
*/
static void torture_ssh_is_ipaddr(void **state) {
(void)state;
assert_int_equal(ssh_is_ipaddr("127.0.0.1"),1);
assert_int_equal(ssh_is_ipaddr("0.0.0.0"),1);
assert_int_equal(ssh_is_ipaddr("1.1.1.1"),1);
assert_int_equal(ssh_is_ipaddr("255.255.255.255"),1);
assert_int_equal(ssh_is_ipaddr("128.128.128.128"),1);
assert_int_equal(ssh_is_ipaddr("1.10.100.1"),1);
assert_int_equal(ssh_is_ipaddr("0.1.10.100"),1);
assert_int_equal(ssh_is_ipaddr("2001:0db8:85a3:0000:0000:8a2e:0370:7334"),1);
assert_int_equal(ssh_is_ipaddr("fe80:0000:0000:0000:0202:b3ff:fe1e:8329"),1);
assert_int_equal(ssh_is_ipaddr("fe80:0:0:0:202:b3ff:fe1e:8329"),1);
assert_int_equal(ssh_is_ipaddr("fe80::202:b3ff:fe1e:8329"),1);
assert_int_equal(ssh_is_ipaddr("::1"),1);
assert_int_equal(ssh_is_ipaddr("::ffff:192.0.2.128"),1);
assert_int_equal(ssh_is_ipaddr("0.0.0.0.0"),0);
assert_int_equal(ssh_is_ipaddr("0.0.0.0.a"),0);
assert_int_equal(ssh_is_ipaddr("a.0.0.0"),0);
assert_int_equal(ssh_is_ipaddr("0a.0.0.0.0"),0);
assert_int_equal(ssh_is_ipaddr(""),0);
assert_int_equal(ssh_is_ipaddr("0.0.0."),0);
assert_int_equal(ssh_is_ipaddr("0.0"),0);
assert_int_equal(ssh_is_ipaddr("0"),0);
assert_int_equal(ssh_is_ipaddr("2001:0db8:85a3:0000:0000:8a2e:0370:7334:1002"), 0);
assert_int_equal(ssh_is_ipaddr("fe80:x:202:b3ff:fe1e:8329"), 0);
assert_int_equal(ssh_is_ipaddr("fe80:x:202:b3ff:fe1e:8329"), 0);
assert_int_equal(ssh_is_ipaddr(":1"), 0);
}
int torture_run_tests(void) {
int rc;
const UnitTest tests[] = {
unit_test(torture_ssh_is_ipaddr)
};
ssh_init();
rc=run_tests(tests);
ssh_finalize();
return rc;
}

View File

@@ -11,6 +11,8 @@
#include "torture.h" #include "torture.h"
#include "misc.c" #include "misc.c"
#include "error.c"
#define TORTURE_TEST_DIR "/usr/local/bin/truc/much/.." #define TORTURE_TEST_DIR "/usr/local/bin/truc/much/.."
@@ -159,6 +161,30 @@ static void torture_path_expand_known_hosts(void **state) {
free(tmp); free(tmp);
} }
static void torture_timeout_elapsed(void **state){
struct ssh_timestamp ts;
(void) state;
ssh_timestamp_init(&ts);
usleep(50000);
assert_true(ssh_timeout_elapsed(&ts,25));
assert_false(ssh_timeout_elapsed(&ts,30000));
assert_false(ssh_timeout_elapsed(&ts,75));
assert_true(ssh_timeout_elapsed(&ts,0));
assert_false(ssh_timeout_elapsed(&ts,-1));
}
static void torture_timeout_update(void **state){
struct ssh_timestamp ts;
(void) state;
ssh_timestamp_init(&ts);
usleep(50000);
assert_int_equal(ssh_timeout_update(&ts,25), 0);
assert_in_range(ssh_timeout_update(&ts,30000),29000,29960);
assert_in_range(ssh_timeout_update(&ts,75),1,40);
assert_int_equal(ssh_timeout_update(&ts,0),0);
assert_int_equal(ssh_timeout_update(&ts,-1),-1);
}
int torture_run_tests(void) { int torture_run_tests(void) {
int rc; int rc;
const UnitTest tests[] = { const UnitTest tests[] = {
@@ -173,6 +199,8 @@ int torture_run_tests(void) {
#endif #endif
unit_test_setup_teardown(torture_path_expand_escape, setup, teardown), unit_test_setup_teardown(torture_path_expand_escape, setup, teardown),
unit_test_setup_teardown(torture_path_expand_known_hosts, setup, teardown), unit_test_setup_teardown(torture_path_expand_known_hosts, setup, teardown),
unit_test(torture_timeout_elapsed),
unit_test(torture_timeout_update),
}; };
ssh_init(); ssh_init();