Line 0
Link Here
|
|
|
1 |
//Imported from KMess (2005-05-19) |
2 |
|
3 |
/*************************************************************************** |
4 |
sslloginhandler.cpp - description |
5 |
------------------- |
6 |
begin : Sat Jun 28 2003 |
7 |
copyright : (C) 2003 by Mike K. Bennett |
8 |
email : mkb137b@hotmail.com |
9 |
***************************************************************************/ |
10 |
|
11 |
/*************************************************************************** |
12 |
* * |
13 |
* This program is free software; you can redistribute it and/or modify * |
14 |
* it under the terms of the GNU General Public License as published by * |
15 |
* the Free Software Foundation; either version 2 of the License, or * |
16 |
* (at your option) any later version. * |
17 |
* * |
18 |
***************************************************************************/ |
19 |
|
20 |
#include "sslloginhandler.h" |
21 |
|
22 |
#include <qstringlist.h> |
23 |
#include <qregexp.h> |
24 |
#include <qsocket.h> |
25 |
#include <qurl.h> |
26 |
|
27 |
#include <kdebug.h> |
28 |
#include <kextsock.h> |
29 |
#include <kssl.h> |
30 |
#include <kurl.h> |
31 |
|
32 |
#if 0 |
33 |
#include "../kmessdebug.h" |
34 |
#include "mimemessage.h" |
35 |
#else |
36 |
//i didn't want to import the whole MimeMessage from Kmess for Kopete so i |
37 |
// reimplemented the base here -Olivier |
38 |
|
39 |
class MimeMessage |
40 |
{ |
41 |
public: |
42 |
MimeMessage(const QString &msg) : message(msg) {} |
43 |
|
44 |
QString getValue(const QString &key) |
45 |
{ |
46 |
QRegExp rx(key+": (.*)\n"); |
47 |
rx.search(message); |
48 |
return rx.cap(1); |
49 |
} |
50 |
private: |
51 |
QString message; |
52 |
}; |
53 |
|
54 |
#include "sslloginhandler.moc" |
55 |
#endif |
56 |
//there is nothing modified from here. this is exactly the kmerlin code |
57 |
|
58 |
|
59 |
|
60 |
/* |
61 |
* Great documentation about this can be found at |
62 |
* http://siebe.bot2k3.net/docs/ |
63 |
*/ |
64 |
|
65 |
|
66 |
// The constructor |
67 |
SslLoginHandler::SslLoginHandler() |
68 |
: mode_(NONE) |
69 |
{ |
70 |
// Create the SSL handler |
71 |
ssl_ = new KSSL( true ); |
72 |
|
73 |
// Create and set up the socket. |
74 |
socket_ = new KExtendedSocket( ); |
75 |
|
76 |
//socket_->setSocketFlags( 0x00 | 0x600000 ); // 0x00 = anySocket | 0x600000 = bufferedSocket |
77 |
socket_->setSocketFlags( 0x00 ); // 0x00 = anySocket | 0x600000 = bufferedSocket |
78 |
socket_->setTimeout( 30 ); |
79 |
socket_->enableRead( true ); |
80 |
connect( socket_, SIGNAL( readyRead() ), |
81 |
this, SLOT ( dataReceived() ) ); |
82 |
connect( socket_, SIGNAL( connectionFailed(int) ), |
83 |
this, SLOT ( socketError(int) ) ); |
84 |
} |
85 |
|
86 |
|
87 |
|
88 |
// The destructor |
89 |
SslLoginHandler::~SslLoginHandler() |
90 |
{ |
91 |
delete ssl_; |
92 |
delete socket_; |
93 |
} |
94 |
|
95 |
|
96 |
|
97 |
// Data was received over the socket |
98 |
void SslLoginHandler::dataReceived() |
99 |
{ |
100 |
#ifdef KMESSDEBUG_SSLLOGINHANDLER |
101 |
kdDebug() << "SslLoginHandler - ******************** Data received ********************" << endl; |
102 |
kdDebug() << "SslLoginHandler - " << socket_->bytesAvailable() << " bytes available." << endl; |
103 |
kdDebug() << "SslLoginHandler - SSL says " << ssl_->pending() << " bytes available." << endl; |
104 |
#endif |
105 |
|
106 |
QString data; |
107 |
int breakOut = 0; |
108 |
const int maxIterations = 1000; |
109 |
while ( ( !data.contains( QRegExp("\r\n") ) ) && ( breakOut < maxIterations ) ) |
110 |
{ |
111 |
// Read data via SSL |
112 |
data = readSslData(); |
113 |
breakOut ++; |
114 |
} |
115 |
|
116 |
// Output the data for debugging |
117 |
#ifdef KMESSDEBUG_SSLLOGINHANDLER |
118 |
kdDebug() << "SslLoginHandler - ******************** Contents ********************" << endl; |
119 |
kdDebug() << data << endl; |
120 |
kdDebug() << "SslLoginHandler - ******************** End of data ********************" << endl; |
121 |
#endif |
122 |
|
123 |
// Warn if timed out |
124 |
if ( breakOut >= maxIterations ) |
125 |
{ |
126 |
kdDebug() << "WARNING - SSL read timed out." << endl; |
127 |
emit loginFailed(); |
128 |
return; |
129 |
} |
130 |
|
131 |
if ( data.length() > 0 ) |
132 |
{ |
133 |
parseHttpResponse(data); |
134 |
} |
135 |
else |
136 |
{ |
137 |
kdDebug() << "WARNING - Available data wasn't read from the SSL socket." << endl; |
138 |
emit loginFailed(); |
139 |
} |
140 |
} |
141 |
|
142 |
|
143 |
|
144 |
// Start the login process |
145 |
void SslLoginHandler::login( QString parameters, QString handle, QString password ) |
146 |
{ |
147 |
#ifdef KMESSDEBUG_SSLLOGINHANDLER |
148 |
kdDebug() << "SslLoginHandler - Starting login with parameters " << parameters << "." << endl; |
149 |
#endif |
150 |
|
151 |
// Store the given data |
152 |
authenticationParameters_ = parameters; |
153 |
handle_ = handle; |
154 |
password_ = password; |
155 |
|
156 |
// Get the login server |
157 |
sendLoginServerRequest("nexus.passport.com"); |
158 |
dataReceived(); |
159 |
} |
160 |
|
161 |
|
162 |
|
163 |
// Get the authentication data from a string |
164 |
void SslLoginHandler::parseAuthenticationData( QString data ) |
165 |
{ |
166 |
QString twnData; |
167 |
|
168 |
// Pull TWN data out of the message |
169 |
twnData = data.right( data.length() - data.find(QRegExp("from-PP='")) - 9 ); |
170 |
twnData = twnData.left( twnData.find(QRegExp("',")) ); |
171 |
|
172 |
#ifdef KMESSDEBUG_SSLLOGINHANDLER |
173 |
kdDebug() << "SslLoginHandler - data for TWN is " << twnData << "." << endl; |
174 |
#endif |
175 |
|
176 |
// Notify the MsnNotificationConnection |
177 |
emit loginSucceeded(twnData); |
178 |
} |
179 |
|
180 |
|
181 |
|
182 |
// Parse the HTTP response from the server |
183 |
void SslLoginHandler::parseHttpResponse(QString data) |
184 |
{ |
185 |
KURL location; |
186 |
int headerEnd; |
187 |
QString header; |
188 |
int headerCode; |
189 |
QString headerText; |
190 |
|
191 |
// Parse the HTTP status header |
192 |
QRegExp re("HTTP/\\d+\\.\\d+ (\\d+) ([^\r\n]+)"); |
193 |
headerEnd = data.find("\r\n"); |
194 |
header = data.left( (headerEnd == -1) ? 20 : headerEnd ); |
195 |
|
196 |
re.search(header); |
197 |
headerCode = re.cap(1).toUInt(); |
198 |
headerText = re.cap(2); |
199 |
|
200 |
// Create a MimeMessage, removing the HTTP status header |
201 |
MimeMessage message( data.section( ",", 1 ) ); |
202 |
|
203 |
|
204 |
switch(mode_) |
205 |
{ |
206 |
case GETLOGINSERVER: |
207 |
{ |
208 |
// Step 1. This data describes the login server to use. |
209 |
if(headerCode == 302) |
210 |
{ |
211 |
// HTTP Redirect |
212 |
location = KURL( message.getValue( "Location" ) ); |
213 |
sendLoginServerRequest(location.host()); |
214 |
} |
215 |
else |
216 |
{ |
217 |
// Parse the data |
218 |
QString loginServer; |
219 |
QString page; |
220 |
parseLoginServerData( loginServer, page, message.getValue("PassportURLs") ); |
221 |
|
222 |
// Send the authentication request |
223 |
sendAuthenticationRequest( loginServer, page ); |
224 |
} |
225 |
break; |
226 |
} |
227 |
case GETAUTHENTICATIONDATA: |
228 |
{ |
229 |
// Step 2. Get the authentication data |
230 |
if(headerCode == 200) |
231 |
{ |
232 |
// Login success |
233 |
parseAuthenticationData(message.getValue("Authentication-Info")); |
234 |
} |
235 |
else if(headerCode == 302) |
236 |
{ |
237 |
// HTTP Redirect |
238 |
location = KURL( message.getValue( "Location" ) ); |
239 |
sendAuthenticationRequest(location.host(), location.path()); |
240 |
} |
241 |
else if(headerCode == 401) |
242 |
{ |
243 |
// Got a HTTP "401 Unauthorized"; Login failed |
244 |
emit loginIncorrect(); |
245 |
} |
246 |
else |
247 |
{ |
248 |
kdDebug() << "SslLoginHandler::parseHttpResponse: WARNING " |
249 |
<< "- Unhandled response code " << headerCode << " " << headerText << endl; |
250 |
emit loginFailed(); |
251 |
} |
252 |
break; |
253 |
} |
254 |
default: |
255 |
{ |
256 |
kdDebug() << "SslLoginHandler::parseHttpResponse: WARNING - Entered illegal state" << endl; |
257 |
emit loginFailed(); |
258 |
} |
259 |
} |
260 |
} |
261 |
|
262 |
|
263 |
// Get login server data from a string |
264 |
void SslLoginHandler::parseLoginServerData( QString &host, QString &page, QString serverData ) |
265 |
{ |
266 |
int slashIndex; |
267 |
|
268 |
// Get everything between "DLLogin=" and to the comma. |
269 |
serverData = serverData.right( serverData.length() - serverData.find( "DALogin=" ) - 8 ); |
270 |
serverData = serverData.left( serverData.find( "," ) ); |
271 |
|
272 |
#ifdef KMESSDEBUG_SSLLOGINHANDLER |
273 |
kdDebug() << "SslLoginHandler - host/page=" << serverData << endl; |
274 |
#endif |
275 |
|
276 |
// Separate the "host/page" string. |
277 |
slashIndex = serverData.find( "/" ); |
278 |
host = serverData.left( slashIndex ); |
279 |
page = serverData.right( serverData.length() - slashIndex ); |
280 |
|
281 |
#ifdef KMESSDEBUG_SSLLOGINHANDLER |
282 |
kdDebug() << "SslLoginHandler - host=" << host << " page=" << page << endl; |
283 |
#endif |
284 |
} |
285 |
|
286 |
|
287 |
|
288 |
// Read data from the socket via SSL |
289 |
QString SslLoginHandler::readSslData() |
290 |
{ |
291 |
char rawblock[1024]; |
292 |
QCString block; |
293 |
QString data = ""; |
294 |
int noBytesRead = 1; |
295 |
|
296 |
// Read data from the SSL socket. |
297 |
if ( ssl_ != 0 ) |
298 |
{ |
299 |
// while( ( ssl_->pending() > 0 ) && ( noBytesRead > 0 ) ) |
300 |
// while( ( socket_->bytesAvailable() > 0 ) && ( noBytesRead > 0 ) ) |
301 |
while(noBytesRead > 0) |
302 |
{ |
303 |
noBytesRead = ssl_->read( rawblock, 1024 ); |
304 |
#ifdef KMESSDEBUG_SSLLOGINHANDLER |
305 |
kdDebug() << "SslLoginHandler - " << noBytesRead << " bytes read." << endl; |
306 |
#endif |
307 |
block = rawblock; |
308 |
block = block.left( noBytesRead ); |
309 |
data += QString::fromUtf8( block ); |
310 |
} |
311 |
} |
312 |
|
313 |
return data; |
314 |
} |
315 |
|
316 |
|
317 |
|
318 |
// Send the authenticationn request |
319 |
void SslLoginHandler::sendAuthenticationRequest( QString loginServer, QString page ) |
320 |
{ |
321 |
#ifdef KMESSDEBUG_SSLLOGINHANDLER |
322 |
kdDebug() << "SslLoginHandler - Step 2. Requesting authentication data." << endl; |
323 |
#endif |
324 |
|
325 |
QString request; |
326 |
QString encodedHandle = handle_; |
327 |
QString encodedPassword = password_; |
328 |
|
329 |
QUrl::encode(encodedHandle); |
330 |
QUrl::encode(encodedPassword); |
331 |
|
332 |
request = "GET " + page + " HTTP/1.1\r\n" |
333 |
"Authorization: Passport1.4" |
334 |
" OrgVerb=GET" |
335 |
",OrgURL=http%3A%2F%2Fmessenger%2Emsn%2Ecom" |
336 |
",sign-in=" + encodedHandle + |
337 |
",pwd=" + encodedPassword + |
338 |
"," + authenticationParameters_ + "\r\n" |
339 |
"User-Agent: MSMSGS\r\n" // Make sure the server won't discriminate |
340 |
"Host: " + loginServer + "\r\n" |
341 |
"Connection: Keep-Alive\r\n" |
342 |
"Cache-Control: no-cache\r\n\r\n"; |
343 |
|
344 |
// Step 2. Send the authorisation request |
345 |
mode_ = GETAUTHENTICATIONDATA; |
346 |
sendHttpRequest( request, loginServer, 443 ); |
347 |
} |
348 |
|
349 |
|
350 |
|
351 |
// Send a HTTP request to the server |
352 |
void SslLoginHandler::sendHttpRequest( QString request, QString host, int port ) |
353 |
{ |
354 |
QString response; |
355 |
QString responseBody; |
356 |
|
357 |
if ( socket_ == 0 ) |
358 |
{ |
359 |
kdDebug() << "SslLoginHandler::sendHttpRequest - WARNING " |
360 |
<< "- Trying to login using a null socket." << endl; |
361 |
return; |
362 |
} |
363 |
|
364 |
// Configure the socket |
365 |
#ifdef KMESSDEBUG_SSLLOGINHANDLER |
366 |
kdDebug() << "SslLoginHandler - Close and reset the socket." << endl; |
367 |
#endif |
368 |
ssl_->setAutoReconfig( true ); |
369 |
ssl_->reInitialize(); |
370 |
socket_->closeNow(); |
371 |
socket_->reset(); |
372 |
|
373 |
// Try to connect |
374 |
#ifdef KMESSDEBUG_SSLLOGINHANDLER |
375 |
kdDebug() << "SslLoginHandler - Connecting to " << host << ":" << port << "." << endl; |
376 |
#endif |
377 |
socket_->setAddress( host, port ); |
378 |
socket_->lookup(); |
379 |
int connectionSuccess = socket_->connect(); |
380 |
if ( connectionSuccess != 0 ) |
381 |
{ |
382 |
kdDebug() << "SslLoginHandler::sendHttpRequest - WARNING " |
383 |
<< "- Connection failed, giving " << connectionSuccess << endl; |
384 |
return; |
385 |
} |
386 |
|
387 |
// Try to wrap the SSL handler |
388 |
#ifdef KMESSDEBUG_SSLLOGINHANDLER |
389 |
kdDebug() << "SslLoginHandler - Connection success, binding SSL to socket fd " << socket_->fd() << endl; |
390 |
#endif |
391 |
int sslConnectionSuccess = ssl_->connect( socket_->fd() ); |
392 |
if ( sslConnectionSuccess != 1 ) |
393 |
{ |
394 |
kdDebug() << "SslLoginHandler::sendHttpRequest - WARNING " |
395 |
<< "- SSL Connection failed, giving " << sslConnectionSuccess << endl; |
396 |
return; |
397 |
} |
398 |
|
399 |
// Send the request |
400 |
#ifdef KMESSDEBUG_SSLLOGINHANDLER |
401 |
kdDebug() << "SslLoginHandler - SSL connected OK, sending the request." << endl; |
402 |
kdDebug() << request; |
403 |
#endif |
404 |
writeSslData( request ); |
405 |
} |
406 |
|
407 |
|
408 |
|
409 |
// Request the name of the login server |
410 |
void SslLoginHandler::sendLoginServerRequest(QString hostname) |
411 |
{ |
412 |
#ifdef KMESSDEBUG_SSLLOGINHANDLER |
413 |
kdDebug() << "SslLoginHandler - Step 1. Requesting the login server." << endl; |
414 |
#endif |
415 |
|
416 |
// Step 1. Send the login server request |
417 |
// The server will respond with the location of the main SSL server. |
418 |
mode_ = GETLOGINSERVER; |
419 |
sendHttpRequest( "GET /rdr/pprdr.asp\r\n\r\n", hostname, 443 ); |
420 |
} |
421 |
|
422 |
|
423 |
|
424 |
// Detect a socket error |
425 |
void SslLoginHandler::socketError(int error) |
426 |
{ |
427 |
kdDebug() << "SslLoginHandler : WARNING - Received error " << error << " from the socket." << endl; |
428 |
} |
429 |
|
430 |
|
431 |
|
432 |
// Write data to the socket via SSL |
433 |
void SslLoginHandler::writeSslData( QString data ) |
434 |
{ |
435 |
int noBytesWritten; |
436 |
|
437 |
if(socket_ != 0 && ssl_ != 0) |
438 |
{ |
439 |
noBytesWritten = ssl_->write( data.latin1(), data.length() ); |
440 |
if(noBytesWritten != (int)data.length()) |
441 |
{ |
442 |
kdDebug() << "WARNING - Wanted to write " << data.length() << " to the socket, " |
443 |
<< " wrote " << noBytesWritten << "." << endl; |
444 |
} |
445 |
#ifdef KMESSDEBUG_SSLLOGINHANDLER |
446 |
else |
447 |
{ |
448 |
kdDebug() << "SslLoginHandler - Sent " << noBytesWritten << " bytes via SSL." << endl; |
449 |
} |
450 |
#endif |
451 |
} |
452 |
} |
453 |
|