summaryrefslogtreecommitdiffstats
path: root/examples/sasltest/sasltest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'examples/sasltest/sasltest.cpp')
-rw-r--r--examples/sasltest/sasltest.cpp615
1 files changed, 615 insertions, 0 deletions
diff --git a/examples/sasltest/sasltest.cpp b/examples/sasltest/sasltest.cpp
new file mode 100644
index 0000000..dd4f858
--- /dev/null
+++ b/examples/sasltest/sasltest.cpp
@@ -0,0 +1,615 @@
+#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
+{
+ Q_OBJECT
+public:
+ ClientTest()
+ {
+ sock = new TQSocket;
+ connect(sock, SIGNAL(connected()), SLOT(sock_connected()));
+ connect(sock, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed()));
+ connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead()));
+ connect(sock, SIGNAL(error(int)), SLOT(sock_error(int)));
+
+ sasl = new QCA::SASL;
+ connect(sasl, SIGNAL(clientFirstStep(const TQString &, const TQByteArray *)), SLOT(sasl_clientFirstStep(const TQString &, const TQByteArray *)));
+ connect(sasl, SIGNAL(nextStep(const TQByteArray &)), SLOT(sasl_nextStep(const TQByteArray &)));
+ connect(sasl, SIGNAL(needParams(bool, bool, bool, bool)), SLOT(sasl_needParams(bool, bool, bool, bool)));
+ connect(sasl, SIGNAL(authenticated()), SLOT(sasl_authenticated()));
+ connect(sasl, SIGNAL(readyRead()), SLOT(sasl_readyRead()));
+ connect(sasl, SIGNAL(readyReadOutgoing(int)), SLOT(sasl_readyReadOutgoing(int)));
+ connect(sasl, SIGNAL(error(int)), 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
+{
+ Q_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);
+ TTQTimer::singleShot(0, this, SIGNAL(quit()));
+ return;
+ }
+ char myhostname[256];
+ int r = gethostname(myhostname, sizeof(myhostname)-1);
+ if(r == -1) {
+ printf("Error getting hostname!\n");
+ TTQTimer::singleShot(0, this, 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, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed()));
+ connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead()));
+ connect(sock, SIGNAL(error(int)), SLOT(sock_error(int)));
+ connect(sock, SIGNAL(bytesWritten(int)), SLOT(sock_bytesWritten(int)));
+
+ sasl = new QCA::SASL;
+ connect(sasl, SIGNAL(authCheck(const TQString &, const TQString &)), SLOT(sasl_authCheck(const TQString &, const TQString &)));
+ connect(sasl, SIGNAL(nextStep(const TQByteArray &)), SLOT(sasl_nextStep(const TQByteArray &)));
+ connect(sasl, SIGNAL(authenticated()), SLOT(sasl_authenticated()));
+ connect(sasl, SIGNAL(readyRead()), SLOT(sasl_readyRead()));
+ connect(sasl, SIGNAL(readyReadOutgoing(int)), SLOT(sasl_readyReadOutgoing(int)));
+ connect(sasl, SIGNAL(error(int)), 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, SIGNAL(quit()), &app, SLOT(quit()));
+ s->start();
+ app.exec();
+ delete s;
+ }
+ else {
+ ClientTest *c = new ClientTest;
+ TQObject::connect(c, SIGNAL(quit()), &app, SLOT(quit()));
+ c->start(host, PROTO_PORT, user, pass);
+ app.exec();
+ delete c;
+ }
+
+ return 0;
+}