2016-03-01 13:13:41 +00:00
|
|
|
/* ssh-base.c
|
|
|
|
* ssh-base has base utility functions to connect to hosts via ssh
|
|
|
|
*
|
|
|
|
* Copyright 2016, Dario Lombardo
|
|
|
|
*
|
|
|
|
* Wireshark - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
|
|
* Copyright 1998 Gerald Combs
|
|
|
|
*
|
2018-02-07 11:26:45 +00:00
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
2016-03-01 13:13:41 +00:00
|
|
|
*/
|
|
|
|
|
2015-11-24 22:03:13 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
2016-03-01 13:13:41 +00:00
|
|
|
#include "ssh-base.h"
|
|
|
|
|
|
|
|
#include <extcap/extcap-base.h>
|
|
|
|
#include <log.h>
|
2016-03-04 09:53:56 +00:00
|
|
|
#include <string.h>
|
2018-11-10 20:15:58 +00:00
|
|
|
#include <libssh/callbacks.h>
|
|
|
|
#include <ws_attributes.h>
|
|
|
|
|
2018-12-25 19:05:50 +00:00
|
|
|
static void extcap_log(int priority _U_, const char *function, const char *buffer, void *userdata _U_)
|
2018-11-10 20:15:58 +00:00
|
|
|
{
|
|
|
|
g_debug("[%s] %s", function, buffer);
|
|
|
|
}
|
2016-03-01 13:13:41 +00:00
|
|
|
|
2018-11-09 22:10:46 +00:00
|
|
|
ssh_session create_ssh_connection(const ssh_params_t* ssh_params, char** err_info)
|
2016-03-01 13:13:41 +00:00
|
|
|
{
|
|
|
|
ssh_session sshs;
|
2018-11-09 22:10:46 +00:00
|
|
|
gchar* username = NULL;
|
|
|
|
guint port;
|
2016-03-01 13:13:41 +00:00
|
|
|
|
|
|
|
/* Open session and set options */
|
|
|
|
sshs = ssh_new();
|
|
|
|
if (sshs == NULL) {
|
2016-06-06 02:24:47 +00:00
|
|
|
*err_info = g_strdup("Can't create ssh session");
|
2016-03-01 13:13:41 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-11-09 22:10:46 +00:00
|
|
|
if (!ssh_params->host) {
|
2016-06-06 02:24:47 +00:00
|
|
|
*err_info = g_strdup("Hostname needed");
|
2016-03-01 13:13:41 +00:00
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
|
2018-11-09 22:10:46 +00:00
|
|
|
if (ssh_options_set(sshs, SSH_OPTIONS_HOST, ssh_params->host)) {
|
|
|
|
*err_info = g_strdup_printf("Can't set the host: %s", ssh_params->host);
|
2016-03-01 13:13:41 +00:00
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
|
2018-11-09 16:41:36 +00:00
|
|
|
/* Load the configurations already present in the system configuration file. */
|
|
|
|
/* They will be overwritten by the user-provided configurations. */
|
|
|
|
if (ssh_options_parse_config(sshs, NULL) != 0) {
|
|
|
|
*err_info = g_strdup("Unable to load the configuration file");
|
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
|
2018-11-10 20:15:58 +00:00
|
|
|
if (ssh_params->debug) {
|
|
|
|
int debug_level = SSH_LOG_INFO;
|
|
|
|
ssh_options_set(sshs, SSH_OPTIONS_LOG_VERBOSITY, &debug_level);
|
|
|
|
ssh_set_log_callback(extcap_log);
|
|
|
|
}
|
|
|
|
|
2018-11-09 22:10:46 +00:00
|
|
|
if (ssh_params->port != 0) {
|
|
|
|
port = ssh_params->port;
|
2016-03-01 13:13:41 +00:00
|
|
|
if (ssh_options_set(sshs, SSH_OPTIONS_PORT, &port)) {
|
2018-11-09 22:10:46 +00:00
|
|
|
*err_info = g_strdup_printf("Can't set the port: %u", port);
|
2016-03-01 13:13:41 +00:00
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-09 22:10:46 +00:00
|
|
|
if (ssh_params->proxycommand) {
|
|
|
|
if (ssh_options_set(sshs, SSH_OPTIONS_PROXYCOMMAND, ssh_params->proxycommand)) {
|
|
|
|
*err_info = g_strdup_printf("Can't set the ProxyCommand: %s", ssh_params->proxycommand);
|
2018-11-03 14:15:43 +00:00
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-09 22:10:46 +00:00
|
|
|
if (ssh_params->username) {
|
|
|
|
if (ssh_options_set(sshs, SSH_OPTIONS_USER, ssh_params->username)) {
|
|
|
|
*err_info = g_strdup_printf("Can't set the username: %s", ssh_params->username);
|
2018-11-09 16:41:36 +00:00
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-09 22:10:46 +00:00
|
|
|
ssh_options_get(sshs, SSH_OPTIONS_USER, &username);
|
|
|
|
ssh_options_get_port(sshs, &port);
|
2018-11-09 16:41:36 +00:00
|
|
|
|
2018-11-09 22:10:46 +00:00
|
|
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Opening ssh connection to %s@%s:%u", username,
|
|
|
|
ssh_params->host, port);
|
2018-11-09 16:41:36 +00:00
|
|
|
|
2018-11-09 22:10:46 +00:00
|
|
|
ssh_string_free_char(username);
|
2016-03-01 13:13:41 +00:00
|
|
|
|
|
|
|
/* Connect to server */
|
|
|
|
if (ssh_connect(sshs) != SSH_OK) {
|
2018-11-09 16:41:36 +00:00
|
|
|
*err_info = g_strdup_printf("Connection error: %s", ssh_get_error(sshs));
|
2016-03-01 13:13:41 +00:00
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_LIBSSH_USERAUTH_AGENT
|
2017-10-14 20:04:14 +00:00
|
|
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Connecting using ssh-agent...");
|
2016-03-01 13:13:41 +00:00
|
|
|
/* Try to authenticate using ssh agent */
|
|
|
|
if (ssh_userauth_agent(sshs, NULL) == SSH_AUTH_SUCCESS) {
|
|
|
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "done");
|
|
|
|
return sshs;
|
|
|
|
}
|
2017-10-14 20:04:14 +00:00
|
|
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "failed");
|
2016-03-01 13:13:41 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* If a public key path has been provided, try to authenticate using it */
|
2018-11-09 22:10:46 +00:00
|
|
|
if (ssh_params->sshkey_path) {
|
2016-03-01 13:13:41 +00:00
|
|
|
ssh_key pkey = ssh_key_new();
|
|
|
|
int ret;
|
|
|
|
|
2018-11-09 22:10:46 +00:00
|
|
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Connecting using public key in %s...", ssh_params->sshkey_path);
|
|
|
|
ret = ssh_pki_import_privkey_file(ssh_params->sshkey_path, ssh_params->sshkey_passphrase, NULL, NULL, &pkey);
|
2016-03-01 13:13:41 +00:00
|
|
|
|
|
|
|
if (ret == SSH_OK) {
|
|
|
|
if (ssh_userauth_publickey(sshs, NULL, pkey) == SSH_AUTH_SUCCESS) {
|
|
|
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "done");
|
|
|
|
ssh_key_free(pkey);
|
|
|
|
return sshs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ssh_key_free(pkey);
|
|
|
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "failed (%s)", ssh_get_error(sshs));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Try to authenticate using standard public key */
|
|
|
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Connecting using standard public key...");
|
|
|
|
if (ssh_userauth_publickey_auto(sshs, NULL, NULL) == SSH_AUTH_SUCCESS) {
|
|
|
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "done");
|
|
|
|
return sshs;
|
|
|
|
}
|
|
|
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "failed");
|
|
|
|
|
|
|
|
/* If a password has been provided and all previous attempts failed, try to use it */
|
2018-11-09 22:10:46 +00:00
|
|
|
if (ssh_params->password) {
|
2016-03-01 13:13:41 +00:00
|
|
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Connecting using password...");
|
2018-11-09 22:10:46 +00:00
|
|
|
if (ssh_userauth_password(sshs, ssh_params->username, ssh_params->password) == SSH_AUTH_SUCCESS) {
|
2016-03-01 13:13:41 +00:00
|
|
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "done");
|
|
|
|
return sshs;
|
|
|
|
}
|
|
|
|
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
*err_info = g_strdup_printf("Can't find a valid authentication. Disconnecting.");
|
|
|
|
|
|
|
|
/* All authentication failed. Disconnect and return */
|
|
|
|
ssh_disconnect(sshs);
|
|
|
|
|
|
|
|
failure:
|
|
|
|
ssh_free(sshs);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-03-04 09:53:56 +00:00
|
|
|
int ssh_channel_printf(ssh_channel channel, const char* fmt, ...)
|
|
|
|
{
|
|
|
|
gchar* buf;
|
|
|
|
va_list arg;
|
|
|
|
int ret = EXIT_SUCCESS;
|
|
|
|
|
|
|
|
va_start(arg, fmt);
|
|
|
|
buf = g_strdup_vprintf(fmt, arg);
|
|
|
|
if (ssh_channel_write(channel, buf, (guint32)strlen(buf)) == SSH_ERROR)
|
|
|
|
ret = EXIT_FAILURE;
|
|
|
|
va_end(arg);
|
|
|
|
g_free(buf);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-03-01 13:13:41 +00:00
|
|
|
void ssh_cleanup(ssh_session* sshs, ssh_channel* channel)
|
|
|
|
{
|
|
|
|
if (*channel) {
|
|
|
|
ssh_channel_send_eof(*channel);
|
|
|
|
ssh_channel_close(*channel);
|
|
|
|
ssh_channel_free(*channel);
|
|
|
|
*channel = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*sshs) {
|
|
|
|
ssh_disconnect(*sshs);
|
|
|
|
ssh_free(*sshs);
|
|
|
|
*sshs = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-09 22:10:46 +00:00
|
|
|
ssh_params_t* ssh_params_new(void)
|
|
|
|
{
|
|
|
|
return g_new0(ssh_params_t, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ssh_params_free(ssh_params_t* ssh_params)
|
|
|
|
{
|
|
|
|
if (!ssh_params)
|
|
|
|
return;
|
|
|
|
g_free(ssh_params->host);
|
|
|
|
g_free(ssh_params->username);
|
|
|
|
g_free(ssh_params->password);
|
|
|
|
g_free(ssh_params->sshkey_path);
|
|
|
|
g_free(ssh_params->sshkey_passphrase);
|
|
|
|
g_free(ssh_params->proxycommand);
|
|
|
|
g_free(ssh_params);
|
|
|
|
}
|
|
|
|
|
2016-03-01 13:13:41 +00:00
|
|
|
/*
|
|
|
|
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
|
|
|
*
|
|
|
|
* Local variables:
|
|
|
|
* c-basic-offset: 8
|
|
|
|
* tab-width: 8
|
|
|
|
* indent-tabs-mode: t
|
|
|
|
* End:
|
|
|
|
*
|
|
|
|
* vi: set shiftwidth=8 tabstop=8 noexpandtab:
|
|
|
|
* :indentSize=8:tabSize=8:noTabs=false:
|
2016-05-03 05:28:42 +00:00
|
|
|
*/
|