summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2015-08-16 17:52:46 +0200
committerAndreas Baumann <mail@andreasbaumann.cc>2015-08-16 17:52:46 +0200
commitc2408c9d74a780d3f1c502b78f4c47b15959a1a9 (patch)
treea62d572b1049ee71d6bf510c2c114c031de5c0d2
parent6f373f6b63cdcc136ab09a1179fd49d35af92287 (diff)
downloadcssh-c2408c9d74a780d3f1c502b78f4c47b15959a1a9.tar.gz
cssh-c2408c9d74a780d3f1c502b78f4c47b15959a1a9.tar.bz2
tried to make connect and authentication non-blocking
-rw-r--r--README3
-rw-r--r--src/cssh.c211
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 );
}