00001 #include "krfblogin.h"
00002 #include "krfbconnection.h"
00003
00004
00005 #include <opie2/odebug.h>
00006 using namespace Opie::Core;
00007
00008
00009 #include <qtimer.h>
00010
00011
00012 #include <assert.h>
00013 extern "C" {
00014 #include "vncauth.h"
00015 }
00016
00017
00018
00019 const int ServerVersionLength = 12;
00020 const int ClientVersionLength = 12;
00021 const int AuthSchemeLength = 4;
00022 const int FailureReasonSizeLength = 4;
00023 const int ChallengeLength = 16;
00024 const int AuthResultLength = 4;
00025
00026
00027 enum AuthResult {
00028 AuthOk,
00029 AuthFailed,
00030 AuthTooMany
00031 };
00032
00033 typedef unsigned char CARD8;
00034 typedef unsigned short CARD16;
00035 typedef unsigned long CARD32;
00036
00037 const int endianTest = 1;
00038
00039
00040 #define Swap16IfLE(s) \
00041 (*(char *)&endianTest ? ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) : (s))
00042
00043 #define Swap32IfLE(l) \
00044 (*(char *)&endianTest ? ((((l) & 0xff000000) >> 24) | \
00045 (((l) & 0x00ff0000) >> 8) | \
00046 (((l) & 0x0000ff00) << 8) | \
00047 (((l) & 0x000000ff) << 24)) : (l))
00048
00049 KRFBLogin::KRFBLogin( KRFBConnection *con )
00050 : QObject( con, "RFB login manager" )
00051 {
00052 assert( con );
00053 this->con = con;
00054 currentState = AwaitingServerVersion;
00055
00056 connect( this, SIGNAL( error(const QString&) ),
00057 con, SIGNAL( error(const QString&) ) );
00058
00059
00060 owarn << "Waiting for server version..." << oendl;
00061
00062 static QString statusMsg = tr( "Waiting for server version..." );
00063 emit status( statusMsg );
00064
00065
00066 connect( con, SIGNAL( gotEnoughData() ), SLOT( gotServerVersion() ) );
00067 con->waitForData( ServerVersionLength );
00068 }
00069
00070 KRFBLogin::~KRFBLogin()
00071 {
00072
00073 }
00074
00075 KRFBLogin::State KRFBLogin::state() const
00076 {
00077 return currentState;
00078 }
00079
00080 void KRFBLogin::gotServerVersion()
00081 {
00082 owarn << "Got server version" << oendl;
00083
00084 disconnect( con, SIGNAL( gotEnoughData() ),
00085 this, SLOT( gotServerVersion() ) );
00086
00087
00088 char serverVersion[ ServerVersionLength + 1 ];
00089 con->read( serverVersion, ServerVersionLength );
00090 serverVersion[ ServerVersionLength ] = '\0';
00091
00092 QCString rfbString( serverVersion, ServerVersionLength + 1 );
00093 versionString = rfbString;
00094
00095 QRegExp regexp( "RFB [0-9][0-9][0-9]\\.[0-9][0-9][0-9]\n" );
00096
00097 if ( rfbString.find( regexp ) == -1 ) {
00098 static QString msg = tr( "Error: Invalid server version, %1" ).arg( rfbString );
00099
00100 owarn << msg << oendl;
00101 emit error( msg );
00102 currentState = Error;
00103 return;
00104 }
00105
00106
00107 serverMajor = (serverVersion[4] - '0') * 100
00108 + (serverVersion[5] - '0') * 10
00109 + (serverVersion[6] - '0');
00110 serverMinor = (serverVersion[8] - '0') * 100
00111 + (serverVersion[9] - '0') * 10
00112 + (serverVersion[10] - '0');
00113
00114 owarn << "Server Version: " << serverMajor << "." << serverMinor << "" << oendl;
00115
00116 if ( serverMajor != 3 ) {
00117 QString msg = tr( "Error: Unsupported server version, %1" )
00118 .arg( rfbString );
00119
00120 owarn << msg << oendl;
00121 emit error( msg );
00122 currentState = Error;
00123 return;
00124 }
00125
00126 if ( serverMinor != 3 ) {
00127 owarn << "Minor version mismatch: " << serverMinor << "" << oendl;
00128 }
00129
00130
00131 sendClientVersion();
00132
00133 connect( con, SIGNAL( gotEnoughData() ), SLOT( gotAuthScheme() ) );
00134 con->waitForData( AuthSchemeLength );
00135 }
00136
00137 void KRFBLogin::gotAuthScheme()
00138 {
00139 disconnect( con, SIGNAL( gotEnoughData() ),
00140 this, SLOT( gotAuthScheme() ) );
00141
00142
00143 CARD32 scheme;
00144 con->read( &scheme, AuthSchemeLength );
00145 scheme = Swap32IfLE( scheme );
00146
00147 static QString statusMsgOk = tr( "Logged in" );
00148
00149 switch ( scheme ) {
00150 case 0:
00151 owarn << "Failed" << oendl;
00152
00153 connect( con, SIGNAL( gotEnoughData() ), SLOT( gotFailureReasonSize() ) );
00154 con->waitForData( FailureReasonSizeLength );
00155 break;
00156 case 1:
00157
00158 emit status( statusMsgOk );
00159 con->gotRFBConnection();
00160 break;
00161 case 2:
00162
00163 connect( con, SIGNAL( gotEnoughData() ), SLOT( gotChallenge() ) );
00164 con->waitForData( ChallengeLength );
00165 break;
00166 default:
00167 owarn << "Unknown authentication scheme, 0x" << scheme << "" << oendl;
00168 currentState = Error;
00169 break;
00170 };
00171 }
00172
00173 void KRFBLogin::gotChallenge()
00174 {
00175 disconnect( con, SIGNAL( gotEnoughData() ),
00176 this, SLOT( gotChallenge() ) );
00177
00178 QTimer::singleShot( 0, this, SLOT(getPassword()) );
00179 }
00180
00181 void KRFBLogin::getPassword()
00182 {
00183
00184 CARD8 challenge[ ChallengeLength ];
00185 con->read( challenge, ChallengeLength );
00186
00187
00188 if ( con->options_->password.isNull() ) {
00189 owarn << "krfblogin needs a password" << oendl;
00190 emit passwordRequired( con );
00191 }
00192
00193 if ( con->options_->password.isNull() ) {
00194 QString msg = tr( "Error: This server requires a password, but none "
00195 "has been specified.\n" );
00196
00197 emit error( msg );
00198 return;
00199 }
00200
00201 vncEncryptBytes( (unsigned char *) challenge, QCString(con->options_->password.latin1()).data() );
00202 con->write( challenge, ChallengeLength );
00203
00204 connect( con, SIGNAL( gotEnoughData() ), SLOT( gotAuthResult() ) );
00205 con->waitForData( AuthResultLength );
00206 }
00207
00208 void KRFBLogin::gotFailureReasonSize()
00209 {
00210 disconnect( con, SIGNAL( gotEnoughData() ), this,
00211 SLOT( gotFailureReasonSize() ) );
00212 }
00213
00214 void KRFBLogin::gotAuthResult()
00215 {
00216
00217 disconnect( con, SIGNAL( gotEnoughData() ), this,
00218 SLOT( gotAuthResult() ) );
00219
00220 long result;
00221 con->read( &result, AuthResultLength );
00222 result = Swap32IfLE( result );
00223
00224 owarn << "Authentication Result is 0x" << result << "" << oendl;
00225
00226 static QString failed = tr( "Error: The password you specified was incorrect." );
00227 static QString tooMany = tr( "Error: Too many invalid login attempts have been made\n"
00228 "to this account, please try later." );
00229
00230 static QString statusMsgOk = tr( "Logged in" );
00231 static QString statusMsgFailed = tr( "Login Failed" );
00232 static QString statusMsgTooMany = tr( "Too many failures" );
00233
00234 switch( result ) {
00235 case AuthOk:
00236 emit status( statusMsgOk );
00237 con->gotRFBConnection();
00238 break;
00239 case AuthFailed:
00240 owarn << "Dammit" << oendl;
00241 emit status( statusMsgFailed );
00242 emit error( failed );
00243 break;
00244 case AuthTooMany:
00245 emit status( statusMsgTooMany );
00246 emit error( tooMany );
00247 break;
00248 default:
00249 owarn << "Invalid authentication result, " << result << "" << oendl;
00250 break;
00251 }
00252 }
00253
00254 void KRFBLogin::sendClientVersion()
00255 {
00256 owarn << "Sending client version" << oendl;
00257 con->write( (void*)"RFB 003.003\n", ClientVersionLength );
00258 }