From c258810b81a9ef4d93530f5c26a5512954a86220 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Fri, 19 Nov 2021 21:23:28 +0100 Subject: added option --ignore-authentication-errors to ignore authentication errors added option --allow-password-authentication to explicitely allow authentication with password added some similar projects to README --- README | 16 ++++++++++ TODOS | 2 ++ src/cssh.c | 85 ++++++++++++++++++++++++++++++++---------------------- src/options.ggo.in | 8 +++++ 4 files changed, 77 insertions(+), 34 deletions(-) diff --git a/README b/README index fe66791..7c28af9 100644 --- a/README +++ b/README @@ -33,6 +33,22 @@ GNU parallel Way complex, good for batches. I think cssh should not try to compete with it. GNU parallel is written in Perl. +Dsh +--- + +http://www.netfort.gr.jp/~dancer/software/dsh.html + +Distributed or Dancer's shell, written in C. dssh with -M -c -r ssh is +basically the same what we are doing. dssh has no interactive mode. + +Clusterit +--------- + +http://www.sourceforge.net/projects/clusterit + +Also written in C. Set of tools for simple cluster-excution, focus +on compilation and shell. + Why libssh and not libssh2 -------------------------- diff --git a/TODOS b/TODOS index 5bec231..05c40c7 100644 --- a/TODOS +++ b/TODOS @@ -12,6 +12,8 @@ - clusters: named set of hosts - tags: for things line cssh -t centos -c yum update or so - meta commands like enable/disable some hosts/tags +- make password authentication optional +- make ignore-errors and auth-methods enums in gengetopt diff --git a/src/cssh.c b/src/cssh.c index 6b68362..3fe7218 100644 --- a/src/cssh.c +++ b/src/cssh.c @@ -352,7 +352,7 @@ static int authenticate_pubkey( ssh_session session ) } static int authenticate_password( ssh_session session, const char *host, const unsigned short port, const char *user ) -{ +{ char prompt[128]; char pass[128]; @@ -369,13 +369,16 @@ static int authenticate_password( ssh_session session, const char *host, const u } } - snprintf( prompt, sizeof( prompt ), "%s@%s:%d's password:", - prompt_user, host, port ); + if( strchr( host, '@' ) == NULL ) { + snprintf( prompt, sizeof( prompt ), "%s@%s:%d's password:", + prompt_user, host, port ); + } else { + snprintf( prompt, sizeof( prompt ), "%s:%d's password:", + host, port ); + } memset( pass, 0, sizeof( pass ) ); if( ssh_getpass( prompt, pass, sizeof( pass ), 0, 0 ) < 0 ) { - fprintf( stderr, "ERROR: ssh_getpass failed\n" ); - ssh_disconnect( session ); - ssh_free( session ); + fprintf( stderr, "\nERROR: ssh_getpass failed\n" ); return -1; } @@ -398,8 +401,6 @@ static int authenticate_password( ssh_session session, const char *host, const u case SSH_AUTH_ERROR: fprintf( stderr, "ERROR: Failed to authenticate with password: %s\n", ssh_get_error( session ) ); - ssh_disconnect( session ); - ssh_free( session ); return SSH_AUTH_ERROR; } @@ -793,7 +794,7 @@ int main( int argc, char *argv[] ) } for( unsigned int i = 0; i < nof_sessions; i++ ) { session[i] = ssh_new( ); - if( session == NULL ) { + if( session[i] == NULL ) { exit( EXIT_FAILURE ); } } @@ -821,13 +822,12 @@ int main( int argc, char *argv[] ) // asynchonous connection phase - connection_state_e *connection_state = (connection_state_e *)malloc( nof_sessions * sizeof( connection_state_e ) ); + connection_state_e *connection_state = (connection_state_e *)calloc( nof_sessions, sizeof( connection_state_e ) ); if( connection_state == NULL ) { fprintf( stderr, "ERROR: Memory allocation failed for 'connection_state'\n" ); cleanup_sessions( &session, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_SUCCESS ); } - memset( connection_state, CSSH_CONNECTION_STATE_UNCONNECTED, nof_sessions * sizeof( connection_state_e ) ); unsigned int nof_connected = 0; while( nof_connected < nof_sessions ) { nof_connected = 0; @@ -867,13 +867,12 @@ int main( int argc, char *argv[] ) // authentication phase - auth_state_e *auth_state = (auth_state_e *)malloc( ( nof_sessions + 1 ) * sizeof( auth_state_e ) ); + auth_state_e *auth_state = (auth_state_e *)calloc( nof_sessions, sizeof( auth_state_e ) ); if( auth_state == NULL ) { fprintf( stderr, "ERROR: Memory allocation failed for 'auth_state'\n" ); cleanup_sessions( &session, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } - memset( auth_state, CSSH_AUTH_INIT, ( nof_sessions + 1 ) * sizeof( auth_state_e ) ); unsigned int nof_authenticated = 0; while( nof_authenticated < nof_connected ) { for( unsigned int i = 0; i < nof_sessions; i++ ) { @@ -941,18 +940,22 @@ int main( int argc, char *argv[] ) break; case CSSH_AUTH_PUBKEY_DONE_FAILED: - rc = authenticate_password( session[i], host[i], port[i], args_info.login_given ? args_info.login_arg : NULL ); - - if( rc == SSH_AUTH_SUCCESS ) { - auth_state[i] = CSSH_AUTH_PASSWORD_DONE_SUCCESS; - } else if( rc == SSH_AUTH_AGAIN ) { - // ok, wait next iteration - } else if( rc == SSH_AUTH_DENIED ) { - auth_state[i] = CSSH_AUTH_PASSWORD_DONE_FAILED; + if( args_info.allow_password_authentication_given ) { + rc = authenticate_password( session[i], host[i], port[i], args_info.login_given ? args_info.login_arg : NULL ); + if( rc == SSH_AUTH_SUCCESS ) { + auth_state[i] = CSSH_AUTH_PASSWORD_DONE_SUCCESS; + } else if( rc == SSH_AUTH_AGAIN ) { + // ok, wait next iteration + } else if( rc == SSH_AUTH_DENIED ) { + auth_state[i] = CSSH_AUTH_PASSWORD_DONE_FAILED; + } else { + cleanup_sessions( &session, NULL, NULL, host, &port, nof_sessions, args_info.verbose_given > 0 ); + ssh_finalize( ); + exit( EXIT_FAILURE ); + } } else { - cleanup_sessions( &session, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); - exit( EXIT_FAILURE ); - } + auth_state[i] = CSSH_AUTH_DONE_FAILED; + } break; case CSSH_AUTH_PASSWORD_DONE_SUCCESS: @@ -971,8 +974,13 @@ int main( int argc, char *argv[] ) case CSSH_AUTH_DONE_FAILED: // one authentication failed, bail out for now fprintf( stderr, "ERROR: authentication failed for one host ('%s'), aborting now\n", host[i] ); - cleanup_sessions( &session, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); - exit( EXIT_FAILURE ); + if( args_info.ignore_authentication_errors_given ) { + connection_state[i] = CSSH_CONNECTION_STATE_ERROR; + } else { + cleanup_sessions( &session, NULL, NULL, host, &port, nof_sessions, args_info.verbose_given > 0 ); + ssh_finalize( ); + exit( EXIT_FAILURE ); + } } } @@ -986,12 +994,22 @@ int main( int argc, char *argv[] ) if( i != j ) { connection_state[j] = connection_state[i]; auth_state[j] = auth_state[i]; + session[j] = session[i]; + host[j] = host[i]; + port[j] = port[i]; } j++; + } else { + fprintf( stderr, "ERROR: host '%s' has errors, ignoring it\n", host[i] ); } } - nof_sessions = j; - + if( j != nof_sessions ) { + nof_sessions = j; + connection_state = (connection_state_e *)realloc( connection_state, nof_sessions * sizeof( connection_state_e ) ); + auth_state = (auth_state_e *)realloc( auth_state, nof_sessions * sizeof( auth_state_e ) ); + session = (ssh_session *)realloc( session, nof_sessions * sizeof( ssh_session ) ); + } + // in CLI mode get next command from linenoise CLI_NEXT_CMD: @@ -1026,19 +1044,18 @@ CLI_NEXT_CMD: // explicit low-level handling of channels in SSH mode - ssh_data_t *ssh_data = (ssh_data_t *)malloc( ( nof_sessions + 1 ) * sizeof( ssh_data_t ) ); + ssh_data_t *ssh_data = (ssh_data_t *)calloc( nof_sessions, sizeof( ssh_data_t ) ); if( ssh_data == NULL ) { fprintf( stderr, "ERROR: Memory allocation failed for ssh_data array\n" ); cleanup_sessions( &session, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } - memset( ssh_data, 0, ( nof_sessions + 1 ) * sizeof( ssh_data_t ) ); for( unsigned int i = 0; i < nof_sessions; i++ ) { ssh_data[i].channel = ssh_channel_new( session[i] ); if( ssh_data[i].channel == NULL ) { - fprintf( stderr, "ERROR: Unable to open SSH channel: %s\n", - ssh_get_error( session[i] ) ); + fprintf( stderr, "ERROR: Unable to open SSH channel for host '%s': %s\n", + host[i], ssh_get_error( session[i] ) ); cleanup_sessions( &session, &ssh_data, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } @@ -1192,13 +1209,12 @@ SHELL_EOF: case CSSH_EXECUTE_AS_SCP: { - scp_data_t *scp_data = (scp_data_t *)malloc( ( nof_sessions + 1 ) * sizeof( scp_data_t ) ); + scp_data_t *scp_data = (scp_data_t *)calloc( nof_sessions, sizeof( scp_data_t ) ); if( scp_data == NULL ) { fprintf( stderr, "ERROR: Memory allocation failed for scp_data array\n" ); cleanup_sessions( &session, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } - memset( scp_data, 0, ( nof_sessions + 1 ) * sizeof( scp_data_t ) ); for( unsigned int i = 0; i < nof_sessions; i++ ) { scp_data[i].read_state = CSSH_SCP_READ_STATE_IDLE; } @@ -1533,6 +1549,7 @@ SHELL_EOF: // the end free( connection_state ); + free( auth_state ); cmdline_parser_free( &args_info ); diff --git a/src/options.ggo.in b/src/options.ggo.in index 46eb635..71e4364 100644 --- a/src/options.ggo.in +++ b/src/options.ggo.in @@ -52,3 +52,11 @@ section "Additional options" "Ignore host if we cannot connect to it at startup" optional + option "ignore-authentication-errors" - + "Ignore host if we cannot authenticate to it at startup" + optional + + option "allow-password-authentication" - + "Allow password identification if identification with keys fails" + optional + -- cgit v1.2.3-54-g00ecf