source: qca/trunk/examples/sasltest/sasltest.cpp@ 139

Last change on this file since 139 was 24, checked in by dmik, 19 years ago

QCA: Imported original QCA 1.0 sources from Affinix

  • Property svn:keywords set to Id
File size: 12.5 KB
Line 
1#include<qapplication.h>
2#include<qtimer.h>
3#include<qsocket.h>
4#include<qserversocket.h>
5#include<stdio.h>
6
7#ifdef Q_OS_UNIX
8#include<unistd.h>
9#endif
10
11#include"base64.h"
12#include"qca.h"
13
14#define PROTO_NAME "foo"
15#define PROTO_PORT 8001
16
17static QString prompt(const QString &s)
18{
19 printf("* %s ", s.latin1());
20 fflush(stdout);
21 char line[256];
22 fgets(line, 255, stdin);
23 QString result = line;
24 if(result[result.length()-1] == '\n')
25 result.truncate(result.length()-1);
26 return result;
27}
28
29class ClientTest : public QObject
30{
31 Q_OBJECT
32public:
33 ClientTest()
34 {
35 sock = new QSocket;
36 connect(sock, SIGNAL(connected()), SLOT(sock_connected()));
37 connect(sock, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed()));
38 connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead()));
39 connect(sock, SIGNAL(error(int)), SLOT(sock_error(int)));
40
41 sasl = new QCA::SASL;
42 connect(sasl, SIGNAL(clientFirstStep(const QString &, const QByteArray *)), SLOT(sasl_clientFirstStep(const QString &, const QByteArray *)));
43 connect(sasl, SIGNAL(nextStep(const QByteArray &)), SLOT(sasl_nextStep(const QByteArray &)));
44 connect(sasl, SIGNAL(needParams(bool, bool, bool, bool)), SLOT(sasl_needParams(bool, bool, bool, bool)));
45 connect(sasl, SIGNAL(authenticated()), SLOT(sasl_authenticated()));
46 connect(sasl, SIGNAL(readyRead()), SLOT(sasl_readyRead()));
47 connect(sasl, SIGNAL(readyReadOutgoing(int)), SLOT(sasl_readyReadOutgoing(int)));
48 connect(sasl, SIGNAL(error(int)), SLOT(sasl_error(int)));
49 }
50
51 ~ClientTest()
52 {
53 delete sock;
54 delete sasl;
55 }
56
57 void start(const QString &_host, int port, const QString &user="", const QString &pass="")
58 {
59 mode = 0;
60 host = _host;
61 sock->connectToHost(host, port);
62 sasl->setMinimumSSF(0);
63 sasl->setMaximumSSF(256);
64
65 if(!user.isEmpty()) {
66 sasl->setUsername(user);
67 sasl->setAuthzid(user);
68 }
69 if(!pass.isEmpty())
70 sasl->setPassword(pass);
71 }
72
73signals:
74 void quit();
75
76private slots:
77 void sock_connected()
78 {
79 printf("Connected to server. Awaiting mechanism list...\n");
80 }
81
82 void sock_connectionClosed()
83 {
84 printf("Connection closed by peer.\n");
85 quit();
86 }
87
88 void sock_error(int x)
89 {
90 QString s;
91 if(x == QSocket::ErrConnectionRefused)
92 s = "connection refused or timed out";
93 else if(x == QSocket::ErrHostNotFound)
94 s = "host not found";
95 else if(x == QSocket::ErrSocketRead)
96 s = "read error";
97
98 printf("Socket error: %s\n", s.latin1());
99 quit();
100 }
101
102 void sock_readyRead()
103 {
104 if(mode == 2) {
105 int avail = sock->bytesAvailable();
106 QByteArray a(avail);
107 int n = sock->readBlock(a.data(), a.size());
108 a.resize(n);
109 printf("Read %d bytes\n", a.size());
110 sasl->writeIncoming(a);
111 }
112 else {
113 if(sock->canReadLine()) {
114 QString line = sock->readLine();
115 line.truncate(line.length()-1); // chop the newline
116 handleLine(line);
117 }
118 }
119 }
120
121 void sasl_clientFirstStep(const QString &mech, const QByteArray *clientInit)
122 {
123 printf("Choosing mech: %s\n", mech.latin1());
124 QString line = mech;
125 if(clientInit) {
126 QCString cs(clientInit->data(), clientInit->size()+1);
127 line += ' ';
128 line += cs;
129 }
130 sendLine(line);
131 }
132
133 void sasl_nextStep(const QByteArray &stepData)
134 {
135 QCString cs(stepData.data(), stepData.size()+1);
136 QString line = "C";
137 if(!stepData.isEmpty()) {
138 line += ',';
139 line += cs;
140 }
141 sendLine(line);
142 }
143
144 void sasl_needParams(bool user, bool authzid, bool pass, bool realm)
145 {
146 QString username;
147 if(user || authzid)
148 username = prompt("Username:");
149 if(user) {
150 sasl->setUsername(username);
151 }
152 if(authzid) {
153 sasl->setAuthzid(username);
154 }
155 if(pass) {
156 sasl->setPassword(prompt("Password (not hidden!) :"));
157 }
158 if(realm) {
159 sasl->setRealm(prompt("Realm:"));
160 }
161 sasl->continueAfterParams();
162 }
163
164 void sasl_authenticated()
165 {
166 printf("SASL success!\n");
167 printf("SSF: %d\n", sasl->ssf());
168 }
169
170 void sasl_readyRead()
171 {
172 QByteArray a = sasl->read();
173 int oldsize = inbuf.size();
174 inbuf.resize(oldsize + a.size());
175 memcpy(inbuf.data() + oldsize, a.data(), a.size());
176 processInbuf();
177 }
178
179 void sasl_readyReadOutgoing(int)
180 {
181 QByteArray a = sasl->readOutgoing();
182 sock->writeBlock(a.data(), a.size());
183 }
184
185 void sasl_error(int)
186 {
187 printf("SASL error!\n");
188 quit();
189 return;
190 }
191
192private:
193 QSocket *sock;
194 QCA::SASL *sasl;
195 int mode;
196 QString host;
197 QByteArray inbuf;
198
199 void processInbuf()
200 {
201 QStringList list;
202 for(int n = 0; n < (int)inbuf.size(); ++n) {
203 if(inbuf[n] == '\n') {
204 QCString cs(inbuf.data(), n+1);
205 char *p = inbuf.data();
206 ++n;
207 int x = inbuf.size() - n;
208 memmove(p, p + n, x);
209 inbuf.resize(x);
210 list += QString::fromUtf8(cs);
211 // start over, basically
212 n = -1;
213 }
214 }
215
216 for(QStringList::ConstIterator it = list.begin(); it != list.end(); ++it)
217 handleLine(*it);
218 }
219
220 void handleLine(const QString &line)
221 {
222 printf("Reading: [%s]\n", line.latin1());
223 if(mode == 0) {
224 // first line is the method list
225 QStringList mechlist = QStringList::split(' ', line);
226 ++mode;
227
228 // kick off the client
229 sasl->setAllowAnonymous(false);
230 if(!sasl->startClient(PROTO_NAME, host, mechlist)) {
231 printf("Error starting client!\n");
232 quit();
233 }
234 }
235 else if(mode == 1) {
236 QString type, rest;
237 int n = line.find(',');
238 if(n != -1) {
239 type = line.mid(0, n);
240 rest = line.mid(n+1);
241 }
242 else {
243 type = line;
244 rest = "";
245 }
246
247 if(type == "C") {
248 QCString cs = rest.latin1();
249 QByteArray buf(cs.length());
250 memcpy(buf.data(), cs.data(), buf.size());
251 sasl->putStep(buf);
252 }
253 else if(type == "E") {
254 printf("Authentication failed.\n");
255 quit();
256 return;
257 }
258 else if(type == "A") {
259 printf("Authentication success.\n");
260 ++mode;
261 sock_readyRead(); // any extra data?
262 return;
263 }
264 else {
265 printf("Bad format from peer, closing.\n");
266 quit();
267 return;
268 }
269 }
270 else {
271 }
272 }
273
274 void sendLine(const QString &line)
275 {
276 printf("Writing: {%s}\n", line.latin1());
277 QString s = line + '\n';
278 QCString cs = s.latin1();
279 if(mode == 2) {
280 QByteArray a(cs.length());
281 memcpy(a.data(), cs.data(), a.size());
282 sasl->write(a);
283 }
284 else
285 sock->writeBlock(cs.data(), cs.length());
286 }
287};
288
289class ServerTest : public QServerSocket
290{
291 Q_OBJECT
292public:
293 ServerTest(const QString &_str, int _port) : QServerSocket(_port), port(_port)
294 {
295 sock = 0;
296 sasl = 0;
297 realm = QString::null;
298 str = _str;
299 }
300
301 ~ServerTest()
302 {
303 delete sock;
304 delete sasl;
305 }
306
307 void start()
308 {
309 if(!ok()) {
310 printf("Error binding to port %d!\n", port);
311 QTimer::singleShot(0, this, SIGNAL(quit()));
312 return;
313 }
314 char myhostname[256];
315 int r = gethostname(myhostname, sizeof(myhostname)-1);
316 if(r == -1) {
317 printf("Error getting hostname!\n");
318 QTimer::singleShot(0, this, SIGNAL(quit()));
319 return;
320 }
321 host = myhostname;
322 printf("Listening on %s:%d ...\n", host.latin1(), port);
323 }
324
325 void newConnection(int s)
326 {
327 // Note: only 1 connection supported at a time in this example!
328 if(sock) {
329 QSocket tmp;
330 tmp.setSocket(s);
331 printf("Connection ignored, already have one active.\n");
332 return;
333 }
334
335 printf("Connection received! Starting SASL handshake...\n");
336
337 sock = new QSocket;
338 connect(sock, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed()));
339 connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead()));
340 connect(sock, SIGNAL(error(int)), SLOT(sock_error(int)));
341 connect(sock, SIGNAL(bytesWritten(int)), SLOT(sock_bytesWritten(int)));
342
343 sasl = new QCA::SASL;
344 connect(sasl, SIGNAL(authCheck(const QString &, const QString &)), SLOT(sasl_authCheck(const QString &, const QString &)));
345 connect(sasl, SIGNAL(nextStep(const QByteArray &)), SLOT(sasl_nextStep(const QByteArray &)));
346 connect(sasl, SIGNAL(authenticated()), SLOT(sasl_authenticated()));
347 connect(sasl, SIGNAL(readyRead()), SLOT(sasl_readyRead()));
348 connect(sasl, SIGNAL(readyReadOutgoing(int)), SLOT(sasl_readyReadOutgoing(int)));
349 connect(sasl, SIGNAL(error(int)), SLOT(sasl_error(int)));
350
351 sock->setSocket(s);
352 mode = 0;
353 inbuf.resize(0);
354
355 sasl->setMinimumSSF(0);
356 sasl->setMaximumSSF(256);
357
358 QStringList mechlist;
359 if(!sasl->startServer(PROTO_NAME, host, realm, &mechlist)) {
360 printf("Error starting server!\n");
361 quit();
362 }
363 QString str;
364 bool first = true;
365 for(QStringList::ConstIterator it = mechlist.begin(); it != mechlist.end(); ++it) {
366 if(!first)
367 str += ' ';
368 str += *it;
369 first = false;
370 }
371 sendLine(str);
372 }
373
374signals:
375 void quit();
376
377private slots:
378 void sock_connectionClosed()
379 {
380 printf("Connection closed by peer.\n");
381 close();
382 }
383
384 void sock_error(int x)
385 {
386 QString s;
387 if(x == QSocket::ErrConnectionRefused)
388 s = "connection refused or timed out";
389 else if(x == QSocket::ErrHostNotFound)
390 s = "host not found";
391 else if(x == QSocket::ErrSocketRead)
392 s = "read error";
393
394 printf("Socket error: %s\n", s.latin1());
395 close();
396 }
397
398 void sock_readyRead()
399 {
400 if(sock->canReadLine()) {
401 QString line = sock->readLine();
402 line.truncate(line.length()-1); // chop the newline
403 handleLine(line);
404 }
405 }
406
407 void sock_bytesWritten(int x)
408 {
409 if(mode == 2) {
410 toWrite -= x;
411 if(toWrite <= 0) {
412 printf("Sent, closing.\n");
413 close();
414 }
415 }
416 }
417
418 void sasl_nextStep(const QByteArray &stepData)
419 {
420 QCString cs(stepData.data(), stepData.size()+1);
421 QString line = "C";
422 if(!stepData.isEmpty()) {
423 line += ',';
424 line += cs;
425 }
426 sendLine(line);
427 }
428
429 void sasl_authCheck(const QString &user, const QString &authzid)
430 {
431 printf("AuthCheck: User: [%s], Authzid: [%s]\n", user.latin1(), authzid.latin1());
432 sasl->continueAfterAuthCheck();
433 }
434
435 void sasl_authenticated()
436 {
437 sendLine("A");
438 printf("Authentication success.\n");
439 ++mode;
440 printf("SSF: %d\n", sasl->ssf());
441 sendLine(str);
442 }
443
444 void sasl_readyRead()
445 {
446 QByteArray a = sasl->read();
447 int oldsize = inbuf.size();
448 inbuf.resize(oldsize + a.size());
449 memcpy(inbuf.data() + oldsize, a.data(), a.size());
450 processInbuf();
451 }
452
453 void sasl_readyReadOutgoing(int)
454 {
455 QByteArray a = sasl->readOutgoing();
456 toWrite = a.size();
457 sock->writeBlock(a.data(), a.size());
458 }
459
460 void sasl_error(int x)
461 {
462 if(x == QCA::SASL::ErrAuth) {
463 sendLine("E");
464 printf("Authentication failed.\n");
465 close();
466 }
467 else {
468 printf("SASL security layer error!\n");
469 close();
470 }
471 }
472
473private:
474 QSocket *sock;
475 QCA::SASL *sasl;
476 QString host, realm;
477 int port;
478 int mode;
479 QString str;
480 QByteArray inbuf;
481 int toWrite;
482
483 void processInbuf()
484 {
485 }
486
487 void handleLine(const QString &line)
488 {
489 printf("Reading: [%s]\n", line.latin1());
490 if(mode == 0) {
491 int n = line.find(' ');
492 if(n != -1) {
493 QString mech = line.mid(0, n);
494 QCString cs = line.mid(n+1).latin1();
495 QByteArray clientInit(cs.length());
496 memcpy(clientInit.data(), cs.data(), clientInit.size());
497 sasl->putServerFirstStep(mech, clientInit);
498 }
499 else
500 sasl->putServerFirstStep(line);
501 ++mode;
502 }
503 else if(mode == 1) {
504 QString type, rest;
505 int n = line.find(',');
506 if(n != -1) {
507 type = line.mid(0, n);
508 rest = line.mid(n+1);
509 }
510 else {
511 type = line;
512 rest = "";
513 }
514
515 if(type == "C") {
516 QCString cs = rest.latin1();
517 QByteArray buf(cs.length());
518 memcpy(buf.data(), cs.data(), buf.size());
519 sasl->putStep(buf);
520 }
521 else {
522 printf("Bad format from peer, closing.\n");
523 close();
524 return;
525 }
526 }
527 }
528
529 void sendLine(const QString &line)
530 {
531 printf("Writing: {%s}\n", line.latin1());
532 QString s = line + '\n';
533 QCString cs = s.latin1();
534 if(mode == 2) {
535 QByteArray a(cs.length());
536 memcpy(a.data(), cs.data(), a.size());
537 sasl->write(a);
538 }
539 else
540 sock->writeBlock(cs.data(), cs.length());
541 }
542
543 void close()
544 {
545 sock->deleteLater();
546 sock = 0;
547 delete sasl;
548 sasl = 0;
549 }
550};
551
552#include"sasltest.moc"
553
554void usage()
555{
556 printf("usage: sasltest client [host] [user] [pass]\n");
557 printf(" sasltest server [string]\n\n");
558}
559
560int main(int argc, char **argv)
561{
562 QApplication app(argc, argv, false);
563
564 QString host, user, pass;
565 QString str = "Hello, World";
566 bool server;
567 if(argc < 2) {
568 usage();
569 return 0;
570 }
571 QString arg = argv[1];
572 if(arg == "client") {
573 if(argc < 3) {
574 usage();
575 return 0;
576 }
577 host = argv[2];
578 if(argc >= 4)
579 user = argv[3];
580 if(argc >= 5)
581 pass = argv[4];
582 server = false;
583 }
584 else if(arg == "server") {
585 if(argc >= 3)
586 str = argv[2];
587 server = true;
588 }
589 else {
590 usage();
591 return 0;
592 }
593
594 if(!QCA::isSupported(QCA::CAP_SASL)) {
595 printf("SASL not supported!\n");
596 return 1;
597 }
598
599 if(server) {
600 ServerTest *s = new ServerTest(str, PROTO_PORT);
601 QObject::connect(s, SIGNAL(quit()), &app, SLOT(quit()));
602 s->start();
603 app.exec();
604 delete s;
605 }
606 else {
607 ClientTest *c = new ClientTest;
608 QObject::connect(c, SIGNAL(quit()), &app, SLOT(quit()));
609 c->start(host, PROTO_PORT, user, pass);
610 app.exec();
611 delete c;
612 }
613
614 return 0;
615}
Note: See TracBrowser for help on using the repository browser.