diff --git a/docs/conf/inspircd.conf.example b/docs/conf/inspircd.conf.example index 9512e17c44..b63ef83bd9 100644 --- a/docs/conf/inspircd.conf.example +++ b/docs/conf/inspircd.conf.example @@ -277,6 +277,9 @@ # useident: Defines if users in this class MUST respond to a ident query or not. useident="no" + # forceident: Defines the ident which all users in this class will get + forceident="" + # limit: How many users are allowed in this class limit="5000" diff --git a/src/modules/m_bridgechan.cpp b/src/modules/m_bridgechan.cpp new file mode 100644 index 0000000000..6b9ca5ab58 --- /dev/null +++ b/src/modules/m_bridgechan.cpp @@ -0,0 +1,29 @@ +#include "inspircd.h" + +class BridgeChannel : public Module +{ + public: + + void init() + { + ServerInstance->Modules->Attach(I_OnUserPreJoin, this); + } + + virtual ModResult OnUserPreJoin(User *user, Channel *chan, const char *cname, std::string &privs, const std::string &keygiven) + { + if ( cname[ 1 ] == '^' ) + { + user->WriteNumeric( 384, "%s :Cannot join channel, reserved for bridges", cname ); + ServerInstance->SNO->WriteGlobalSno( 'a', "%s tried to join bridge channel %s", user->nick.c_str(), cname ); + return MOD_RES_DENY; + } + return MOD_RES_PASSTHRU; + } + + Version GetVersion() + { + return Version( "Prevents clients from creating channels starting with ^" ); + } +}; + +MODULE_INIT(BridgeChannel) diff --git a/src/modules/m_cgiirc.cpp b/src/modules/m_cgiirc.cpp index ccbaaae320..c792fc9e93 100644 --- a/src/modules/m_cgiirc.cpp +++ b/src/modules/m_cgiirc.cpp @@ -30,6 +30,14 @@ enum CGItype { PASS, IDENT, PASSFIRST, IDENTFIRST, WEBIRC }; +// We need this method up here so that it can be acessed from anywhere +static void ChangeIP(User* user, const std::string& newip) +{ + ServerInstance->Users->RemoveCloneCounts(user); + user->SetClientIP(newip.c_str()); + ServerInstance->Users->AddLocalClone(user); + ServerInstance->Users->AddGlobalClone(user); +} /** Holds a CGI site's details */ @@ -62,16 +70,10 @@ class CommandWebirc : public Command { public: bool notify; - StringExtItem realhost; - StringExtItem realip; - LocalStringExt webirc_hostname; - LocalStringExt webirc_ip; CGIHostlist Hosts; CommandWebirc(Module* Creator) - : Command(Creator, "WEBIRC", 4), - realhost("cgiirc_realhost", Creator), realip("cgiirc_realip", Creator), - webirc_hostname("cgiirc_webirc_hostname", Creator), webirc_ip("cgiirc_webirc_ip", Creator) + : Command(Creator, "WEBIRC", 4) { works_before_reg = true; this->syntax = "password client hostname ip"; @@ -87,28 +89,25 @@ class CommandWebirc : public Command { if(iter->type == WEBIRC && parameters[0] == iter->password) { - realhost.set(user, user->host); - realip.set(user, user->GetIPString()); + // TODO: Why do we have a 64 char check here, maybe we should handle this globally bool host_ok = (parameters[2].length() < 64); const std::string& newhost = (host_ok ? parameters[2] : parameters[3]); if (notify) - ServerInstance->SNO->WriteGlobalSno('a', "Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from %s", user->nick.c_str(), user->host.c_str(), newhost.c_str(), user->host.c_str()); + ServerInstance->SNO->WriteGlobalSno('w', "Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from %s", user->nick.c_str(), user->host.c_str(), newhost.c_str(), user->host.c_str()); - // Check if we're happy with the provided hostname. If it's problematic then make sure we won't set a host later, just the IP - if (host_ok) - webirc_hostname.set(user, parameters[2]); - else - webirc_hostname.unset(user); + // Where the magic happens - change their IP + ChangeIP(user, parameters[3]); + // And follow this up by changing their host + user->host = user->dhost = newhost; - webirc_ip.set(user, parameters[3]); return CMD_SUCCESS; } } } - ServerInstance->SNO->WriteGlobalSno('a', "Connecting user %s tried to use WEBIRC, but didn't match any configured webirc blocks.", user->GetFullRealHost().c_str()); + ServerInstance->SNO->WriteGlobalSno('w', "Warning: Connecting user %s tried to use WEBIRC, but didn't match any configured webirc blocks.", user->GetFullRealHost().c_str()); return CMD_FAILURE; } }; @@ -137,7 +136,7 @@ class CGIResolver : public Resolver if ((them) && (!them->quitting)) { if (notify) - ServerInstance->SNO->WriteGlobalSno('a', "Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from %s", them->nick.c_str(), them->host.c_str(), result.c_str(), typ.c_str()); + ServerInstance->SNO->WriteGlobalSno('w', "Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from %s", them->nick.c_str(), them->host.c_str(), result.c_str(), typ.c_str()); if (result.length() > 64) return; @@ -156,7 +155,7 @@ class CGIResolver : public Resolver User* them = ServerInstance->FindUUID(theiruid); if ((them) && (!them->quitting)) { - ServerInstance->SNO->WriteToSnoMask('a', "Connecting user %s detected as using CGI:IRC (%s), but their host can't be resolved from their %s!", them->nick.c_str(), them->host.c_str(), typ.c_str()); + ServerInstance->SNO->WriteToSnoMask('w', "Connecting user %s detected as using CGI:IRC (%s), but their host can't be resolved from their %s!", them->nick.c_str(), them->host.c_str(), typ.c_str()); } } @@ -183,18 +182,8 @@ class ModuleCgiIRC : public Module user->CheckClass(); } - static void ChangeIP(LocalUser* user, const std::string& newip) - { - ServerInstance->Users->RemoveCloneCounts(user); - user->SetClientIP(newip.c_str()); - ServerInstance->Users->AddLocalClone(user); - ServerInstance->Users->AddGlobalClone(user); - } - void HandleIdentOrPass(LocalUser* user, const std::string& newip, bool was_pass) { - cmd.realhost.set(user, user->host); - cmd.realip.set(user, user->GetIPString()); ChangeIP(user, newip); user->host = user->dhost = user->GetIPString(); user->InvalidateCache(); @@ -213,7 +202,7 @@ class ModuleCgiIRC : public Module catch (...) { if (cmd.notify) - ServerInstance->SNO->WriteToSnoMask('a', "Connecting user %s detected as using CGI:IRC (%s), but I could not resolve their hostname!", user->nick.c_str(), user->host.c_str()); + ServerInstance->SNO->WriteToSnoMask('w', "Connecting user %s detected as using CGI:IRC (%s), but I could not resolve their hostname!", user->nick.c_str(), user->host.c_str()); } } @@ -225,7 +214,10 @@ class ModuleCgiIRC : public Module void init() { OnRehash(NULL); - ServiceProvider* providerlist[] = { &cmd, &cmd.realhost, &cmd.realip, &cmd.webirc_hostname, &cmd.webirc_ip, &waiting }; + + ServerInstance->SNO->EnableSnomask('w', "CGIIRC"); + + ServiceProvider* providerlist[] = { &cmd, &waiting }; ServerInstance->Modules->AddServices(providerlist, sizeof(providerlist)/sizeof(ServiceProvider*)); Implementation eventlist[] = { I_OnRehash, I_OnUserRegister, I_OnCheckReady }; @@ -286,15 +278,6 @@ class ModuleCgiIRC : public Module if (waiting.get(user)) return MOD_RES_DENY; - std::string *webirc_ip = cmd.webirc_ip.get(user); - if (!webirc_ip) - return MOD_RES_PASSTHRU; - - ChangeIP(user, *webirc_ip); - - std::string* webirc_hostname = cmd.webirc_hostname.get(user); - user->host = user->dhost = (webirc_hostname ? *webirc_hostname : user->GetIPString()); - RecheckClass(user); if (user->quitting) return MOD_RES_DENY; @@ -303,9 +286,6 @@ class ModuleCgiIRC : public Module if (user->quitting) return MOD_RES_DENY; - cmd.webirc_hostname.unset(user); - cmd.webirc_ip.unset(user); - return MOD_RES_PASSTHRU; } diff --git a/src/modules/m_conn_banner.cpp b/src/modules/m_conn_banner.cpp new file mode 100644 index 0000000000..b22a75db26 --- /dev/null +++ b/src/modules/m_conn_banner.cpp @@ -0,0 +1,54 @@ +/* +* InspIRCd -- Internet Relay Chat Daemon +* +* Copyright (C) 2012 Attila Molnar +* +* This file is part of InspIRCd. InspIRCd is free software: you can +* redistribute it and/or modify it under the terms of the GNU General Public +* License as published by the Free Software Foundation, version 2. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +* details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +/* $ModAuthor: Attila Molnar */ +/* $ModAuthorMail: attilamolnar@hush.com */ +/* $ModDesc: Displays a static text to every connecting user before registration */ +/* $ModDepends: core 2.0 */ + +#include "inspircd.h" + +class ModuleConnBanner : public Module +{ + std::string text; + public: + void init() + { + OnRehash(NULL); + Implementation eventlist[] = { I_OnRehash, I_OnUserInit }; + ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); + } + + void OnRehash(User* user) + { + text = ServerInstance->Config->ConfValue("connbanner")->getString("text"); + } + + void OnUserInit(LocalUser* user) + { + if (!text.empty()) + user->WriteServ("NOTICE Auth :*** " + text); + } + + Version GetVersion() + { + return Version("Displays a static text to every connecting user before registration", VF_VENDOR); + } +}; + +MODULE_INIT(ModuleConnBanner) diff --git a/src/modules/m_delayjoin.cpp b/src/modules/m_delayjoin.cpp index a9a92e67a9..014d9799f0 100644 --- a/src/modules/m_delayjoin.cpp +++ b/src/modules/m_delayjoin.cpp @@ -32,7 +32,8 @@ class DelayJoinMode : public ModeHandler public: DelayJoinMode(Module* Parent) : ModeHandler(Parent, "delayjoin", 'D', PARAM_NONE, MODETYPE_CHANNEL) { - levelrequired = OP_VALUE; + ConfigTag* conf = ServerInstance->Config->ConfValue("delayjoin"); + levelrequired = (conf && conf->getBool("allowhalfop", false)) ? HALFOP_VALUE : OP_VALUE; } ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding); diff --git a/src/modules/m_ident.cpp b/src/modules/m_ident.cpp index 6099e7c141..2df0f1364c 100644 --- a/src/modules/m_ident.cpp +++ b/src/modules/m_ident.cpp @@ -311,6 +311,13 @@ class ModuleIdent : public Module if (!tag->getBool("useident", true)) return; + std::string ForcedIdent = tag->getString("forceident"); + if (!ForcedIdent.empty()) + { + user->ident = ForcedIdent; + return; + } + user->WriteServ("NOTICE Auth :*** Looking up your ident..."); try diff --git a/src/modules/m_invisible.cpp b/src/modules/m_invisible.cpp new file mode 100644 index 0000000000..3c04bf02cf --- /dev/null +++ b/src/modules/m_invisible.cpp @@ -0,0 +1,195 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2010 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" +#include + +/* $ModDesc: Allows for opered clients to join channels without being seen, similar to unreal 3.1 +I mode */ +/* $ModDepends: core 2.0 */ + +class InvisibleMode : public ModeHandler +{ + public: + InvisibleMode(Module* Creator) : ModeHandler(Creator, "invis-oper", 'Q', PARAM_NONE, MODETYPE_USER) + { + oper = true; + } + + ~InvisibleMode() + { + } + + ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) + { + if (dest->IsModeSet('Q') != adding) + { + dest->SetMode('Q', adding); + + /* Fix for bug #379 reported by stealth. On +/-Q make m_watch think the user has signed on/off */ + Module* m = ServerInstance->Modules->Find("m_watch.so"); + + /* This must come before setting/unsetting the handler */ + if (m && adding) + m->OnUserQuit(dest, "Connection closed", "Connection closed"); + + /* User appears to vanish or appear from nowhere */ + for (UCListIter f = dest->chans.begin(); f != dest->chans.end(); f++) + { + const UserMembList *ulist = (*f)->GetUsers(); + char tb[MAXBUF]; + + snprintf(tb,MAXBUF,":%s %s %s", dest->GetFullHost().c_str(), adding ? "PART" : "JOIN", (*f)->name.c_str()); + std::string out = tb; + Membership* memb = (**f).GetUser(dest); + std::string ms = memb->modes; + for(unsigned int i=0; i < memb->modes.length(); i++) + ms.append(" ").append(dest->nick); + + + for (UserMembCIter i = ulist->begin(); i != ulist->end(); i++) + { + /* User only appears to vanish for non-opers */ + if (IS_LOCAL(i->first) && !IS_OPER(i->first)) + { + i->first->Write(out); + if (!ms.empty() && !adding) + i->first->WriteServ("MODE %s +%s", (**f).name.c_str(), ms.c_str()); + } + } + } + + if (IS_LOCAL(dest)) + { + ServerInstance->SNO->WriteToSnoMask('a', "Oper %s has become %svisible (%cQ)", dest->GetFullHost().c_str(), adding ? "in" : "", adding ? '+' : '-'); + } + return MODEACTION_ALLOW; + } + else + { + return MODEACTION_DENY; + } + } +}; + +class ModuleInvisible : public Module +{ + private: + InvisibleMode qm; + bool hidejoin; + bool hidelist; + bool hidewho; + bool hidemsg; + public: + ModuleInvisible() : qm(this) + { + } + + void init() + { + ServerInstance->Modules->AddService(qm); + + Implementation eventlist[] = { + I_OnUserPreMessage, I_OnUserPreNotice, I_OnUserJoin, + I_OnBuildNeighborList, I_OnSendWhoLine, I_OnNamesListItem, + I_OnRehash + }; + ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); + OnRehash(NULL); + } + + void OnRehash(User*) + { + ConfigTag* tag = ServerInstance->Config->ConfValue("invisible"); + hidejoin = tag->getBool("join"); + hidelist = tag->getBool("list"); + hidewho = tag->getBool("who"); + hidemsg = tag->getBool("msg"); + } + Version GetVersion(); + void OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts); + void OnBuildNeighborList(User* source, UserChanList &include, std::map &exceptions); + ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list); + ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list); + void OnSendWhoLine(User* source, const std::vector&, User* user, std::string& line); + void OnNamesListItem(User* issuer, Membership* memb, std::string &prefixes, std::string &nick); +}; + +Version ModuleInvisible::GetVersion() +{ + return Version("Allows opers to join channels invisibly", VF_COMMON); +} + +static void BuildExcept(Membership* memb, CUList& excepts) +{ + const UserMembList* users = memb->chan->GetUsers(); + for(UserMembCIter i = users->begin(); i != users->end(); i++) + { + if (IS_LOCAL(i->first) && !IS_OPER(i->first)) + excepts.insert(i->first); + } +} + +void ModuleInvisible::OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts) +{ + if (hidejoin && memb->user->IsModeSet('Q')) + { + BuildExcept(memb, excepts); + if (IS_LOCAL(memb->user)) + { + ServerInstance->SNO->WriteToSnoMask('a', "Oper %s has joined %s invisibly (+Q)", + memb->user->GetFullHost().c_str(), memb->chan->name.c_str()); + } + } +} + +void ModuleInvisible::OnBuildNeighborList(User* source, UserChanList &include, std::map &exceptions) +{ + if (hidewho && source->IsModeSet('Q')) + { + include.clear(); + } +} + +/* No privmsg response when hiding - submitted by Eric at neowin */ +ModResult ModuleInvisible::OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) +{ + if ((target_type == TYPE_USER) && (IS_LOCAL(user))) + { + User* target = (User*)dest; + if(hidemsg && target->IsModeSet('Q') && !IS_OPER(user)) + { + user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), target->nick.c_str()); + return MOD_RES_DENY; + } + } + return MOD_RES_PASSTHRU; +} + +ModResult ModuleInvisible::OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) +{ + return OnUserPreNotice(user, dest, target_type, text, status, exempt_list); +} + +void ModuleInvisible::OnSendWhoLine(User* source, const std::vector& params, User* user, std::string& line) +{ + if (hidewho && user->IsModeSet('Q') && !IS_OPER(source)) + line.clear(); +} + +void ModuleInvisible::OnNamesListItem(User* issuer, Membership* memb, std::string &prefixes, std::string &nick) +{ + if (hidelist && memb->user->IsModeSet('Q') && !IS_OPER(issuer)) + nick.clear(); +} + +MODULE_INIT(ModuleInvisible) diff --git a/src/modules/m_operchans.cpp b/src/modules/m_operchans.cpp index ca948d95b3..be84127427 100644 --- a/src/modules/m_operchans.cpp +++ b/src/modules/m_operchans.cpp @@ -45,7 +45,7 @@ class ModuleOperChans : public Module void init() { ServerInstance->Modules->AddService(oc); - Implementation eventlist[] = { I_OnCheckBan, I_On005Numeric, I_OnUserPreJoin }; + Implementation eventlist[] = { I_OnUserPreJoin }; ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } @@ -60,28 +60,13 @@ class ModuleOperChans : public Module return MOD_RES_PASSTHRU; } - ModResult OnCheckBan(User *user, Channel *c, const std::string& mask) - { - if ((mask.length() > 2) && (mask[0] == 'O') && (mask[1] == ':')) - { - if (IS_OPER(user) && InspIRCd::Match(user->oper->name, mask.substr(2))) - return MOD_RES_DENY; - } - return MOD_RES_PASSTHRU; - } - - void On005Numeric(std::string &output) - { - ServerInstance->AddExtBanChar('O'); - } - ~ModuleOperChans() { } Version GetVersion() { - return Version("Provides support for oper-only chans via the +O channel mode and 'O' extban", VF_VENDOR); + return Version("Provides support for oper-only chans via the +O channel mode", VF_VENDOR); } };