mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-05 04:40:31 +09:00
Compare commits
43 Commits
libssh-0.6
...
libssh-0.6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78d5d64b38 | ||
|
|
f73a44c223 | ||
|
|
1cccfdf8a0 | ||
|
|
abe4ed0e75 | ||
|
|
e7f831f0a3 | ||
|
|
4ea4e12df2 | ||
|
|
fb49e194df | ||
|
|
13f4e31ad1 | ||
|
|
da5fa4ef66 | ||
|
|
dca415a38e | ||
|
|
56f86cd4a1 | ||
|
|
f265afacfb | ||
|
|
99f8b2b803 | ||
|
|
22edaf43ee | ||
|
|
497bd31364 | ||
|
|
8ed0c0b3c8 | ||
|
|
ce39d2fa73 | ||
|
|
90d3768f0f | ||
|
|
6f66032209 | ||
|
|
c571cd8402 | ||
|
|
b049e12652 | ||
|
|
785682ac28 | ||
|
|
f29f10876a | ||
|
|
45d28c7682 | ||
|
|
2786565e77 | ||
|
|
96ad690c80 | ||
|
|
0d82186503 | ||
|
|
5157d96958 | ||
|
|
6a0787a366 | ||
|
|
709e921942 | ||
|
|
43a69b0a65 | ||
|
|
18506f697c | ||
|
|
15bede0c0e | ||
|
|
92dde09a37 | ||
|
|
809d76cbf2 | ||
|
|
f78a74c160 | ||
|
|
b3b3045a81 | ||
|
|
72fd3a73df | ||
|
|
cf19770ede | ||
|
|
7f42f5a3c9 | ||
|
|
6223e05b23 | ||
|
|
634671db11 | ||
|
|
1f689261ec |
@@ -8,7 +8,7 @@ set(APPLICATION_NAME ${PROJECT_NAME})
|
||||
|
||||
set(APPLICATION_VERSION_MAJOR "0")
|
||||
set(APPLICATION_VERSION_MINOR "6")
|
||||
set(APPLICATION_VERSION_PATCH "0")
|
||||
set(APPLICATION_VERSION_PATCH "1")
|
||||
|
||||
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
|
||||
# If the source code was changed, but there were no interface changes:
|
||||
# Increment REVISION.
|
||||
set(LIBRARY_VERSION "4.3.0")
|
||||
set(LIBRARY_VERSION "4.4.0")
|
||||
set(LIBRARY_SOVERSION "4")
|
||||
|
||||
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
|
||||
|
||||
@@ -19,7 +19,7 @@ set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSIO
|
||||
|
||||
### source generator
|
||||
set(CPACK_SOURCE_GENERATOR "TGZ")
|
||||
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]svn/;/[.]git/;.gitignore;/build/;tags;cscope.*")
|
||||
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]svn/;/[.]git/;.gitignore;/build/;/obj/;tags;cscope.*")
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
|
||||
|
||||
if (WIN32)
|
||||
|
||||
12
ChangeLog
12
ChangeLog
@@ -1,6 +1,18 @@
|
||||
ChangeLog
|
||||
==========
|
||||
|
||||
version 0.6.1 (released 2014-02-08)
|
||||
* Added support for libgcrypt 1.6.
|
||||
* Added ssh_channel_accept_forward().
|
||||
* Added known_hosts heuristic during connection (#138).
|
||||
* Added getters for session cipher names.
|
||||
* Fixed decrypt of zero length buffer.
|
||||
* Fixed padding in RSA signature blobs.
|
||||
* Fixed DSA signature extraction.
|
||||
* Fixed some memory leaks.
|
||||
* Fixed read of non-connected socket.
|
||||
* Fixed thread dectection.
|
||||
|
||||
version 0.6.0 (released 2014-01-08)
|
||||
* Added new publicy key API.
|
||||
* Added new userauth API.
|
||||
|
||||
@@ -169,11 +169,9 @@ if (GCRYPT_FOUND)
|
||||
endif (GCRYPT_VERSION VERSION_GREATER "1.4.6")
|
||||
endif (GCRYPT_FOUND)
|
||||
|
||||
if (CMAKE_HAVE_THREADS_LIBRARY)
|
||||
if (CMAKE_USE_PTHREADS_INIT)
|
||||
set(HAVE_PTHREAD 1)
|
||||
endif (CMAKE_USE_PTHREADS_INIT)
|
||||
endif (CMAKE_HAVE_THREADS_LIBRARY)
|
||||
if (CMAKE_USE_PTHREADS_INIT)
|
||||
set(HAVE_PTHREAD 1)
|
||||
endif (CMAKE_USE_PTHREADS_INIT)
|
||||
|
||||
# OPTIONS
|
||||
check_c_source_compiles("
|
||||
|
||||
@@ -75,3 +75,10 @@ if (MSVC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_NONSTDC_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1")
|
||||
endif (MSVC)
|
||||
|
||||
# This removes this annoying warning
|
||||
# "warning: 'BN_CTX_free' is deprecated: first deprecated in OS X 10.7 [-Wdeprecated-declarations]"
|
||||
if (OSX)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-declarations")
|
||||
endif (OSX)
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ or whatever use you have for it.
|
||||
@subsection libssh_reverse Doing reverse port forwarding with libssh
|
||||
|
||||
To do reverse port forwarding, call ssh_forward_listen(),
|
||||
then ssh_forward_accept().
|
||||
then ssh_channel_accept_forward().
|
||||
|
||||
When you call ssh_forward_listen(), you can let the remote server
|
||||
chose the non-priviledged port it should listen to. Otherwise, you can chose
|
||||
@@ -164,6 +164,7 @@ int web_server(ssh_session session)
|
||||
ssh_channel channel;
|
||||
char buffer[256];
|
||||
int nbytes, nwritten;
|
||||
int port;
|
||||
char *helloworld = ""
|
||||
"HTTP/1.1 200 OK\n"
|
||||
"Content-Type: text/html\n"
|
||||
@@ -186,7 +187,7 @@ int web_server(ssh_session session)
|
||||
return rc;
|
||||
}
|
||||
|
||||
channel = ssh_forward_accept(session, 60000);
|
||||
channel = ssh_channel_accept_forward(session, 60000, &port);
|
||||
if (channel == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error waiting for incoming connection: %s\n",
|
||||
|
||||
@@ -61,5 +61,6 @@ implement the following methods :
|
||||
- mutex_destroy
|
||||
- thread_id
|
||||
|
||||
libgcrypt 1.6 and bigger backend does not support custom callback. Using anything else than pthreads (ssh_threads_get_pthread()) here will fail.
|
||||
Good luck !
|
||||
*/
|
||||
|
||||
@@ -495,6 +495,8 @@ LIBSSH_API int ssh_set_callbacks(ssh_session session, ssh_callbacks cb);
|
||||
* @param len the length of the data
|
||||
* @param is_stderr is 0 for stdout or 1 for stderr
|
||||
* @param userdata Userdata to be passed to the callback function.
|
||||
* @returns number of bytes processed by the callee. The remaining bytes will
|
||||
* be sent in the next callback message, when more data is available.
|
||||
*/
|
||||
typedef int (*ssh_channel_data_callback) (ssh_session session,
|
||||
ssh_channel channel,
|
||||
@@ -801,6 +803,8 @@ struct ssh_threads_callbacks_struct {
|
||||
*
|
||||
* @see ssh_threads_callbacks_struct
|
||||
* @see SSH_THREADS_PTHREAD
|
||||
* @bug libgcrypt 1.6 and bigger backend does not support custom callback.
|
||||
* Using anything else than pthreads here will fail.
|
||||
*/
|
||||
LIBSSH_API int ssh_threads_set_callbacks(struct ssh_threads_callbacks_struct
|
||||
*cb);
|
||||
|
||||
27
include/libssh/knownhosts.h
Normal file
27
include/libssh/knownhosts.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 20014 by Aris Adamantiadis <aris@badcode.be>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef KNOWNHOSTS_H_
|
||||
#define KNOWNHOSTS_H_
|
||||
|
||||
char **ssh_knownhosts_algorithms(ssh_session session);
|
||||
|
||||
#endif /* KNOWNHOSTS_H_ */
|
||||
@@ -78,7 +78,7 @@
|
||||
/* libssh version */
|
||||
#define LIBSSH_VERSION_MAJOR 0
|
||||
#define LIBSSH_VERSION_MINOR 6
|
||||
#define LIBSSH_VERSION_MICRO 0
|
||||
#define LIBSSH_VERSION_MICRO 1
|
||||
|
||||
#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \
|
||||
LIBSSH_VERSION_MINOR, \
|
||||
@@ -377,7 +377,7 @@ LIBSSH_API int ssh_channel_open_x11(ssh_channel channel, const char *orig_addr,
|
||||
LIBSSH_API int ssh_channel_poll(ssh_channel channel, int is_stderr);
|
||||
LIBSSH_API int ssh_channel_poll_timeout(ssh_channel channel, int timeout, int is_stderr);
|
||||
LIBSSH_API int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_stderr);
|
||||
LIBSSH_API int ssh_channel_read_timeout(ssh_channel channel, void *dest, uint32_t count, int is_stderr, int timeout);
|
||||
LIBSSH_API int ssh_channel_read_timeout(ssh_channel channel, void *dest, uint32_t count, int is_stderr, int timeout_ms);
|
||||
LIBSSH_API int ssh_channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count,
|
||||
int is_stderr);
|
||||
LIBSSH_API int ssh_channel_request_env(ssh_channel channel, const char *name, const char *value);
|
||||
@@ -406,6 +406,7 @@ LIBSSH_API void ssh_disconnect(ssh_session session);
|
||||
LIBSSH_API char *ssh_dirname (const char *path);
|
||||
LIBSSH_API int ssh_finalize(void);
|
||||
LIBSSH_API ssh_channel ssh_forward_accept(ssh_session session, int timeout_ms);
|
||||
LIBSSH_API ssh_channel ssh_channel_accept_forward(ssh_session session, int timeout_ms, int *destination_port);
|
||||
LIBSSH_API int ssh_forward_cancel(ssh_session session, const char *address, int port);
|
||||
LIBSSH_API int ssh_forward_listen(ssh_session session, const char *address, int port, int *bound_port);
|
||||
LIBSSH_API void ssh_free(ssh_session session);
|
||||
@@ -627,6 +628,8 @@ LIBSSH_API int ssh_event_remove_session(ssh_event event, ssh_session session);
|
||||
LIBSSH_API void ssh_event_free(ssh_event event);
|
||||
LIBSSH_API const char* ssh_get_clientbanner(ssh_session session);
|
||||
LIBSSH_API const char* ssh_get_serverbanner(ssh_session session);
|
||||
LIBSSH_API const char* ssh_get_cipher_in(ssh_session session);
|
||||
LIBSSH_API const char* ssh_get_cipher_out(ssh_session session);
|
||||
|
||||
#ifndef LIBSSH_LEGACY_0_4
|
||||
#include "libssh/legacy.h"
|
||||
|
||||
@@ -120,11 +120,24 @@ int gettimeofday(struct timeval *__p, void *__t);
|
||||
#include "libssh/callbacks.h"
|
||||
|
||||
/* some constants */
|
||||
#ifndef MAX_PACKAT_LEN
|
||||
#define MAX_PACKET_LEN 262144
|
||||
#endif
|
||||
#ifndef ERROR_BUFFERLEN
|
||||
#define ERROR_BUFFERLEN 1024
|
||||
#endif
|
||||
#ifndef CLIENTBANNER1
|
||||
#define CLIENTBANNER1 "SSH-1.5-libssh-" SSH_STRINGIFY(LIBSSH_VERSION)
|
||||
#endif
|
||||
#ifndef CLIENTBANNER2
|
||||
#define CLIENTBANNER2 "SSH-2.0-libssh-" SSH_STRINGIFY(LIBSSH_VERSION)
|
||||
#endif
|
||||
#ifndef KBDINT_MAX_PROMPT
|
||||
#define KBDINT_MAX_PROMPT 256 /* more than openssh's :) */
|
||||
#endif
|
||||
#ifndef MAX_BUF_SIZE
|
||||
#define MAX_BUF_SIZE 4096
|
||||
#endif
|
||||
|
||||
#ifndef __FUNCTION__
|
||||
#if defined(__SUNPRO_C)
|
||||
@@ -155,16 +168,6 @@ int gettimeofday(struct timeval *__p, void *__t);
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* get rid of deprecacy warnings on OSX when using OpenSSL
|
||||
*/
|
||||
#if defined(__APPLE__)
|
||||
#ifdef MAC_OS_X_VERSION_MIN_REQUIRED
|
||||
#undef MAC_OS_X_VERSION_MIN_REQUIRED
|
||||
#endif
|
||||
#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_6
|
||||
#endif
|
||||
|
||||
/* forward declarations */
|
||||
struct ssh_common_struct;
|
||||
struct ssh_kex_struct;
|
||||
|
||||
@@ -175,6 +175,7 @@ struct ssh_session_struct {
|
||||
char *knownhosts;
|
||||
char *wanted_methods[10];
|
||||
char *ProxyCommand;
|
||||
char *custombanner;
|
||||
unsigned long timeout; /* seconds */
|
||||
unsigned long timeout_usec;
|
||||
unsigned int port;
|
||||
|
||||
@@ -288,6 +288,6 @@ if (WITH_STATIC_LIB)
|
||||
)
|
||||
endif (WITH_STATIC_LIB)
|
||||
|
||||
if (CMAKE_HAVE_THREADS_LIBRARY)
|
||||
if (Threads_FOUND)
|
||||
add_subdirectory(threads)
|
||||
endif (CMAKE_HAVE_THREADS_LIBRARY)
|
||||
endif (Threads_FOUND)
|
||||
|
||||
60
src/bind.c
60
src/bind.c
@@ -144,26 +144,19 @@ ssh_bind ssh_bind_new(void) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
int ssh_bind_listen(ssh_bind sshbind) {
|
||||
const char *host;
|
||||
socket_t fd;
|
||||
static int ssh_bind_import_keys(ssh_bind sshbind) {
|
||||
int rc;
|
||||
|
||||
if (ssh_init() < 0) {
|
||||
ssh_set_error(sshbind, SSH_FATAL, "ssh_init() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sshbind->ecdsakey == NULL &&
|
||||
sshbind->dsakey == NULL &&
|
||||
sshbind->rsakey == NULL) {
|
||||
ssh_set_error(sshbind, SSH_FATAL,
|
||||
"DSA or RSA host key file must be set before listen()");
|
||||
"ECDSA, DSA, or RSA host key file must be set");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ECC
|
||||
if (sshbind->ecdsakey) {
|
||||
if (sshbind->ecdsa == NULL && sshbind->ecdsakey != NULL) {
|
||||
rc = ssh_pki_import_privkey_file(sshbind->ecdsakey,
|
||||
NULL,
|
||||
NULL,
|
||||
@@ -179,12 +172,13 @@ int ssh_bind_listen(ssh_bind sshbind) {
|
||||
ssh_set_error(sshbind, SSH_FATAL,
|
||||
"The ECDSA host key has the wrong type");
|
||||
ssh_key_free(sshbind->ecdsa);
|
||||
sshbind->ecdsa = NULL;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sshbind->dsakey) {
|
||||
if (sshbind->dsa == NULL && sshbind->dsakey != NULL) {
|
||||
rc = ssh_pki_import_privkey_file(sshbind->dsakey,
|
||||
NULL,
|
||||
NULL,
|
||||
@@ -201,11 +195,12 @@ int ssh_bind_listen(ssh_bind sshbind) {
|
||||
"The DSA host key has the wrong type: %d",
|
||||
ssh_key_type(sshbind->dsa));
|
||||
ssh_key_free(sshbind->dsa);
|
||||
sshbind->dsa = NULL;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (sshbind->rsakey) {
|
||||
if (sshbind->rsa == NULL && sshbind->rsakey != NULL) {
|
||||
rc = ssh_pki_import_privkey_file(sshbind->rsakey,
|
||||
NULL,
|
||||
NULL,
|
||||
@@ -222,10 +217,29 @@ int ssh_bind_listen(ssh_bind sshbind) {
|
||||
ssh_set_error(sshbind, SSH_FATAL,
|
||||
"The RSA host key has the wrong type");
|
||||
ssh_key_free(sshbind->rsa);
|
||||
sshbind->rsa = NULL;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int ssh_bind_listen(ssh_bind sshbind) {
|
||||
const char *host;
|
||||
socket_t fd;
|
||||
int rc;
|
||||
|
||||
if (ssh_init() < 0) {
|
||||
ssh_set_error(sshbind, SSH_FATAL, "ssh_init() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = ssh_bind_import_keys(sshbind);
|
||||
if (rc != SSH_OK) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (sshbind->bindfd == SSH_INVALID_SOCKET) {
|
||||
host = sshbind->bindaddr;
|
||||
if (host == NULL) {
|
||||
@@ -235,7 +249,9 @@ int ssh_bind_listen(ssh_bind sshbind) {
|
||||
fd = bind_socket(sshbind, host, sshbind->bindport);
|
||||
if (fd == SSH_INVALID_SOCKET) {
|
||||
ssh_key_free(sshbind->dsa);
|
||||
sshbind->dsa = NULL;
|
||||
ssh_key_free(sshbind->rsa);
|
||||
sshbind->rsa = NULL;
|
||||
return -1;
|
||||
}
|
||||
sshbind->bindfd = fd;
|
||||
@@ -246,7 +262,9 @@ int ssh_bind_listen(ssh_bind sshbind) {
|
||||
fd, strerror(errno));
|
||||
close(fd);
|
||||
ssh_key_free(sshbind->dsa);
|
||||
sshbind->dsa = NULL;
|
||||
ssh_key_free(sshbind->rsa);
|
||||
sshbind->rsa = NULL;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
@@ -348,8 +366,11 @@ void ssh_bind_free(ssh_bind sshbind){
|
||||
SAFE_FREE(sshbind->ecdsakey);
|
||||
|
||||
ssh_key_free(sshbind->dsa);
|
||||
sshbind->dsa = NULL;
|
||||
ssh_key_free(sshbind->rsa);
|
||||
sshbind->rsa = NULL;
|
||||
ssh_key_free(sshbind->ecdsa);
|
||||
sshbind->ecdsa = NULL;
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (sshbind->wanted_methods[i]) {
|
||||
@@ -361,7 +382,7 @@ void ssh_bind_free(ssh_bind sshbind){
|
||||
}
|
||||
|
||||
int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
|
||||
int i;
|
||||
int i, rc;
|
||||
|
||||
if (session == NULL){
|
||||
ssh_set_error(sshbind, SSH_FATAL,"session is null");
|
||||
@@ -392,7 +413,8 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
|
||||
}
|
||||
|
||||
session->common.log_verbosity = sshbind->common.log_verbosity;
|
||||
|
||||
if(sshbind->banner != NULL)
|
||||
session->opts.custombanner = strdup(sshbind->banner);
|
||||
ssh_socket_free(session->socket);
|
||||
session->socket = ssh_socket_new(session);
|
||||
if (session->socket == NULL) {
|
||||
@@ -403,6 +425,16 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
|
||||
ssh_socket_set_fd(session->socket, fd);
|
||||
ssh_socket_get_poll_handle_out(session->socket);
|
||||
|
||||
/* We must try to import any keys that could be imported in case
|
||||
* we are not using ssh_bind_listen (which is the other place
|
||||
* where keys can be imported) on this ssh_bind and are instead
|
||||
* only using ssh_bind_accept_fd to manage sockets ourselves.
|
||||
*/
|
||||
rc = ssh_bind_import_keys(sshbind);
|
||||
if (rc != SSH_OK) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ECC
|
||||
if (sshbind->ecdsa) {
|
||||
session->srv.ecdsa_key = ssh_key_dup(sshbind->ecdsa);
|
||||
|
||||
120
src/channels.c
120
src/channels.c
@@ -916,10 +916,10 @@ int channel_default_bufferize(ssh_channel channel, void *data, int len,
|
||||
* SSH_AGAIN if in nonblocking mode and call has
|
||||
* to be done again.
|
||||
*
|
||||
* @see channel_open_forward()
|
||||
* @see channel_request_env()
|
||||
* @see channel_request_shell()
|
||||
* @see channel_request_exec()
|
||||
* @see ssh_channel_open_forward()
|
||||
* @see ssh_channel_request_env()
|
||||
* @see ssh_channel_request_shell()
|
||||
* @see ssh_channel_request_exec()
|
||||
*/
|
||||
int ssh_channel_open_session(ssh_channel channel) {
|
||||
if(channel == NULL) {
|
||||
@@ -952,7 +952,7 @@ int ssh_channel_open_session(ssh_channel channel) {
|
||||
* SSH_AGAIN if in nonblocking mode and call has
|
||||
* to be done again.
|
||||
*
|
||||
* @see channel_open_forward()
|
||||
* @see ssh_channel_open_forward()
|
||||
*/
|
||||
int ssh_channel_open_auth_agent(ssh_channel channel){
|
||||
if(channel == NULL) {
|
||||
@@ -1120,8 +1120,24 @@ void ssh_channel_do_free(ssh_channel channel){
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR if an error occurred.
|
||||
*
|
||||
* @see channel_close()
|
||||
* @see channel_free()
|
||||
* Example:
|
||||
@code
|
||||
rc = ssh_channel_send_eof(channel);
|
||||
if (rc == SSH_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
while(!ssh_channel_is_eof(channel)) {
|
||||
rc = ssh_channel_read(channel, buf, sizeof(buf), 0);
|
||||
if (rc == SSH_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
ssh_channel_close(channel);
|
||||
@endcode
|
||||
*
|
||||
* @see ssh_channel_close()
|
||||
* @see ssh_channel_free()
|
||||
* @see ssh_channel_is_eof()
|
||||
*/
|
||||
int ssh_channel_send_eof(ssh_channel channel){
|
||||
ssh_session session;
|
||||
@@ -1170,8 +1186,8 @@ error:
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR if an error occurred.
|
||||
*
|
||||
* @see channel_free()
|
||||
* @see channel_eof()
|
||||
* @see ssh_channel_free()
|
||||
* @see ssh_channel_is_eof()
|
||||
*/
|
||||
int ssh_channel_close(ssh_channel channel){
|
||||
ssh_session session;
|
||||
@@ -1397,7 +1413,7 @@ uint32_t ssh_channel_window_size(ssh_channel channel) {
|
||||
*
|
||||
* @return The number of bytes written, SSH_ERROR on error.
|
||||
*
|
||||
* @see channel_read()
|
||||
* @see ssh_channel_read()
|
||||
*/
|
||||
int ssh_channel_write(ssh_channel channel, const void *data, uint32_t len) {
|
||||
return channel_write_common(channel, data, len, 0);
|
||||
@@ -1410,7 +1426,7 @@ int ssh_channel_write(ssh_channel channel, const void *data, uint32_t len) {
|
||||
*
|
||||
* @return 0 if channel is closed, nonzero otherwise.
|
||||
*
|
||||
* @see channel_is_closed()
|
||||
* @see ssh_channel_is_closed()
|
||||
*/
|
||||
int ssh_channel_is_open(ssh_channel channel) {
|
||||
if(channel == NULL) {
|
||||
@@ -1426,7 +1442,7 @@ int ssh_channel_is_open(ssh_channel channel) {
|
||||
*
|
||||
* @return 0 if channel is opened, nonzero otherwise.
|
||||
*
|
||||
* @see channel_is_open()
|
||||
* @see ssh_channel_is_open()
|
||||
*/
|
||||
int ssh_channel_is_closed(ssh_channel channel) {
|
||||
if(channel == NULL) {
|
||||
@@ -1725,7 +1741,7 @@ error:
|
||||
* SSH_AGAIN if in nonblocking mode and call has
|
||||
* to be done again.
|
||||
*
|
||||
* @see channel_request_pty_size()
|
||||
* @see ssh_channel_request_pty_size()
|
||||
*/
|
||||
int ssh_channel_request_pty(ssh_channel channel) {
|
||||
return ssh_channel_request_pty_size(channel, "xterm", 80, 24);
|
||||
@@ -1964,7 +1980,7 @@ error:
|
||||
}
|
||||
|
||||
static ssh_channel ssh_channel_accept(ssh_session session, int channeltype,
|
||||
int timeout_ms) {
|
||||
int timeout_ms, int *destination_port) {
|
||||
#ifndef _WIN32
|
||||
static const struct timespec ts = {
|
||||
.tv_sec = 0,
|
||||
@@ -1981,7 +1997,11 @@ static ssh_channel ssh_channel_accept(ssh_session session, int channeltype,
|
||||
* 50 ms. So we need to decrement by 100 ms.
|
||||
*/
|
||||
for (t = timeout_ms; t >= 0; t -= 100) {
|
||||
ssh_handle_packets(session, 50);
|
||||
if (timeout_ms == 0) {
|
||||
ssh_handle_packets(session, 0);
|
||||
} else {
|
||||
ssh_handle_packets(session, 50);
|
||||
}
|
||||
|
||||
if (session->ssh_message_list) {
|
||||
iterator = ssh_list_get_iterator(session->ssh_message_list);
|
||||
@@ -1991,6 +2011,10 @@ static ssh_channel ssh_channel_accept(ssh_session session, int channeltype,
|
||||
ssh_message_subtype(msg) == channeltype) {
|
||||
ssh_list_remove(session->ssh_message_list, iterator);
|
||||
channel = ssh_message_channel_request_open_reply_accept(msg);
|
||||
if(destination_port) {
|
||||
*destination_port=msg->channel_request_open.destination_port;
|
||||
}
|
||||
|
||||
ssh_message_free(msg);
|
||||
return channel;
|
||||
}
|
||||
@@ -2021,7 +2045,7 @@ static ssh_channel ssh_channel_accept(ssh_session session, int channeltype,
|
||||
* the server.
|
||||
*/
|
||||
ssh_channel ssh_channel_accept_x11(ssh_channel channel, int timeout_ms) {
|
||||
return ssh_channel_accept(channel->session, SSH_CHANNEL_X11, timeout_ms);
|
||||
return ssh_channel_accept(channel->session, SSH_CHANNEL_X11, timeout_ms, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2275,7 +2299,23 @@ error:
|
||||
* the server
|
||||
*/
|
||||
ssh_channel ssh_forward_accept(ssh_session session, int timeout_ms) {
|
||||
return ssh_channel_accept(session, SSH_CHANNEL_FORWARDED_TCPIP, timeout_ms);
|
||||
return ssh_channel_accept(session, SSH_CHANNEL_FORWARDED_TCPIP, timeout_ms, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Accept an incoming TCP/IP forwarding channel and get information
|
||||
* about incomming connection
|
||||
* @param[in] session The ssh session to use.
|
||||
*
|
||||
* @param[in] timeout_ms A timeout in milliseconds.
|
||||
*
|
||||
* @param[in] destination_port A pointer to destination port or NULL.
|
||||
*
|
||||
* @return Newly created channel, or NULL if no incoming channel request from
|
||||
* the server
|
||||
*/
|
||||
ssh_channel ssh_channel_accept_forward(ssh_session session, int timeout_ms, int* destination_port) {
|
||||
return ssh_channel_accept(session, SSH_CHANNEL_FORWARDED_TCPIP, timeout_ms, destination_port);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2411,20 +2451,22 @@ error:
|
||||
* SSH_ERROR if an error occurred,
|
||||
* SSH_AGAIN if in nonblocking mode and call has
|
||||
* to be done again.
|
||||
* @code
|
||||
* rc = channel_request_exec(channel, "ps aux");
|
||||
* if (rc > 0) {
|
||||
* return -1;
|
||||
* }
|
||||
*
|
||||
* while ((rc = channel_read(channel, buffer, sizeof(buffer), 0)) > 0) {
|
||||
* if (fwrite(buffer, 1, rc, stdout) != (unsigned int) rc) {
|
||||
* return -1;
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
* Example:
|
||||
@code
|
||||
rc = channel_request_exec(channel, "ps aux");
|
||||
if (rc > 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((rc = channel_read(channel, buffer, sizeof(buffer), 0)) > 0) {
|
||||
if (fwrite(buffer, 1, rc, stdout) != (unsigned int) rc) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@endcode
|
||||
*
|
||||
* @see channel_request_shell()
|
||||
* @see ssh_channel_request_shell()
|
||||
*/
|
||||
int ssh_channel_request_exec(ssh_channel channel, const char *cmd) {
|
||||
ssh_buffer buffer = NULL;
|
||||
@@ -2678,16 +2720,16 @@ int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_std
|
||||
/**
|
||||
* @brief Reads data from a channel.
|
||||
*
|
||||
* @param[in] channel The channel to read from.
|
||||
* @param[in] channel The channel to read from.
|
||||
*
|
||||
* @param[in] dest The destination buffer which will get the data.
|
||||
* @param[in] dest The destination buffer which will get the data.
|
||||
*
|
||||
* @param[in] count The count of bytes to be read.
|
||||
* @param[in] count The count of bytes to be read.
|
||||
*
|
||||
* @param[in] is_stderr A boolean value to mark reading from the stderr flow.
|
||||
* @param[in] is_stderr A boolean value to mark reading from the stderr flow.
|
||||
*
|
||||
* @param[in] timeout A timeout in seconds. A value of -1 means infinite
|
||||
* timeout.
|
||||
* @param[in] timeout_ms A timeout in milliseconds. A value of -1 means
|
||||
* infinite timeout.
|
||||
*
|
||||
* @return The number of bytes read, 0 on end of file or SSH_ERROR
|
||||
* on error. In nonblocking mode it Can return 0 if no data
|
||||
@@ -2803,7 +2845,7 @@ int ssh_channel_read_timeout(ssh_channel channel,
|
||||
*
|
||||
* @warning Don't forget to check for EOF as it would return 0 here.
|
||||
*
|
||||
* @see channel_is_eof()
|
||||
* @see ssh_channel_is_eof()
|
||||
*/
|
||||
int ssh_channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count,
|
||||
int is_stderr) {
|
||||
@@ -2855,7 +2897,7 @@ int ssh_channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count
|
||||
*
|
||||
* @warning When the channel is in EOF state, the function returns SSH_EOF.
|
||||
*
|
||||
* @see channel_is_eof()
|
||||
* @see ssh_channel_is_eof()
|
||||
*/
|
||||
int ssh_channel_poll(ssh_channel channel, int is_stderr){
|
||||
ssh_buffer stdbuf;
|
||||
@@ -2907,7 +2949,7 @@ int ssh_channel_poll(ssh_channel channel, int is_stderr){
|
||||
*
|
||||
* @warning When the channel is in EOF state, the function returns SSH_EOF.
|
||||
*
|
||||
* @see channel_is_eof()
|
||||
* @see ssh_channel_is_eof()
|
||||
*/
|
||||
int ssh_channel_poll_timeout(ssh_channel channel, int timeout, int is_stderr){
|
||||
ssh_session session;
|
||||
@@ -3212,7 +3254,7 @@ int ssh_channel_select(ssh_channel *readchans, ssh_channel *writechans,
|
||||
*
|
||||
* @return The number of bytes written, SSH_ERROR on error.
|
||||
*
|
||||
* @see channel_read()
|
||||
* @see ssh_channel_read()
|
||||
*/
|
||||
int ssh_channel_write_stderr(ssh_channel channel, const void *data, uint32_t len) {
|
||||
return channel_write_common(channel, data, len, 1);
|
||||
|
||||
17
src/client.c
17
src/client.c
@@ -152,19 +152,27 @@ int ssh_send_banner(ssh_session session, int server) {
|
||||
banner = session->version == 1 ? CLIENTBANNER1 : CLIENTBANNER2;
|
||||
|
||||
if (server) {
|
||||
session->serverbanner = strdup(banner);
|
||||
if(session->opts.custombanner == NULL){
|
||||
session->serverbanner = strdup(banner);
|
||||
} else {
|
||||
session->serverbanner = malloc(strlen(session->opts.custombanner) + 9);
|
||||
if(!session->serverbanner)
|
||||
goto end;
|
||||
strcpy(session->serverbanner, "SSH-2.0-");
|
||||
strcat(session->serverbanner, session->opts.custombanner);
|
||||
}
|
||||
if (session->serverbanner == NULL) {
|
||||
goto end;
|
||||
}
|
||||
snprintf(buffer, 128, "%s\n", session->serverbanner);
|
||||
} else {
|
||||
session->clientbanner = strdup(banner);
|
||||
if (session->clientbanner == NULL) {
|
||||
goto end;
|
||||
}
|
||||
snprintf(buffer, 128, "%s\n", session->clientbanner);
|
||||
}
|
||||
|
||||
snprintf(buffer, 128, "%s\n", banner);
|
||||
|
||||
if (ssh_socket_write(session->socket, buffer, strlen(buffer)) == SSH_ERROR) {
|
||||
goto end;
|
||||
}
|
||||
@@ -536,7 +544,8 @@ pending:
|
||||
}
|
||||
SSH_LOG(SSH_LOG_PACKET,"ssh_connect: Actual timeout : %d", timeout);
|
||||
ret = ssh_handle_packets_termination(session, timeout, ssh_connect_termination, session);
|
||||
if (ret == SSH_ERROR || !ssh_connect_termination(session)) {
|
||||
if (session->session_state != SSH_SESSION_STATE_ERROR &&
|
||||
(ret == SSH_ERROR || !ssh_connect_termination(session))) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Timeout connecting to %s", session->opts.host);
|
||||
session->session_state = SSH_SESSION_STATE_ERROR;
|
||||
|
||||
@@ -421,7 +421,7 @@ static int ssh_select_cb (socket_t fd, int revents, void *userdata){
|
||||
* @param[in] readfds A fd_set of file descriptors to be select'ed for
|
||||
* reading.
|
||||
*
|
||||
* @param[in] timeout A timeout for the select.
|
||||
* @param[in] timeout The timeout in milliseconds.
|
||||
*
|
||||
* @return SSH_OK on success,
|
||||
* SSH_ERROR on error,
|
||||
|
||||
2
src/dh.c
2
src/dh.c
@@ -170,7 +170,7 @@ int ssh_crypto_init(void) {
|
||||
return -1;
|
||||
}
|
||||
bignum_bin2bn(p_group14_value, P_GROUP14_LEN, &p_group14);
|
||||
if (p_group1 == NULL) {
|
||||
if (p_group14 == NULL) {
|
||||
bignum_free(g);
|
||||
bignum_free(p_group1);
|
||||
g = NULL;
|
||||
|
||||
@@ -104,7 +104,7 @@ void _ssh_set_error_invalid(void *error, const char *function)
|
||||
/**
|
||||
* @brief Retrieve the error text message from the last error.
|
||||
*
|
||||
* @param error The SSH session pointer.
|
||||
* @param error An ssh_session or ssh_bind.
|
||||
*
|
||||
* @return A static string describing the error.
|
||||
*/
|
||||
@@ -117,7 +117,7 @@ const char *ssh_get_error(void *error) {
|
||||
/**
|
||||
* @brief Retrieve the error code from the last error.
|
||||
*
|
||||
* @param error The SSH session pointer.
|
||||
* @param error An ssh_session or ssh_bind.
|
||||
*
|
||||
* \return SSH_NO_ERROR No error occurred\n
|
||||
* SSH_REQUEST_DENIED The last request was denied but situation is
|
||||
|
||||
55
src/kex.c
55
src/kex.c
@@ -35,6 +35,7 @@
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/string.h"
|
||||
#include "libssh/curve25519.h"
|
||||
#include "libssh/knownhosts.h"
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
# define BLOWFISH "blowfish-cbc,"
|
||||
@@ -373,6 +374,53 @@ void ssh_list_kex(struct ssh_kex_struct *kex) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief selects the hostkey mechanisms to be chosen for the key exchange,
|
||||
* as some hostkey mechanisms may be present in known_hosts file and preferred
|
||||
* @returns a cstring containing a comma-separated list of hostkey methods.
|
||||
* NULL if no method matches
|
||||
*/
|
||||
static char *ssh_client_select_hostkeys(ssh_session session){
|
||||
char methods_buffer[128]={0};
|
||||
static const char *preferred_hostkeys[]={"ecdsa-sha2-nistp521","ecdsa-sha2-nistp384",
|
||||
"ecdsa-sha2-nistp256", "ssh-rsa", "ssh-dss", "ssh-rsa1", NULL};
|
||||
char **methods;
|
||||
int i,j;
|
||||
int needcoma=0;
|
||||
|
||||
methods = ssh_knownhosts_algorithms(session);
|
||||
if (methods == NULL || methods[0] == NULL){
|
||||
SAFE_FREE(methods);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i=0;preferred_hostkeys[i] != NULL; ++i){
|
||||
for (j=0; methods[j] != NULL; ++j){
|
||||
if(strcmp(preferred_hostkeys[i], methods[j]) == 0){
|
||||
if (verify_existing_algo(SSH_HOSTKEYS, methods[j])){
|
||||
if(needcoma)
|
||||
strncat(methods_buffer,",",sizeof(methods_buffer)-strlen(methods_buffer)-1);
|
||||
strncat(methods_buffer, methods[j], sizeof(methods_buffer)-strlen(methods_buffer)-1);
|
||||
needcoma = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for(i=0;methods[i]!= NULL; ++i){
|
||||
SAFE_FREE(methods[i]);
|
||||
}
|
||||
SAFE_FREE(methods);
|
||||
|
||||
if(strlen(methods_buffer) > 0){
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Changing host key method to \"%s\"", methods_buffer);
|
||||
return strdup(methods_buffer);
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_DEBUG, "No supported kex method for existing key in known_hosts file");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* @brief sets the key exchange parameters to be sent to the server,
|
||||
* in function of the options and available methods.
|
||||
@@ -385,6 +433,13 @@ int set_client_kex(ssh_session session){
|
||||
ssh_get_random(client->cookie, 16, 0);
|
||||
|
||||
memset(client->methods, 0, KEX_METHODS_SIZE * sizeof(char **));
|
||||
/* first check if we have specific host key methods */
|
||||
if(session->opts.wanted_methods[SSH_HOSTKEYS] == NULL){
|
||||
/* Only if no override */
|
||||
session->opts.wanted_methods[SSH_HOSTKEYS] =
|
||||
ssh_client_select_hostkeys(session);
|
||||
}
|
||||
|
||||
for (i = 0; i < KEX_METHODS_SIZE; i++) {
|
||||
wanted = session->opts.wanted_methods[i];
|
||||
if (wanted == NULL)
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "libssh/misc.h"
|
||||
#include "libssh/pki.h"
|
||||
#include "libssh/options.h"
|
||||
|
||||
#include "libssh/knownhosts.h"
|
||||
/*todo: remove this include */
|
||||
#include "libssh/string.h"
|
||||
|
||||
@@ -647,6 +647,102 @@ int ssh_write_knownhost(ssh_session session) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define KNOWNHOSTS_MAXTYPES 10
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief Check which kind of host keys should be preferred for connection
|
||||
* by reading the known_hosts file.
|
||||
*
|
||||
* @param[in] session The SSH session to use.
|
||||
*
|
||||
* @returns array of supported key types
|
||||
* NULL on error
|
||||
*/
|
||||
char **ssh_knownhosts_algorithms(ssh_session session) {
|
||||
FILE *file = NULL;
|
||||
char **tokens;
|
||||
char *host;
|
||||
char *hostport;
|
||||
const char *type;
|
||||
int match;
|
||||
char **array;
|
||||
int i=0, j;
|
||||
|
||||
if (session->opts.knownhosts == NULL) {
|
||||
if (ssh_options_apply(session) < 0) {
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"Can't find a known_hosts file");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (session->opts.host == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
host = ssh_lowercase(session->opts.host);
|
||||
hostport = ssh_hostport(host, session->opts.port);
|
||||
array = malloc(sizeof(char *) * KNOWNHOSTS_MAXTYPES);
|
||||
|
||||
if (host == NULL || hostport == NULL || array == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
SAFE_FREE(host);
|
||||
SAFE_FREE(hostport);
|
||||
SAFE_FREE(array);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
do {
|
||||
tokens = ssh_get_knownhost_line(&file,
|
||||
session->opts.knownhosts, &type);
|
||||
|
||||
/* End of file, return the current state */
|
||||
if (tokens == NULL) {
|
||||
break;
|
||||
}
|
||||
match = match_hashed_host(host, tokens[0]);
|
||||
if (match == 0){
|
||||
match = match_hostname(hostport, tokens[0], strlen(tokens[0]));
|
||||
}
|
||||
if (match == 0) {
|
||||
match = match_hostname(host, tokens[0], strlen(tokens[0]));
|
||||
}
|
||||
if (match == 0) {
|
||||
match = match_hashed_host(hostport, tokens[0]);
|
||||
}
|
||||
if (match) {
|
||||
/* We got a match. Now check the key type */
|
||||
SSH_LOG(SSH_LOG_DEBUG, "server %s:%d has %s in known_hosts",
|
||||
host, session->opts.port, type);
|
||||
/* don't copy more than once */
|
||||
for(j=0;j<i && match;++j){
|
||||
if(strcmp(array[j], type)==0)
|
||||
match=0;
|
||||
}
|
||||
if (match){
|
||||
array[i] = strdup(type);
|
||||
i++;
|
||||
if(i>= KNOWNHOSTS_MAXTYPES-1){
|
||||
tokens_free(tokens);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
tokens_free(tokens);
|
||||
} while (1);
|
||||
|
||||
array[i]=NULL;
|
||||
SAFE_FREE(host);
|
||||
SAFE_FREE(hostport);
|
||||
if (file != NULL) {
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
/* Return the current state at end of file */
|
||||
return array;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/* vim: set ts=4 sw=4 et cindent: */
|
||||
|
||||
@@ -208,8 +208,8 @@ static int ssh_execute_server_request(ssh_session session, ssh_message msg)
|
||||
ssh_callbacks_exists(channel->callbacks, channel_pty_window_change_function)) {
|
||||
rc = channel->callbacks->channel_pty_window_change_function(session,
|
||||
channel,
|
||||
msg->channel_request.height, msg->channel_request.width,
|
||||
msg->channel_request.pxheight, msg->channel_request.pxwidth,
|
||||
msg->channel_request.width, msg->channel_request.height,
|
||||
msg->channel_request.pxwidth, msg->channel_request.pxheight,
|
||||
channel->callbacks->userdata);
|
||||
} else if (msg->channel_request.type == SSH_CHANNEL_REQUEST_EXEC &&
|
||||
ssh_callbacks_exists(channel->callbacks, channel_exec_request_function)) {
|
||||
|
||||
@@ -697,7 +697,6 @@ char *ssh_path_expand_tilde(const char *d) {
|
||||
}
|
||||
|
||||
char *ssh_path_expand_escape(ssh_session session, const char *s) {
|
||||
#define MAX_BUF_SIZE 4096
|
||||
char host[NI_MAXHOST];
|
||||
char buf[MAX_BUF_SIZE];
|
||||
char *r, *x = NULL;
|
||||
|
||||
18
src/packet.c
18
src/packet.c
@@ -251,12 +251,18 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
|
||||
* Decrypt the rest of the packet (blocksize bytes already
|
||||
* have been decrypted)
|
||||
*/
|
||||
rc = packet_decrypt(session,
|
||||
((uint8_t*)buffer_get_rest(session->in_buffer) + blocksize),
|
||||
buffer_get_rest_len(session->in_buffer) - blocksize);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Decrypt error");
|
||||
goto error;
|
||||
uint32_t buffer_len = buffer_get_rest_len(session->in_buffer);
|
||||
|
||||
/* The following check avoids decrypting zero bytes */
|
||||
if (buffer_len > blocksize) {
|
||||
uint8_t *payload = ((uint8_t*)buffer_get_rest(session->in_buffer) + blocksize);
|
||||
uint32_t plen = buffer_len - blocksize;
|
||||
|
||||
rc = packet_decrypt(session, payload, plen);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Decrypt error");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* copy the last part from the incoming buffer */
|
||||
|
||||
@@ -106,7 +106,7 @@ int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user
|
||||
size_t processed=0;
|
||||
uint32_t padding;
|
||||
uint32_t crc;
|
||||
uint32_t len;
|
||||
uint32_t len, buffer_len;
|
||||
ssh_session session=(ssh_session)user;
|
||||
|
||||
switch (session->packet_state){
|
||||
@@ -168,11 +168,16 @@ int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user
|
||||
* We decrypt everything, missing the lenght part (which was
|
||||
* previously read, unencrypted, and is not part of the buffer
|
||||
*/
|
||||
if (packet_decrypt(session,
|
||||
ssh_buffer_get_begin(session->in_buffer),
|
||||
ssh_buffer_get_len(session->in_buffer)) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Packet decrypt error");
|
||||
goto error;
|
||||
buffer_len = ssh_buffer_get_len(session->in_buffer);
|
||||
if (buffer_len > 0) {
|
||||
int rc;
|
||||
rc = packet_decrypt(session,
|
||||
ssh_buffer_get_begin(session->in_buffer),
|
||||
buffer_len);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Packet decrypt error");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_CRYPTO
|
||||
@@ -300,6 +305,8 @@ int packet_send1(ssh_session session) {
|
||||
ssh_buffer_get_len(session->out_buffer));
|
||||
#endif
|
||||
|
||||
/* session->out_buffer should have more than sizeof(uint32_t) bytes
|
||||
in it as required for packet_encrypt */
|
||||
packet_encrypt(session, (unsigned char *)ssh_buffer_get_begin(session->out_buffer) + sizeof(uint32_t),
|
||||
ssh_buffer_get_len(session->out_buffer) - sizeof(uint32_t));
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -59,6 +60,9 @@ uint32_t packet_decrypt_len(ssh_session session, char *crypted){
|
||||
int packet_decrypt(ssh_session session, void *data,uint32_t len) {
|
||||
struct ssh_cipher_struct *crypto = session->current_crypto->in_cipher;
|
||||
char *out = NULL;
|
||||
|
||||
assert(len);
|
||||
|
||||
if(len % session->current_crypto->in_cipher->blocksize != 0){
|
||||
ssh_set_error(session, SSH_FATAL, "Cryptographic functions must be set on at least one blocksize (received %d)",len);
|
||||
return SSH_ERROR;
|
||||
@@ -89,6 +93,8 @@ unsigned char *packet_encrypt(ssh_session session, void *data, uint32_t len) {
|
||||
unsigned int finallen;
|
||||
uint32_t seq;
|
||||
|
||||
assert(len);
|
||||
|
||||
if (!session->current_crypto) {
|
||||
return NULL; /* nothing to do here */
|
||||
}
|
||||
|
||||
164
src/pki_crypto.c
164
src/pki_crypto.c
@@ -200,9 +200,11 @@ int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* EC_KEY_set_public_key duplicates p */
|
||||
ok = EC_KEY_set_public_key(key->ecdsa, p);
|
||||
EC_POINT_free(p);
|
||||
if (!ok) {
|
||||
EC_POINT_free(p);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1094,41 +1096,65 @@ static ssh_string _RSA_do_sign(const unsigned char *digest,
|
||||
return sig_blob;
|
||||
}
|
||||
|
||||
static ssh_string pki_dsa_signature_to_blob(const ssh_signature sig)
|
||||
{
|
||||
char buffer[40] = { 0 };
|
||||
ssh_string sig_blob = NULL;
|
||||
|
||||
ssh_string r;
|
||||
int r_len, r_offset_in, r_offset_out;
|
||||
|
||||
ssh_string s;
|
||||
int s_len, s_offset_in, s_offset_out;
|
||||
|
||||
r = make_bignum_string(sig->dsa_sig->r);
|
||||
if (r == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = make_bignum_string(sig->dsa_sig->s);
|
||||
if (s == NULL) {
|
||||
ssh_string_free(r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r_len = ssh_string_len(r);
|
||||
r_offset_in = (r_len > 20) ? (r_len - 20) : 0;
|
||||
r_offset_out = (r_len < 20) ? (20 - r_len) : 0;
|
||||
|
||||
s_len = ssh_string_len(s);
|
||||
s_offset_in = (s_len > 20) ? (s_len - 20) : 0;
|
||||
s_offset_out = (s_len < 20) ? (20 - s_len) : 0;
|
||||
|
||||
memcpy(buffer + r_offset_out,
|
||||
((char *)ssh_string_data(r)) + r_offset_in,
|
||||
r_len - r_offset_in);
|
||||
memcpy(buffer + 20 + s_offset_out,
|
||||
((char *)ssh_string_data(s)) + s_offset_in,
|
||||
s_len - s_offset_in);
|
||||
|
||||
ssh_string_free(r);
|
||||
ssh_string_free(s);
|
||||
|
||||
sig_blob = ssh_string_new(40);
|
||||
if (sig_blob == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssh_string_fill(sig_blob, buffer, 40);
|
||||
|
||||
return sig_blob;
|
||||
}
|
||||
|
||||
ssh_string pki_signature_to_blob(const ssh_signature sig)
|
||||
{
|
||||
char buffer[40] = {0};
|
||||
ssh_string sig_blob = NULL;
|
||||
ssh_string r;
|
||||
ssh_string s;
|
||||
ssh_string sig_blob = NULL;
|
||||
|
||||
switch(sig->type) {
|
||||
case SSH_KEYTYPE_DSS:
|
||||
r = make_bignum_string(sig->dsa_sig->r);
|
||||
if (r == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
s = make_bignum_string(sig->dsa_sig->s);
|
||||
if (s == NULL) {
|
||||
ssh_string_free(r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(buffer,
|
||||
((char *)ssh_string_data(r)) + ssh_string_len(r) - 20,
|
||||
20);
|
||||
memcpy(buffer + 20,
|
||||
((char *)ssh_string_data(s)) + ssh_string_len(s) - 20,
|
||||
20);
|
||||
|
||||
ssh_string_free(r);
|
||||
ssh_string_free(s);
|
||||
|
||||
sig_blob = ssh_string_new(40);
|
||||
if (sig_blob == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssh_string_fill(sig_blob, buffer, 40);
|
||||
sig_blob = pki_dsa_signature_to_blob(sig);
|
||||
break;
|
||||
case SSH_KEYTYPE_RSA:
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
@@ -1188,6 +1214,61 @@ ssh_string pki_signature_to_blob(const ssh_signature sig)
|
||||
return sig_blob;
|
||||
}
|
||||
|
||||
static ssh_signature pki_signature_from_rsa_blob(const ssh_key pubkey,
|
||||
const ssh_string sig_blob,
|
||||
ssh_signature sig)
|
||||
{
|
||||
uint32_t pad_len = 0;
|
||||
char *blob_orig;
|
||||
char *blob_padded_data;
|
||||
ssh_string sig_blob_padded;
|
||||
|
||||
size_t len = ssh_string_len(sig_blob);
|
||||
size_t rsalen= RSA_size(pubkey->rsa);
|
||||
|
||||
if (len > rsalen) {
|
||||
ssh_pki_log("Signature is too big: %lu > %lu",
|
||||
(unsigned long)len, (unsigned long)rsalen);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_pki_log("RSA signature len: %lu", (unsigned long)len);
|
||||
ssh_print_hexa("RSA signature", ssh_string_data(sig_blob), len);
|
||||
#endif
|
||||
|
||||
if (len == rsalen) {
|
||||
sig->rsa_sig = ssh_string_copy(sig_blob);
|
||||
} else {
|
||||
/* pad the blob to the expected rsalen size */
|
||||
ssh_pki_log("RSA signature len %lu < %lu",
|
||||
(unsigned long)len, (unsigned long)rsalen);
|
||||
|
||||
pad_len = rsalen - len;
|
||||
|
||||
sig_blob_padded = ssh_string_new(rsalen);
|
||||
if (sig_blob_padded == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
blob_padded_data = (char *) ssh_string_data(sig_blob_padded);
|
||||
blob_orig = (char *) ssh_string_data(sig_blob);
|
||||
|
||||
/* front-pad the buffer with zeroes */
|
||||
BURN_BUFFER(blob_padded_data, pad_len);
|
||||
/* fill the rest with the actual signature blob */
|
||||
memcpy(blob_padded_data + pad_len, blob_orig, len);
|
||||
|
||||
sig->rsa_sig = sig_blob_padded;
|
||||
}
|
||||
|
||||
return sig;
|
||||
|
||||
errout:
|
||||
ssh_signature_free(sig);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
const ssh_string sig_blob,
|
||||
enum ssh_keytypes_e type)
|
||||
@@ -1196,7 +1277,6 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
ssh_string r;
|
||||
ssh_string s;
|
||||
size_t len;
|
||||
size_t rsalen;
|
||||
|
||||
sig = ssh_signature_new();
|
||||
if (sig == NULL) {
|
||||
@@ -1260,29 +1340,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
break;
|
||||
case SSH_KEYTYPE_RSA:
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
rsalen = RSA_size(pubkey->rsa);
|
||||
|
||||
if (len > rsalen) {
|
||||
ssh_pki_log("Signature is to big size: %lu",
|
||||
(unsigned long)len);
|
||||
ssh_signature_free(sig);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (len < rsalen) {
|
||||
ssh_pki_log("RSA signature len %lu < %lu",
|
||||
(unsigned long)len, (unsigned long)rsalen);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_pki_log("RSA signature len: %lu", (unsigned long)len);
|
||||
ssh_print_hexa("RSA signature", ssh_string_data(sig_blob), len);
|
||||
#endif
|
||||
sig->rsa_sig = ssh_string_copy(sig_blob);
|
||||
if (sig->rsa_sig == NULL) {
|
||||
ssh_signature_free(sig);
|
||||
return NULL;
|
||||
}
|
||||
sig = pki_signature_from_rsa_blob(pubkey, sig_blob, sig);
|
||||
break;
|
||||
case SSH_KEYTYPE_ECDSA:
|
||||
#ifdef HAVE_OPENSSL_ECC
|
||||
|
||||
@@ -545,7 +545,7 @@ int ssh_scp_read_string(ssh_scp scp, char *buffer, size_t len){
|
||||
* @see ssh_scp_request_get_warning()
|
||||
*/
|
||||
int ssh_scp_pull_request(ssh_scp scp){
|
||||
char buffer[4096] = {0};
|
||||
char buffer[MAX_BUF_SIZE] = {0};
|
||||
char *mode=NULL;
|
||||
char *p,*tmp;
|
||||
uint64_t size;
|
||||
@@ -642,7 +642,7 @@ int ssh_scp_pull_request(ssh_scp scp){
|
||||
* the message failed, or sending it in a bad state.
|
||||
*/
|
||||
int ssh_scp_deny_request(ssh_scp scp, const char *reason){
|
||||
char buffer[4096];
|
||||
char buffer[MAX_BUF_SIZE];
|
||||
int err;
|
||||
if(scp==NULL)
|
||||
return SSH_ERROR;
|
||||
@@ -814,7 +814,7 @@ int ssh_scp_integer_mode(const char *mode){
|
||||
*/
|
||||
char *ssh_scp_string_mode(int mode){
|
||||
char buffer[16];
|
||||
snprintf(buffer,sizeof(buffer),"%.4d",mode);
|
||||
snprintf(buffer,sizeof(buffer),"%.4o",mode);
|
||||
return strdup(buffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -309,6 +309,38 @@ const char* ssh_get_serverbanner(ssh_session session) {
|
||||
return session->serverbanner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the name of the input for the given session.
|
||||
*
|
||||
* @param[in] session The SSH session.
|
||||
*
|
||||
* @return Returns cipher name or NULL.
|
||||
*/
|
||||
const char* ssh_get_cipher_in(ssh_session session) {
|
||||
if ((session != NULL) &&
|
||||
(session->current_crypto != NULL) &&
|
||||
(session->current_crypto->in_cipher != NULL)) {
|
||||
return session->current_crypto->in_cipher->name;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the name of the output cipher for the given session.
|
||||
*
|
||||
* @param[in] session The SSH session.
|
||||
*
|
||||
* @return Returns cipher name or NULL.
|
||||
*/
|
||||
const char* ssh_get_cipher_out(ssh_session session) {
|
||||
if ((session != NULL) &&
|
||||
(session->current_crypto != NULL) &&
|
||||
(session->current_crypto->out_cipher != NULL)) {
|
||||
return session->current_crypto->out_cipher->name;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disconnect impolitely from a remote host by closing the socket.
|
||||
*
|
||||
@@ -567,7 +599,11 @@ int ssh_handle_packets_termination(ssh_session session,
|
||||
}
|
||||
}
|
||||
|
||||
ssh_timestamp_init(&ts);
|
||||
/* avoid unnecessary syscall for the SSH_TIMEOUT_NONBLOCKING case */
|
||||
if (timeout != SSH_TIMEOUT_NONBLOCKING) {
|
||||
ssh_timestamp_init(&ts);
|
||||
}
|
||||
|
||||
tm = timeout;
|
||||
while(!fct(user)) {
|
||||
ret = ssh_handle_packets(session, tm);
|
||||
@@ -695,8 +731,13 @@ void ssh_socket_exception_callback(int code, int errno_code, void *user){
|
||||
ssh_session session=(ssh_session)user;
|
||||
|
||||
SSH_LOG(SSH_LOG_RARE,"Socket exception callback: %d (%d)",code, errno_code);
|
||||
session->session_state=SSH_SESSION_STATE_ERROR;
|
||||
ssh_set_error(session,SSH_FATAL,"Socket error: %s",strerror(errno_code));
|
||||
session->session_state = SSH_SESSION_STATE_ERROR;
|
||||
if (errno_code == 0 && code == SSH_SOCKET_EXCEPTION_EOF) {
|
||||
ssh_set_error(session, SSH_FATAL, "Socket error: disconnected");
|
||||
} else {
|
||||
ssh_set_error(session, SSH_FATAL, "Socket error: %s", strerror(errno_code));
|
||||
}
|
||||
|
||||
session->ssh_connection_callback(session);
|
||||
}
|
||||
|
||||
|
||||
@@ -308,7 +308,7 @@ int sftp_packet_write(sftp_session sftp, uint8_t type, ssh_buffer payload){
|
||||
}
|
||||
|
||||
sftp_packet sftp_packet_read(sftp_session sftp) {
|
||||
unsigned char buffer[4096];
|
||||
unsigned char buffer[MAX_BUF_SIZE];
|
||||
sftp_packet packet = NULL;
|
||||
uint32_t size;
|
||||
int r;
|
||||
|
||||
@@ -218,7 +218,7 @@ void ssh_socket_set_callbacks(ssh_socket s, ssh_socket_callbacks callbacks){
|
||||
*/
|
||||
int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int revents, void *v_s){
|
||||
ssh_socket s=(ssh_socket )v_s;
|
||||
char buffer[4096];
|
||||
char buffer[MAX_BUF_SIZE];
|
||||
int r;
|
||||
int err=0;
|
||||
socklen_t errlen=sizeof(err);
|
||||
@@ -291,7 +291,7 @@ int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int r
|
||||
buffer_get_rest_len(s->in_buffer),
|
||||
s->callbacks->userdata);
|
||||
buffer_pass_bytes(s->in_buffer,r);
|
||||
} while (r > 0);
|
||||
} while ((r > 0) && (s->state == SSH_SOCKET_CONNECTED));
|
||||
/* p may have been freed, so don't use it
|
||||
* anymore in this function */
|
||||
p = NULL;
|
||||
@@ -440,6 +440,8 @@ void ssh_socket_close(ssh_socket s){
|
||||
ssh_poll_free(s->poll_out);
|
||||
s->poll_out=NULL;
|
||||
}
|
||||
|
||||
s->state = SSH_SOCKET_CLOSED;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -59,8 +59,28 @@ struct ssh_threads_callbacks_struct *ssh_threads_get_noop(void) {
|
||||
static struct ssh_threads_callbacks_struct *user_callbacks =&ssh_threads_noop;
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
#if (GCRYPT_VERSION_NUMBER >= 0x010600)
|
||||
/* libgcrypt >= 1.6 does not support custom callbacks */
|
||||
GCRY_THREAD_OPTION_PTHREAD_IMPL;
|
||||
|
||||
/* Libgcrypt specific way of handling thread callbacks */
|
||||
static int libgcrypt_thread_init(void){
|
||||
if(user_callbacks == NULL)
|
||||
return SSH_ERROR;
|
||||
if(user_callbacks == &ssh_threads_noop)
|
||||
return SSH_OK;
|
||||
if (strcmp(user_callbacks->type, "threads_pthread") == 0){
|
||||
gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
|
||||
return SSH_OK;
|
||||
} else {
|
||||
/* not supported */
|
||||
SSH_LOG(SSH_LOG_WARN, "Custom thread handlers not supported with libgcrypt >=1.6, using pthreads");
|
||||
gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
|
||||
return SSH_OK;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
/* Libgcrypt < 1.6 specific way of handling thread callbacks */
|
||||
|
||||
static struct gcry_thread_cbs gcrypt_threads_callbacks;
|
||||
|
||||
@@ -79,7 +99,8 @@ static int libgcrypt_thread_init(void){
|
||||
gcry_control(GCRYCTL_SET_THREAD_CBS, &gcrypt_threads_callbacks);
|
||||
return SSH_OK;
|
||||
}
|
||||
#else
|
||||
#endif /* GCRYPT_VERSION_NUMBER */
|
||||
#else /* HAVE_LIBGCRYPT */
|
||||
|
||||
/* Libcrypto specific stuff */
|
||||
|
||||
|
||||
@@ -23,8 +23,26 @@
|
||||
|
||||
#include "torture.h"
|
||||
#include "session.c"
|
||||
#include "known_hosts.c"
|
||||
|
||||
#define KNOWNHOSTFILES "libssh_torture_knownhosts"
|
||||
#define BADRSA "AAAAB3NzaC1yc2EAAAADAQABAAABAQChm5" \
|
||||
"a6Av65O8cKtx5YXOnui3wJnYE6A6J/I4kZSAibbn14Jcl+34VJQwv96f25AxNmo" \
|
||||
"NwoiZV93IzdypQmiuieh6s6wB9WhYjU9K/6CkIpNhpCxswA90b3ePjS7LnR9B9J" \
|
||||
"slPSbG1H0KC1c5lb7G3utXteXtM+4YvCvpN5VdC4CpghT+p0cwN2Na8Md5vRItz" \
|
||||
"YgIytryNn7LLiwYfoSxvWigFrTTZsrVtCOYyNgklmffpGdzuC43wdANvTewfI9G" \
|
||||
"o71r8EXmEc228CrYPmb8Scv3mpXFK/BosohSGkPlEHu9lf3YjnknBicDaVtJOYp" \
|
||||
"wnXJPjZo2EhG79HxDRpjJHH"
|
||||
#define BADDSA "AAAAB3NzaC1kc3MAAACBAITDKqGQ5aC5wHySG6ZdL1+BVBY2nLP5vzw3i3pvZfP" \
|
||||
"yNUS0UCwrt5pajsMvDRGXXebTJhWVonDnv8tpSgiuIBXMZrma8CU1KCFGRzwb/n8" \
|
||||
"cc5tJmIphlOUTrObjBmsRz7u1eZmoaddXC9ask6BNnt0DmhzYi2esL3mbardy8IN" \
|
||||
"zAAAAFQDlPFCm410pgQQPb3X5FWjyVEIl+QAAAIAp0vqfir8K8p+zP4dzFG7ppnt" \
|
||||
"DjaXf3ge6URF7f5xPDo6CClGo2JQ2REF8NxM7K9cLgR9Ifx2ahO48UMgrXEl/BOp" \
|
||||
"IQHpeBqUz26a49O5J0WEW16YSUHxWwMxWVe/SRmyKdTUZJ6fcepH88JNqm3XudNn" \
|
||||
"s78grM+yx9mcXnK2AsAAAAIBxpF8ZQIlGrSgwCmCfwjP156bC3Ya6LYf9ZpLJ0dX" \
|
||||
"EcxqLVllrNEvd2EGD9p16BYO2yaalYon8im59PtOcul2ay5XQ6rVDQ2T0pgNUpsI" \
|
||||
"h0dSi8VJXI1wes5HTyLsv9VBmU1uCXUUvufoQKfF/OcSH0ufcCpnd62g1/adZcy2" \
|
||||
"WJg=="
|
||||
|
||||
static void setup(void **state) {
|
||||
int verbosity=torture_libssh_verbosity();
|
||||
@@ -93,10 +111,184 @@ static void torture_knownhosts_port(void **state) {
|
||||
assert_true(rc == SSH_SERVER_KNOWN_OK);
|
||||
}
|
||||
|
||||
static void torture_knownhosts_fail(void **state) {
|
||||
ssh_session session = *state;
|
||||
FILE *file;
|
||||
int rc;
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, "ssh-rsa");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
file = fopen(KNOWNHOSTFILES, "w");
|
||||
assert_true(file != NULL);
|
||||
fprintf(file, "localhost ssh-rsa %s\n", BADRSA);
|
||||
fclose(file);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_true(rc==SSH_OK);
|
||||
|
||||
rc = ssh_is_server_known(session);
|
||||
assert_true(rc == SSH_SERVER_KNOWN_CHANGED);
|
||||
}
|
||||
|
||||
static void torture_knownhosts_other(void **state) {
|
||||
ssh_session session = *state;
|
||||
FILE *file;
|
||||
int rc;
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, "ssh-dss");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
file = fopen(KNOWNHOSTFILES, "w");
|
||||
assert_true(file != NULL);
|
||||
fprintf(file, "localhost ssh-rsa %s\n", BADRSA);
|
||||
fclose(file);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_true(rc==SSH_OK);
|
||||
|
||||
rc = ssh_is_server_known(session);
|
||||
assert_true(rc == SSH_SERVER_FOUND_OTHER);
|
||||
}
|
||||
|
||||
static void torture_knownhosts_other_auto(void **state) {
|
||||
ssh_session session = *state;
|
||||
int rc;
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, "ssh-dss");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_true(rc==SSH_OK);
|
||||
|
||||
rc = ssh_is_server_known(session);
|
||||
assert_true(rc == SSH_SERVER_NOT_KNOWN);
|
||||
|
||||
rc = ssh_write_knownhost(session);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
ssh_disconnect(session);
|
||||
ssh_free(session);
|
||||
|
||||
/* connect again and check host key */
|
||||
*state = session = ssh_new();
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_true(rc==SSH_OK);
|
||||
|
||||
/* ssh-rsa is the default but libssh should try ssh-dss instead */
|
||||
rc = ssh_is_server_known(session);
|
||||
assert_true(rc == SSH_SERVER_KNOWN_OK);
|
||||
}
|
||||
|
||||
static void torture_knownhosts_conflict(void **state) {
|
||||
ssh_session session = *state;
|
||||
FILE *file;
|
||||
int rc;
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, "ssh-rsa");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
file = fopen(KNOWNHOSTFILES, "w");
|
||||
assert_true(file != NULL);
|
||||
fprintf(file, "localhost ssh-rsa %s\n", BADRSA);
|
||||
fprintf(file, "localhost ssh-dss %s\n", BADDSA);
|
||||
fclose(file);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_true(rc==SSH_OK);
|
||||
|
||||
rc = ssh_is_server_known(session);
|
||||
assert_true(rc == SSH_SERVER_KNOWN_CHANGED);
|
||||
|
||||
rc = ssh_write_knownhost(session);
|
||||
assert_true(rc==SSH_OK);
|
||||
|
||||
ssh_disconnect(session);
|
||||
ssh_free(session);
|
||||
|
||||
/* connect again and check host key */
|
||||
*state = session = ssh_new();
|
||||
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, "ssh-rsa");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_is_server_known(session);
|
||||
assert_true(rc == SSH_SERVER_KNOWN_OK);
|
||||
}
|
||||
|
||||
static void torture_knownhosts_precheck(void **state) {
|
||||
ssh_session session = *state;
|
||||
FILE *file;
|
||||
int rc;
|
||||
char **kex;
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
file = fopen(KNOWNHOSTFILES, "w");
|
||||
assert_true(file != NULL);
|
||||
fprintf(file, "localhost ssh-rsa %s\n", BADRSA);
|
||||
fprintf(file, "localhost ssh-dss %s\n", BADDSA);
|
||||
fclose(file);
|
||||
|
||||
kex = ssh_knownhosts_algorithms(session);
|
||||
assert_true(kex != NULL);
|
||||
assert_string_equal(kex[0],"ssh-rsa");
|
||||
assert_string_equal(kex[1],"ssh-dss");
|
||||
assert_true(kex[2]==NULL);
|
||||
free(kex[1]);
|
||||
free(kex[0]);
|
||||
free(kex);
|
||||
}
|
||||
|
||||
int torture_run_tests(void) {
|
||||
int rc;
|
||||
const UnitTest tests[] = {
|
||||
unit_test_setup_teardown(torture_knownhosts_port, setup, teardown),
|
||||
unit_test_setup_teardown(torture_knownhosts_fail, setup, teardown),
|
||||
unit_test_setup_teardown(torture_knownhosts_other, setup, teardown),
|
||||
unit_test_setup_teardown(torture_knownhosts_other_auto, setup, teardown),
|
||||
unit_test_setup_teardown(torture_knownhosts_conflict, setup, teardown),
|
||||
unit_test_setup_teardown(torture_knownhosts_precheck, setup, teardown)
|
||||
};
|
||||
|
||||
ssh_init();
|
||||
|
||||
139
tests/test_ssh_bind_accept_fd.c
Normal file
139
tests/test_ssh_bind_accept_fd.c
Normal file
@@ -0,0 +1,139 @@
|
||||
/* Test the ability to use ssh_bind_accept_fd.
|
||||
*
|
||||
* Expected behavior: Prints "SUCCESS!"
|
||||
*
|
||||
* Faulty behavior observed before change: Connection timeout
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <err.h>
|
||||
#include <libssh/libssh.h>
|
||||
#include <libssh/server.h>
|
||||
#include <netinet/in.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct options {
|
||||
const char *server_keyfile;
|
||||
} options;
|
||||
|
||||
const char HOST[] = "127.0.0.1";
|
||||
const int PORT = 3333;
|
||||
|
||||
int get_connection() {
|
||||
int rc, server_socket, client_conn = -1;
|
||||
struct sockaddr_in server_socket_addr;
|
||||
struct sockaddr_storage client_conn_addr;
|
||||
socklen_t client_conn_addr_size = sizeof(client_conn_addr);
|
||||
|
||||
server_socket = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (server_socket < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
server_socket_addr.sin_family = AF_INET;
|
||||
server_socket_addr.sin_port = htons(PORT);
|
||||
if (inet_pton(AF_INET, HOST, &server_socket_addr.sin_addr) != 1) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = bind(server_socket, (struct sockaddr *)&server_socket_addr,
|
||||
sizeof(server_socket_addr));
|
||||
if (rc < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (listen(server_socket, 0) < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
client_conn = accept(server_socket,
|
||||
(struct sockaddr *)&client_conn_addr,
|
||||
&client_conn_addr_size);
|
||||
|
||||
out:
|
||||
return client_conn;
|
||||
}
|
||||
|
||||
void ssh_server() {
|
||||
ssh_bind bind;
|
||||
ssh_session session;
|
||||
|
||||
int client_conn = get_connection();
|
||||
if (client_conn < 0) {
|
||||
err(1, "get_connection");
|
||||
}
|
||||
|
||||
bind = ssh_bind_new();
|
||||
if (!bind) {
|
||||
errx(1, "ssh_bind_new");
|
||||
}
|
||||
|
||||
if (ssh_bind_options_set(bind, SSH_BIND_OPTIONS_DSAKEY,
|
||||
options.server_keyfile) != SSH_OK) {
|
||||
errx(1, "ssh_bind_options_set(SSH_BIND_OPTIONS_DSAKEY");
|
||||
}
|
||||
|
||||
session = ssh_new();
|
||||
if (!session) {
|
||||
errx(1, "ssh_new");
|
||||
}
|
||||
|
||||
if (ssh_bind_accept_fd(bind, session, client_conn) != SSH_OK) {
|
||||
errx(1, "ssh_bind_accept: %s", ssh_get_error(bind));
|
||||
}
|
||||
|
||||
if (ssh_handle_key_exchange(session) != SSH_OK) {
|
||||
errx(1, "ssh_handle_key_exchange: %s", ssh_get_error(session));
|
||||
}
|
||||
|
||||
printf("SUCCESS!\n");
|
||||
}
|
||||
|
||||
void ssh_client() {
|
||||
ssh_session session;
|
||||
|
||||
session = ssh_new();
|
||||
if (!session) {
|
||||
errx(1, "ssh_new");
|
||||
}
|
||||
|
||||
if (ssh_options_set(session, SSH_OPTIONS_HOST, HOST) < 0) {
|
||||
errx(1, "ssh_options_set(SSH_OPTIONS_HOST)");
|
||||
}
|
||||
if (ssh_options_set(session, SSH_OPTIONS_PORT, &PORT) < 0) {
|
||||
errx(1, "ssh_options_set(SSH_OPTIONS_PORT)");
|
||||
}
|
||||
|
||||
if (ssh_connect(session) != SSH_OK) {
|
||||
errx(1, "ssh_connect: %s", ssh_get_error(session));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
if (argc != 2) {
|
||||
printf("Usage: %s <private key file>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
options.server_keyfile = argv[1];
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
errx(1, "fork");
|
||||
}
|
||||
if (pid == 0) {
|
||||
/* Allow the server to get set up */
|
||||
sleep(3);
|
||||
|
||||
ssh_client();
|
||||
} else {
|
||||
ssh_server();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user