1 /*
2 * qca-sasl.cpp - SASL plugin for QCA
3 * Copyright (C) 2003-2007 Justin Karneges <justin@affinix.com>
4 * Copyright (C) 2006 Michail Pishchagin <mblsha@gmail.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 *
20 */
21
22 #include <QDebug>
23 #include <QtCrypto>
24 #include <QtPlugin>
25 #include <qcaprovider.h>
26
27 extern "C" {
28 #include <sasl/sasl.h>
29 }
30
31 #include <QFile>
32 #include <QList>
33 #include <QStringList>
34
35 #define SASL_BUFSIZE 8192
36 #define SASL_APP "qca"
37
38 using namespace QCA;
39
40 namespace saslQCAPlugin {
41
42 class saslProvider : public Provider
43 {
44 public:
45 saslProvider();
46 void init() override;
47 ~saslProvider() override;
48 int qcaVersion() const override;
49 QString name() const override;
50 QString credit() const override;
51 QStringList features() const override;
52 Context * createContext(const QString &type) override;
53
54 bool client_init;
55 bool server_init;
56 QString appname;
57 };
58
59 //----------------------------------------------------------------------------
60 // SASLParams
61 //----------------------------------------------------------------------------
62
63 class SASLParams
64 {
65 public:
66 class SParams
67 {
68 public:
69 bool user, authzid, pass, realm;
70 };
71
SASLParams()72 SASLParams()
73 {
74 reset();
75 }
76
reset()77 void reset()
78 {
79 resetNeed();
80 resetHave();
81 foreach (char *result, results)
82 delete result;
83 results.clear();
84 }
85
resetNeed()86 void resetNeed()
87 {
88 need.user = false;
89 need.authzid = false;
90 need.pass = false;
91 need.realm = false;
92 }
93
resetHave()94 void resetHave()
95 {
96 have.user = false;
97 have.authzid = false;
98 have.pass = false;
99 have.realm = false;
100 }
101
setUsername(const QString & s)102 void setUsername(const QString &s)
103 {
104 have.user = true;
105 user = s;
106 }
107
setAuthzid(const QString & s)108 void setAuthzid(const QString &s)
109 {
110 have.authzid = true;
111 authzid = s;
112 }
113
setPassword(const SecureArray & s)114 void setPassword(const SecureArray &s)
115 {
116 have.pass = true;
117 pass = QString::fromUtf8(s.toByteArray());
118 }
119
setRealm(const QString & s)120 void setRealm(const QString &s)
121 {
122 have.realm = true;
123 realm = s;
124 }
125
applyInteract(sasl_interact_t * needp)126 void applyInteract(sasl_interact_t *needp)
127 {
128 for (int n = 0; needp[n].id != SASL_CB_LIST_END; ++n) {
129 if (needp[n].id == SASL_CB_AUTHNAME)
130 need.user = true; // yes, I know these
131 if (needp[n].id == SASL_CB_USER)
132 need.authzid = true; // look backwards
133 if (needp[n].id == SASL_CB_PASS)
134 need.pass = true;
135 if (needp[n].id == SASL_CB_GETREALM)
136 need.realm = true;
137 }
138 }
139
extractHave(sasl_interact_t * needp)140 void extractHave(sasl_interact_t *needp)
141 {
142 for (int n = 0; needp[n].id != SASL_CB_LIST_END; ++n) {
143 if (needp[n].id == SASL_CB_AUTHNAME && have.user)
144 setValue(&needp[n], user);
145 if (needp[n].id == SASL_CB_USER && have.authzid)
146 setValue(&needp[n], authzid);
147 if (needp[n].id == SASL_CB_PASS && have.pass)
148 setValue(&needp[n], pass);
149 if (needp[n].id == SASL_CB_GETREALM && have.realm)
150 setValue(&needp[n], realm);
151 }
152 }
153
missingAny() const154 bool missingAny() const
155 {
156 if ((need.user && !have.user) /*|| (need.authzid && !have.authzid)*/ ||
157 (need.pass && !have.pass) /*|| (need.realm && !have.realm)*/)
158 return true;
159 return false;
160 }
161
missing() const162 SParams missing() const
163 {
164 SParams np = need;
165 if (have.user)
166 np.user = false;
167 if (have.authzid)
168 np.authzid = false;
169 if (have.pass)
170 np.pass = false;
171 if (have.realm)
172 np.realm = false;
173 return np;
174 }
175
setValue(sasl_interact_t * i,const QString & s)176 void setValue(sasl_interact_t *i, const QString &s)
177 {
178 if (i->result)
179 return;
180 const QByteArray cs = s.toUtf8();
181 const int len = cs.length();
182 char * p = new char[len + 1];
183 memcpy(p, cs.data(), len);
184 p[len] = 0;
185 i->result = p;
186 i->len = len;
187
188 // record this
189 results.append(p);
190 }
191
192 QList<char *> results;
193 SParams need;
194 SParams have;
195 QString user, authzid, pass, realm;
196 };
197
makeByteArray(const void * in,unsigned int len)198 static QByteArray makeByteArray(const void *in, unsigned int len)
199 {
200 QByteArray buf(len, 0);
201 memcpy(buf.data(), in, len);
202 return buf;
203 }
204
addrString(const SASLContext::HostPort & hp)205 static QString addrString(const SASLContext::HostPort &hp)
206 {
207 return (hp.addr + QLatin1Char(';') + QString::number(hp.port));
208 }
209
210 //----------------------------------------------------------------------------
211 // saslContext
212 //----------------------------------------------------------------------------
213
214 class saslContext : public SASLContext
215 {
216 Q_OBJECT
217 saslProvider *g;
218
219 // core props
220 QString service, host;
221 QString localAddr, remoteAddr;
222
223 // security props
224 int secflags;
225 int ssf_min, ssf_max;
226 QString ext_authid;
227 int ext_ssf;
228
229 sasl_conn_t * con;
230 sasl_interact_t *need;
231 int maxoutbuf;
232 sasl_callback_t *callbacks;
233
234 // state
235 bool servermode;
236 int step;
237 bool in_sendFirst;
238 QByteArray in_buf;
239 QString in_mech;
240 bool in_useClientInit;
241 QByteArray in_clientInit;
242 QString out_mech;
243 // bool out_useClientInit;
244 // QByteArray out_clientInit;
245 QByteArray out_buf;
246
247 SASLParams params;
248 QString sc_username, sc_authzid;
249 bool ca_flag, ca_done, ca_skip;
250 int last_r;
251
252 int result_ssf;
253 Result result_result;
254 bool result_haveClientInit;
255 QStringList result_mechlist;
256 SASL::AuthCondition result_authCondition;
257 QByteArray result_to_net;
258 QByteArray result_plain;
259 int result_encoded;
260
261 private:
resetState()262 void resetState()
263 {
264 if (con) {
265 sasl_dispose(&con);
266 con = nullptr;
267 }
268 need = nullptr;
269 if (callbacks) {
270 delete callbacks;
271 callbacks = nullptr;
272 }
273
274 localAddr = QLatin1String("");
275 remoteAddr = QLatin1String("");
276 maxoutbuf = 128;
277 sc_username = QLatin1String("");
278 sc_authzid = QLatin1String("");
279
280 result_authCondition = SASL::AuthFail;
281 result_haveClientInit = false;
282 result_mechlist.clear();
283 result_plain.clear();
284 result_plain.clear();
285 result_plain.clear();
286 result_ssf = 0;
287 }
288
resetParams()289 void resetParams()
290 {
291 params.reset();
292 secflags = 0;
293 ssf_min = 0;
294 ssf_max = 0;
295 ext_authid = QLatin1String("");
296 ext_ssf = 0;
297 }
298
setsecprops()299 bool setsecprops()
300 {
301 sasl_security_properties_t secprops;
302 secprops.min_ssf = ssf_min;
303 secprops.max_ssf = ssf_max;
304 secprops.maxbufsize = SASL_BUFSIZE;
305 secprops.property_names = nullptr;
306 secprops.property_values = nullptr;
307 secprops.security_flags = secflags;
308 int r = sasl_setprop(con, SASL_SEC_PROPS, &secprops);
309 if (r != SASL_OK)
310 return false;
311
312 if (!ext_authid.isEmpty()) {
313 const QByteArray ext_authidBA = ext_authid.toLatin1();
314 const char * authid = ext_authidBA.data();
315 sasl_ssf_t ssf = ext_ssf;
316 r = sasl_setprop(con, SASL_SSF_EXTERNAL, &ssf);
317 if (r != SASL_OK)
318 return false;
319 r = sasl_setprop(con, SASL_AUTH_EXTERNAL, authid);
320 if (r != SASL_OK)
321 return false;
322 }
323
324 return true;
325 }
326
setAuthCondition(int r)327 void setAuthCondition(int r)
328 {
329 // qDebug() << "authcondition: " << r;
330 SASL::AuthCondition x;
331 switch (r) {
332 // common
333 case SASL_NOMECH:
334 x = SASL::NoMechanism;
335 break;
336 case SASL_BADPROT:
337 x = SASL::BadProtocol;
338 break;
339
340 // client
341 case SASL_BADSERV:
342 x = SASL::BadServer;
343 break;
344
345 // server
346 case SASL_BADAUTH:
347 x = SASL::BadAuth;
348 break;
349 case SASL_NOAUTHZ:
350 x = SASL::NoAuthzid;
351 break;
352 case SASL_TOOWEAK:
353 x = SASL::TooWeak;
354 break;
355 case SASL_ENCRYPT:
356 x = SASL::NeedEncrypt;
357 break;
358 case SASL_EXPIRED:
359 x = SASL::Expired;
360 break;
361 case SASL_DISABLED:
362 x = SASL::Disabled;
363 break;
364 case SASL_NOUSER:
365 x = SASL::NoUser;
366 break;
367 case SASL_UNAVAIL:
368 x = SASL::RemoteUnavailable;
369 break;
370
371 default:
372 x = SASL::AuthFail;
373 break;
374 }
375 result_authCondition = x;
376 }
377
getssfparams()378 void getssfparams()
379 {
380 const void *maybe_sff;
381 if (SASL_OK == sasl_getprop(con, SASL_SSF, &maybe_sff))
382 result_ssf = *(const int *)maybe_sff;
383
384 const void *maybe_maxoutbuf;
385 if (SASL_OK == sasl_getprop(con, SASL_MAXOUTBUF, &maybe_maxoutbuf))
386 maxoutbuf = *(const int *)maybe_maxoutbuf;
387 }
388
scb_checkauth(sasl_conn_t *,void * context,const char * requested_user,unsigned,const char * auth_identity,unsigned,const char *,unsigned,struct propctx *)389 static int scb_checkauth(sasl_conn_t *,
390 void * context,
391 const char *requested_user,
392 unsigned,
393 const char *auth_identity,
394 unsigned,
395 const char *,
396 unsigned,
397 struct propctx *)
398 {
399 saslContext *that = (saslContext *)context;
400 that->sc_username = QString::fromLatin1(auth_identity); // yeah yeah, it looks
401 that->sc_authzid = QString::fromLatin1(requested_user); // backwards, but it is right
402 that->ca_flag = true;
403 return SASL_OK;
404 }
405
clientTryAgain()406 void clientTryAgain()
407 {
408 result_haveClientInit = false;
409
410 if (step == 0) {
411 const char * clientout, *m;
412 unsigned int clientoutlen;
413
414 need = nullptr;
415 const QString list = result_mechlist.join(QStringLiteral(" "));
416 int r;
417 while (true) {
418 if (need)
419 params.extractHave(need);
420 if (in_sendFirst)
421 r = sasl_client_start(con, list.toLatin1().data(), &need, &clientout, &clientoutlen, &m);
422 else
423 r = sasl_client_start(con, list.toLatin1().data(), &need, nullptr, nullptr, &m);
424 if (r != SASL_INTERACT)
425 break;
426
427 params.applyInteract(need);
428 if (params.missingAny()) {
429 out_mech = QString::fromLatin1(m);
430 result_result = Params;
431 return;
432 }
433 }
434 if (r != SASL_OK && r != SASL_CONTINUE) {
435 setAuthCondition(r);
436 result_result = Error;
437 return;
438 }
439
440 out_mech = QString::fromLatin1(m);
441 if (in_sendFirst && clientout) {
442 out_buf = makeByteArray(clientout, clientoutlen);
443 result_haveClientInit = true;
444 }
445
446 ++step;
447
448 if (r == SASL_OK) {
449 getssfparams();
450 result_result = Success;
451 return;
452 }
453 result_result = Continue;
454 return;
455 } else {
456 const char * clientout;
457 unsigned int clientoutlen;
458 int r;
459 while (true) {
460 if (need)
461 params.extractHave(need);
462 // printf("sasl_client_step(con, {%s}, %d, &need, &clientout, &clientoutlen);\n", in_buf.data(),
463 // in_buf.size());
464 r = sasl_client_step(con, in_buf.data(), in_buf.size(), &need, &clientout, &clientoutlen);
465 // printf("returned: %d\n", r);
466 if (r != SASL_INTERACT)
467 break;
468
469 params.applyInteract(need);
470 if (params.missingAny()) {
471 result_result = Params;
472 return;
473 }
474 }
475 if (r != SASL_OK && r != SASL_CONTINUE) {
476 setAuthCondition(r);
477 result_result = Error;
478 return;
479 }
480 out_buf = makeByteArray(clientout, clientoutlen);
481 if (r == SASL_OK) {
482 getssfparams();
483 result_result = Success;
484 return;
485 }
486 result_result = Continue;
487 return;
488 }
489 }
490
serverTryAgain()491 void serverTryAgain()
492 {
493 if (step == 0) {
494 if (!ca_skip) {
495 const char * clientin = nullptr;
496 unsigned int clientinlen = 0;
497 if (in_useClientInit) {
498 clientin = in_clientInit.data();
499 clientinlen = in_clientInit.size();
500 }
501 const char * serverout;
502 unsigned int serveroutlen;
503 ca_flag = false;
504 const int r =
505 sasl_server_start(con, in_mech.toLatin1().data(), clientin, clientinlen, &serverout, &serveroutlen);
506 if (r != SASL_OK && r != SASL_CONTINUE) {
507 setAuthCondition(r);
508 result_result = Error;
509 return;
510 }
511 out_buf = makeByteArray(serverout, serveroutlen);
512 last_r = r;
513 if (ca_flag && !ca_done) {
514 ca_done = true;
515 ca_skip = true;
516 result_result = AuthCheck;
517 return;
518 }
519 }
520 ca_skip = false;
521 ++step;
522
523 if (last_r == SASL_OK) {
524 getssfparams();
525 result_result = Success;
526 return;
527 }
528 result_result = Continue;
529 return;
530 } else {
531 if (!ca_skip) {
532 const char * serverout;
533 unsigned int serveroutlen;
534 const int r = sasl_server_step(con, in_buf.data(), in_buf.size(), &serverout, &serveroutlen);
535 if (r != SASL_OK && r != SASL_CONTINUE) {
536 setAuthCondition(r);
537 result_result = Error;
538 return;
539 }
540 if (r == SASL_OK)
541 out_buf.resize(0);
542 else
543 out_buf = makeByteArray(serverout, serveroutlen);
544 last_r = r;
545 if (ca_flag && !ca_done) {
546 ca_done = true;
547 ca_skip = true;
548 result_result = AuthCheck;
549 return;
550 }
551 }
552 ca_skip = false;
553 if (last_r == SASL_OK) {
554 getssfparams();
555 result_result = Success;
556 return;
557 }
558 result_result = Continue;
559 return;
560 }
561 }
562
sasl_endecode(const QByteArray & in,QByteArray * out,bool enc)563 bool sasl_endecode(const QByteArray &in, QByteArray *out, bool enc)
564 {
565 // no security
566 if (result_ssf == 0) {
567 *out = in;
568 return true;
569 }
570
571 int at = 0;
572 out->resize(0);
573 while (true) {
574 int size = in.size() - at;
575 if (size == 0)
576 break;
577 if (size > maxoutbuf)
578 size = maxoutbuf;
579 const char *outbuf;
580 unsigned len;
581 int r;
582 if (enc)
583 r = sasl_encode(con, in.data() + at, size, &outbuf, &len);
584 else
585 r = sasl_decode(con, in.data() + at, size, &outbuf, &len);
586 if (r != SASL_OK)
587 return false;
588 const int oldsize = out->size();
589 out->resize(oldsize + len);
590 memcpy(out->data() + oldsize, outbuf, len);
591 at += size;
592 }
593 return true;
594 }
595
doResultsReady()596 void doResultsReady()
597 {
598 QMetaObject::invokeMethod(this, "resultsReady", Qt::QueuedConnection);
599 }
600
601 public:
saslContext(saslProvider * _g)602 saslContext(saslProvider *_g)
603 : SASLContext(_g)
604 {
605 result_result = Success;
606 g = _g;
607 con = nullptr;
608 callbacks = nullptr;
609
610 reset();
611 }
612
~saslContext()613 ~saslContext() override
614 {
615 reset();
616 }
617
clone() const618 Provider::Context *clone() const override
619 {
620 return nullptr;
621 }
622
result() const623 Result result() const override
624 {
625 return result_result;
626 }
627
reset()628 void reset() override
629 {
630 resetState();
631 resetParams();
632 }
633
setup(const QString & _service,const QString & _host,const HostPort * local,const HostPort * remote,const QString & ext_id,int _ext_ssf)634 void setup(const QString & _service,
635 const QString & _host,
636 const HostPort *local,
637 const HostPort *remote,
638 const QString & ext_id,
639 int _ext_ssf) override
640 {
641 service = _service;
642 host = _host;
643 localAddr = local ? addrString(*local) : QLatin1String("");
644 remoteAddr = remote ? addrString(*remote) : QLatin1String("");
645 ext_authid = ext_id;
646 ext_ssf = _ext_ssf;
647 }
648
ssf() const649 int ssf() const override
650 {
651 return result_ssf;
652 }
653
startClient(const QStringList & mechlist,bool allowClientSendFirst)654 void startClient(const QStringList &mechlist, bool allowClientSendFirst) override
655 {
656 resetState();
657
658 in_sendFirst = allowClientSendFirst;
659
660 if (!g->client_init) {
661 sasl_client_init(nullptr);
662 g->client_init = true;
663 }
664
665 callbacks = new sasl_callback_t[5];
666
667 callbacks[0].id = SASL_CB_GETREALM;
668 callbacks[0].proc = nullptr;
669 callbacks[0].context = nullptr;
670
671 callbacks[1].id = SASL_CB_USER;
672 callbacks[1].proc = nullptr;
673 callbacks[1].context = nullptr;
674
675 callbacks[2].id = SASL_CB_AUTHNAME;
676 callbacks[2].proc = nullptr;
677 callbacks[2].context = nullptr;
678
679 callbacks[3].id = SASL_CB_PASS;
680 callbacks[3].proc = nullptr;
681 callbacks[3].context = nullptr;
682
683 callbacks[4].id = SASL_CB_LIST_END;
684 callbacks[4].proc = nullptr;
685 callbacks[4].context = nullptr;
686
687 result_result = Error;
688
689 const int r = sasl_client_new(service.toLatin1().data(),
690 host.toLatin1().data(),
691 localAddr.isEmpty() ? nullptr : localAddr.toLatin1().data(),
692 remoteAddr.isEmpty() ? nullptr : remoteAddr.toLatin1().data(),
693 callbacks,
694 0,
695 &con);
696 if (r != SASL_OK) {
697 setAuthCondition(r);
698 doResultsReady();
699 return;
700 }
701
702 if (!setsecprops()) {
703 doResultsReady();
704 return;
705 }
706
707 result_mechlist = mechlist;
708 servermode = false;
709 step = 0;
710 result_result = Success;
711 clientTryAgain();
712 doResultsReady();
713 return;
714 }
715
716 // TODO: make use of disableServerSendLast
startServer(const QString & realm,bool disableServerSendLast)717 void startServer(const QString &realm, bool disableServerSendLast) override
718 {
719 Q_UNUSED(disableServerSendLast);
720 resetState();
721
722 g->appname = QStringLiteral(SASL_APP);
723 if (!g->server_init) {
724 sasl_server_init(nullptr, QFile::encodeName(g->appname).constData());
725 g->server_init = true;
726 }
727
728 callbacks = new sasl_callback_t[2];
729
730 callbacks[0].id = SASL_CB_PROXY_POLICY;
731 callbacks[0].proc = (int (*)())scb_checkauth;
732 callbacks[0].context = this;
733
734 callbacks[1].id = SASL_CB_LIST_END;
735 callbacks[1].proc = nullptr;
736 callbacks[1].context = nullptr;
737
738 result_result = Error;
739
740 int r = sasl_server_new(service.toLatin1().data(),
741 host.toLatin1().data(),
742 !realm.isEmpty() ? realm.toLatin1().data() : nullptr,
743 localAddr.isEmpty() ? nullptr : localAddr.toLatin1().data(),
744 remoteAddr.isEmpty() ? nullptr : remoteAddr.toLatin1().data(),
745 callbacks,
746 0,
747 &con);
748 if (r != SASL_OK) {
749 setAuthCondition(r);
750 doResultsReady();
751 return;
752 }
753
754 if (!setsecprops()) {
755 doResultsReady();
756 return;
757 }
758
759 const char *ml;
760 r = sasl_listmech(con, nullptr, nullptr, " ", nullptr, &ml, nullptr, nullptr);
761 if (r != SASL_OK)
762 return;
763 result_mechlist = QString::fromUtf8(ml).split(QLatin1Char(' '));
764
765 servermode = true;
766 step = 0;
767 ca_done = false;
768 ca_skip = false;
769 result_result = Success;
770 doResultsReady();
771 return;
772 }
773
serverFirstStep(const QString & mech,const QByteArray * clientInit)774 void serverFirstStep(const QString &mech, const QByteArray *clientInit) override
775 {
776 in_mech = mech;
777 if (clientInit) {
778 in_useClientInit = true;
779 in_clientInit = *clientInit;
780 } else
781 in_useClientInit = false;
782 serverTryAgain();
783 doResultsReady();
784 }
785
clientParams() const786 SASL::Params clientParams() const override
787 {
788 const SASLParams::SParams sparams = params.missing();
789 return SASL::Params(sparams.user, sparams.authzid, sparams.pass, sparams.realm);
790 }
791
792 void
setClientParams(const QString * user,const QString * authzid,const SecureArray * pass,const QString * realm)793 setClientParams(const QString *user, const QString *authzid, const SecureArray *pass, const QString *realm) override
794 {
795 if (user)
796 params.setUsername(*user);
797 if (authzid)
798 params.setAuthzid(*authzid);
799 if (pass)
800 params.setPassword(*pass);
801 if (realm)
802 params.setRealm(*realm);
803 }
804
username() const805 QString username() const override
806 {
807 return sc_username;
808 }
809
authzid() const810 QString authzid() const override
811 {
812 return sc_authzid;
813 }
814
nextStep(const QByteArray & from_net)815 void nextStep(const QByteArray &from_net) override
816 {
817 in_buf = from_net;
818 tryAgain();
819 }
820
tryAgain()821 void tryAgain() override
822 {
823 if (servermode)
824 serverTryAgain();
825 else
826 clientTryAgain();
827 doResultsReady();
828 }
829
mech() const830 QString mech() const override
831 {
832 if (servermode)
833 return in_mech;
834 else
835 return out_mech;
836 }
837
mechlist() const838 QStringList mechlist() const override
839 {
840 return result_mechlist;
841 }
842
realmlist() const843 QStringList realmlist() const override
844 {
845 // TODO
846 return QStringList();
847 }
848
setConstraints(SASL::AuthFlags f,int minSSF,int maxSSF)849 void setConstraints(SASL::AuthFlags f, int minSSF, int maxSSF) override
850 {
851 int sf = 0;
852 if (!(f & SASL::AllowPlain))
853 sf |= SASL_SEC_NOPLAINTEXT;
854 // if( !(f & SASL::AllowActiveVulnerable) ) // TODO
855 // sf |= SASL_SEC_NOACTIVE;
856 // if( !(f & SASL::AllowDictVulnerable) ) // TODO
857 // sf |= SASL_SEC_NODICTIONARY;
858 if (!(f & SASL::AllowAnonymous))
859 sf |= SASL_SEC_NOANONYMOUS;
860 if (f & SASL::RequireForwardSecrecy)
861 sf |= SASL_SEC_FORWARD_SECRECY;
862 if (f & SASL::RequirePassCredentials)
863 sf |= SASL_SEC_PASS_CREDENTIALS;
864 if (f & SASL::RequireMutualAuth)
865 sf |= SASL_SEC_MUTUAL_AUTH;
866
867 secflags = sf;
868 ssf_min = minSSF;
869 ssf_max = maxSSF;
870 }
871
waitForResultsReady(int msecs)872 bool waitForResultsReady(int msecs) override
873 {
874 // TODO: for now, all operations block anyway
875 Q_UNUSED(msecs);
876 return true;
877 }
878
update(const QByteArray & from_net,const QByteArray & from_app)879 void update(const QByteArray &from_net, const QByteArray &from_app) override
880 {
881 bool ok = true;
882 if (!from_app.isEmpty())
883 ok = sasl_endecode(from_app, &result_to_net, true);
884 if (ok && !from_net.isEmpty())
885 ok = sasl_endecode(from_net, &result_plain, false);
886 result_result = ok ? Success : Error;
887 result_encoded = from_app.size();
888
889 // printf("update (from_net=%d, to_net=%d, from_app=%d, to_app=%d)\n", from_net.size(), result_to_net.size(),
890 // from_app.size(), result_plain.size());
891
892 doResultsReady();
893 }
894
haveClientInit() const895 bool haveClientInit() const override
896 {
897 return result_haveClientInit;
898 }
899
stepData() const900 QByteArray stepData() const override
901 {
902 return out_buf;
903 }
904
to_net()905 QByteArray to_net() override
906 {
907 const QByteArray a = result_to_net;
908 result_to_net.clear();
909 return a;
910 }
911
encoded() const912 int encoded() const override
913 {
914 return result_encoded;
915 }
916
to_app()917 QByteArray to_app() override
918 {
919 const QByteArray a = result_plain;
920 result_plain.clear();
921 return a;
922 }
923
authCondition() const924 SASL::AuthCondition authCondition() const override
925 {
926 return result_authCondition;
927 }
928 };
929
930 //----------------------------------------------------------------------------
931 // saslProvider
932 //----------------------------------------------------------------------------
saslProvider()933 saslProvider::saslProvider()
934 {
935 client_init = false;
936 server_init = false;
937 }
938
init()939 void saslProvider::init()
940 {
941 }
942
~saslProvider()943 saslProvider::~saslProvider()
944 {
945 if (client_init || server_init)
946 sasl_done();
947 }
948
qcaVersion() const949 int saslProvider::qcaVersion() const
950 {
951 return QCA_VERSION;
952 }
953
name() const954 QString saslProvider::name() const
955 {
956 return QStringLiteral("qca-cyrus-sasl");
957 }
958
credit() const959 QString saslProvider::credit() const
960 {
961 return QString(); // TODO
962 }
963
features() const964 QStringList saslProvider::features() const
965 {
966 QStringList list;
967 list += QStringLiteral("sasl");
968
969 return list;
970 }
971
createContext(const QString & type)972 Provider::Context *saslProvider::createContext(const QString &type)
973 {
974 if (type == QLatin1String("sasl"))
975 return new saslContext(this);
976
977 return nullptr;
978 }
979
980 } // namespace saslQCAPlugin
981
982 using namespace saslQCAPlugin;
983
984 //----------------------------------------------------------------------------
985 // saslPlugin
986 //----------------------------------------------------------------------------
987
988 class saslPlugin : public QObject, public QCAPlugin
989 {
990 Q_OBJECT
991 Q_PLUGIN_METADATA(IID "com.affinix.qca.Plugin/1.0")
992 Q_INTERFACES(QCAPlugin)
993 public:
createProvider()994 Provider *createProvider() override
995 {
996 return new saslProvider;
997 }
998 };
999
1000 #include "qca-cyrus-sasl.moc"
1001