From 1a0788c26404b5f42b6be2919bff5be261b2f3e7 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Sun, 12 Jul 2020 13:12:23 +0300 Subject: Jabber: ugly scheme with flags replaced with TJabberAuth instantiation --- protocols/JabberG/src/jabber_proto.cpp | 3 +- protocols/JabberG/src/jabber_proto.h | 21 +--- protocols/JabberG/src/jabber_secur.cpp | 75 ++++++------- protocols/JabberG/src/jabber_secur.h | 27 ++--- protocols/JabberG/src/jabber_strm_mgmt.cpp | 5 +- protocols/JabberG/src/jabber_thread.cpp | 168 +++++++++-------------------- protocols/JabberG/src/stdafx.h | 4 +- 7 files changed, 109 insertions(+), 194 deletions(-) (limited to 'protocols/JabberG/src') diff --git a/protocols/JabberG/src/jabber_proto.cpp b/protocols/JabberG/src/jabber_proto.cpp index 27b02bbf34..b91f9bc881 100755 --- a/protocols/JabberG/src/jabber_proto.cpp +++ b/protocols/JabberG/src/jabber_proto.cpp @@ -27,6 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "jabber_iq.h" #include "jabber_caps.h" #include "jabber_disco.h" +#include "jabber_secur.h" #pragma warning(disable:4355) @@ -57,6 +58,7 @@ CJabberProto::CJabberProto(const char *aProtoName, const wchar_t *aUserName) : m_impl(*this), m_omemo(this), m_arChatMarks(50, NumericKeySortT), + m_arAuthMechs(1, &TJabberAuth::compare), m_lstTransports(50, compareTransports), m_lstRoster(50, compareListItems), m_iqManager(this), @@ -250,7 +252,6 @@ CJabberProto::~CJabberProto() ListWipe(); mir_free(m_tszSelectedLang); - mir_free(m_gssapiHostName); mir_free(m_modeMsgs.szOnline); mir_free(m_modeMsgs.szAway); diff --git a/protocols/JabberG/src/jabber_proto.h b/protocols/JabberG/src/jabber_proto.h index 6531e59319..139a7371cd 100755 --- a/protocols/JabberG/src/jabber_proto.h +++ b/protocols/JabberG/src/jabber_proto.h @@ -794,26 +794,9 @@ struct CJabberProto : public PROTO, public IJabberInterface ptrA m_szGroupDelimiter; ptrW m_savedPassword; - union { - int m_dwAuthMechs; - struct { - bool m_isPlainAvailable : 1; - bool m_isPlainOldAvailable : 1; - bool m_isMd5Available : 1; - bool m_isScramSha1Available : 1; - bool m_isScramSha1PlusAvailable : 1; - bool m_isScramSha256Available : 1; - bool m_isScramSha256PlusAvailable : 1; - bool m_isNtlmAvailable : 1; - bool m_isSpnegoAvailable : 1; - bool m_isKerberosAvailable : 1; - bool m_isAuthAvailable : 1; - bool m_isSessionAvailable : 1; - }; - }; + OBJLIST m_arAuthMechs; + bool m_isSessionAvailable, m_isAuthAvailable; - char* m_gssapiHostName; - void __cdecl ServerThread(JABBER_CONN_DATA *info); void OnProcessFailure(const TiXmlElement *node, ThreadData *info); diff --git a/protocols/JabberG/src/jabber_secur.cpp b/protocols/JabberG/src/jabber_secur.cpp index 0a20304cc7..c92cc4dc64 100644 --- a/protocols/JabberG/src/jabber_secur.cpp +++ b/protocols/JabberG/src/jabber_secur.cpp @@ -28,33 +28,30 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ///////////////////////////////////////////////////////////////////////////////////////// // ntlm auth - LanServer based authorization -TNtlmAuth::TNtlmAuth(ThreadData *info, const char *mechanism, const char *hostname) : - TJabberAuth(info) +TNtlmAuth::TNtlmAuth(ThreadData *info, const char *mechanism) : + TJabberAuth(info, mechanism) { - szName = mechanism; - szHostName = hostname; + bIsValid = false; const wchar_t *szProvider; if (!mir_strcmp(mechanism, "GSS-SPNEGO")) - szProvider = L"Negotiate"; + szProvider = L"Negotiate", priority = 703; else if (!mir_strcmp(mechanism, "GSSAPI")) - szProvider = L"Kerberos"; + szProvider = L"Kerberos", priority = 702; else if (!mir_strcmp(mechanism, "NTLM")) - szProvider = L"NTLM"; - else { -LBL_Invalid: - bIsValid = false; - hProvider = nullptr; + szProvider = L"NTLM", priority = 701; + else return; - } wchar_t szSpn[1024]; szSpn[0] = 0; if (!mir_strcmp(mechanism, "GSSAPI")) if (!getSpn(szSpn, _countof(szSpn))) - goto LBL_Invalid; + return; if ((hProvider = Netlib_InitSecurityProvider(szProvider, szSpn)) == nullptr) - bIsValid = false; + return; + + bIsValid = true; } TNtlmAuth::~TNtlmAuth() @@ -77,9 +74,9 @@ bool TNtlmAuth::getSpn(wchar_t* szSpn, size_t dwSpnLen) if (name) *name = 0; else return false; - if (szHostName && szHostName[0]) { + if (info->gssapiHostName && info->gssapiHostName[0]) { wchar_t *szFullUserNameU = wcsupr(mir_wstrdup(szFullUserName)); - mir_snwprintf(szSpn, dwSpnLen, L"xmpp/%s/%s@%s", szHostName, szFullUserName, szFullUserNameU); + mir_snwprintf(szSpn, dwSpnLen, L"xmpp/%s/%s@%s", info->gssapiHostName, szFullUserName, szFullUserNameU); mir_free(szFullUserNameU); } else { @@ -127,10 +124,10 @@ char* TNtlmAuth::getChallenge(const char *challenge) // md5 auth - digest-based authorization TMD5Auth::TMD5Auth(ThreadData *info) : - TJabberAuth(info), + TJabberAuth(info, "DIGEST-MD5"), iCallCount(0) { - szName = "DIGEST-MD5"; + priority = 301; } TMD5Auth::~TMD5Auth() @@ -206,19 +203,23 @@ char* TMD5Auth::getChallenge(const char *challenge) ///////////////////////////////////////////////////////////////////////////////////////// // SCRAM-SHA-1 authorization -TScramAuth::TScramAuth(ThreadData *info, bool bSha1, void *pData, size_t cbLen) : - TJabberAuth(info), - hashMethod(bSha1 ? EVP_sha1() : EVP_sha256()) +TScramAuth::TScramAuth(ThreadData *info, const char *pszMech, const EVP_MD *pMethod, int iPriority) : + TJabberAuth(info, pszMech), + hashMethod(pMethod) { - if (pData) { - szName = bSha1 ? "SCRAM-SHA-1-PLUS" : "SCRAM-SHA-256-PLUS"; + priority = iPriority; + + if ((iPriority % 10) == 1) { bindFlag = "p=tls-unique,,"; - bindData.append(pData, cbLen); + + int cbLen; + void *pData = Netlib_GetTlsUnique(info->s, cbLen); + if (pData == nullptr) + bIsValid = false; + else + bindData.append(pData, cbLen); } - else { - szName = bSha1 ? "SCRAM-SHA-1" : "SCRAM-SHA-256"; - bindFlag = "n,,"; - } + else bindFlag = "n,,"; } TScramAuth::~TScramAuth() @@ -335,14 +336,10 @@ bool TScramAuth::validateLogin(const char *challenge) // plain auth - the most simple one TPlainAuth::TPlainAuth(ThreadData *info, bool old) : - TJabberAuth(info) -{ - szName = "PLAIN"; - bOld = old; -} - -TPlainAuth::~TPlainAuth() + TJabberAuth(info, "PLAIN"), + bOld(old) { + priority = (old) ? 100 : 101; } char* TPlainAuth::getInitialRequest() @@ -359,11 +356,9 @@ char* TPlainAuth::getInitialRequest() ///////////////////////////////////////////////////////////////////////////////////////// // basic type -TJabberAuth::TJabberAuth(ThreadData* pInfo) : - bIsValid(true), - complete(0), - szName(nullptr), - info(pInfo) +TJabberAuth::TJabberAuth(ThreadData* pInfo, const char *pszMech) : + info(pInfo), + szName(mir_strdup(pszMech)) { } diff --git a/protocols/JabberG/src/jabber_secur.h b/protocols/JabberG/src/jabber_secur.h index 78dccfa70a..14ad699b70 100644 --- a/protocols/JabberG/src/jabber_secur.h +++ b/protocols/JabberG/src/jabber_secur.h @@ -28,19 +28,24 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // basic class - provides interface for various Jabber auth -class TJabberAuth +class TJabberAuth : public MZeroedObject { -protected: bool bIsValid; - const char* szName; +protected: bool bIsValid = true; + ptrA szName; unsigned complete; + int priority; ThreadData *info; public: - TJabberAuth(ThreadData*); + TJabberAuth(ThreadData *pInfo, const char *pszMech); virtual ~TJabberAuth(); virtual char* getInitialRequest(); virtual char* getChallenge(const char *challenge); - virtual bool validateLogin(const char *challenge); + virtual bool validateLogin(const char *challenge); + + static int compare(const TJabberAuth *p1, const TJabberAuth *p2) + { return p2->priority - p1->priority; // reverse sorting order + } inline const char* getName() const { return szName; @@ -59,11 +64,10 @@ class TPlainAuth : public TJabberAuth bool bOld; +public: + TPlainAuth(ThreadData*, bool); -public: TPlainAuth(ThreadData*, bool); - virtual ~TPlainAuth(); - - virtual char* getInitialRequest(); + char* getInitialRequest() override; }; // md5 auth - digest-based authorization @@ -89,7 +93,7 @@ class TScramAuth : public TJabberAuth const EVP_MD *hashMethod; public: - TScramAuth(ThreadData*, bool bSha1, void *pData = nullptr, size_t cbLen = 0); + TScramAuth(ThreadData *pInfo, const char *pszMech, const EVP_MD *pMethod, int priority); ~TScramAuth(); char* getInitialRequest() override; @@ -106,10 +110,9 @@ class TNtlmAuth : public TJabberAuth typedef TJabberAuth CSuper; HANDLE hProvider; - const char *szHostName; public: - TNtlmAuth(ThreadData*, const char* mechanism, const char *hostname = nullptr); + TNtlmAuth(ThreadData*, const char* mechanism); ~TNtlmAuth(); char* getInitialRequest() override; diff --git a/protocols/JabberG/src/jabber_strm_mgmt.cpp b/protocols/JabberG/src/jabber_strm_mgmt.cpp index 151de8203e..1fcd6e3ac3 100755 --- a/protocols/JabberG/src/jabber_strm_mgmt.cpp +++ b/protocols/JabberG/src/jabber_strm_mgmt.cpp @@ -268,8 +268,7 @@ bool strm_mgmt::IsResumeIdPresent() void strm_mgmt::FinishLoginProcess(ThreadData *info) { - - if (info->auth) { //We are already logged-in + if (proto->m_arAuthMechs.getCount()) { //We are already logged-in info->send( XmlNodeIq(proto->AddIQ(&CJabberProto::OnIqResultBind, JABBER_IQ_TYPE_SET)) << XCHILDNS("bind", JABBER_FEAT_BIND) @@ -281,6 +280,6 @@ void strm_mgmt::FinishLoginProcess(ThreadData *info) return; } - //mechanisms not available and we are not logged in + // mechanisms not available and we are not logged in proto->PerformIqAuth(info); } diff --git a/protocols/JabberG/src/jabber_thread.cpp b/protocols/JabberG/src/jabber_thread.cpp index 586cbce6f9..6f734a68a6 100755 --- a/protocols/JabberG/src/jabber_thread.cpp +++ b/protocols/JabberG/src/jabber_thread.cpp @@ -585,93 +585,10 @@ void CJabberProto::OnProcessStreamOpening(const TiXmlElement *node, ThreadData * void CJabberProto::PerformAuthentication(ThreadData *info) { - TJabberAuth* auth = nullptr; - char* request = nullptr; - - if (info->auth) { - delete info->auth; - info->auth = nullptr; - } - - if (m_isSpnegoAvailable) { - m_isSpnegoAvailable = false; - auth = new TNtlmAuth(info, "GSS-SPNEGO"); - if (!auth->isValid()) { - delete auth; - auth = nullptr; - } - } - - if (auth == nullptr && m_isKerberosAvailable) { - m_isKerberosAvailable = false; - auth = new TNtlmAuth(info, "GSSAPI", m_gssapiHostName); - if (!auth->isValid()) { - delete auth; - auth = nullptr; - } - else { - request = auth->getInitialRequest(); - if (!request) { - delete auth; - auth = nullptr; - } - } - } - - if (auth == nullptr && m_isNtlmAvailable) { - m_isNtlmAvailable = false; - auth = new TNtlmAuth(info, "NTLM"); - if (!auth->isValid()) { - delete auth; - auth = nullptr; - } - } - - if (auth == nullptr && m_isScramSha256PlusAvailable) { - m_isScramSha256PlusAvailable = false; - - int len = 0; - void *pBuf = Netlib_GetTlsUnique(info->s, len); - if (pBuf) - auth = new TScramAuth(info, EVP_sha256(), pBuf, len); - } - - if (auth == nullptr && m_isScramSha256Available) { - m_isScramSha256Available = false; - auth = new TScramAuth(info, EVP_sha256()); - } - - if (auth == nullptr && m_isScramSha1PlusAvailable) { - m_isScramSha1PlusAvailable = false; - - int len = 0; - void *pBuf = Netlib_GetTlsUnique(info->s, len); - if (pBuf) - auth = new TScramAuth(info, EVP_sha1(), pBuf, len); - } - - if (auth == nullptr && m_isScramSha1Available) { - m_isScramSha1Available = false; - auth = new TScramAuth(info, EVP_sha1()); - } - - if (auth == nullptr && m_isMd5Available) { - m_isMd5Available = false; - auth = new TMD5Auth(info); - } - - if (auth == nullptr && m_isPlainAvailable) { - m_isPlainAvailable = false; - auth = new TPlainAuth(info, false); - } - - if (auth == nullptr && m_isPlainOldAvailable) { - m_isPlainOldAvailable = false; - auth = new TPlainAuth(info, true); - } - - if (auth == nullptr) { - if (m_isAuthAvailable) { // no known mechanisms but iq_auth is available + // no known mechanisms + if (m_arAuthMechs.getCount() == 0) { + // if iq_auth is available, use it + if (m_isAuthAvailable) { m_isAuthAvailable = false; PerformIqAuth(info); return; @@ -687,12 +604,8 @@ void CJabberProto::PerformAuthentication(ThreadData *info) return; } - info->auth = auth; - - if (!request) request = auth->getInitialRequest(); - info->send(XmlNode("auth", request) << XATTR("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl") - << XATTR("mechanism", auth->getName())); - mir_free(request); + auto &auth = m_arAuthMechs[0]; + info->send(XmlNode("auth", ptrA(auth.getInitialRequest())) << XATTR("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl") << XATTR("mechanism", auth.getName())); } ///////////////////////////////////////////////////////////////////////////////////////// @@ -725,37 +638,57 @@ void CJabberProto::OnProcessFeatures(const TiXmlElement *node, ThreadData *info) } if (!mir_strcmp(pszName, "mechanisms")) { - m_dwAuthMechs = 0; - replaceStr(m_gssapiHostName, nullptr); + m_arAuthMechs.destroy(); + replaceStr(info->gssapiHostName, nullptr); areMechanismsDefined = true; for (auto *c : TiXmlEnum(n)) { if (!mir_strcmp(c->Name(), "mechanism")) { + TJabberAuth *pAuth = nullptr; const char *szMechanism = c->GetText(); - if (!mir_strcmp(szMechanism, "PLAIN")) - m_isPlainOldAvailable = m_isPlainAvailable = true; + if (!mir_strcmp(szMechanism, "PLAIN")) { + m_arAuthMechs.insert(new TPlainAuth(info, false)); + pAuth = new TPlainAuth(info, true); + } else if (!mir_strcmp(szMechanism, "DIGEST-MD5")) - m_isMd5Available = true; + pAuth = new TMD5Auth(info); else if (!mir_strcmp(szMechanism, "SCRAM-SHA-1")) - m_isScramSha1Available = true; + pAuth = new TScramAuth(info, szMechanism, EVP_sha1(), 500); else if (!mir_strcmp(szMechanism, "SCRAM-SHA-1-PLUS")) - m_isScramSha1PlusAvailable = true; + pAuth = new TScramAuth(info, szMechanism, EVP_sha1(), 501); + else if (!mir_strcmp(szMechanism, "SCRAM-SHA-224")) + pAuth = new TScramAuth(info, szMechanism, EVP_sha224(), 510); + else if (!mir_strcmp(szMechanism, "SCRAM-SHA-224-PLUS")) + pAuth = new TScramAuth(info, szMechanism, EVP_sha224(), 511); else if (!mir_strcmp(szMechanism, "SCRAM-SHA-256")) - m_isScramSha256Available = true; + pAuth = new TScramAuth(info, szMechanism, EVP_sha256(), 520); else if (!mir_strcmp(szMechanism, "SCRAM-SHA-256-PLUS")) - m_isScramSha256PlusAvailable = true; - else if (!mir_strcmp(szMechanism, "NTLM")) - m_isNtlmAvailable = true; - else if (!mir_strcmp(szMechanism, "GSS-SPNEGO")) - m_isSpnegoAvailable = true; - else if (!mir_strcmp(szMechanism, "GSSAPI")) - m_isKerberosAvailable = true; + pAuth = new TScramAuth(info, szMechanism, EVP_sha256(), 521); + else if (!mir_strcmp(szMechanism, "SCRAM-SHA-384")) + pAuth = new TScramAuth(info, szMechanism, EVP_sha384(), 530); + else if (!mir_strcmp(szMechanism, "SCRAM-SHA-384-PLUS")) + pAuth = new TScramAuth(info, szMechanism, EVP_sha384(), 531); + else if (!mir_strcmp(szMechanism, "SCRAM-SHA-512")) + pAuth = new TScramAuth(info, szMechanism, EVP_sha512(), 540); + else if (!mir_strcmp(szMechanism, "SCRAM-SHA-512-PLUS")) + pAuth = new TScramAuth(info, szMechanism, EVP_sha512(), 541); + else if (!mir_strcmp(szMechanism, "NTLM") || !mir_strcmp(szMechanism, "GSS-SPNEGO") || !mir_strcmp(szMechanism, "GSSAPI")) + pAuth = new TNtlmAuth(info, szMechanism); + else { + debugLogA("Unsupported auth mechanism: %s, skipping", szMechanism); + continue; + } + + if (!pAuth->isValid()) + delete pAuth; + else + m_arAuthMechs.insert(pAuth); } else if (!mir_strcmp(c->Name(), "hostname")) { const char *mech = XmlGetAttr(c, "mechanism"); if (mech && mir_strcmpi(mech, "GSSAPI") == 0) - m_gssapiHostName = mir_strdup(c->GetText()); + info->gssapiHostName = mir_strdup(c->GetText()); } } } @@ -783,7 +716,7 @@ void CJabberProto::OnProcessFeatures(const TiXmlElement *node, ThreadData *info) if (m_bEnableStreamMgmt && m_StrmMgmt.IsResumeIdPresent()) // resume should be done here m_StrmMgmt.CheckState(); else { - if (info->auth) { // we are already logged-in + if (m_arAuthMechs.getCount()) { // we are already logged-in info->send( XmlNodeIq(AddIQ(&CJabberProto::OnIqResultBind, JABBER_IQ_TYPE_SET)) << XCHILDNS("bind", JABBER_FEAT_BIND) @@ -801,8 +734,10 @@ void CJabberProto::OnProcessFailure(const TiXmlElement *node, ThreadData *info) { // failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" const char *type = XmlGetAttr(node, "xmlns"); - if (!mir_strcmp(type, "urn:ietf:params:xml:ns:xmpp-sasl")) + if (!mir_strcmp(type, "urn:ietf:params:xml:ns:xmpp-sasl")) { + m_arAuthMechs.remove(0L); PerformAuthentication(info); + } } void CJabberProto::OnProcessFailed(const TiXmlElement *node, ThreadData *info) //used failed instead of failure, notes: https://xmpp.org/extensions/xep-0198.html#errors @@ -810,14 +745,12 @@ void CJabberProto::OnProcessFailed(const TiXmlElement *node, ThreadData *info) / m_StrmMgmt.OnProcessFailed(node, info); } - void CJabberProto::OnProcessEnabled(const TiXmlElement *node, ThreadData * info) { if (m_bEnableStreamMgmt && !mir_strcmp(XmlGetAttr(node, "xmlns"), "urn:xmpp:sm:3")) m_StrmMgmt.OnProcessEnabled(node, info); } - void CJabberProto::OnProcessError(const TiXmlElement *node, ThreadData *info) { //failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" @@ -858,7 +791,7 @@ void CJabberProto::OnProcessSuccess(const TiXmlElement *node, ThreadData *info) return; if (!mir_strcmp(type, "urn:ietf:params:xml:ns:xmpp-sasl")) { - if (!info->auth->validateLogin(node->GetText())) { + if (!m_arAuthMechs[0].validateLogin(node->GetText())) { info->send(""); return; } @@ -875,7 +808,7 @@ void CJabberProto::OnProcessSuccess(const TiXmlElement *node, ThreadData *info) void CJabberProto::OnProcessChallenge(const TiXmlElement *node, ThreadData *info) { - if (info->auth == nullptr) { + if (m_arAuthMechs.getCount() == 0) { debugLogA("No previous auth have been made, exiting..."); return; } @@ -883,7 +816,7 @@ void CJabberProto::OnProcessChallenge(const TiXmlElement *node, ThreadData *info if (mir_strcmp(XmlGetAttr(node, "xmlns"), "urn:ietf:params:xml:ns:xmpp-sasl")) return; - char* challenge = info->auth->getChallenge(node->GetText()); + char* challenge = m_arAuthMechs[0].getChallenge(node->GetText()); info->send(XmlNode("response", challenge) << XATTR("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl")); mir_free(challenge); } @@ -2005,8 +1938,7 @@ ThreadData::~ThreadData() if (!bIsReg && proto->m_ThreadInfo == this) proto->m_ThreadInfo = nullptr; - delete auth; - + mir_free(gssapiHostName); mir_free(zRecvData); mir_free(buffer); diff --git a/protocols/JabberG/src/stdafx.h b/protocols/JabberG/src/stdafx.h index 8b0f14ab70..dc11269456 100755 --- a/protocols/JabberG/src/stdafx.h +++ b/protocols/JabberG/src/stdafx.h @@ -376,7 +376,9 @@ struct ThreadData char fullJID[JABBER_MAX_JID_LEN]; ptrA tszNewPassword; - class TJabberAuth *auth; +// class TJabberAuth *auth; + char *gssapiHostName; + JabberCapsBits jabberServerCaps; void close(void); -- cgit v1.2.3