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.
616 lines
13 KiB
616 lines
13 KiB
#include<tqapplication.h>
|
|
#include<tqtimer.h>
|
|
#include<tqsocket.h>
|
|
#include<tqserversocket.h>
|
|
#include<stdio.h>
|
|
|
|
#ifdef Q_OS_UNIX
|
|
#include<unistd.h>
|
|
#endif
|
|
|
|
#include"base64.h"
|
|
#include"qca.h"
|
|
|
|
#define PROTO_NAME "foo"
|
|
#define PROTO_PORT 8001
|
|
|
|
static TQString prompt(const TQString &s)
|
|
{
|
|
printf("* %s ", s.latin1());
|
|
fflush(stdout);
|
|
char line[256];
|
|
fgets(line, 255, stdin);
|
|
TQString result = line;
|
|
if(result[result.length()-1] == '\n')
|
|
result.truncate(result.length()-1);
|
|
return result;
|
|
}
|
|
|
|
class ClientTest : public TQObject
|
|
{
|
|
TQ_OBJECT
|
|
public:
|
|
ClientTest()
|
|
{
|
|
sock = new TQSocket;
|
|
connect(sock, TQ_SIGNAL(connected()), TQ_SLOT(sock_connected()));
|
|
connect(sock, TQ_SIGNAL(connectionClosed()), TQ_SLOT(sock_connectionClosed()));
|
|
connect(sock, TQ_SIGNAL(readyRead()), TQ_SLOT(sock_readyRead()));
|
|
connect(sock, TQ_SIGNAL(error(int)), TQ_SLOT(sock_error(int)));
|
|
|
|
sasl = new QCA::SASL;
|
|
connect(sasl, TQ_SIGNAL(clientFirstStep(const TQString &, const TQByteArray *)), TQ_SLOT(sasl_clientFirstStep(const TQString &, const TQByteArray *)));
|
|
connect(sasl, TQ_SIGNAL(nextStep(const TQByteArray &)), TQ_SLOT(sasl_nextStep(const TQByteArray &)));
|
|
connect(sasl, TQ_SIGNAL(needParams(bool, bool, bool, bool)), TQ_SLOT(sasl_needParams(bool, bool, bool, bool)));
|
|
connect(sasl, TQ_SIGNAL(authenticated()), TQ_SLOT(sasl_authenticated()));
|
|
connect(sasl, TQ_SIGNAL(readyRead()), TQ_SLOT(sasl_readyRead()));
|
|
connect(sasl, TQ_SIGNAL(readyReadOutgoing(int)), TQ_SLOT(sasl_readyReadOutgoing(int)));
|
|
connect(sasl, TQ_SIGNAL(error(int)), TQ_SLOT(sasl_error(int)));
|
|
}
|
|
|
|
~ClientTest()
|
|
{
|
|
delete sock;
|
|
delete sasl;
|
|
}
|
|
|
|
void start(const TQString &_host, int port, const TQString &user="", const TQString &pass="")
|
|
{
|
|
mode = 0;
|
|
host = _host;
|
|
sock->connectToHost(host, port);
|
|
sasl->setMinimumSSF(0);
|
|
sasl->setMaximumSSF(256);
|
|
|
|
if(!user.isEmpty()) {
|
|
sasl->setUsername(user);
|
|
sasl->setAuthzid(user);
|
|
}
|
|
if(!pass.isEmpty())
|
|
sasl->setPassword(pass);
|
|
}
|
|
|
|
signals:
|
|
void quit();
|
|
|
|
private slots:
|
|
void sock_connected()
|
|
{
|
|
printf("Connected to server. Awaiting mechanism list...\n");
|
|
}
|
|
|
|
void sock_connectionClosed()
|
|
{
|
|
printf("Connection closed by peer.\n");
|
|
quit();
|
|
}
|
|
|
|
void sock_error(int x)
|
|
{
|
|
TQString s;
|
|
if(x == TQSocket::ErrConnectionRefused)
|
|
s = "connection refused or timed out";
|
|
else if(x == TQSocket::ErrHostNotFound)
|
|
s = "host not found";
|
|
else if(x == TQSocket::ErrSocketRead)
|
|
s = "read error";
|
|
|
|
printf("Socket error: %s\n", s.latin1());
|
|
quit();
|
|
}
|
|
|
|
void sock_readyRead()
|
|
{
|
|
if(mode == 2) {
|
|
int avail = sock->bytesAvailable();
|
|
TQByteArray a(avail);
|
|
int n = sock->readBlock(a.data(), a.size());
|
|
a.resize(n);
|
|
printf("Read %d bytes\n", a.size());
|
|
sasl->writeIncoming(a);
|
|
}
|
|
else {
|
|
if(sock->canReadLine()) {
|
|
TQString line = sock->readLine();
|
|
line.truncate(line.length()-1); // chop the newline
|
|
handleLine(line);
|
|
}
|
|
}
|
|
}
|
|
|
|
void sasl_clientFirstStep(const TQString &mech, const TQByteArray *clientInit)
|
|
{
|
|
printf("Choosing mech: %s\n", mech.latin1());
|
|
TQString line = mech;
|
|
if(clientInit) {
|
|
TQCString cs(clientInit->data(), clientInit->size()+1);
|
|
line += ' ';
|
|
line += cs;
|
|
}
|
|
sendLine(line);
|
|
}
|
|
|
|
void sasl_nextStep(const TQByteArray &stepData)
|
|
{
|
|
TQCString cs(stepData.data(), stepData.size()+1);
|
|
TQString line = "C";
|
|
if(!stepData.isEmpty()) {
|
|
line += ',';
|
|
line += cs;
|
|
}
|
|
sendLine(line);
|
|
}
|
|
|
|
void sasl_needParams(bool user, bool authzid, bool pass, bool realm)
|
|
{
|
|
TQString username;
|
|
if(user || authzid)
|
|
username = prompt("Username:");
|
|
if(user) {
|
|
sasl->setUsername(username);
|
|
}
|
|
if(authzid) {
|
|
sasl->setAuthzid(username);
|
|
}
|
|
if(pass) {
|
|
sasl->setPassword(prompt("Password (not hidden!) :"));
|
|
}
|
|
if(realm) {
|
|
sasl->setRealm(prompt("Realm:"));
|
|
}
|
|
sasl->continueAfterParams();
|
|
}
|
|
|
|
void sasl_authenticated()
|
|
{
|
|
printf("SASL success!\n");
|
|
printf("SSF: %d\n", sasl->ssf());
|
|
}
|
|
|
|
void sasl_readyRead()
|
|
{
|
|
TQByteArray a = sasl->read();
|
|
int oldsize = inbuf.size();
|
|
inbuf.resize(oldsize + a.size());
|
|
memcpy(inbuf.data() + oldsize, a.data(), a.size());
|
|
processInbuf();
|
|
}
|
|
|
|
void sasl_readyReadOutgoing(int)
|
|
{
|
|
TQByteArray a = sasl->readOutgoing();
|
|
sock->writeBlock(a.data(), a.size());
|
|
}
|
|
|
|
void sasl_error(int)
|
|
{
|
|
printf("SASL error!\n");
|
|
quit();
|
|
return;
|
|
}
|
|
|
|
private:
|
|
TQSocket *sock;
|
|
QCA::SASL *sasl;
|
|
int mode;
|
|
TQString host;
|
|
TQByteArray inbuf;
|
|
|
|
void processInbuf()
|
|
{
|
|
TQStringList list;
|
|
for(int n = 0; n < (int)inbuf.size(); ++n) {
|
|
if(inbuf[n] == '\n') {
|
|
TQCString cs(inbuf.data(), n+1);
|
|
char *p = inbuf.data();
|
|
++n;
|
|
int x = inbuf.size() - n;
|
|
memmove(p, p + n, x);
|
|
inbuf.resize(x);
|
|
list += TQString::fromUtf8(cs);
|
|
// start over, basically
|
|
n = -1;
|
|
}
|
|
}
|
|
|
|
for(TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it)
|
|
handleLine(*it);
|
|
}
|
|
|
|
void handleLine(const TQString &line)
|
|
{
|
|
printf("Reading: [%s]\n", line.latin1());
|
|
if(mode == 0) {
|
|
// first line is the method list
|
|
TQStringList mechlist = TQStringList::split(' ', line);
|
|
++mode;
|
|
|
|
// kick off the client
|
|
sasl->setAllowAnonymous(false);
|
|
if(!sasl->startClient(PROTO_NAME, host, mechlist)) {
|
|
printf("Error starting client!\n");
|
|
quit();
|
|
}
|
|
}
|
|
else if(mode == 1) {
|
|
TQString type, rest;
|
|
int n = line.find(',');
|
|
if(n != -1) {
|
|
type = line.mid(0, n);
|
|
rest = line.mid(n+1);
|
|
}
|
|
else {
|
|
type = line;
|
|
rest = "";
|
|
}
|
|
|
|
if(type == "C") {
|
|
TQCString cs = rest.latin1();
|
|
TQByteArray buf(cs.length());
|
|
memcpy(buf.data(), cs.data(), buf.size());
|
|
sasl->putStep(buf);
|
|
}
|
|
else if(type == "E") {
|
|
printf("Authentication failed.\n");
|
|
quit();
|
|
return;
|
|
}
|
|
else if(type == "A") {
|
|
printf("Authentication success.\n");
|
|
++mode;
|
|
sock_readyRead(); // any extra data?
|
|
return;
|
|
}
|
|
else {
|
|
printf("Bad format from peer, closing.\n");
|
|
quit();
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
}
|
|
}
|
|
|
|
void sendLine(const TQString &line)
|
|
{
|
|
printf("Writing: {%s}\n", line.latin1());
|
|
TQString s = line + '\n';
|
|
TQCString cs = s.latin1();
|
|
if(mode == 2) {
|
|
TQByteArray a(cs.length());
|
|
memcpy(a.data(), cs.data(), a.size());
|
|
sasl->write(a);
|
|
}
|
|
else
|
|
sock->writeBlock(cs.data(), cs.length());
|
|
}
|
|
};
|
|
|
|
class ServerTest : public QServerSocket
|
|
{
|
|
TQ_OBJECT
|
|
public:
|
|
ServerTest(const TQString &_str, int _port) : QServerSocket(_port), port(_port)
|
|
{
|
|
sock = 0;
|
|
sasl = 0;
|
|
realm = TQString::null;
|
|
str = _str;
|
|
}
|
|
|
|
~ServerTest()
|
|
{
|
|
delete sock;
|
|
delete sasl;
|
|
}
|
|
|
|
void start()
|
|
{
|
|
if(!ok()) {
|
|
printf("Error binding to port %d!\n", port);
|
|
TQTimer::singleShot(0, this, TQ_SIGNAL(quit()));
|
|
return;
|
|
}
|
|
char myhostname[256];
|
|
int r = gethostname(myhostname, sizeof(myhostname)-1);
|
|
if(r == -1) {
|
|
printf("Error getting hostname!\n");
|
|
TQTimer::singleShot(0, this, TQ_SIGNAL(quit()));
|
|
return;
|
|
}
|
|
host = myhostname;
|
|
printf("Listening on %s:%d ...\n", host.latin1(), port);
|
|
}
|
|
|
|
void newConnection(int s)
|
|
{
|
|
// Note: only 1 connection supported at a time in this example!
|
|
if(sock) {
|
|
TQSocket tmp;
|
|
tmp.setSocket(s);
|
|
printf("Connection ignored, already have one active.\n");
|
|
return;
|
|
}
|
|
|
|
printf("Connection received! Starting SASL handshake...\n");
|
|
|
|
sock = new TQSocket;
|
|
connect(sock, TQ_SIGNAL(connectionClosed()), TQ_SLOT(sock_connectionClosed()));
|
|
connect(sock, TQ_SIGNAL(readyRead()), TQ_SLOT(sock_readyRead()));
|
|
connect(sock, TQ_SIGNAL(error(int)), TQ_SLOT(sock_error(int)));
|
|
connect(sock, TQ_SIGNAL(bytesWritten(int)), TQ_SLOT(sock_bytesWritten(int)));
|
|
|
|
sasl = new QCA::SASL;
|
|
connect(sasl, TQ_SIGNAL(authCheck(const TQString &, const TQString &)), TQ_SLOT(sasl_authCheck(const TQString &, const TQString &)));
|
|
connect(sasl, TQ_SIGNAL(nextStep(const TQByteArray &)), TQ_SLOT(sasl_nextStep(const TQByteArray &)));
|
|
connect(sasl, TQ_SIGNAL(authenticated()), TQ_SLOT(sasl_authenticated()));
|
|
connect(sasl, TQ_SIGNAL(readyRead()), TQ_SLOT(sasl_readyRead()));
|
|
connect(sasl, TQ_SIGNAL(readyReadOutgoing(int)), TQ_SLOT(sasl_readyReadOutgoing(int)));
|
|
connect(sasl, TQ_SIGNAL(error(int)), TQ_SLOT(sasl_error(int)));
|
|
|
|
sock->setSocket(s);
|
|
mode = 0;
|
|
inbuf.resize(0);
|
|
|
|
sasl->setMinimumSSF(0);
|
|
sasl->setMaximumSSF(256);
|
|
|
|
TQStringList mechlist;
|
|
if(!sasl->startServer(PROTO_NAME, host, realm, &mechlist)) {
|
|
printf("Error starting server!\n");
|
|
quit();
|
|
}
|
|
TQString str;
|
|
bool first = true;
|
|
for(TQStringList::ConstIterator it = mechlist.begin(); it != mechlist.end(); ++it) {
|
|
if(!first)
|
|
str += ' ';
|
|
str += *it;
|
|
first = false;
|
|
}
|
|
sendLine(str);
|
|
}
|
|
|
|
signals:
|
|
void quit();
|
|
|
|
private slots:
|
|
void sock_connectionClosed()
|
|
{
|
|
printf("Connection closed by peer.\n");
|
|
close();
|
|
}
|
|
|
|
void sock_error(int x)
|
|
{
|
|
TQString s;
|
|
if(x == TQSocket::ErrConnectionRefused)
|
|
s = "connection refused or timed out";
|
|
else if(x == TQSocket::ErrHostNotFound)
|
|
s = "host not found";
|
|
else if(x == TQSocket::ErrSocketRead)
|
|
s = "read error";
|
|
|
|
printf("Socket error: %s\n", s.latin1());
|
|
close();
|
|
}
|
|
|
|
void sock_readyRead()
|
|
{
|
|
if(sock->canReadLine()) {
|
|
TQString line = sock->readLine();
|
|
line.truncate(line.length()-1); // chop the newline
|
|
handleLine(line);
|
|
}
|
|
}
|
|
|
|
void sock_bytesWritten(int x)
|
|
{
|
|
if(mode == 2) {
|
|
toWrite -= x;
|
|
if(toWrite <= 0) {
|
|
printf("Sent, closing.\n");
|
|
close();
|
|
}
|
|
}
|
|
}
|
|
|
|
void sasl_nextStep(const TQByteArray &stepData)
|
|
{
|
|
TQCString cs(stepData.data(), stepData.size()+1);
|
|
TQString line = "C";
|
|
if(!stepData.isEmpty()) {
|
|
line += ',';
|
|
line += cs;
|
|
}
|
|
sendLine(line);
|
|
}
|
|
|
|
void sasl_authCheck(const TQString &user, const TQString &authzid)
|
|
{
|
|
printf("AuthCheck: User: [%s], Authzid: [%s]\n", user.latin1(), authzid.latin1());
|
|
sasl->continueAfterAuthCheck();
|
|
}
|
|
|
|
void sasl_authenticated()
|
|
{
|
|
sendLine("A");
|
|
printf("Authentication success.\n");
|
|
++mode;
|
|
printf("SSF: %d\n", sasl->ssf());
|
|
sendLine(str);
|
|
}
|
|
|
|
void sasl_readyRead()
|
|
{
|
|
TQByteArray a = sasl->read();
|
|
int oldsize = inbuf.size();
|
|
inbuf.resize(oldsize + a.size());
|
|
memcpy(inbuf.data() + oldsize, a.data(), a.size());
|
|
processInbuf();
|
|
}
|
|
|
|
void sasl_readyReadOutgoing(int)
|
|
{
|
|
TQByteArray a = sasl->readOutgoing();
|
|
toWrite = a.size();
|
|
sock->writeBlock(a.data(), a.size());
|
|
}
|
|
|
|
void sasl_error(int x)
|
|
{
|
|
if(x == QCA::SASL::ErrAuth) {
|
|
sendLine("E");
|
|
printf("Authentication failed.\n");
|
|
close();
|
|
}
|
|
else {
|
|
printf("SASL security layer error!\n");
|
|
close();
|
|
}
|
|
}
|
|
|
|
private:
|
|
TQSocket *sock;
|
|
QCA::SASL *sasl;
|
|
TQString host, realm;
|
|
int port;
|
|
int mode;
|
|
TQString str;
|
|
TQByteArray inbuf;
|
|
int toWrite;
|
|
|
|
void processInbuf()
|
|
{
|
|
}
|
|
|
|
void handleLine(const TQString &line)
|
|
{
|
|
printf("Reading: [%s]\n", line.latin1());
|
|
if(mode == 0) {
|
|
int n = line.find(' ');
|
|
if(n != -1) {
|
|
TQString mech = line.mid(0, n);
|
|
TQCString cs = line.mid(n+1).latin1();
|
|
TQByteArray clientInit(cs.length());
|
|
memcpy(clientInit.data(), cs.data(), clientInit.size());
|
|
sasl->putServerFirstStep(mech, clientInit);
|
|
}
|
|
else
|
|
sasl->putServerFirstStep(line);
|
|
++mode;
|
|
}
|
|
else if(mode == 1) {
|
|
TQString type, rest;
|
|
int n = line.find(',');
|
|
if(n != -1) {
|
|
type = line.mid(0, n);
|
|
rest = line.mid(n+1);
|
|
}
|
|
else {
|
|
type = line;
|
|
rest = "";
|
|
}
|
|
|
|
if(type == "C") {
|
|
TQCString cs = rest.latin1();
|
|
TQByteArray buf(cs.length());
|
|
memcpy(buf.data(), cs.data(), buf.size());
|
|
sasl->putStep(buf);
|
|
}
|
|
else {
|
|
printf("Bad format from peer, closing.\n");
|
|
close();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void sendLine(const TQString &line)
|
|
{
|
|
printf("Writing: {%s}\n", line.latin1());
|
|
TQString s = line + '\n';
|
|
TQCString cs = s.latin1();
|
|
if(mode == 2) {
|
|
TQByteArray a(cs.length());
|
|
memcpy(a.data(), cs.data(), a.size());
|
|
sasl->write(a);
|
|
}
|
|
else
|
|
sock->writeBlock(cs.data(), cs.length());
|
|
}
|
|
|
|
void close()
|
|
{
|
|
sock->deleteLater();
|
|
sock = 0;
|
|
delete sasl;
|
|
sasl = 0;
|
|
}
|
|
};
|
|
|
|
#include"sasltest.moc"
|
|
|
|
void usage()
|
|
{
|
|
printf("usage: sasltest client [host] [user] [pass]\n");
|
|
printf(" sasltest server [string]\n\n");
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
TQApplication app(argc, argv, false);
|
|
|
|
TQString host, user, pass;
|
|
TQString str = "Hello, World";
|
|
bool server;
|
|
if(argc < 2) {
|
|
usage();
|
|
return 0;
|
|
}
|
|
TQString arg = argv[1];
|
|
if(arg == "client") {
|
|
if(argc < 3) {
|
|
usage();
|
|
return 0;
|
|
}
|
|
host = argv[2];
|
|
if(argc >= 4)
|
|
user = argv[3];
|
|
if(argc >= 5)
|
|
pass = argv[4];
|
|
server = false;
|
|
}
|
|
else if(arg == "server") {
|
|
if(argc >= 3)
|
|
str = argv[2];
|
|
server = true;
|
|
}
|
|
else {
|
|
usage();
|
|
return 0;
|
|
}
|
|
|
|
if(!QCA::isSupported(QCA::CAP_SASL)) {
|
|
printf("SASL not supported!\n");
|
|
return 1;
|
|
}
|
|
|
|
if(server) {
|
|
ServerTest *s = new ServerTest(str, PROTO_PORT);
|
|
TQObject::connect(s, TQ_SIGNAL(quit()), &app, TQ_SLOT(quit()));
|
|
s->start();
|
|
app.exec();
|
|
delete s;
|
|
}
|
|
else {
|
|
ClientTest *c = new ClientTest;
|
|
TQObject::connect(c, TQ_SIGNAL(quit()), &app, TQ_SLOT(quit()));
|
|
c->start(host, PROTO_PORT, user, pass);
|
|
app.exec();
|
|
delete c;
|
|
}
|
|
|
|
return 0;
|
|
}
|