Diffstat (limited to 'noncore/comm/keypebble/krfblogin.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | noncore/comm/keypebble/krfblogin.cpp | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/noncore/comm/keypebble/krfblogin.cpp b/noncore/comm/keypebble/krfblogin.cpp new file mode 100644 index 0000000..073ba0e --- a/dev/null +++ b/noncore/comm/keypebble/krfblogin.cpp | |||
@@ -0,0 +1,255 @@ | |||
1 | #include <assert.h> | ||
2 | |||
3 | |||
4 | extern "C" { | ||
5 | #include "vncauth.h" | ||
6 | } | ||
7 | |||
8 | #include "krfblogin.h" | ||
9 | #include "krfbconnection.h" | ||
10 | #include <qtimer.h> | ||
11 | |||
12 | // The length of the various messages (used to decide how many bytes to | ||
13 | // wait for). | ||
14 | const int ServerVersionLength = 12; | ||
15 | const int ClientVersionLength = 12; | ||
16 | const int AuthSchemeLength = 4; | ||
17 | const int FailureReasonSizeLength = 4; | ||
18 | const int ChallengeLength = 16; | ||
19 | const int AuthResultLength = 4; | ||
20 | |||
21 | // Authentication results | ||
22 | enum AuthResult { | ||
23 | AuthOk, | ||
24 | AuthFailed, | ||
25 | AuthTooMany | ||
26 | }; | ||
27 | |||
28 | typedef unsigned char CARD8; | ||
29 | typedef unsigned short CARD16; | ||
30 | typedef unsigned long CARD32; | ||
31 | |||
32 | const int endianTest = 1; | ||
33 | |||
34 | // Endian stuff | ||
35 | #define Swap16IfLE(s) \ | ||
36 | (*(char *)&endianTest ? ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) : (s)) | ||
37 | |||
38 | #define Swap32IfLE(l) \ | ||
39 | (*(char *)&endianTest ? ((((l) & 0xff000000) >> 24) | \ | ||
40 | (((l) & 0x00ff0000) >> 8) | \ | ||
41 | (((l) & 0x0000ff00) << 8) | \ | ||
42 | (((l) & 0x000000ff) << 24)) : (l)) | ||
43 | |||
44 | KRFBLogin::KRFBLogin( KRFBConnection *con ) | ||
45 | : QObject( con, "RFB login manager" ) | ||
46 | { | ||
47 | assert( con ); | ||
48 | this->con = con; | ||
49 | currentState = AwaitingServerVersion; | ||
50 | |||
51 | connect( this, SIGNAL( error( const QString & ) ), | ||
52 | con, SIGNAL( error( const QString & ) ) ); | ||
53 | |||
54 | connect( this, SIGNAL( passwordRequired( KRFBConnection * ) ), | ||
55 | con, SIGNAL( passwordRequired( KRFBConnection * ) ) ); | ||
56 | |||
57 | qWarning( "Waiting for server version..." ); | ||
58 | |||
59 | static QString statusMsg = tr( "Waiting for server version..." ); | ||
60 | emit status( statusMsg ); | ||
61 | |||
62 | // Kick off the state machine | ||
63 | connect( con, SIGNAL( gotEnoughData() ), SLOT( gotServerVersion() ) ); | ||
64 | con->waitForData( ServerVersionLength ); | ||
65 | } | ||
66 | |||
67 | KRFBLogin::~KRFBLogin() | ||
68 | { | ||
69 | |||
70 | } | ||
71 | |||
72 | KRFBLogin::State KRFBLogin::state() const | ||
73 | { | ||
74 | return currentState; | ||
75 | } | ||
76 | |||
77 | void KRFBLogin::gotServerVersion() | ||
78 | { | ||
79 | qWarning( "Got server version" ); | ||
80 | |||
81 | disconnect( con, SIGNAL( gotEnoughData() ), | ||
82 | this, SLOT( gotServerVersion() ) ); | ||
83 | |||
84 | // Read the server's version message | ||
85 | char serverVersion[ ServerVersionLength + 1 ]; | ||
86 | con->read( serverVersion, ServerVersionLength ); | ||
87 | serverVersion[ ServerVersionLength ] = '\0'; | ||
88 | |||
89 | QCString rfbString( serverVersion, ServerVersionLength + 1 ); | ||
90 | versionString = rfbString; | ||
91 | |||
92 | QRegExp regexp( "RFB [0-9][0-9][0-9]\\.[0-9][0-9][0-9]\n" ); | ||
93 | |||
94 | if ( rfbString.find( regexp ) == -1 ) { | ||
95 | static QString msg = tr( "Error: Invalid server version, %1" ).arg( rfbString ); | ||
96 | |||
97 | qWarning( msg ); | ||
98 | emit error( msg ); | ||
99 | currentState = Error; | ||
100 | return; | ||
101 | } | ||
102 | |||
103 | // Calculate the actual version number | ||
104 | serverMajor = (serverVersion[4] - '0') * 100 | ||
105 | + (serverVersion[5] - '0') * 10 | ||
106 | + (serverVersion[6] - '0'); | ||
107 | serverMinor = (serverVersion[8] - '0') * 100 | ||
108 | + (serverVersion[9] - '0') * 10 | ||
109 | + (serverVersion[10] - '0'); | ||
110 | |||
111 | qWarning("Server Version: %03d.%03d", serverMajor, serverMinor ); | ||
112 | |||
113 | if ( serverMajor != 3 ) { | ||
114 | QString msg = tr( "Error: Unsupported server version, %1" ) | ||
115 | .arg( rfbString ); | ||
116 | |||
117 | qWarning( msg ); | ||
118 | emit error( msg ); | ||
119 | currentState = Error; | ||
120 | return; | ||
121 | } | ||
122 | |||
123 | if ( serverMinor != 3 ) { | ||
124 | qWarning( "Minor version mismatch: %d", serverMinor ); | ||
125 | } | ||
126 | |||
127 | // Setup for the next state | ||
128 | sendClientVersion(); | ||
129 | |||
130 | connect( con, SIGNAL( gotEnoughData() ), SLOT( gotAuthScheme() ) ); | ||
131 | con->waitForData( AuthSchemeLength ); | ||
132 | } | ||
133 | |||
134 | void KRFBLogin::gotAuthScheme() | ||
135 | { | ||
136 | disconnect( con, SIGNAL( gotEnoughData() ), | ||
137 | this, SLOT( gotAuthScheme() ) ); | ||
138 | |||
139 | // Got data | ||
140 | CARD32 scheme; | ||
141 | con->read( &scheme, AuthSchemeLength ); | ||
142 | scheme = Swap32IfLE( scheme ); | ||
143 | |||
144 | static QString statusMsgOk = tr( "Logged in" ); | ||
145 | |||
146 | switch ( scheme ) { | ||
147 | case 0: | ||
148 | qWarning( "Failed" ); | ||
149 | // Handle failure | ||
150 | connect( con, SIGNAL( gotEnoughData() ), SLOT( gotFailureReasonSize() ) ); | ||
151 | con->waitForData( FailureReasonSizeLength ); | ||
152 | break; | ||
153 | case 1: | ||
154 | // Handle no auth | ||
155 | emit status( statusMsgOk ); | ||
156 | con->gotRFBConnection(); | ||
157 | break; | ||
158 | case 2: | ||
159 | // Handle VNC auth | ||
160 | connect( con, SIGNAL( gotEnoughData() ), SLOT( gotChallenge() ) ); | ||
161 | con->waitForData( ChallengeLength ); | ||
162 | break; | ||
163 | default: | ||
164 | qWarning( "Unknown authentication scheme, 0x%08lx", scheme ); | ||
165 | currentState = Error; | ||
166 | break; | ||
167 | }; | ||
168 | } | ||
169 | |||
170 | void KRFBLogin::gotChallenge() | ||
171 | { | ||
172 | disconnect( con, SIGNAL( gotEnoughData() ), | ||
173 | this, SLOT( gotChallenge() ) ); | ||
174 | |||
175 | QTimer::singleShot( 0, this, SLOT(getPassword()) ); | ||
176 | } | ||
177 | |||
178 | void KRFBLogin::getPassword() | ||
179 | { | ||
180 | // Got data | ||
181 | CARD8 challenge[ ChallengeLength ]; | ||
182 | con->read( challenge, ChallengeLength ); | ||
183 | |||
184 | // Last chance to enter a password | ||
185 | if ( con->pass_.isNull() ) { | ||
186 | qWarning( "krfblogin needs a password" ); | ||
187 | emit passwordRequired( con ); | ||
188 | } | ||
189 | |||
190 | if ( con->pass_.isNull() ) { | ||
191 | QString msg = tr( "Error: This server requires a password, but none " | ||
192 | "has been specified.\n" ); | ||
193 | |||
194 | emit error( msg ); | ||
195 | return; | ||
196 | } | ||
197 | |||
198 | vncEncryptBytes( (unsigned char *) challenge, con->pass_.data() ); | ||
199 | con->write( challenge, ChallengeLength ); | ||
200 | |||
201 | connect( con, SIGNAL( gotEnoughData() ), SLOT( gotAuthResult() ) ); | ||
202 | con->waitForData( AuthResultLength ); | ||
203 | } | ||
204 | |||
205 | void KRFBLogin::gotFailureReasonSize() | ||
206 | { | ||
207 | disconnect( con, SIGNAL( gotEnoughData() ), this, | ||
208 | SLOT( gotFailureReasonSize() ) ); | ||
209 | } | ||
210 | |||
211 | void KRFBLogin::gotAuthResult() | ||
212 | { | ||
213 | // Got data | ||
214 | disconnect( con, SIGNAL( gotEnoughData() ), this, | ||
215 | SLOT( gotAuthResult() ) ); | ||
216 | |||
217 | long result; | ||
218 | con->read( &result, AuthResultLength ); | ||
219 | result = Swap32IfLE( result ); | ||
220 | |||
221 | qWarning( "Authentication Result is 0x%08lx", result ); | ||
222 | |||
223 | static QString failed = tr( "Error: The password you specified was incorrect." ); | ||
224 | static QString tooMany = tr( "Error: Too many invalid login attempts have been made\n" | ||
225 | "to this account, please try later." ); | ||
226 | |||
227 | static QString statusMsgOk = tr( "Logged in" ); | ||
228 | static QString statusMsgFailed = tr( "Login Failed" ); | ||
229 | static QString statusMsgTooMany = tr( "Too many failures" ); | ||
230 | |||
231 | switch( result ) { | ||
232 | case AuthOk: | ||
233 | emit status( statusMsgOk ); | ||
234 | con->gotRFBConnection(); | ||
235 | break; | ||
236 | case AuthFailed: | ||
237 | qWarning( "Dammit" ); | ||
238 | emit status( statusMsgFailed ); | ||
239 | emit error( failed ); | ||
240 | break; | ||
241 | case AuthTooMany: | ||
242 | emit status( statusMsgTooMany ); | ||
243 | emit error( tooMany ); | ||
244 | break; | ||
245 | default: | ||
246 | qWarning( "Invalid authentication result, %lx", result ); | ||
247 | break; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | void KRFBLogin::sendClientVersion() | ||
252 | { | ||
253 | qWarning( "Sending client version" ); | ||
254 | con->write( (void*)"RFB 003.003\n", ClientVersionLength ); | ||
255 | } | ||