Update libssh

This commit is contained in:
Nicolas Viennot 2013-10-04 16:34:20 -04:00
parent 8a87170c8a
commit bb5634ce20
18 changed files with 626 additions and 51 deletions

View file

@ -76,6 +76,18 @@ if (WITH_GSSAPI AND GSSAPI_FOUND)
)
endif (WITH_GSSAPI AND GSSAPI_FOUND)
if (WITH_NACL AND NACL_FOUND)
set(LIBSSH_PRIVATE_INCLUDE_DIRS
${LIBSSH_PRIVATE_INCLUDE_DIRS}
${NACL_INCLUDE_DIR}
)
set(LIBSSH_LINK_LIBRARIES
${LIBSSH_LINK_LIBRARIES}
${NACL_LIBRARY}
)
endif (WITH_NACL AND NACL_FOUND)
set(LIBSSH_LINK_LIBRARIES
${LIBSSH_LINK_LIBRARIES}
CACHE INTERNAL "libssh link libraries"
@ -192,6 +204,13 @@ if (WITH_GSSAPI AND GSSAPI_FOUND)
)
endif (WITH_GSSAPI AND GSSAPI_FOUND)
if (WITH_NACL)
set(libssh_SRCS
${libssh_SRCS}
curve25519.c
)
endif (WITH_NACL)
include_directories(
${LIBSSH_PUBLIC_INCLUDE_DIRS}
${LIBSSH_PRIVATE_INCLUDE_DIRS}

View file

@ -312,7 +312,11 @@ static int channel_open(ssh_channel channel, const char *type_c, int window,
type_c, channel->local_channel);
pending:
/* wait until channel is opened by server */
err = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER, ssh_channel_open_termination, channel);
err = ssh_handle_packets_termination(session,
SSH_TIMEOUT_DEFAULT,
ssh_channel_open_termination,
channel);
if (session->session_state == SSH_SESSION_STATE_ERROR)
err = SSH_ERROR;
end:
@ -1607,7 +1611,11 @@ static int channel_request(ssh_channel channel, const char *request,
return SSH_OK;
}
pending:
rc = ssh_handle_packets_termination(session,SSH_TIMEOUT_USER, ssh_channel_request_termination, channel);
rc = ssh_handle_packets_termination(session,
SSH_TIMEOUT_DEFAULT,
ssh_channel_request_termination,
channel);
if(session->session_state == SSH_SESSION_STATE_ERROR || rc == SSH_ERROR) {
channel->request_state = SSH_CHANNEL_REQ_STATE_ERROR;
}
@ -1983,8 +1991,11 @@ static ssh_channel ssh_channel_accept(ssh_session session, int channeltype,
struct ssh_iterator *iterator;
int t;
for (t = timeout_ms; t >= 0; t -= 50)
{
/*
* We sleep for 50 ms in ssh_handle_packets() and later sleep for
* 50 ms. So we need to decrement by 100 ms.
*/
for (t = timeout_ms; t >= 0; t -= 100) {
ssh_handle_packets(session, 50);
if (session->ssh_message_list) {
@ -2145,8 +2156,11 @@ static int global_request(ssh_session session, const char *request,
return SSH_OK;
}
pending:
rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER,
ssh_global_request_termination, session);
rc = ssh_handle_packets_termination(session,
SSH_TIMEOUT_DEFAULT,
ssh_global_request_termination,
session);
if(rc==SSH_ERROR || session->session_state == SSH_SESSION_STATE_ERROR){
session->global_req_state = SSH_CHANNEL_REQ_STATE_ERROR;
}
@ -2640,8 +2654,8 @@ static int ssh_channel_read_termination(void *s){
* @param[in] is_stderr A boolean value to mark reading from the stderr flow.
*
* @return The number of bytes read, 0 on end of file or SSH_ERROR
* on error. Can return 0 if nothing is available in nonblocking
* mode.
* on error. In nonblocking mode it Can return 0 if no data
* is available or SSH_AGAIN.
*
* @warning This function may return less than count bytes of data, and won't
* block until count bytes have been read.
@ -2924,8 +2938,10 @@ int ssh_channel_get_exit_status(ssh_channel channel) {
if(channel == NULL) {
return SSH_ERROR;
}
rc = ssh_handle_packets_termination(channel->session, SSH_TIMEOUT_USER,
ssh_channel_exit_status_termination, channel);
rc = ssh_handle_packets_termination(channel->session,
SSH_TIMEOUT_DEFAULT,
ssh_channel_exit_status_termination,
channel);
if (rc == SSH_ERROR || channel->session->session_state ==
SSH_SESSION_STATE_ERROR)
return SSH_ERROR;

View file

@ -196,6 +196,11 @@ static int dh_handshake(ssh_session session) {
case SSH_KEX_ECDH_SHA2_NISTP256:
rc = ssh_client_ecdh_init(session);
break;
#endif
#ifdef HAVE_CURVE25519
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
rc = ssh_client_curve25519_init(session);
break;
#endif
default:
rc = SSH_ERROR;
@ -579,6 +584,14 @@ char *ssh_get_issue_banner(ssh_session session) {
* @param[in] session The SSH session to use.
*
* @return The version number if available, 0 otherwise.
*
* @code
* int openssh = ssh_get_openssh_version();
*
* if (openssh == SSH_INT_VERSION(6, 1, 0)) {
* printf("Version match!\m");
* }
* @endcode
*/
int ssh_get_openssh_version(ssh_session session) {
if (session == NULL) {

285
libssh/src/curve25519.c Normal file
View file

@ -0,0 +1,285 @@
/*
* curve25519.c - Curve25519 ECDH functions for key exchange
* curve25519-sha256@libssh.org
*
* This file is part of the SSH Library
*
* Copyright (c) 2013 by Aris Adamantiadis <aris@badcode.be>
*
* 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, version 2.1 of the License.
*
* 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"
#include "libssh/curve25519.h"
#ifdef HAVE_CURVE25519
#include "nacl/crypto_scalarmult_curve25519.h"
#include "libssh/ssh2.h"
#include "libssh/buffer.h"
#include "libssh/priv.h"
#include "libssh/session.h"
#include "libssh/crypto.h"
#include "libssh/dh.h"
#include "libssh/pki.h"
/** @internal
* @brief Starts curve25519-sha256@libssh.org key exchange
*/
int ssh_client_curve25519_init(ssh_session session){
ssh_string client_pubkey;
int rc;
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_INIT);
if (rc < 0) {
return SSH_ERROR;
}
rc = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
if (rc == 0){
ssh_set_error(session, SSH_FATAL, "PRNG error");
return SSH_ERROR;
}
crypto_scalarmult_curve25519_base(session->next_crypto->curve25519_client_pubkey,
session->next_crypto->curve25519_privkey);
client_pubkey = ssh_string_new(CURVE25519_PUBKEY_SIZE);
if (client_pubkey == NULL) {
return SSH_ERROR;
}
ssh_string_fill(client_pubkey, session->next_crypto->curve25519_client_pubkey,
CURVE25519_PUBKEY_SIZE);
rc = buffer_add_ssh_string(session->out_buffer,client_pubkey);
if (rc < 0) {
ssh_string_free(client_pubkey);
return SSH_ERROR;
}
rc = packet_send(session);
return rc;
}
static int ssh_curve25519_build_k(ssh_session session) {
ssh_curve25519_pubkey k;
session->next_crypto->k = bignum_new();
if (session->next_crypto->k == NULL) {
return SSH_ERROR;
}
if (session->server)
crypto_scalarmult_curve25519(k, session->next_crypto->curve25519_privkey,
session->next_crypto->curve25519_client_pubkey);
else
crypto_scalarmult_curve25519(k, session->next_crypto->curve25519_privkey,
session->next_crypto->curve25519_server_pubkey);
BN_bin2bn(k, CURVE25519_PUBKEY_SIZE, session->next_crypto->k);
#ifdef DEBUG_CRYPTO
ssh_print_hexa("Session server cookie",
session->next_crypto->server_kex.cookie, 16);
ssh_print_hexa("Session client cookie",
session->next_crypto->client_kex.cookie, 16);
ssh_print_bignum("Shared secret key", session->next_crypto->k);
#endif
return 0;
}
/** @internal
* @brief parses a SSH_MSG_KEX_ECDH_REPLY packet and sends back
* a SSH_MSG_NEWKEYS
*/
int ssh_client_curve25519_reply(ssh_session session, ssh_buffer packet){
ssh_string q_s_string = NULL;
ssh_string pubkey = NULL;
ssh_string signature = NULL;
int rc;
pubkey = buffer_get_ssh_string(packet);
if (pubkey == NULL){
ssh_set_error(session,SSH_FATAL, "No public key in packet");
goto error;
}
/* this is the server host key */
session->next_crypto->server_pubkey = pubkey;
pubkey = NULL;
q_s_string = buffer_get_ssh_string(packet);
if (q_s_string == NULL) {
ssh_set_error(session,SSH_FATAL, "No Q_S ECC point in packet");
goto error;
}
if (ssh_string_len(q_s_string) != CURVE25519_PUBKEY_SIZE){
ssh_set_error(session, SSH_FATAL, "Incorrect size for server Curve25519 public key: %d",
ssh_string_len(q_s_string));
ssh_string_free(q_s_string);
goto error;
}
memcpy(session->next_crypto->curve25519_server_pubkey, ssh_string_data(q_s_string), CURVE25519_PUBKEY_SIZE);
signature = buffer_get_ssh_string(packet);
if (signature == NULL) {
ssh_set_error(session, SSH_FATAL, "No signature in packet");
goto error;
}
session->next_crypto->dh_server_signature = signature;
signature=NULL; /* ownership changed */
/* TODO: verify signature now instead of waiting for NEWKEYS */
if (ssh_curve25519_build_k(session) < 0) {
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
goto error;
}
/* Send the MSG_NEWKEYS */
if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
goto error;
}
rc=packet_send(session);
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
return rc;
error:
return SSH_ERROR;
}
#ifdef WITH_SERVER
/** @brief Parse a SSH_MSG_KEXDH_INIT packet (server) and send a
* SSH_MSG_KEXDH_REPLY
*/
int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){
/* ECDH keys */
ssh_string q_c_string;
ssh_string q_s_string;
/* SSH host keys (rsa,dsa,ecdsa) */
ssh_key privkey;
ssh_string sig_blob = NULL;
int rc;
/* Extract the client pubkey from the init packet */
q_c_string = buffer_get_ssh_string(packet);
if (q_c_string == NULL) {
ssh_set_error(session,SSH_FATAL, "No Q_C ECC point in packet");
return SSH_ERROR;
}
if (ssh_string_len(q_c_string) != CURVE25519_PUBKEY_SIZE){
ssh_set_error(session, SSH_FATAL, "Incorrect size for server Curve25519 public key: %d",
ssh_string_len(q_c_string));
ssh_string_free(q_c_string);
return SSH_ERROR;
}
memcpy(session->next_crypto->curve25519_client_pubkey,
ssh_string_data(q_c_string), CURVE25519_PUBKEY_SIZE);
ssh_string_free(q_c_string);
/* Build server's keypair */
rc = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
if (rc == 0){
ssh_set_error(session, SSH_FATAL, "PRNG error");
return SSH_ERROR;
}
crypto_scalarmult_curve25519_base(session->next_crypto->curve25519_server_pubkey,
session->next_crypto->curve25519_privkey);
q_s_string = ssh_string_new(CURVE25519_PUBKEY_SIZE);
if (q_s_string == NULL) {
return SSH_ERROR;
}
ssh_string_fill(q_s_string, session->next_crypto->curve25519_server_pubkey,
CURVE25519_PUBKEY_SIZE);
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_REPLY);
if (rc < 0) {
ssh_set_error_oom(session);
return SSH_ERROR;
}
/* build k and session_id */
rc = ssh_curve25519_build_k(session);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
return SSH_ERROR;
}
/* privkey is not allocated */
rc = ssh_get_key_params(session, &privkey);
if (rc == SSH_ERROR) {
return SSH_ERROR;
}
rc = make_sessionid(session);
if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL, "Could not create a session id");
return SSH_ERROR;
}
/* add host's public key */
rc = buffer_add_ssh_string(session->out_buffer,
session->next_crypto->server_pubkey);
if (rc < 0) {
ssh_set_error_oom(session);
return SSH_ERROR;
}
/* add ecdh public key */
rc = buffer_add_ssh_string(session->out_buffer, q_s_string);
ssh_string_free(q_s_string);
if (rc < 0) {
ssh_set_error_oom(session);
return SSH_ERROR;
}
/* add signature blob */
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
if (sig_blob == NULL) {
ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
return SSH_ERROR;
}
rc = buffer_add_ssh_string(session->out_buffer, sig_blob);
ssh_string_free(sig_blob);
if (rc < 0) {
ssh_set_error_oom(session);
return SSH_ERROR;
}
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_ECDH_REPLY sent");
rc = packet_send(session);
if (rc == SSH_ERROR) {
return SSH_ERROR;
}
/* Send the MSG_NEWKEYS */
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS);
if (rc < 0) {
return SSH_ERROR;;
}
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
rc = packet_send(session);
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
return rc;
}
#endif /* WITH_SERVER */
#endif /* HAVE_CURVE25519 */

View file

@ -770,6 +770,18 @@ int make_sessionid(ssh_session session) {
if (rc < 0) {
goto error;
}
#endif
#ifdef HAVE_CURVE25519
} else if(session->next_crypto->kex_type == SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG){
rc = buffer_add_u32(buf, htonl(CURVE25519_PUBKEY_SIZE));
rc += buffer_add_data(buf, session->next_crypto->curve25519_client_pubkey,
CURVE25519_PUBKEY_SIZE);
rc += buffer_add_u32(buf, htonl(CURVE25519_PUBKEY_SIZE));
rc += buffer_add_data(buf, session->next_crypto->curve25519_server_pubkey,
CURVE25519_PUBKEY_SIZE);
if (rc != SSH_OK) {
goto error;
}
#endif
}
num = make_bignum_string(session->next_crypto->k);
@ -800,6 +812,7 @@ int make_sessionid(ssh_session session) {
session->next_crypto->secret_hash);
break;
case SSH_KEX_ECDH_SHA2_NISTP256:
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
session->next_crypto->digest_len = SHA256_DIGEST_LENGTH;
session->next_crypto->mac_type = SSH_MAC_SHA256;
session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);

