File indexing completed on 2024-05-05 04:45:03

0001 /*
0002  * qca-sasl.cpp - SASL plugin for QCA
0003  * Copyright (C) 2003-2007  Justin Karneges <justin@affinix.com>
0004  * Copyright (C) 2006  Michail Pishchagin <mblsha@gmail.com>
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Lesser General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2.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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
0019  *
0020  */
0021 
0022 #include <QDebug>
0023 #include <QtCrypto>
0024 #include <QtPlugin>
0025 #include <qcaprovider.h>
0026 
0027 extern "C" {
0028 #include <sasl/sasl.h>
0029 }
0030 
0031 #include <QFile>
0032 #include <QList>
0033 #include <QStringList>
0034 
0035 #define SASL_BUFSIZE 8192
0036 #define SASL_APP "qca"
0037 
0038 using namespace QCA;
0039 
0040 namespace saslQCAPlugin {
0041 
0042 class saslProvider : public Provider
0043 {
0044 public:
0045     saslProvider();
0046     void init() override;
0047     ~saslProvider() override;
0048     int         qcaVersion() const override;
0049     QString     name() const override;
0050     QString     credit() const override;
0051     QStringList features() const override;
0052     Context    *createContext(const QString &type) override;
0053 
0054     bool    client_init;
0055     bool    server_init;
0056     QString appname;
0057 };
0058 
0059 //----------------------------------------------------------------------------
0060 // SASLParams
0061 //----------------------------------------------------------------------------
0062 
0063 class SASLParams
0064 {
0065 public:
0066     class SParams
0067     {
0068     public:
0069         bool user, authzid, pass, realm;
0070     };
0071 
0072     SASLParams()
0073     {
0074         reset();
0075     }
0076 
0077     void reset()
0078     {
0079         resetNeed();
0080         resetHave();
0081         foreach (char *result, results)
0082             delete result;
0083         results.clear();
0084     }
0085 
0086     void resetNeed()
0087     {
0088         need.user    = false;
0089         need.authzid = false;
0090         need.pass    = false;
0091         need.realm   = false;
0092     }
0093 
0094     void resetHave()
0095     {
0096         have.user    = false;
0097         have.authzid = false;
0098         have.pass    = false;
0099         have.realm   = false;
0100     }
0101 
0102     void setUsername(const QString &s)
0103     {
0104         have.user = true;
0105         user      = s;
0106     }
0107 
0108     void setAuthzid(const QString &s)
0109     {
0110         have.authzid = true;
0111         authzid      = s;
0112     }
0113 
0114     void setPassword(const SecureArray &s)
0115     {
0116         have.pass = true;
0117         pass      = QString::fromUtf8(s.toByteArray());
0118     }
0119 
0120     void setRealm(const QString &s)
0121     {
0122         have.realm = true;
0123         realm      = s;
0124     }
0125 
0126     void applyInteract(sasl_interact_t *needp)
0127     {
0128         for (int n = 0; needp[n].id != SASL_CB_LIST_END; ++n) {
0129             if (needp[n].id == SASL_CB_AUTHNAME)
0130                 need.user = true; // yes, I know these
0131             if (needp[n].id == SASL_CB_USER)
0132                 need.authzid = true; // look backwards
0133             if (needp[n].id == SASL_CB_PASS)
0134                 need.pass = true;
0135             if (needp[n].id == SASL_CB_GETREALM)
0136                 need.realm = true;
0137         }
0138     }
0139 
0140     void extractHave(sasl_interact_t *needp)
0141     {
0142         for (int n = 0; needp[n].id != SASL_CB_LIST_END; ++n) {
0143             if (needp[n].id == SASL_CB_AUTHNAME && have.user)
0144                 setValue(&needp[n], user);
0145             if (needp[n].id == SASL_CB_USER && have.authzid)
0146                 setValue(&needp[n], authzid);
0147             if (needp[n].id == SASL_CB_PASS && have.pass)
0148                 setValue(&needp[n], pass);
0149             if (needp[n].id == SASL_CB_GETREALM && have.realm)
0150                 setValue(&needp[n], realm);
0151         }
0152     }
0153 
0154     bool missingAny() const
0155     {
0156         if ((need.user && !have.user) /*|| (need.authzid && !have.authzid)*/ ||
0157             (need.pass && !have.pass) /*|| (need.realm && !have.realm)*/)
0158             return true;
0159         return false;
0160     }
0161 
0162     SParams missing() const
0163     {
0164         SParams np = need;
0165         if (have.user)
0166             np.user = false;
0167         if (have.authzid)
0168             np.authzid = false;
0169         if (have.pass)
0170             np.pass = false;
0171         if (have.realm)
0172             np.realm = false;
0173         return np;
0174     }
0175 
0176     void setValue(sasl_interact_t *i, const QString &s)
0177     {
0178         if (i->result)
0179             return;
0180         const QByteArray cs  = s.toUtf8();
0181         const int        len = cs.length();
0182         char            *p   = new char[len + 1];
0183         memcpy(p, cs.data(), len);
0184         p[len]    = 0;
0185         i->result = p;
0186         i->len    = len;
0187 
0188         // record this
0189         results.append(p);
0190     }
0191 
0192     QList<char *> results;
0193     SParams       need;
0194     SParams       have;
0195     QString       user, authzid, pass, realm;
0196 };
0197 
0198 static QByteArray makeByteArray(const void *in, unsigned int len)
0199 {
0200     QByteArray buf(len, 0);
0201     memcpy(buf.data(), in, len);
0202     return buf;
0203 }
0204 
0205 static QString addrString(const SASLContext::HostPort &hp)
0206 {
0207     return (hp.addr + QLatin1Char(';') + QString::number(hp.port));
0208 }
0209 
0210 //----------------------------------------------------------------------------
0211 // saslContext
0212 //----------------------------------------------------------------------------
0213 
0214 class saslContext : public SASLContext
0215 {
0216     Q_OBJECT
0217     saslProvider *g;
0218 
0219     // core props
0220     QString service, host;
0221     QString localAddr, remoteAddr;
0222 
0223     // security props
0224     int     secflags;
0225     int     ssf_min, ssf_max;
0226     QString ext_authid;
0227     int     ext_ssf;
0228 
0229     sasl_conn_t     *con;
0230     sasl_interact_t *need;
0231     int              maxoutbuf;
0232     sasl_callback_t *callbacks;
0233 
0234     // state
0235     bool       servermode;
0236     int        step;
0237     bool       in_sendFirst;
0238     QByteArray in_buf;
0239     QString    in_mech;
0240     bool       in_useClientInit;
0241     QByteArray in_clientInit;
0242     QString    out_mech;
0243     // bool out_useClientInit;
0244     // QByteArray out_clientInit;
0245     QByteArray out_buf;
0246 
0247     SASLParams params;
0248     QString    sc_username, sc_authzid;
0249     bool       ca_flag, ca_done, ca_skip;
0250     int        last_r;
0251 
0252     int                 result_ssf;
0253     Result              result_result;
0254     bool                result_haveClientInit;
0255     QStringList         result_mechlist;
0256     SASL::AuthCondition result_authCondition;
0257     QByteArray          result_to_net;
0258     QByteArray          result_plain;
0259     int                 result_encoded;
0260 
0261 private:
0262     void resetState()
0263     {
0264         if (con) {
0265             sasl_dispose(&con);
0266             con = nullptr;
0267         }
0268         need = nullptr;
0269         if (callbacks) {
0270             delete callbacks;
0271             callbacks = nullptr;
0272         }
0273 
0274         localAddr   = QLatin1String("");
0275         remoteAddr  = QLatin1String("");
0276         maxoutbuf   = 128;
0277         sc_username = QLatin1String("");
0278         sc_authzid  = QLatin1String("");
0279 
0280         result_authCondition  = SASL::AuthFail;
0281         result_haveClientInit = false;
0282         result_mechlist.clear();
0283         result_plain.clear();
0284         result_plain.clear();
0285         result_plain.clear();
0286         result_ssf = 0;
0287     }
0288 
0289     void resetParams()
0290     {
0291         params.reset();
0292         secflags   = 0;
0293         ssf_min    = 0;
0294         ssf_max    = 0;
0295         ext_authid = QLatin1String("");
0296         ext_ssf    = 0;
0297     }
0298 
0299     bool setsecprops()
0300     {
0301         sasl_security_properties_t secprops;
0302         secprops.min_ssf         = ssf_min;
0303         secprops.max_ssf         = ssf_max;
0304         secprops.maxbufsize      = SASL_BUFSIZE;
0305         secprops.property_names  = nullptr;
0306         secprops.property_values = nullptr;
0307         secprops.security_flags  = secflags;
0308         int r                    = sasl_setprop(con, SASL_SEC_PROPS, &secprops);
0309         if (r != SASL_OK)
0310             return false;
0311 
0312         if (!ext_authid.isEmpty()) {
0313             const QByteArray ext_authidBA = ext_authid.toLatin1();
0314             const char      *authid       = ext_authidBA.data();
0315             sasl_ssf_t       ssf          = ext_ssf;
0316             r                             = sasl_setprop(con, SASL_SSF_EXTERNAL, &ssf);
0317             if (r != SASL_OK)
0318                 return false;
0319             r = sasl_setprop(con, SASL_AUTH_EXTERNAL, authid);
0320             if (r != SASL_OK)
0321                 return false;
0322         }
0323 
0324         return true;
0325     }
0326 
0327     void setAuthCondition(int r)
0328     {
0329         // qDebug() << "authcondition: " << r;
0330         SASL::AuthCondition x;
0331         switch (r) {
0332         // common
0333         case SASL_NOMECH:
0334             x = SASL::NoMechanism;
0335             break;
0336         case SASL_BADPROT:
0337             x = SASL::BadProtocol;
0338             break;
0339 
0340         // client
0341         case SASL_BADSERV:
0342             x = SASL::BadServer;
0343             break;
0344 
0345         // server
0346         case SASL_BADAUTH:
0347             x = SASL::BadAuth;
0348             break;
0349         case SASL_NOAUTHZ:
0350             x = SASL::NoAuthzid;
0351             break;
0352         case SASL_TOOWEAK:
0353             x = SASL::TooWeak;
0354             break;
0355         case SASL_ENCRYPT:
0356             x = SASL::NeedEncrypt;
0357             break;
0358         case SASL_EXPIRED:
0359             x = SASL::Expired;
0360             break;
0361         case SASL_DISABLED:
0362             x = SASL::Disabled;
0363             break;
0364         case SASL_NOUSER:
0365             x = SASL::NoUser;
0366             break;
0367         case SASL_UNAVAIL:
0368             x = SASL::RemoteUnavailable;
0369             break;
0370 
0371         default:
0372             x = SASL::AuthFail;
0373             break;
0374         }
0375         result_authCondition = x;
0376     }
0377 
0378     void getssfparams()
0379     {
0380         const void *maybe_sff;
0381         if (SASL_OK == sasl_getprop(con, SASL_SSF, &maybe_sff))
0382             result_ssf = *(const int *)maybe_sff;
0383 
0384         const void *maybe_maxoutbuf;
0385         if (SASL_OK == sasl_getprop(con, SASL_MAXOUTBUF, &maybe_maxoutbuf))
0386             maxoutbuf = *(const int *)maybe_maxoutbuf;
0387     }
0388 
0389     static int scb_checkauth(sasl_conn_t *,
0390                              void       *context,
0391                              const char *requested_user,
0392                              unsigned,
0393                              const char *auth_identity,
0394                              unsigned,
0395                              const char *,
0396                              unsigned,
0397                              struct propctx *)
0398     {
0399         saslContext *that = (saslContext *)context;
0400         that->sc_username = QString::fromLatin1(auth_identity);  // yeah yeah, it looks
0401         that->sc_authzid  = QString::fromLatin1(requested_user); // backwards, but it is right
0402         that->ca_flag     = true;
0403         return SASL_OK;
0404     }
0405 
0406     void clientTryAgain()
0407     {
0408         result_haveClientInit = false;
0409 
0410         if (step == 0) {
0411             const char  *clientout, *m;
0412             unsigned int clientoutlen;
0413 
0414             need               = nullptr;
0415             const QString list = result_mechlist.join(QStringLiteral(" "));
0416             int           r;
0417             while (true) {
0418                 if (need)
0419                     params.extractHave(need);
0420                 if (in_sendFirst)
0421                     r = sasl_client_start(con, list.toLatin1().data(), &need, &clientout, &clientoutlen, &m);
0422                 else
0423                     r = sasl_client_start(con, list.toLatin1().data(), &need, nullptr, nullptr, &m);
0424                 if (r != SASL_INTERACT)
0425                     break;
0426 
0427                 params.applyInteract(need);
0428                 if (params.missingAny()) {
0429                     out_mech      = QString::fromLatin1(m);
0430                     result_result = Params;
0431                     return;
0432                 }
0433             }
0434             if (r != SASL_OK && r != SASL_CONTINUE) {
0435                 setAuthCondition(r);
0436                 result_result = Error;
0437                 return;
0438             }
0439 
0440             out_mech = QString::fromLatin1(m);
0441             if (in_sendFirst && clientout) {
0442                 out_buf               = makeByteArray(clientout, clientoutlen);
0443                 result_haveClientInit = true;
0444             }
0445 
0446             ++step;
0447 
0448             if (r == SASL_OK) {
0449                 getssfparams();
0450                 result_result = Success;
0451                 return;
0452             }
0453             result_result = Continue;
0454             return;
0455         } else {
0456             const char  *clientout;
0457             unsigned int clientoutlen;
0458             int          r;
0459             while (true) {
0460                 if (need)
0461                     params.extractHave(need);
0462                 // printf("sasl_client_step(con, {%s}, %d, &need, &clientout, &clientoutlen);\n", in_buf.data(),
0463                 // in_buf.size());
0464                 r = sasl_client_step(con, in_buf.data(), in_buf.size(), &need, &clientout, &clientoutlen);
0465                 // printf("returned: %d\n", r);
0466                 if (r != SASL_INTERACT)
0467                     break;
0468 
0469                 params.applyInteract(need);
0470                 if (params.missingAny()) {
0471                     result_result = Params;
0472                     return;
0473                 }
0474             }
0475             if (r != SASL_OK && r != SASL_CONTINUE) {
0476                 setAuthCondition(r);
0477                 result_result = Error;
0478                 return;
0479             }
0480             out_buf = makeByteArray(clientout, clientoutlen);
0481             if (r == SASL_OK) {
0482                 getssfparams();
0483                 result_result = Success;
0484                 return;
0485             }
0486             result_result = Continue;
0487             return;
0488         }
0489     }
0490 
0491     void serverTryAgain()
0492     {
0493         if (step == 0) {
0494             if (!ca_skip) {
0495                 const char  *clientin    = nullptr;
0496                 unsigned int clientinlen = 0;
0497                 if (in_useClientInit) {
0498                     clientin    = in_clientInit.data();
0499                     clientinlen = in_clientInit.size();
0500                 }
0501                 const char  *serverout;
0502                 unsigned int serveroutlen;
0503                 ca_flag = false;
0504                 const int r =
0505                     sasl_server_start(con, in_mech.toLatin1().data(), clientin, clientinlen, &serverout, &serveroutlen);
0506                 if (r != SASL_OK && r != SASL_CONTINUE) {
0507                     setAuthCondition(r);
0508                     result_result = Error;
0509                     return;
0510                 }
0511                 out_buf = makeByteArray(serverout, serveroutlen);
0512                 last_r  = r;
0513                 if (ca_flag && !ca_done) {
0514                     ca_done       = true;
0515                     ca_skip       = true;
0516                     result_result = AuthCheck;
0517                     return;
0518                 }
0519             }
0520             ca_skip = false;
0521             ++step;
0522 
0523             if (last_r == SASL_OK) {
0524                 getssfparams();
0525                 result_result = Success;
0526                 return;
0527             }
0528             result_result = Continue;
0529             return;
0530         } else {
0531             if (!ca_skip) {
0532                 const char  *serverout;
0533                 unsigned int serveroutlen;
0534                 const int    r = sasl_server_step(con, in_buf.data(), in_buf.size(), &serverout, &serveroutlen);
0535                 if (r != SASL_OK && r != SASL_CONTINUE) {
0536                     setAuthCondition(r);
0537                     result_result = Error;
0538                     return;
0539                 }
0540                 if (r == SASL_OK)
0541                     out_buf.resize(0);
0542                 else
0543                     out_buf = makeByteArray(serverout, serveroutlen);
0544                 last_r = r;
0545                 if (ca_flag && !ca_done) {
0546                     ca_done       = true;
0547                     ca_skip       = true;
0548                     result_result = AuthCheck;
0549                     return;
0550                 }
0551             }
0552             ca_skip = false;
0553             if (last_r == SASL_OK) {
0554                 getssfparams();
0555                 result_result = Success;
0556                 return;
0557             }
0558             result_result = Continue;
0559             return;
0560         }
0561     }
0562 
0563     bool sasl_endecode(const QByteArray &in, QByteArray *out, bool enc)
0564     {
0565         // no security
0566         if (result_ssf == 0) {
0567             *out = in;
0568             return true;
0569         }
0570 
0571         int at = 0;
0572         out->resize(0);
0573         while (true) {
0574             int size = in.size() - at;
0575             if (size == 0)
0576                 break;
0577             if (size > maxoutbuf)
0578                 size = maxoutbuf;
0579             const char *outbuf;
0580             unsigned    len;
0581             int         r;
0582             if (enc)
0583                 r = sasl_encode(con, in.data() + at, size, &outbuf, &len);
0584             else
0585                 r = sasl_decode(con, in.data() + at, size, &outbuf, &len);
0586             if (r != SASL_OK)
0587                 return false;
0588             const int oldsize = out->size();
0589             out->resize(oldsize + len);
0590             memcpy(out->data() + oldsize, outbuf, len);
0591             at += size;
0592         }
0593         return true;
0594     }
0595 
0596     void doResultsReady()
0597     {
0598         QMetaObject::invokeMethod(this, "resultsReady", Qt::QueuedConnection);
0599     }
0600 
0601 public:
0602     saslContext(saslProvider *_g)
0603         : SASLContext(_g)
0604     {
0605         result_result = Success;
0606         g             = _g;
0607         con           = nullptr;
0608         callbacks     = nullptr;
0609 
0610         reset();
0611     }
0612 
0613     ~saslContext() override
0614     {
0615         reset();
0616     }
0617 
0618     Provider::Context *clone() const override
0619     {
0620         return nullptr;
0621     }
0622 
0623     Result result() const override
0624     {
0625         return result_result;
0626     }
0627 
0628     void reset() override
0629     {
0630         resetState();
0631         resetParams();
0632     }
0633 
0634     void setup(const QString  &_service,
0635                const QString  &_host,
0636                const HostPort *local,
0637                const HostPort *remote,
0638                const QString  &ext_id,
0639                int             _ext_ssf) override
0640     {
0641         service    = _service;
0642         host       = _host;
0643         localAddr  = local ? addrString(*local) : QLatin1String("");
0644         remoteAddr = remote ? addrString(*remote) : QLatin1String("");
0645         ext_authid = ext_id;
0646         ext_ssf    = _ext_ssf;
0647     }
0648 
0649     int ssf() const override
0650     {
0651         return result_ssf;
0652     }
0653 
0654     void startClient(const QStringList &mechlist, bool allowClientSendFirst) override
0655     {
0656         resetState();
0657 
0658         in_sendFirst = allowClientSendFirst;
0659 
0660         if (!g->client_init) {
0661             sasl_client_init(nullptr);
0662             g->client_init = true;
0663         }
0664 
0665         callbacks = new sasl_callback_t[5];
0666 
0667         callbacks[0].id      = SASL_CB_GETREALM;
0668         callbacks[0].proc    = nullptr;
0669         callbacks[0].context = nullptr;
0670 
0671         callbacks[1].id      = SASL_CB_USER;
0672         callbacks[1].proc    = nullptr;
0673         callbacks[1].context = nullptr;
0674 
0675         callbacks[2].id      = SASL_CB_AUTHNAME;
0676         callbacks[2].proc    = nullptr;
0677         callbacks[2].context = nullptr;
0678 
0679         callbacks[3].id      = SASL_CB_PASS;
0680         callbacks[3].proc    = nullptr;
0681         callbacks[3].context = nullptr;
0682 
0683         callbacks[4].id      = SASL_CB_LIST_END;
0684         callbacks[4].proc    = nullptr;
0685         callbacks[4].context = nullptr;
0686 
0687         result_result = Error;
0688 
0689         const int r = sasl_client_new(service.toLatin1().data(),
0690                                       host.toLatin1().data(),
0691                                       localAddr.isEmpty() ? nullptr : localAddr.toLatin1().data(),
0692                                       remoteAddr.isEmpty() ? nullptr : remoteAddr.toLatin1().data(),
0693                                       callbacks,
0694                                       0,
0695                                       &con);
0696         if (r != SASL_OK) {
0697             setAuthCondition(r);
0698             doResultsReady();
0699             return;
0700         }
0701 
0702         if (!setsecprops()) {
0703             doResultsReady();
0704             return;
0705         }
0706 
0707         result_mechlist = mechlist;
0708         servermode      = false;
0709         step            = 0;
0710         result_result   = Success;
0711         clientTryAgain();
0712         doResultsReady();
0713         return;
0714     }
0715 
0716     // TODO: make use of disableServerSendLast
0717     void startServer(const QString &realm, bool disableServerSendLast) override
0718     {
0719         Q_UNUSED(disableServerSendLast);
0720         resetState();
0721 
0722         g->appname = QStringLiteral(SASL_APP);
0723         if (!g->server_init) {
0724             sasl_server_init(nullptr, QFile::encodeName(g->appname).constData());
0725             g->server_init = true;
0726         }
0727 
0728         callbacks = new sasl_callback_t[2];
0729 
0730         callbacks[0].id      = SASL_CB_PROXY_POLICY;
0731         callbacks[0].proc    = (int (*)())scb_checkauth;
0732         callbacks[0].context = this;
0733 
0734         callbacks[1].id      = SASL_CB_LIST_END;
0735         callbacks[1].proc    = nullptr;
0736         callbacks[1].context = nullptr;
0737 
0738         result_result = Error;
0739 
0740         int r = sasl_server_new(service.toLatin1().data(),
0741                                 host.toLatin1().data(),
0742                                 !realm.isEmpty() ? realm.toLatin1().data() : nullptr,
0743                                 localAddr.isEmpty() ? nullptr : localAddr.toLatin1().data(),
0744                                 remoteAddr.isEmpty() ? nullptr : remoteAddr.toLatin1().data(),
0745                                 callbacks,
0746                                 0,
0747                                 &con);
0748         if (r != SASL_OK) {
0749             setAuthCondition(r);
0750             doResultsReady();
0751             return;
0752         }
0753 
0754         if (!setsecprops()) {
0755             doResultsReady();
0756             return;
0757         }
0758 
0759         const char *ml;
0760         r = sasl_listmech(con, nullptr, nullptr, " ", nullptr, &ml, nullptr, nullptr);
0761         if (r != SASL_OK)
0762             return;
0763         result_mechlist = QString::fromUtf8(ml).split(QLatin1Char(' '));
0764 
0765         servermode    = true;
0766         step          = 0;
0767         ca_done       = false;
0768         ca_skip       = false;
0769         result_result = Success;
0770         doResultsReady();
0771         return;
0772     }
0773 
0774     void serverFirstStep(const QString &mech, const QByteArray *clientInit) override
0775     {
0776         in_mech = mech;
0777         if (clientInit) {
0778             in_useClientInit = true;
0779             in_clientInit    = *clientInit;
0780         } else
0781             in_useClientInit = false;
0782         serverTryAgain();
0783         doResultsReady();
0784     }
0785 
0786     SASL::Params clientParams() const override
0787     {
0788         const SASLParams::SParams sparams = params.missing();
0789         return SASL::Params(sparams.user, sparams.authzid, sparams.pass, sparams.realm);
0790     }
0791 
0792     void
0793     setClientParams(const QString *user, const QString *authzid, const SecureArray *pass, const QString *realm) override
0794     {
0795         if (user)
0796             params.setUsername(*user);
0797         if (authzid)
0798             params.setAuthzid(*authzid);
0799         if (pass)
0800             params.setPassword(*pass);
0801         if (realm)
0802             params.setRealm(*realm);
0803     }
0804 
0805     QString username() const override
0806     {
0807         return sc_username;
0808     }
0809 
0810     QString authzid() const override
0811     {
0812         return sc_authzid;
0813     }
0814 
0815     void nextStep(const QByteArray &from_net) override
0816     {
0817         in_buf = from_net;
0818         tryAgain();
0819     }
0820 
0821     void tryAgain() override
0822     {
0823         if (servermode)
0824             serverTryAgain();
0825         else
0826             clientTryAgain();
0827         doResultsReady();
0828     }
0829 
0830     QString mech() const override
0831     {
0832         if (servermode)
0833             return in_mech;
0834         else
0835             return out_mech;
0836     }
0837 
0838     QStringList mechlist() const override
0839     {
0840         return result_mechlist;
0841     }
0842 
0843     QStringList realmlist() const override
0844     {
0845         // TODO
0846         return QStringList();
0847     }
0848 
0849     void setConstraints(SASL::AuthFlags f, int minSSF, int maxSSF) override
0850     {
0851         int sf = 0;
0852         if (!(f & SASL::AllowPlain))
0853             sf |= SASL_SEC_NOPLAINTEXT;
0854         // if( !(f & SASL::AllowActiveVulnerable) ) // TODO
0855         //  sf |= SASL_SEC_NOACTIVE;
0856         // if( !(f & SASL::AllowDictVulnerable) ) // TODO
0857         //  sf |= SASL_SEC_NODICTIONARY;
0858         if (!(f & SASL::AllowAnonymous))
0859             sf |= SASL_SEC_NOANONYMOUS;
0860         if (f & SASL::RequireForwardSecrecy)
0861             sf |= SASL_SEC_FORWARD_SECRECY;
0862         if (f & SASL::RequirePassCredentials)
0863             sf |= SASL_SEC_PASS_CREDENTIALS;
0864         if (f & SASL::RequireMutualAuth)
0865             sf |= SASL_SEC_MUTUAL_AUTH;
0866 
0867         secflags = sf;
0868         ssf_min  = minSSF;
0869         ssf_max  = maxSSF;
0870     }
0871 
0872     bool waitForResultsReady(int msecs) override
0873     {
0874         // TODO: for now, all operations block anyway
0875         Q_UNUSED(msecs);
0876         return true;
0877     }
0878 
0879     void update(const QByteArray &from_net, const QByteArray &from_app) override
0880     {
0881         bool ok = true;
0882         if (!from_app.isEmpty())
0883             ok = sasl_endecode(from_app, &result_to_net, true);
0884         if (ok && !from_net.isEmpty())
0885             ok = sasl_endecode(from_net, &result_plain, false);
0886         result_result  = ok ? Success : Error;
0887         result_encoded = from_app.size();
0888 
0889         // printf("update (from_net=%d, to_net=%d, from_app=%d, to_app=%d)\n", from_net.size(), result_to_net.size(),
0890         // from_app.size(), result_plain.size());
0891 
0892         doResultsReady();
0893     }
0894 
0895     bool haveClientInit() const override
0896     {
0897         return result_haveClientInit;
0898     }
0899 
0900     QByteArray stepData() const override
0901     {
0902         return out_buf;
0903     }
0904 
0905     QByteArray to_net() override
0906     {
0907         const QByteArray a = result_to_net;
0908         result_to_net.clear();
0909         return a;
0910     }
0911 
0912     int encoded() const override
0913     {
0914         return result_encoded;
0915     }
0916 
0917     QByteArray to_app() override
0918     {
0919         const QByteArray a = result_plain;
0920         result_plain.clear();
0921         return a;
0922     }
0923 
0924     SASL::AuthCondition authCondition() const override
0925     {
0926         return result_authCondition;
0927     }
0928 };
0929 
0930 //----------------------------------------------------------------------------
0931 // saslProvider
0932 //----------------------------------------------------------------------------
0933 saslProvider::saslProvider()
0934 {
0935     client_init = false;
0936     server_init = false;
0937 }
0938 
0939 void saslProvider::init()
0940 {
0941 }
0942 
0943 saslProvider::~saslProvider()
0944 {
0945     if (client_init || server_init)
0946         sasl_done();
0947 }
0948 
0949 int saslProvider::qcaVersion() const
0950 {
0951     return QCA_VERSION;
0952 }
0953 
0954 QString saslProvider::name() const
0955 {
0956     return QStringLiteral("qca-cyrus-sasl");
0957 }
0958 
0959 QString saslProvider::credit() const
0960 {
0961     return QString(); // TODO
0962 }
0963 
0964 QStringList saslProvider::features() const
0965 {
0966     QStringList list;
0967     list += QStringLiteral("sasl");
0968 
0969     return list;
0970 }
0971 
0972 Provider::Context *saslProvider::createContext(const QString &type)
0973 {
0974     if (type == QLatin1String("sasl"))
0975         return new saslContext(this);
0976 
0977     return nullptr;
0978 }
0979 
0980 } // namespace saslQCAPlugin
0981 
0982 using namespace saslQCAPlugin;
0983 
0984 //----------------------------------------------------------------------------
0985 // saslPlugin
0986 //----------------------------------------------------------------------------
0987 
0988 class saslPlugin : public QObject, public QCAPlugin
0989 {
0990     Q_OBJECT
0991     Q_PLUGIN_METADATA(IID "com.affinix.qca.Plugin/1.0")
0992     Q_INTERFACES(QCAPlugin)
0993 public:
0994     Provider *createProvider() override
0995     {
0996         return new saslProvider;
0997     }
0998 };
0999 
1000 #include "qca-cyrus-sasl.moc"