mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-05 12:50:30 +09:00
Compare commits
30 Commits
libssh-0.1
...
libssh-0.9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79900e5246 | ||
|
|
63b0399373 | ||
|
|
39665fd9c5 | ||
|
|
83f0be1f04 | ||
|
|
3bc5f88f77 | ||
|
|
466ca07626 | ||
|
|
b6e757d692 | ||
|
|
3f2375e948 | ||
|
|
4d06c2f283 | ||
|
|
0298bfbbf0 | ||
|
|
2399a9f8de | ||
|
|
79756c5c56 | ||
|
|
e8510043d2 | ||
|
|
1f7889f271 | ||
|
|
89efd56217 | ||
|
|
e3fca31c59 | ||
|
|
d71a7976dd | ||
|
|
8fe8d13e29 | ||
|
|
722f979790 | ||
|
|
2c60ef04d9 | ||
|
|
ec486d13db | ||
|
|
ebfe46f6ad | ||
|
|
3c0897b975 | ||
|
|
993e0df81e | ||
|
|
551188d99b | ||
|
|
cafafe8f5a | ||
|
|
c6c7856b51 | ||
|
|
ea71af9c22 | ||
|
|
bb98413fc1 | ||
|
|
2a8cd81e8f |
@@ -6,7 +6,7 @@ variables:
|
|||||||
MINGW_BUILD: buildenv-mingw
|
MINGW_BUILD: buildenv-mingw
|
||||||
DEBIAN_CROSS_BUILD: buildenv-debian-cross
|
DEBIAN_CROSS_BUILD: buildenv-debian-cross
|
||||||
|
|
||||||
# torture_auth fails on centos7 docker images, so we don't use -DCLIENT_TESTING=ON
|
# pkd tests fail on CentOS7 docker images, so we don't use -DSERVER_TESTING=ON
|
||||||
centos7/openssl_1.0.x/x86_64:
|
centos7/openssl_1.0.x/x86_64:
|
||||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS7_BUILD
|
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS7_BUILD
|
||||||
script:
|
script:
|
||||||
@@ -14,7 +14,7 @@ centos7/openssl_1.0.x/x86_64:
|
|||||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||||
-DPICKY_DEVELOPER=ON
|
-DPICKY_DEVELOPER=ON
|
||||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||||
-DUNIT_TESTING=ON .. &&
|
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON .. &&
|
||||||
make -j$(nproc) && ctest --output-on-failure
|
make -j$(nproc) && ctest --output-on-failure
|
||||||
tags:
|
tags:
|
||||||
- shared
|
- shared
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules")
|
|||||||
include(DefineCMakeDefaults)
|
include(DefineCMakeDefaults)
|
||||||
include(DefineCompilerFlags)
|
include(DefineCompilerFlags)
|
||||||
|
|
||||||
project(libssh VERSION 0.8.90 LANGUAGES C)
|
project(libssh VERSION 0.9.0 LANGUAGES C)
|
||||||
|
|
||||||
# global needed variable
|
# global needed variable
|
||||||
set(APPLICATION_NAME ${PROJECT_NAME})
|
set(APPLICATION_NAME ${PROJECT_NAME})
|
||||||
|
|||||||
68
ChangeLog
68
ChangeLog
@@ -1,7 +1,7 @@
|
|||||||
ChangeLog
|
ChangeLog
|
||||||
==========
|
==========
|
||||||
|
|
||||||
version 0.9.0 (released 2019-02-xx)
|
version 0.9.0 (released 2019-06-28)
|
||||||
* Added support for AES-GCM
|
* Added support for AES-GCM
|
||||||
* Added improved rekeying support
|
* Added improved rekeying support
|
||||||
* Added performance improvements
|
* Added performance improvements
|
||||||
@@ -11,10 +11,76 @@ version 0.9.0 (released 2019-02-xx)
|
|||||||
* Added support for Encrypt-then-MAC mode
|
* Added support for Encrypt-then-MAC mode
|
||||||
* Added support for parsing server side configuration file
|
* Added support for parsing server side configuration file
|
||||||
* Added support for ECDSA/Ed25519 certificates
|
* Added support for ECDSA/Ed25519 certificates
|
||||||
|
* Added FIPS 140-2 compatibility
|
||||||
* Improved known_hosts parsing
|
* Improved known_hosts parsing
|
||||||
* Improved documentation
|
* Improved documentation
|
||||||
* Improved OpenSSL API usage for KEX, DH, and signatures
|
* Improved OpenSSL API usage for KEX, DH, and signatures
|
||||||
|
|
||||||
|
version 0.8.7 (released 2019-02-25)
|
||||||
|
* Fixed handling extension flags in the server implementation
|
||||||
|
* Fixed exporting ed25519 private keys
|
||||||
|
* Fixed corner cases for rsa-sha2 signatures
|
||||||
|
* Fixed some issues with connector
|
||||||
|
|
||||||
|
version 0.8.6 (released 2018-12-24)
|
||||||
|
* Fixed compilation issues with different OpenSSL versions
|
||||||
|
* Fixed StrictHostKeyChecking in new knownhosts API
|
||||||
|
* Fixed ssh_send_keepalive() with packet filter
|
||||||
|
* Fixed possible crash with knownhosts options
|
||||||
|
* Fixed issus with rekeying
|
||||||
|
* Fixed strong ECDSA keys
|
||||||
|
* Fixed some issues with rsa-sha2 extentions
|
||||||
|
* Fixed access violation in ssh_init() (static linking)
|
||||||
|
* Fixed ssh_channel_close() handling
|
||||||
|
|
||||||
|
version 0.8.5 (released 2018-10-29)
|
||||||
|
* Added support to get known_hosts locations with ssh_options_get()
|
||||||
|
* Fixed preferred algorithm for known hosts negotiations
|
||||||
|
* Fixed KEX with some server implementations (e.g. Cisco)
|
||||||
|
* Fixed issues with MSVC
|
||||||
|
* Fixed keyboard-interactive auth in server mode
|
||||||
|
(regression from CVE-2018-10933)
|
||||||
|
* Fixed gssapi auth in server mode (regression from CVE-2018-10933)
|
||||||
|
* Fixed socket fd handling with proxy command
|
||||||
|
* Fixed a memory leak with OpenSSL
|
||||||
|
|
||||||
|
version 0.8.4 (released 2018-10-16)
|
||||||
|
* Fixed CVE-2018-10933
|
||||||
|
* Fixed building without globbing support
|
||||||
|
* Fixed possible memory leaks
|
||||||
|
* Avoid SIGPIPE on sockets
|
||||||
|
|
||||||
|
version 0.8.3 (released 2018-09-21)
|
||||||
|
* Added support for rsa-sha2
|
||||||
|
* Added support to parse private keys in openssh container format
|
||||||
|
(other than ed25519)
|
||||||
|
* Added support for diffie-hellman-group18-sha512 and
|
||||||
|
diffie-hellman-group16-sha512
|
||||||
|
* Added ssh_get_fingerprint_hash()
|
||||||
|
* Added ssh_pki_export_privkey_base64()
|
||||||
|
* Added support for Match keyword in config file
|
||||||
|
* Improved performance and reduced memory footprint for sftp
|
||||||
|
* Fixed ecdsa publickey auth
|
||||||
|
* Fixed reading a closed channel
|
||||||
|
* Added support to announce posix-rename@openssh.com and
|
||||||
|
hardlink@openssh.com in the sftp server
|
||||||
|
|
||||||
|
version 0.8.2 (released 2018-08-30)
|
||||||
|
* Added sha256 fingerprints for pubkeys
|
||||||
|
* Improved compiler flag detection
|
||||||
|
* Fixed race condition in reading sftp messages
|
||||||
|
* Fixed doxygen generation and added modern style
|
||||||
|
* Fixed library initialization on Windows
|
||||||
|
* Fixed __bounded__ attribute detection
|
||||||
|
* Fixed a bug in the options parser
|
||||||
|
* Fixed documentation for new knwon_hosts API
|
||||||
|
|
||||||
|
version 0.8.1 (released 2018-08-13)
|
||||||
|
* Fixed version number in the header
|
||||||
|
* Fixed version number in pkg-config and cmake config
|
||||||
|
* Fixed library initialization
|
||||||
|
* Fixed attribute detection
|
||||||
|
|
||||||
version 0.8.0 (released 2018-08-10)
|
version 0.8.0 (released 2018-08-10)
|
||||||
* Removed support for deprecated SSHv1 protocol
|
* Removed support for deprecated SSHv1 protocol
|
||||||
* Added new connector API for clients
|
* Added new connector API for clients
|
||||||
|
|||||||
@@ -197,6 +197,7 @@ static void sizechanged(void)
|
|||||||
static void select_loop(ssh_session session,ssh_channel channel)
|
static void select_loop(ssh_session session,ssh_channel channel)
|
||||||
{
|
{
|
||||||
ssh_connector connector_in, connector_out, connector_err;
|
ssh_connector connector_in, connector_out, connector_err;
|
||||||
|
int rc;
|
||||||
|
|
||||||
ssh_event event = ssh_event_new();
|
ssh_event event = ssh_event_new();
|
||||||
|
|
||||||
@@ -222,7 +223,11 @@ static void select_loop(ssh_session session,ssh_channel channel)
|
|||||||
if (signal_delayed) {
|
if (signal_delayed) {
|
||||||
sizechanged();
|
sizechanged();
|
||||||
}
|
}
|
||||||
ssh_event_dopoll(event, 60000);
|
rc = ssh_event_dopoll(event, 60000);
|
||||||
|
if (rc == SSH_ERROR) {
|
||||||
|
fprintf(stderr, "Error in ssh_event_dopoll()\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ssh_event_remove_connector(event, connector_in);
|
ssh_event_remove_connector(event, connector_in);
|
||||||
ssh_event_remove_connector(event, connector_out);
|
ssh_event_remove_connector(event, connector_out);
|
||||||
|
|||||||
@@ -78,8 +78,8 @@
|
|||||||
|
|
||||||
/* libssh version */
|
/* libssh version */
|
||||||
#define LIBSSH_VERSION_MAJOR 0
|
#define LIBSSH_VERSION_MAJOR 0
|
||||||
#define LIBSSH_VERSION_MINOR 8
|
#define LIBSSH_VERSION_MINOR 9
|
||||||
#define LIBSSH_VERSION_MICRO 90
|
#define LIBSSH_VERSION_MICRO 0
|
||||||
|
|
||||||
#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, \
|
||||||
|
|||||||
@@ -272,8 +272,6 @@ int ssh_auth_reply_success(ssh_session session, int partial);
|
|||||||
int ssh_send_banner(ssh_session session, int is_server);
|
int ssh_send_banner(ssh_session session, int is_server);
|
||||||
|
|
||||||
/* connect.c */
|
/* connect.c */
|
||||||
socket_t ssh_connect_host(ssh_session session, const char *host,const char
|
|
||||||
*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,
|
||||||
const char *bind_addr, int port);
|
const char *bind_addr, int port);
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ static int ssh_userauth_request_service(ssh_session session) {
|
|||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = ssh_service_request(session, "ssh-userauth");
|
rc = ssh_service_request(session, "ssh-userauth");
|
||||||
if (rc != SSH_OK) {
|
if ((rc != SSH_OK) && (rc != SSH_AGAIN)) {
|
||||||
SSH_LOG(SSH_LOG_WARN,
|
SSH_LOG(SSH_LOG_WARN,
|
||||||
"Failed to request \"ssh-userauth\" service");
|
"Failed to request \"ssh-userauth\" service");
|
||||||
}
|
}
|
||||||
|
|||||||
537
src/connect.c
537
src/connect.c
@@ -90,131 +90,55 @@
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#ifndef gai_strerror
|
#ifndef gai_strerror
|
||||||
char WSAAPI *gai_strerrorA(int code) {
|
char WSAAPI *gai_strerrorA(int code)
|
||||||
static char buf[256];
|
{
|
||||||
|
static char buf[256];
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "Undetermined error code (%d)", code);
|
snprintf(buf, sizeof(buf), "Undetermined error code (%d)", code);
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
#endif /* gai_strerror */
|
#endif /* gai_strerror */
|
||||||
#endif /* _WIN32 */
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
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);
|
||||||
#else
|
#else
|
||||||
return close(s);
|
return close(s);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int getai(const char *host, int port, struct addrinfo **ai)
|
||||||
|
{
|
||||||
|
const char *service = NULL;
|
||||||
|
struct addrinfo hints;
|
||||||
|
char s_port[10];
|
||||||
|
|
||||||
static int getai(const char *host, int port, struct addrinfo **ai) {
|
ZERO_STRUCT(hints);
|
||||||
const char *service = NULL;
|
|
||||||
struct addrinfo hints;
|
|
||||||
char s_port[10];
|
|
||||||
|
|
||||||
ZERO_STRUCT(hints);
|
hints.ai_protocol = IPPROTO_TCP;
|
||||||
|
hints.ai_family = PF_UNSPEC;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
|
||||||
hints.ai_protocol = IPPROTO_TCP;
|
if (port == 0) {
|
||||||
hints.ai_family = PF_UNSPEC;
|
hints.ai_flags = AI_PASSIVE;
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
} else {
|
||||||
|
snprintf(s_port, sizeof(s_port), "%hu", (unsigned short)port);
|
||||||
if (port == 0) {
|
service = s_port;
|
||||||
hints.ai_flags = AI_PASSIVE;
|
|
||||||
} else {
|
|
||||||
snprintf(s_port, sizeof(s_port), "%hu", (unsigned short)port);
|
|
||||||
service = s_port;
|
|
||||||
#ifdef AI_NUMERICSERV
|
#ifdef AI_NUMERICSERV
|
||||||
hints.ai_flags=AI_NUMERICSERV;
|
hints.ai_flags = AI_NUMERICSERV;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ssh_is_ipaddr(host)) {
|
if (ssh_is_ipaddr(host)) {
|
||||||
/* this is an IP address */
|
/* this is an IP address */
|
||||||
SSH_LOG(SSH_LOG_PACKET,"host %s matches an IP address",host);
|
SSH_LOG(SSH_LOG_PACKET, "host %s matches an IP address", host);
|
||||||
hints.ai_flags |= AI_NUMERICHOST;
|
hints.ai_flags |= AI_NUMERICHOST;
|
||||||
}
|
}
|
||||||
|
|
||||||
return getaddrinfo(host, service, &hints, ai);
|
return getaddrinfo(host, service, &hints, ai);
|
||||||
}
|
|
||||||
|
|
||||||
static int ssh_connect_ai_timeout(ssh_session session, const char *host,
|
|
||||||
int port, struct addrinfo *ai, long timeout, long usec, socket_t s) {
|
|
||||||
int timeout_ms;
|
|
||||||
ssh_pollfd_t fds;
|
|
||||||
int rc = 0;
|
|
||||||
int ret;
|
|
||||||
socklen_t len = sizeof(rc);
|
|
||||||
|
|
||||||
/* I know we're losing some precision. But it's not like poll-like family
|
|
||||||
* type of mechanisms are precise up to the microsecond.
|
|
||||||
*/
|
|
||||||
timeout_ms=timeout * 1000 + usec / 1000;
|
|
||||||
|
|
||||||
rc = ssh_socket_set_nonblocking(s);
|
|
||||||
if (rc < 0) {
|
|
||||||
ssh_set_error(session, SSH_FATAL,
|
|
||||||
"Failed to set socket non-blocking for %s:%d", host, port);
|
|
||||||
ssh_connect_socket_close(s);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
SSH_LOG(SSH_LOG_RARE, "Trying to connect to host: %s:%d with "
|
|
||||||
"timeout %d ms", host, port, timeout_ms);
|
|
||||||
|
|
||||||
/* The return value is checked later */
|
|
||||||
connect(s, ai->ai_addr, ai->ai_addrlen);
|
|
||||||
freeaddrinfo(ai);
|
|
||||||
|
|
||||||
fds.fd=s;
|
|
||||||
fds.revents=0;
|
|
||||||
fds.events=POLLOUT;
|
|
||||||
#ifdef _WIN32
|
|
||||||
fds.events |= POLLWRNORM;
|
|
||||||
#endif
|
|
||||||
rc = ssh_poll(&fds,1,timeout_ms);
|
|
||||||
|
|
||||||
if (rc == 0) {
|
|
||||||
/* timeout */
|
|
||||||
ssh_set_error(session, SSH_FATAL,
|
|
||||||
"Timeout while connecting to %s:%d", host, port);
|
|
||||||
ssh_connect_socket_close(s);
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rc < 0) {
|
|
||||||
ssh_set_error(session, SSH_FATAL,
|
|
||||||
"poll error: %s", strerror(errno));
|
|
||||||
ssh_connect_socket_close(s);
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
rc = -1;
|
|
||||||
|
|
||||||
/* Get connect(2) return code. Zero means no error */
|
|
||||||
ret = getsockopt(s, SOL_SOCKET, SO_ERROR,(char *) &rc, &len);
|
|
||||||
if (ret < 0 || rc != 0) {
|
|
||||||
ssh_set_error(session, SSH_FATAL,
|
|
||||||
"Connect to %s:%d failed: %s", host, port, strerror(rc));
|
|
||||||
ssh_connect_socket_close(s);
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* s is connected ? */
|
|
||||||
SSH_LOG(SSH_LOG_PACKET, "Socket connected with timeout");
|
|
||||||
ret = ssh_socket_set_blocking(s);
|
|
||||||
if (ret < 0) {
|
|
||||||
ssh_set_error(session, SSH_FATAL,
|
|
||||||
"Failed to set socket as blocking connecting to %s:%d failed: %s",
|
|
||||||
host, port, strerror(errno));
|
|
||||||
ssh_connect_socket_close(s);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_tcp_nodelay(socket_t socket)
|
static int set_tcp_nodelay(socket_t socket)
|
||||||
@@ -228,99 +152,6 @@ static int set_tcp_nodelay(socket_t socket)
|
|||||||
sizeof(opt));
|
sizeof(opt));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*
|
|
||||||
* @brief Connect to an IPv4 or IPv6 host specified by its IP address or
|
|
||||||
* hostname.
|
|
||||||
*
|
|
||||||
* @returns A file descriptor, < 0 on error.
|
|
||||||
*/
|
|
||||||
socket_t ssh_connect_host(ssh_session session, const char *host,
|
|
||||||
const char *bind_addr, int port, long timeout, long usec) {
|
|
||||||
socket_t s = -1;
|
|
||||||
int rc;
|
|
||||||
struct addrinfo *ai;
|
|
||||||
struct addrinfo *itr;
|
|
||||||
|
|
||||||
rc = getai(host, port, &ai);
|
|
||||||
if (rc != 0) {
|
|
||||||
ssh_set_error(session, SSH_FATAL,
|
|
||||||
"Failed to resolve hostname %s (%s)", host, gai_strerror(rc));
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (itr = ai; itr != NULL; itr = itr->ai_next){
|
|
||||||
/* create socket */
|
|
||||||
s = socket(itr->ai_family, itr->ai_socktype, itr->ai_protocol);
|
|
||||||
if (s < 0) {
|
|
||||||
ssh_set_error(session, SSH_FATAL,
|
|
||||||
"Socket create failed: %s", strerror(errno));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bind_addr) {
|
|
||||||
struct addrinfo *bind_ai;
|
|
||||||
struct addrinfo *bind_itr;
|
|
||||||
|
|
||||||
SSH_LOG(SSH_LOG_PACKET, "Resolving %s", bind_addr);
|
|
||||||
|
|
||||||
rc = getai(bind_addr, 0, &bind_ai);
|
|
||||||
if (rc != 0) {
|
|
||||||
ssh_set_error(session, SSH_FATAL,
|
|
||||||
"Failed to resolve bind address %s (%s)",
|
|
||||||
bind_addr,
|
|
||||||
gai_strerror(rc));
|
|
||||||
freeaddrinfo(ai);
|
|
||||||
close(s);
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (bind_itr = bind_ai; bind_itr != NULL; bind_itr = bind_itr->ai_next) {
|
|
||||||
if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) {
|
|
||||||
ssh_set_error(session, SSH_FATAL,
|
|
||||||
"Binding local address: %s", strerror(errno));
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
freeaddrinfo(bind_ai);
|
|
||||||
|
|
||||||
/* Cannot bind to any local addresses */
|
|
||||||
if (bind_itr == NULL) {
|
|
||||||
ssh_connect_socket_close(s);
|
|
||||||
s = -1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timeout || usec) {
|
|
||||||
socket_t ret = ssh_connect_ai_timeout(session, host, port, itr,
|
|
||||||
timeout, usec, s);
|
|
||||||
|
|
||||||
freeaddrinfo(ai);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (connect(s, itr->ai_addr, itr->ai_addrlen) < 0) {
|
|
||||||
ssh_set_error(session, SSH_FATAL, "Connect failed: %s", strerror(errno));
|
|
||||||
ssh_connect_socket_close(s);
|
|
||||||
s = -1;
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
/* We are connected */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
freeaddrinfo(ai);
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*
|
*
|
||||||
@@ -331,102 +162,109 @@ socket_t ssh_connect_host(ssh_session session, const char *host,
|
|||||||
* @warning very ugly !!!
|
* @warning very ugly !!!
|
||||||
*/
|
*/
|
||||||
socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
||||||
const char *bind_addr, int port) {
|
const char *bind_addr, int port)
|
||||||
socket_t s = -1;
|
{
|
||||||
int rc;
|
socket_t s = -1;
|
||||||
struct addrinfo *ai;
|
int rc;
|
||||||
struct addrinfo *itr;
|
struct addrinfo *ai = NULL;
|
||||||
|
struct addrinfo *itr = NULL;
|
||||||
|
|
||||||
rc = getai(host, port, &ai);
|
rc = getai(host, port, &ai);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
ssh_set_error(session, SSH_FATAL,
|
ssh_set_error(session, SSH_FATAL,
|
||||||
"Failed to resolve hostname %s (%s)", host, gai_strerror(rc));
|
"Failed to resolve hostname %s (%s)",
|
||||||
|
host, gai_strerror(rc));
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
for (itr = ai; itr != NULL; itr = itr->ai_next){
|
|
||||||
/* create socket */
|
|
||||||
s = socket(itr->ai_family, itr->ai_socktype, itr->ai_protocol);
|
|
||||||
if (s < 0) {
|
|
||||||
ssh_set_error(session, SSH_FATAL,
|
|
||||||
"Socket create failed: %s", strerror(errno));
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bind_addr) {
|
for (itr = ai; itr != NULL; itr = itr->ai_next) {
|
||||||
struct addrinfo *bind_ai;
|
/* create socket */
|
||||||
struct addrinfo *bind_itr;
|
s = socket(itr->ai_family, itr->ai_socktype, itr->ai_protocol);
|
||||||
|
if (s < 0) {
|
||||||
SSH_LOG(SSH_LOG_PACKET, "Resolving %s", bind_addr);
|
ssh_set_error(session, SSH_FATAL,
|
||||||
|
"Socket create failed: %s", strerror(errno));
|
||||||
rc = getai(bind_addr, 0, &bind_ai);
|
continue;
|
||||||
if (rc != 0) {
|
|
||||||
ssh_set_error(session, SSH_FATAL,
|
|
||||||
"Failed to resolve bind address %s (%s)",
|
|
||||||
bind_addr,
|
|
||||||
gai_strerror(rc));
|
|
||||||
ssh_connect_socket_close(s);
|
|
||||||
s=-1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (bind_itr = bind_ai; bind_itr != NULL; bind_itr = bind_itr->ai_next) {
|
|
||||||
if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) {
|
|
||||||
ssh_set_error(session, SSH_FATAL,
|
|
||||||
"Binding local address: %s", strerror(errno));
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
freeaddrinfo(bind_ai);
|
|
||||||
|
|
||||||
/* Cannot bind to any local addresses */
|
if (bind_addr) {
|
||||||
if (bind_itr == NULL) {
|
struct addrinfo *bind_ai;
|
||||||
ssh_connect_socket_close(s);
|
struct addrinfo *bind_itr;
|
||||||
s = -1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = ssh_socket_set_nonblocking(s);
|
SSH_LOG(SSH_LOG_PACKET, "Resolving %s", bind_addr);
|
||||||
if (rc < 0) {
|
|
||||||
ssh_set_error(session, SSH_FATAL,
|
|
||||||
"Failed to set socket non-blocking for %s:%d", host, port);
|
|
||||||
ssh_connect_socket_close(s);
|
|
||||||
s = -1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (session->opts.nodelay) {
|
rc = getai(bind_addr, 0, &bind_ai);
|
||||||
/* For winsock, socket options are only effective before connect */
|
if (rc != 0) {
|
||||||
rc = set_tcp_nodelay(s);
|
ssh_set_error(session, SSH_FATAL,
|
||||||
|
"Failed to resolve bind address %s (%s)",
|
||||||
|
bind_addr,
|
||||||
|
gai_strerror(rc));
|
||||||
|
ssh_connect_socket_close(s);
|
||||||
|
s = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (bind_itr = bind_ai;
|
||||||
|
bind_itr != NULL;
|
||||||
|
bind_itr = bind_itr->ai_next)
|
||||||
|
{
|
||||||
|
if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) {
|
||||||
|
ssh_set_error(session, SSH_FATAL,
|
||||||
|
"Binding local address: %s", strerror(errno));
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freeaddrinfo(bind_ai);
|
||||||
|
|
||||||
|
/* Cannot bind to any local addresses */
|
||||||
|
if (bind_itr == NULL) {
|
||||||
|
ssh_connect_socket_close(s);
|
||||||
|
s = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ssh_socket_set_nonblocking(s);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
ssh_set_error(session, SSH_FATAL,
|
ssh_set_error(session, SSH_FATAL,
|
||||||
"Failed to set TCP_NODELAY on socket: %s", strerror(errno));
|
"Failed to set socket non-blocking for %s:%d",
|
||||||
|
host, port);
|
||||||
ssh_connect_socket_close(s);
|
ssh_connect_socket_close(s);
|
||||||
s = -1;
|
s = -1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (session->opts.nodelay) {
|
||||||
|
/* For winsock, socket options are only effective before connect */
|
||||||
|
rc = set_tcp_nodelay(s);
|
||||||
|
if (rc < 0) {
|
||||||
|
ssh_set_error(session, SSH_FATAL,
|
||||||
|
"Failed to set TCP_NODELAY on socket: %s",
|
||||||
|
strerror(errno));
|
||||||
|
ssh_connect_socket_close(s);
|
||||||
|
s = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
rc = connect(s, itr->ai_addr, itr->ai_addrlen);
|
||||||
|
if (rc == -1 && (errno != 0) && (errno != EINPROGRESS)) {
|
||||||
|
ssh_set_error(session, SSH_FATAL,
|
||||||
|
"Failed to connect: %s", strerror(errno));
|
||||||
|
ssh_connect_socket_close(s);
|
||||||
|
s = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
errno = 0;
|
freeaddrinfo(ai);
|
||||||
rc = connect(s, itr->ai_addr, itr->ai_addrlen);
|
|
||||||
if (rc == -1 && (errno != 0) && (errno != EINPROGRESS)) {
|
|
||||||
ssh_set_error(session, SSH_FATAL,
|
|
||||||
"Failed to connect: %s", strerror(errno));
|
|
||||||
ssh_connect_socket_close(s);
|
|
||||||
s = -1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
return s;
|
||||||
}
|
|
||||||
|
|
||||||
freeaddrinfo(ai);
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -435,11 +273,13 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int ssh_select_cb (socket_t fd, int revents, void *userdata){
|
static int ssh_select_cb (socket_t fd, int revents, void *userdata)
|
||||||
fd_set *set = (fd_set *)userdata;
|
{
|
||||||
if(revents & POLLIN)
|
fd_set *set = (fd_set *)userdata;
|
||||||
FD_SET(fd, set);
|
if (revents & POLLIN) {
|
||||||
return 0;
|
FD_SET(fd, set);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -473,73 +313,84 @@ static int ssh_select_cb (socket_t fd, int revents, void *userdata){
|
|||||||
* @see select(2)
|
* @see select(2)
|
||||||
*/
|
*/
|
||||||
int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
|
int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
|
||||||
fd_set *readfds, struct timeval *timeout) {
|
fd_set *readfds, struct timeval *timeout)
|
||||||
fd_set origfds;
|
{
|
||||||
socket_t fd;
|
fd_set origfds;
|
||||||
size_t i, j;
|
socket_t fd;
|
||||||
int rc;
|
size_t i, j;
|
||||||
int base_tm, tm;
|
int rc;
|
||||||
struct ssh_timestamp ts;
|
int base_tm, tm;
|
||||||
ssh_event event = ssh_event_new();
|
struct ssh_timestamp ts;
|
||||||
int firstround=1;
|
ssh_event event = ssh_event_new();
|
||||||
|
int firstround = 1;
|
||||||
|
|
||||||
base_tm = tm=timeout->tv_sec * 1000 + timeout->tv_usec/1000;
|
base_tm = tm = (timeout->tv_sec * 1000) + (timeout->tv_usec / 1000);
|
||||||
for (i=0 ; channels[i] != NULL; ++i){
|
for (i = 0 ; channels[i] != NULL; ++i) {
|
||||||
ssh_event_add_session(event, channels[i]->session);
|
ssh_event_add_session(event, channels[i]->session);
|
||||||
}
|
|
||||||
|
|
||||||
ZERO_STRUCT(origfds);
|
|
||||||
FD_ZERO(&origfds);
|
|
||||||
for (fd = 0; fd < maxfd ; fd++) {
|
|
||||||
if (FD_ISSET(fd, readfds)) {
|
|
||||||
ssh_event_add_fd(event, fd, POLLIN, ssh_select_cb, readfds);
|
|
||||||
FD_SET(fd, &origfds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
outchannels[0] = NULL;
|
|
||||||
FD_ZERO(readfds);
|
|
||||||
ssh_timestamp_init(&ts);
|
|
||||||
do {
|
|
||||||
/* Poll every channel */
|
|
||||||
j = 0;
|
|
||||||
for (i = 0; channels[i]; i++) {
|
|
||||||
if(ssh_channel_poll(channels[i], 0) != 0) {
|
|
||||||
outchannels[j] = channels[i];
|
|
||||||
j++;
|
|
||||||
} else if(ssh_channel_poll(channels[i], 1) != 0) {
|
|
||||||
outchannels[j] = channels[i];
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
outchannels[j] = NULL;
|
|
||||||
if(j != 0)
|
ZERO_STRUCT(origfds);
|
||||||
break;
|
FD_ZERO(&origfds);
|
||||||
/* watch if a user socket was triggered */
|
for (fd = 0; fd < maxfd ; fd++) {
|
||||||
for (fd = 0; fd < maxfd; fd++) {
|
|
||||||
if (FD_ISSET(fd, readfds)) {
|
if (FD_ISSET(fd, readfds)) {
|
||||||
goto out;
|
ssh_event_add_fd(event, fd, POLLIN, ssh_select_cb, readfds);
|
||||||
|
FD_SET(fd, &origfds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
outchannels[0] = NULL;
|
||||||
|
FD_ZERO(readfds);
|
||||||
|
ssh_timestamp_init(&ts);
|
||||||
|
do {
|
||||||
|
/* Poll every channel */
|
||||||
|
j = 0;
|
||||||
|
for (i = 0; channels[i]; i++) {
|
||||||
|
rc = ssh_channel_poll(channels[i], 0);
|
||||||
|
if (rc != 0) {
|
||||||
|
outchannels[j] = channels[i];
|
||||||
|
j++;
|
||||||
|
} else {
|
||||||
|
rc = ssh_channel_poll(channels[i], 1);
|
||||||
|
if (rc != 0) {
|
||||||
|
outchannels[j] = channels[i];
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If the timeout is elapsed, we should go out */
|
outchannels[j] = NULL;
|
||||||
if(!firstround && ssh_timeout_elapsed(&ts, base_tm))
|
if (j != 0) {
|
||||||
goto out;
|
break;
|
||||||
/* since there's nothing, let's fire the polling */
|
}
|
||||||
rc = ssh_event_dopoll(event,tm);
|
|
||||||
if (rc == SSH_ERROR){
|
/* watch if a user socket was triggered */
|
||||||
goto out;
|
for (fd = 0; fd < maxfd; fd++) {
|
||||||
}
|
if (FD_ISSET(fd, readfds)) {
|
||||||
tm = ssh_timeout_update(&ts, base_tm);
|
goto out;
|
||||||
firstround=0;
|
}
|
||||||
} while (1);
|
}
|
||||||
|
|
||||||
|
/* If the timeout is elapsed, we should go out */
|
||||||
|
if (!firstround && ssh_timeout_elapsed(&ts, base_tm)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* since there's nothing, let's fire the polling */
|
||||||
|
rc = ssh_event_dopoll(event,tm);
|
||||||
|
if (rc == SSH_ERROR) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
tm = ssh_timeout_update(&ts, base_tm);
|
||||||
|
firstround = 0;
|
||||||
|
} while (1);
|
||||||
out:
|
out:
|
||||||
for (fd = 0; fd < maxfd; fd++) {
|
for (fd = 0; fd < maxfd; fd++) {
|
||||||
if (FD_ISSET(fd, &origfds)) {
|
if (FD_ISSET(fd, &origfds)) {
|
||||||
ssh_event_remove_fd(event, fd);
|
ssh_event_remove_fd(event, fd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
ssh_event_free(event);
|
||||||
ssh_event_free(event);
|
return SSH_OK;
|
||||||
return SSH_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|||||||
@@ -194,8 +194,13 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group)
|
|||||||
if (rc == SSH_ERROR) {
|
if (rc == SSH_ERROR) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = ssh_dh_keypair_get_keys(session->next_crypto->dh_ctx,
|
rc = ssh_dh_keypair_get_keys(session->next_crypto->dh_ctx,
|
||||||
DH_CLIENT_KEYPAIR, NULL, &pubkey);
|
DH_CLIENT_KEYPAIR, NULL, &pubkey);
|
||||||
|
if (rc != SSH_OK) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
rc = ssh_buffer_pack(session->out_buffer,
|
rc = ssh_buffer_pack(session->out_buffer,
|
||||||
"bB",
|
"bB",
|
||||||
SSH2_MSG_KEX_DH_GEX_INIT,
|
SSH2_MSG_KEX_DH_GEX_INIT,
|
||||||
|
|||||||
@@ -306,7 +306,7 @@ static char *ssh_session_get_host_port(ssh_session session)
|
|||||||
if (session->opts.host == NULL) {
|
if (session->opts.host == NULL) {
|
||||||
ssh_set_error(session,
|
ssh_set_error(session,
|
||||||
SSH_FATAL,
|
SSH_FATAL,
|
||||||
"Can't verify server inn known hosts if the host we "
|
"Can't verify server in known hosts if the host we "
|
||||||
"should connect to has not been set");
|
"should connect to has not been set");
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -638,14 +638,15 @@ enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session)
|
|||||||
struct ssh_list *entry_list = NULL;
|
struct ssh_list *entry_list = NULL;
|
||||||
struct ssh_iterator *it = NULL;
|
struct ssh_iterator *it = NULL;
|
||||||
char *host_port = NULL;
|
char *host_port = NULL;
|
||||||
bool ok;
|
bool global_known_hosts_found = false;
|
||||||
|
bool known_hosts_found = false;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (session->opts.knownhosts == NULL) {
|
if (session->opts.knownhosts == NULL) {
|
||||||
if (ssh_options_apply(session) < 0) {
|
if (ssh_options_apply(session) < 0) {
|
||||||
ssh_set_error(session,
|
ssh_set_error(session,
|
||||||
SSH_REQUEST_DENIED,
|
SSH_REQUEST_DENIED,
|
||||||
"Can't find a known_hosts file");
|
"Cannot find a known_hosts file");
|
||||||
|
|
||||||
return SSH_KNOWN_HOSTS_NOT_FOUND;
|
return SSH_KNOWN_HOSTS_NOT_FOUND;
|
||||||
}
|
}
|
||||||
@@ -653,23 +654,38 @@ enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session)
|
|||||||
|
|
||||||
if (session->opts.knownhosts == NULL &&
|
if (session->opts.knownhosts == NULL &&
|
||||||
session->opts.global_knownhosts == NULL) {
|
session->opts.global_knownhosts == NULL) {
|
||||||
|
ssh_set_error(session,
|
||||||
|
SSH_REQUEST_DENIED,
|
||||||
|
"No path set for a known_hosts file");
|
||||||
|
|
||||||
return SSH_KNOWN_HOSTS_NOT_FOUND;
|
return SSH_KNOWN_HOSTS_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session->opts.knownhosts != NULL) {
|
if (session->opts.knownhosts != NULL) {
|
||||||
ok = ssh_file_readaccess_ok(session->opts.knownhosts);
|
known_hosts_found = ssh_file_readaccess_ok(session->opts.knownhosts);
|
||||||
if (!ok) {
|
if (!known_hosts_found) {
|
||||||
return SSH_KNOWN_HOSTS_NOT_FOUND;
|
SSH_LOG(SSH_LOG_WARN, "Cannot access file %s",
|
||||||
|
session->opts.knownhosts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session->opts.global_knownhosts != NULL) {
|
if (session->opts.global_knownhosts != NULL) {
|
||||||
ok = ssh_file_readaccess_ok(session->opts.global_knownhosts);
|
global_known_hosts_found =
|
||||||
if (!ok) {
|
ssh_file_readaccess_ok(session->opts.global_knownhosts);
|
||||||
return SSH_KNOWN_HOSTS_NOT_FOUND;
|
if (!global_known_hosts_found) {
|
||||||
|
SSH_LOG(SSH_LOG_WARN, "Cannot access file %s",
|
||||||
|
session->opts.global_knownhosts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((!known_hosts_found) && (!global_known_hosts_found)) {
|
||||||
|
ssh_set_error(session,
|
||||||
|
SSH_REQUEST_DENIED,
|
||||||
|
"Cannot find a known_hosts file");
|
||||||
|
|
||||||
|
return SSH_KNOWN_HOSTS_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
host_port = ssh_session_get_host_port(session);
|
host_port = ssh_session_get_host_port(session);
|
||||||
if (host_port == NULL) {
|
if (host_port == NULL) {
|
||||||
return SSH_KNOWN_HOSTS_ERROR;
|
return SSH_KNOWN_HOSTS_ERROR;
|
||||||
@@ -682,7 +698,7 @@ enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session)
|
|||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
SAFE_FREE(host_port);
|
SAFE_FREE(host_port);
|
||||||
ssh_list_free(entry_list);
|
ssh_list_free(entry_list);
|
||||||
return SSH_KNOWN_HOSTS_UNKNOWN;
|
return SSH_KNOWN_HOSTS_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -693,7 +709,7 @@ enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session)
|
|||||||
SAFE_FREE(host_port);
|
SAFE_FREE(host_port);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
ssh_list_free(entry_list);
|
ssh_list_free(entry_list);
|
||||||
return SSH_KNOWN_HOSTS_UNKNOWN;
|
return SSH_KNOWN_HOSTS_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1491,12 +1491,18 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){
|
|||||||
msg->type = SSH_REQUEST_GLOBAL;
|
msg->type = SSH_REQUEST_GLOBAL;
|
||||||
|
|
||||||
if (strcmp(request, "tcpip-forward") == 0) {
|
if (strcmp(request, "tcpip-forward") == 0) {
|
||||||
|
|
||||||
|
/* According to RFC4254, the client SHOULD reject this message */
|
||||||
|
if (session->client) {
|
||||||
|
goto reply_with_failure;
|
||||||
|
}
|
||||||
|
|
||||||
r = ssh_buffer_unpack(packet, "sd",
|
r = ssh_buffer_unpack(packet, "sd",
|
||||||
&msg->global_request.bind_address,
|
&msg->global_request.bind_address,
|
||||||
&msg->global_request.bind_port
|
&msg->global_request.bind_port
|
||||||
);
|
);
|
||||||
if (r != SSH_OK){
|
if (r != SSH_OK){
|
||||||
goto error;
|
goto reply_with_failure;
|
||||||
}
|
}
|
||||||
msg->global_request.type = SSH_GLOBAL_REQUEST_TCPIP_FORWARD;
|
msg->global_request.type = SSH_GLOBAL_REQUEST_TCPIP_FORWARD;
|
||||||
msg->global_request.want_reply = want_reply;
|
msg->global_request.want_reply = want_reply;
|
||||||
@@ -1516,11 +1522,17 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
} else if (strcmp(request, "cancel-tcpip-forward") == 0) {
|
} else if (strcmp(request, "cancel-tcpip-forward") == 0) {
|
||||||
|
|
||||||
|
/* According to RFC4254, the client SHOULD reject this message */
|
||||||
|
if (session->client) {
|
||||||
|
goto reply_with_failure;
|
||||||
|
}
|
||||||
|
|
||||||
r = ssh_buffer_unpack(packet, "sd",
|
r = ssh_buffer_unpack(packet, "sd",
|
||||||
&msg->global_request.bind_address,
|
&msg->global_request.bind_address,
|
||||||
&msg->global_request.bind_port);
|
&msg->global_request.bind_port);
|
||||||
if (r != SSH_OK){
|
if (r != SSH_OK){
|
||||||
goto error;
|
goto reply_with_failure;
|
||||||
}
|
}
|
||||||
msg->global_request.type = SSH_GLOBAL_REQUEST_CANCEL_TCPIP_FORWARD;
|
msg->global_request.type = SSH_GLOBAL_REQUEST_CANCEL_TCPIP_FORWARD;
|
||||||
msg->global_request.want_reply = want_reply;
|
msg->global_request.want_reply = want_reply;
|
||||||
@@ -1546,18 +1558,41 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){
|
|||||||
ssh_message_global_request_reply_success(msg, 0);
|
ssh_message_global_request_reply_success(msg, 0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SSH_LOG(SSH_LOG_PROTOCOL, "UNKNOWN SSH_MSG_GLOBAL_REQUEST %s %d", request, want_reply);
|
SSH_LOG(SSH_LOG_PROTOCOL, "UNKNOWN SSH_MSG_GLOBAL_REQUEST %s, "
|
||||||
rc = SSH_PACKET_NOT_USED;
|
"want_reply = %d", request, want_reply);
|
||||||
|
goto reply_with_failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
SAFE_FREE(msg);
|
SAFE_FREE(msg);
|
||||||
SAFE_FREE(request);
|
SAFE_FREE(request);
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
reply_with_failure:
|
||||||
|
/* Only report the failure if requested */
|
||||||
|
if (want_reply) {
|
||||||
|
r = ssh_buffer_add_u8(session->out_buffer,
|
||||||
|
SSH2_MSG_REQUEST_FAILURE);
|
||||||
|
if (r < 0) {
|
||||||
|
ssh_set_error_oom(session);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = ssh_packet_send(session);
|
||||||
|
if (r != SSH_OK) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SSH_LOG(SSH_LOG_PACKET,
|
||||||
|
"The requester doesn't want to know the request failed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Consume the message to avoid sending UNIMPLEMENTED later */
|
||||||
|
rc = SSH_PACKET_USED;
|
||||||
error:
|
error:
|
||||||
SAFE_FREE(msg);
|
SAFE_FREE(msg);
|
||||||
SAFE_FREE(request);
|
SAFE_FREE(request);
|
||||||
SSH_LOG(SSH_LOG_WARNING, "Invalid SSH_MSG_GLOBAL_REQUEST packet");
|
SSH_LOG(SSH_LOG_WARNING, "Invalid SSH_MSG_GLOBAL_REQUEST packet");
|
||||||
return SSH_PACKET_NOT_USED;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* WITH_SERVER */
|
#endif /* WITH_SERVER */
|
||||||
|
|||||||
75
src/packet.c
75
src/packet.c
@@ -1438,37 +1438,54 @@ void ssh_packet_set_default_callbacks(ssh_session session){
|
|||||||
* @brief dispatch the call of packet handlers callbacks for a received packet
|
* @brief dispatch the call of packet handlers callbacks for a received packet
|
||||||
* @param type type of packet
|
* @param type type of packet
|
||||||
*/
|
*/
|
||||||
void ssh_packet_process(ssh_session session, uint8_t type){
|
void ssh_packet_process(ssh_session session, uint8_t type)
|
||||||
struct ssh_iterator *i;
|
{
|
||||||
int r=SSH_PACKET_NOT_USED;
|
struct ssh_iterator *i = NULL;
|
||||||
ssh_packet_callbacks cb;
|
int rc = SSH_PACKET_NOT_USED;
|
||||||
|
ssh_packet_callbacks cb;
|
||||||
|
|
||||||
SSH_LOG(SSH_LOG_PACKET, "Dispatching handler for packet type %d",type);
|
SSH_LOG(SSH_LOG_PACKET, "Dispatching handler for packet type %d", type);
|
||||||
if(session->packet_callbacks == NULL){
|
if (session->packet_callbacks == NULL) {
|
||||||
SSH_LOG(SSH_LOG_RARE,"Packet callback is not initialized !");
|
SSH_LOG(SSH_LOG_RARE, "Packet callback is not initialized !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
i = ssh_list_get_iterator(session->packet_callbacks);
|
||||||
}
|
while (i != NULL) {
|
||||||
i=ssh_list_get_iterator(session->packet_callbacks);
|
cb = ssh_iterator_value(ssh_packet_callbacks, i);
|
||||||
while(i != NULL){
|
i = i->next;
|
||||||
cb=ssh_iterator_value(ssh_packet_callbacks,i);
|
|
||||||
i=i->next;
|
if (!cb) {
|
||||||
if(!cb)
|
continue;
|
||||||
continue;
|
}
|
||||||
if(cb->start > type)
|
|
||||||
continue;
|
if (cb->start > type) {
|
||||||
if(cb->start + cb->n_callbacks <= type)
|
continue;
|
||||||
continue;
|
}
|
||||||
if(cb->callbacks[type - cb->start]==NULL)
|
|
||||||
continue;
|
if (cb->start + cb->n_callbacks <= type) {
|
||||||
r=cb->callbacks[type - cb->start](session,type,session->in_buffer,cb->user);
|
continue;
|
||||||
if(r==SSH_PACKET_USED)
|
}
|
||||||
break;
|
|
||||||
}
|
if (cb->callbacks[type - cb->start] == NULL) {
|
||||||
if(r==SSH_PACKET_NOT_USED){
|
continue;
|
||||||
SSH_LOG(SSH_LOG_RARE,"Couldn't do anything with packet type %d",type);
|
}
|
||||||
ssh_packet_send_unimplemented(session, session->recv_seq-1);
|
|
||||||
}
|
rc = cb->callbacks[type - cb->start](session, type, session->in_buffer,
|
||||||
|
cb->user);
|
||||||
|
if (rc == SSH_PACKET_USED) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc == SSH_PACKET_NOT_USED) {
|
||||||
|
SSH_LOG(SSH_LOG_RARE, "Couldn't do anything with packet type %d", type);
|
||||||
|
rc = ssh_packet_send_unimplemented(session, session->recv_seq - 1);
|
||||||
|
if (rc != SSH_OK) {
|
||||||
|
SSH_LOG(SSH_LOG_RARE, "Failed to send unimplemented: %s",
|
||||||
|
ssh_get_error(session));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal
|
/** @internal
|
||||||
|
|||||||
42
src/pki.c
42
src/pki.c
@@ -64,16 +64,22 @@
|
|||||||
#include "libssh/misc.h"
|
#include "libssh/misc.h"
|
||||||
#include "libssh/agent.h"
|
#include "libssh/agent.h"
|
||||||
|
|
||||||
enum ssh_keytypes_e pki_privatekey_type_from_string(const char *privkey) {
|
enum ssh_keytypes_e pki_privatekey_type_from_string(const char *privkey)
|
||||||
if (strncmp(privkey, DSA_HEADER_BEGIN, strlen(DSA_HEADER_BEGIN)) == 0) {
|
{
|
||||||
|
char *start = NULL;
|
||||||
|
|
||||||
|
start = strstr(privkey, DSA_HEADER_BEGIN);
|
||||||
|
if (start != NULL) {
|
||||||
return SSH_KEYTYPE_DSS;
|
return SSH_KEYTYPE_DSS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strncmp(privkey, RSA_HEADER_BEGIN, strlen(RSA_HEADER_BEGIN)) == 0) {
|
start = strstr(privkey, RSA_HEADER_BEGIN);
|
||||||
|
if (start != NULL) {
|
||||||
return SSH_KEYTYPE_RSA;
|
return SSH_KEYTYPE_RSA;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strncmp(privkey, ECDSA_HEADER_BEGIN, strlen(ECDSA_HEADER_BEGIN)) == 0) {
|
start = strstr(privkey, ECDSA_HEADER_BEGIN);
|
||||||
|
if (start != 0) {
|
||||||
/* We don't know what the curve is at this point, so we don't actually
|
/* We don't know what the curve is at this point, so we don't actually
|
||||||
* know the type. We figure out the actual curve and fix things up in
|
* know the type. We figure out the actual curve and fix things up in
|
||||||
* pki_private_key_from_base64 */
|
* pki_private_key_from_base64 */
|
||||||
@@ -382,6 +388,19 @@ enum ssh_digest_e ssh_key_type_to_hash(ssh_session session,
|
|||||||
case SSH_KEYTYPE_DSS:
|
case SSH_KEYTYPE_DSS:
|
||||||
return SSH_DIGEST_SHA1;
|
return SSH_DIGEST_SHA1;
|
||||||
case SSH_KEYTYPE_RSA_CERT01:
|
case SSH_KEYTYPE_RSA_CERT01:
|
||||||
|
/* If we are talking to an old OpenSSH version which does not support
|
||||||
|
* SHA2 in certificates */
|
||||||
|
if ((session->openssh > 0) &&
|
||||||
|
(session->openssh < SSH_VERSION_INT(7, 2, 0)))
|
||||||
|
{
|
||||||
|
SSH_LOG(SSH_LOG_DEBUG,
|
||||||
|
"We are talking to an old OpenSSH (%x); "
|
||||||
|
"returning SSH_DIGEST_SHA1",
|
||||||
|
session->openssh);
|
||||||
|
|
||||||
|
return SSH_DIGEST_SHA1;
|
||||||
|
}
|
||||||
|
FALL_THROUGH;
|
||||||
case SSH_KEYTYPE_RSA:
|
case SSH_KEYTYPE_RSA:
|
||||||
if (ssh_key_algorithm_allowed(session, "rsa-sha2-512") &&
|
if (ssh_key_algorithm_allowed(session, "rsa-sha2-512") &&
|
||||||
(session->extensions & SSH_EXT_SIG_RSA_SHA512)) {
|
(session->extensions & SSH_EXT_SIG_RSA_SHA512)) {
|
||||||
@@ -435,6 +454,21 @@ ssh_key_get_signature_algorithm(ssh_session session,
|
|||||||
{
|
{
|
||||||
enum ssh_digest_e hash_type;
|
enum ssh_digest_e hash_type;
|
||||||
|
|
||||||
|
if (type == SSH_KEYTYPE_RSA_CERT01) {
|
||||||
|
/* If we are talking to an old OpenSSH version which does not support
|
||||||
|
* rsa-sha2-{256,512}-cert-v01@openssh.com */
|
||||||
|
if ((session->openssh > 0) &&
|
||||||
|
(session->openssh < SSH_VERSION_INT(7, 8, 0)))
|
||||||
|
{
|
||||||
|
SSH_LOG(SSH_LOG_DEBUG,
|
||||||
|
"We are talking to an old OpenSSH (%x); "
|
||||||
|
"using old cert format",
|
||||||
|
session->openssh);
|
||||||
|
|
||||||
|
return "ssh-rsa-cert-v01@openssh.com";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hash_type = ssh_key_type_to_hash(session, type);
|
hash_type = ssh_key_type_to_hash(session, type);
|
||||||
|
|
||||||
return ssh_key_signature_to_char(type, hash_type);
|
return ssh_key_signature_to_char(type, hash_type);
|
||||||
|
|||||||
@@ -529,7 +529,7 @@ int pki_key_generate_rsa(ssh_key key, int parameter){
|
|||||||
|
|
||||||
BN_free(e);
|
BN_free(e);
|
||||||
|
|
||||||
if (rc == -1 || key->rsa == NULL)
|
if (rc <= 0 || key->rsa == NULL)
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
504
src/socket.c
504
src/socket.c
@@ -102,36 +102,37 @@ static ssize_t ssh_socket_unbuffered_write(ssh_socket s,
|
|||||||
* \internal
|
* \internal
|
||||||
* \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) {
|
{
|
||||||
|
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
|
||||||
|
ssh_poll_init();
|
||||||
|
|
||||||
|
sockets_initialized = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
return 0;
|
||||||
ssh_poll_init();
|
|
||||||
|
|
||||||
sockets_initialized = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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();
|
if (sockets_initialized == 1) {
|
||||||
|
ssh_poll_cleanup();
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
#endif
|
#endif
|
||||||
sockets_initialized = 0;
|
sockets_initialized = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -139,37 +140,38 @@ void ssh_socket_cleanup(void) {
|
|||||||
* \internal
|
* \internal
|
||||||
* \brief creates a new Socket object
|
* \brief creates a new Socket object
|
||||||
*/
|
*/
|
||||||
ssh_socket ssh_socket_new(ssh_session session) {
|
ssh_socket ssh_socket_new(ssh_session session)
|
||||||
ssh_socket s;
|
{
|
||||||
|
ssh_socket s;
|
||||||
|
|
||||||
s = calloc(1, sizeof(struct ssh_socket_struct));
|
s = calloc(1, sizeof(struct ssh_socket_struct));
|
||||||
if (s == NULL) {
|
if (s == NULL) {
|
||||||
ssh_set_error_oom(session);
|
ssh_set_error_oom(session);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
s->fd = SSH_INVALID_SOCKET;
|
s->fd = SSH_INVALID_SOCKET;
|
||||||
s->last_errno = -1;
|
s->last_errno = -1;
|
||||||
s->fd_is_socket = 1;
|
s->fd_is_socket = 1;
|
||||||
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);
|
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_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;
|
||||||
}
|
}
|
||||||
s->read_wontblock = 0;
|
s->read_wontblock = 0;
|
||||||
s->write_wontblock = 0;
|
s->write_wontblock = 0;
|
||||||
s->data_except = 0;
|
s->data_except = 0;
|
||||||
s->poll_handle = NULL;
|
s->poll_handle = NULL;
|
||||||
s->state=SSH_SOCKET_NONE;
|
s->state=SSH_SOCKET_NONE;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -177,17 +179,18 @@ ssh_socket ssh_socket_new(ssh_session session) {
|
|||||||
* @brief Reset the state of a socket so it looks brand-new
|
* @brief Reset the state of a socket so it looks brand-new
|
||||||
* @param[in] s socket to rest
|
* @param[in] s socket to rest
|
||||||
*/
|
*/
|
||||||
void ssh_socket_reset(ssh_socket s){
|
void ssh_socket_reset(ssh_socket s)
|
||||||
s->fd = SSH_INVALID_SOCKET;
|
{
|
||||||
s->last_errno = -1;
|
s->fd = SSH_INVALID_SOCKET;
|
||||||
s->fd_is_socket = 1;
|
s->last_errno = -1;
|
||||||
ssh_buffer_reinit(s->in_buffer);
|
s->fd_is_socket = 1;
|
||||||
ssh_buffer_reinit(s->out_buffer);
|
ssh_buffer_reinit(s->in_buffer);
|
||||||
s->read_wontblock = 0;
|
ssh_buffer_reinit(s->out_buffer);
|
||||||
s->write_wontblock = 0;
|
s->read_wontblock = 0;
|
||||||
s->data_except = 0;
|
s->write_wontblock = 0;
|
||||||
s->poll_handle = NULL;
|
s->data_except = 0;
|
||||||
s->state=SSH_SOCKET_NONE;
|
s->poll_handle = NULL;
|
||||||
|
s->state=SSH_SOCKET_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -198,8 +201,9 @@ void ssh_socket_reset(ssh_socket s){
|
|||||||
* @param callbacks a ssh_socket_callback object reference.
|
* @param callbacks a ssh_socket_callback object reference.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void ssh_socket_set_callbacks(ssh_socket s, ssh_socket_callbacks callbacks){
|
void ssh_socket_set_callbacks(ssh_socket s, ssh_socket_callbacks callbacks)
|
||||||
s->callbacks=callbacks;
|
{
|
||||||
|
s->callbacks = callbacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -383,71 +387,73 @@ ssh_poll_handle ssh_socket_get_poll_handle(ssh_socket s)
|
|||||||
/** \internal
|
/** \internal
|
||||||
* \brief Deletes a socket object
|
* \brief Deletes a socket object
|
||||||
*/
|
*/
|
||||||
void ssh_socket_free(ssh_socket s){
|
void ssh_socket_free(ssh_socket s)
|
||||||
if (s == NULL) {
|
{
|
||||||
return;
|
if (s == NULL) {
|
||||||
}
|
return;
|
||||||
ssh_socket_close(s);
|
}
|
||||||
ssh_buffer_free(s->in_buffer);
|
ssh_socket_close(s);
|
||||||
ssh_buffer_free(s->out_buffer);
|
ssh_buffer_free(s->in_buffer);
|
||||||
SAFE_FREE(s);
|
ssh_buffer_free(s->out_buffer);
|
||||||
|
SAFE_FREE(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
int ssh_socket_unix(ssh_socket s, const char *path) {
|
int ssh_socket_unix(ssh_socket s, const char *path)
|
||||||
struct sockaddr_un sunaddr;
|
{
|
||||||
socket_t fd;
|
struct sockaddr_un sunaddr;
|
||||||
sunaddr.sun_family = AF_UNIX;
|
socket_t fd;
|
||||||
snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), "%s", path);
|
sunaddr.sun_family = AF_UNIX;
|
||||||
|
snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), "%s", 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,
|
ssh_set_error(s->session, SSH_FATAL,
|
||||||
"Error from socket(AF_UNIX, SOCK_STREAM, 0): %s",
|
"Error from socket(AF_UNIX, SOCK_STREAM, 0): %s",
|
||||||
strerror(errno));
|
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,
|
ssh_set_error(s->session, SSH_FATAL,
|
||||||
"Error from fcntl(fd, F_SETFD, 1): %s",
|
"Error from fcntl(fd, F_SETFD, 1): %s",
|
||||||
strerror(errno));
|
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",
|
||||||
ssh_set_error(s->session, SSH_FATAL, "Error from connect(): %s",
|
strerror(errno));
|
||||||
strerror(errno));
|
close(fd);
|
||||||
close(fd);
|
return -1;
|
||||||
return -1;
|
}
|
||||||
}
|
ssh_socket_set_fd(s,fd);
|
||||||
ssh_socket_set_fd(s,fd);
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** \internal
|
/** \internal
|
||||||
* \brief closes a socket
|
* \brief closes a socket
|
||||||
*/
|
*/
|
||||||
void ssh_socket_close(ssh_socket s){
|
void ssh_socket_close(ssh_socket s)
|
||||||
if (ssh_socket_is_open(s)) {
|
{
|
||||||
|
if (ssh_socket_is_open(s)) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
CLOSE_SOCKET(s->fd);
|
CLOSE_SOCKET(s->fd);
|
||||||
s->last_errno = WSAGetLastError();
|
s->last_errno = WSAGetLastError();
|
||||||
#else
|
#else
|
||||||
CLOSE_SOCKET(s->fd);
|
CLOSE_SOCKET(s->fd);
|
||||||
s->last_errno = errno;
|
s->last_errno = errno;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if(s->poll_handle != NULL){
|
if (s->poll_handle != NULL) {
|
||||||
ssh_poll_free(s->poll_handle);
|
ssh_poll_free(s->poll_handle);
|
||||||
s->poll_handle=NULL;
|
s->poll_handle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->state = SSH_SOCKET_CLOSED;
|
s->state = SSH_SOCKET_CLOSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -458,7 +464,8 @@ void ssh_socket_close(ssh_socket s){
|
|||||||
* @warning this function updates boths the input and output
|
* @warning this function updates boths the input and output
|
||||||
* file descriptors
|
* file descriptors
|
||||||
*/
|
*/
|
||||||
void ssh_socket_set_fd(ssh_socket s, socket_t fd) {
|
void ssh_socket_set_fd(ssh_socket s, socket_t fd)
|
||||||
|
{
|
||||||
s->fd = fd;
|
s->fd = fd;
|
||||||
|
|
||||||
if (s->poll_handle) {
|
if (s->poll_handle) {
|
||||||
@@ -479,14 +486,15 @@ void ssh_socket_set_fd(ssh_socket s, socket_t fd) {
|
|||||||
*/
|
*/
|
||||||
socket_t ssh_socket_get_fd(ssh_socket s)
|
socket_t ssh_socket_get_fd(ssh_socket s)
|
||||||
{
|
{
|
||||||
return s->fd;
|
return s->fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \internal
|
/** \internal
|
||||||
* \brief returns nonzero if the socket is open
|
* \brief returns nonzero if the socket is open
|
||||||
*/
|
*/
|
||||||
int ssh_socket_is_open(ssh_socket s) {
|
int ssh_socket_is_open(ssh_socket s)
|
||||||
return s->fd != SSH_INVALID_SOCKET;
|
{
|
||||||
|
return s->fd != SSH_INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \internal
|
/** \internal
|
||||||
@@ -564,29 +572,31 @@ static ssize_t ssh_socket_unbuffered_write(ssh_socket s,
|
|||||||
/** \internal
|
/** \internal
|
||||||
* \brief returns nonzero if the current socket is in the fd_set
|
* \brief returns nonzero if the current socket is in the fd_set
|
||||||
*/
|
*/
|
||||||
int ssh_socket_fd_isset(ssh_socket s, fd_set *set) {
|
int ssh_socket_fd_isset(ssh_socket s, fd_set *set)
|
||||||
if(s->fd == SSH_INVALID_SOCKET) {
|
{
|
||||||
return 0;
|
if(s->fd == SSH_INVALID_SOCKET) {
|
||||||
}
|
return 0;
|
||||||
return FD_ISSET(s->fd,set);
|
}
|
||||||
|
return FD_ISSET(s->fd,set);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \internal
|
/** \internal
|
||||||
* \brief sets the current fd in a fd_set and updates the max_fd
|
* \brief sets the current fd in a fd_set and updates the max_fd
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void ssh_socket_fd_set(ssh_socket s, fd_set *set, socket_t *max_fd) {
|
void ssh_socket_fd_set(ssh_socket s, fd_set *set, socket_t *max_fd)
|
||||||
if (s->fd == SSH_INVALID_SOCKET) {
|
{
|
||||||
return;
|
if (s->fd == SSH_INVALID_SOCKET) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
FD_SET(s->fd,set);
|
FD_SET(s->fd,set);
|
||||||
|
|
||||||
if (s->fd >= 0 &&
|
if (s->fd >= 0 &&
|
||||||
s->fd >= *max_fd &&
|
s->fd >= *max_fd &&
|
||||||
s->fd != SSH_INVALID_SOCKET) {
|
s->fd != SSH_INVALID_SOCKET) {
|
||||||
*max_fd = s->fd + 1;
|
*max_fd = s->fd + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \internal
|
/** \internal
|
||||||
@@ -594,16 +604,17 @@ void ssh_socket_fd_set(ssh_socket s, fd_set *set, socket_t *max_fd) {
|
|||||||
* \returns SSH_OK, or SSH_ERROR
|
* \returns SSH_OK, or SSH_ERROR
|
||||||
* \warning has no effect on socket before a flush
|
* \warning has no effect on socket before a flush
|
||||||
*/
|
*/
|
||||||
int ssh_socket_write(ssh_socket s, const void *buffer, int len) {
|
int ssh_socket_write(ssh_socket s, const void *buffer, int len)
|
||||||
if(len > 0) {
|
{
|
||||||
if (ssh_buffer_add_data(s->out_buffer, buffer, len) < 0) {
|
if (len > 0) {
|
||||||
ssh_set_error_oom(s->session);
|
if (ssh_buffer_add_data(s->out_buffer, buffer, len) < 0) {
|
||||||
return SSH_ERROR;
|
ssh_set_error_oom(s->session);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
ssh_socket_nonblocking_flush(s);
|
||||||
}
|
}
|
||||||
ssh_socket_nonblocking_flush(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -685,24 +696,29 @@ int ssh_socket_nonblocking_flush(ssh_socket s)
|
|||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssh_socket_set_write_wontblock(ssh_socket s) {
|
void ssh_socket_set_write_wontblock(ssh_socket s)
|
||||||
s->write_wontblock = 1;
|
{
|
||||||
|
s->write_wontblock = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssh_socket_set_read_wontblock(ssh_socket s) {
|
void ssh_socket_set_read_wontblock(ssh_socket s)
|
||||||
s->read_wontblock = 1;
|
{
|
||||||
|
s->read_wontblock = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssh_socket_set_except(ssh_socket s) {
|
void ssh_socket_set_except(ssh_socket s)
|
||||||
s->data_except = 1;
|
{
|
||||||
|
s->data_except = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ssh_socket_data_available(ssh_socket s) {
|
int ssh_socket_data_available(ssh_socket s)
|
||||||
return s->read_wontblock;
|
{
|
||||||
|
return s->read_wontblock;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ssh_socket_data_writable(ssh_socket s) {
|
int ssh_socket_data_writable(ssh_socket s)
|
||||||
return s->write_wontblock;
|
{
|
||||||
|
return s->write_wontblock;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal
|
/** @internal
|
||||||
@@ -710,60 +726,69 @@ int ssh_socket_data_writable(ssh_socket s) {
|
|||||||
* @param s the socket
|
* @param s the socket
|
||||||
* @returns numbers of bytes buffered, or 0 if the socket isn't connected
|
* @returns numbers of bytes buffered, or 0 if the socket isn't connected
|
||||||
*/
|
*/
|
||||||
int ssh_socket_buffered_write_bytes(ssh_socket s){
|
int ssh_socket_buffered_write_bytes(ssh_socket s)
|
||||||
if(s==NULL || s->out_buffer == NULL)
|
{
|
||||||
return 0;
|
if (s==NULL || s->out_buffer == NULL) {
|
||||||
return ssh_buffer_get_len(s->out_buffer);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ssh_buffer_get_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;
|
||||||
|
|
||||||
if (ssh_buffer_get_len(s->in_buffer) > 0) {
|
if (ssh_buffer_get_len(s->in_buffer) > 0) {
|
||||||
r |= SSH_READ_PENDING;
|
r |= SSH_READ_PENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ssh_buffer_get_len(s->out_buffer) > 0) {
|
if (ssh_buffer_get_len(s->out_buffer) > 0) {
|
||||||
r |= SSH_WRITE_PENDING;
|
r |= SSH_WRITE_PENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->data_except) {
|
if (s->data_except) {
|
||||||
r |= SSH_CLOSED_ERROR;
|
r |= SSH_CLOSED_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ssh_socket_get_poll_flags(ssh_socket s) {
|
int ssh_socket_get_poll_flags(ssh_socket s)
|
||||||
int r = 0;
|
{
|
||||||
if (s->poll_handle != NULL && (ssh_poll_get_events (s->poll_handle) & POLLIN) > 0) {
|
int r = 0;
|
||||||
r |= SSH_READ_PENDING;
|
if (s->poll_handle != NULL && (ssh_poll_get_events (s->poll_handle) & POLLIN) > 0) {
|
||||||
}
|
r |= SSH_READ_PENDING;
|
||||||
if (s->poll_handle != NULL && (ssh_poll_get_events (s->poll_handle) & POLLOUT) > 0) {
|
}
|
||||||
r |= SSH_WRITE_PENDING;
|
if (s->poll_handle != NULL && (ssh_poll_get_events (s->poll_handle) & POLLOUT) > 0) {
|
||||||
}
|
r |= SSH_WRITE_PENDING;
|
||||||
return r;
|
}
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
int ssh_socket_set_nonblocking(socket_t fd) {
|
int ssh_socket_set_nonblocking(socket_t fd)
|
||||||
u_long nonblocking = 1;
|
{
|
||||||
return ioctlsocket(fd, FIONBIO, &nonblocking);
|
u_long nonblocking = 1;
|
||||||
|
return ioctlsocket(fd, FIONBIO, &nonblocking);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ssh_socket_set_blocking(socket_t fd) {
|
int ssh_socket_set_blocking(socket_t fd)
|
||||||
u_long nonblocking = 0;
|
{
|
||||||
return ioctlsocket(fd, FIONBIO, &nonblocking);
|
u_long nonblocking = 0;
|
||||||
|
return ioctlsocket(fd, FIONBIO, &nonblocking);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* _WIN32 */
|
#else /* _WIN32 */
|
||||||
int ssh_socket_set_nonblocking(socket_t fd) {
|
int ssh_socket_set_nonblocking(socket_t fd)
|
||||||
return fcntl(fd, F_SETFL, O_NONBLOCK);
|
{
|
||||||
|
return fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ssh_socket_set_blocking(socket_t fd) {
|
int ssh_socket_set_blocking(socket_t fd)
|
||||||
return fcntl(fd, F_SETFL, 0);
|
{
|
||||||
|
return fcntl(fd, F_SETFL, 0);
|
||||||
}
|
}
|
||||||
#endif /* _WIN32 */
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
@@ -782,21 +807,24 @@ int ssh_socket_set_blocking(socket_t fd) {
|
|||||||
* which is problematic for hosts having DNS fail-over.
|
* which is problematic for hosts having DNS fail-over.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int ssh_socket_connect(ssh_socket s, const char *host, int port, const char *bind_addr){
|
int
|
||||||
socket_t fd;
|
ssh_socket_connect(ssh_socket s, const char *host, int port, const char *bind_addr)
|
||||||
|
{
|
||||||
|
socket_t fd;
|
||||||
|
|
||||||
if(s->state != SSH_SOCKET_NONE) {
|
if (s->state != SSH_SOCKET_NONE) {
|
||||||
ssh_set_error(s->session, SSH_FATAL,
|
ssh_set_error(s->session, SSH_FATAL,
|
||||||
"ssh_socket_connect called on socket not unconnected");
|
"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(SSH_LOG_PROTOCOL,"Nonblocking connection socket: %d",fd);
|
SSH_LOG(SSH_LOG_PROTOCOL, "Nonblocking connection socket: %d", fd);
|
||||||
if(fd == SSH_INVALID_SOCKET)
|
if (fd == SSH_INVALID_SOCKET) {
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
ssh_socket_set_fd(s,fd);
|
}
|
||||||
|
ssh_socket_set_fd(s,fd);
|
||||||
|
|
||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
@@ -807,16 +835,26 @@ int ssh_socket_connect(ssh_socket s, const char *host, int port, const char *bin
|
|||||||
* @param in input file descriptor
|
* @param in input file descriptor
|
||||||
* @param out output file descriptor
|
* @param out output file descriptor
|
||||||
*/
|
*/
|
||||||
void ssh_execute_command(const char *command, socket_t in, socket_t out){
|
void
|
||||||
const char *args[]={"/bin/sh","-c",command,NULL};
|
ssh_execute_command(const char *command, socket_t in, socket_t out)
|
||||||
/* redirect in and out to stdin, stdout and stderr */
|
{
|
||||||
dup2(in, 0);
|
const char *args[] = {"/bin/sh", "-c", command, NULL};
|
||||||
dup2(out,1);
|
/* Prepare /dev/null socket for the stderr redirection */
|
||||||
dup2(out,2);
|
int devnull = open("/dev/null", O_WRONLY);
|
||||||
close(in);
|
if (devnull == -1) {
|
||||||
close(out);
|
SSH_LOG(SSH_LOG_WARNING, "Failed to open stderr");
|
||||||
execv(args[0],(char * const *)args);
|
exit(1);
|
||||||
exit(1);
|
}
|
||||||
|
|
||||||
|
/* redirect in and out to stdin, stdout */
|
||||||
|
dup2(in, 0);
|
||||||
|
dup2(out, 1);
|
||||||
|
/* Ignore anything on the stderr */
|
||||||
|
dup2(devnull, STDERR_FILENO);
|
||||||
|
close(in);
|
||||||
|
close(out);
|
||||||
|
execv(args[0], (char * const *)args);
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -829,37 +867,39 @@ void ssh_execute_command(const char *command, socket_t in, socket_t out){
|
|||||||
* @returns SSH_ERROR error while executing the command.
|
* @returns SSH_ERROR error while executing the command.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int ssh_socket_connect_proxycommand(ssh_socket s, const char *command){
|
int
|
||||||
socket_t pair[2];
|
ssh_socket_connect_proxycommand(ssh_socket s, const char *command)
|
||||||
int pid;
|
{
|
||||||
int rc;
|
socket_t pair[2];
|
||||||
|
int pid;
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (s->state != SSH_SOCKET_NONE) {
|
if (s->state != SSH_SOCKET_NONE) {
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = socketpair(PF_UNIX, SOCK_STREAM, 0, pair);
|
rc = socketpair(PF_UNIX, SOCK_STREAM, 0, pair);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
SSH_LOG(SSH_LOG_PROTOCOL,"Executing proxycommand '%s'",command);
|
SSH_LOG(SSH_LOG_PROTOCOL, "Executing proxycommand '%s'", command);
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if(pid == 0){
|
if(pid == 0) {
|
||||||
ssh_execute_command(command,pair[0],pair[0]);
|
ssh_execute_command(command, pair[0], pair[0]);
|
||||||
}
|
}
|
||||||
close(pair[0]);
|
close(pair[0]);
|
||||||
SSH_LOG(SSH_LOG_PROTOCOL,"ProxyCommand connection pipe: [%d,%d]",pair[0],pair[1]);
|
SSH_LOG(SSH_LOG_PROTOCOL, "ProxyCommand connection pipe: [%d,%d]",pair[0],pair[1]);
|
||||||
ssh_socket_set_fd(s, pair[1]);
|
ssh_socket_set_fd(s, pair[1]);
|
||||||
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(s), POLLIN | POLLOUT);
|
ssh_poll_set_events(ssh_socket_get_poll_handle(s), POLLIN | 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _WIN32 */
|
#endif /* _WIN32 */
|
||||||
|
|||||||
@@ -67,8 +67,8 @@ if (CLIENT_TESTING)
|
|||||||
find_program(SSH_EXECUTABLE NAMES ssh)
|
find_program(SSH_EXECUTABLE NAMES ssh)
|
||||||
if (SSH_EXECUTABLE)
|
if (SSH_EXECUTABLE)
|
||||||
execute_process(COMMAND ${SSH_EXECUTABLE} -V ERROR_VARIABLE OPENSSH_VERSION_STR)
|
execute_process(COMMAND ${SSH_EXECUTABLE} -V ERROR_VARIABLE OPENSSH_VERSION_STR)
|
||||||
string(REGEX REPLACE "^OpenSSH_([0-9]).[0-9].*$" "\\1" OPENSSH_VERSION_MAJOR "${OPENSSH_VERSION_STR}")
|
string(REGEX REPLACE "^.*OpenSSH_([0-9]).[0-9].*$" "\\1" OPENSSH_VERSION_MAJOR "${OPENSSH_VERSION_STR}")
|
||||||
string(REGEX REPLACE "^OpenSSH_[0-9].([0-9]).*$" "\\1" OPENSSH_VERSION_MINOR "${OPENSSH_VERSION_STR}")
|
string(REGEX REPLACE "^.*OpenSSH_[0-9].([0-9]).*$" "\\1" OPENSSH_VERSION_MINOR "${OPENSSH_VERSION_STR}")
|
||||||
add_definitions(-DOPENSSH_VERSION_MAJOR=${OPENSSH_VERSION_MAJOR} -DOPENSSH_VERSION_MINOR=${OPENSSH_VERSION_MINOR})
|
add_definitions(-DOPENSSH_VERSION_MAJOR=${OPENSSH_VERSION_MAJOR} -DOPENSSH_VERSION_MINOR=${OPENSSH_VERSION_MINOR})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ set(LIBSSH_CLIENT_TESTS
|
|||||||
torture_knownhosts_verify
|
torture_knownhosts_verify
|
||||||
torture_proxycommand
|
torture_proxycommand
|
||||||
torture_session
|
torture_session
|
||||||
torture_request_env)
|
torture_request_env
|
||||||
|
torture_client_global_requests)
|
||||||
|
|
||||||
if (DEFAULT_C_NO_DEPRECATION_FLAGS)
|
if (DEFAULT_C_NO_DEPRECATION_FLAGS)
|
||||||
set_source_files_properties(torture_knownhosts.c
|
set_source_files_properties(torture_knownhosts.c
|
||||||
|
|||||||
152
tests/client/torture_client_global_requests.c
Normal file
152
tests/client/torture_client_global_requests.c
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* torture_client_global_requests.c - Tests for client global requests
|
||||||
|
*
|
||||||
|
* This file is part of the SSH Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 by Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* Author: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||||
|
*
|
||||||
|
* The SSH 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, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* The SSH 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 the SSH Library; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||||
|
* MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#define LIBSSH_STATIC
|
||||||
|
|
||||||
|
#include "torture.h"
|
||||||
|
#include "libssh/libssh.h"
|
||||||
|
#include "libssh/priv.h"
|
||||||
|
#include "libssh/session.h"
|
||||||
|
#include "libssh/channels.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
|
||||||
|
static int sshd_setup(void **state)
|
||||||
|
{
|
||||||
|
torture_setup_sshd_server(state, true);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sshd_teardown(void **state)
|
||||||
|
{
|
||||||
|
torture_teardown_sshd_server(state);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int session_setup(void **state)
|
||||||
|
{
|
||||||
|
struct torture_state *s = *state;
|
||||||
|
int verbosity = torture_libssh_verbosity();
|
||||||
|
struct passwd *pwd;
|
||||||
|
bool b = false;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
pwd = getpwnam("bob");
|
||||||
|
assert_non_null(pwd);
|
||||||
|
|
||||||
|
rc = setuid(pwd->pw_uid);
|
||||||
|
assert_return_code(rc, errno);
|
||||||
|
|
||||||
|
s->ssh.session = ssh_new();
|
||||||
|
assert_non_null(s->ssh.session);
|
||||||
|
|
||||||
|
ssh_options_set(s->ssh.session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
|
||||||
|
ssh_options_set(s->ssh.session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
|
||||||
|
|
||||||
|
/* Make sure no other configuration options from system will get used */
|
||||||
|
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_PROCESS_CONFIG, &b);
|
||||||
|
assert_ssh_return_code(s->ssh.session, rc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int session_teardown(void **state)
|
||||||
|
{
|
||||||
|
struct torture_state *s = *state;
|
||||||
|
|
||||||
|
ssh_disconnect(s->ssh.session);
|
||||||
|
ssh_free(s->ssh.session);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int authenticate(void **state)
|
||||||
|
{
|
||||||
|
struct torture_state *s = *state;
|
||||||
|
ssh_session session = s->ssh.session;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = ssh_options_set(session, SSH_OPTIONS_USER, TORTURE_SSH_USER_BOB);
|
||||||
|
assert_int_equal(rc, SSH_OK);
|
||||||
|
|
||||||
|
rc = ssh_connect(session);
|
||||||
|
assert_int_equal(rc, SSH_OK);
|
||||||
|
|
||||||
|
rc = ssh_userauth_password(session, NULL, TORTURE_SSH_USER_BOB_PASSWORD);
|
||||||
|
assert_int_equal(rc, SSH_AUTH_SUCCESS);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void torture_unknown_request(void **state)
|
||||||
|
{
|
||||||
|
struct torture_state *s = *state;
|
||||||
|
ssh_session session = s->ssh.session;
|
||||||
|
ssh_channel channel;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = authenticate(state);
|
||||||
|
assert_ssh_return_code(session, rc);
|
||||||
|
|
||||||
|
/* Request asking for reply */
|
||||||
|
rc = ssh_global_request(session, "unknown-request-00@test.com", NULL, 1);
|
||||||
|
assert_ssh_return_code_equal(session, rc, SSH_ERROR);
|
||||||
|
|
||||||
|
/* Request and don't ask for reply */
|
||||||
|
rc = ssh_global_request(session, "another-bad-req-00@test.com", NULL, 0);
|
||||||
|
assert_ssh_return_code(session, rc);
|
||||||
|
|
||||||
|
/* Open channel to make sure the session is still working */
|
||||||
|
channel = ssh_channel_new(session);
|
||||||
|
assert_non_null(channel);
|
||||||
|
|
||||||
|
rc = ssh_channel_open_session(channel);
|
||||||
|
assert_ssh_return_code(session, rc);
|
||||||
|
|
||||||
|
ssh_channel_close(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
int torture_run_tests(void)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct CMUnitTest tests[] = {
|
||||||
|
cmocka_unit_test_setup_teardown(torture_unknown_request,
|
||||||
|
session_setup,
|
||||||
|
session_teardown),
|
||||||
|
};
|
||||||
|
|
||||||
|
ssh_init();
|
||||||
|
torture_filter_tests(tests);
|
||||||
|
rc = cmocka_run_group_tests(tests, sshd_setup, sshd_teardown);
|
||||||
|
ssh_finalize();
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
@@ -115,6 +115,28 @@ static void torture_options_set_proxycommand_ssh(void **state)
|
|||||||
assert_int_equal(rc & O_RDWR, O_RDWR);
|
assert_int_equal(rc & O_RDWR, O_RDWR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void torture_options_set_proxycommand_ssh_stderr(void **state)
|
||||||
|
{
|
||||||
|
struct torture_state *s = *state;
|
||||||
|
ssh_session session = s->ssh.session;
|
||||||
|
const char *address = torture_server_address(AF_INET);
|
||||||
|
char command[255] = {0};
|
||||||
|
int rc;
|
||||||
|
socket_t fd;
|
||||||
|
|
||||||
|
rc = snprintf(command, sizeof(command), "ssh -vvv -W [%%h]:%%p alice@%s", address);
|
||||||
|
assert_true((size_t)rc < sizeof(command));
|
||||||
|
|
||||||
|
rc = ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, command);
|
||||||
|
assert_int_equal(rc, 0);
|
||||||
|
rc = ssh_connect(session);
|
||||||
|
assert_ssh_return_code(session, rc);
|
||||||
|
fd = ssh_get_fd(session);
|
||||||
|
assert_true(fd != SSH_INVALID_SOCKET);
|
||||||
|
rc = fcntl(fd, F_GETFL);
|
||||||
|
assert_int_equal(rc & O_RDWR, O_RDWR);
|
||||||
|
}
|
||||||
|
|
||||||
int torture_run_tests(void) {
|
int torture_run_tests(void) {
|
||||||
int rc;
|
int rc;
|
||||||
struct CMUnitTest tests[] = {
|
struct CMUnitTest tests[] = {
|
||||||
@@ -127,6 +149,9 @@ int torture_run_tests(void) {
|
|||||||
cmocka_unit_test_setup_teardown(torture_options_set_proxycommand_ssh,
|
cmocka_unit_test_setup_teardown(torture_options_set_proxycommand_ssh,
|
||||||
session_setup,
|
session_setup,
|
||||||
session_teardown),
|
session_teardown),
|
||||||
|
cmocka_unit_test_setup_teardown(torture_options_set_proxycommand_ssh_stderr,
|
||||||
|
session_setup,
|
||||||
|
session_teardown),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ static int torture_pkd_setup_ecdsa_521(void **state) {
|
|||||||
f(client, ecdsa_256_diffie_hellman_group_exchange_sha256, kexcmd(GEX_SHA256), setup_ecdsa_256, teardown) \
|
f(client, ecdsa_256_diffie_hellman_group_exchange_sha256, kexcmd(GEX_SHA256), setup_ecdsa_256, teardown) \
|
||||||
f(client, ecdsa_384_diffie_hellman_group_exchange_sha256, kexcmd(GEX_SHA256), setup_ecdsa_384, teardown) \
|
f(client, ecdsa_384_diffie_hellman_group_exchange_sha256, kexcmd(GEX_SHA256), setup_ecdsa_384, teardown) \
|
||||||
f(client, ecdsa_521_diffie_hellman_group_exchange_sha256, kexcmd(GEX_SHA256), setup_ecdsa_521, teardown)
|
f(client, ecdsa_521_diffie_hellman_group_exchange_sha256, kexcmd(GEX_SHA256), setup_ecdsa_521, teardown)
|
||||||
#elif /* !defined(WITH_GEX) */
|
#else /* !defined(WITH_GEX) */
|
||||||
#define PKDTESTS_KEX_FIPS(f, client, kexcmd) \
|
#define PKDTESTS_KEX_FIPS(f, client, kexcmd) \
|
||||||
f(client, rsa_ecdh_sha2_nistp256, kexcmd("ecdh-sha2-nistp256"), setup_rsa, teardown) \
|
f(client, rsa_ecdh_sha2_nistp256, kexcmd("ecdh-sha2-nistp256"), setup_rsa, teardown) \
|
||||||
f(client, rsa_ecdh_sha2_nistp384, kexcmd("ecdh-sha2-nistp384"), setup_rsa, teardown) \
|
f(client, rsa_ecdh_sha2_nistp384, kexcmd("ecdh-sha2-nistp384"), setup_rsa, teardown) \
|
||||||
|
|||||||
@@ -473,6 +473,50 @@ static void torture_server_hostkey_mismatch(void **state)
|
|||||||
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
|
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void torture_server_unknown_global_request(void **state)
|
||||||
|
{
|
||||||
|
struct test_server_st *tss = *state;
|
||||||
|
struct torture_state *s = NULL;
|
||||||
|
ssh_session session = NULL;
|
||||||
|
ssh_channel channel;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
assert_non_null(tss);
|
||||||
|
|
||||||
|
s = tss->state;
|
||||||
|
assert_non_null(s);
|
||||||
|
|
||||||
|
session = s->ssh.session;
|
||||||
|
assert_non_null(session);
|
||||||
|
|
||||||
|
rc = ssh_options_set(session, SSH_OPTIONS_USER, SSHD_DEFAULT_USER);
|
||||||
|
assert_int_equal(rc, SSH_OK);
|
||||||
|
|
||||||
|
rc = ssh_connect(session);
|
||||||
|
assert_int_equal(rc, SSH_OK);
|
||||||
|
|
||||||
|
/* Using the default password for the server */
|
||||||
|
rc = ssh_userauth_password(session, NULL, SSHD_DEFAULT_PASSWORD);
|
||||||
|
assert_int_equal(rc, SSH_AUTH_SUCCESS);
|
||||||
|
|
||||||
|
/* Request asking for reply */
|
||||||
|
rc = ssh_global_request(session, "unknown-request-00@test.com", NULL, 1);
|
||||||
|
assert_ssh_return_code_equal(session, rc, SSH_ERROR);
|
||||||
|
|
||||||
|
/* Request and don't ask for reply */
|
||||||
|
rc = ssh_global_request(session, "another-bad-req-00@test.com", NULL, 0);
|
||||||
|
assert_ssh_return_code(session, rc);
|
||||||
|
|
||||||
|
/* Open channel to make sure the session is still working */
|
||||||
|
channel = ssh_channel_new(session);
|
||||||
|
assert_non_null(channel);
|
||||||
|
|
||||||
|
rc = ssh_channel_open_session(channel);
|
||||||
|
assert_ssh_return_code(session, rc);
|
||||||
|
|
||||||
|
ssh_channel_close(channel);
|
||||||
|
}
|
||||||
|
|
||||||
int torture_run_tests(void) {
|
int torture_run_tests(void) {
|
||||||
int rc;
|
int rc;
|
||||||
struct CMUnitTest tests[] = {
|
struct CMUnitTest tests[] = {
|
||||||
@@ -488,6 +532,9 @@ int torture_run_tests(void) {
|
|||||||
cmocka_unit_test_setup_teardown(torture_server_hostkey_mismatch,
|
cmocka_unit_test_setup_teardown(torture_server_hostkey_mismatch,
|
||||||
session_setup,
|
session_setup,
|
||||||
session_teardown),
|
session_teardown),
|
||||||
|
cmocka_unit_test_setup_teardown(torture_server_unknown_global_request,
|
||||||
|
session_setup,
|
||||||
|
session_teardown),
|
||||||
};
|
};
|
||||||
|
|
||||||
ssh_init();
|
ssh_init();
|
||||||
|
|||||||
@@ -381,6 +381,7 @@ static void torture_knownhosts_host_exists(void **state)
|
|||||||
|
|
||||||
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||||
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, knownhosts_file);
|
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, knownhosts_file);
|
||||||
|
|
||||||
/* This makes sure the system's known_hosts are not used */
|
/* This makes sure the system's known_hosts are not used */
|
||||||
ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, "/dev/null");
|
ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, "/dev/null");
|
||||||
|
|
||||||
@@ -388,6 +389,14 @@ static void torture_knownhosts_host_exists(void **state)
|
|||||||
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
|
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
|
||||||
assert_true(found == SSH_KNOWN_HOSTS_OK);
|
assert_true(found == SSH_KNOWN_HOSTS_OK);
|
||||||
|
|
||||||
|
/* This makes sure the check will not fail when the system's known_hosts is
|
||||||
|
* not accessible*/
|
||||||
|
ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, "./unaccessible");
|
||||||
|
|
||||||
|
found = ssh_session_has_known_hosts_entry(session);
|
||||||
|
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
|
||||||
|
assert_true(found == SSH_KNOWN_HOSTS_OK);
|
||||||
|
|
||||||
ssh_options_set(session, SSH_OPTIONS_HOST, "wurstbrot");
|
ssh_options_set(session, SSH_OPTIONS_HOST, "wurstbrot");
|
||||||
found = ssh_session_has_known_hosts_entry(session);
|
found = ssh_session_has_known_hosts_entry(session);
|
||||||
assert_true(found == SSH_KNOWN_HOSTS_UNKNOWN);
|
assert_true(found == SSH_KNOWN_HOSTS_UNKNOWN);
|
||||||
|
|||||||
@@ -168,6 +168,37 @@ static void torture_pki_dsa_import_privkey_base64(void **state)
|
|||||||
SSH_KEY_FREE(key);
|
SSH_KEY_FREE(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void torture_pki_dsa_import_privkey_base64_comment(void **state)
|
||||||
|
{
|
||||||
|
int rc, file_str_len;
|
||||||
|
ssh_key key = NULL;
|
||||||
|
const char *passphrase = torture_get_testkey_passphrase();
|
||||||
|
const char *comment_str = "#this is line-comment\n#this is another\n";
|
||||||
|
const char *key_str = NULL;
|
||||||
|
char *file_str = NULL;
|
||||||
|
|
||||||
|
(void) state; /* unused */
|
||||||
|
|
||||||
|
key_str = torture_get_testkey(SSH_KEYTYPE_DSS, 0);
|
||||||
|
assert_non_null(key_str);
|
||||||
|
|
||||||
|
file_str_len = strlen(comment_str) + strlen(key_str) + 1;
|
||||||
|
file_str = malloc(file_str_len);
|
||||||
|
assert_non_null(file_str);
|
||||||
|
rc = snprintf(file_str, file_str_len, "%s%s", comment_str, key_str);
|
||||||
|
assert_int_equal(rc, file_str_len - 1);
|
||||||
|
|
||||||
|
rc = ssh_pki_import_privkey_base64(file_str,
|
||||||
|
passphrase,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&key);
|
||||||
|
assert_true(rc == 0);
|
||||||
|
|
||||||
|
free(file_str);
|
||||||
|
SSH_KEY_FREE(key);
|
||||||
|
}
|
||||||
|
|
||||||
static int test_sign_verify_data(ssh_key key,
|
static int test_sign_verify_data(ssh_key key,
|
||||||
enum ssh_digest_e hash_type,
|
enum ssh_digest_e hash_type,
|
||||||
const unsigned char *input,
|
const unsigned char *input,
|
||||||
@@ -833,6 +864,9 @@ int torture_run_tests(void)
|
|||||||
cmocka_unit_test_setup_teardown(torture_pki_dsa_import_privkey_base64,
|
cmocka_unit_test_setup_teardown(torture_pki_dsa_import_privkey_base64,
|
||||||
setup_dsa_key,
|
setup_dsa_key,
|
||||||
teardown),
|
teardown),
|
||||||
|
cmocka_unit_test_setup_teardown(torture_pki_dsa_import_privkey_base64_comment,
|
||||||
|
setup_dsa_key,
|
||||||
|
teardown),
|
||||||
cmocka_unit_test_setup_teardown(torture_pki_dsa_import_privkey_base64,
|
cmocka_unit_test_setup_teardown(torture_pki_dsa_import_privkey_base64,
|
||||||
setup_openssh_dsa_key,
|
setup_openssh_dsa_key,
|
||||||
teardown),
|
teardown),
|
||||||
|
|||||||
@@ -241,6 +241,37 @@ static void torture_pki_ecdsa_import_privkey_base64(void **state)
|
|||||||
SSH_KEY_FREE(key);
|
SSH_KEY_FREE(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void torture_pki_ecdsa_import_privkey_base64_comment(void **state)
|
||||||
|
{
|
||||||
|
int rc, file_str_len;
|
||||||
|
const char *comment_str = "#this is line-comment\n#this is another\n";
|
||||||
|
char *key_str = NULL, *file_str = NULL;
|
||||||
|
ssh_key key = NULL;
|
||||||
|
const char *passphrase = torture_get_testkey_passphrase();
|
||||||
|
|
||||||
|
(void) state; /* unused */
|
||||||
|
|
||||||
|
key_str = torture_pki_read_file(LIBSSH_ECDSA_TESTKEY);
|
||||||
|
assert_non_null(key_str);
|
||||||
|
|
||||||
|
file_str_len = strlen(comment_str) + strlen(key_str) + 1;
|
||||||
|
file_str = malloc(file_str_len);
|
||||||
|
assert_non_null(file_str);
|
||||||
|
rc = snprintf(file_str, file_str_len, "%s%s", comment_str, key_str);
|
||||||
|
assert_int_equal(rc, file_str_len - 1);
|
||||||
|
|
||||||
|
rc = ssh_pki_import_privkey_base64(file_str, passphrase, NULL, NULL, &key);
|
||||||
|
assert_true(rc == 0);
|
||||||
|
assert_non_null(key);
|
||||||
|
|
||||||
|
rc = ssh_key_is_private(key);
|
||||||
|
assert_true(rc == 1);
|
||||||
|
|
||||||
|
free(key_str);
|
||||||
|
free(file_str);
|
||||||
|
SSH_KEY_FREE(key);
|
||||||
|
}
|
||||||
|
|
||||||
static void torture_pki_ecdsa_publickey_from_privatekey(void **state)
|
static void torture_pki_ecdsa_publickey_from_privatekey(void **state)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
@@ -904,6 +935,15 @@ int torture_run_tests(void) {
|
|||||||
cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64,
|
cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64,
|
||||||
setup_ecdsa_key_521,
|
setup_ecdsa_key_521,
|
||||||
teardown),
|
teardown),
|
||||||
|
cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64_comment,
|
||||||
|
setup_ecdsa_key_256,
|
||||||
|
teardown),
|
||||||
|
cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64_comment,
|
||||||
|
setup_ecdsa_key_384,
|
||||||
|
teardown),
|
||||||
|
cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64_comment,
|
||||||
|
setup_ecdsa_key_521,
|
||||||
|
teardown),
|
||||||
cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64,
|
cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64,
|
||||||
setup_openssh_ecdsa_key_256,
|
setup_openssh_ecdsa_key_256,
|
||||||
teardown),
|
teardown),
|
||||||
|
|||||||
@@ -213,6 +213,44 @@ static void torture_pki_rsa_import_privkey_base64(void **state)
|
|||||||
SSH_KEY_FREE(key);
|
SSH_KEY_FREE(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void torture_pki_rsa_import_privkey_base64_comment(void **state)
|
||||||
|
{
|
||||||
|
int rc, file_str_len;
|
||||||
|
const char *comment_str = "#this is line-comment\n#this is another\n";
|
||||||
|
char *key_str = NULL, *file_str = NULL;
|
||||||
|
ssh_key key = NULL;
|
||||||
|
const char *passphrase = torture_get_testkey_passphrase();
|
||||||
|
enum ssh_keytypes_e type;
|
||||||
|
|
||||||
|
(void) state; /* unused */
|
||||||
|
|
||||||
|
key_str = torture_pki_read_file(LIBSSH_RSA_TESTKEY);
|
||||||
|
assert_non_null(key_str);
|
||||||
|
|
||||||
|
file_str_len = strlen(comment_str) + strlen(key_str) + 1;
|
||||||
|
file_str = malloc(file_str_len);
|
||||||
|
assert_non_null(file_str);
|
||||||
|
rc = snprintf(file_str, file_str_len, "%s%s", comment_str, key_str);
|
||||||
|
assert_int_equal(rc, file_str_len - 1);
|
||||||
|
|
||||||
|
rc = ssh_pki_import_privkey_base64(file_str, passphrase, NULL, NULL, &key);
|
||||||
|
assert_true(rc == 0);
|
||||||
|
assert_non_null(key);
|
||||||
|
|
||||||
|
type = ssh_key_type(key);
|
||||||
|
assert_true(type == SSH_KEYTYPE_RSA);
|
||||||
|
|
||||||
|
rc = ssh_key_is_private(key);
|
||||||
|
assert_true(rc == 1);
|
||||||
|
|
||||||
|
rc = ssh_key_is_public(key);
|
||||||
|
assert_true(rc == 1);
|
||||||
|
|
||||||
|
free(key_str);
|
||||||
|
free(file_str);
|
||||||
|
SSH_KEY_FREE(key);
|
||||||
|
}
|
||||||
|
|
||||||
static void torture_pki_rsa_publickey_from_privatekey(void **state)
|
static void torture_pki_rsa_publickey_from_privatekey(void **state)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
@@ -468,21 +506,23 @@ static void torture_pki_rsa_generate_key(void **state)
|
|||||||
ssh_session session=ssh_new();
|
ssh_session session=ssh_new();
|
||||||
(void) state;
|
(void) state;
|
||||||
|
|
||||||
rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 1024, &key);
|
if (!ssh_fips_mode()) {
|
||||||
assert_true(rc == SSH_OK);
|
rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 1024, &key);
|
||||||
assert_non_null(key);
|
assert_true(rc == SSH_OK);
|
||||||
rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey);
|
assert_non_null(key);
|
||||||
assert_int_equal(rc, SSH_OK);
|
rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey);
|
||||||
assert_non_null(pubkey);
|
assert_int_equal(rc, SSH_OK);
|
||||||
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA256);
|
assert_non_null(pubkey);
|
||||||
assert_non_null(sign);
|
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA256);
|
||||||
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
assert_non_null(sign);
|
||||||
assert_true(rc == SSH_OK);
|
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||||
ssh_signature_free(sign);
|
assert_true(rc == SSH_OK);
|
||||||
SSH_KEY_FREE(key);
|
ssh_signature_free(sign);
|
||||||
SSH_KEY_FREE(pubkey);
|
SSH_KEY_FREE(key);
|
||||||
key = NULL;
|
SSH_KEY_FREE(pubkey);
|
||||||
pubkey = NULL;
|
key = NULL;
|
||||||
|
pubkey = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 2048, &key);
|
rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 2048, &key);
|
||||||
assert_true(rc == SSH_OK);
|
assert_true(rc == SSH_OK);
|
||||||
@@ -877,6 +917,9 @@ int torture_run_tests(void) {
|
|||||||
cmocka_unit_test_setup_teardown(torture_pki_rsa_import_privkey_base64,
|
cmocka_unit_test_setup_teardown(torture_pki_rsa_import_privkey_base64,
|
||||||
setup_rsa_key,
|
setup_rsa_key,
|
||||||
teardown),
|
teardown),
|
||||||
|
cmocka_unit_test_setup_teardown(torture_pki_rsa_import_privkey_base64_comment,
|
||||||
|
setup_rsa_key,
|
||||||
|
teardown),
|
||||||
cmocka_unit_test_setup_teardown(torture_pki_rsa_import_privkey_base64,
|
cmocka_unit_test_setup_teardown(torture_pki_rsa_import_privkey_base64,
|
||||||
setup_openssh_rsa_key,
|
setup_openssh_rsa_key,
|
||||||
teardown),
|
teardown),
|
||||||
|
|||||||
Reference in New Issue
Block a user