From 1a0cf2b8e5db44312b51bd8084d23f4ebae23e84 Mon Sep 17 00:00:00 2001 From: Justin Karneges Date: Thu, 28 Aug 2003 01:38:28 +0000 Subject: [PATCH] reorganized cyrus sasl plugin svn path=/trunk/kdesupport/qca/; revision=245831 --- TODO | 7 +- plugins/qcacyrussasl.cpp | 392 +++++++++++++++++++++++++-------------- src/qca.cpp | 73 +++++--- src/qca.h | 2 +- src/qcaprovider.h | 35 ++-- 5 files changed, 326 insertions(+), 183 deletions(-) diff --git a/TODO b/TODO index 2899769a..a1043656 100644 --- a/TODO +++ b/TODO @@ -1,14 +1,11 @@ * cipher: option to specify size for genkey * cert: properly check hostnames with wildcards * ssl: error signal -* sasl: option to not support client-send-first -* sasl: other security options -* sasl: server auth callback -* sasl: security layer +* sasl: bring API up to speed with the plugin * openssl plugin: fixmes and todos +* cyrussasl plugin: serverstepthread -* sasl: external auth * dsa * diffie-hellman diff --git a/plugins/qcacyrussasl.cpp b/plugins/qcacyrussasl.cpp index ce90f3a9..33cc7c91 100644 --- a/plugins/qcacyrussasl.cpp +++ b/plugins/qcacyrussasl.cpp @@ -29,6 +29,7 @@ extern "C" #include #include #include +#include #define SASL_BUFSIZE 8192 @@ -185,10 +186,25 @@ static QString methodsToString(const QStringList &methods) return list; } +// needed to give interactive behavior to a callback-based function +class ServerStepThread : public QThread +{ +public: + ServerStepThread() + { + } + + void run() + { + //int r = sasl_server_start(con, in_mech.latin1(), clientin, clientinlen, &serverout, &serveroutlen); + } +}; + class SASLContext : public QCA_SASLContext { public: QCACyrusSASL *g; + ServerStepThread *sst; // core props QString service, host; @@ -197,25 +213,37 @@ public: // security props int secflags; int ssf_min, ssf_max; - - // params - SASLParams params; - int ssf, maxoutbuf; + QString ext_authid; + int ext_ssf; sasl_conn_t *con; sasl_interact_t *need; + int ssf, maxoutbuf; QStringList mechlist; - bool servermode; sasl_callback_t *callbacks; - bool (*authCallback)(const QString &authname, const QString &username, QCA_SASLContext *c); + + // state + bool servermode; + int step; + bool in_sendFirst; + QByteArray in_buf; + QString in_mech; + bool in_useClientInit; + QByteArray in_clientInit; + QString out_mech; + bool out_useClientInit; + QByteArray out_clientInit; + QByteArray out_buf; + + SASLParams params; + QString sc_authname, sc_username; SASLContext(QCACyrusSASL *_g) { g = _g; con = 0; - need = 0; callbacks = 0; - authCallback = 0; + sst = 0; reset(); } @@ -233,6 +261,10 @@ public: void resetState() { + if(sst) { + // only would happen if the user forgot to call setAuth, so let's do it now + setAuth(false); + } if(con) { sasl_dispose(&con); con = 0; @@ -248,6 +280,8 @@ public: mechlist.clear(); ssf = 0; maxoutbuf = 0; + sc_authname = ""; + sc_username = ""; } void resetParams() @@ -256,6 +290,8 @@ public: secflags = 0; ssf_min = 0; ssf_max = 0; + ext_authid = ""; + ext_ssf = 0; } void setCoreProps(const QString &_service, const QString &_host, QCA_SASLHostPort *la, QCA_SASLHostPort *ra) @@ -266,7 +302,7 @@ public: remoteAddr = ra ? addrString(*ra) : ""; } - void setSecurityProps(bool noPlain, bool noActive, bool noDict, bool noAnon, bool reqForward, bool reqCreds, bool reqMutual, int ssfMin, int ssfMax) + void setSecurityProps(bool noPlain, bool noActive, bool noDict, bool noAnon, bool reqForward, bool reqCreds, bool reqMutual, int ssfMin, int ssfMax, const QString &_ext_authid, int _ext_ssf) { int sf = 0; if(noPlain) @@ -286,11 +322,8 @@ public: secflags = sf; ssf_min = ssfMin; ssf_max = ssfMax; - } - - void setAuthCallback(bool (*auth)(const QString &authname, const QString &username, QCA_SASLContext *c)) - { - authCallback = auth; + ext_authid = _ext_authid; + ext_ssf = _ext_ssf; } static int scb_checkauth(sasl_conn_t *, void *context, const char *requested_user, unsigned, const char *auth_identity, unsigned, const char *, unsigned, struct propctx *) @@ -298,17 +331,17 @@ public: SASLContext *that = (SASLContext *)context; QString authname = auth_identity; QString username = requested_user; - if(that->authCallback) { + /*if(that->authCallback) { if(that->authCallback(authname, username, that)) return SASL_OK; else return SASL_NOAUTHZ; } - else + else*/ return SASL_OK; } - void setsecprops() + bool setsecprops() { sasl_security_properties_t secprops; secprops.min_ssf = ssf_min; @@ -317,7 +350,22 @@ public: secprops.property_names = NULL; secprops.property_values = NULL; secprops.security_flags = secflags; - sasl_setprop(con, SASL_SEC_PROPS, &secprops); + int r = sasl_setprop(con, SASL_SEC_PROPS, &secprops); + if(r != SASL_OK) + return false; + + if(!ext_authid.isEmpty()) { + const char *authid = ext_authid.latin1(); + sasl_ssf_t ssf = ext_ssf; + r = sasl_setprop(con, SASL_SSF_EXTERNAL, &ssf); + if(r != SASL_OK) + return false; + r = sasl_setprop(con, SASL_AUTH_EXTERNAL, &authid); + if(r != SASL_OK) + return false; + } + + return true; } void getssfparams() @@ -369,13 +417,21 @@ public: if(r != SASL_OK) return false; - setsecprops(); + if(!setsecprops()) + return false; mechlist = _mechlist; servermode = false; + step = 0; return true; } + int clientFirstStep(bool allowClientSendFirst) + { + in_sendFirst = allowClientSendFirst; + return clientTryAgain(); + } + bool serverStart(const QString &realm, QStringList *mechlist, const QString &name) { resetState(); @@ -400,7 +456,8 @@ public: if(r != SASL_OK) return false; - setsecprops(); + if(!setsecprops()) + return false; const char *ml; r = sasl_listmech(con, 0, NULL, " ", NULL, &ml, 0, 0); @@ -408,138 +465,201 @@ public: return false; *mechlist = QStringList::split(' ', ml); servermode = true; + step = 0; return true; } - int clientFirstStep(QString *mech, QByteArray **out, QCA_SASLNeedParams *np) + int serverFirstStep(const QString &mech, const QByteArray *in) { - bool supportClientSendFirst = out ? true: false; - - const char *clientout, *m; - unsigned int clientoutlen; - - need = 0; - QString list = methodsToString(mechlist); - int r; - while(1) { - if(need) - params.extractHave(need); - if(supportClientSendFirst) - r = sasl_client_start(con, list.latin1(), &need, &clientout, &clientoutlen, &m); - else - r = sasl_client_start(con, list.latin1(), &need, NULL, NULL, &m); - if(r != SASL_INTERACT) - break; - - params.applyInteract(need); - if(params.missingAny()) { - *np = params.need; - return NeedParams; - } - } - if(r != SASL_OK && r != SASL_CONTINUE) - return Error; - - *mech = m; - if(supportClientSendFirst && clientout) - *out = new QByteArray(makeByteArray(clientout, clientoutlen)); - else - *out = 0; - - if(r == SASL_OK) { - getssfparams(); - return Success; - } - else - return Continue; - } - - int serverFirstStep(const QString &mech, const QByteArray *in, QByteArray *out) - { - const char *clientin = 0; - unsigned int clientinlen = 0; + in_mech = mech; if(in) { - clientin = in->data(); - clientinlen = in->size(); - } - const char *serverout; - unsigned int serveroutlen; - int r = sasl_server_start(con, mech.latin1(), clientin, clientinlen, &serverout, &serveroutlen); - if(r != SASL_OK && r != SASL_CONTINUE) - return Error; - *out = makeByteArray(serverout, serveroutlen); - if(r == SASL_OK) { - getssfparams(); - return Success; + in_useClientInit = true; + in_clientInit = in->copy(); } else - return Continue; + in_useClientInit = false; + return serverTryAgain(); } - int clientNextStep(const QByteArray &in, QByteArray *out, QCA_SASLNeedParams *np) + QCA_SASLNeedParams clientParamsNeeded() const { - //clearNeedParams(np); - const char *clientout; - unsigned int clientoutlen; - int r; - while(1) { - if(need) - params.extractHave(need); - r = sasl_client_step(con, in.data(), in.size(), &need, &clientout, &clientoutlen); - if(r != SASL_INTERACT) - break; + return params.need; + } - params.applyInteract(need); - if(params.missingAny()) { - *np = params.need; - return NeedParams; + void setClientParams(const QString *auth, const QString *user, const QString *pass, const QString *realm) + { + if(auth) + params.setAuthname(*auth); + if(user) + params.setUsername(*user); + if(pass) + params.setPassword(*pass); + if(realm) + params.setRealm(*realm); + } + + QString authname() const + { + return sc_authname; + } + + QString username() const + { + return sc_username; + } + + void setAuth(bool) + { + if(!sst) + return; + + // TODO: send the decision to the thread + sst->wait(); + delete sst; + sst = 0; + } + + int nextStep(const QByteArray &in) + { + in_buf = in.copy(); + return tryAgain(); + } + + int tryAgain() + { + if(servermode) + return serverTryAgain(); + else + return clientTryAgain(); + } + + QString mech() const + { + return out_mech; + } + + const QByteArray *clientInit() const + { + if(out_useClientInit) + return &out_clientInit; + else + return 0; + } + + QByteArray result() const + { + return out_buf; + } + + int clientTryAgain() + { + if(step == 0) { + const char *clientout, *m; + unsigned int clientoutlen; + + need = 0; + QString list = methodsToString(mechlist); + int r; + while(1) { + if(need) + params.extractHave(need); + if(in_sendFirst) + r = sasl_client_start(con, list.latin1(), &need, &clientout, &clientoutlen, &m); + else + r = sasl_client_start(con, list.latin1(), &need, NULL, NULL, &m); + if(r != SASL_INTERACT) + break; + + params.applyInteract(need); + if(params.missingAny()) + return NeedParams; } + if(r != SASL_OK && r != SASL_CONTINUE) + return Error; + + out_mech = m; + if(in_sendFirst && clientout) { + out_clientInit = makeByteArray(clientout, clientoutlen); + out_useClientInit = true; + } + else + out_useClientInit = false; + + ++step; + + if(r == SASL_OK) { + getssfparams(); + return Success; + } + else + return Continue; } - if(r != SASL_OK && r != SASL_CONTINUE) - return Error; - *out = makeByteArray(clientout, clientoutlen); - if(r == SASL_OK) { - getssfparams(); - return Success; + else { + const char *clientout; + unsigned int clientoutlen; + int r; + while(1) { + if(need) + params.extractHave(need); + r = sasl_client_step(con, in_buf.data(), in_buf.size(), &need, &clientout, &clientoutlen); + if(r != SASL_INTERACT) + break; + + params.applyInteract(need); + if(params.missingAny()) + return NeedParams; + } + if(r != SASL_OK && r != SASL_CONTINUE) + return Error; + out_buf = makeByteArray(clientout, clientoutlen); + if(r == SASL_OK) { + getssfparams(); + return Success; + } + else + return Continue; } - else + } + + int serverTryAgain() + { + if(step == 0) { + const char *clientin = 0; + unsigned int clientinlen = 0; + if(in_useClientInit) { + clientin = in_clientInit.data(); + clientinlen = in_clientInit.size(); + } + const char *serverout; + unsigned int serveroutlen; + int r = sasl_server_start(con, in_mech.latin1(), clientin, clientinlen, &serverout, &serveroutlen); + if(r != SASL_OK && r != SASL_CONTINUE) + return Error; + out_buf = makeByteArray(serverout, serveroutlen); + + ++step; + + if(r == SASL_OK) { + getssfparams(); + return Success; + } + else + return Continue; + } + else { + const char *serverout; + unsigned int serveroutlen; + int r = sasl_server_step(con, in_buf.data(), in_buf.size(), &serverout, &serveroutlen); + if(r != SASL_OK && r != SASL_CONTINUE) + return Error; + if(r == SASL_OK) { + out_buf.resize(0); + getssfparams(); + return Success; + } + out_buf = makeByteArray(serverout, serveroutlen); return Continue; - } - - int serverNextStep(const QByteArray &in, QByteArray *out) - { - const char *serverout; - unsigned int serveroutlen; - int r = sasl_server_step(con, in.data(), in.size(), &serverout, &serveroutlen); - if(r != SASL_OK && r != SASL_CONTINUE) - return Error; - if(r == SASL_OK) { - out->resize(0); - getssfparams(); - return Success; } - *out = makeByteArray(serverout, serveroutlen); - return Continue; - } - - void setAuthname(const QString &s) - { - params.setAuthname(s); - } - - void setUsername(const QString &s) - { - params.setUsername(s); - } - - void setPassword(const QString &s) - { - params.setPassword(s); - } - - void setRealm(const QString &s) - { - params.setRealm(s); } bool encode(const QByteArray &in, QByteArray *out) diff --git a/src/qca.cpp b/src/qca.cpp index c0da922f..23ff1fa0 100644 --- a/src/qca.cpp +++ b/src/qca.cpp @@ -837,6 +837,7 @@ public: delete c; } + bool tried; QCA_SASLContext *c; bool allowPlain; QHostAddress localAddr, remoteAddr; @@ -897,11 +898,12 @@ bool SASL::startClient(const QString &service, const QString &host, const QStrin } d->c->setCoreProps(service, host, d->localPort != -1 ? &la : 0, d->remotePort != -1 ? &ra : 0); - d->c->setSecurityProps(!d->allowPlain, false, false, false, false, false, false, 0, 256); + d->c->setSecurityProps(!d->allowPlain, false, false, false, false, false, false, 0, 256, "", 0); if(!d->c->clientStart(mechlist)) return false; d->first = true; d->server = false; + d->tried = false; QTimer::singleShot(0, this, SLOT(tryAgain())); return true; } @@ -919,34 +921,33 @@ bool SASL::startServer(const QString &service, const QString &host, const QStrin } d->c->setCoreProps(service, host, d->localPort != -1 ? &la : 0, d->remotePort != -1 ? &ra : 0); - d->c->setSecurityProps(!d->allowPlain, false, false, false, false, false, false, 0, 256); + d->c->setSecurityProps(!d->allowPlain, false, false, false, false, false, false, 0, 256, "", 0); if(!d->c->serverStart(realm, mechlist, saslappname)) return false; d->first = true; d->server = true; + d->tried = false; return true; } void SASL::putServerFirstStep(const QString &mech) { - QByteArray buf; - int r = d->c->serverFirstStep(mech, 0, &buf); - handleServerFirstStep(r, buf); + int r = d->c->serverFirstStep(mech, 0); + handleServerFirstStep(r); } void SASL::putServerFirstStep(const QString &mech, const QByteArray &clientInit) { - QByteArray buf; - int r = d->c->serverFirstStep(mech, &clientInit, &buf); - handleServerFirstStep(r, buf); + int r = d->c->serverFirstStep(mech, &clientInit); + handleServerFirstStep(r); } -void SASL::handleServerFirstStep(int r, const QByteArray &buf) +void SASL::handleServerFirstStep(int r) { if(r == QCA_SASLContext::Success) authenticated(true); else if(r == QCA_SASLContext::Continue) - nextStep(buf); + nextStep(d->c->result()); else authenticated(false); } @@ -959,22 +960,22 @@ void SASL::putStep(const QByteArray &stepData) void SASL::setAuthname(const QString &auth) { - d->c->setAuthname(auth); + d->c->setClientParams(&auth, 0, 0, 0); } void SASL::setUsername(const QString &user) { - d->c->setUsername(user); + d->c->setClientParams(0, &user, 0, 0); } void SASL::setPassword(const QString &pass) { - d->c->setPassword(pass); + d->c->setClientParams(0, 0, &pass, 0); } void SASL::setRealm(const QString &realm) { - d->c->setRealm(realm); + d->c->setClientParams(0, 0, 0, &realm); } void SASL::continueAfterParams() @@ -987,50 +988,70 @@ void SASL::tryAgain() int r; if(d->server) { - QByteArray out; - r = d->c->serverNextStep(d->stepData, &out); + if(!d->tried) { + r = d->c->nextStep(d->stepData); + d->tried = true; + } + else + r = d->c->tryAgain(); + if(r == QCA_SASLContext::Error) { authenticated(false); return; } else if(r == QCA_SASLContext::Continue) { - nextStep(out); + d->tried = false; + nextStep(d->c->result()); return; } } else { if(d->first) { - QString mech; - QByteArray *clientInit; - QCA_SASLNeedParams np; - r = d->c->clientFirstStep(&mech, &clientInit, &np); + if(!d->tried) { + r = d->c->clientFirstStep(true); + d->tried = true; + } + else + r = d->c->tryAgain(); + if(r == QCA_SASLContext::Error) { authenticated(false); return; } else if(r == QCA_SASLContext::NeedParams) { + d->tried = false; + QCA_SASLNeedParams np = d->c->clientParamsNeeded(); needParams(np.auth, np.user, np.pass, np.realm); return; } + QString mech = d->c->mech(); + const QByteArray *clientInit = d->c->clientInit(); + d->first = false; + d->tried = false; clientFirstStep(mech, clientInit); - delete clientInit; } else { - QByteArray out; - QCA_SASLNeedParams np; - r = d->c->clientNextStep(d->stepData, &out, &np); + if(!d->tried) { + r = d->c->nextStep(d->stepData); + d->tried = true; + } + else + r = d->c->tryAgain(); + if(r == QCA_SASLContext::Error) { authenticated(false); return; } else if(r == QCA_SASLContext::NeedParams) { + d->tried = false; + QCA_SASLNeedParams np = d->c->clientParamsNeeded(); needParams(np.auth, np.user, np.pass, np.realm); return; } //else if(r == QCA_SASLContext::Continue) { - nextStep(out); + nextStep(d->c->result()); // return; //} } diff --git a/src/qca.h b/src/qca.h index 60f0f237..a908aaa1 100644 --- a/src/qca.h +++ b/src/qca.h @@ -372,7 +372,7 @@ namespace QCA class Private; Private *d; - void handleServerFirstStep(int r, const QByteArray &buf); + void handleServerFirstStep(int r); }; }; diff --git a/src/qcaprovider.h b/src/qcaprovider.h index cb4db48f..0eeecee6 100644 --- a/src/qcaprovider.h +++ b/src/qcaprovider.h @@ -134,31 +134,36 @@ struct QCA_SASLNeedParams class QCA_SASLContext { public: - enum { Success, Error, NeedParams, Continue }; + enum { Success, Error, NeedParams, AuthCheck, Continue }; virtual ~QCA_SASLContext() {} // common virtual void reset()=0; virtual void setCoreProps(const QString &service, const QString &host, QCA_SASLHostPort *local, QCA_SASLHostPort *remote)=0; - virtual void setSecurityProps(bool noPlain, bool noActive, bool noDict, bool noAnon, bool reqForward, bool reqCreds, bool reqMutual, int ssfMin, int ssfMax)=0; + virtual void setSecurityProps(bool noPlain, bool noActive, bool noDict, bool noAnon, bool reqForward, bool reqCreds, bool reqMutual, int ssfMin, int ssfMax, const QString &_ext_authid, int _ext_ssf)=0; virtual int security() const=0; - // client + // init / first step virtual bool clientStart(const QStringList &mechlist)=0; - virtual int clientFirstStep(QString *mech, QByteArray **out, QCA_SASLNeedParams *np)=0; - virtual int clientNextStep(const QByteArray &in, QByteArray *out, QCA_SASLNeedParams *np)=0; - - // server + virtual int clientFirstStep(bool allowClientSendFirst)=0; virtual bool serverStart(const QString &realm, QStringList *mechlist, const QString &name)=0; - virtual int serverFirstStep(const QString &mech, const QByteArray *in, QByteArray *out)=0; - virtual int serverNextStep(const QByteArray &in, QByteArray *out)=0; - virtual void setAuthCallback(bool (*auth)(const QString &authname, const QString &username, QCA_SASLContext *c))=0; + virtual int serverFirstStep(const QString &mech, const QByteArray *in)=0; - // client params - virtual void setAuthname(const QString &)=0; - virtual void setUsername(const QString &)=0; - virtual void setPassword(const QString &)=0; - virtual void setRealm(const QString &)=0; + // get / set params + virtual QCA_SASLNeedParams clientParamsNeeded() const=0; + virtual void setClientParams(const QString *auth, const QString *user, const QString *pass, const QString *realm)=0; + virtual QString authname() const=0; + virtual QString username() const=0; + virtual void setAuth(bool)=0; + + // continue steps + virtual int nextStep(const QByteArray &in)=0; + virtual int tryAgain()=0; + + // results + virtual QString mech() const=0; + virtual const QByteArray *clientInit() const=0; + virtual QByteArray result() const=0; // security layer virtual bool encode(const QByteArray &in, QByteArray *out)=0;