diff options
author | Peter Powell <petpow@saberuk.com> | 2018-11-26 15:15:18 +0000 |
---|---|---|
committer | Peter Powell <petpow@saberuk.com> | 2018-12-01 23:48:33 +0000 |
commit | ec6955f28ba9423828ac24ef83caee09ffa6b52c (patch) | |
tree | 5160c97069498ba1a11732f21398380a7be008f4 | |
parent | 95749975408a985d6a6a9ff53bbf3592c90b8649 (diff) |
Fix detecting secure clients connecting through HAProxy/WEBIRC.
-rw-r--r-- | src/modules/m_cgiirc.cpp | 10 | ||||
-rw-r--r-- | src/modules/m_jumpserver.cpp | 7 | ||||
-rw-r--r-- | src/modules/m_sasl.cpp | 19 | ||||
-rw-r--r-- | src/modules/m_sqlauth.cpp | 6 | ||||
-rw-r--r-- | src/modules/m_sslinfo.cpp | 95 | ||||
-rw-r--r-- | src/modules/m_sslmodes.cpp | 40 |
6 files changed, 92 insertions, 85 deletions
diff --git a/src/modules/m_cgiirc.cpp b/src/modules/m_cgiirc.cpp index 1e5a188f8..4a5a4fb03 100644 --- a/src/modules/m_cgiirc.cpp +++ b/src/modules/m_cgiirc.cpp @@ -103,15 +103,15 @@ class WebIRCHost { } - bool Matches(LocalUser* user, const std::string& pass) const + bool Matches(LocalUser* user, const std::string& pass, UserCertificateAPI& sslapi) const { // Did the user send a valid password? if (!password.empty() && !ServerInstance->PassCompare(user, password, pass, passhash)) return false; // Does the user have a valid fingerprint? - const std::string fp = SSLClientCert::GetFingerprint(&user->eh); - if (!fingerprint.empty() && fp != fingerprint) + const std::string fp = sslapi ? sslapi->GetFingerprint(user) : ""; + if (!fingerprint.empty() && !InspIRCd::TimingSafeCompare(fp, fingerprint)) return false; // Does the user's hostname match our hostmask? @@ -142,6 +142,7 @@ class CommandWebIRC : public SplitCommand StringExtItem gateway; StringExtItem realhost; StringExtItem realip; + UserCertificateAPI sslapi; Events::ModuleEventProvider webircevprov; CommandWebIRC(Module* Creator) @@ -149,6 +150,7 @@ class CommandWebIRC : public SplitCommand , gateway("cgiirc_gateway", ExtensionItem::EXT_USER, Creator) , realhost("cgiirc_realhost", ExtensionItem::EXT_USER, Creator) , realip("cgiirc_realip", ExtensionItem::EXT_USER, Creator) + , sslapi(Creator) , webircevprov(Creator, "event/webirc") { allow_empty_last_param = false; @@ -164,7 +166,7 @@ class CommandWebIRC : public SplitCommand for (std::vector<WebIRCHost>::const_iterator iter = hosts.begin(); iter != hosts.end(); ++iter) { // If we don't match the host then skip to the next host. - if (!iter->Matches(user, parameters[0])) + if (!iter->Matches(user, parameters[0], sslapi)) continue; irc::sockets::sockaddrs ipaddr; diff --git a/src/modules/m_jumpserver.cpp b/src/modules/m_jumpserver.cpp index 682e353d2..fc13a831c 100644 --- a/src/modules/m_jumpserver.cpp +++ b/src/modules/m_jumpserver.cpp @@ -38,8 +38,11 @@ class CommandJumpserver : public Command std::string reason; int port; int sslport; + UserCertificateAPI sslapi; - CommandJumpserver(Module* Creator) : Command(Creator, "JUMPSERVER", 0, 4) + CommandJumpserver(Module* Creator) + : Command(Creator, "JUMPSERVER", 0, 4) + , sslapi(Creator) { flags_needed = 'o'; syntax = "[<server> <port>[:<sslport>] <+/-an> <reason>]"; @@ -146,7 +149,7 @@ class CommandJumpserver : public Command int GetPort(LocalUser* user) { - int p = (SSLIOHook::IsSSL(&user->eh) ? sslport : port); + int p = (sslapi && sslapi->GetCertificate(user) ? sslport : port); if (p == 0) p = user->GetServerPort(); return p; diff --git a/src/modules/m_sasl.cpp b/src/modules/m_sasl.cpp index 480f8f6db..cb5245111 100644 --- a/src/modules/m_sasl.cpp +++ b/src/modules/m_sasl.cpp @@ -171,26 +171,28 @@ class SaslAuthenticator SaslResult result; bool state_announced; - void SendHostIP() + void SendHostIP(UserCertificateAPI& sslapi) { std::vector<std::string> params; params.push_back(user->GetRealHost()); params.push_back(user->GetIPString()); - params.push_back(SSLIOHook::IsSSL(&user->eh) ? "S" : "P"); + params.push_back(sslapi && sslapi->GetCertificate(user) ? "S" : "P"); SendSASL(user, "*", 'H', params); } public: - SaslAuthenticator(LocalUser* user_, const std::string& method) - : user(user_), state(SASL_INIT), state_announced(false) + SaslAuthenticator(LocalUser* user_, const std::string& method, UserCertificateAPI& sslapi) + : user(user_) + , state(SASL_INIT) + , state_announced(false) { - SendHostIP(); + SendHostIP(sslapi); std::vector<std::string> params; params.push_back(method); - const std::string fp = SSLClientCert::GetFingerprint(&user->eh); + const std::string fp = sslapi ? sslapi->GetFingerprint(user) : ""; if (fp.size()) params.push_back(fp); @@ -305,10 +307,13 @@ class CommandAuthenticate : public SplitCommand public: SimpleExtItem<SaslAuthenticator>& authExt; Cap::Capability& cap; + UserCertificateAPI sslapi; + CommandAuthenticate(Module* Creator, SimpleExtItem<SaslAuthenticator>& ext, Cap::Capability& Cap) : SplitCommand(Creator, "AUTHENTICATE", 1) , authExt(ext) , cap(Cap) + , sslapi(Creator) { works_before_reg = true; allow_empty_last_param = false; @@ -331,7 +336,7 @@ class CommandAuthenticate : public SplitCommand SaslAuthenticator *sasl = authExt.get(user); if (!sasl) - authExt.set(user, new SaslAuthenticator(user, parameters[0])); + authExt.set(user, new SaslAuthenticator(user, parameters[0], sslapi)); else if (sasl->SendClientMessage(parameters) == false) // IAL abort extension --nenolod { sasl->AnnounceState(); diff --git a/src/modules/m_sqlauth.cpp b/src/modules/m_sqlauth.cpp index 5c3c5a84e..d2466f719 100644 --- a/src/modules/m_sqlauth.cpp +++ b/src/modules/m_sqlauth.cpp @@ -116,6 +116,7 @@ class ModuleSQLAuth : public Module { LocalIntExt pendingExt; dynamic_reference<SQL::Provider> SQL; + UserCertificateAPI sslapi; std::string freeformquery; std::string killreason; @@ -129,6 +130,7 @@ class ModuleSQLAuth : public Module ModuleSQLAuth() : pendingExt("sqlauth-wait", ExtensionItem::EXT_USER, this) , SQL(this, "SQL") + , sslapi(this) { } @@ -179,6 +181,7 @@ class ModuleSQLAuth : public Module SQL::ParamMap userinfo; SQL::PopulateUserInfo(user, userinfo); userinfo["pass"] = user->password; + userinfo["certfp"] = sslapi ? sslapi->GetFingerprint(user) : ""; for (std::vector<std::string>::const_iterator it = hash_algos.begin(); it != hash_algos.end(); ++it) { @@ -187,9 +190,6 @@ class ModuleSQLAuth : public Module userinfo[*it + "pass"] = hashprov->Generate(user->password); } - const std::string certfp = SSLClientCert::GetFingerprint(&user->eh); - userinfo["certfp"] = certfp; - SQL->Submit(new AuthQuery(this, user->uuid, pendingExt, verbose, kdf, pwcolumn), freeformquery, userinfo); return MOD_RES_PASSTHRU; diff --git a/src/modules/m_sslinfo.cpp b/src/modules/m_sslinfo.cpp index a258c35a5..54aeb9755 100644 --- a/src/modules/m_sslinfo.cpp +++ b/src/modules/m_sslinfo.cpp @@ -31,7 +31,8 @@ enum RPL_WHOISSECURE = 671 }; -class SSLCertExt : public ExtensionItem { +class SSLCertExt : public ExtensionItem +{ public: SSLCertExt(Module* parent) : ExtensionItem("ssl_cert", ExtensionItem::EXT_USER, parent) @@ -42,6 +43,7 @@ class SSLCertExt : public ExtensionItem { { return static_cast<ssl_cert*>(get_raw(item)); } + void set(Extensible* item, ssl_cert* value) { value->refcount_inc(); @@ -94,14 +96,53 @@ class SSLCertExt : public ExtensionItem { } }; -/** Handle /SSLINFO - */ +class UserCertificateAPIImpl : public UserCertificateAPIBase +{ + public: + LocalIntExt nosslext; + SSLCertExt sslext; + + UserCertificateAPIImpl(Module* mod) + : UserCertificateAPIBase(mod) + , nosslext("no_ssl_cert", ExtensionItem::EXT_USER, mod) + , sslext(mod) + { + } + + ssl_cert* GetCertificate(User* user) CXX11_OVERRIDE + { + ssl_cert* cert = sslext.get(user); + if (cert) + return cert; + + LocalUser* luser = IS_LOCAL(user); + if (!luser || nosslext.get(luser)) + return NULL; + + cert = SSLClientCert::GetCertificate(&luser->eh); + if (!cert) + return NULL; + + SetCertificate(user, cert); + return cert; + } + + void SetCertificate(User* user, ssl_cert* cert) CXX11_OVERRIDE + { + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Setting SSL certificate for %s: %s", + user->GetFullHost().c_str(), cert->GetMetaLine().c_str()); + sslext.set(user, cert); + } +}; + class CommandSSLInfo : public Command { public: - SSLCertExt CertExt; + UserCertificateAPIImpl sslapi; - CommandSSLInfo(Module* Creator) : Command(Creator, "SSLINFO", 1), CertExt(Creator) + CommandSSLInfo(Module* Creator) + : Command(Creator, "SSLINFO", 1) + , sslapi(Creator) { this->syntax = "<nick>"; } @@ -121,7 +162,7 @@ class CommandSSLInfo : public Command user->WriteNotice("*** You cannot view SSL certificate information for other users"); return CMD_FAILURE; } - ssl_cert* cert = CertExt.get(target); + ssl_cert* cert = sslapi.GetCertificate(target); if (!cert) { user->WriteNotice("*** No SSL certificate for this user"); @@ -140,41 +181,19 @@ class CommandSSLInfo : public Command } }; -class UserCertificateAPIImpl : public UserCertificateAPIBase -{ - SSLCertExt& ext; - - public: - UserCertificateAPIImpl(Module* mod, SSLCertExt& certext) - : UserCertificateAPIBase(mod), ext(certext) - { - } - - ssl_cert* GetCertificate(User* user) CXX11_OVERRIDE - { - return ext.get(user); - } - - void SetCertificate(User* user, ssl_cert* cert) CXX11_OVERRIDE - { - ext.set(user, cert); - } -}; - class ModuleSSLInfo : public Module , public WebIRC::EventListener , public Whois::EventListener { + private: CommandSSLInfo cmd; - UserCertificateAPIImpl APIImpl; public: ModuleSSLInfo() : WebIRC::EventListener(this) , Whois::EventListener(this) , cmd(this) - , APIImpl(this, cmd.CertExt) { } @@ -185,7 +204,7 @@ class ModuleSSLInfo void OnWhois(Whois::Context& whois) CXX11_OVERRIDE { - ssl_cert* cert = cmd.CertExt.get(whois.GetTarget()); + ssl_cert* cert = cmd.sslapi.GetCertificate(whois.GetTarget()); if (cert) { whois.SendLine(RPL_WHOISSECURE, "is using a secure connection"); @@ -203,7 +222,7 @@ class ModuleSSLInfo if (i != ServerInstance->Config->oper_blocks.end()) { OperInfo* ifo = i->second; - ssl_cert* cert = cmd.CertExt.get(user); + ssl_cert* cert = cmd.sslapi.GetCertificate(user); if (ifo->oper_block->getBool("sslonly") && !cert) { @@ -226,13 +245,6 @@ class ModuleSSLInfo return MOD_RES_PASSTHRU; } - void OnUserConnect(LocalUser* user) CXX11_OVERRIDE - { - ssl_cert* cert = SSLClientCert::GetCertificate(&user->eh); - if (cert) - cmd.CertExt.set(user, cert); - } - void OnPostConnect(User* user) CXX11_OVERRIDE { LocalUser* const localuser = IS_LOCAL(user); @@ -298,7 +310,7 @@ class ModuleSSLInfo // We only care about the tls connection flag if the connection // between the gateway and the server is secure. - if (!cmd.CertExt.get(user)) + if (!cmd.sslapi.GetCertificate(user)) return; WebIRC::FlagMap::const_iterator iter = flags->find("secure"); @@ -306,7 +318,8 @@ class ModuleSSLInfo { // If this is not set then the connection between the client and // the gateway is not secure. - cmd.CertExt.unset(user); + cmd.sslapi.nosslext.set(user, 1); + cmd.sslapi.sslext.unset(user); return; } @@ -317,7 +330,7 @@ class ModuleSSLInfo cert->revoked = true; cert->trusted = false; cert->unknownsigner = true; - cmd.CertExt.set(user, cert); + cmd.sslapi.SetCertificate(user, cert); } }; diff --git a/src/modules/m_sslmodes.cpp b/src/modules/m_sslmodes.cpp index dc0063d29..f162ceb87 100644 --- a/src/modules/m_sslmodes.cpp +++ b/src/modules/m_sslmodes.cpp @@ -32,18 +32,6 @@ enum ERR_ALLMUSTSSL = 490 }; -namespace -{ - bool IsSSLUser(UserCertificateAPI& api, User* user) - { - if (!api) - return false; - - ssl_cert* cert = api->GetCertificate(user); - return (cert != NULL); - } -} - /** Handle channel mode +z */ class SSLMode : public ModeHandler @@ -67,7 +55,10 @@ class SSLMode : public ModeHandler if (IS_LOCAL(source)) { if (!API) + { + source->WriteNumeric(ERR_ALLMUSTSSL, channel->name, "Unable to determine whether all members of the channel are connected via SSL"); return MODEACTION_DENY; + } const Channel::MemberMap& userlist = channel->GetUsers(); for (Channel::MemberMap::const_iterator i = userlist.begin(); i != userlist.end(); ++i) @@ -123,7 +114,7 @@ class SSLModeUser : public ModeHandler { if (!dest->IsModeSet(this)) { - if (!IsSSLUser(API, user)) + if (!API || !API->GetCertificate(user)) return MODEACTION_DENY; dest->SetMode(this, true); @@ -163,17 +154,13 @@ class ModuleSSLModes : public Module if(chan && chan->IsModeSet(sslm)) { if (!api) - return MOD_RES_DENY; - - ssl_cert* cert = api->GetCertificate(user); - if (cert) { - // Let them in - return MOD_RES_PASSTHRU; + user->WriteNumeric(ERR_SECUREONLYCHAN, cname, "Cannot join channel; unable to determine if you are a SSL user (+z)"); + return MOD_RES_DENY; } - else + + if (!api->GetCertificate(user)) { - // Deny user->WriteNumeric(ERR_SECUREONLYCHAN, cname, "Cannot join channel; SSL users only (+z)"); return MOD_RES_DENY; } @@ -196,7 +183,7 @@ class ModuleSSLModes : public Module /* If the target is +z */ if (target->IsModeSet(sslquery)) { - if (!IsSSLUser(api, user)) + if (!api || !api->GetCertificate(user)) { /* The sending user is not on an SSL connection */ user->WriteNumeric(ERR_CANTSENDTOUSER, target->nick, "You are not permitted to send private messages to this user (+z set)"); @@ -206,7 +193,7 @@ class ModuleSSLModes : public Module /* If the user is +z */ else if (user->IsModeSet(sslquery)) { - if (!IsSSLUser(api, target)) + if (!api || !api->GetCertificate(target)) { user->WriteNumeric(ERR_CANTSENDTOUSER, target->nick, "You must remove usermode 'z' before you are able to send private messages to a non-ssl user."); return MOD_RES_DENY; @@ -220,11 +207,8 @@ class ModuleSSLModes : public Module { if ((mask.length() > 2) && (mask[0] == 'z') && (mask[1] == ':')) { - if (!api) - return MOD_RES_DENY; - - ssl_cert* cert = api->GetCertificate(user); - if (cert && InspIRCd::Match(cert->GetFingerprint(), mask.substr(2))) + const std::string fp = api ? api->GetFingerprint(user) : ""; + if (!fp.empty() && InspIRCd::Match(fp, mask.substr(2))) return MOD_RES_DENY; } return MOD_RES_PASSTHRU; |