File indexing completed on 2024-06-02 04:07:04

0001 /*
0002  * stream.cpp - handles a client stream
0003  * Copyright (C) 2003  Justin Karneges
0004  *
0005  * This library is free software; you can redistribute it and/or
0006  * modify it under the terms of the GNU Lesser General Public
0007  * License as published by the Free Software Foundation; either
0008  * either version 2
0009    of the License, or (at your option) any later version.1 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Lesser General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Lesser General Public
0017  * License along with this library; if not, write to the Free Software
0018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
0019  *
0020  */
0021 
0022 /*
0023   Notes:
0024     - For Non-SASL auth (JEP-0078), username and resource fields are required.
0025 
0026   TODO:
0027     - sasl needParams is totally jacked?  PLAIN requires authzid, etc
0028     - server error handling
0029       - reply with protocol errors if the client send something wrong
0030       - don't necessarily disconnect on protocol error.  prepare for more.
0031     - server function
0032       - deal with stream 'to' attribute dynamically
0033       - flag tls/sasl/binding support dynamically (have the ability to specify extra stream:features)
0034       - inform the caller about the user authentication information
0035       - sasl security settings
0036       - resource-binding interaction
0037       - timeouts
0038     - allow exchanges of non-standard stanzas
0039     - send </stream:stream> even if we close prematurely?
0040     - ensure ClientStream and child classes are fully deletable after signals
0041     - xml:lang in root (<stream>) element
0042     - sasl external
0043     - sasl anonymous
0044 */
0045 
0046 #include "xmpp.h"
0047 
0048 #include <QTextStream>
0049 #include <QPointer>
0050 #include <QTimer>
0051 #include <QList>
0052 #include <QByteArray>
0053 #include <stdlib.h>
0054 #include "bytestream.h"
0055 #include <QtCrypto>
0056 #include <QUrl>
0057 #include "simplesasl.h"
0058 #include "securestream.h"
0059 #include "protocol.h"
0060 
0061 #ifdef XMPP_TEST
0062 #include "td.h"
0063 #endif
0064 
0065 //#define XMPP_DEBUG
0066 
0067 using namespace XMPP;
0068 
0069 static Debug *debug_ptr = 0;
0070 void XMPP::setDebug(Debug *p)
0071 {
0072     debug_ptr = p;
0073 }
0074 
0075 static QByteArray randomArray(int size)
0076 {
0077     QByteArray a;
0078     a.resize(size);
0079     for(int n = 0; n < size; ++n)
0080         a[n] = (char)(256.0*rand()/(RAND_MAX+1.0));
0081     return a;
0082 }
0083 
0084 static QString genId()
0085 {
0086     // need SHA1 here
0087     //if(!QCA::isSupported(QCA::CAP_SHA1))
0088     //  QCA::insertProvider(createProviderHash());
0089 
0090     return QCA::Hash("sha1").hashToString(randomArray(128));
0091 }
0092 
0093 //----------------------------------------------------------------------------
0094 // Stream
0095 //----------------------------------------------------------------------------
0096 static XmlProtocol *foo = 0;
0097 Stream::Stream(QObject *parent)
0098 :QObject(parent)
0099 {
0100 }
0101 
0102 Stream::~Stream()
0103 {
0104 }
0105 
0106 Stanza Stream::createStanza(Stanza::Kind k, const Jid &to, const QString &type, const QString &id)
0107 {
0108     return Stanza(this, k, to, type, id);
0109 }
0110 
0111 Stanza Stream::createStanza(const QDomElement &e)
0112 {
0113     return Stanza(this, e);
0114 }
0115 
0116 QString Stream::xmlToString(const QDomElement &e, bool clip)
0117 {
0118     if(!foo)
0119         foo = new CoreProtocol;
0120     return foo->elementToString(e, clip);
0121 }
0122 
0123 //----------------------------------------------------------------------------
0124 // ClientStream
0125 //----------------------------------------------------------------------------
0126 enum {
0127     Idle,
0128     Connecting,
0129     WaitVersion,
0130     WaitTLS,
0131     NeedParams,
0132     Active,
0133     Closing
0134 };
0135 
0136 enum {
0137     Client,
0138     Server
0139 };
0140 
0141 class ClientStream::Private
0142 {
0143 public:
0144     Private()
0145     {
0146         conn = 0;
0147         bs = 0;
0148         ss = 0;
0149         tlsHandler = 0;
0150         tls = 0;
0151         sasl = 0;
0152 
0153         oldOnly = false;
0154         allowPlain = NoAllowPlain;
0155         mutualAuth = false;
0156         haveLocalAddr = false;
0157         minimumSSF = 0;
0158         maximumSSF = 0;
0159         doBinding = true;
0160         lang = "";
0161 
0162         in_rrsig = false;
0163 
0164         reset();
0165     }
0166 
0167     void reset()
0168     {
0169         state = Idle;
0170         notify = 0;
0171         newStanzas = false;
0172         sasl_ssf = 0;
0173         tls_warned = false;
0174         using_tls = false;
0175     }
0176 
0177     Jid jid;
0178     QString server;
0179     bool oldOnly;
0180     bool mutualAuth;
0181     AllowPlainType allowPlain;
0182     bool haveLocalAddr;
0183     QHostAddress localAddr;
0184     quint16 localPort;
0185     QString connectHost;
0186     int minimumSSF, maximumSSF;
0187     QString sasl_mech;
0188     bool doBinding;
0189 
0190     bool in_rrsig;
0191 
0192     Connector *conn;
0193     ByteStream *bs;
0194     TLSHandler *tlsHandler;
0195     QCA::TLS *tls;
0196     QCA::SASL *sasl;
0197     SecureStream *ss;
0198     CoreProtocol client;
0199     CoreProtocol srv;
0200     QString lang;
0201 
0202     QString defRealm;
0203 
0204     int mode;
0205     int state;
0206     int notify;
0207     bool newStanzas;
0208     int sasl_ssf;
0209     bool tls_warned, using_tls;
0210     bool doAuth;
0211     bool doCompress;
0212 
0213     QStringList sasl_mechlist;
0214 
0215     int errCond;
0216     QString errText;
0217     QDomElement errAppSpec;
0218 
0219     QList<Stanza*> in;
0220 
0221     QTimer noopTimer;
0222     int noop_time;
0223 };
0224 
0225 ClientStream::ClientStream(Connector *conn, TLSHandler *tlsHandler, QObject *parent)
0226 :Stream(parent)
0227 {
0228     d = new Private;
0229     d->mode = Client;
0230     d->conn = conn;
0231     connect(d->conn, &Connector::connected, this, &ClientStream::cr_connected);
0232     connect(d->conn, &Connector::error, this, &ClientStream::cr_error);
0233 
0234     d->noop_time = 0;
0235     connect(&d->noopTimer, &QTimer::timeout, this, &ClientStream::doNoop);
0236 
0237     d->tlsHandler = tlsHandler;
0238 }
0239 
0240 ClientStream::ClientStream(const QString &host, const QString &defRealm, ByteStream *bs, QCA::TLS *tls, QObject *parent)
0241 :Stream(parent)
0242 {
0243     d = new Private;
0244     d->mode = Server;
0245     d->bs = bs;
0246     connect(d->bs, &ByteStream::connectionClosed, this, &ClientStream::bs_connectionClosed);
0247     connect(d->bs, &ByteStream::delayedCloseFinished, this, &ClientStream::bs_delayedCloseFinished);
0248     connect(d->bs, &ByteStream::error, this, &ClientStream::bs_error);
0249 
0250     QByteArray spare = d->bs->read();
0251 
0252     d->ss = new SecureStream(d->bs);
0253     connect(d->ss, &ByteStream::readyRead, this, &ClientStream::ss_readyRead);
0254     connect(d->ss, &ByteStream::bytesWritten, this, &ClientStream::ss_bytesWritten);
0255     connect(d->ss, &SecureStream::tlsHandshaken, this, &ClientStream::ss_tlsHandshaken);
0256     connect(d->ss, &SecureStream::tlsClosed, this, &ClientStream::ss_tlsClosed);
0257     connect(d->ss, &ByteStream::error, this, &ClientStream::ss_error);
0258 
0259     d->server = host;
0260     d->defRealm = defRealm;
0261 
0262     d->tls = tls;
0263 
0264     d->srv.startClientIn(genId());
0265     //d->srv.startServerIn(genId());
0266     //d->state = Connecting;
0267     //d->jid = Jid();
0268     //d->server = QString();
0269 }
0270 
0271 ClientStream::~ClientStream()
0272 {
0273     reset();
0274     delete d;
0275 }
0276 
0277 void ClientStream::reset(bool all)
0278 {
0279     d->reset();
0280     d->noopTimer.stop();
0281 
0282     // delete securestream
0283     delete d->ss;
0284     d->ss = 0;
0285 
0286     // reset sasl
0287     delete d->sasl;
0288     d->sasl = 0;
0289 
0290     // client
0291     if(d->mode == Client) {
0292         // reset tls
0293         // FIXME: Temporarily disabled
0294         //if(d->tlsHandler)
0295         //  d->tlsHandler->reset();
0296 
0297         // reset connector
0298         if(d->bs) {
0299             d->bs->close();
0300             d->bs = 0;
0301         }
0302         d->conn->done();
0303 
0304         // reset state machine
0305         d->client.reset();
0306     }
0307     // server
0308     else {
0309         if(d->tls)
0310             d->tls->reset();
0311 
0312         if(d->bs) {
0313             d->bs->close();
0314             d->bs = 0;
0315         }
0316 
0317         d->srv.reset();
0318     }
0319 
0320     if(all) {
0321         while (!d->in.isEmpty()) {
0322             delete d->in.takeFirst();
0323         }
0324     }
0325 }
0326 
0327 Jid ClientStream::jid() const
0328 {
0329     return d->jid;
0330 }
0331 
0332 void ClientStream::connectToServer(const Jid &jid, bool auth)
0333 {
0334     reset(true);
0335     d->state = Connecting;
0336     d->jid = jid;
0337     d->doAuth = auth;
0338     d->server = d->jid.domain();
0339 
0340     d->conn->connectToServer(d->server);
0341 }
0342 
0343 void ClientStream::continueAfterWarning()
0344 {
0345     if(d->state == WaitVersion) {
0346         // if we don't have TLS yet, then we're never going to get it
0347         if(!d->tls_warned && !d->using_tls) {
0348             d->tls_warned = true;
0349             d->state = WaitTLS;
0350             warning(WarnNoTLS);
0351             return;
0352         }
0353         d->state = Connecting;
0354         processNext();
0355     }
0356     else if(d->state == WaitTLS) {
0357         d->state = Connecting;
0358         processNext();
0359     }
0360 }
0361 
0362 void ClientStream::accept()
0363 {
0364     d->srv.host = d->server;
0365     processNext();
0366 }
0367 
0368 bool ClientStream::isActive() const
0369 {
0370     return (d->state != Idle) ? true: false;
0371 }
0372 
0373 bool ClientStream::isAuthenticated() const
0374 {
0375     return (d->state == Active) ? true: false;
0376 }
0377 
0378 void ClientStream::setUsername(const QString &s)
0379 {
0380     if(d->sasl)
0381         d->sasl->setUsername(s);
0382 }
0383 
0384 void ClientStream::setPassword(const QString &s)
0385 {
0386     if(d->client.old) {
0387         d->client.setPassword(s);
0388     }
0389     else {
0390         if(d->sasl)
0391             d->sasl->setPassword(QCA::SecureArray(s.toUtf8()));
0392     }
0393 }
0394 
0395 void ClientStream::setRealm(const QString &s)
0396 {
0397     if(d->sasl)
0398         d->sasl->setRealm(s);
0399 }
0400 
0401 void ClientStream::setAuthzid(const QString &s)
0402 {
0403     if(d->sasl)
0404         d->sasl->setAuthzid(s);
0405 }
0406 
0407 void ClientStream::continueAfterParams()
0408 {
0409     if(d->state == NeedParams) {
0410         d->state = Connecting;
0411         if(d->client.old) {
0412             processNext();
0413         }
0414         else {
0415             if(d->sasl)
0416                 d->sasl->continueAfterParams();
0417         }
0418     }
0419 }
0420 
0421 void ClientStream::setResourceBinding(bool b)
0422 {
0423     d->doBinding = b;
0424 }
0425 
0426 void ClientStream::setLang(const QString& lang)
0427 {
0428     d->lang = lang;
0429 }
0430 
0431 void ClientStream::setNoopTime(int mills)
0432 {
0433     d->noop_time = mills;
0434 
0435     if(d->state != Active)
0436         return;
0437 
0438     if(d->noop_time == 0) {
0439         d->noopTimer.stop();
0440         return;
0441     }
0442     d->noopTimer.start(d->noop_time);
0443 }
0444 
0445 QString ClientStream::saslMechanism() const
0446 {
0447     return d->client.saslMech();
0448 }
0449 
0450 int ClientStream::saslSSF() const
0451 {
0452     return d->sasl_ssf;
0453 }
0454 
0455 void ClientStream::setSASLMechanism(const QString &s)
0456 {
0457     d->sasl_mech = s;
0458 }
0459 
0460 void ClientStream::setLocalAddr(const QHostAddress &addr, quint16 port)
0461 {
0462     d->haveLocalAddr = true;
0463     d->localAddr = addr;
0464     d->localPort = port;
0465 }
0466 
0467 void ClientStream::setCompress(bool compress) 
0468 {
0469     d->doCompress = compress;
0470 }
0471 
0472 int ClientStream::errorCondition() const
0473 {
0474     return d->errCond;
0475 }
0476 
0477 QString ClientStream::errorText() const
0478 {
0479     return d->errText;
0480 }
0481 
0482 QDomElement ClientStream::errorAppSpec() const
0483 {
0484     return d->errAppSpec;
0485 }
0486 
0487 bool ClientStream::old() const
0488 {
0489     return d->client.old;
0490 }
0491 
0492 void ClientStream::close()
0493 {
0494     if(d->state == Active) {
0495         d->state = Closing;
0496         d->client.shutdown();
0497         processNext();
0498     }
0499     else if(d->state != Idle && d->state != Closing) {
0500         reset();
0501     }
0502 }
0503 
0504 QDomDocument & ClientStream::doc() const
0505 {
0506     return d->client.doc;
0507 }
0508 
0509 QString ClientStream::baseNS() const
0510 {
0511     return NS_CLIENT;
0512 }
0513 
0514 void ClientStream::setAllowPlain(AllowPlainType a)
0515 {
0516     d->allowPlain = a;
0517 }
0518 
0519 void ClientStream::setRequireMutualAuth(bool b)
0520 {
0521     d->mutualAuth = b;
0522 }
0523 
0524 void ClientStream::setSSFRange(int low, int high)
0525 {
0526     d->minimumSSF = low;
0527     d->maximumSSF = high;
0528 }
0529 
0530 void ClientStream::setOldOnly(bool b)
0531 {
0532     d->oldOnly = b;
0533 }
0534 
0535 bool ClientStream::stanzaAvailable() const
0536 {
0537     return (!d->in.isEmpty());
0538 }
0539 
0540 Stanza ClientStream::read()
0541 {
0542     if(d->in.isEmpty())
0543         return Stanza();
0544     else {
0545         Stanza *sp = d->in.takeFirst();
0546         Stanza s = *sp;
0547         delete sp;
0548         return s;
0549     }
0550 }
0551 
0552 void ClientStream::write(const Stanza &s)
0553 {
0554     if(d->state == Active) {
0555         d->client.sendStanza(s.element());
0556         processNext();
0557     }
0558 }
0559 
0560 void ClientStream::cr_connected()
0561 {
0562     d->connectHost = d->conn->host();
0563     d->bs = d->conn->stream();
0564     connect(d->bs, &ByteStream::connectionClosed, this, &ClientStream::bs_connectionClosed);
0565     connect(d->bs, &ByteStream::delayedCloseFinished, this, &ClientStream::bs_delayedCloseFinished);
0566 
0567     QByteArray spare = d->bs->read();
0568 
0569     d->ss = new SecureStream(d->bs);
0570     connect(d->ss, &ByteStream::readyRead, this, &ClientStream::ss_readyRead);
0571     connect(d->ss, &ByteStream::bytesWritten, this, &ClientStream::ss_bytesWritten);
0572     connect(d->ss, &SecureStream::tlsHandshaken, this, &ClientStream::ss_tlsHandshaken);
0573     connect(d->ss, &SecureStream::tlsClosed, this, &ClientStream::ss_tlsClosed);
0574     connect(d->ss, &ByteStream::error, this, &ClientStream::ss_error);
0575 
0576     //d->client.startDialbackOut("andbit.net", "im.pyxa.org");
0577     //d->client.startServerOut(d->server);
0578 
0579     d->client.startClientOut(d->jid, d->oldOnly, d->conn->useSSL(), d->doAuth, d->doCompress);
0580     d->client.setAllowTLS(d->tlsHandler ? true: false);
0581     d->client.setAllowBind(d->doBinding);
0582     d->client.setAllowPlain(d->allowPlain == AllowPlain || (d->allowPlain == AllowPlainOverTLS && d->conn->useSSL()));
0583     d->client.setLang(d->lang);
0584 
0585     /*d->client.jid = d->jid;
0586     d->client.server = d->server;
0587     d->client.allowPlain = d->allowPlain;
0588     d->client.oldOnly = d->oldOnly;
0589     d->client.sasl_mech = d->sasl_mech;
0590     d->client.doTLS = d->tlsHandler ? true: false;
0591     d->client.doBinding = d->doBinding;*/
0592 
0593     QPointer<QObject> self = this;
0594     connected();
0595     if(!self)
0596         return;
0597 
0598     // immediate SSL?
0599     if(d->conn->useSSL()) {
0600         d->using_tls = true;
0601         d->ss->startTLSClient(d->tlsHandler, d->server, spare);
0602     }
0603     else {
0604         d->client.addIncomingData(spare);
0605         processNext();
0606     }
0607 }
0608 
0609 void ClientStream::cr_error()
0610 {
0611     reset();
0612     error(ErrConnection);
0613 }
0614 
0615 void ClientStream::bs_connectionClosed()
0616 {
0617     reset();
0618     connectionClosed();
0619 }
0620 
0621 void ClientStream::bs_delayedCloseFinished()
0622 {
0623     // we don't care about this (we track all important data ourself)
0624 }
0625 
0626 void ClientStream::bs_error(int)
0627 {
0628     // TODO
0629 }
0630 
0631 void ClientStream::ss_readyRead()
0632 {
0633     QByteArray a = d->ss->read();
0634 
0635 #ifdef XMPP_DEBUG
0636     fprintf(stderr, "ClientStream: recv: %d [%s]\n", a.size(), a.data());
0637 #endif
0638 
0639     if(d->mode == Client)
0640         d->client.addIncomingData(a);
0641     else
0642         d->srv.addIncomingData(a);
0643     if(d->notify & CoreProtocol::NRecv) {
0644 #ifdef XMPP_DEBUG
0645         printf("We needed data, so let's process it\n");
0646 #endif
0647         processNext();
0648     }
0649 }
0650 
0651 void ClientStream::ss_bytesWritten(int bytes)
0652 {
0653     if(d->mode == Client)
0654         d->client.outgoingDataWritten(bytes);
0655     else
0656         d->srv.outgoingDataWritten(bytes);
0657 
0658     if(d->notify & CoreProtocol::NSend) {
0659 #ifdef XMPP_DEBUG
0660         printf("We were waiting for data to be written, so let's process\n");
0661 #endif
0662         processNext();
0663     }
0664 }
0665 
0666 void ClientStream::ss_tlsHandshaken()
0667 {
0668     QPointer<QObject> self = this;
0669     securityLayerActivated(LayerTLS);
0670     if(!self)
0671         return;
0672     d->client.setAllowPlain(d->allowPlain == AllowPlain || d->allowPlain == AllowPlainOverTLS);
0673     processNext();
0674 }
0675 
0676 void ClientStream::ss_tlsClosed()
0677 {
0678     reset();
0679     connectionClosed();
0680 }
0681 
0682 void ClientStream::ss_error(int x)
0683 {
0684     if(x == SecureStream::ErrTLS) {
0685         reset();
0686         d->errCond = TLSFail;
0687         error(ErrTLS);
0688     }
0689     else {
0690         reset();
0691         error(ErrSecurityLayer);
0692     }
0693 }
0694 
0695 void ClientStream::sasl_clientFirstStep(bool, const QByteArray& ba)
0696 {
0697     d->client.setSASLFirst(d->sasl->mechanism(), ba);
0698     //d->client.sasl_mech = mech;
0699     //d->client.sasl_firstStep = stepData ? true : false;
0700     //d->client.sasl_step = stepData ? *stepData : QByteArray();
0701 
0702     processNext();
0703 }
0704 
0705 void ClientStream::sasl_nextStep(const QByteArray &stepData)
0706 {
0707     if(d->mode == Client)
0708         d->client.setSASLNext(stepData);
0709         //d->client.sasl_step = stepData;
0710     else
0711         d->srv.setSASLNext(stepData);
0712         //d->srv.sasl_step = stepData;
0713 
0714     processNext();
0715 }
0716 
0717 void ClientStream::sasl_needParams(const QCA::SASL::Params& p) 
0718 {
0719 #ifdef XMPP_DEBUG
0720     printf("need params: %d,%d,%d,%d\n", p.user, p.authzid, p.pass, p.realm);
0721 #endif
0722     /*if(p.authzid && !p.user) {
0723         d->sasl->setAuthzid(d->jid.bare());
0724         //d->sasl->setAuthzid("infiniti.homelesshackers.org");
0725     }*/
0726     if(p.needUsername() || p.needPassword() || p.canSendRealm()) {
0727         d->state = NeedParams;
0728         needAuthParams(p.needUsername(), p.needPassword(), p.canSendRealm());
0729     }
0730     else
0731         d->sasl->continueAfterParams();
0732 }
0733 
0734 void ClientStream::sasl_authCheck(const QString &user, const QString &)
0735 {
0736 //#ifdef XMPP_DEBUG
0737 //  printf("authcheck: [%s], [%s]\n", user.latin1(), authzid.latin1());
0738 //#endif
0739     QString u = user;
0740     int n = u.indexOf('@');
0741     if(n != -1)
0742         u.truncate(n);
0743     d->srv.user = u;
0744     d->sasl->continueAfterAuthCheck();
0745 }
0746 
0747 void ClientStream::sasl_authenticated()
0748 {
0749 #ifdef XMPP_DEBUG
0750     printf("sasl authed!!\n");
0751 #endif
0752     d->sasl_ssf = d->sasl->ssf();
0753 
0754     if(d->mode == Server) {
0755         d->srv.setSASLAuthed();
0756         processNext();
0757     }
0758 }
0759 
0760 void ClientStream::sasl_error()
0761 {
0762 #ifdef XMPP_DEBUG
0763     printf("sasl error: %d\n", d->sasl->authCondition());
0764 #endif
0765     // has to be auth error
0766     int x = convertedSASLCond();
0767     reset();
0768     d->errCond = x;
0769     error(ErrAuth);
0770 }
0771 
0772 void ClientStream::srvProcessNext()
0773 {
0774     while(1) {
0775         printf("Processing step...\n");
0776         if(!d->srv.processStep()) {
0777             int need = d->srv.need;
0778             if(need == CoreProtocol::NNotify) {
0779                 d->notify = d->srv.notify;
0780                 if(d->notify & CoreProtocol::NSend)
0781                     printf("More data needs to be written to process next step\n");
0782                 if(d->notify & CoreProtocol::NRecv)
0783                     printf("More data is needed to process next step\n");
0784             }
0785             else if(need == CoreProtocol::NSASLMechs) {
0786                 if(!d->sasl) {
0787                     d->sasl = new QCA::SASL;
0788                     connect(d->sasl, &QCA::SASL::authCheck, this, &ClientStream::sasl_authCheck);
0789                     connect(d->sasl, &QCA::SASL::nextStep, this, &ClientStream::sasl_nextStep);
0790                     connect(d->sasl, &QCA::SASL::authenticated, this, &ClientStream::sasl_authenticated);
0791                     connect(d->sasl, &QCA::SecureLayer::error, this, &ClientStream::sasl_error);
0792 
0793                     //d->sasl->setAllowAnonymous(false);
0794                     //d->sasl->setRequirePassCredentials(true);
0795                     //d->sasl->setExternalAuthID("localhost");
0796                     QCA::SASL::AuthFlags auth_flags = (QCA::SASL::AuthFlags) 0;
0797                     d->sasl->setConstraints(auth_flags,0,256);
0798 
0799                     QStringList list;
0800                     // TODO: d->server is probably wrong here
0801                     d->sasl->startServer("xmpp", d->server, d->defRealm, QCA::SASL::AllowServerSendLast);
0802                     d->sasl_mechlist = list;
0803                 }
0804                 d->srv.setSASLMechList(d->sasl_mechlist);
0805                 continue;
0806             }
0807             else if(need == CoreProtocol::NStartTLS) {
0808                 printf("Need StartTLS\n");
0809                 //if(!d->tls->startServer()) {
0810                 d->tls->startServer();
0811                 QByteArray a = d->srv.spare;
0812                 d->ss->startTLSServer(d->tls, a);
0813             }
0814             else if(need == CoreProtocol::NSASLFirst) {
0815                 printf("Need SASL First Step\n");
0816                 QByteArray a = d->srv.saslStep();
0817                 d->sasl->putServerFirstStep(d->srv.saslMech(), a);
0818             }
0819             else if(need == CoreProtocol::NSASLNext) {
0820                 printf("Need SASL Next Step\n");
0821                 QByteArray a = d->srv.saslStep();
0822                 printf("[%s]\n", a.data());
0823                 d->sasl->putStep(a);
0824             }
0825             else if(need == CoreProtocol::NSASLLayer) {
0826             }
0827 
0828             // now we can announce stanzas
0829             //if(!d->in.isEmpty())
0830             //  readyRead();
0831             return;
0832         }
0833 
0834         d->notify = 0;
0835 
0836         int event = d->srv.event;
0837         printf("event: %d\n", event);
0838         switch(event) {
0839             case CoreProtocol::EError: {
0840                 printf("Error! Code=%d\n", d->srv.errorCode);
0841                 reset();
0842                 error(ErrProtocol);
0843                 //handleError();
0844                 return;
0845             }
0846             case CoreProtocol::ESend: {
0847                 QByteArray a = d->srv.takeOutgoingData();
0848                 printf("Need Send: {%s}\n", a.data());
0849                 d->ss->write(a);
0850                 break;
0851             }
0852             case CoreProtocol::ERecvOpen: {
0853                 printf("Break (RecvOpen)\n");
0854 
0855                 // calculate key
0856                 QByteArray str = QCA::Hash("sha1").hashToString("secret").toUtf8();
0857                 str = QCA::Hash("sha1").hashToString(str + "im.pyxa.org").toUtf8();
0858                 str = QCA::Hash("sha1").hashToString(str + d->srv.id.toUtf8()).toUtf8();
0859                 d->srv.setDialbackKey(str);
0860 
0861                 //d->srv.setDialbackKey("3c5d721ea2fcc45b163a11420e4e358f87e3142a");
0862 
0863                 if(d->srv.to != d->server) {
0864                     // host-gone, host-unknown, see-other-host
0865                     d->srv.shutdownWithError(CoreProtocol::HostUnknown);
0866                 }
0867                 else
0868                     d->srv.setFrom(d->server);
0869                 break;
0870             }
0871             case CoreProtocol::ESASLSuccess: {
0872                 printf("Break SASL Success\n");
0873                 disconnect(d->sasl, &QCA::SecureLayer::error, this, &ClientStream::sasl_error);
0874                 QByteArray a = d->srv.spare;
0875                 d->ss->setLayerSASL(d->sasl, a);
0876                 break;
0877             }
0878             case CoreProtocol::EPeerClosed: {
0879                 // TODO: this isn' an error
0880                 printf("peer closed\n");
0881                 reset();
0882                 error(ErrProtocol);
0883                 return;
0884             }
0885         }
0886     }
0887 }
0888 
0889 void ClientStream::doReadyRead()
0890 {
0891     //QGuardedPtr<QObject> self = this;
0892     readyRead();
0893     //if(!self)
0894     //  return;
0895     //d->in_rrsig = false;
0896 }
0897 
0898 void ClientStream::processNext()
0899 {
0900     if(d->mode == Server) {
0901         srvProcessNext();
0902         return;
0903     }
0904 
0905     QPointer<QObject> self = this;
0906 
0907     while(1) {
0908 #ifdef XMPP_DEBUG
0909         printf("Processing step...\n");
0910 #endif
0911         bool ok = d->client.processStep();
0912         // deal with send/received items
0913         for(QList<XmlProtocol::TransferItem>::ConstIterator it = d->client.transferItemList.constBegin(); it != d->client.transferItemList.constEnd(); ++it) {
0914             const XmlProtocol::TransferItem &i = *it;
0915             if(i.isExternal)
0916                 continue;
0917             QString str;
0918             if(i.isString) {
0919                 // skip whitespace pings
0920                 if(i.str.trimmed().isEmpty())
0921                     continue;
0922                 str = i.str;
0923             }
0924             else
0925                 str = d->client.elementToString(i.elem);
0926             if(i.isSent)
0927                 outgoingXml(str);
0928             else
0929                 incomingXml(str);
0930         }
0931 
0932         if(!ok) {
0933             bool cont = handleNeed();
0934 
0935             // now we can announce stanzas
0936             //if(!d->in_rrsig && !d->in.isEmpty()) {
0937             if(!d->in.isEmpty()) {
0938                 //d->in_rrsig = true;
0939                 QTimer::singleShot(0, this, &ClientStream::doReadyRead);
0940             }
0941 
0942             if(cont)
0943                 continue;
0944             return;
0945         }
0946 
0947         int event = d->client.event;
0948         d->notify = 0;
0949         switch(event) {
0950             case CoreProtocol::EError: {
0951 #ifdef XMPP_DEBUG
0952                 printf("Error! Code=%d\n", d->client.errorCode);
0953 #endif
0954                 handleError();
0955                 return;
0956             }
0957             case CoreProtocol::ESend: {
0958                 QByteArray a = d->client.takeOutgoingData();
0959 #ifdef XMPP_DEBUG
0960                 printf("Need Send: {%s}\n", a.data());
0961 #endif
0962                 d->ss->write(a);
0963                 break;
0964             }
0965             case CoreProtocol::ERecvOpen: {
0966 #ifdef XMPP_DEBUG
0967                 printf("Break (RecvOpen)\n");
0968 #endif
0969 
0970 #ifdef XMPP_TEST
0971                 QString s = QString("handshake success (lang=[%1]").arg(d->client.lang);
0972                 if(!d->client.from.isEmpty())
0973                     s += QString(", from=[%1]").arg(d->client.from);
0974                 s += ')';
0975                 TD::msg(s);
0976 #endif
0977 
0978                 if(d->client.old) {
0979                     d->state = WaitVersion;
0980                     warning(WarnOldVersion);
0981                     return;
0982                 }
0983                 break;
0984             }
0985             case CoreProtocol::EFeatures: {
0986 #ifdef XMPP_DEBUG
0987                 printf("Break (Features)\n");
0988 #endif
0989                 if(!d->tls_warned && !d->using_tls && !d->client.features.tls_supported) {
0990                     d->tls_warned = true;
0991                     d->state = WaitTLS;
0992                     warning(WarnNoTLS);
0993                     return;
0994                 }
0995                 break;
0996             }
0997             case CoreProtocol::ESASLSuccess: {
0998 #ifdef XMPP_DEBUG
0999                 printf("Break SASL Success\n");
1000 #endif
1001                 break;
1002             }
1003             case CoreProtocol::EReady: {
1004 #ifdef XMPP_DEBUG
1005                 printf("Done!\n");
1006 #endif
1007                 // grab the JID, in case it changed
1008                 d->jid = d->client.jid();
1009                 d->state = Active;
1010                 setNoopTime(d->noop_time);
1011                 authenticated();
1012                 if(!self)
1013                     return;
1014                 break;
1015             }
1016             case CoreProtocol::EPeerClosed: {
1017 #ifdef XMPP_DEBUG
1018                 printf("DocumentClosed\n");
1019 #endif
1020                 reset();
1021                 connectionClosed();
1022                 return;
1023             }
1024             case CoreProtocol::EStanzaReady: {
1025 #ifdef XMPP_DEBUG
1026                 printf("StanzaReady\n");
1027 #endif
1028                 // store the stanza for now, announce after processing all events
1029                 Stanza s = createStanza(d->client.recvStanza());
1030                 if(s.isNull())
1031                     break;
1032                 d->in.append(new Stanza(s));
1033                 break;
1034             }
1035             case CoreProtocol::EStanzaSent: {
1036 #ifdef XMPP_DEBUG
1037                 printf("StanzasSent\n");
1038 #endif
1039                 stanzaWritten();
1040                 if(!self)
1041                     return;
1042                 break;
1043             }
1044             case CoreProtocol::EClosed: {
1045 #ifdef XMPP_DEBUG
1046                 printf("Closed\n");
1047 #endif
1048                 reset();
1049                 delayedCloseFinished();
1050                 return;
1051             }
1052         }
1053     }
1054 }
1055 
1056 bool ClientStream::handleNeed()
1057 {
1058     int need = d->client.need;
1059     if(need == CoreProtocol::NNotify) {
1060         d->notify = d->client.notify;
1061 #ifdef XMPP_DEBUG
1062         if(d->notify & CoreProtocol::NSend)
1063             printf("More data needs to be written to process next step\n");
1064         if(d->notify & CoreProtocol::NRecv)
1065             printf("More data is needed to process next step\n");
1066 #endif
1067         return false;
1068     }
1069 
1070     d->notify = 0;
1071     switch(need) {
1072         case CoreProtocol::NStartTLS: {
1073 #ifdef XMPP_DEBUG
1074             printf("Need StartTLS\n");
1075 #endif
1076             d->using_tls = true;
1077             d->ss->startTLSClient(d->tlsHandler, d->server, d->client.spare);
1078             return false;
1079         }
1080         case CoreProtocol::NCompress: {
1081 #ifdef XMPP_DEBUG
1082             printf("Need compress\n");
1083 #endif
1084             d->ss->setLayerCompress(d->client.spare);
1085             return true;
1086         }
1087         case CoreProtocol::NSASLFirst: {
1088 #ifdef XMPP_DEBUG
1089             printf("Need SASL First Step\n");
1090 #endif
1091 
1092             // ensure simplesasl provider is installed
1093             bool found = false;
1094             foreach(QCA::Provider *p, QCA::providers()) {
1095                 if(p->name() == "simplesasl") {
1096                     found = true;
1097                     break;
1098                 }
1099             }
1100             if(!found) {
1101                 // install with low-priority
1102                 QCA::insertProvider(createProviderSimpleSASL());
1103                 QCA::setProviderPriority("simplesasl", 10);
1104             }
1105 
1106             d->sasl = new QCA::SASL();
1107             connect(d->sasl, &QCA::SASL::clientStarted, this, &ClientStream::sasl_clientFirstStep);
1108             connect(d->sasl, &QCA::SASL::nextStep, this, &ClientStream::sasl_nextStep);
1109             connect(d->sasl, &QCA::SASL::needParams, this, &ClientStream::sasl_needParams);
1110             connect(d->sasl, &QCA::SASL::authenticated, this, &ClientStream::sasl_authenticated);
1111             connect(d->sasl, &QCA::SecureLayer::error, this, &ClientStream::sasl_error);
1112 
1113             if(d->haveLocalAddr)
1114                 d->sasl->setLocalAddress(d->localAddr.toString(), d->localPort);
1115             if(d->conn->havePeerAddress())
1116                 d->sasl->setRemoteAddress(d->conn->peerAddress().toString(), d->conn->peerPort());
1117 
1118             //d->sasl_mech = "ANONYMOUS";
1119             //d->sasl->setRequirePassCredentials(true);
1120             //d->sasl->setExternalAuthID("localhost");
1121             //d->sasl->setExternalSSF(64);
1122             //d->sasl_mech = "EXTERNAL";
1123 
1124             QCA::SASL::AuthFlags auth_flags = (QCA::SASL::AuthFlags) 0;
1125             if (d->allowPlain == AllowPlain || (d->allowPlain == AllowPlainOverTLS && d->using_tls))
1126                 auth_flags = (QCA::SASL::AuthFlags) (auth_flags | QCA::SASL::AllowPlain);
1127             if (d->mutualAuth)
1128                 auth_flags = (QCA::SASL::AuthFlags) (auth_flags | QCA::SASL::RequireMutualAuth);
1129             d->sasl->setConstraints(auth_flags,d->minimumSSF,d->maximumSSF);
1130 
1131             QStringList ml;
1132             if(!d->sasl_mech.isEmpty())
1133                 ml += d->sasl_mech;
1134             else
1135                 ml = d->client.features.sasl_mechs;
1136 
1137 #ifdef IRIS_SASLCONNECTHOST
1138             d->sasl->startClient("xmpp", QUrl::toAce(d->connectHost), ml, QCA::SASL::AllowClientSendFirst);
1139 #else
1140             d->sasl->startClient("xmpp", QUrl::toAce(d->server), ml, QCA::SASL::AllowClientSendFirst);
1141 #endif
1142             return false;
1143         }
1144         case CoreProtocol::NSASLNext: {
1145 #ifdef XMPP_DEBUG
1146             printf("Need SASL Next Step\n");
1147 #endif
1148             QByteArray a = d->client.saslStep();
1149             d->sasl->putStep(a);
1150             return false;
1151         }
1152         case CoreProtocol::NSASLLayer: {
1153             // SecureStream will handle the errors from this point
1154             disconnect(d->sasl, &QCA::SecureLayer::error, this, &ClientStream::sasl_error);
1155             d->ss->setLayerSASL(d->sasl, d->client.spare);
1156             if(d->sasl_ssf > 0) {
1157                 QPointer<QObject> self = this;
1158                 securityLayerActivated(LayerSASL);
1159                 if(!self)
1160                     return false;
1161             }
1162             break;
1163         }
1164         case CoreProtocol::NPassword: {
1165 #ifdef XMPP_DEBUG
1166             printf("Need Password\n");
1167 #endif
1168             d->state = NeedParams;
1169             needAuthParams(false, true, false);
1170             return false;
1171         }
1172     }
1173 
1174     return true;
1175 }
1176 
1177 int ClientStream::convertedSASLCond() const
1178 {
1179     int x = d->sasl->authCondition();
1180     if(x == QCA::SASL::NoMechanism)
1181         return NoMech;
1182     else if(x == QCA::SASL::BadProtocol)
1183         return BadProto;
1184     else if(x == QCA::SASL::BadServer)
1185         return BadServ;
1186     else if(x == QCA::SASL::TooWeak)
1187         return MechTooWeak;
1188     else
1189         return GenericAuthError;
1190     return 0;
1191 }
1192 
1193 void ClientStream::doNoop()
1194 {
1195     if(d->state == Active) {
1196 #ifdef XMPP_DEBUG
1197         printf("doPing\n");
1198 #endif
1199         d->client.sendWhitespace();
1200         processNext();
1201     }
1202 }
1203 
1204 void ClientStream::writeDirect(const QString &s)
1205 {
1206     if(d->state == Active) {
1207 #ifdef XMPP_DEBUG
1208         printf("writeDirect\n");
1209 #endif
1210         d->client.sendDirect(s);
1211         processNext();
1212     }
1213 }
1214 
1215 void ClientStream::handleError()
1216 {
1217     int c = d->client.errorCode;
1218     if(c == CoreProtocol::ErrParse) {
1219         reset();
1220         error(ErrParse);
1221     }
1222     else if(c == CoreProtocol::ErrProtocol) {
1223         reset();
1224         error(ErrProtocol);
1225     }
1226     else if(c == CoreProtocol::ErrStream) {
1227         int x = d->client.errCond;
1228         QString text = d->client.errText;
1229         QDomElement appSpec = d->client.errAppSpec;
1230 
1231         int connErr = -1;
1232         int strErr = -1;
1233 
1234         switch(x) {
1235             case CoreProtocol::BadFormat: { break; } // should NOT happen (we send the right format)
1236             case CoreProtocol::BadNamespacePrefix: { break; } // should NOT happen (we send prefixes)
1237             case CoreProtocol::Conflict: { strErr = Conflict; break; }
1238             case CoreProtocol::ConnectionTimeout: { strErr = ConnectionTimeout; break; }
1239             case CoreProtocol::HostGone: { connErr = HostGone; break; }
1240             case CoreProtocol::HostUnknown: { connErr = HostUnknown; break; }
1241             case CoreProtocol::ImproperAddressing: { break; } // should NOT happen (we aren't a server)
1242             case CoreProtocol::InternalServerError: { strErr = InternalServerError;  break; }
1243             case CoreProtocol::InvalidFrom: { strErr = InvalidFrom; break; }
1244             case CoreProtocol::InvalidId: { break; } // should NOT happen (clients don't specify id)
1245             case CoreProtocol::InvalidNamespace: { break; } // should NOT happen (we set the right ns)
1246             case CoreProtocol::InvalidXml: { strErr = InvalidXml; break; } // shouldn't happen either, but just in case ...
1247             case CoreProtocol::StreamNotAuthorized: { break; } // should NOT happen (we're not stupid)
1248             case CoreProtocol::PolicyViolation: { strErr = PolicyViolation; break; }
1249             case CoreProtocol::RemoteConnectionFailed: { connErr = RemoteConnectionFailed; break; }
1250             case CoreProtocol::ResourceConstraint: { strErr = ResourceConstraint; break; }
1251             case CoreProtocol::RestrictedXml: { strErr = InvalidXml; break; } // group with this one
1252             case CoreProtocol::SeeOtherHost: { connErr = SeeOtherHost; break; }
1253             case CoreProtocol::SystemShutdown: { strErr = SystemShutdown; break; }
1254             case CoreProtocol::UndefinedCondition: { break; } // leave as null error
1255             case CoreProtocol::UnsupportedEncoding: { break; } // should NOT happen (we send good encoding)
1256             case CoreProtocol::UnsupportedStanzaType: { break; } // should NOT happen (we're not stupid)
1257             case CoreProtocol::UnsupportedVersion: { connErr = UnsupportedVersion; break; }
1258             case CoreProtocol::XmlNotWellFormed: { strErr = InvalidXml; break; } // group with this one
1259             default: { break; }
1260         }
1261 
1262         reset();
1263 
1264         d->errText = text;
1265         d->errAppSpec = appSpec;
1266         if(connErr != -1) {
1267             d->errCond = connErr;
1268             error(ErrNeg);
1269         }
1270         else {
1271             if(strErr != -1)
1272                 d->errCond = strErr;
1273             else
1274                 d->errCond = GenericStreamError;
1275             error(ErrStream);
1276         }
1277     }
1278     else if(c == CoreProtocol::ErrStartTLS) {
1279         reset();
1280         d->errCond = TLSStart;
1281         error(ErrTLS);
1282     }
1283     else if(c == CoreProtocol::ErrAuth) {
1284         int x = d->client.errCond;
1285         int r = GenericAuthError;
1286         if(d->client.old) {
1287             if(x == 401) // not authorized
1288                 r = NotAuthorized;
1289             else if(x == 409) // conflict
1290                 r = GenericAuthError;
1291             else if(x == 406) // not acceptable (this should NOT happen)
1292                 r = GenericAuthError;
1293         }
1294         else {
1295             switch(x) {
1296                 case CoreProtocol::Aborted: { r = GenericAuthError; break; } // should NOT happen (we never send <abort/>)
1297                 case CoreProtocol::IncorrectEncoding: { r = GenericAuthError; break; } // should NOT happen
1298                 case CoreProtocol::InvalidAuthzid: { r = InvalidAuthzid; break; }
1299                 case CoreProtocol::InvalidMech: { r = InvalidMech; break; }
1300                 case CoreProtocol::MechTooWeak: { r = MechTooWeak; break; }
1301                 case CoreProtocol::NotAuthorized: { r = NotAuthorized; break; }
1302                 case CoreProtocol::TemporaryAuthFailure: { r = TemporaryAuthFailure; break; }
1303             }
1304         }
1305         reset();
1306         d->errCond = r;
1307         error(ErrAuth);
1308     }
1309     else if(c == CoreProtocol::ErrPlain) {
1310         reset();
1311         d->errCond = NoMech;
1312         error(ErrAuth);
1313     }
1314     else if(c == CoreProtocol::ErrBind) {
1315         int r = -1;
1316         if(d->client.errCond == CoreProtocol::BindBadRequest) {
1317             // should NOT happen
1318         }
1319         else if(d->client.errCond == CoreProtocol::BindNotAllowed) {
1320             r = BindNotAllowed;
1321         }
1322         else if(d->client.errCond == CoreProtocol::BindConflict) {
1323             r = BindConflict;
1324         }
1325 
1326         if(r != -1) {
1327             reset();
1328             d->errCond = r;
1329             error(ErrBind);
1330         }
1331         else {
1332             reset();
1333             error(ErrProtocol);
1334         }
1335     }
1336 }
1337 
1338 QStringList ClientStream::hosts() const
1339 {
1340     return d->client.hosts;
1341 }
1342 
1343 
1344 //----------------------------------------------------------------------------
1345 // Debug
1346 //----------------------------------------------------------------------------
1347 Debug::~Debug()
1348 {
1349 }
1350 
1351 #ifdef XMPP_TEST
1352 TD::TD()
1353 {
1354 }
1355 
1356 TD::~TD()
1357 {
1358 }
1359 
1360 void TD::msg(const QString &s)
1361 {
1362     if(debug_ptr)
1363         debug_ptr->msg(s);
1364 }
1365 
1366 void TD::outgoingTag(const QString &s)
1367 {
1368     if(debug_ptr)
1369         debug_ptr->outgoingTag(s);
1370 }
1371 
1372 void TD::incomingTag(const QString &s)
1373 {
1374     if(debug_ptr)
1375         debug_ptr->incomingTag(s);
1376 }
1377 
1378 void TD::outgoingXml(const QDomElement &e)
1379 {
1380     if(debug_ptr)
1381         debug_ptr->outgoingXml(e);
1382 }
1383 
1384 void TD::incomingXml(const QDomElement &e)
1385 {
1386     if(debug_ptr)
1387         debug_ptr->incomingXml(e);
1388 }
1389 #endif