You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
154 lines
5.1 KiB
154 lines
5.1 KiB
/*
|
|
smpppdunsettled.cpp
|
|
|
|
Copyright (c) 2006 by Heiko Schaefer <heiko@rangun.de>
|
|
|
|
Kopete (c) 2002-2006 by the Kopete developers <kopete-devel@kde.org>
|
|
|
|
*************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; version 2 of the License. *
|
|
* *
|
|
*************************************************************************
|
|
*/
|
|
|
|
#include <cstdlib>
|
|
#include <openssl/md5.h>
|
|
|
|
#include <qregexp.h>
|
|
|
|
#include <kdebug.h>
|
|
#include <kstreamsocket.h>
|
|
|
|
#include "smpppdready.h"
|
|
#include "smpppdunsettled.h"
|
|
|
|
using namespace SMPPPD;
|
|
|
|
Unsettled * Unsettled::m_instance = NULL;
|
|
|
|
Unsettled::Unsettled() {}
|
|
|
|
Unsettled::~Unsettled() {}
|
|
|
|
Unsettled * Unsettled::instance() {
|
|
if(!m_instance) {
|
|
m_instance = new Unsettled();
|
|
}
|
|
|
|
return m_instance;
|
|
}
|
|
|
|
bool Unsettled::connect(Client * client, const QString& server, uint port) {
|
|
if(!socket(client) ||
|
|
socket(client)->state() != KNetwork::KStreamSocket::Connected ||
|
|
socket(client)->state() != KNetwork::KStreamSocket::Connecting) {
|
|
|
|
QString resolvedServer = server;
|
|
|
|
changeState(client, Ready::instance());
|
|
disconnect(client);
|
|
|
|
// since a lookup on a non-existant host can take a lot of time we
|
|
// try to get the IP of server before and we do the lookup ourself
|
|
KNetwork::KResolver resolver(server);
|
|
resolver.start();
|
|
if(resolver.wait(500)) {
|
|
KNetwork::KResolverResults results = resolver.results();
|
|
if(!results.empty()) {
|
|
QString ip = results[0].address().asInet().ipAddress().toString();
|
|
kdDebug(14312) << k_funcinfo << "Found IP-Address for " << server << ": " << ip << endl;
|
|
resolvedServer = ip;
|
|
} else {
|
|
kdWarning(14312) << k_funcinfo << "No IP-Address found for " << server << endl;
|
|
return false;
|
|
}
|
|
} else {
|
|
kdWarning(14312) << k_funcinfo << "Looking up hostname timed out, consider to use IP or correct host" << endl;
|
|
return false;
|
|
}
|
|
|
|
setSocket(client, new KNetwork::KStreamSocket(resolvedServer, QString::number(port)));
|
|
socket(client)->setBlocking(TRUE);
|
|
|
|
if(!socket(client)->connect()) {
|
|
kdDebug(14312) << k_funcinfo << "Socket Error: " << KNetwork::KStreamSocket::errorString(socket(client)->error()) << endl;
|
|
} else {
|
|
kdDebug(14312) << k_funcinfo << "Successfully connected to smpppd \"" << server << ":" << port << "\"" << endl;
|
|
|
|
static QString verRex = "^SuSE Meta pppd \\(smpppd\\), Version (.*)$";
|
|
static QString clgRex = "^challenge = (.*)$";
|
|
|
|
QRegExp ver(verRex);
|
|
QRegExp clg(clgRex);
|
|
|
|
QString response = read(client)[0];
|
|
|
|
if(response != QString::null &&
|
|
ver.exactMatch(response)) {
|
|
setServerID(client, response);
|
|
setServerVersion(client, ver.cap(1));
|
|
changeState(client, Ready::instance());
|
|
return true;
|
|
} else if(response != QString::null &&
|
|
clg.exactMatch(response)) {
|
|
if(password(client) != QString::null) {
|
|
// we are challenged, ok, respond
|
|
write(client, QString("response = %1\n").arg(make_response(clg.cap(1).stripWhiteSpace(), password(client))).latin1());
|
|
response = read(client)[0];
|
|
if(ver.exactMatch(response)) {
|
|
setServerID(client, response);
|
|
setServerVersion(client, ver.cap(1));
|
|
return true;
|
|
} else {
|
|
kdWarning(14312) << k_funcinfo << "SMPPPD responded: " << response << endl;
|
|
changeState(client, Ready::instance());
|
|
disconnect(client);
|
|
}
|
|
} else {
|
|
kdWarning(14312) << k_funcinfo << "SMPPPD requested a challenge, but no password was supplied!" << endl;
|
|
changeState(client, Ready::instance());
|
|
disconnect(client);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
QString Unsettled::make_response(const QString& chex, const QString& password) const {
|
|
|
|
int size = chex.length ();
|
|
if (size & 1)
|
|
return "error";
|
|
size >>= 1;
|
|
|
|
// convert challenge from hex to bin
|
|
QString cbin;
|
|
for (int i = 0; i < size; i++) {
|
|
QString tmp = chex.mid (2 * i, 2);
|
|
cbin.append ((char) strtol (tmp.ascii (), 0, 16));
|
|
}
|
|
|
|
// calculate response
|
|
unsigned char rbin[MD5_DIGEST_LENGTH];
|
|
MD5state_st md5;
|
|
MD5_Init (&md5);
|
|
MD5_Update (&md5, cbin.ascii (), size);
|
|
MD5_Update (&md5, password.ascii(), password.length ());
|
|
MD5_Final (rbin, &md5);
|
|
|
|
// convert response from bin to hex
|
|
QString rhex;
|
|
for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
|
|
char buffer[3];
|
|
snprintf (buffer, 3, "%02x", rbin[i]);
|
|
rhex.append (buffer);
|
|
}
|
|
|
|
return rhex;
|
|
}
|