36 #define G_LOG_DOMAIN "Dialogs.Ssh"
45 #include <sys/types.h>
79 #define SSH_CACHE_FILE "rofi-2.sshcache"
85 #define SSH_TOKEN_DELIM "= \t\r\n"
99 gchar *portstr = NULL;
100 if ( entry->
port > 0 ) {
101 portstr = g_strdup_printf(
"%d", entry->
port);
109 gsize l = strlen (
"Connecting to '' via rofi" ) + strlen ( entry->
hostname ) + 1;
110 gchar *desc = g_newa ( gchar, l );
112 g_snprintf ( desc, l,
"Connecting to '%s' via rofi", entry->
hostname );
141 if ( entry->
port > 0 ) {
142 char *store = g_strdup_printf(
"%s\x1F%d", entry->
hostname, entry->
port );
158 if ( !host || !host[0] ) {
176 FILE *fd = fopen ( path,
"r" );
179 size_t buffer_length = 0;
181 while ( getline ( &buffer, &buffer_length, fd ) > 0 ) {
183 char *start = g_strstrip(&(buffer[0]));
185 if ( *start ==
'#' || *start ==
'@' ){
189 if ( *start ==
'|' ) {
194 char *end = strstr ( start,
" " );
201 start = strsep(&sep,
", " );
205 if ( start[0] ==
'[' ) {
207 char *end = strchr ( start,
']');
208 if ( end[1] ==
':' ){
211 gchar *endptr = NULL;
212 gint64 number = g_ascii_strtoll ( &(end[2]), &endptr, 10);
214 g_warning (
"Failed to parse port number: %s.", &(end[2]) );
215 }
else if ( endptr == &(end[2])) {
216 g_warning (
"Failed to parse port number: %s, invalid number.", &(end[2]) );
217 }
else if ( number < 0 || number > 65535 ) {
218 g_warning (
"Failed to parse port number: %s, out of range.", &(end[2]) );
227 for (
unsigned int j = 0; j < ( *length ); j++ ) {
228 if ( !g_ascii_strcasecmp ( start, retv[j].hostname ) ) {
236 retv = g_realloc ( retv, ( ( *length ) + 2 ) *
sizeof (
SshEntry ) );
237 retv[( *length )].
hostname = g_strdup ( start );
238 retv[( *length )].
port = port;
239 retv[( *length ) + 1].
hostname = NULL;
240 retv[( *length ) + 1].
port = 0;
243 start = strsep(&sep,
", " );
246 if ( buffer != NULL ) {
249 if ( fclose ( fd ) != 0 ) {
250 g_warning (
"Failed to close hosts file: '%s'", g_strerror ( errno ) );
253 g_debug (
"Failed to open KnownHostFile: '%s'", path );
270 FILE *fd = fopen (
"/etc/hosts",
"r" );
273 size_t buffer_length = 0;
275 while ( getline ( &buffer, &buffer_length, fd ) > 0 ) {
277 unsigned int index = 0, ti = 0;
278 char *token = buffer;
282 char c = buffer[index];
284 if ( c ==
' ' || c ==
'\t' || c ==
'\n' || c ==
'\0' || c ==
'#' ) {
285 buffer[index] =
'\0';
287 if ( token[0] !=
'\0' ) {
294 for (
unsigned int j = 0; j < ( *length ); j++ ) {
295 if ( !g_ascii_strcasecmp ( token, retv[j].hostname ) ) {
303 retv = g_realloc ( retv,
304 ( ( *length ) + 2 ) *
sizeof (
SshEntry ) );
305 retv[( *length )].
hostname = g_strdup ( token );
306 retv[( *length )].
port = 0;
307 retv[( *length ) + 1].
hostname = NULL;
313 token = &buffer[index + 1];
321 }
while ( buffer[index] !=
'\0' && buffer[index] !=
'#' );
323 if ( buffer != NULL ) {
326 if ( fclose ( fd ) != 0 ) {
327 g_warning (
"Failed to close hosts file: '%s'", g_strerror ( errno ) );
336 GList *item = g_list_find_custom ( pd->
user_known_hosts, token, (GCompareFunc)g_strcmp0 );
337 if ( item == NULL ) {
338 g_debug(
"Add '%s' to UserKnownHost list", token);
341 g_debug(
"File '%s' already in UserKnownHostsFile list", token);
347 FILE *fd = fopen ( filename,
"r" );
349 g_debug (
"Parsing ssh config file: %s", filename );
352 size_t buffer_length = 0;
353 char *strtok_pointer = NULL;
354 while ( getline ( &buffer, &buffer_length, fd ) > 0 ) {
363 if ( !token || *token ==
'#' ) {
366 char *low_token = g_ascii_strdown(token, -1);
367 if ( g_strcmp0 ( low_token,
"include" ) == 0 ) {
369 g_debug (
"Found Include: %s", token );
371 gchar *full_path = NULL;
372 if ( !g_path_is_absolute ( path ) ) {
373 char *dirname = g_path_get_dirname ( filename );
374 full_path = g_build_filename ( dirname, path, NULL );
378 full_path = g_strdup ( path );
380 glob_t globbuf = { .gl_pathc = 0, .gl_pathv = NULL, .gl_offs = 0 };
382 if ( glob ( full_path, 0, NULL, &globbuf ) == 0 ) {
383 for (
size_t iter = 0; iter < globbuf.gl_pathc; iter++ ) {
387 globfree ( &globbuf );
389 g_free ( full_path );
392 else if ( g_strcmp0 ( low_token,
"userknownhostsfile" ) == 0 ) {
393 while ( ( token = strtok_r ( NULL,
SSH_TOKEN_DELIM, &strtok_pointer ) ) ) {
394 g_debug(
"Found extra UserKnownHostsFile: %s", token);
398 else if ( g_strcmp0 ( low_token,
"host" ) == 0 ) {
404 while ( ( token = strtok_r ( NULL,
SSH_TOKEN_DELIM, &strtok_pointer ) ) ) {
406 const char *
const sep =
"*?";
407 if ( *token ==
'!' || strpbrk ( token, sep ) ) {
412 if ( *token ==
'#' ) {
420 for (
unsigned int j = 0; j < num_favorites; j++ ) {
421 if ( !g_ascii_strcasecmp ( token, ( *retv )[j].hostname ) ) {
432 ( *retv ) = g_realloc ( ( *retv ), ( ( *length ) + 2 ) *
sizeof (
SshEntry ) );
433 ( *retv )[( *length )].hostname = g_strdup ( token );
434 ( *retv )[( *length )].port = 0;
435 ( *retv )[( *length ) + 1].hostname = NULL;
439 g_free ( low_token );
441 if ( buffer != NULL ) {
445 if ( fclose ( fd ) != 0 ) {
446 g_warning (
"Failed to close ssh configuration file: '%s'", g_strerror ( errno ) );
461 unsigned int num_favorites = 0;
464 if ( g_get_home_dir () == NULL ) {
471 retv = malloc ( (*length)*
sizeof(
SshEntry));
472 for (
unsigned int i = 0; i < (*length); i++ ){
474 char *portstr = strchr ( h[i],
'\x1F' );
475 if ( portstr != NULL ) {
479 gint64 number = g_ascii_strtoll ( &(portstr[1]), &endptr, 10);
481 g_warning (
"Failed to parse port number: %s.", &(portstr[1]) );
482 }
else if ( endptr == &(portstr[1])) {
483 g_warning (
"Failed to parse port number: %s, invalid number.", &(portstr[1]) );
484 }
else if ( number < 0 || number > 65535 ) {
485 g_warning (
"Failed to parse port number: %s, out of range.", &(portstr[1]) );
496 num_favorites = ( *length );
498 const char *hd = g_get_home_dir ();
499 path = g_build_filename ( hd,
".ssh",
"config", NULL );
503 char *path = g_build_filename ( g_get_home_dir (),
".ssh",
"known_hosts", NULL );
506 for ( GList *iter = g_list_first ( pd->
user_known_hosts); iter; iter = g_list_next ( iter ) ) {
534 pd->hosts_list =
get_ssh ( pd, &( pd->hosts_list_length ) );
559 if ( rmpd != NULL ) {
596 else if ( ( mretv &
MENU_CUSTOM_INPUT ) && *input != NULL && *input[0] !=
'\0' ) {
622 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 )
646 .cfg_name_key =
"display-ssh",
653 ._get_completion = NULL,
654 ._preprocess_input = NULL,
655 .private_data = NULL,