diff options
author | George Hazan <george.hazan@gmail.com> | 2024-12-02 13:24:58 +0300 |
---|---|---|
committer | George Hazan <george.hazan@gmail.com> | 2024-12-02 13:24:58 +0300 |
commit | 7e939a1efe055c425465de20489b4760b5e12374 (patch) | |
tree | ff3272d9c4384e88a400f3566ebfce09eb20facd | |
parent | 562334068a5526a92fa6f931581c4b221a70ab41 (diff) |
fixes #3792 (XEP-0388: Extensible SASL Profile support)
-rw-r--r-- | protocols/JabberG/src/jabber_caps.h | 4 | ||||
-rw-r--r-- | protocols/JabberG/src/jabber_iqid.cpp | 2 | ||||
-rw-r--r-- | protocols/JabberG/src/jabber_omemo.cpp | 2 | ||||
-rw-r--r-- | protocols/JabberG/src/jabber_opt.cpp | 1 | ||||
-rw-r--r-- | protocols/JabberG/src/jabber_proto.cpp | 1 | ||||
-rw-r--r-- | protocols/JabberG/src/jabber_proto.h | 4 | ||||
-rw-r--r-- | protocols/JabberG/src/jabber_secur.cpp | 55 | ||||
-rw-r--r-- | protocols/JabberG/src/jabber_strm_mgmt.cpp | 24 | ||||
-rw-r--r-- | protocols/JabberG/src/jabber_thread.cpp | 88 |
9 files changed, 111 insertions, 70 deletions
diff --git a/protocols/JabberG/src/jabber_caps.h b/protocols/JabberG/src/jabber_caps.h index eaea80b919..c6981be3a7 100644 --- a/protocols/JabberG/src/jabber_caps.h +++ b/protocols/JabberG/src/jabber_caps.h @@ -198,15 +198,17 @@ typedef unsigned __int64 JabberCapsBits; #define JABBER_FEAT_ARCHIVE "urn:xmpp:archive"
#define JABBER_FEAT_BIND "urn:ietf:params:xml:ns:xmpp-bind"
#define JABBER_FEAT_CAPTCHA "urn:xmpp:captcha"
+#define JABBER_FEAT_CHANNEL_BINDING "urn:xmpp:sasl-cb:0"
#define JABBER_FEAT_CSI "urn:xmpp:csi:0"
#define JABBER_FEAT_JUD "jabber:iq:search"
#define JABBER_FEAT_IDLE "urn:xmpp:idle:1"
+#define JABBER_FEAT_SASL2 "urn:xmpp:sasl:2"
#define JABBER_FEAT_SERVER_AVATAR "storage:client:avatar"
#define JABBER_FEAT_SID "urn:xmpp:sid:0"
+#define JABBER_FEAT_SM "urn:xmpp:sm:3"
#define JABBER_FEAT_SOFTWARE_INFO "urn:xmpp:dataforms:softwareinfo"
#define JABBER_FEAT_UPLOAD "urn:xmpp:http:upload"
#define JABBER_FEAT_UPLOAD0 "urn:xmpp:http:upload:0"
-#define JABBER_FEAT_CHANNEL_BINDING "urn:xmpp:sasl-cb:0"
#define JABBER_FEAT_RSM "http://jabber.org/protocol/rsm"
#define JABBER_FEAT_PUBSUB_EVENT "http://jabber.org/protocol/pubsub#event"
diff --git a/protocols/JabberG/src/jabber_iqid.cpp b/protocols/JabberG/src/jabber_iqid.cpp index bbd7a0dd60..2839a73e30 100644 --- a/protocols/JabberG/src/jabber_iqid.cpp +++ b/protocols/JabberG/src/jabber_iqid.cpp @@ -389,7 +389,7 @@ void CJabberProto::OnIqResultBind(const TiXmlElement *iqNode, CJabberIqInfo *pIn }
}
- if (m_isSessionAvailable) {
+ if (m_hasSession) {
m_ThreadInfo->send(
XmlNodeIq(AddIQ(&CJabberProto::OnIqResultSession, JABBER_IQ_TYPE_SET))
<< XCHILDNS("session", "urn:ietf:params:xml:ns:xmpp-session"));
diff --git a/protocols/JabberG/src/jabber_omemo.cpp b/protocols/JabberG/src/jabber_omemo.cpp index 7a01603a1e..39b6b7d8dd 100644 --- a/protocols/JabberG/src/jabber_omemo.cpp +++ b/protocols/JabberG/src/jabber_omemo.cpp @@ -1733,7 +1733,7 @@ void CJabberProto::OmemoOnIqResultGetBundle(const TiXmlElement *iqNode, CJabberI return; //failed to build signal(omemo) session
}
- OmemoCheckSession((MCONTACT)IqInfo->GetUserData(), false);
+ OmemoCheckSession((UINT_PTR)IqInfo->GetUserData(), false);
}
int CJabberProto::OmemoEncryptMessage(XmlNode &msg, const char *msg_text, MCONTACT hContact)
diff --git a/protocols/JabberG/src/jabber_opt.cpp b/protocols/JabberG/src/jabber_opt.cpp index f85836701f..5254d9ea10 100644 --- a/protocols/JabberG/src/jabber_opt.cpp +++ b/protocols/JabberG/src/jabber_opt.cpp @@ -741,6 +741,7 @@ public: pOptions->AddOption(LPGENW("Server options"), LPGENW("Use Stream Management (XEP-0198)"), m_proto->m_bEnableStreamMgmt);
pOptions->AddOption(LPGENW("Server options"), LPGENW("Disable SASL authentication (for old servers)"), m_proto->m_bDisable3920auth);
+ pOptions->AddOption(LPGENW("Server options"), LPGENW("Enable SASL2 authentication, if present"), m_proto->m_bEnableSasl2);
pOptions->AddOption(LPGENW("Server options"), LPGENW("Enable stream compression"), m_proto->m_bEnableZlib);
pOptions->AddOption(LPGENW("Other"), LPGENW("Enable remote controlling (from another resource of same JID only)"), m_proto->m_bEnableRemoteControl);
diff --git a/protocols/JabberG/src/jabber_proto.cpp b/protocols/JabberG/src/jabber_proto.cpp index c4f02c7774..fbb772ac56 100644 --- a/protocols/JabberG/src/jabber_proto.cpp +++ b/protocols/JabberG/src/jabber_proto.cpp @@ -98,6 +98,7 @@ CJabberProto::CJabberProto(const char *aProtoName, const wchar_t *aUserName) : m_bEnableMam(this, "EnableMam", true),
m_bEnableMsgArchive(this, "EnableMsgArchive", false),
m_bEnableRemoteControl(this, "EnableRemoteControl", false),
+ m_bEnableSasl2(this, "EnableSasl2", true),
m_bEnableStreamMgmt(this, "UseStreamMgmt", false),
m_bEnableUserActivity(this, "EnableUserActivity", true),
m_bEnableUserMood(this, "EnableUserMood", true),
diff --git a/protocols/JabberG/src/jabber_proto.h b/protocols/JabberG/src/jabber_proto.h index f1e0f97f44..407e5c91ca 100644 --- a/protocols/JabberG/src/jabber_proto.h +++ b/protocols/JabberG/src/jabber_proto.h @@ -203,6 +203,7 @@ struct CJabberProto : public PROTO<CJabberProto>, public IJabberInterface CMOption<bool> m_bEnableMsgArchive;
CMOption<bool> m_bEnableMam;
CMOption<bool> m_bEnableRemoteControl;
+ CMOption<bool> m_bEnableSasl2;
CMOption<bool> m_bEnableStreamMgmt;
CMOption<bool> m_bEnableUserActivity;
CMOption<bool> m_bEnableUserMood;
@@ -816,7 +817,7 @@ struct CJabberProto : public PROTO<CJabberProto>, public IJabberInterface ptrW m_savedPassword;
OBJLIST<class TJabberAuth> m_arAuthMechs;
- bool m_isSessionAvailable, m_isAuthAvailable;
+ bool m_hasSession, m_hasAuth, m_hasSasl2;
void __cdecl ServerThread(JABBER_CONN_DATA *info);
bool ServerThreadStub(ThreadData &info);
@@ -842,6 +843,7 @@ struct CJabberProto : public PROTO<CJabberProto>, public IJabberInterface void PerformRegistration(ThreadData *info);
void PerformIqAuth(ThreadData *info);
void PerformAuthentication(ThreadData *info);
+ bool OnProcessMechanism(const TiXmlElement *node, ThreadData *info);
void OnProcessFeatures(const TiXmlElement *node, ThreadData *info);
void xmlStreamInitialize(char *which);
diff --git a/protocols/JabberG/src/jabber_secur.cpp b/protocols/JabberG/src/jabber_secur.cpp index 104c225504..2b52830960 100644 --- a/protocols/JabberG/src/jabber_secur.cpp +++ b/protocols/JabberG/src/jabber_secur.cpp @@ -25,6 +25,61 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "stdafx.h"
#include "jabber_secur.h"
+bool CJabberProto::OnProcessMechanism(const TiXmlElement *n, ThreadData *info)
+{
+ if (!mir_strcmp(n->Name(), "mechanism")) {
+ TJabberAuth *pAuth = nullptr;
+ const char *szMechanism = n->GetText();
+ if (!mir_strcmp(szMechanism, "PLAIN")) {
+ m_arAuthMechs.insert(new TPlainAuth(info, false));
+ pAuth = new TPlainAuth(info, true);
+ }
+ else if (!mir_strcmp(szMechanism, "DIGEST-MD5"))
+ pAuth = new TMD5Auth(info);
+ else if (!mir_strcmp(szMechanism, "SCRAM-SHA-1"))
+ pAuth = new TScramAuth(info, szMechanism, EVP_sha1(), 500);
+ else if (!mir_strcmp(szMechanism, "SCRAM-SHA-1-PLUS"))
+ pAuth = new TScramAuth(info, szMechanism, EVP_sha1(), 601);
+ 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(), 611);
+ else if (!mir_strcmp(szMechanism, "SCRAM-SHA-256"))
+ pAuth = new TScramAuth(info, szMechanism, EVP_sha256(), 520);
+ else if (!mir_strcmp(szMechanism, "SCRAM-SHA-256-PLUS"))
+ pAuth = new TScramAuth(info, szMechanism, EVP_sha256(), 621);
+ 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(), 631);
+ 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(), 641);
+ 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);
+ return true;
+ }
+
+ if (!pAuth->isValid())
+ delete pAuth;
+ else
+ m_arAuthMechs.insert(pAuth);
+ return true;
+ }
+
+ if (!mir_strcmp(n->Name(), "hostname")) {
+ const char *mech = XmlGetAttr(n, "mechanism");
+ if (mech && mir_strcmpi(mech, "GSSAPI") == 0)
+ info->gssapiHostName = mir_strdup(n->GetText());
+ return true;
+ }
+
+ return false;
+}
+
/////////////////////////////////////////////////////////////////////////////////////////
// ntlm auth - LanServer based authorization
diff --git a/protocols/JabberG/src/jabber_strm_mgmt.cpp b/protocols/JabberG/src/jabber_strm_mgmt.cpp index 48074cdb38..c92ba4ea98 100644 --- a/protocols/JabberG/src/jabber_strm_mgmt.cpp +++ b/protocols/JabberG/src/jabber_strm_mgmt.cpp @@ -52,7 +52,7 @@ void strm_mgmt::OnProcessEnabled(const TiXmlElement *node, ThreadData * /*info*/ void strm_mgmt::OnProcessResumed(const TiXmlElement *node, ThreadData * /*info*/)
{
- if (mir_strcmp(XmlGetAttr(node, "xmlns"), "urn:xmpp:sm:3"))
+ if (mir_strcmp(XmlGetAttr(node, "xmlns"), JABBER_FEAT_SM))
return;
auto *var = XmlGetAttr(node, "previd");
@@ -74,7 +74,7 @@ void strm_mgmt::OnProcessResumed(const TiXmlElement *node, ThreadData * /*info*/ void strm_mgmt::OnProcessSMa(const TiXmlElement *node)
{
- if (mir_strcmp(XmlGetAttr(node, "xmlns"), "urn:xmpp:sm:3"))
+ if (mir_strcmp(XmlGetAttr(node, "xmlns"), JABBER_FEAT_SM))
return;
if (!m_bRequestPending)
@@ -118,13 +118,13 @@ void strm_mgmt::ProcessCache(uint32_t nSrvHCount, bool resuming) void strm_mgmt::OnProcessSMr(const TiXmlElement *node)
{
- if (!mir_strcmp(XmlGetAttr(node, "xmlns"), "urn:xmpp:sm:3"))
+ if (!mir_strcmp(XmlGetAttr(node, "xmlns"), JABBER_FEAT_SM))
SendAck();
}
void strm_mgmt::OnProcessFailed(const TiXmlElement *node, ThreadData *info) //used failed instead of failure, notes: https://xmpp.org/extensions/xep-0198.html#errors
{
- if (mir_strcmp(XmlGetAttr(node, "xmlns"), "urn:xmpp:sm:3"))
+ if (mir_strcmp(XmlGetAttr(node, "xmlns"), JABBER_FEAT_SM))
return;
proto->debugLogA("strm_mgmt: error: Failed to resume session %s", m_sResumeId.c_str());
@@ -147,11 +147,15 @@ void strm_mgmt::OnProcessFailed(const TiXmlElement *node, ThreadData *info) //us void strm_mgmt::CheckStreamFeatures(const TiXmlElement *node)
{
+ // this may be necessary to reset counters if session resume id is not set
if (!IsResumeIdPresent())
- ResetState(); //this may be necessary to reset counters if session resume id is not set
- if (mir_strcmp(node->Name(), "sm") || !XmlGetAttr(node, "xmlns") || mir_strcmp(XmlGetAttr(node, "xmlns"), "urn:xmpp:sm:3")) //we work only with version 3 or higher of sm
+ ResetState();
+
+ // we work only with version 3 or higher of sm
+ if (mir_strcmp(node->Name(), "sm") || !XmlGetAttr(node, "xmlns") || mir_strcmp(XmlGetAttr(node, "xmlns"), JABBER_FEAT_SM))
return;
- if (!(proto->m_bJabberOnline))
+
+ if (!proto->m_bJabberOnline)
m_bPendingEnable = true;
else
EnableStrmMgmt();
@@ -224,14 +228,14 @@ void strm_mgmt::EnableStrmMgmt() if (m_sResumeId.empty()) {
XmlNode enable_sm("enable");
- XmlAddAttr(enable_sm, "xmlns", "urn:xmpp:sm:3");
+ XmlAddAttr(enable_sm, "xmlns", JABBER_FEAT_SM);
XmlAddAttr(enable_sm, "resume", "true"); // enable resumption (most useful part of this xep)
proto->m_ThreadInfo->send(enable_sm);
m_nLocalSCount = 0;
}
else { // resume session
XmlNode enable_sm("resume");
- enable_sm << XATTR("xmlns", "urn:xmpp:sm:3") << XATTRI("h", m_nLocalHCount) << XATTR("previd", m_sResumeId.c_str());
+ enable_sm << XATTR("xmlns", JABBER_FEAT_SM) << XATTRI("h", m_nLocalHCount) << XATTR("previd", m_sResumeId.c_str());
proto->m_ThreadInfo->send(enable_sm);
}
}
@@ -243,7 +247,7 @@ void strm_mgmt::SendAck() proto->debugLogA("strm_mgmt: info: sending ack: locally received node count %d", m_nLocalHCount);
XmlNode ack_node("a");
- ack_node << XATTR("xmlns", "urn:xmpp:sm:3") << XATTRI("h", m_nLocalHCount);
+ ack_node << XATTR("xmlns", JABBER_FEAT_SM) << XATTRI("h", m_nLocalHCount);
proto->m_ThreadInfo->send_no_strm_mgmt(ack_node);
}
diff --git a/protocols/JabberG/src/jabber_thread.cpp b/protocols/JabberG/src/jabber_thread.cpp index b1d5eb28cf..b5b13ce4ec 100644 --- a/protocols/JabberG/src/jabber_thread.cpp +++ b/protocols/JabberG/src/jabber_thread.cpp @@ -225,8 +225,11 @@ void CJabberProto::xmlStreamInitializeNow(ThreadData *info) if (m_tszSelectedLang)
n << XATTR("xml:lang", m_tszSelectedLang);
- if (!m_bDisable3920auth)
+ if (!m_bDisable3920auth) {
n << XATTR("version", "1.0");
+ if (m_bEnableSasl2)
+ n << XATTR("from", CMStringA(FORMAT, "%s@%s", info->conn.username, info->conn.server));
+ }
tinyxml2::XMLPrinter printer(0, true);
n.Print(&printer);
@@ -615,8 +618,8 @@ void CJabberProto::PerformAuthentication(ThreadData *info) // no known mechanisms
if (m_arAuthMechs.getCount() == 0) {
// if iq_auth is available, use it
- if (m_isAuthAvailable) {
- m_isAuthAvailable = false;
+ if (m_hasAuth) {
+ m_hasAuth = false;
PerformIqAuth(info);
return;
}
@@ -667,72 +670,45 @@ void CJabberProto::OnProcessFeatures(const TiXmlElement *node, ThreadData *info) }
}
+ auto *xmlns = n->Attribute("xmlns");
if (!mir_strcmp(pszName, "mechanisms")) {
+ areMechanismsDefined = true;
m_arAuthMechs.destroy();
replaceStr(info->gssapiHostName, nullptr);
- areMechanismsDefined = true;
+ for (auto *c : TiXmlEnum(n))
+ OnProcessMechanism(c, info);
+ }
+ else if (!mir_strcmp(pszName, "register"))
+ isRegisterAvailable = true;
+ else if (!mir_strcmp(pszName, "auth"))
+ m_hasAuth = true;
+ else if (!mir_strcmp(pszName, "authentication") && !mir_strcmp(xmlns, JABBER_FEAT_SASL2) && m_bEnableSasl2) {
+ m_hasSasl2 = areMechanismsDefined = true;
+ m_arAuthMechs.destroy();
+ replaceStr(info->gssapiHostName, nullptr);
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_arAuthMechs.insert(new TPlainAuth(info, false));
- pAuth = new TPlainAuth(info, true);
- }
- else if (!mir_strcmp(szMechanism, "DIGEST-MD5"))
- pAuth = new TMD5Auth(info);
- else if (!mir_strcmp(szMechanism, "SCRAM-SHA-1"))
- pAuth = new TScramAuth(info, szMechanism, EVP_sha1(), 500);
- else if (!mir_strcmp(szMechanism, "SCRAM-SHA-1-PLUS"))
- pAuth = new TScramAuth(info, szMechanism, EVP_sha1(), 601);
- 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(), 611);
- else if (!mir_strcmp(szMechanism, "SCRAM-SHA-256"))
- pAuth = new TScramAuth(info, szMechanism, EVP_sha256(), 520);
- else if (!mir_strcmp(szMechanism, "SCRAM-SHA-256-PLUS"))
- pAuth = new TScramAuth(info, szMechanism, EVP_sha256(), 621);
- 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(), 631);
- 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(), 641);
- 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 (OnProcessMechanism(c, info))
+ 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)
- info->gssapiHostName = mir_strdup(c->GetText());
+ if (!mir_strcmp(c->Name(), "inline")) {
+ if (auto *sm = XmlGetChildByTag(c, "sm", "xmlns", JABBER_FEAT_SM))
+ m_StrmMgmt.CheckStreamFeatures(sm);
+
+ if (auto *bind = XmlGetChildByTag(c, "sm", "xmlns", "urn:xmpp:bind:0")) {
+ // dunno why we need to handle that
+ }
}
}
}
- else if (!mir_strcmp(pszName, "register"))
- isRegisterAvailable = true;
- else if (!mir_strcmp(pszName, "auth"))
- m_isAuthAvailable = true;
else if (!mir_strcmp(pszName, "session"))
- m_isSessionAvailable = true;
+ m_hasSession = true;
else if (m_bEnableStreamMgmt && !mir_strcmp(pszName, "sm"))
m_StrmMgmt.CheckStreamFeatures(n);
- else if (!mir_strcmp(pszName, "csi") && n->Attribute("xmlns", JABBER_FEAT_CSI))
+ else if (!mir_strcmp(pszName, "csi") && !mir_strcmp(xmlns, JABBER_FEAT_CSI))
m_bCisAvailable = true;
- else if (!mir_strcmp(pszName, "c") && !mir_strcmp(n->Attribute("xmlns"), JABBER_FEAT_ENTITY_CAPS)) {
+ else if (!mir_strcmp(pszName, "c") && !mir_strcmp(xmlns, JABBER_FEAT_ENTITY_CAPS)) {
auto *szNode = n->Attribute("node"), *szHash = n->Attribute("ver");
auto *pCaps = g_clientCapsManager.GetPartialCaps(szNode, szHash);
if (pCaps == nullptr) {
@@ -741,7 +717,7 @@ void CJabberProto::OnProcessFeatures(const TiXmlElement *node, ThreadData *info) }
else info->jabberServerCaps |= pCaps->GetCaps();
}
- else if (!mir_strcmp(pszName, "sasl-channel-binding") && !mir_strcmp(n->Attribute("xmlns"), JABBER_FEAT_CHANNEL_BINDING)) {
+ else if (!mir_strcmp(pszName, "sasl-channel-binding") && !mir_strcmp(xmlns, JABBER_FEAT_CHANNEL_BINDING)) {
for (auto *it : TiXmlFilter(n, "channel-binding")) {
if (auto *pszType = it->Attribute("type")) {
if (!mir_strcmp(pszType, "tls-exporter"))
|