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 class ServerTest : public QTcpServer
00039 {
00040 Q_OBJECT
00041 public:
00042 ServerTest(const QString &_str, int _port) : port(_port)
00043 {
00044 sock = 0;
00045 sasl = 0;
00046
00047 connect(this, SIGNAL(newConnection()), SLOT(serv_newConnection()));
00048 realm.clear();
00049 str = _str;
00050 }
00051
00052 ~ServerTest()
00053 {
00054 delete sock;
00055 delete sasl;
00056 }
00057
00058 void start()
00059 {
00060 if(!listen(QHostAddress::Any, port)) {
00061 printf("Error binding to port %d!\n", port);
00062 QTimer::singleShot(0, this, SIGNAL(quit()));
00063 return;
00064 }
00065 char myhostname[256];
00066 int r = gethostname(myhostname, sizeof(myhostname)-1);
00067 if(r == -1) {
00068 printf("Error getting hostname!\n");
00069 QTimer::singleShot(0, this, SIGNAL(quit()));
00070 return;
00071 }
00072 host = myhostname;
00073 printf("Listening on %s:%d ...\n", host.toLatin1().data(), port);
00074 }
00075
00076 private slots:
00077 void serv_newConnection()
00078 {
00079
00080 if(sock) {
00081 delete nextPendingConnection();
00082 printf("Connection ignored, already have one active.\n");
00083 return;
00084 }
00085
00086 printf("Connection received! Starting SASL handshake...\n");
00087
00088 sock = nextPendingConnection();
00089 connect(sock, SIGNAL(disconnected()), SLOT(sock_connectionClosed()));
00090 connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead()));
00091 connect(sock, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(sock_error(QAbstractSocket::SocketError)));
00092 connect(sock, SIGNAL(bytesWritten(qint64)), SLOT(sock_bytesWritten(qint64)));
00093
00094 sasl = new QCA::SASL;
00095 connect(sasl, SIGNAL(authCheck(const QString &, const QString &)), SLOT(sasl_authCheck(const QString &, const QString &)));
00096 connect(sasl, SIGNAL(nextStep(const QByteArray &)), SLOT(sasl_nextStep(const QByteArray &)));
00097 connect(sasl, SIGNAL(authenticated()), SLOT(sasl_authenticated()));
00098 connect(sasl, SIGNAL(readyRead()), SLOT(sasl_readyRead()));
00099 connect(sasl, SIGNAL(readyReadOutgoing()), SLOT(sasl_readyReadOutgoing()));
00100 connect(sasl, SIGNAL(error()), SLOT(sasl_error()));
00101 connect(sasl, SIGNAL(serverStarted()), SLOT(sasl_serverStarted()));
00102
00103 mode = 0;
00104 inbuf.resize(0);
00105
00106 sasl->setConstraints((QCA::SASL::AuthFlags)(QCA::SASL::AllowPlain | QCA::SASL::AllowAnonymous), 0, 256);
00107
00108 sasl->startServer(PROTO_NAME, host, realm);
00109 }
00110
00111 signals:
00112 void quit();
00113
00114 private slots:
00115 void sasl_serverStarted()
00116 {
00117 sendLine(sasl->mechanismList().join(" "));
00118 }
00119
00120 void sock_connectionClosed()
00121 {
00122 printf("Connection closed by peer.\n");
00123 close();
00124 }
00125
00126 void sock_error(QAbstractSocket::SocketError x)
00127 {
00128 printSocketError(x);
00129 close();
00130 }
00131
00132 void sock_readyRead()
00133 {
00134 if(sock->canReadLine()) {
00135 QString line = sock->readLine();
00136 line.truncate(line.length()-1);
00137 handleLine(line);
00138 }
00139 }
00140
00141 void sock_bytesWritten(qint64 x)
00142 {
00143 if(mode == 2) {
00144 toWrite -= x;
00145 if(toWrite <= 0) {
00146 printf("Sent, closing.\n");
00147 close();
00148 }
00149 }
00150 }
00151
00152 void sasl_nextStep(const QByteArray &stepData)
00153 {
00154 QString line = "C";
00155 if(!stepData.isEmpty()) {
00156 line += ',';
00157 line += arrayToString(stepData.data());
00158 }
00159 sendLine(line);
00160 }
00161
00162 void sasl_authCheck(const QString &user, const QString &authzid)
00163 {
00164 printf("AuthCheck: User: [%s], Authzid: [%s]\n", user.toLatin1().data(), authzid.toLatin1().data());
00165 sasl->continueAfterAuthCheck();
00166 }
00167
00168 void sasl_authenticated()
00169 {
00170 sendLine("A");
00171 printf("Authentication success.\n");
00172 ++mode;
00173 printf("SSF: %d\n", sasl->ssf());
00174 sendLine(str);
00175 }
00176
00177 void sasl_readyRead()
00178 {
00179 QByteArray a = sasl->read();
00180 int oldsize = inbuf.size();
00181 inbuf.resize(oldsize + a.size());
00182 memcpy(inbuf.data() + oldsize, a.data(), a.size());
00183 processInbuf();
00184 }
00185
00186 void sasl_readyReadOutgoing()
00187 {
00188 QByteArray a = sasl->readOutgoing();
00189 toWrite = a.size();
00190 sock->write(a.data(), a.size());
00191 }
00192
00193 void sasl_error()
00194 {
00195 QCA::SASL::Error x = sasl->errorCode();
00196 if(x == QCA::SASL::ErrorInit) {
00197 printf("Problem starting up SASL\n");
00198 quit();
00199 }
00200 else if(x == QCA::SASL::ErrorHandshake) {
00201 sendLine("E");
00202 printf("Authentication failed. AuthCondition = %d.\n", sasl->authCondition());
00203 if ( sasl->authCondition() == QCA::SASL::NoUser ) {
00204 printf( "No user!\n" );
00205 }
00206 close();
00207 }
00208 else if(x == QCA::SASL::ErrorCrypt) {
00209 printf("SASL security layer error!\n");
00210 close();
00211 }
00212 }
00213
00214
00215 private:
00216 QString host, realm;
00217 int port;
00218 QString str;
00219 QByteArray inbuf;
00220 int toWrite;
00221 QTcpSocket *sock;
00222 QCA::SASL *sasl;
00223 int mode;
00224
00225
00226 void processInbuf()
00227 {
00228 }
00229
00230 void handleLine(const QString &line)
00231 {
00232 printf("Reading: [%s]\n", line.toLatin1().data());
00233 if(mode == 0) {
00234 int n = line.indexOf(' ');
00235 if(n != -1) {
00236 QString mech = line.mid(0, n);
00237 QString rest = line.mid(n+1).toUtf8();
00238 sasl->putServerFirstStep(mech, stringToArray(rest));
00239 }
00240 else
00241 sasl->putServerFirstStep(line);
00242 ++mode;
00243 }
00244 else if(mode == 1) {
00245 QString type, rest;
00246 int n = line.indexOf(',');
00247 if(n != -1) {
00248 type = line.mid(0, n);
00249 rest = line.mid(n+1);
00250 }
00251 else {
00252 type = line;
00253 rest = "";
00254 }
00255
00256 if(type == "C") {
00257 sasl->putStep(stringToArray(rest));
00258 }
00259 else {
00260 printf("Bad format from peer, closing.\n");
00261 close();
00262 return;
00263 }
00264 }
00265 }
00266
00267 void close()
00268 {
00269 delete sasl;
00270 sock->deleteLater();
00271 sock = 0;
00272 sasl = 0;
00273 }
00274 QString arrayToString(const QByteArray &ba)
00275 {
00276 QCA::Base64 encoder;
00277 return encoder.arrayToString(ba);
00278 }
00279
00280 QByteArray stringToArray(const QString &s)
00281 {
00282 QCA::Base64 decoder(QCA::Decode);
00283 return decoder.stringToArray(s).toByteArray();
00284 }
00285
00286 void sendLine(const QString &line)
00287 {
00288 printf("Writing: {%s}\n", line.toUtf8().data());
00289 QString s = line + '\n';
00290 QByteArray a = s.toUtf8();
00291 if(mode == 2)
00292 sasl->write(a);
00293 else
00294 sock->write(a.data(), a.length());
00295 }
00296
00297 void printSocketError(QAbstractSocket::SocketError x)
00298 {
00299 QString s;
00300 if(x == QAbstractSocket::ConnectionRefusedError)
00301 s = "connection refused or timed out";
00302 else if(x == QAbstractSocket::RemoteHostClosedError)
00303 s = "remote host closed the connection";
00304 else if(x == QAbstractSocket::HostNotFoundError)
00305 s = "host not found";
00306 else if(x == QAbstractSocket::SocketAccessError)
00307 s = "access error";
00308 else if(x == QAbstractSocket::SocketResourceError)
00309 s = "too many sockets";
00310 else if(x == QAbstractSocket::SocketTimeoutError)
00311 s = "operation timed out";
00312 else if(x == QAbstractSocket::DatagramTooLargeError)
00313 s = "datagram was larger than system limit";
00314 else if(x == QAbstractSocket::NetworkError)
00315 s = "network error";
00316 else if(x == QAbstractSocket::AddressInUseError)
00317 s = "address is already in use";
00318 else if(x == QAbstractSocket::SocketAddressNotAvailableError)
00319 s = "address does not belong to the host";
00320 else if(x == QAbstractSocket::UnsupportedSocketOperationError)
00321 s = "operation is not supported by the local operating system";
00322 else
00323 s = "unknown socket error";
00324
00325 printf("Socket error: %s\n", s.toLatin1().data());
00326 }
00327 };
00328
00329 #include "saslservtest.moc"
00330
00331 int main(int argc, char **argv)
00332 {
00333 QCA::Initializer init;
00334 QCoreApplication app(argc, argv);
00335
00336 QString host, user, pass;
00337 QString str = "Hello, World";
00338
00339 if(argc >= 2)
00340 str = argv[2];
00341
00342 if(!QCA::isSupported("sasl")) {
00343 printf("SASL not supported!\n");
00344 return 1;
00345 }
00346
00347 QCA::setAppName("saslservtest");
00348
00349 ServerTest *s = new ServerTest(str, PROTO_PORT);
00350 QObject::connect(s, SIGNAL(quit()), &app, SLOT(quit()));
00351 s->start();
00352 app.exec();
00353 delete s;
00354
00355 return 0;
00356 }