Skip to content
Permalink
Branch: master
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
251 lines (202 sloc) 8.01 KB
/*
* This file is part of RTRlib.
*
* This file is subject to the terms and conditions of the MIT license.
* See the file LICENSE in the top level directory for more details.
*
* Website: http://rtrlib.realmv6.org/
*/
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <libssh/libssh.h>
#include "rtrlib/lib/alloc_utils_private.h"
#include "rtrlib/lib/log_private.h"
#include "rtrlib/lib/utils_private.h"
#include "rtrlib/rtrlib_export_private.h"
#include "rtrlib/transport/ssh/ssh_transport_private.h"
#include "rtrlib/transport/transport_private.h"
#define SSH_DBG(fmt, sock, ...) lrtr_dbg("SSH Transport(%s@%s:%u): " fmt, (sock)->config.username, (sock)->config.host, (sock)->config.port, ## __VA_ARGS__)
#define SSH_DBG1(a, sock) lrtr_dbg("SSH Transport(%s@%s:%u): " a, (sock)->config.username, (sock)->config.host, (sock)->config.port)
struct tr_ssh_socket {
ssh_session session;
ssh_channel channel;
struct tr_ssh_config config;
char *ident;
};
static int tr_ssh_open(void *tr_ssh_sock);
static void tr_ssh_close(void *tr_ssh_sock);
static void tr_ssh_free(struct tr_socket *tr_sock);
static int tr_ssh_recv(const void *tr_ssh_sock, void *buf, const size_t buf_len, const time_t timeout);
static int tr_ssh_send(const void *tr_ssh_sock, const void *pdu, const size_t len, const time_t timeout);
static int tr_ssh_recv_async(const struct tr_ssh_socket *tr_ssh_sock, void *buf, const size_t buf_len);
static const char *tr_ssh_ident(void *tr_ssh_sock);
int tr_ssh_open(void *socket)
{
struct tr_ssh_socket *ssh_socket = socket;
const struct tr_ssh_config *config = &ssh_socket->config;
assert(ssh_socket->channel == NULL);
assert(ssh_socket->session == NULL);
if((ssh_socket->session = ssh_new()) == NULL) {
SSH_DBG1("tr_ssh_init: can't create ssh_session", ssh_socket);
goto error;
}
const int verbosity = SSH_LOG_NOLOG;
ssh_options_set(ssh_socket->session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
ssh_options_set(ssh_socket->session, SSH_OPTIONS_HOST, config->host);
ssh_options_set(ssh_socket->session, SSH_OPTIONS_PORT, &(config->port));
ssh_options_set(ssh_socket->session, SSH_OPTIONS_BINDADDR, config->bindaddr);
ssh_options_set(ssh_socket->session, SSH_OPTIONS_USER, config->username);
if (config->server_hostkey_path != NULL)
ssh_options_set(ssh_socket->session, SSH_OPTIONS_KNOWNHOSTS, config->server_hostkey_path);
if (config->client_privkey_path != NULL)
ssh_options_set(ssh_socket->session, SSH_OPTIONS_IDENTITY, config->client_privkey_path);
if(ssh_connect(ssh_socket->session) == SSH_ERROR) {
SSH_DBG1("tr_ssh_init: opening SSH connection failed", ssh_socket);
goto error;
}
//check server identity
if((config->server_hostkey_path != NULL) && (ssh_is_server_known(ssh_socket->session) != SSH_SERVER_KNOWN_OK)) {
SSH_DBG1("tr_ssh_init: Wrong hostkey", ssh_socket);
goto error;
}
#if LIBSSH_VERSION_MAJOR > 0 || LIBSSH_VERSION_MINOR > 5
const int rtval = ssh_userauth_publickey_auto(ssh_socket->session, NULL, NULL);
#else /* else use libSSH version 0.5.0 */
const int rtval = ssh_userauth_autopubkey(ssh_socket->session, NULL);
#endif
if(rtval != SSH_AUTH_SUCCESS) {
SSH_DBG1("tr_ssh_init: Authentication failed", ssh_socket);
goto error;
}
if((ssh_socket->channel = ssh_channel_new(ssh_socket->session)) == NULL)
goto error;
if(ssh_channel_open_session(ssh_socket->channel) == SSH_ERROR)
goto error;
if(ssh_channel_request_subsystem(ssh_socket->channel, "rpki-rtr") == SSH_ERROR) {
SSH_DBG1("tr_ssh_init: Error requesting subsystem rpki-rtr", ssh_socket);
goto error;
}
SSH_DBG1("Connection established", ssh_socket);
return TR_SUCCESS;
error:
tr_ssh_close(ssh_socket);
return TR_ERROR;
}
void tr_ssh_close(void *tr_ssh_sock)
{
struct tr_ssh_socket *socket = tr_ssh_sock;
if(socket->channel != NULL) {
if(ssh_channel_is_open(socket->channel))
ssh_channel_close(socket->channel);
ssh_channel_free(socket->channel);
socket->channel = NULL;
}
if(socket->session != NULL) {
ssh_disconnect(socket->session);
ssh_free(socket->session);
socket->session = NULL;
}
SSH_DBG1("Socket closed", socket);
}
void tr_ssh_free(struct tr_socket *tr_sock)
{
struct tr_ssh_socket *tr_ssh_sock = tr_sock->socket;
assert(tr_ssh_sock->channel == NULL);
assert(tr_ssh_sock->session == NULL);
SSH_DBG1("Freeing socket", tr_ssh_sock);
lrtr_free(tr_ssh_sock->config.host);
lrtr_free(tr_ssh_sock->config.bindaddr);
lrtr_free(tr_ssh_sock->config.username);
lrtr_free(tr_ssh_sock->config.client_privkey_path);
lrtr_free(tr_ssh_sock->config.server_hostkey_path);
if (tr_ssh_sock->ident != NULL)
lrtr_free(tr_ssh_sock->ident);
lrtr_free(tr_ssh_sock);
tr_sock->socket = NULL;
}
int tr_ssh_recv_async(const struct tr_ssh_socket *tr_ssh_sock, void *buf, const size_t buf_len)
{
const int rtval = ssh_channel_read_nonblocking(tr_ssh_sock->channel, buf, buf_len, false);
if(rtval == 0) {
if(ssh_channel_is_eof(tr_ssh_sock->channel) != 0) {
SSH_DBG1("remote has sent EOF", tr_ssh_sock);
return TR_CLOSED;
} else {
return TR_WOULDBLOCK;
}
} else if(rtval == SSH_ERROR) {
SSH_DBG1("recv(..) error", tr_ssh_sock);
return TR_ERROR;
}
return rtval;
}
int tr_ssh_recv(const void* tr_ssh_sock, void* buf, const size_t buf_len, const time_t timeout){
ssh_channel rchans[2] = { ((struct tr_ssh_socket*) tr_ssh_sock)->channel, NULL };
struct timeval timev = { 1, 0 };
if(ssh_channel_select(rchans, NULL, NULL, &timev) == SSH_EINTR)
return TR_INTR;
if(ssh_channel_is_eof(((struct tr_ssh_socket*) tr_ssh_sock)->channel) != 0)
return SSH_ERROR;
if(rchans[0] == NULL)
return TR_WOULDBLOCK;
return tr_ssh_recv_async(tr_ssh_sock, buf, buf_len);
}
int tr_ssh_send(const void *tr_ssh_sock, const void *pdu, const size_t len, const time_t timeout __attribute__((unused)))
{
return ssh_channel_write(((struct tr_ssh_socket *) tr_ssh_sock)->channel, pdu, len);
}
const char *tr_ssh_ident(void *tr_ssh_sock)
{
size_t len;
struct tr_ssh_socket *sock = tr_ssh_sock;
assert(sock != NULL);
if (sock->ident != NULL)
return sock->ident;
len = strlen(sock->config.username) + 1 + strlen(sock->config.host) + 1 +
5 + 1;
sock->ident = lrtr_malloc(len);
if (sock->ident == NULL)
return NULL;
snprintf(sock->ident, len, "%s@%s:%u", sock->config.username,
sock->config.host, sock->config.port);
return sock->ident;
}
RTRLIB_EXPORT int tr_ssh_init(const struct tr_ssh_config *config, struct tr_socket *socket)
{
socket->close_fp = &tr_ssh_close;
socket->free_fp = &tr_ssh_free;
socket->open_fp = &tr_ssh_open;
socket->recv_fp = &tr_ssh_recv;
socket->send_fp = &tr_ssh_send;;
socket->ident_fp = &tr_ssh_ident;
socket->socket = lrtr_malloc(sizeof(struct tr_ssh_socket));
struct tr_ssh_socket *ssh_socket = socket->socket;
ssh_socket->channel = NULL;
ssh_socket->session = NULL;
ssh_socket->config.host = lrtr_strdup(config->host);
ssh_socket->config.port = config->port;
ssh_socket->config.username = lrtr_strdup(config->username);
if (config->bindaddr) {
ssh_socket->config.bindaddr = lrtr_strdup(config->bindaddr);
} else {
ssh_socket->config.bindaddr = NULL;
}
if (config->client_privkey_path) {
ssh_socket->config.client_privkey_path =
lrtr_strdup(config->client_privkey_path);
} else {
ssh_socket->config.client_privkey_path = NULL;
}
if (config->server_hostkey_path) {
ssh_socket->config.server_hostkey_path =
lrtr_strdup(config->server_hostkey_path);
} else {
ssh_socket->config.server_hostkey_path = NULL;
}
ssh_socket->ident = NULL;;
return TR_SUCCESS;
}
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.