From f94fdac5294c571ec83faf89949159cdb609fbd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sl=C3=A1vek=20Banko?= Date: Sat, 15 Oct 2016 18:54:59 +0200 Subject: [PATCH] Kopete - jabber: Add SASL PLAIN method for authentication MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Slávek Banko (cherry picked from commit a9aee0e6e0157a1fbeba6433aaaeda584698dc4e) --- .../libiris/iris/xmpp-core/simplesasl.cpp | 207 +++++++++++------- 1 file changed, 128 insertions(+), 79 deletions(-) diff --git a/kopete/protocols/jabber/libiris/iris/xmpp-core/simplesasl.cpp b/kopete/protocols/jabber/libiris/iris/xmpp-core/simplesasl.cpp index 92091f63..371f6092 100644 --- a/kopete/protocols/jabber/libiris/iris/xmpp-core/simplesasl.cpp +++ b/kopete/protocols/jabber/libiris/iris/xmpp-core/simplesasl.cpp @@ -155,6 +155,7 @@ public: TQString out_mech; TQByteArray out_buf; bool capable; + bool allow_plain; int err; TQCA_SASLNeedParams need; @@ -207,12 +208,13 @@ public: host = _host; } - void setSecurityProps(bool, bool, bool, bool, bool reqForward, bool reqCreds, bool reqMutual, int ssfMin, int, const TQString &, int) + void setSecurityProps(bool noPlain, bool, bool, bool, bool reqForward, bool reqCreds, bool reqMutual, int ssfMin, int, const TQString &, int) { if(reqForward || reqCreds || reqMutual || ssfMin > 0) capable = false; else capable = true; + allow_plain = !noPlain; } int security() const @@ -228,8 +230,17 @@ public: bool clientStart(const TQStringList &mechlist) { bool haveMech = false; + resetState(); + step = 0; + for(TQStringList::ConstIterator it = mechlist.begin(); it != mechlist.end(); ++it) { + if((*it) == "PLAIN" && allow_plain) { + out_mech = "PLAIN"; + haveMech = true; + break; + } if((*it) == "DIGEST-MD5") { + out_mech = "DIGEST-MD5"; haveMech = true; break; } @@ -238,9 +249,6 @@ public: err = TQCA::SASL::NoMech; return false; } - - resetState(); - step = 0; return true; } @@ -316,7 +324,7 @@ public: const TQByteArray *clientInit() const { - return 0; + return out_mech == "PLAIN" ? &out_buf : 0; } TQByteArray result() const @@ -326,85 +334,126 @@ public: int clientTryAgain() { - if(step == 0) { - out_mech = "DIGEST-MD5"; - ++step; - return Continue; + if( out_mech == "PLAIN" ) { + if(step == 0) { + // First, check if we have everything + if(need.user || need.pass) { + err = -1; + return Error; + } + if(!have.user) { + need.user = true; + } + if(!have.pass) { + need.pass = true; + } + if(need.user || need.pass) { + return NeedParams; + } + + TQCString authz_ = authz.utf8(); + TQCString user_ = user.utf8(); + TQCString pass_ = pass.utf8(); + int l = 0; + + out_buf.resize(authz_.length() + 1 + user_.length() + 1 + pass_.length()); + memcpy(&out_buf[l], authz_.data(), authz_.length()); + l += authz_.length(); + out_buf[l] = '\0'; + l += 1; + memcpy(&out_buf[l], user_.data(), user_.length()); + l += user_.length(); + out_buf[l] = '\0'; + l += 1; + + memcpy(&out_buf[l], pass_.data(), pass_.length()); + ++step; + return Continue; + } + + out_buf.resize(0); + return Success; } - else if(step == 1) { - // if we still need params, then the app has failed us! - if(need.user || need.authzid || need.pass || need.realm) { - err = -1; - return Error; + + if( out_mech == "DIGEST-MD5" ) { + if(step == 0) { + ++step; + return Continue; } + else if(step == 1) { + // if we still need params, then the app has failed us! + if(need.user || need.authzid || need.pass || need.realm) { + err = -1; + return Error; + } - // see if some params are needed - if(!have.user) - need.user = true; - if(!have.authzid) - need.authzid = true; - if(!have.pass) - need.pass = true; - if(need.user || need.authzid || need.pass) - return NeedParams; - - // get props - TQCString cs(in_buf.data(), in_buf.size()+1); - PropList in; - if(!in.fromString(cs)) { - err = TQCA::SASL::BadProto; - return Error; + // see if some params are needed + if(!have.user) + need.user = true; + if(!have.authzid) + need.authzid = true; + if(!have.pass) + need.pass = true; + if(need.user || need.authzid || need.pass) + return NeedParams; + + // get props + TQCString cs(in_buf.data(), in_buf.size()+1); + PropList in; + if(!in.fromString(cs)) { + err = TQCA::SASL::BadProto; + return Error; + } + + // make a cnonce + TQByteArray a(32); + for(int n = 0; n < (int)a.size(); ++n) + a[n] = (char)(256.0*rand()/(RAND_MAX+1.0)); + TQCString cnonce = Base64::arrayToString(a).latin1(); + + // make other variables + realm = host; + TQCString nonce = in.get("nonce"); + TQCString nc = "00000001"; + TQCString uri = service.utf8() + '/' + host.utf8(); + TQCString qop = "auth"; + + // build 'response' + TQCString X = user.utf8() + ':' + realm.utf8() + ':' + pass.utf8(); + TQByteArray Y = TQCA::MD5::hash(X); + TQCString tmp = TQCString(":") + nonce + ':' + cnonce + ':' + authz.utf8(); + TQByteArray A1(Y.size() + tmp.length()); + memcpy(A1.data(), Y.data(), Y.size()); + memcpy(A1.data() + Y.size(), tmp.data(), tmp.length()); + TQCString A2 = "AUTHENTICATE:" + uri; + TQCString HA1 = TQCA::MD5::hashToString(A1).latin1(); + TQCString HA2 = TQCA::MD5::hashToString(A2).latin1(); + TQCString KD = HA1 + ':' + nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + HA2; + TQCString Z = TQCA::MD5::hashToString(KD).latin1(); + + // build output + PropList out; + out.set("username", user.utf8()); + out.set("realm", host.utf8()); + out.set("nonce", nonce); + out.set("cnonce", cnonce); + out.set("nc", nc); + out.set("serv-type", service.utf8()); + out.set("host", host.utf8()); + out.set("digest-uri", uri); + out.set("qop", qop); + out.set("response", Z); + out.set("charset", "utf-8"); + out.set("authzid", authz.utf8()); + TQCString s = out.toString(); + + // done + out_buf.resize(s.length()); + memcpy(out_buf.data(), s.data(), out_buf.size()); + ++step; + return Continue; } - // make a cnonce - TQByteArray a(32); - for(int n = 0; n < (int)a.size(); ++n) - a[n] = (char)(256.0*rand()/(RAND_MAX+1.0)); - TQCString cnonce = Base64::arrayToString(a).latin1(); - - // make other variables - realm = host; - TQCString nonce = in.get("nonce"); - TQCString nc = "00000001"; - TQCString uri = service.utf8() + '/' + host.utf8(); - TQCString qop = "auth"; - - // build 'response' - TQCString X = user.utf8() + ':' + realm.utf8() + ':' + pass.utf8(); - TQByteArray Y = TQCA::MD5::hash(X); - TQCString tmp = TQCString(":") + nonce + ':' + cnonce + ':' + authz.utf8(); - TQByteArray A1(Y.size() + tmp.length()); - memcpy(A1.data(), Y.data(), Y.size()); - memcpy(A1.data() + Y.size(), tmp.data(), tmp.length()); - TQCString A2 = "AUTHENTICATE:" + uri; - TQCString HA1 = TQCA::MD5::hashToString(A1).latin1(); - TQCString HA2 = TQCA::MD5::hashToString(A2).latin1(); - TQCString KD = HA1 + ':' + nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + HA2; - TQCString Z = TQCA::MD5::hashToString(KD).latin1(); - - // build output - PropList out; - out.set("username", user.utf8()); - out.set("realm", host.utf8()); - out.set("nonce", nonce); - out.set("cnonce", cnonce); - out.set("nc", nc); - out.set("serv-type", service.utf8()); - out.set("host", host.utf8()); - out.set("digest-uri", uri); - out.set("qop", qop); - out.set("response", Z); - out.set("charset", "utf-8"); - out.set("authzid", authz.utf8()); - TQCString s = out.toString(); - - // done - out_buf.resize(s.length()); - memcpy(out_buf.data(), s.data(), out_buf.size()); - ++step; - return Continue; - } - else { out_buf.resize(0); return Success; }