View file

@ -34,6 +34,7 @@
#include "libssh/session.h"
#include "libssh/ssh2.h"
#include "libssh/string.h"
#include "libssh/curve25519.h"
#ifdef HAVE_LIBGCRYPT
# define BLOWFISH "blowfish-cbc,"
@ -63,14 +64,21 @@
#define ZLIB "none"
#endif
#ifdef HAVE_ECDH
#define KEY_EXCHANGE "ecdh-sha2-nistp256,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1"
#define HOSTKEYS "ecdsa-sha2-nistp256,ssh-rsa,ssh-dss"
#ifdef HAVE_CURVE25519
#define CURVE25519 "curve25519-sha256@libssh.org,"
#else
#define KEY_EXCHANGE "diffie-hellman-group14-sha1,diffie-hellman-group1-sha1"
#define HOSTKEYS "ssh-rsa,ssh-dss"
#define CURVE25519 ""
#endif
#ifdef HAVE_ECDH
#define ECDH "ecdh-sha2-nistp256,"
#define HOSTKEYS "ecdsa-sha2-nistp256,ssh-rsa,ssh-dss"
#else
#define HOSTKEYS "ssh-rsa,ssh-dss"
#define ECDH ""
#endif
#define KEY_EXCHANGE CURVE25519 ECDH "diffie-hellman-group14-sha1,diffie-hellman-group1-sha1"
#define KEX_METHODS_SIZE 10
/* NOTE: This is a fixed API and the index is defined by ssh_kex_types_e */
@ -412,6 +420,8 @@ int ssh_kex_select_methods (ssh_session session){
session->next_crypto->kex_type=SSH_KEX_DH_GROUP14_SHA1;
} else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp256") == 0){
session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP256;
} else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "curve25519-sha256@libssh.org") == 0){
session->next_crypto->kex_type=SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG;
}
return SSH_OK;

