From c2408c9d74a780d3f1c502b78f4c47b15959a1a9 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Sun, 16 Aug 2015 17:52:46 +0200 Subject: tried to make connect and authentication non-blocking --- README | 3 + src/cssh.c | 211 +++++++++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 174 insertions(+), 40 deletions(-) diff --git a/README b/README index 783691f..cbb66a7 100644 --- a/README +++ b/README @@ -24,6 +24,9 @@ be stdout/stderr. Pssh shows results at the very end, I want to be able to monitor progress of the commands being executed. +Pssh doesn't seem to do non-blocking connections and authentication +in parallel. + GNU parallel ------------ diff --git a/src/cssh.c b/src/cssh.c index c280e62..25244b0 100644 --- a/src/cssh.c +++ b/src/cssh.c @@ -157,6 +157,9 @@ static int authenticate_pubkey( ssh_session session ) case SSH_AUTH_PARTIAL: return SSH_AUTH_PARTIAL; + case SSH_AUTH_AGAIN: + return SSH_AUTH_AGAIN; + case SSH_AUTH_ERROR: fprintf( stderr, "ERROR: authentication with public key failed: %s\n", ssh_get_error( session ) ); @@ -207,6 +210,9 @@ static int authenticate_password( ssh_session session, const char *host, const u fprintf( stderr, "ERROR: Password authentication failed.\n" ); return SSH_AUTH_DENIED; + case SSH_AUTH_AGAIN: + return SSH_AUTH_AGAIN; + case SSH_AUTH_ERROR: fprintf( stderr, "ERROR: Failed to authenticate with password: %s\n", ssh_get_error( session ) ); @@ -363,61 +369,178 @@ int main( int argc, char *argv[] ) } for( unsigned int i = 0; i < nof_sessions; i++ ) { + ssh_set_blocking( session[i], 0 ); ssh_options_set( session[i], SSH_OPTIONS_HOST, host[i] ); ssh_options_set( session[i], SSH_OPTIONS_PORT, &port[i] ); ssh_options_set( session[i], SSH_OPTIONS_LOG_VERBOSITY, &verbosity ); } - + for( unsigned int i = 0; i < nof_sessions; i++ ) { if( args_info.verbose_given ) { fprintf( stderr, "Connecting to '%s', port %d..\n", host[i], port[i] ); } - rc = ssh_connect( session[i] ); - if( rc != SSH_OK ) { - fprintf( stderr, "ERROR: error connecting to '%s', port '%d': %s\n", - host[i], port[i], ssh_get_error( session[i] ) ); - cleanup_sessions( &session, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); - exit( EXIT_FAILURE ); - } - - if( verify_knownhost( session[i] ) < 0 ) { - fprintf( stderr, "ERROR: closing connection to '%s', port '%d' due to security reasons\n", - host[i], port[i] ); - cleanup_sessions( &session, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); - exit( EXIT_FAILURE ); - } - - rc = ssh_userauth_none( session[i], NULL ); - if( rc == SSH_AUTH_ERROR ) { - fprintf( stderr, "ERROR: ssh_userauth_none to '%s', port '%d' failed: %s\n", - host[i], port[i], ssh_get_error( session[i] ) ); - cleanup_sessions( &session, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); - exit( EXIT_FAILURE ); - } + } - char *banner = ssh_get_issue_banner( session[i] ); - if( banner ) { - puts( banner ); - free( banner ); + bool all_connected = false; + bool *is_connected = (bool *)malloc( ( nof_sessions + 1 ) * sizeof( bool ) ); + if( is_connected == NULL ) { + fprintf( stderr, "ERROR: Memory allocation failed for 'is_connected'" ); + return -1; + } + memset( is_connected, false, ( nof_sessions + 1 ) * sizeof( bool ) ); + while( !all_connected ) { + for( unsigned int i = 0; i < nof_sessions; i++ ) { + rc = ssh_connect( session[i] ); + if( rc == SSH_OK ) { + is_connected[i] = true; + //~ ssh_set_blocking( session[i], 1 ); + if( args_info.verbose_given ) { + fprintf( stderr, "Connected to '%s', port %d..\n", host[i], port[i] ); + } + } else if( rc == SSH_AGAIN ) { + // not connected yet + } else { + fprintf( stderr, "ERROR: error connecting to '%s', port '%d': %s\n", + host[i], port[i], ssh_get_error( session[i] ) ); + cleanup_sessions( &session, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } } - rc = authenticate_pubkey( session[i] ); - if( rc == SSH_AUTH_ERROR ) { - cleanup_sessions( &session, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); - exit( EXIT_FAILURE ); + all_connected = true; + for( unsigned int i = 0; i < nof_sessions; i++ ) { + if( !is_connected[i] ) { + all_connected = false; + } } + + cssh_msleep( 10 ); + } - if( rc != SSH_AUTH_SUCCESS ) { - rc = authenticate_password( session[i], host[i], port[i], args_info.login_given ? args_info.login_arg : NULL ); - if( rc < 0 ) { - cleanup_sessions( &session, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); - exit( EXIT_FAILURE ); + bool all_authenticated = false; + typedef enum auth_state_e { + CSSH_AUTH_INIT, + CSSH_AUTH_VERIFY_HOST_DONE, + CSSH_AUTH_NONE_DONE, + CSSH_AUTH_BANNER_DONE, + CSSH_AUTH_PUBKEY_DONE_SUCCESS, + CSSH_AUTH_PUBKEY_DONE_FAILED, + CSSH_AUTH_PASSWORD_DONE_SUCCESS, + CSSH_AUTH_PASSWORD_DONE_FAILED, + CSSH_AUTH_DONE_SUCCESS, + CSSH_AUTH_DONE_FAILED + } auth_state_e; + auth_state_e *auth_state = (auth_state_e *)malloc( ( nof_sessions + 1 ) * sizeof( auth_state_e ) ); + if( auth_state == NULL ) { + fprintf( stderr, "ERROR: Memory allocation failed for 'auth_state'" ); + return -1; + } + memset( auth_state, CSSH_AUTH_INIT, ( nof_sessions + 1 ) * sizeof( auth_state_e ) ); + while( !all_authenticated ) { + for( unsigned int i = 0; i < nof_sessions; i++ ) { + switch( auth_state[i] ) { + case CSSH_AUTH_INIT: + if( verify_knownhost( session[i] ) < 0 ) { + fprintf( stderr, "ERROR: closing connection to '%s', port '%d' due to security reasons\n", + host[i], port[i] ); + cleanup_sessions( &session, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + auth_state[i] = CSSH_AUTH_VERIFY_HOST_DONE; + break; + + case CSSH_AUTH_VERIFY_HOST_DONE: + // returns Failed to request "ssh-userauth" service, not handling SSH_AUTH_AGAIN correctly internally? + ssh_set_blocking( session[i], 1 ); + rc = ssh_userauth_none( session[i], NULL ); + if( rc == SSH_AUTH_SUCCESS ) { + auth_state[i] = CSSH_AUTH_NONE_DONE; + ssh_set_blocking( session[i], 1 ); + } else if( rc == SSH_AUTH_AGAIN ) { + // ok, wait next iteration + } else if( rc == SSH_AUTH_DENIED ) { + auth_state[i] = CSSH_AUTH_NONE_DONE; + //~ ssh_set_blocking( session[i], 0 ); + } else { + fprintf( stderr, "ERROR: ssh_userauth_none to '%s', port '%d' failed: %s\n", + host[i], port[i], ssh_get_error( session[i] ) ); + cleanup_sessions( &session, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + break; + + case CSSH_AUTH_NONE_DONE: { + ssh_set_blocking( session[i], 1 ); + char *banner = ssh_get_issue_banner( session[i] ); + if( banner ) { + puts( banner ); + free( banner ); + } + auth_state[i] = CSSH_AUTH_BANNER_DONE; + } break; + + case CSSH_AUTH_BANNER_DONE: + rc = authenticate_pubkey( session[i] ); + + if( rc == SSH_AUTH_SUCCESS ) { + auth_state[i] = CSSH_AUTH_PUBKEY_DONE_SUCCESS; + } else if( rc == SSH_AUTH_AGAIN ) { + // ok, wait next iteration + } else if( rc == SSH_AUTH_DENIED ) { + auth_state[i] = CSSH_AUTH_PUBKEY_DONE_FAILED; + } else { + cleanup_sessions( &session, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + break; + + case CSSH_AUTH_PUBKEY_DONE_SUCCESS: + auth_state[i] = CSSH_AUTH_DONE_SUCCESS; + 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; + } else { + cleanup_sessions( &session, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + break; + + case CSSH_AUTH_PASSWORD_DONE_SUCCESS: + auth_state[i] = CSSH_AUTH_DONE_SUCCESS; + break; + + case CSSH_AUTH_PASSWORD_DONE_FAILED: + auth_state[i] = CSSH_AUTH_DONE_FAILED; + break; + + case CSSH_AUTH_DONE_SUCCESS: + // ok + break; + + case CSSH_AUTH_DONE_FAILED: + // one authentication failed, bail out for now + fprintf( stderr, "ERROR: authentication failed for one host ('%s'), aborting now", host[i] ); + cleanup_sessions( &session, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); } } - if( args_info.verbose_given ) { - fprintf( stderr, "Connected to '%s', port %d..\n", host[i], port[i] ); + all_authenticated = true; + for( unsigned int i = 0; i < nof_sessions; i++ ) { + if( auth_state[i] != CSSH_AUTH_DONE_SUCCESS ) { + all_authenticated = false; + } } + + cssh_msleep( 10 ); } ssh_channel *channel = (ssh_channel *)malloc( ( nof_sessions + 1 ) * sizeof( ssh_channel ) ); @@ -425,7 +548,7 @@ int main( int argc, char *argv[] ) if( channel == NULL ) { fprintf( stderr, "ERROR: Memory allocation failed for ssh_channels" ); cleanup_sessions( &session, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); - return -1; + exit( EXIT_FAILURE ); } for( unsigned int i = 0; i < nof_sessions; i++ ) { channel[i] = ssh_channel_new( session[i] ); @@ -473,8 +596,16 @@ int main( int argc, char *argv[] ) bool all_eof = false; bool *eof_sent = (bool *)malloc( ( nof_sessions + 1 ) * sizeof( bool ) ); + if( eof_sent == NULL ) { + fprintf( stderr, "ERROR: Memory allocation failed for 'eof_sent'" ); + return -1; + } memset( eof_sent, false, ( nof_sessions + 1 ) * sizeof( bool ) ); bool *is_eof = (bool *)malloc( ( nof_sessions + 1 ) * sizeof( bool ) ); + if( is_eof == NULL ) { + fprintf( stderr, "ERROR: Memory allocation failed for 'is_eof'" ); + return -1; + } memset( is_eof, false, ( nof_sessions + 1 ) * sizeof( bool ) ); while( !all_eof ) { @@ -509,7 +640,7 @@ int main( int argc, char *argv[] ) unsigned int nread = ssh_channel_read_nonblocking( channel[i], buffer, sizeof( buffer ), 0 ); if( nread == SSH_ERROR ) { fprintf( stderr, "ERROR: ssh_channel_read_nonblocking on stdout failed: %s\n", - ssh_get_error( channel[i] ) ); + ssh_get_error( session[i] ) ); cleanup_sessions( &session, &channel, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } -- cgit v1.2.3-54-g00ecf