📄 ssh.c
字号:
if( cryptStatusOK( status ) )
{
status = cryptSetAttribute( cryptSession,
CRYPT_SESSINFO_PRIVATEKEY, privateKey );
cryptDestroyContext( privateKey );
}
}
else
{
#ifdef USER_SUPPLIED_PASSWORD
char password[ 256 ];
printf( "Enter SSHv2 server password: " );
fgets( password, 255, stdin );
password[ strlen( password ) - 1 ] = '\0';
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_PASSWORD,
password, strlen( password ) );
#else
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_PASSWORD,
SSH_PASSWORD,
paramStrlen( SSH_PASSWORD ) );
#endif /* User-supplied password */
}
}
if( cryptStatusOK( status ) && \
( testType == SSH_TEST_SUBSYSTEM ) )
status = createChannel( cryptSession, TEXT( "subsystem" ),
TEXT( "sftp" ) );
if( cryptStatusOK( status ) && \
( testType == SSH_TEST_PORTFORWARDING || \
testType == SSH_TEST_MULTICHANNEL ) )
createChannel( cryptSession, TEXT( "direct-tcpip" ),
TEXT( "localhost:1234" ) );
if( cryptStatusOK( status ) && \
( testType == SSH_TEST_FINGERPRINT ) )
{
BYTE fingerPrint[ CRYPT_MAX_HASHSIZE ];
/* Set a dummy (all-zero) fingerprint to force the connect to
fail */
memset( fingerPrint, 0, CRYPT_MAX_HASHSIZE );
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_SERVER_FINGERPRINT,
fingerPrint, 16 );
}
if( cryptStatusOK( status ) && \
( testType == SSH_TEST_EXEC ) )
status = createChannel( cryptSession, TEXT( "exec" ),
TEXT( "/bin/netstat" ) );
}
if( cryptStatusOK( status ) )
status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_VERSION,
( testType == SSH_TEST_SSH1 ) ? 1 : 2 );
if( cryptStatusOK( status ) && isServer && \
( testType != SSH_TEST_CONFIRMAUTH && \
testType != SSH_TEST_DUALTHREAD ) )
{
/* If we're not testing manual confirmation of client auth, have
cryptlib automatically confirm the auth */
status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_AUTHRESPONSE,
TRUE );
}
if( cryptStatusError( status ) )
{
/* If we're trying to enable SSHv1 and it fails, this isn't an error
since this protocol is disabled by default */
if( testType == SSH_TEST_SSH1 )
{
puts( "SSHv1 appears to be disbled in this build." );
cryptDestroySession( cryptSession );
puts( isServer ? "SVR: SSH server session succeeded.\n" : \
"SSH client session succeeded.\n" );
return( CRYPT_ERROR_NOTAVAIL );
}
printf( "%scryptSetAttribute/AttributeString() failed with error "
"code %d, line %d.\n", isServer ? "SVR: " : "", status,
__LINE__ );
return( FALSE );
}
/* Activate the session. Since we need to be able to process out-of-
band signalling such as channel control messages, we set a non-zero
timeout for reads */
cryptSetAttribute( cryptSession, CRYPT_OPTION_NET_READTIMEOUT, 5 );
if( localSession && isServer )
/* Tell the client that we're ready to go */
releaseMutex();
status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE );
if( isServer )
{
#ifdef WINDOWS_THREADS
if( isServer && testType == SSH_TEST_DUALTHREAD && \
status == CRYPT_ENVELOPE_RESOURCE )
{
static CRYPT_SESSION localCryptSession = 0;
unsigned threadID;
/* Start a second thread to complete the handshake and exit */
localCryptSession = cryptSession;
_beginthreadex( NULL, 0, ssh2ServerDualThread2, NULL, 0,
&threadID );
return( TRUE );
/* The second thread continues from here */
dualThreadContinue:
assert( localSession > 0 );
cryptSession = localCryptSession;
/* Allow the auth.and complete the handshake */
puts( "SVR: Confirming authentication to client..." );
status = cryptSetAttribute( cryptSession,
CRYPT_SESSINFO_AUTHRESPONSE, TRUE );
if( cryptStatusOK( status ) )
status = cryptSetAttribute( cryptSession,
CRYPT_SESSINFO_ACTIVE, TRUE );
}
#endif /* WINDOWS_THREADS */
if( status == CRYPT_ENVELOPE_RESOURCE )
{
/* The client has tried to authenticate themselves, print the
info */
if( !printAuthInfo( cryptSession ) )
return( FALSE );
/* Deny the auth.and force them to retry */
puts( "SVR: Denying authentication to client, who should reauth..." );
status = cryptSetAttribute( cryptSession,
CRYPT_SESSINFO_AUTHRESPONSE, FALSE );
if( cryptStatusOK( status ) )
status = cryptSetAttribute( cryptSession,
CRYPT_SESSINFO_ACTIVE, TRUE );
if( status != CRYPT_ENVELOPE_RESOURCE )
{
printf( "SVR: Attempt to deny auth.to client failed with error "
"code %d, line %d.\n", status, __LINE__ );
return( FALSE );
}
if( !printAuthInfo( cryptSession ) )
return( FALSE );
/* Allow the auth.and complete the handshake */
puts( "SVR: Confirming authentication to client..." );
status = cryptSetAttribute( cryptSession,
CRYPT_SESSINFO_AUTHRESPONSE, TRUE );
if( cryptStatusOK( status ) )
status = cryptSetAttribute( cryptSession,
CRYPT_SESSINFO_ACTIVE, TRUE );
}
/* Now that the handshake is complete, display the connection info */
if( cryptStatusOK( status ) && !printConnectInfo( cryptSession ) )
return( FALSE );
}
if( cryptStatusError( status ) )
{
if( testType == SSH_TEST_FINGERPRINT )
{
/* We've forced the connect to fail by using a dummy fingerprint,
everything is OK */
if( isServer )
printf( "SVR: " );
puts( "SSH client rejected key with invalid fingerprint." );
cryptDestroySession( cryptSession );
puts( isServer ? "SVR: SSH server session succeeded.\n" : \
"SSH client session succeeded.\n" );
fflush( stdout );
return( TRUE );
}
printExtError( cryptSession, isServer ? \
"SVR: Attempt to activate SSH server session" : \
"Attempt to activate SSH client session", status,
__LINE__ );
cryptDestroySession( cryptSession );
if( status == CRYPT_ERROR_OPEN || status == CRYPT_ERROR_NOTFOUND )
{
/* These servers are constantly appearing and disappearing so if
we get a straight connect error we don't treat it as a serious
failure */
puts( " (Server could be down, faking it and continuing...)\n" );
return( CRYPT_ERROR_FAILED );
}
if( status == CRYPT_ERROR_WRONGKEY )
{
/* This is another possible soft error condition, the default
username and password shouldn't be able to get into many
machines */
puts( " (Incorrect username/password, continuing...)\n" );
return( TRUE );
}
if( status == CRYPT_ERROR_NOSECURE )
{
/* Another soft error condition, the server can't handle the
security level we want (usually occurs when trying to perform
an SSHv2 connect to an SSHv1 server) */
puts( " (Insufficiently secure protocol parameters, "
"continuing...)\n" );
return( TRUE );
}
return( FALSE );
}
if( testType == SSH_TEST_FINGERPRINT )
{
printf( "Attempt to connect with invalid key fingerprint succeeded "
"when it should\nhave failed, line %d.\n", __LINE__ );
return( FALSE );
}
/* Report the session security info */
if( !printSecurityInfo( cryptSession, isServer, TRUE ) )
return( FALSE );
status = cryptGetAttribute( cryptSession, CRYPT_SESSINFO_SSH_CHANNEL,
&channel );
if( cryptStatusError( status ) )
{
printf( "cryptGetAttributeString() failed with error code "
"%d, line %d.\n", status, __LINE__ );
return( FALSE );
}
printf( "%sCurrent channel is #%d.\n", isServer ? "SVR: " : "",
channel );
fflush( stdout );
/* Report additional channel-specific information */
if( isServer )
{
/* Display info on any channels that the client has opened */
if( !printChannelInfo( cryptSession, testType, TRUE ) )
return( FALSE );
/* Process any additional information that the client may throw
at us after the user-auth has completed */
status = cryptPopData( cryptSession, buffer, BUFFER_SIZE,
&bytesCopied );
if( cryptStatusOK( status ) && bytesCopied > 0 )
{
printf( "SVR: Client sent additional %d bytes post-"
"handshake data.\n", bytesCopied );
fflush( stdout );
}
else
{
if( status == CRYPT_ENVELOPE_RESOURCE )
{
/* The client performed additional control actions that were
handled inline as part of the data-pop, report the
details */
if( !printChannelInfo( cryptSession, testType, TRUE ) )
return( FALSE );
}
}
}
/* If we're using the SFTP subsystem as a server, use the special-case
routines for this */
#ifdef WINDOWS_THREADS
if( testType == SSH_TEST_SUBSYSTEM )
{
if( isServer )
{
int sftpServer( const CRYPT_SESSION cryptSession );
status = sftpServer( cryptSession );
if( cryptStatusError( status ) )
{
printf( "SVR: Couldn't receive SFTP data from client, status %d, "
"line %d.\n", status, __LINE__ );
return( FALSE );
}
cryptDestroySession( cryptSession );
puts( "SVR: SFTP server session succeeded.\n" );
fflush( stdout );
return( TRUE );
}
else
{
int sftpClient( const CRYPT_SESSION cryptSession );
status = sftpClient( cryptSession );
if( cryptStatusError( status ) )
{
printf( "Couldn't send SFTP data to server, status %d, line "
"%d.\n", status, __LINE__ );
return( FALSE );
}
cryptDestroySession( cryptSession );
puts( "SFTP client session succeeded.\n" );
fflush( stdout );
return( TRUE );
}
}
#endif /* WINDOWS_THREADS */
/* If we're performing a multi-channel test, open a second channel (the
server handles this as part of its general connect-handling) */
if( testType == SSH_TEST_MULTICHANNEL && !isServer )
{
status = createChannel( cryptSession, TEXT( "direct-tcpip" ),
TEXT( "localhost:5678" ) );
if( cryptStatusOK( status ) )
status = cryptGetAttribute( cryptSession,
CRYPT_SESSINFO_SSH_CHANNEL,
&channel );
if( cryptStatusOK( status ) )
status = cryptSetAttribute( cryptSession,
CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE,
TRUE );
if( cryptStatusError( status ) )
{
printf( "Couldn't open second SSH chanel, status %d, line "
"%d.\n", status, __LINE__ );
return( FALSE );
}
printf( "Opened additional channel #%d to server.\n", channel );
fflush( stdout );
}
/* Send data over the SSH link */
if( isServer )
{
/* Send a status message to the client */
status = cryptPushData( cryptSession, "Welcome to cryptlib, now go "
"away.\r\n", 35, &bytesCopied );
if( cryptStatusOK( status ) )
status = cryptFlushData( cryptSession );
if( cryptStatusError( status ) || bytesCopied != 35 )
{
printf( "SVR: Couldn't send data to client, status %d, line "
"%d.\n", status, __LINE__ );
return( FALSE );
}
}
/* Wait a bit while data arrives */
delayThread( 2 );
/* Print the first lot of output from the other side */
if( !printDataInfo( cryptSession, buffer, &bytesCopied, isServer ) )
return( FALSE );
/* If we're the server, echo the command to the client */
if( isServer )
{
const int clientBytesCopied = bytesCopied;
int dummy, i;
/* If it's a multi-channel test, send the response back on a
different channel. The currently-selected channel will be the
last one that the client opened (#2), so we can hardcode in
#1 for testing purposes */
if( testType == SSH_TEST_MULTICHANNEL )
{
status = cryptSetAttribute( cryptSession,
CRYPT_SESSINFO_SSH_CHANNEL, 1 );
if( cryptStatusError( status ) )
{
printf( "SVR: Couldn't select channel #1 to return data to "
"client, status %d, line %d.\n", status, __LINE__ );
return( FALSE );
}
}
for( i = 0; i < clientBytesCopied; i++ )
{
if( buffer[ i ] < ' ' || buffer[ i ] >= 0x7F )
buffer[ i ] = '.';
}
status = cryptPushData( cryptSession, "Input was [", 11, &dummy );
if( cryptStatusOK( status ) && clientBytesCopied > 0 )
status = cryptPushData( cryptSession, buffer, clientBytesCopied,
&bytesCopied );
if( cryptStatusOK( status ) )
status = cryptPushData( cryptSession, "]\r\n", 3, &dummy );
if( cryptStatusOK( status ) )
status = cryptFlushData( cryptSession );
if( cryptStatusError( status ) || bytesCopied != clientBytesCopied )
{
printf( "SVR: Couldn't send data to client, status %d, line "
"%d.\n", status, __LINE__ );
return( FALSE );
}
}
else
{
/* We're the client, if it's a session to a Unix ssh server, send a
sample command and display the output */
if( !localSession )
{
/* Send a command to the server and get the results */
status = cryptPushData( cryptSession, "ls -l | head -25\n", 18,
&bytesCopied );
if( cryptStatusOK( status ) )
status = cryptFlushData( cryptSession );
if( cryptStatusError( status ) || bytesCopied != 18 )
{
printf( "Couldn't send data to server, status %d, line "
"%d.\n", status, __LINE__ );
return( FALSE );
}
puts( "Sent 'ls -l | head -25'" );
delayThread( 3 );
if( !printDataInfo( cryptSession, buffer, &bytesCopied,
isServer ) )
return( FALSE );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -