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"