diff options
| author | 2019-02-05 00:47:30 +0000 | |
|---|---|---|
| committer | 2019-02-05 00:47:30 +0000 | |
| commit | bfa5fb407e13ad4adb5c062021de50ecd760ed95 (patch) | |
| tree | c573269b1a94fd7e7da27c1b90b05fa60916de23 /src/modules | |
| parent | Remove support for the deprecated <power> config tag. (diff) | |
| parent | ModuleManager: use std::flush instead of fflush(stdout). (diff) | |
Merge branch 'insp3' into master.
Diffstat (limited to 'src/modules')
| -rw-r--r-- | src/modules/m_anticaps.cpp | 2 | ||||
| -rw-r--r-- | src/modules/m_cban.cpp | 6 | ||||
| -rw-r--r-- | src/modules/m_cgiirc.cpp | 4 | ||||
| -rw-r--r-- | src/modules/m_check.cpp | 75 | ||||
| -rw-r--r-- | src/modules/m_cloaking.cpp | 12 | ||||
| -rw-r--r-- | src/modules/m_hostchange.cpp | 4 | ||||
| -rw-r--r-- | src/modules/m_httpd_stats.cpp | 372 | ||||
| -rw-r--r-- | src/modules/m_ident.cpp | 96 | ||||
| -rw-r--r-- | src/modules/m_ircv3_sts.cpp | 2 | ||||
| -rw-r--r-- | src/modules/m_muteban.cpp | 10 | ||||
| -rw-r--r-- | src/modules/m_opermotd.cpp | 2 | ||||
| -rw-r--r-- | src/modules/m_rline.cpp | 6 | ||||
| -rw-r--r-- | src/modules/m_samode.cpp | 4 | ||||
| -rw-r--r-- | src/modules/m_setname.cpp | 17 | ||||
| -rw-r--r-- | src/modules/m_showwhois.cpp | 2 | ||||
| -rw-r--r-- | src/modules/m_shun.cpp | 10 | ||||
| -rw-r--r-- | src/modules/m_spanningtree/delline.cpp | 7 | ||||
| -rw-r--r-- | src/modules/m_spanningtree/uid.cpp | 2 | ||||
| -rw-r--r-- | src/modules/m_sslinfo.cpp | 11 | ||||
| -rw-r--r-- | src/modules/m_svshold.cpp | 6 |
20 files changed, 412 insertions, 238 deletions
diff --git a/src/modules/m_anticaps.cpp b/src/modules/m_anticaps.cpp index efb3d091b..c5da88bfb 100644 --- a/src/modules/m_anticaps.cpp +++ b/src/modules/m_anticaps.cpp @@ -148,7 +148,7 @@ class AntiCapsMode : public ParamMode<AntiCapsMode, SimpleExtItem<AntiCapsSettin out.push_back(':'); out.append(ConvToStr(acs->minlen)); out.push_back(':'); - out.append(ConvToStr(acs->percent)); + out.append(ConvNumeric(acs->percent)); } }; diff --git a/src/modules/m_cban.cpp b/src/modules/m_cban.cpp index 724ebc10f..949b410dd 100644 --- a/src/modules/m_cban.cpp +++ b/src/modules/m_cban.cpp @@ -98,9 +98,11 @@ class CommandCBan : public Command if (parameters.size() == 1) { - if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "CBAN", user)) + std::string reason; + + if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "CBAN", reason, user)) { - ServerInstance->SNO->WriteGlobalSno('x', "%s removed CBan on %s.",user->nick.c_str(),parameters[0].c_str()); + ServerInstance->SNO->WriteGlobalSno('x', "%s removed CBan on %s: %s", user->nick.c_str(), parameters[0].c_str(), reason.c_str()); } else { diff --git a/src/modules/m_cgiirc.cpp b/src/modules/m_cgiirc.cpp index 55129b78e..ec926242e 100644 --- a/src/modules/m_cgiirc.cpp +++ b/src/modules/m_cgiirc.cpp @@ -311,7 +311,7 @@ class ModuleCgiIRC } else { - throw ModuleException(type + " is an invalid <cgihost:mask> type, at " + tag->getTagLocation()); + throw ModuleException(type + " is an invalid <cgihost:mask> type, at " + tag->getTagLocation()); } } @@ -369,7 +369,7 @@ class ModuleCgiIRC user->ChangeIdent(newident); user->SetClientIP(address); - break; + break; } return MOD_RES_PASSTHRU; } diff --git a/src/modules/m_check.cpp b/src/modules/m_check.cpp index ca9541176..cf2954697 100644 --- a/src/modules/m_check.cpp +++ b/src/modules/m_check.cpp @@ -30,9 +30,18 @@ enum class CheckContext { + private: User* const user; const std::string& target; + std::string FormatTime(time_t ts) + { + std::string timestr(InspIRCd::TimeString(ts, "%Y-%m-%d %H:%M:%S UTC (", true)); + timestr.append(ConvToStr(ts)); + timestr.push_back(')'); + return timestr; + } + public: CheckContext(User* u, const std::string& targetstr) : user(u) @@ -51,18 +60,28 @@ class CheckContext user->WriteRemoteNumeric(RPL_CHECK, type, text); } + void Write(const std::string& type, time_t ts) + { + user->WriteRemoteNumeric(RPL_CHECK, type, FormatTime(ts)); + } + User* GetUser() const { return user; } - void DumpListMode(const ListModeBase::ModeList* list) + void DumpListMode(ListModeBase* mode, Channel* chan) { + const ListModeBase::ModeList* list = mode->GetList(chan); if (!list) return; - CheckContext::List modelist(*this, "modelist"); for (ListModeBase::ModeList::const_iterator i = list->begin(); i != list->end(); ++i) - modelist.Add(i->mask); - - modelist.Flush(); + { + CheckContext::List listmode(*this, "listmode"); + listmode.Add(ConvToStr(mode->GetModeChar())); + listmode.Add(i->mask); + listmode.Add(i->setter); + listmode.Add(FormatTime(i->time)); + listmode.Flush(); + } } void DumpExt(Extensible* ext) @@ -130,19 +149,9 @@ class CommandCheck : public Command flags_needed = 'o'; syntax = "<nickname>|<ip>|<hostmask>|<channel> <server>"; } - std::string timestring(time_t time) - { - char timebuf[60]; - struct tm *mytime = gmtime(&time); - strftime(timebuf, 59, "%Y-%m-%d %H:%M:%S UTC (", mytime); - std::string ret(timebuf); - ret.append(ConvToStr(time)).push_back(')'); - return ret; - } - CmdResult Handle(User* user, const Params& parameters) override { - if (parameters.size() > 1 && parameters[1] != ServerInstance->Config->ServerName) + if (parameters.size() > 1 && !irc::equals(parameters[1], ServerInstance->Config->ServerName)) return CMD_SUCCESS; User *targuser; @@ -173,15 +182,15 @@ class CommandCheck : public Command context.Write("snomasks", GetSnomasks(targuser)); context.Write("server", targuser->server->GetName()); context.Write("uid", targuser->uuid); - context.Write("signon", timestring(targuser->signon)); - context.Write("nickts", timestring(targuser->age)); + context.Write("signon", targuser->signon); + context.Write("nickts", targuser->age); if (loctarg) - context.Write("lastmsg", timestring(loctarg->idle_lastmsg)); + context.Write("lastmsg", loctarg->idle_lastmsg); if (targuser->IsAway()) { /* user is away */ - context.Write("awaytime", timestring(targuser->awaytime)); + context.Write("awaytime", targuser->awaytime); context.Write("awaymsg", targuser->awaymsg); } @@ -192,16 +201,10 @@ class CommandCheck : public Command context.Write("opertype", oper->name); if (loctarg) { - std::string umodes = GetAllowedOperOnlyModes(loctarg, MODETYPE_USER); - std::string cmodes = GetAllowedOperOnlyModes(loctarg, MODETYPE_CHANNEL); - context.Write("modeperms", "user=" + umodes + " channel=" + cmodes); - - CheckContext::List opcmdlist(context, "commandperms"); - opcmdlist.Add(oper->AllowedOperCommands.ToString()); - opcmdlist.Flush(); - CheckContext::List privlist(context, "permissions"); - privlist.Add(oper->AllowedPrivs.ToString()); - privlist.Flush(); + context.Write("chanmodeperms", GetAllowedOperOnlyModes(loctarg, MODETYPE_CHANNEL)); + context.Write("usermodeperms", GetAllowedOperOnlyModes(loctarg, MODETYPE_USER)); + context.Write("commandperms", oper->AllowedOperCommands.ToString()); + context.Write("permissions", oper->AllowedPrivs.ToString()); } } @@ -237,14 +240,14 @@ class CommandCheck : public Command else if (targchan) { /* /check on a channel */ - context.Write("timestamp", timestring(targchan->age)); + context.Write("createdat", targchan->age); if (!targchan->topic.empty()) { /* there is a topic, assume topic related information exists */ context.Write("topic", targchan->topic); context.Write("topic_setby", targchan->setby); - context.Write("topic_setat", timestring(targchan->topicset)); + context.Write("topic_setat", targchan->topicset); } context.Write("modes", targchan->ChanModes(true)); @@ -261,14 +264,14 @@ class CommandCheck : public Command * Unlike Asuka, I define a clone as coming from the same host. --w00t */ const UserManager::CloneCounts& clonecount = ServerInstance->Users->GetCloneCounts(i->first); - context.Write("member", InspIRCd::Format("%-3u %s%s (%s@%s) %s ", clonecount.global, - i->second->GetAllPrefixChars().c_str(), i->first->nick.c_str(), - i->first->ident.c_str(), i->first->GetDisplayedHost().c_str(), i->first->GetRealName().c_str())); + context.Write("member", InspIRCd::Format("%u %s%s (%s)", clonecount.global, + i->second->GetAllPrefixChars().c_str(), i->first->GetFullHost().c_str(), + i->first->GetRealName().c_str())); } const ModeParser::ListModeList& listmodes = ServerInstance->Modes->GetListModes(); for (ModeParser::ListModeList::const_iterator i = listmodes.begin(); i != listmodes.end(); ++i) - context.DumpListMode((*i)->GetList(targchan)); + context.DumpListMode(*i, targchan); context.DumpExt(targchan); } diff --git a/src/modules/m_cloaking.cpp b/src/modules/m_cloaking.cpp index bf96216c3..01bdce2ca 100644 --- a/src/modules/m_cloaking.cpp +++ b/src/modules/m_cloaking.cpp @@ -210,24 +210,24 @@ class ModuleCloaking : public Module { // The position at which we found the last dot. std::string::const_reverse_iterator dotpos; - + // The number of dots we have seen so far. unsigned int seendots = 0; - + for (std::string::const_reverse_iterator iter = host.rbegin(); iter != host.rend(); ++iter) { if (*iter != '.') continue; - + // We have found a dot! dotpos = iter; seendots += 1; - + // Do we have enough segments to stop? if (seendots >= domainparts) break; } - + // We only returns a domain part if more than one label is // present. See above for a full explanation. if (!seendots) @@ -435,7 +435,7 @@ class ModuleCloaking : public Module else if (stdalgo::string::equalsci(mode, "full")) newcloaks.push_back(CloakInfo(MODE_OPAQUE, key, prefix, suffix)); else - throw ModuleException(mode + " is an invalid value for <cloak:mode>; acceptable values are 'half' and 'full', at " + tag->getTagLocation()); + throw ModuleException(mode + " is an invalid value for <cloak:mode>; acceptable values are 'half' and 'full', at " + tag->getTagLocation()); } // The cloak configuration was valid so we can apply it. diff --git a/src/modules/m_hostchange.cpp b/src/modules/m_hostchange.cpp index b676e19a7..7b53a53d7 100644 --- a/src/modules/m_hostchange.cpp +++ b/src/modules/m_hostchange.cpp @@ -34,7 +34,7 @@ class HostRule // Add the user's nickname to their hostname. HCA_ADDNICK, - // Set the user's hostname to the specific value. + // Set the user's hostname to the specific value. HCA_SET }; @@ -168,7 +168,7 @@ private: } else { - throw ModuleException(action + " is an invalid <hostchange:action> type, at " + tag->getTagLocation()); + throw ModuleException(action + " is an invalid <hostchange:action> type, at " + tag->getTagLocation()); } } diff --git a/src/modules/m_httpd_stats.cpp b/src/modules/m_httpd_stats.cpp index 927e6c906..7442587da 100644 --- a/src/modules/m_httpd_stats.cpp +++ b/src/modules/m_httpd_stats.cpp @@ -25,34 +25,41 @@ #include "modules/httpd.h" #include "xline.h" -class ModuleHttpStats : public Module, public HTTPRequestEventListener +namespace Stats { - static const insp::flat_map<char, char const*>& entities; - HTTPdAPI API; + struct Entities + { + static const insp::flat_map<char, char const*>& entities; + }; - public: - ModuleHttpStats() - : HTTPRequestEventListener(this) - , API(this) + static const insp::flat_map<char, char const*>& init_entities() { + static insp::flat_map<char, char const*> entities; + entities['<'] = "lt"; + entities['>'] = "gt"; + entities['&'] = "amp"; + entities['"'] = "quot"; + return entities; } - std::string Sanitize(const std::string &str) + const insp::flat_map<char, char const*>& Entities::entities = init_entities(); + + std::string Sanitize(const std::string& str) { std::string ret; ret.reserve(str.length() * 2); for (std::string::const_iterator x = str.begin(); x != str.end(); ++x) { - insp::flat_map<char, char const*>::const_iterator it = entities.find(*x); + insp::flat_map<char, char const*>::const_iterator it = Entities::entities.find(*x); - if (it != entities.end()) + if (it != Entities::entities.end()) { ret += '&'; ret += it->second; ret += ';'; } - else if (*x == 0x09 || *x == 0x0A || *x == 0x0D || ((*x >= 0x20) && (*x <= 0x7e))) + else if (*x == 0x09 || *x == 0x0A || *x == 0x0D || ((*x >= 0x20) && (*x <= 0x7e))) { // The XML specification defines the following characters as valid inside an XML document: // Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] @@ -73,10 +80,10 @@ class ModuleHttpStats : public Module, public HTTPRequestEventListener return ret; } - void DumpMeta(std::stringstream& data, Extensible* ext) + void DumpMeta(std::ostream& data, Extensible* ext) { data << "<metadata>"; - for(Extensible::ExtensibleStore::const_iterator i = ext->GetExtList().begin(); i != ext->GetExtList().end(); i++) + for (Extensible::ExtensibleStore::const_iterator i = ext->GetExtList().begin(); i != ext->GetExtList().end(); i++) { ExtensionItem* item = i->first; std::string value = item->serialize(FORMAT_USER, ext, i->second); @@ -88,156 +95,241 @@ class ModuleHttpStats : public Module, public HTTPRequestEventListener data << "</metadata>"; } - ModResult HandleRequest(HTTPRequest* http) + std::ostream& ServerInfo(std::ostream& data) { - std::stringstream data(""); + return data << "<server><name>" << ServerInstance->Config->ServerName << "</name><description>" + << Sanitize(ServerInstance->Config->ServerDesc) << "</description><version>" + << Sanitize(ServerInstance->GetVersionString()) << "</version></server>"; + } + std::ostream& ISupport(std::ostream& data) + { + data << "<isupport>"; + const std::vector<Numeric::Numeric>& isupport = ServerInstance->ISupport.GetLines(); + for (std::vector<Numeric::Numeric>::const_iterator i = isupport.begin(); i != isupport.end(); ++i) { - ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Handling httpd event"); + const Numeric::Numeric& num = *i; + for (std::vector<std::string>::const_iterator j = num.GetParams().begin(); j != num.GetParams().end() - 1; ++j) + data << "<token>" << Sanitize(*j) << "</token>"; + } + return data << "</isupport>"; + } - if ((http->GetURI() == "/stats") || (http->GetURI() == "/stats/")) - { - data << "<inspircdstats><server><name>" << ServerInstance->Config->ServerName << "</name><description>" - << Sanitize(ServerInstance->Config->ServerDesc) << "</description><version>" - << Sanitize(ServerInstance->GetVersionString()) << "</version></server>"; + std::ostream& General(std::ostream& data) + { + data << "<general>"; + data << "<usercount>" << ServerInstance->Users->GetUsers().size() << "</usercount>"; + data << "<localusercount>" << ServerInstance->Users->GetLocalUsers().size() << "</localusercount>"; + data << "<channelcount>" << ServerInstance->GetChans().size() << "</channelcount>"; + data << "<opercount>" << ServerInstance->Users->all_opers.size() << "</opercount>"; + data << "<socketcount>" << (SocketEngine::GetUsedFds()) << "</socketcount><socketmax>" << SocketEngine::GetMaxFds() << "</socketmax>"; + data << "<uptime><boot_time_t>" << ServerInstance->startup_time << "</boot_time_t></uptime>"; - data << "<general>"; - data << "<usercount>" << ServerInstance->Users->GetUsers().size() << "</usercount>"; - data << "<channelcount>" << ServerInstance->GetChans().size() << "</channelcount>"; - data << "<opercount>" << ServerInstance->Users->all_opers.size() << "</opercount>"; - data << "<socketcount>" << (SocketEngine::GetUsedFds()) << "</socketcount><socketmax>" << SocketEngine::GetMaxFds() << "</socketmax>"; - data << "<uptime><boot_time_t>" << ServerInstance->startup_time << "</boot_time_t></uptime>"; + data << ISupport; + return data << "</general>"; + } - data << "<isupport>"; - const std::vector<Numeric::Numeric>& isupport = ServerInstance->ISupport.GetLines(); - for (std::vector<Numeric::Numeric>::const_iterator i = isupport.begin(); i != isupport.end(); ++i) - { - const Numeric::Numeric& num = *i; - for (std::vector<std::string>::const_iterator j = num.GetParams().begin(); j != num.GetParams().end()-1; ++j) - data << "<token>" << Sanitize(*j) << "</token>" << std::endl; - } - data << "</isupport></general><xlines>"; - std::vector<std::string> xltypes = ServerInstance->XLines->GetAllTypes(); - for (std::vector<std::string>::iterator it = xltypes.begin(); it != xltypes.end(); ++it) - { - XLineLookup* lookup = ServerInstance->XLines->GetAll(*it); + std::ostream& XLines(std::ostream& data) + { + data << "<xlines>"; + std::vector<std::string> xltypes = ServerInstance->XLines->GetAllTypes(); + for (std::vector<std::string>::iterator it = xltypes.begin(); it != xltypes.end(); ++it) + { + XLineLookup* lookup = ServerInstance->XLines->GetAll(*it); - if (!lookup) - continue; - for (LookupIter i = lookup->begin(); i != lookup->end(); ++i) - { - data << "<xline type=\"" << it->c_str() << "\"><mask>" - << Sanitize(i->second->Displayable()) << "</mask><settime>" - << i->second->set_time << "</settime><duration>" << i->second->duration - << "</duration><reason>" << Sanitize(i->second->reason) - << "</reason></xline>"; - } - } + if (!lookup) + continue; + for (LookupIter i = lookup->begin(); i != lookup->end(); ++i) + { + data << "<xline type=\"" << it->c_str() << "\"><mask>" + << Sanitize(i->second->Displayable()) << "</mask><settime>" + << i->second->set_time << "</settime><duration>" << i->second->duration + << "</duration><reason>" << Sanitize(i->second->reason) + << "</reason></xline>"; + } + } + return data << "</xlines>"; + } + + std::ostream& Modules(std::ostream& data) + { + data << "<modulelist>"; + const ModuleManager::ModuleMap& mods = ServerInstance->Modules->GetModules(); - data << "</xlines><modulelist>"; - const ModuleManager::ModuleMap& mods = ServerInstance->Modules->GetModules(); + for (ModuleManager::ModuleMap::const_iterator i = mods.begin(); i != mods.end(); ++i) + { + Version v = i->second->GetVersion(); + data << "<module><name>" << i->first << "</name><description>" << Sanitize(v.description) << "</description></module>"; + } + return data << "</modulelist>"; + } - for (ModuleManager::ModuleMap::const_iterator i = mods.begin(); i != mods.end(); ++i) - { - Version v = i->second->GetVersion(); - data << "<module><name>" << i->first << "</name><description>" << Sanitize(v.description) << "</description></module>"; - } - data << "</modulelist><channellist>"; + std::ostream& Channels(std::ostream& data) + { + data << "<channellist>"; - const chan_hash& chans = ServerInstance->GetChans(); - for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ++i) - { - Channel* c = i->second; + const chan_hash& chans = ServerInstance->GetChans(); + for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ++i) + { + Channel* c = i->second; - data << "<channel>"; - data << "<usercount>" << c->GetUsers().size() << "</usercount><channelname>" << Sanitize(c->name) << "</channelname>"; - data << "<channeltopic>"; - data << "<topictext>" << Sanitize(c->topic) << "</topictext>"; - data << "<setby>" << Sanitize(c->setby) << "</setby>"; - data << "<settime>" << c->topicset << "</settime>"; - data << "</channeltopic>"; - data << "<channelmodes>" << Sanitize(c->ChanModes(true)) << "</channelmodes>"; + data << "<channel>"; + data << "<usercount>" << c->GetUsers().size() << "</usercount><channelname>" << Sanitize(c->name) << "</channelname>"; + data << "<channeltopic>"; + data << "<topictext>" << Sanitize(c->topic) << "</topictext>"; + data << "<setby>" << Sanitize(c->setby) << "</setby>"; + data << "<settime>" << c->topicset << "</settime>"; + data << "</channeltopic>"; + data << "<channelmodes>" << Sanitize(c->ChanModes(true)) << "</channelmodes>"; - const Channel::MemberMap& ulist = c->GetUsers(); - for (Channel::MemberMap::const_iterator x = ulist.begin(); x != ulist.end(); ++x) - { - Membership* memb = x->second; - data << "<channelmember><uid>" << memb->user->uuid << "</uid><privs>" - << Sanitize(memb->GetAllPrefixChars()) << "</privs><modes>" - << memb->modes << "</modes>"; - DumpMeta(data, memb); - data << "</channelmember>"; - } + const Channel::MemberMap& ulist = c->GetUsers(); + for (Channel::MemberMap::const_iterator x = ulist.begin(); x != ulist.end(); ++x) + { + Membership* memb = x->second; + data << "<channelmember><uid>" << memb->user->uuid << "</uid><privs>" + << Sanitize(memb->GetAllPrefixChars()) << "</privs><modes>" + << memb->modes << "</modes>"; + DumpMeta(data, memb); + data << "</channelmember>"; + } - DumpMeta(data, c); + DumpMeta(data, c); - data << "</channel>"; - } + data << "</channel>"; + } - data << "</channellist><userlist>"; + return data << "</channellist>"; + } - const user_hash& users = ServerInstance->Users->GetUsers(); - for (user_hash::const_iterator i = users.begin(); i != users.end(); ++i) - { - User* u = i->second; + std::ostream& Users(std::ostream& data) + { + data << "<userlist>"; + const user_hash& users = ServerInstance->Users->GetUsers(); + for (user_hash::const_iterator i = users.begin(); i != users.end(); ++i) + { + User* u = i->second; - data << "<user>"; - data << "<nickname>" << u->nick << "</nickname><uuid>" << u->uuid << "</uuid><realhost>" - << u->GetRealHost() << "</realhost><displayhost>" << u->GetDisplayedHost() << "</displayhost><realname>" - << Sanitize(u->GetRealName()) << "</realname><server>" << u->server->GetName() << "</server>"; - if (u->IsAway()) - data << "<away>" << Sanitize(u->awaymsg) << "</away><awaytime>" << u->awaytime << "</awaytime>"; - if (u->IsOper()) - data << "<opertype>" << Sanitize(u->oper->name) << "</opertype>"; - data << "<modes>" << u->GetModeLetters().substr(1) << "</modes><ident>" << Sanitize(u->ident) << "</ident>"; - LocalUser* lu = IS_LOCAL(u); - if (lu) - data << "<port>" << lu->GetServerPort() << "</port><servaddr>" - << lu->server_sa.str() << "</servaddr>"; - data << "<ipaddress>" << u->GetIPString() << "</ipaddress>"; + data << "<user>"; + data << "<nickname>" << u->nick << "</nickname><uuid>" << u->uuid << "</uuid><realhost>" + << u->GetRealHost() << "</realhost><displayhost>" << u->GetDisplayedHost() << "</displayhost><realname>" + << Sanitize(u->GetRealName()) << "</realname><server>" << u->server->GetName() << "</server>"; + if (u->IsAway()) + data << "<away>" << Sanitize(u->awaymsg) << "</away><awaytime>" << u->awaytime << "</awaytime>"; + if (u->IsOper()) + data << "<opertype>" << Sanitize(u->oper->name) << "</opertype>"; + data << "<modes>" << u->GetModeLetters().substr(1) << "</modes><ident>" << Sanitize(u->ident) << "</ident>"; + LocalUser* lu = IS_LOCAL(u); + if (lu) + data << "<port>" << lu->GetServerPort() << "</port><servaddr>" + << lu->server_sa.str() << "</servaddr>"; + data << "<ipaddress>" << u->GetIPString() << "</ipaddress>"; - DumpMeta(data, u); + DumpMeta(data, u); - data << "</user>"; - } + data << "</user>"; + } + return data << "</userlist>"; + } - data << "</userlist><serverlist>"; + std::ostream& Servers(std::ostream& data) + { + data << "<serverlist>"; - ProtocolInterface::ServerList sl; - ServerInstance->PI->GetServerList(sl); + ProtocolInterface::ServerList sl; + ServerInstance->PI->GetServerList(sl); - for (ProtocolInterface::ServerList::const_iterator b = sl.begin(); b != sl.end(); ++b) - { - data << "<server>"; - data << "<servername>" << b->servername << "</servername>"; - data << "<parentname>" << b->parentname << "</parentname>"; - data << "<description>" << Sanitize(b->description) << "</description>"; - data << "<usercount>" << b->usercount << "</usercount>"; + for (ProtocolInterface::ServerList::const_iterator b = sl.begin(); b != sl.end(); ++b) + { + data << "<server>"; + data << "<servername>" << b->servername << "</servername>"; + data << "<parentname>" << b->parentname << "</parentname>"; + data << "<description>" << Sanitize(b->description) << "</description>"; + data << "<usercount>" << b->usercount << "</usercount>"; // This is currently not implemented, so, commented out. // data << "<opercount>" << b->opercount << "</opercount>"; - data << "<lagmillisecs>" << b->latencyms << "</lagmillisecs>"; - data << "</server>"; - } + data << "<lagmillisecs>" << b->latencyms << "</lagmillisecs>"; + data << "</server>"; + } + + return data << "</serverlist>"; + } - data << "</serverlist><commandlist>"; + std::ostream& Commands(std::ostream& data) + { + data << "<commandlist>"; - const CommandParser::CommandMap& commands = ServerInstance->Parser.GetCommands(); - for (CommandParser::CommandMap::const_iterator i = commands.begin(); i != commands.end(); ++i) - { - data << "<command><name>" << i->second->name << "</name><usecount>" << i->second->use_count << "</usecount></command>"; - } + const CommandParser::CommandMap& commands = ServerInstance->Parser.GetCommands(); + for (CommandParser::CommandMap::const_iterator i = commands.begin(); i != commands.end(); ++i) + { + data << "<command><name>" << i->second->name << "</name><usecount>" << i->second->use_count << "</usecount></command>"; + } + return data << "</commandlist>"; + } +} - data << "</commandlist></inspircdstats>"; +class ModuleHttpStats : public Module, public HTTPRequestEventListener +{ + HTTPdAPI API; - /* Send the document back to m_httpd */ - HTTPDocumentResponse response(this, *http, &data, 200); - response.headers.SetHeader("X-Powered-By", MODNAME); - response.headers.SetHeader("Content-Type", "text/xml"); - API->SendResponse(response); - return MOD_RES_DENY; // Handled - } + public: + ModuleHttpStats() + : HTTPRequestEventListener(this) + , API(this) + { + } + + ModResult HandleRequest(HTTPRequest* http) + { + std::string uri = http->GetURI(); + + if (uri != "/stats" && uri.substr(0, 7) != "/stats/") + return MOD_RES_PASSTHRU; + + if (uri[uri.size() - 1] == '/') + uri.erase(uri.size() - 1, 1); + + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Handling httpd event"); + + bool found = true; + std::stringstream data; + data << "<inspircdstats>"; + + if (uri == "/stats") + { + data << Stats::ServerInfo << Stats::General + << Stats::XLines << Stats::Modules + << Stats::Channels << Stats::Users + << Stats::Servers << Stats::Commands; + } + else if (uri == "/stats/general") + { + data << Stats::General; + } + else if (uri == "/stats/users") + { + data << Stats::Users; + } + else + { + found = false; } - return MOD_RES_PASSTHRU; + + if (found) + { + data << "</inspircdstats>"; + } + else + { + data.clear(); + data.str(std::string()); + } + + /* Send the document back to m_httpd */ + HTTPDocumentResponse response(this, *http, &data, found ? 200 : 404); + response.headers.SetHeader("X-Powered-By", MODNAME); + response.headers.SetHeader("Content-Type", "text/xml"); + API->SendResponse(response); + return MOD_RES_DENY; // Handled } ModResult OnHTTPRequest(HTTPRequest& req) override @@ -251,16 +343,4 @@ class ModuleHttpStats : public Module, public HTTPRequestEventListener } }; -static const insp::flat_map<char, char const*>& init_entities() -{ - static insp::flat_map<char, char const*> entities; - entities['<'] = "lt"; - entities['>'] = "gt"; - entities['&'] = "amp"; - entities['"'] = "quot"; - return entities; -} - -const insp::flat_map<char, char const*>& ModuleHttpStats::entities = init_entities(); - MODULE_INIT(ModuleHttpStats) diff --git a/src/modules/m_ident.cpp b/src/modules/m_ident.cpp index dec07ce73..96aa7ef26 100644 --- a/src/modules/m_ident.cpp +++ b/src/modules/m_ident.cpp @@ -24,6 +24,24 @@ #include "inspircd.h" +enum +{ + // Either the ident looup has not started yet or the user is registered. + IDENT_UNKNOWN = 0, + + // Ident lookups are not enabled and a user has been marked as being skipped. + IDENT_SKIPPED, + + // Ident looups are not enabled and a user has been an insecure ident prefix. + IDENT_PREFIXED, + + // An ident lookup was done and an ident was found. + IDENT_FOUND, + + // An ident lookup was done but no ident was found + IDENT_MISSING +}; + /* -------------------------------------------------------------- * Note that this is the third incarnation of m_ident. The first * two attempts were pretty crashy, mainly due to the fact we tried @@ -254,12 +272,34 @@ class IdentRequestSocket : public EventHandler class ModuleIdent : public Module { - int RequestTimeout; - bool NoLookupPrefix; - SimpleExtItem<IdentRequestSocket, stdalgo::culldeleter> ext; + private: + unsigned int timeout; + bool prefixunqueried; + SimpleExtItem<IdentRequestSocket, stdalgo::culldeleter> socket; + LocalIntExt state; + + static void PrefixIdent(LocalUser* user) + { + // Check that they haven't been prefixed already. + if (user->ident[0] == '~') + return; + + // All invalid usernames are prefixed with a tilde. + std::string newident(user->ident); + newident.insert(newident.begin(), '~'); + + // If the username is too long then truncate it. + if (newident.length() > ServerInstance->Config->Limits.IdentMax) + newident.erase(ServerInstance->Config->Limits.IdentMax); + + // Apply the new username. + user->ChangeIdent(newident); + } + public: ModuleIdent() - : ext("ident_socket", ExtensionItem::EXT_USER, this) + : socket("ident_socket", ExtensionItem::EXT_USER, this) + , state("ident_state", ExtensionItem::EXT_USER, this) { } @@ -271,18 +311,18 @@ class ModuleIdent : public Module void ReadConfig(ConfigStatus& status) override { ConfigTag* tag = ServerInstance->Config->ConfValue("ident"); - RequestTimeout = tag->getDuration("timeout", 5, 1); - NoLookupPrefix = tag->getBool("nolookupprefix", false); + timeout = tag->getDuration("timeout", 5, 1, 60); + prefixunqueried = tag->getBool("prefixunqueried"); } void OnSetUserIP(LocalUser* user) override { - IdentRequestSocket* isock = ext.get(user); + IdentRequestSocket* isock = socket.get(user); if (isock) { // If an ident lookup request was in progress then cancel it. isock->Close(); - ext.unset(user); + socket.unset(user); } // The ident protocol requires that clients are connecting over a protocol with ports. @@ -295,14 +335,17 @@ class ModuleIdent : public Module ConfigTag* tag = user->MyClass->config; if (!tag->getBool("useident", true)) + { + state.set(user, IDENT_SKIPPED); return; + } user->WriteNotice("*** Looking up your ident..."); try { isock = new IdentRequestSocket(user); - ext.set(user, isock); + socket.set(user, isock); } catch (ModuleException &e) { @@ -317,22 +360,26 @@ class ModuleIdent : public Module ModResult OnCheckReady(LocalUser *user) override { /* Does user have an ident socket attached at all? */ - IdentRequestSocket *isock = ext.get(user); + IdentRequestSocket* isock = socket.get(user); if (!isock) { - if ((NoLookupPrefix) && (user->ident[0] != '~')) - user->ident.insert(user->ident.begin(), 1, '~'); + if (prefixunqueried && state.get(user) == IDENT_SKIPPED) + { + PrefixIdent(user); + state.set(user, IDENT_PREFIXED); + } return MOD_RES_PASSTHRU; } - time_t compare = isock->age; - compare += RequestTimeout; + time_t compare = isock->age + timeout; /* Check for timeout of the socket */ if (ServerInstance->Time() >= compare) { /* Ident timeout */ - user->WriteNotice("*** Ident request timed out."); + state.set(user, IDENT_MISSING); + PrefixIdent(user); + user->WriteNotice("*** Ident lookup timed out, using " + user->ident + " instead."); } else if (!isock->HasResult()) { @@ -341,29 +388,36 @@ class ModuleIdent : public Module } /* wooo, got a result (it will be good, or bad) */ - if (isock->result.empty()) + else if (isock->result.empty()) { - user->ident.insert(user->ident.begin(), 1, '~'); + state.set(user, IDENT_MISSING); + PrefixIdent(user); user->WriteNotice("*** Could not find your ident, using " + user->ident + " instead."); } else { - user->ident = isock->result; + state.set(user, IDENT_FOUND); + user->ChangeIdent(isock->result); user->WriteNotice("*** Found your ident, '" + user->ident + "'"); } - user->InvalidateCache(); isock->Close(); - ext.unset(user); + socket.unset(user); return MOD_RES_PASSTHRU; } ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) override { - if (myclass->config->getBool("requireident") && user->ident[0] == '~') + if (myclass->config->getBool("requireident") && state.get(user) != IDENT_FOUND) return MOD_RES_DENY; return MOD_RES_PASSTHRU; } + + void OnUserConnect(LocalUser* user) override + { + // Clear this as it is no longer necessary. + state.unset(user); + } }; MODULE_INIT(ModuleIdent) diff --git a/src/modules/m_ircv3_sts.cpp b/src/modules/m_ircv3_sts.cpp index 0a83c6e0b..226bdb3ac 100644 --- a/src/modules/m_ircv3_sts.cpp +++ b/src/modules/m_ircv3_sts.cpp @@ -130,7 +130,7 @@ class ModuleIRCv3STS : public Module for (std::vector<ListenSocket*>::const_iterator iter = ServerInstance->ports.begin(); iter != ServerInstance->ports.end(); ++iter) { ListenSocket* ls = *iter; - + // Is this listener on the right port? unsigned int saport = ls->bind_sa.port(); if (saport != port) diff --git a/src/modules/m_muteban.cpp b/src/modules/m_muteban.cpp index 97104f0c5..06b55d2cb 100644 --- a/src/modules/m_muteban.cpp +++ b/src/modules/m_muteban.cpp @@ -22,7 +22,16 @@ class ModuleQuietBan : public Module { + private: + bool notifyuser; + public: + void ReadConfig(ConfigStatus& status) override + { + ConfigTag* tag = ServerInstance->Config->ConfValue("muteban"); + notifyuser = tag->getBool("notifyuser", true); + } + Version GetVersion() override { return Version("Implements extban +b m: - mute bans",VF_OPTCOMMON|VF_VENDOR); @@ -36,7 +45,6 @@ class ModuleQuietBan : public Module Channel* chan = target.Get<Channel>(); if (chan->GetExtBanStatus(user, 'm') == MOD_RES_DENY && chan->GetPrefixValue(user) < VOICE_VALUE) { - bool notifyuser = ServerInstance->Config->ConfValue("muteban")->getBool("notifyuser", true); if (!notifyuser) { details.echo_original = true; diff --git a/src/modules/m_opermotd.cpp b/src/modules/m_opermotd.cpp index f277d8f6a..b62b6a01f 100644 --- a/src/modules/m_opermotd.cpp +++ b/src/modules/m_opermotd.cpp @@ -36,7 +36,7 @@ class CommandOpermotd : public Command CmdResult Handle(User* user, const Params& parameters) override { - if ((parameters.empty()) || (parameters[0] == ServerInstance->Config->ServerName)) + if ((parameters.empty()) || (irc::equals(parameters[0], ServerInstance->Config->ServerName))) ShowOperMOTD(user); return CMD_SUCCESS; } diff --git a/src/modules/m_rline.cpp b/src/modules/m_rline.cpp index 23093ae3c..248b3ec0d 100644 --- a/src/modules/m_rline.cpp +++ b/src/modules/m_rline.cpp @@ -190,9 +190,11 @@ class CommandRLine : public Command } else { - if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "R", user)) + std::string reason; + + if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "R", reason, user)) { - ServerInstance->SNO->WriteToSnoMask('x',"%s removed R-line on %s",user->nick.c_str(),parameters[0].c_str()); + ServerInstance->SNO->WriteToSnoMask('x', "%s removed R-line on %s: %s", user->nick.c_str(), parameters[0].c_str(), reason.c_str()); } else { diff --git a/src/modules/m_samode.cpp b/src/modules/m_samode.cpp index 564864b31..45dd37e8c 100644 --- a/src/modules/m_samode.cpp +++ b/src/modules/m_samode.cpp @@ -124,8 +124,8 @@ class ModuleSaMode : public Module void Prioritize() override { - Module* disabled = ServerInstance->Modules->Find("m_disabled.so"); - ServerInstance->Modules->SetPriority(this, I_OnRawMode, PRIORITY_BEFORE, disabled); + Module* disable = ServerInstance->Modules->Find("m_disable.so"); + ServerInstance->Modules->SetPriority(this, I_OnRawMode, PRIORITY_BEFORE, disable); Module *override = ServerInstance->Modules->Find("m_override.so"); ServerInstance->Modules->SetPriority(this, I_OnPreMode, PRIORITY_BEFORE, override); diff --git a/src/modules/m_setname.cpp b/src/modules/m_setname.cpp index 17a8669e3..9f9db7f79 100644 --- a/src/modules/m_setname.cpp +++ b/src/modules/m_setname.cpp @@ -26,6 +26,7 @@ class CommandSetname : public Command { public: + bool notifyopers; CommandSetname(Module* Creator) : Command(Creator,"SETNAME", 1, 1) { allow_empty_last_param = false; @@ -42,7 +43,9 @@ class CommandSetname : public Command if (user->ChangeRealName(parameters[0])) { - ServerInstance->SNO->WriteGlobalSno('a', "%s used SETNAME to change their real name to '%s'", user->nick.c_str(), parameters[0].c_str()); + if (notifyopers) + ServerInstance->SNO->WriteGlobalSno('a', "%s used SETNAME to change their real name to '%s'", + user->nick.c_str(), parameters[0].c_str()); } return CMD_SUCCESS; @@ -59,6 +62,18 @@ class ModuleSetName : public Module { } + void ReadConfig(ConfigStatus& status) override + { + ConfigTag* tag = ServerInstance->Config->ConfValue("setname"); + + // Whether the module should only be usable by server operators. + bool operonly = tag->getBool("operonly"); + cmd.flags_needed = operonly ? 'o' : 0; + + // Whether a snotice should be sent out when a user changes their real name. + cmd.notifyopers = tag->getBool("notifyopers", !operonly); + } + Version GetVersion() override { return Version("Provides support for the SETNAME command", VF_VENDOR); diff --git a/src/modules/m_showwhois.cpp b/src/modules/m_showwhois.cpp index 58109a67d..ef300cc53 100644 --- a/src/modules/m_showwhois.cpp +++ b/src/modules/m_showwhois.cpp @@ -51,7 +51,7 @@ class WhoisNoticeCmd : public Command void HandleFast(User* dest, User* src) { dest->WriteNotice("*** " + src->nick + " (" + src->ident + "@" + - src->GetHost(dest->HasPrivPermission("users/auspex")) + + src->GetHost(dest->HasPrivPermission("users/auspex")) + ") did a /whois on you"); } diff --git a/src/modules/m_shun.cpp b/src/modules/m_shun.cpp index eff3557f0..f3117392f 100644 --- a/src/modules/m_shun.cpp +++ b/src/modules/m_shun.cpp @@ -69,13 +69,15 @@ class CommandShun : public Command if (parameters.size() == 1) { - if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "SHUN", user)) + std::string reason; + + if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "SHUN", reason, user)) { - ServerInstance->SNO->WriteToSnoMask('x', "%s removed SHUN on %s", user->nick.c_str(), parameters[0].c_str()); + ServerInstance->SNO->WriteToSnoMask('x', "%s removed SHUN on %s: %s", user->nick.c_str(), parameters[0].c_str(), reason.c_str()); } - else if (ServerInstance->XLines->DelLine(target.c_str(), "SHUN", user)) + else if (ServerInstance->XLines->DelLine(target.c_str(), "SHUN", reason, user)) { - ServerInstance->SNO->WriteToSnoMask('x',"%s removed SHUN on %s", user->nick.c_str(), target.c_str()); + ServerInstance->SNO->WriteToSnoMask('x', "%s removed SHUN on %s: %s", user->nick.c_str(), target.c_str(), reason.c_str()); } else { diff --git a/src/modules/m_spanningtree/delline.cpp b/src/modules/m_spanningtree/delline.cpp index c64bec654..e376147fd 100644 --- a/src/modules/m_spanningtree/delline.cpp +++ b/src/modules/m_spanningtree/delline.cpp @@ -25,12 +25,13 @@ CmdResult CommandDelLine::Handle(User* user, Params& params) { const std::string& setter = user->nick; + std::string reason; // XLineManager::DelLine() returns true if the xline existed, false if it didn't - if (ServerInstance->XLines->DelLine(params[1].c_str(), params[0], user)) + if (ServerInstance->XLines->DelLine(params[1].c_str(), params[0], reason, user)) { - ServerInstance->SNO->WriteToSnoMask('X',"%s removed %s%s on %s", setter.c_str(), - params[0].c_str(), params[0].length() == 1 ? "-line" : "", params[1].c_str()); + ServerInstance->SNO->WriteToSnoMask('X', "%s removed %s%s on %s: %s", setter.c_str(), + params[0].c_str(), params[0].length() == 1 ? "-line" : "", params[1].c_str(), reason.c_str()); return CMD_SUCCESS; } return CMD_FAILURE; diff --git a/src/modules/m_spanningtree/uid.cpp b/src/modules/m_spanningtree/uid.cpp index 01af56fa6..0729065fc 100644 --- a/src/modules/m_spanningtree/uid.cpp +++ b/src/modules/m_spanningtree/uid.cpp @@ -134,7 +134,7 @@ CmdResult CommandUID::HandleServer(TreeServer* remoteserver, CommandBase::Params } CmdResult CommandFHost::HandleRemote(RemoteUser* src, Params& params) -{ +{ src->ChangeDisplayedHost(params[0]); return CMD_SUCCESS; } diff --git a/src/modules/m_sslinfo.cpp b/src/modules/m_sslinfo.cpp index 2266b6861..7e08c8a3d 100644 --- a/src/modules/m_sslinfo.cpp +++ b/src/modules/m_sslinfo.cpp @@ -188,6 +188,11 @@ class ModuleSSLInfo private: CommandSSLInfo cmd; + bool MatchFP(ssl_cert* const cert, const std::string& fp) const + { + return irc::spacesepstream(fp).Contains(cert->GetFingerprint()); + } + public: ModuleSSLInfo() : WebIRC::EventListener(this) @@ -231,7 +236,7 @@ class ModuleSSLInfo } std::string fingerprint; - if (ifo->oper_block->readString("fingerprint", fingerprint) && (!cert || cert->GetFingerprint() != fingerprint)) + if (ifo->oper_block->readString("fingerprint", fingerprint) && (!cert || !MatchFP(cert, fingerprint))) { user->WriteNumeric(ERR_NOOPERHOST, "This oper login requires a matching SSL certificate fingerprint."); user->CommandFloodPenalty += 10000; @@ -251,7 +256,7 @@ class ModuleSSLInfo return; const SSLIOHook* const ssliohook = SSLIOHook::IsSSL(&localuser->eh); - if (!ssliohook) + if (!ssliohook || cmd.sslapi.nosslext.get(localuser)) return; ssl_cert* const cert = ssliohook->GetCertificate(); @@ -275,7 +280,7 @@ class ModuleSSLInfo { OperInfo* ifo = i->second; std::string fp = ifo->oper_block->getString("fingerprint"); - if (fp == cert->fingerprint && ifo->oper_block->getBool("autologin")) + if (MatchFP(cert, fp) && ifo->oper_block->getBool("autologin")) user->Oper(ifo); } } diff --git a/src/modules/m_svshold.cpp b/src/modules/m_svshold.cpp index ede845fd8..ca8f30d0b 100644 --- a/src/modules/m_svshold.cpp +++ b/src/modules/m_svshold.cpp @@ -112,10 +112,12 @@ class CommandSvshold : public Command if (parameters.size() == 1) { - if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "SVSHOLD", user)) + std::string reason; + + if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "SVSHOLD", reason, user)) { if (!silent) - ServerInstance->SNO->WriteToSnoMask('x',"%s removed SVSHOLD on %s",user->nick.c_str(),parameters[0].c_str()); + ServerInstance->SNO->WriteToSnoMask('x', "%s removed SVSHOLD on %s: %s", user->nick.c_str(), parameters[0].c_str(), reason.c_str()); } else { |
