summaryrefslogtreecommitdiffstats
path: root/source/dialogs/ssh.c
diff options
context:
space:
mode:
authorDave Davenport <qball@gmpclient.org>2019-02-10 13:55:09 +0100
committerDave Davenport <qball@gmpclient.org>2019-02-10 13:56:44 +0100
commitf87906241708adbbb0239b7815e2850727469f7c (patch)
tree2983ae068d80daf16039caf359b4fb329e1f106f /source/dialogs/ssh.c
parent9af5cac65b6c2c7cbb4a08a8796b36281f1e15cf (diff)
[SSH] Add support for parsing port number from known hosts file.
* Store port number in history. * Parse the [host]:port format. * Update default ssh command to (optionally) add -p {port}. Fixes: #580
Diffstat (limited to 'source/dialogs/ssh.c')
-rw-r--r--source/dialogs/ssh.c125
1 files changed, 85 insertions, 40 deletions
diff --git a/source/dialogs/ssh.c b/source/dialogs/ssh.c
index 486cced1..c719f393 100644
--- a/source/dialogs/ssh.c
+++ b/source/dialogs/ssh.c
@@ -67,6 +67,12 @@
*/
#define SSH_TOKEN_DELIM "= \t\r\n"
+
+typedef struct _SshEntry {
+ char *hostname;
+ int port;
+} SshEntry;
+
/**
* @param host The host to connect too
*
@@ -74,24 +80,31 @@
*
* @returns FALSE On failure, TRUE on success
*/
-static int execshssh ( const char *host )
+static int execshssh ( const SshEntry *entry)
{
char **args = NULL;
int argsv = 0;
+ gchar *portstr = NULL;
+ if ( entry->port > 0 ) {
+ portstr = g_strdup_printf("%d", entry->port);
+ }
+ helper_parse_setup ( config.ssh_command, &args, &argsv,
+ "{host}", entry->hostname,
+ "{port}", portstr,
+ (char *) 0 );
+ g_free ( portstr );
- helper_parse_setup ( config.ssh_command, &args, &argsv, "{host}", host, (char *) 0 );
-
- gsize l = strlen ( "Connecting to '' via rofi" ) + strlen ( host ) + 1;
+ gsize l = strlen ( "Connecting to '' via rofi" ) + strlen ( entry->hostname ) + 1;
gchar *desc = g_newa ( gchar, l );
- g_snprintf ( desc, l, "Connecting to '%s' via rofi", host );
+ g_snprintf ( desc, l, "Connecting to '%s' via rofi", entry->hostname );
RofiHelperExecuteContext context = {
.name = "ssh",
.description = desc,
.command = "ssh",
};
- return helper_execute ( NULL, args, "ssh ", host, &context );
+ return helper_execute ( NULL, args, "ssh ", entry->hostname, &context );
}
/**
@@ -99,20 +112,27 @@ static int execshssh ( const char *host )
*
* SSH into the selected host, if successful update history.
*/
-static void exec_ssh ( const char *host )
+static void exec_ssh ( const SshEntry *entry )
{
- if ( !host || !host[0] ) {
+ if ( !(entry->hostname )|| !(entry->hostname[0]) ) {
return;
}
- if ( !execshssh ( host ) ) {
+ if ( !execshssh ( entry ) ) {
return;
}
// This happens in non-critical time (After launching app)
// It is allowed to be a bit slower.
char *path = g_build_filename ( cache_dir, SSH_CACHE_FILE, NULL );
- history_set ( path, host );
+ // TODO update.
+ if ( entry->port > 0 ) {
+ char *store = g_strdup_printf("%s:%d", entry->hostname, entry->port );
+ history_set ( path, store );
+ g_free ( store );
+ } else {
+ history_set ( path, entry->hostname );
+ }
g_free ( path );
}
@@ -139,7 +159,7 @@ static void delete_ssh ( const char *host )
*
* @returns updated list of hosts.
*/
-static char **read_known_hosts_file ( char ** retv, unsigned int *length )
+static SshEntry *read_known_hosts_file ( SshEntry * retv, unsigned int *length )
{
char *path = g_build_filename ( g_get_home_dir (), ".ssh", "known_hosts", NULL );
FILE *fd = fopen ( path, "r" );
@@ -160,10 +180,6 @@ static char **read_known_hosts_file ( char ** retv, unsigned int *length )
// Skip hashed hostnames.
continue;
}
- if ( *start == '[' ) {
- // Don't support port versions yet, TODO
- continue;
- }
// Find end of hostname set.
char *end = strstr ( start, " " );
if ( end == NULL ) {
@@ -175,11 +191,20 @@ static char **read_known_hosts_file ( char ** retv, unsigned int *length )
start = strsep(&sep,", " );
while ( start )
{
+ int port = 0;
+ if ( start[0] == '[' ) {
+ start++;
+ char *end = strchr ( start, ']');
+ if ( end[1] == ':' ){
+ *end = '\0';
+ port = atoi ( &(end[2]) );
+ }
+ }
// Is this host name already in the list?
// We often get duplicates in hosts file, so lets check this.
int found = 0;
for ( unsigned int j = 0; j < ( *length ); j++ ) {
- if ( !g_ascii_strcasecmp ( start, retv[j] ) ) {
+ if ( !g_ascii_strcasecmp ( start, retv[j].hostname ) ) {
found = 1;
break;
}
@@ -187,9 +212,11 @@ static char **read_known_hosts_file ( char ** retv, unsigned int *length )
if ( !found ) {
// Add this host name to the list.
- retv = g_realloc ( retv, ( ( *length ) + 2 ) * sizeof ( char* ) );
- retv[( *length )] = g_strdup ( start );
- retv[( *length ) + 1] = NULL;
+ retv = g_realloc ( retv, ( ( *length ) + 2 ) * sizeof ( SshEntry ) );
+ retv[( *length )].hostname = g_strdup ( start );
+ retv[( *length )].port = port;
+ retv[( *length ) + 1].hostname = NULL;
+ retv[( *length ) + 1].port = 0;
( *length )++;
}
start = strsep(&sep,", " );
@@ -215,7 +242,7 @@ static char **read_known_hosts_file ( char ** retv, unsigned int *length )
*
* @returns an updated list with the added hosts.
*/
-static char **read_hosts_file ( char ** retv, unsigned int *length )
+static SshEntry *read_hosts_file ( SshEntry * retv, unsigned int *length )
{
// Read the hosts file.
FILE *fd = fopen ( "/etc/hosts", "r" );
@@ -243,7 +270,7 @@ static char **read_hosts_file ( char ** retv, unsigned int *length )
// We often get duplicates in hosts file, so lets check this.
int found = 0;
for ( unsigned int j = 0; j < ( *length ); j++ ) {
- if ( !g_ascii_strcasecmp ( token, retv[j] ) ) {
+ if ( !g_ascii_strcasecmp ( token, retv[j].hostname ) ) {
found = 1;
break;
}
@@ -253,8 +280,8 @@ static char **read_hosts_file ( char ** retv, unsigned int *length )
// Add this host name to the list.
retv = g_realloc ( retv,
( ( *length ) + 2 ) * sizeof ( char* ) );
- retv[( *length )] = g_strdup ( token );
- retv[( *length ) + 1] = NULL;
+ retv[( *length )].hostname = g_strdup ( token );
+ retv[( *length ) + 1].hostname = NULL;
( *length )++;
}
}
@@ -281,7 +308,7 @@ static char **read_hosts_file ( char ** retv, unsigned int *length )
return retv;
}
-static void parse_ssh_config_file ( const char *filename, char ***retv, unsigned int *length, unsigned int num_favorites )
+static void parse_ssh_config_file ( const char *filename, SshEntry **retv, unsigned int *length, unsigned int num_favorites )
{
FILE *fd = fopen ( filename, "r" );
@@ -352,7 +379,7 @@ static void parse_ssh_config_file ( const char *filename, char ***retv, unsigned
// given num_favorites is max 25.
int found = 0;
for ( unsigned int j = 0; j < num_favorites; j++ ) {
- if ( !g_ascii_strcasecmp ( token, ( *retv )[j] ) ) {
+ if ( !g_ascii_strcasecmp ( token, ( *retv )[j].hostname ) ) {
found = 1;
break;
}
@@ -363,9 +390,9 @@ static void parse_ssh_config_file ( const char *filename, char ***retv, unsigned
}
// Add this host name to the list.
- ( *retv ) = g_realloc ( ( *retv ), ( ( *length ) + 2 ) * sizeof ( char* ) );
- ( *retv )[( *length )] = g_strdup ( token );
- ( *retv )[( *length ) + 1] = NULL;
+ ( *retv ) = g_realloc ( ( *retv ), ( ( *length ) + 2 ) * sizeof ( SshEntry ) );
+ ( *retv )[( *length )].hostname = g_strdup ( token );
+ ( *retv )[( *length ) + 1].hostname = NULL;
( *length )++;
}
}
@@ -387,9 +414,9 @@ static void parse_ssh_config_file ( const char *filename, char ***retv, unsigned
*
* @return an array of strings containing all the hosts.
*/
-static char ** get_ssh ( unsigned int *length )
+static SshEntry * get_ssh ( unsigned int *length )
{
- char **retv = NULL;
+ SshEntry *retv = NULL;
unsigned int num_favorites = 0;
char *path;
@@ -398,7 +425,21 @@ static char ** get_ssh ( unsigned int *length )
}
path = g_build_filename ( cache_dir, SSH_CACHE_FILE, NULL );
- retv = history_get_list ( path, length );
+ char **h = history_get_list ( path, length );
+
+ retv = malloc ( (*length)*sizeof(SshEntry));
+ for ( unsigned int i = 0; i < (*length); i++ ){
+ int port = 0;
+ char *portstr = strchr ( h[i], ':' );
+ if ( portstr != NULL ) {
+ *portstr = '\0';
+ port = atoi ( &(portstr[1]) );
+ }
+ retv[i].hostname = h[i];
+ retv[i].port = port;
+ }
+ g_free (h);
+
g_free ( path );
num_favorites = ( *length );
@@ -424,7 +465,7 @@ static char ** get_ssh ( unsigned int *length )
typedef struct
{
/** List if available ssh hosts.*/
- char **hosts_list;
+ SshEntry *hosts_list;
/** Length of the #hosts_list.*/
unsigned int hosts_list_length;
} SSHModePrivateData;
@@ -466,7 +507,10 @@ static void ssh_mode_destroy ( Mode *sw )
{
SSHModePrivateData *rmpd = (SSHModePrivateData *) mode_get_private_data ( sw );
if ( rmpd != NULL ) {
- g_strfreev ( rmpd->hosts_list );
+ for ( unsigned int i = 0; i < rmpd->hosts_list_length; i++ ){
+ g_free( rmpd->hosts_list[i].hostname );
+ }
+ g_free ( rmpd->hosts_list );
g_free ( rmpd );
mode_set_private_data ( sw, NULL );
}
@@ -495,14 +539,15 @@ static ModeMode ssh_mode_result ( Mode *sw, int mretv, char **input, unsigned in
else if ( mretv & MENU_QUICK_SWITCH ) {
retv = ( mretv & MENU_LOWER_MASK );
}
- else if ( ( mretv & MENU_OK ) && rmpd->hosts_list[selected_line] != NULL ) {
- exec_ssh ( rmpd->hosts_list[selected_line] );
+ else if ( ( mretv & MENU_OK ) && rmpd->hosts_list[selected_line].hostname != NULL ) {
+ exec_ssh ( &(rmpd->hosts_list[selected_line]) );
}
else if ( ( mretv & MENU_CUSTOM_INPUT ) && *input != NULL && *input[0] != '\0' ) {
- exec_ssh ( *input );
+ SshEntry entry = { .hostname = *input, .port = 0 };
+ exec_ssh ( &entry );
}
- else if ( ( mretv & MENU_ENTRY_DELETE ) && rmpd->hosts_list[selected_line] ) {
- delete_ssh ( rmpd->hosts_list[selected_line] );
+ else if ( ( mretv & MENU_ENTRY_DELETE ) && rmpd->hosts_list[selected_line].hostname ) {
+ delete_ssh ( rmpd->hosts_list[selected_line].hostname );
// Stay
retv = RELOAD_DIALOG;
ssh_mode_destroy ( sw );
@@ -526,7 +571,7 @@ static ModeMode ssh_mode_result ( Mode *sw, int mretv, char **input, unsigned in
static char *_get_display_value ( const Mode *sw, unsigned int selected_line, G_GNUC_UNUSED int *state, G_GNUC_UNUSED GList **attr_list, int get_entry )
{
SSHModePrivateData *rmpd = (SSHModePrivateData *) mode_get_private_data ( sw );
- return get_entry ? g_strdup ( rmpd->hosts_list[selected_line] ) : NULL;
+ return get_entry ? g_strdup ( rmpd->hosts_list[selected_line].hostname ) : NULL;
}
/**
@@ -541,7 +586,7 @@ static char *_get_display_value ( const Mode *sw, unsigned int selected_line, G_
static int ssh_token_match ( const Mode *sw, rofi_int_matcher **tokens, unsigned int index )
{
SSHModePrivateData *rmpd = (SSHModePrivateData *) mode_get_private_data ( sw );
- return helper_token_match ( tokens, rmpd->hosts_list[index] );
+ return helper_token_match ( tokens, rmpd->hosts_list[index].hostname );
}
#include "mode-private.h"
Mode ssh_mode =