diff options
author | Andreas Baumann <mail@andreasbaumann.cc> | 2015-08-27 16:15:54 +0200 |
---|---|---|
committer | Andreas Baumann <mail@andreasbaumann.cc> | 2015-08-27 16:15:54 +0200 |
commit | 648886a5914fab9444ec4ce02abde8eb1a3bb4f8 (patch) | |
tree | 07d714e5e0f94a6ee87ef68db0958b5161b98ce4 | |
parent | b7e207c9186fa4d4c44bdfa6f0b08012947a31b5 (diff) | |
download | cssh-648886a5914fab9444ec4ce02abde8eb1a3bb4f8.tar.gz cssh-648886a5914fab9444ec4ce02abde8eb1a3bb4f8.tar.bz2 |
preparations for scp mode
l--------- | src/cscp | 1 | ||||
-rw-r--r-- | src/cssh.c | 356 |
2 files changed, 209 insertions, 148 deletions
diff --git a/src/cscp b/src/cscp new file mode 120000 index 0000000..e58b80a --- /dev/null +++ b/src/cscp @@ -0,0 +1 @@ +cssh
\ No newline at end of file @@ -275,7 +275,7 @@ static int read_hosts_file( const char *hosts_file, unsigned short default_port, return 0; } -static void cleanup_sessions( ssh_session **session, ssh_channel **channel, char **host, unsigned short *port, const int nof_sessions, bool verbose ) +static void cleanup_sessions( ssh_session **session, ssh_channel **channel, ssh_scp **scp, char **host, unsigned short *port, const int nof_sessions, bool verbose ) { for( unsigned int i = 0; i < nof_sessions; i++ ) { if( ssh_is_connected( (*session)[i] ) ) { @@ -289,6 +289,10 @@ static void cleanup_sessions( ssh_session **session, ssh_channel **channel, char ssh_channel_free( (*channel)[i] ); } } + if( scp != NULL ) { + ssh_scp_close( (*scp)[i] ); + ssh_scp_free( (*scp)[i] ); + } ssh_disconnect( (*session)[i] ); if( verbose ) { fprintf( stderr, "Disconnected from '%s', port %d..\n", host[i], port[i] ); @@ -299,6 +303,9 @@ static void cleanup_sessions( ssh_session **session, ssh_channel **channel, char if( channel != NULL ) { free( *channel ); } + if( scp != NULL ) { + free( *scp ); + } free( *session ); free( *host ); free( port ); @@ -310,6 +317,11 @@ typedef enum execution_mode_e { CSSH_EXECUTE_AS_SCP } execution_mode_e; +typedef enum copy_direction_e { + CSSH_COPY_DIRECTION_UPLOAD, + CSSH_COPY_DIRECTION_DOWNLOAD +} copy_direction_e; + static execution_mode_e determine_execution_mode( const char *argv0 ) { char *b = ssh_basename( argv0 ); @@ -445,7 +457,7 @@ int main( int argc, char *argv[] ) } 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 ); + cleanup_sessions( &session, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } } @@ -487,7 +499,7 @@ int main( int argc, char *argv[] ) 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 ); + cleanup_sessions( &session, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } auth_state[i] = CSSH_AUTH_VERIFY_HOST_DONE; @@ -508,7 +520,7 @@ int main( int argc, char *argv[] ) } 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 ); + cleanup_sessions( &session, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } break; @@ -533,7 +545,7 @@ int main( int argc, char *argv[] ) } 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 ); + cleanup_sessions( &session, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } break; @@ -552,7 +564,7 @@ int main( int argc, char *argv[] ) } 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 ); + cleanup_sessions( &session, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } break; @@ -572,7 +584,7 @@ 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", host[i] ); - cleanup_sessions( &session, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } } @@ -587,174 +599,222 @@ int main( int argc, char *argv[] ) cssh_msleep( 10 ); } - ssh_channel *channel = (ssh_channel *)malloc( ( nof_sessions + 1 ) * sizeof( ssh_channel ) ); - memset( channel, 0, nof_sessions + 1 ); - 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 ); - exit( EXIT_FAILURE ); - } - for( unsigned int i = 0; i < nof_sessions; i++ ) { - channel[i] = ssh_channel_new( session[i] ); - if( channel[i] == NULL ) { - fprintf( stderr, "ERROR: Unable to open SSH channel: %s\n", - ssh_get_error( session[i] ) ); - cleanup_sessions( &session, &channel, host, port, nof_sessions, args_info.verbose_given > 0 ); - exit( EXIT_FAILURE ); - } - } - - for( unsigned int i = 0; i < nof_sessions; i++ ) { - rc = ssh_channel_open_session( channel[i] ); - if( rc != SSH_OK ) { - cleanup_sessions( &session, &channel, host, port, nof_sessions, args_info.verbose_given > 0 ); - exit( EXIT_FAILURE ); - } - } - - char cmd[1024]; - cmd[0] = '\0'; - if( args_info.inputs_num > 0 ) { - for( int i = command_pos; i < args_info.inputs_num; i++ ) { - if( i != command_pos ) { - strncat( cmd, " ", sizeof( cmd ) - strlen( cmd ) - 1 ); + switch( execution_mode ) { + case CSSH_EXECUTE_AS_SSH: { + + // explicit low-level handling of channels in SSH mode + ssh_channel *channel = (ssh_channel *)malloc( ( nof_sessions + 1 ) * sizeof( ssh_channel ) ); + memset( channel, 0, nof_sessions + 1 ); + if( channel == NULL ) { + fprintf( stderr, "ERROR: Memory allocation failed for ssh_channels" ); + cleanup_sessions( &session, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + for( unsigned int i = 0; i < nof_sessions; i++ ) { + channel[i] = ssh_channel_new( session[i] ); + if( channel[i] == NULL ) { + fprintf( stderr, "ERROR: Unable to open SSH channel: %s\n", + ssh_get_error( session[i] ) ); + cleanup_sessions( &session, &channel, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } } - strncat( cmd, args_info.inputs[i], sizeof( cmd ) - strlen( cmd ) - 1 ); - } - } - if( cmd[0] == '\0' ) { - fprintf( stderr, "ERROR: Empty command, no interactive CLI supported currently\n" ); - cleanup_sessions( &session, &channel, host, port, nof_sessions, args_info.verbose_given > 0 ); - exit( EXIT_FAILURE ); - } - - for( unsigned int i = 0; i < nof_sessions; i++ ) { - rc = ssh_channel_request_exec( channel[i], cmd ); - if( rc != SSH_OK ) { - fprintf( stderr, "ERROR: Executing SSH command '%s' failed: %s\n", - cmd, ssh_get_error( session[i] ) ); - cleanup_sessions( &session, &channel, host, port, nof_sessions, args_info.verbose_given > 0 ); - exit( EXIT_FAILURE ); - } - } - - 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 ) { - all_eof = true; - for( unsigned int i = 0; i < nof_sessions; i++ ) { - if( !ssh_channel_is_closed( channel[i] ) && !ssh_channel_is_eof( channel[i] ) ) { - all_eof = false; + for( unsigned int i = 0; i < nof_sessions; i++ ) { + rc = ssh_channel_open_session( channel[i] ); + if( rc != SSH_OK ) { + cleanup_sessions( &session, &channel, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } } - } - - // no stdin sent to commands on remote machines for now - for( unsigned int i = 0; i < nof_sessions; i++ ) { - if( is_eof[i] && !eof_sent[i] ) { - ssh_channel_send_eof( channel[i] ); - eof_sent[i] = true; - continue; + + // compose command to be executed in SSH mode + char cmd[1024]; + cmd[0] = '\0'; + if( args_info.inputs_num > 0 ) { + for( int i = command_pos; i < args_info.inputs_num; i++ ) { + if( i != command_pos ) { + strncat( cmd, " ", sizeof( cmd ) - strlen( cmd ) - 1 ); + } + strncat( cmd, args_info.inputs[i], sizeof( cmd ) - strlen( cmd ) - 1 ); + } } - } - - for( unsigned int i = 0; i < nof_sessions; i++ ) { - char buffer[4096]; - rc = ssh_channel_poll( channel[i], 0 ); - if( rc == SSH_ERROR ) { - fprintf( stderr, "ERROR: ssh_channel_poll on stdout failed: %s\n", - ssh_get_error( session[i] ) ); - cleanup_sessions( &session, &channel, host, port, nof_sessions, args_info.verbose_given > 0 ); + if( cmd[0] == '\0' ) { + fprintf( stderr, "ERROR: Empty command, no interactive CLI supported currently\n" ); + cleanup_sessions( &session, &channel, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } - - if( rc > 0 ) { - 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( session[i] ) ); - cleanup_sessions( &session, &channel, host, port, nof_sessions, args_info.verbose_given > 0 ); + + // execute command on all channels + for( unsigned int i = 0; i < nof_sessions; i++ ) { + rc = ssh_channel_request_exec( channel[i], cmd ); + if( rc != SSH_OK ) { + fprintf( stderr, "ERROR: Executing SSH command '%s' failed: %s\n", + cmd, ssh_get_error( session[i] ) ); + cleanup_sessions( &session, &channel, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } + } + + 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 ) { + + all_eof = true; + for( unsigned int i = 0; i < nof_sessions; i++ ) { + if( !ssh_channel_is_closed( channel[i] ) && !ssh_channel_is_eof( channel[i] ) ) { + all_eof = false; + } + } - if( nread == 0 ) { - is_eof[i] = true; + // no stdin sent to commands on remote machines for now + for( unsigned int i = 0; i < nof_sessions; i++ ) { + if( is_eof[i] && !eof_sent[i] ) { + ssh_channel_send_eof( channel[i] ); + eof_sent[i] = true; + continue; + } } - - if( nread > 0 ) { - size_t wrc = fwrite( buffer, 1, nread, stdout ); - if( wrc < 0 ) { - fprintf( stderr, "ERROR: while writing to stdout: %s\n", - strerror( errno ) ); - cleanup_sessions( &session, &channel, host, port, nof_sessions, args_info.verbose_given > 0 ); + + for( unsigned int i = 0; i < nof_sessions; i++ ) { + char buffer[4096]; + rc = ssh_channel_poll( channel[i], 0 ); + if( rc == SSH_ERROR ) { + fprintf( stderr, "ERROR: ssh_channel_poll on stdout failed: %s\n", + ssh_get_error( session[i] ) ); + cleanup_sessions( &session, &channel, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } + + if( rc > 0 ) { + 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( session[i] ) ); + cleanup_sessions( &session, &channel, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + + if( nread == 0 ) { + is_eof[i] = true; + } + + if( nread > 0 ) { + size_t wrc = fwrite( buffer, 1, nread, stdout ); + if( wrc < 0 ) { + fprintf( stderr, "ERROR: while writing to stdout: %s\n", + strerror( errno ) ); + cleanup_sessions( &session, &channel, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + + if( wrc != nread ) { + fprintf( stderr, "ERROR: Write mismatch on stdout (%zu != %d)\n", + wrc, nread ); + cleanup_sessions( &session, &channel, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + } + } - if( wrc != nread ) { - fprintf( stderr, "ERROR: Write mismatch on stdout (%zu != %d)\n", - wrc, nread ); - cleanup_sessions( &session, &channel, host, port, nof_sessions, args_info.verbose_given > 0 ); + rc = ssh_channel_poll( channel[i], 1 ); + if( rc == SSH_ERROR ) { + fprintf( stderr, "ERROR: ssh_channel_poll on stderr failed: %s\n", + ssh_get_error( session[i] ) ); + cleanup_sessions( &session, &channel, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } + + if( rc > 0 ) { + unsigned int nread = ssh_channel_read_nonblocking( channel[i], buffer, sizeof( buffer ), 1 ); + if( nread == SSH_ERROR ) { + fprintf( stderr, "ERROR: ssh_channel_read_nonblocking on stderr failed: %s\n", + ssh_get_error( session[i] ) ); + cleanup_sessions( &session, &channel, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + + if( nread > 0 ) { + size_t wrc = fwrite( buffer, 1, nread, stderr ); + if( wrc < 0 ) { + fprintf( stderr, "ERROR: while writting to stderr: %s\n", + strerror( errno ) ); + cleanup_sessions( &session, &channel, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + + if( wrc != nread ) { + fprintf( stderr, "ERROR: Write mismatch on stderr (%zu != %d)\n", + wrc, nread ); + cleanup_sessions( &session, &channel, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_FAILURE ); + } + } + + if( nread == 0 ) { + is_eof[i] = true; + } + } } + + cssh_msleep( 1 ); } + + cleanup_sessions( &session, &channel, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); + + } break; + + case CSSH_EXECUTE_AS_SCP: { + + // TODO: parse 2 arguments and see where we have a local + // path and where a host destination with path + // TODO: host destination can be explicit (one without -H hosts + // parameter) or it is a placeholder host @HOST@:/dira/dirb + copy_direction_e copy_direction = CSSH_COPY_DIRECTION_DOWNLOAD; + const char *local_directory = "."; + + fprintf( stderr, "Copy mode\n" ); - rc = ssh_channel_poll( channel[i], 1 ); - if( rc == SSH_ERROR ) { - fprintf( stderr, "ERROR: ssh_channel_poll on stderr failed: %s\n", - ssh_get_error( session[i] ) ); - cleanup_sessions( &session, &channel, host, port, nof_sessions, args_info.verbose_given > 0 ); + ssh_scp *scp = (ssh_scp *)malloc( ( nof_sessions + 1 ) * sizeof( ssh_scp ) ); + memset( scp, 0, nof_sessions + 1 ); + if( scp == NULL ) { + fprintf( stderr, "ERROR: Memory allocation failed for ssh_scp" ); + cleanup_sessions( &session, NULL, NULL, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } - - if( rc > 0 ) { - unsigned int nread = ssh_channel_read_nonblocking( channel[i], buffer, sizeof( buffer ), 1 ); - if( nread == SSH_ERROR ) { - fprintf( stderr, "ERROR: ssh_channel_read_nonblocking on stderr failed: %s\n", + for( unsigned int i = 0; i < nof_sessions; i++ ) { + scp[i] = ssh_scp_new( session[i], + ( ( copy_direction == CSSH_COPY_DIRECTION_UPLOAD ) ? SSH_SCP_WRITE : SSH_SCP_READ ) | + ( ( args_info.recursive_given > 0 ) ? SSH_SCP_RECURSIVE : 0 ), + local_directory ); + if( scp[i] == NULL ) { + fprintf( stderr, "ERROR: Unable to open SCP channel: %s\n", ssh_get_error( session[i] ) ); - cleanup_sessions( &session, &channel, host, port, nof_sessions, args_info.verbose_given > 0 ); + cleanup_sessions( &session, NULL, &scp, host, port, nof_sessions, args_info.verbose_given > 0 ); exit( EXIT_FAILURE ); } + } - if( nread > 0 ) { - size_t wrc = fwrite( buffer, 1, nread, stderr ); - if( wrc < 0 ) { - fprintf( stderr, "ERROR: while writting to stderr: %s\n", - strerror( errno ) ); - cleanup_sessions( &session, &channel, host, port, nof_sessions, args_info.verbose_given > 0 ); - exit( EXIT_FAILURE ); - } + cleanup_sessions( &session, NULL, &scp, host, port, nof_sessions, args_info.verbose_given > 0 ); - if( wrc != nread ) { - fprintf( stderr, "ERROR: Write mismatch on stderr (%zu != %d)\n", - wrc, nread ); - cleanup_sessions( &session, &channel, host, port, nof_sessions, args_info.verbose_given > 0 ); - exit( EXIT_FAILURE ); - } - } + } break; - if( nread == 0 ) { - is_eof[i] = true; - } - } - } - - cssh_msleep( 1 ); + case CSSH_EXECUTE_UNKNOWN: + break; } - - cleanup_sessions( &session, &channel, host, port, nof_sessions, args_info.verbose_given > 0 ); + exit( EXIT_SUCCESS ); } |