View file

@ -127,6 +127,17 @@ static int ssh_execute_server_request(ssh_session session, ssh_message msg)
}
return SSH_OK;
} else if (msg->auth_request.method == SSH_AUTH_METHOD_NONE &&
ssh_callbacks_exists(session->server_callbacks, auth_none_function)) {
rc = session->server_callbacks->auth_none_function(session,
msg->auth_request.username, session->server_callbacks->userdata);
if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_PARTIAL){
ssh_message_auth_reply_success(msg, rc == SSH_AUTH_PARTIAL);
} else {
ssh_message_reply_default(msg);
}
return SSH_OK;
}
break;
case SSH_REQUEST_CHANNEL_OPEN:

View file

@ -35,6 +35,7 @@
#include "libssh/session.h"
#include "libssh/socket.h"
#include "libssh/ssh2.h"
#include "libssh/curve25519.h"
/**
* @internal
@ -102,6 +103,11 @@ SSH_PACKET_CALLBACK(ssh_packet_dh_reply){
case SSH_KEX_ECDH_SHA2_NISTP256:
rc = ssh_client_ecdh_reply(session, packet);
break;
#endif
#ifdef HAVE_CURVE25519
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
rc = ssh_client_curve25519_reply(session, packet);
break;
#endif
default:
ssh_set_error(session,SSH_FATAL,"Wrong kex type in ssh_packet_dh_reply");

View file

@ -349,8 +349,8 @@ void ssh_signature_free(ssh_signature sig)
*
* @param[in] auth_data Private data passed to the auth function.
*
* @param[out] pkey A pointer where the key can be stored. You need
* to free the memory.
* @param[out] pkey A pointer where the allocated key can be stored. You
* need to free the memory.
*
* @return SSH_ERROR in case of error, SSH_OK otherwise.
*
@ -397,8 +397,8 @@ int ssh_pki_import_privkey_base64(const char *b64_key,
*
* @param[in] auth_data Private data passed to the auth function.
*
* @param[out] pkey A pointer to store the ssh_key. You need to free the
* key.
* @param[out] pkey A pointer to store the allocated ssh_key. You need to
* free the key.
*
* @returns SSH_OK on success, SSH_EOF if the file doesn't exist or permission
* denied, SSH_ERROR otherwise.
@ -684,8 +684,8 @@ fail:
*
* @param[in] type The type of the key to format.
*
* @param[out] pkey A pointer where the key can be stored. You need
* to free the memory.
* @param[out] pkey A pointer where the allocated key can be stored. You
* need to free the memory.
*
* @return SSH_OK on success, SSH_ERROR on error.
*
@ -728,8 +728,8 @@ int ssh_pki_import_pubkey_base64(const char *b64_key,
* @param[in] key_blob The key blob to import as specified in RFC 4253 section
* 6.6 "Public Key Algorithms".
*
* @param[out] pkey A pointer where the key can be stored. You need
* to free the memory.
* @param[out] pkey A pointer where the allocated key can be stored. You
* need to free the memory.
*
* @return SSH_OK on success, SSH_ERROR on error.
*
@ -789,8 +789,8 @@ fail:
*
* @param[in] filename The path to the public key.
*
* @param[out] pkey A pointer to store the public key. You need to free the
* memory.
* @param[out] pkey A pointer to store the allocated public key. You need to
* free the memory.
*
* @returns SSH_OK on success, SSH_EOF if the file doesn't exist or permission
* denied, SSH_ERROR otherwise.
@ -875,17 +875,20 @@ int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey)
/**
* @brief Generates a keypair.
*
* @param[in] type Type of key to create
*
* @param[in] parameter Parameter to the creation of key:
* rsa : length of the key in bits (e.g. 1024, 2048, 4096)
* dsa : length of the key in bits (e.g. 1024, 2048, 3072)
* ecdsa : bits of the key (e.g. 256, 384, 512)
* @param[out] pkey A pointer to store the private key. You need to free the
* memory.
* @param[out] pkey A pointer to store the allocated private key. You need
* to free the memory.
*
* @return SSH_OK on success, SSH_ERROR on error.
*
* @warning Generating a key pair may take some time.
*/
int ssh_pki_generate(enum ssh_keytypes_e type, int parameter,
ssh_key *pkey){
int rc;
@ -1000,7 +1003,8 @@ int ssh_pki_export_pubkey_blob(const ssh_key key,
*
* @param[in] key The key to hash
*
* @param[out] b64_key A pointer to store the base64 hased key.
* @param[out] b64_key A pointer to store the allocated base64 hashed key. You
* need to free the buffer.
*
* @return SSH_OK on success, SSH_ERROR on error.
*

View file

@ -58,6 +58,7 @@
#include "libssh/dh.h"
#include "libssh/messages.h"
#include "libssh/options.h"
#include "libssh/curve25519.h"
#define set_status(session, status) do {\
if (session->common.callbacks && session->common.callbacks->connect_status_function) \
@ -182,6 +183,11 @@ SSH_PACKET_CALLBACK(ssh_packet_kexdh_init){
case SSH_KEX_ECDH_SHA2_NISTP256:
rc = ssh_server_ecdh_init(session, packet);
break;
#endif
#ifdef HAVE_CURVE25519
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
rc = ssh_server_curve25519_init(session, packet);
break;
#endif
default:
ssh_set_error(session,SSH_FATAL,"Wrong kex type in ssh_packet_kexdh_init");

View file

@ -115,6 +115,17 @@ ssh_session ssh_new(void) {
goto err;
}
#ifdef HAVE_ECC
id = strdup("%d/id_ecdsa");
if (id == NULL) {
goto err;
}
rc = ssh_list_append(session->opts.identity, id);
if (rc == SSH_ERROR) {
goto err;
}
#endif
id = strdup("%d/id_rsa");
if (id == NULL) {
goto err;
@ -268,7 +279,10 @@ void ssh_free(ssh_session session) {
/**
* @brief get the server banner
*
* @param[in] session The SSH session
*
* @return Returns the server banner string or NULL.
*/
const char* ssh_get_serverbanner(ssh_session session) {
if(!session) {
@ -300,8 +314,6 @@ void ssh_silent_disconnect(ssh_session session) {
* @param[in] session The ssh session to change.
*
* @param[in] blocking Zero for nonblocking mode.
*
* \bug nonblocking code is in development and won't work as expected
*/
void ssh_set_blocking(ssh_session session, int blocking) {
if (session == NULL) {
@ -577,7 +589,7 @@ int ssh_get_status(ssh_session session) {
socketstate = ssh_socket_get_status(session->socket);
if (session->closed) {
if (session->session_state == SSH_SESSION_STATE_DISCONNECTED) {
r |= SSH_CLOSED;
}
if (socketstate & SSH_READ_PENDING) {
@ -586,7 +598,8 @@ int ssh_get_status(ssh_session session) {
if (socketstate & SSH_WRITE_PENDING) {
r |= SSH_WRITE_PENDING;
}
if ((session->closed && (socketstate & SSH_CLOSED_ERROR)) ||
if ((session->session_state == SSH_SESSION_STATE_DISCONNECTED &&
(socketstate & SSH_CLOSED_ERROR)) ||
session->session_state == SSH_SESSION_STATE_ERROR) {
r |= SSH_CLOSED_ERROR;
}
@ -610,12 +623,9 @@ const char *ssh_get_disconnect_message(ssh_session session) {
return NULL;
}
if (!session->closed) {
if (session->session_state != SSH_SESSION_STATE_DISCONNECTED) {
ssh_set_error(session, SSH_REQUEST_DENIED,
"Connection not closed yet");
} else if(session->closed_by_except) {
ssh_set_error(session, SSH_REQUEST_DENIED,
"Connection closed by socket error");
} else if(!session->discon_msg) {
ssh_set_error(session, SSH_FATAL,
"Connection correctly closed but no disconnect message");