00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <QCoreApplication>
00023 #include <QTimer>
00024 #include <QTcpSocket>
00025 #include <QTcpServer>
00026 #include <stdio.h>
00027
00028 #ifdef Q_OS_UNIX
00029 #include <unistd.h>
00030 #endif
00031
00032
00033 #include <QtCrypto>
00034
00035 #define PROTO_NAME "foo"
00036 #define PROTO_PORT 8001
00037
00038 static QString prompt(const QString &s)
00039 {
00040 printf("* %s ", s.toLatin1().data());
00041 fflush(stdout);
00042 char line[256];
00043 fgets(line, 255, stdin);
00044 QString result = line;
00045 if(result[result.length()-1] == '\n')
00046 result.truncate(result.length()-1);
00047 return result;
00048 }
00049
00050 class ClientTest : public QObject
00051 {
00052 Q_OBJECT
00053 public:
00054 ClientTest()
00055 {
00056 sock = new QTcpSocket;
00057 connect(sock, SIGNAL(connected()), SLOT(sock_connected()));
00058 connect(sock, SIGNAL(disconnected()), SLOT(sock_connectionClosed()));
00059 connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead()));
00060 connect(sock, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(sock_error(QAbstractSocket::SocketError)));
00061
00062 sasl = new QCA::SASL;
00063 connect(sasl, SIGNAL(clientStarted(bool, const QByteArray &)), SLOT(sasl_clientFirstStep(bool, const QByteArray &)));
00064 connect(sasl, SIGNAL(nextStep(const QByteArray &)), SLOT(sasl_nextStep(const QByteArray &)));
00065 connect(sasl, SIGNAL(needParams(const QCA::SASL::Params &)), SLOT(sasl_needParams(const QCA::SASL::Params &)));
00066 connect(sasl, SIGNAL(authenticated()), SLOT(sasl_authenticated()));
00067 connect(sasl, SIGNAL(readyRead()), SLOT(sasl_readyRead()));
00068 connect(sasl, SIGNAL(readyReadOutgoing()), SLOT(sasl_readyReadOutgoing()));
00069 connect(sasl, SIGNAL(error()), SLOT(sasl_error()));
00070 }
00071
00072 void start(const QString &_host, int port, const QString &user="", const QString &pass="")
00073 {
00074 mode = 0;
00075 host = _host;
00076 sock->connectToHost(host, port);
00077 sasl->setConstraints((QCA::SASL::AuthFlags)(QCA::SASL::AllowPlain | QCA::SASL::AllowAnonymous), 0, 256);
00078
00079 if(!user.isEmpty()) {
00080 sasl->setUsername(user);
00081 sasl->setAuthzid(user);
00082 }
00083 if(!pass.isEmpty())
00084 sasl->setPassword(pass.toUtf8());
00085 }
00086
00087 ~ClientTest()
00088 {
00089 delete sock;
00090 delete sasl;
00091 }
00092
00093 signals:
00094 void quit();
00095
00096 private slots:
00097 void sock_connected()
00098 {
00099 printf("Connected to server. Awaiting mechanism list...\n");
00100 }
00101
00102 void sock_connectionClosed()
00103 {
00104 printf("Connection closed by peer.\n");
00105 quit();
00106 }
00107
00108 void sock_error(QAbstractSocket::SocketError x)
00109 {
00110 printSocketError(x);
00111 quit();
00112 }
00113
00114 void sock_readyRead()
00115 {
00116 if(mode == 2) {
00117 int avail = sock->bytesAvailable();
00118 QByteArray a(avail, 0);
00119 int n = sock->read(a.data(), a.size());
00120 a.resize(n);
00121 printf("Read %d bytes\n", a.size());
00122 sasl->writeIncoming(a);
00123 }
00124 else {
00125 if(sock->canReadLine()) {
00126 QString line = sock->readLine();
00127 line.truncate(line.length()-1);
00128 handleLine(line);
00129 }
00130 }
00131 }
00132
00133 void sasl_clientFirstStep(bool clientInit, const QByteArray &clientInitData)
00134 {
00135 ++mode;
00136 printf("Choosing mech: %s\n", sasl->mechanism().toLatin1().data());
00137 QString line = sasl->mechanism();
00138 if(clientInit) {
00139 line += ' ';
00140 line += arrayToString(clientInitData);
00141 }
00142 sendLine(line);
00143 }
00144
00145 void sasl_nextStep(const QByteArray &stepData)
00146 {
00147 QString line = "C";
00148 if(!stepData.isEmpty()) {
00149 line += ',';
00150 line += arrayToString(stepData);
00151 }
00152 sendLine(line);
00153 }
00154
00155 void sasl_needParams(const QCA::SASL::Params ¶ms)
00156 {
00157 if(params.needUsername())
00158 sasl->setUsername(prompt("Username:"));
00159 if(params.canSendAuthzid()) {
00160 QString authzid = prompt("Authorize As (enter to skip):");
00161 if(!authzid.isEmpty())
00162 sasl->setAuthzid(authzid);
00163 }
00164 if(params.needPassword()) {
00165 QCA::ConsolePrompt prompt;
00166 prompt.getHidden("* Password");
00167 prompt.waitForFinished();
00168 QCA::SecureArray pass = prompt.result();
00169 sasl->setPassword(pass);
00170 }
00171 if(params.canSendRealm()) {
00172 QStringList realms = sasl->realmList();
00173 printf("Available realms:\n");
00174 foreach(const QString &s, realms)
00175 printf(" %s\n", qPrintable(s));
00176 sasl->setRealm(prompt("Realm:"));
00177 }
00178 sasl->continueAfterParams();
00179 }
00180
00181 void sasl_authenticated()
00182 {
00183 printf("SASL success!\n");
00184 printf("SSF: %d\n", sasl->ssf());
00185 }
00186
00187 void sasl_readyRead()
00188 {
00189 QByteArray a = sasl->read();
00190 int oldsize = inbuf.size();
00191 inbuf.resize(oldsize + a.size());
00192 memcpy(inbuf.data() + oldsize, a.data(), a.size());
00193 processInbuf();
00194 }
00195
00196 void sasl_readyReadOutgoing()
00197 {
00198 QByteArray a = sasl->readOutgoing();
00199 sock->write(a.data(), a.size());
00200 }
00201
00202 void sasl_error()
00203 {
00204 printf("SASL error! Auth Condition = %d.\n", sasl->authCondition());
00205 quit();
00206 return;
00207 }
00208
00209 private:
00210 QTcpSocket *sock;
00211 QCA::SASL *sasl;
00212 int mode;
00213 QString host;
00214 QByteArray inbuf;
00215
00216 QString arrayToString(const QByteArray &ba)
00217 {
00218 QCA::Base64 encoder;
00219 return encoder.arrayToString(ba);
00220 }
00221
00222 QByteArray stringToArray(const QString &s)
00223 {
00224 QCA::Base64 decoder(QCA::Decode);
00225 return decoder.stringToArray(s).toByteArray();
00226 }
00227
00228 void sendLine(const QString &line)
00229 {
00230 printf("Writing: {%s}\n", line.toUtf8().data());
00231 QString s = line + '\n';
00232 QByteArray a = s.toUtf8();
00233 if(mode == 2)
00234 sasl->write(a);
00235 else
00236 sock->write(a.data(), a.length());
00237 }
00238
00239 void printSocketError(QAbstractSocket::SocketError x)
00240 {
00241 QString s;
00242 if(x == QAbstractSocket::ConnectionRefusedError)
00243 s = "connection refused or timed out";
00244 else if(x == QAbstractSocket::RemoteHostClosedError)
00245 s = "remote host closed the connection";
00246 else if(x == QAbstractSocket::HostNotFoundError)
00247 s = "host not found";
00248 else if(x == QAbstractSocket::SocketAccessError)
00249 s = "access error";
00250 else if(x == QAbstractSocket::SocketResourceError)
00251 s = "too many sockets";
00252 else if(x == QAbstractSocket::SocketTimeoutError)
00253 s = "operation timed out";
00254 else if(x == QAbstractSocket::DatagramTooLargeError)
00255 s = "datagram was larger than system limit";
00256 else if(x == QAbstractSocket::NetworkError)
00257 s = "network error";
00258 else if(x == QAbstractSocket::AddressInUseError)
00259 s = "address is already in use";
00260 else if(x == QAbstractSocket::SocketAddressNotAvailableError)
00261 s = "address does not belong to the host";
00262 else if(x == QAbstractSocket::UnsupportedSocketOperationError)
00263 s = "operation is not supported by the local operating system";
00264 else
00265 s = "unknown socket error";
00266 printf("Socket error: %s\n", s.toLatin1().data());
00267 }
00268
00269 void processInbuf()
00270 {
00271 QStringList list;
00272 for(int n = 0; n < (int)inbuf.size(); ++n) {
00273 if(inbuf[n] == '\n') {
00274 list += QString::fromUtf8(inbuf.data(), n);
00275
00276 char *p = inbuf.data();
00277 ++n;
00278 int x = inbuf.size() - n;
00279 memmove(p, p + n, x);
00280 inbuf.resize(x);
00281
00282
00283 n = -1;
00284 }
00285 }
00286
00287 foreach(QString line, list)
00288 handleLine(line);
00289 }
00290
00291 void handleLine(const QString &line)
00292 {
00293 printf("Reading: [%s]\n", line.toLatin1().data());
00294 if(mode == 0) {
00295
00296 QStringList mechlist = line.split(' ');
00297 sasl->startClient(PROTO_NAME, host, mechlist);
00298 }
00299 else if(mode == 1) {
00300 QString type, rest;
00301 int n = line.indexOf(',');
00302 if(n != -1) {
00303 type = line.mid(0, n);
00304 rest = line.mid(n+1);
00305 }
00306 else {
00307 type = line;
00308 rest = "";
00309 }
00310
00311 if(type == "C") {
00312 sasl->putStep(stringToArray(rest));
00313 }
00314 else if(type == "E") {
00315 printf("Authentication failed.\n");
00316 quit();
00317 return;
00318 }
00319 else if(type == "A") {
00320 printf("Authentication success.\n");
00321 ++mode;
00322 sock_readyRead();
00323 return;
00324 }
00325 else {
00326 printf("Bad format from peer, closing.\n");
00327 quit();
00328 return;
00329 }
00330 }
00331 }
00332 };
00333
00334 #include "sasltest.moc"
00335
00336 void usage()
00337 {
00338 printf("usage: sasltest host [user] [pass]\n");
00339 }
00340
00341 int main(int argc, char **argv)
00342 {
00343 QCA::Initializer init;
00344 QCoreApplication app(argc, argv);
00345
00346 QString host, user, pass;
00347 QString str = "Hello, World";
00348 if(argc < 2) {
00349 usage();
00350 return 0;
00351 }
00352 host = argv[1];
00353 if(argc >= 3)
00354 user = argv[2];
00355 if(argc >= 4)
00356 pass = argv[3];
00357
00358 if(!QCA::isSupported("sasl")) {
00359 printf("SASL not supported!\n");
00360 return 1;
00361 }
00362
00363 ClientTest *c = new ClientTest;
00364 QObject::connect(c, SIGNAL(quit()), &app, SLOT(quit()));
00365 c->start(host, PROTO_PORT, user, pass);
00366 app.exec();
00367 delete c;
00368
00369 return 0;
00370 }