X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fusers.cpp;h=2ee389c86ff36b5abb69ad005c61fde720b3515a;hb=663f0620bea4dc1e64ec640992f4d511ae1ef97b;hp=c2890f9f723e1b7ffe071a277347075d7bf3913c;hpb=cd712c40e1b352c05e7ae0f72e0a5e84cdf64323;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/users.cpp b/src/users.cpp index c2890f9f7..2ee389c86 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -1,16 +1,28 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2009-2010 Daniel De Graaf + * Copyright (C) 2006-2009 Robin Burchell + * Copyright (C) 2006-2007, 2009 Dennis Friis + * Copyright (C) 2008 John Brooks + * Copyright (C) 2008 Thomas Stagner + * Copyright (C) 2008 Oliver Lupton + * Copyright (C) 2003-2008 Craig Edwards * - * InspIRCd: (C) 2002-2010 InspIRCd Development Team - * See: http://wiki.inspircd.org/Credits + * 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 free but copyrighted software; see - * the file COPYING for details. + * 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 . */ + #include "inspircd.h" #include #include "socketengine.h" @@ -18,37 +30,7 @@ #include "bancache.h" #include "commands/cmd_whowas.h" -typedef unsigned int uniq_id_t; -class sent -{ - uniq_id_t uniq_id; - uniq_id_t* array; - void init() - { - if (!array) - array = new uniq_id_t[ServerInstance->SE->GetMaxFds()]; - memset(array, 0, ServerInstance->SE->GetMaxFds() * sizeof(uniq_id_t)); - uniq_id++; - } - public: - sent() : uniq_id(static_cast(-1)), array(NULL) {} - inline uniq_id_t operator++() - { - if (++uniq_id == 0) - init(); - return uniq_id; - } - inline uniq_id_t& operator[](int i) - { - return array[i]; - } - ~sent() - { - delete[] array; - } -}; - -static sent already_sent; +already_sent_t LocalUser::already_sent_id = 0; std::string User::ProcessNoticeMasks(const char *sm) { @@ -67,9 +49,9 @@ std::string User::ProcessNoticeMasks(const char *sm) adding = false; break; case '*': - for (unsigned char d = 'A'; d <= 'z'; d++) + for (unsigned char d = 'a'; d <= 'z'; d++) { - if (ServerInstance->SNO->IsEnabled(d)) + if (!ServerInstance->SNO->masks[d - 'a'].Description.empty()) { if ((!IsNoticeMaskSet(d) && adding) || (IsNoticeMaskSet(d) && !adding)) { @@ -80,12 +62,23 @@ std::string User::ProcessNoticeMasks(const char *sm) output += d; } + oldadding = adding; + char u = toupper(d); + if ((!IsNoticeMaskSet(u) && adding) || (IsNoticeMaskSet(u) && !adding)) + { + if ((oldadding != adding) || (!output.length())) + output += (adding ? '+' : '-'); + + this->SetNoticeMask(u, adding); + + output += u; + } + oldadding = adding; } - oldadding = adding; } break; default: - if ((*c >= 'A') && (*c <= 'z') && (ServerInstance->SNO->IsEnabled(*c))) + if (isalpha(*c)) { if ((!IsNoticeMaskSet(*c) && adding) || (IsNoticeMaskSet(*c) && !adding)) { @@ -132,6 +125,8 @@ void LocalUser::StartDNSLookup() catch (CoreException& e) { ServerInstance->Logs->Log("USERS", DEBUG,"Error in resolver: %s",e.GetReason()); + dns_done = true; + ServerInstance->stats->statsDnsBad++; } } @@ -210,6 +205,7 @@ User::User(const std::string &uid, const std::string& sid, int type) signon = idle_lastmsg = 0; registered = 0; quietquit = quitting = exempt = dns_done = false; + quitting_sendq = false; client_sa.sa.sa_family = AF_UNSPEC; ServerInstance->Logs->Log("USERS", DEBUG, "New UUID for user: %s", uuid.c_str()); @@ -222,12 +218,11 @@ User::User(const std::string &uid, const std::string& sid, int type) } LocalUser::LocalUser(int myfd, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* servaddr) - : User(ServerInstance->GetUID(), ServerInstance->Config->ServerName, USERTYPE_LOCAL), eh(this) + : User(ServerInstance->GetUID(), ServerInstance->Config->ServerName, USERTYPE_LOCAL), eh(this), + bytes_in(0), bytes_out(0), cmds_in(0), cmds_out(0), nping(0), CommandFloodPenalty(0), + already_sent(0) { - bytes_in = bytes_out = cmds_in = cmds_out = 0; - server_sa.sa.sa_family = AF_UNSPEC; - CommandFloodPenalty = 0; - lastping = nping = 0; + lastping = 0; eh.SetFd(myfd); memcpy(&client_sa, client, sizeof(irc::sockets::sockaddrs)); memcpy(&server_sa, servaddr, sizeof(irc::sockets::sockaddrs)); @@ -236,7 +231,7 @@ LocalUser::LocalUser(int myfd, irc::sockets::sockaddrs* client, irc::sockets::so User::~User() { if (ServerInstance->Users->uuidlist->find(uuid) != ServerInstance->Users->uuidlist->end()) - ServerInstance->Logs->Log("USERS", ERROR, "User destructor for %s called without cull", uuid.c_str()); + ServerInstance->Logs->Log("USERS", DEFAULT, "User destructor for %s called without cull", uuid.c_str()); } const std::string& User::MakeHost() @@ -531,25 +526,19 @@ eol_found: if (user->quitting) return; } - // Add pseudo-penalty so that we continue processing after sendq recedes - if (user->CommandFloodPenalty == 0 && getSendQSize() >= sendqmax) - user->CommandFloodPenalty++; if (user->CommandFloodPenalty >= penaltymax && !user->MyClass->fakelag) ServerInstance->Users->QuitUser(user, "Excess Flood"); } void UserIOHandler::AddWriteBuf(const std::string &data) { + if (user->quitting_sendq) + return; if (!user->quitting && getSendQSize() + data.length() > user->MyClass->GetSendqHardMax() && !user->HasPrivPermission("users/flood/increased-buffers")) { - /* - * Quit the user FIRST, because otherwise we could recurse - * here and hit the same limit. - */ - ServerInstance->Users->QuitUser(user, "SendQ exceeded"); - ServerInstance->SNO->WriteToSnoMask('a', "User %s SendQ exceeds connect class maximum of %lu", - user->nick.c_str(), user->MyClass->GetSendqHardMax()); + user->quitting_sendq = true; + ServerInstance->GlobalCulls.AddSQItem(user); return; } @@ -575,7 +564,6 @@ CullResult User::cull() if (client_sa.sa.sa_family != AF_UNSPEC) ServerInstance->Users->RemoveCloneCounts(this); - ServerInstance->Users->uuidlist->erase(uuid); return Extensible::cull(); } @@ -595,6 +583,8 @@ CullResult FakeUser::cull() { // Fake users don't quit, they just get culled. quitting = true; + ServerInstance->Users->clientlist->erase(nick); + ServerInstance->Users->uuidlist->erase(uuid); return User::cull(); } @@ -620,10 +610,7 @@ void User::Oper(OperInfo* info) l->ChangeDisplayedHost(vhost.c_str()); std::string opClass = oper->getConfig("class"); if (!opClass.empty()) - { l->SetClass(opClass); - l->CheckClass(); - } } ServerInstance->SNO->WriteToSnoMask('o',"%s (%s@%s) is now an IRC operator of type %s (using oper '%s')", @@ -671,7 +658,7 @@ void OperInfo::init() { this->AllowedUserModes.set(); } - else + else if (*c >= 'A' && *c < 'z') { this->AllowedUserModes[*c - 'A'] = true; } @@ -683,7 +670,7 @@ void OperInfo::init() { this->AllowedChanModes.set(); } - else + else if (*c >= 'A' && *c < 'z') { this->AllowedChanModes[*c - 'A'] = true; } @@ -749,22 +736,25 @@ void LocalUser::CheckClass() if (!a) { ServerInstance->Users->QuitUser(this, "Access denied by configuration"); + return; } else if (a->type == CC_DENY) { - ServerInstance->Users->QuitUser(this, "Unauthorised connection"); + ServerInstance->Users->QuitUser(this, a->config->getString("reason", "Unauthorised connection")); return; } else if ((a->GetMaxLocal()) && (ServerInstance->Users->LocalCloneCount(this) > a->GetMaxLocal())) { ServerInstance->Users->QuitUser(this, "No more connections allowed from your host via this connect class (local)"); - ServerInstance->SNO->WriteToSnoMask('a', "WARNING: maximum LOCAL connections (%ld) exceeded for IP %s", a->GetMaxLocal(), this->GetIPString()); + if (a->maxconnwarn) + ServerInstance->SNO->WriteToSnoMask('a', "WARNING: maximum LOCAL connections (%ld) exceeded for IP %s", a->GetMaxLocal(), this->GetIPString()); return; } else if ((a->GetMaxGlobal()) && (ServerInstance->Users->GlobalCloneCount(this) > a->GetMaxGlobal())) { ServerInstance->Users->QuitUser(this, "No more connections allowed from your host via this connect class (global)"); - ServerInstance->SNO->WriteToSnoMask('a', "WARNING: maximum GLOBAL connections (%ld) exceeded for IP %s", a->GetMaxGlobal(), this->GetIPString()); + if (a->maxconnwarn) + ServerInstance->SNO->WriteToSnoMask('a', "WARNING: maximum GLOBAL connections (%ld) exceeded for IP %s", a->GetMaxGlobal(), this->GetIPString()); return; } @@ -803,21 +793,12 @@ void LocalUser::FullConnect() * may put the user into a totally seperate class with different restrictions! so we *must* check again. * Don't remove this! -- w00t */ - this->SetClass(); - - /* Check the password, if one is required by the user's connect class. - * This CANNOT be in CheckClass(), because that is called prior to PASS as well! - */ - if (!MyClass->pass.empty()) - { - if (ServerInstance->PassCompare(this, MyClass->pass.c_str(), password.c_str(), MyClass->hash.c_str())) - { - ServerInstance->Users->QuitUser(this, "Invalid password"); - return; - } - } + MyClass = NULL; + SetClass(); + CheckClass(); + CheckLines(); - if (this->CheckLines()) + if (quitting) return; this->WriteServ("NOTICE Auth :Welcome to \002%s\002!",ServerInstance->Config->Network.c_str()); @@ -829,21 +810,27 @@ void LocalUser::FullConnect() ServerInstance->Config->Send005(this); this->WriteNumeric(RPL_YOURUUID, "%s %s :your unique ID", this->nick.c_str(), this->uuid.c_str()); - - this->ShowMOTD(); - /* Now registered */ if (ServerInstance->Users->unregistered_count) ServerInstance->Users->unregistered_count--; - /* Trigger LUSERS output, give modules a chance too */ + /* Trigger MOTD and LUSERS output, give modules a chance too */ ModResult MOD_RESULT; - std::string command("LUSERS"); + std::string command("MOTD"); std::vector parameters; - FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, parameters, this, true, "LUSERS")); + FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, parameters, this, true, command)); if (!MOD_RESULT) ServerInstance->CallCommandHandler(command, parameters, this); + MOD_RESULT = MOD_RES_PASSTHRU; + command = "LUSERS"; + FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, parameters, this, true, command)); + if (!MOD_RESULT) + ServerInstance->CallCommandHandler(command, parameters, this); + + if (ServerInstance->Config->RawLog) + WriteServ("PRIVMSG %s :*** Raw I/O logging is enabled on this server. All messages, passwords, and commands are being recorded.", nick.c_str()); + /* * We don't set REG_ALL until triggering OnUserConnect, so some module events don't spew out stuff * for a user that doesn't exist yet. @@ -854,31 +841,12 @@ void LocalUser::FullConnect() FOREACH_MOD(I_OnPostConnect,OnPostConnect(this)); - ServerInstance->SNO->WriteToSnoMask('c',"Client connecting on port %d: %s!%s@%s [%s] [%s]", - this->GetServerPort(), this->nick.c_str(), this->ident.c_str(), this->host.c_str(), this->GetIPString(), this->fullname.c_str()); + ServerInstance->SNO->WriteToSnoMask('c',"Client connecting on port %d (class %s): %s!%s@%s [%s] [%s]", + this->GetServerPort(), this->MyClass->name.c_str(), this->nick.c_str(), this->ident.c_str(), this->host.c_str(), this->GetIPString(), this->fullname.c_str()); ServerInstance->Logs->Log("BANCACHE", DEBUG, "BanCache: Adding NEGATIVE hit for %s", this->GetIPString()); ServerInstance->BanCache->AddHit(this->GetIPString(), "", ""); -} - -/** User::UpdateNick() - * re-allocates a nick in the user_hash after they change nicknames, - * returns a pointer to the new user as it may have moved - */ -User* User::UpdateNickHash(const char* New) -{ - //user_hash::iterator newnick; - user_hash::iterator oldnick = ServerInstance->Users->clientlist->find(this->nick); - - if (!irc::string(this->nick.c_str()).compare(New)) - return oldnick->second; - - if (oldnick == ServerInstance->Users->clientlist->end()) - return NULL; /* doesnt exist */ - - User* olduser = oldnick->second; - ServerInstance->Users->clientlist->erase(oldnick); - (*(ServerInstance->Users->clientlist))[New] = olduser; - return olduser; + // reset the flood penalty (which could have been raised due to things like auto +x) + CommandFloodPenalty = 0; } void User::InvalidateCache() @@ -890,13 +858,12 @@ void User::InvalidateCache() cached_fullrealhost.clear(); } -bool User::ForceNickChange(const char* newnick) +bool User::ChangeNick(const std::string& newnick, bool force) { ModResult MOD_RESULT; - this->InvalidateCache(); - - ServerInstance->NICKForced.set(this, 1); + if (force) + ServerInstance->NICKForced.set(this, 1); FIRST_MOD_RESULT(OnUserPreNick, MOD_RESULT, (this, newnick)); ServerInstance->NICKForced.set(this, 0); @@ -906,20 +873,98 @@ bool User::ForceNickChange(const char* newnick) return false; } - std::deque dummy; - Command* nickhandler = ServerInstance->Parser->GetHandler("NICK"); - if (nickhandler) // wtfbbq, when would this not be here + if (assign(newnick) == assign(nick)) { - std::vector parameters; - parameters.push_back(newnick); - ServerInstance->NICKForced.set(this, 1); - bool result = (ServerInstance->Parser->CallHandler("NICK", parameters, this) == CMD_SUCCESS); - ServerInstance->NICKForced.set(this, 0); - return result; + // case change, don't need to check Q:lines and such + // and, if it's identical including case, we can leave right now + if (newnick == nick) + return true; + } + else + { + /* + * Don't check Q:Lines if it's a server-enforced change, just on the off-chance some fucking *moron* + * tries to Q:Line SIDs, also, this means we just get our way period, as it really should be. + * Thanks Kein for finding this. -- w00t + * + * Also don't check Q:Lines for remote nickchanges, they should have our Q:Lines anyway to enforce themselves. + * -- w00t + */ + if (IS_LOCAL(this) && !force) + { + XLine* mq = ServerInstance->XLines->MatchesLine("Q",newnick); + if (mq) + { + if (this->registered == REG_ALL) + { + ServerInstance->SNO->WriteGlobalSno('a', "Q-Lined nickname %s from %s!%s@%s: %s", + newnick.c_str(), this->nick.c_str(), this->ident.c_str(), this->host.c_str(), mq->reason.c_str()); + } + this->WriteNumeric(432, "%s %s :Invalid nickname: %s",this->nick.c_str(), newnick.c_str(), mq->reason.c_str()); + return false; + } + + if (ServerInstance->Config->RestrictBannedUsers) + { + for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++) + { + Channel *chan = *i; + if (chan->GetPrefixValue(this) < VOICE_VALUE && chan->IsBanned(this)) + { + this->WriteNumeric(404, "%s %s :Cannot send to channel (you're banned)", this->nick.c_str(), chan->name.c_str()); + return false; + } + } + } + } + + /* + * Uh oh.. if the nickname is in use, and it's not in use by the person using it (doh) -- + * then we have a potential collide. Check whether someone else is camping on the nick + * (i.e. connect -> send NICK, don't send USER.) If they are camping, force-change the + * camper to their UID, and allow the incoming nick change. + * + * If the guy using the nick is already using it, tell the incoming nick change to gtfo, + * because the nick is already (rightfully) in use. -- w00t + */ + User* InUse = ServerInstance->FindNickOnly(newnick); + if (InUse && (InUse != this)) + { + if (InUse->registered != REG_ALL) + { + /* force the camper to their UUID, and ask them to re-send a NICK. */ + InUse->WriteTo(InUse, "NICK %s", InUse->uuid.c_str()); + InUse->WriteNumeric(433, "%s %s :Nickname overruled.", InUse->nick.c_str(), InUse->nick.c_str()); + + ServerInstance->Users->clientlist->erase(InUse->nick); + (*(ServerInstance->Users->clientlist))[InUse->uuid] = InUse; + + InUse->nick = InUse->uuid; + InUse->InvalidateCache(); + InUse->registered &= ~REG_NICK; + } + else + { + /* No camping, tell the incoming user to stop trying to change nick ;p */ + this->WriteNumeric(433, "%s %s :Nickname is already in use.", this->registered >= REG_NICK ? this->nick.c_str() : "*", newnick.c_str()); + return false; + } + } } - // Unreachable, we hope - return false; + if (this->registered == REG_ALL) + this->WriteCommon("NICK %s",newnick.c_str()); + std::string oldnick = nick; + nick = newnick; + + InvalidateCache(); + ServerInstance->Users->clientlist->erase(oldnick); + (*(ServerInstance->Users->clientlist))[newnick] = this; + + if (registered == REG_ALL) + FOREACH_MOD(I_OnUserPostNick,OnUserPostNick(this,oldnick)); + + return true; } int LocalUser::GetServerPort() @@ -992,7 +1037,7 @@ void LocalUser::Write(const std::string& text) return; } - ServerInstance->Logs->Log("USEROUTPUT", DEBUG,"C[%s] O %s", uuid.c_str(), text.c_str()); + ServerInstance->Logs->Log("USEROUTPUT", RAWIO, "C[%s] O %s", uuid.c_str(), text.c_str()); eh.AddWriteBuf(text); eh.AddWriteBuf(wide_newline); @@ -1146,7 +1191,7 @@ void User::WriteCommonRaw(const std::string &line, bool include_self) if (this->registered != REG_ALL || quitting) return; - uniq_id_t uniq_id = ++already_sent; + LocalUser::already_sent_id++; UserChanList include_c(chans); std::map exceptions; @@ -1160,7 +1205,7 @@ void User::WriteCommonRaw(const std::string &line, bool include_self) LocalUser* u = IS_LOCAL(i->first); if (u && !u->quitting) { - already_sent[u->GetFd()] = uniq_id; + u->already_sent = LocalUser::already_sent_id; if (i->second) u->Write(line); } @@ -1172,9 +1217,9 @@ void User::WriteCommonRaw(const std::string &line, bool include_self) for (UserMembList::const_iterator i = ulist->begin(); i != ulist->end(); i++) { LocalUser* u = IS_LOCAL(i->first); - if (u && !u->quitting && already_sent[u->GetFd()] != uniq_id) + if (u && !u->quitting && u->already_sent != LocalUser::already_sent_id) { - already_sent[u->GetFd()] = uniq_id; + u->already_sent = LocalUser::already_sent_id; u->Write(line); } } @@ -1189,7 +1234,7 @@ void User::WriteCommonQuit(const std::string &normal_text, const std::string &op if (this->registered != REG_ALL) return; - uniq_id_t uniq_id = ++already_sent; + already_sent_t uniq_id = ++LocalUser::already_sent_id; snprintf(tb1,MAXBUF,":%s QUIT :%s",this->GetFullHost().c_str(),normal_text.c_str()); snprintf(tb2,MAXBUF,":%s QUIT :%s",this->GetFullHost().c_str(),oper_text.c_str()); @@ -1206,7 +1251,7 @@ void User::WriteCommonQuit(const std::string &normal_text, const std::string &op LocalUser* u = IS_LOCAL(i->first); if (u && !u->quitting) { - already_sent[u->GetFd()] = uniq_id; + u->already_sent = uniq_id; if (i->second) u->Write(IS_OPER(u) ? out2 : out1); } @@ -1217,9 +1262,9 @@ void User::WriteCommonQuit(const std::string &normal_text, const std::string &op for (UserMembList::const_iterator i = ulist->begin(); i != ulist->end(); i++) { LocalUser* u = IS_LOCAL(i->first); - if (u && !u->quitting && (already_sent[u->GetFd()] != uniq_id)) + if (u && !u->quitting && (u->already_sent != uniq_id)) { - already_sent[u->GetFd()] = uniq_id; + u->already_sent = uniq_id; u->Write(IS_OPER(u) ? out2 : out1); } } @@ -1330,8 +1375,8 @@ void User::DoHostCycle(const std::string &quitline) if (!ServerInstance->Config->CycleHosts) return; - uniq_id_t silent_id = ++already_sent; - uniq_id_t seen_id = ++already_sent; + already_sent_t silent_id = ++LocalUser::already_sent_id; + already_sent_t seen_id = ++LocalUser::already_sent_id; UserChanList include_c(chans); std::map exceptions; @@ -1345,12 +1390,12 @@ void User::DoHostCycle(const std::string &quitline) { if (i->second) { - already_sent[u->GetFd()] = seen_id; + u->already_sent = seen_id; u->Write(quitline); } else { - already_sent[u->GetFd()] = silent_id; + u->already_sent = silent_id; } } } @@ -1365,7 +1410,9 @@ void User::DoHostCycle(const std::string &quitline) { for(unsigned int i=0; i < memb->modes.length(); i++) modeline.append(" ").append(nick); - snprintf(buffer, MAXBUF, ":%s MODE %s +%s", GetFullHost().c_str(), c->name.c_str(), modeline.c_str()); + snprintf(buffer, MAXBUF, ":%s MODE %s +%s", + ServerInstance->Config->CycleHostsFromUser ? GetFullHost().c_str() : ServerInstance->Config->ServerName.c_str(), + c->name.c_str(), modeline.c_str()); modeline = buffer; } @@ -1375,13 +1422,13 @@ void User::DoHostCycle(const std::string &quitline) LocalUser* u = IS_LOCAL(i->first); if (u == NULL || u == this) continue; - if (already_sent[u->GetFd()] == silent_id) + if (u->already_sent == silent_id) continue; - if (already_sent[u->GetFd()] != seen_id) + if (u->already_sent != seen_id) { u->Write(quitline); - already_sent[u->GetFd()] = seen_id; + u->already_sent = seen_id; } u->Write(joinline); if (modeline.length() > 0) @@ -1506,7 +1553,7 @@ void User::SplitChanList(User* dest, const std::string &cl) } } - if (line.length()) + if (line.length() != prefix.str().length()) { ServerInstance->SendWhoisLine(this, dest, 319, "%s", line.c_str()); } @@ -1543,18 +1590,28 @@ void LocalUser::SetClass(const std::string &explicit_name) for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++) { ConnectClass* c = *i; + ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "Checking %s", c->GetName().c_str()); - if (c->type == CC_ALLOW) - { - ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "ALLOW %s %d %s", c->host.c_str(), c->GetPort(), c->GetName().c_str()); - } - else + ModResult MOD_RESULT; + FIRST_MOD_RESULT(OnSetConnectClass, MOD_RESULT, (this,c)); + if (MOD_RESULT == MOD_RES_DENY) + continue; + if (MOD_RESULT == MOD_RES_ALLOW) { - ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "DENY %s %d %s", c->GetHost().c_str(), c->GetPort(), c->GetName().c_str()); + ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "Class forced by module to %s", c->GetName().c_str()); + found = c; + break; } + if (c->type == CC_NAMED) + continue; + + bool regdone = (registered != REG_NONE); + if (c->config->getBool("registered", regdone) != regdone) + continue; + /* check if host matches.. */ - if (c->GetHost().length() && !InspIRCd::MatchCIDR(this->GetIPString(), c->GetHost(), NULL) && + if (!InspIRCd::MatchCIDR(this->GetIPString(), c->GetHost(), NULL) && !InspIRCd::MatchCIDR(this->host, c->GetHost(), NULL)) { ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "No host match (for %s)", c->GetHost().c_str()); @@ -1572,14 +1629,21 @@ void LocalUser::SetClass(const std::string &explicit_name) } /* if it requires a port ... */ - if (c->GetPort()) + int port = c->config->getInt("port"); + if (port) { - ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "Requires port (%d)", c->GetPort()); + ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "Requires port (%d)", port); /* and our port doesn't match, fail. */ - if (this->GetServerPort() != c->GetPort()) + if (this->GetServerPort() != port) + continue; + } + + if (regdone && !c->config->getString("password").empty()) + { + if (ServerInstance->PassCompare(this, c->config->getString("password"), password, c->config->getString("hash"))) { - ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "Port match failed (%d)", this->GetServerPort()); + ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "Bad password, skipping"); continue; } } @@ -1626,37 +1690,6 @@ void User::PurgeEmptyChannels() this->UnOper(); } -void User::ShowMOTD() -{ - if (!ServerInstance->Config->MOTD.size()) - { - this->WriteNumeric(ERR_NOMOTD, "%s :Message of the day file is missing.",this->nick.c_str()); - return; - } - this->WriteNumeric(RPL_MOTDSTART, "%s :%s message of the day", this->nick.c_str(), ServerInstance->Config->ServerName.c_str()); - - for (file_cache::iterator i = ServerInstance->Config->MOTD.begin(); i != ServerInstance->Config->MOTD.end(); i++) - this->WriteNumeric(RPL_MOTD, "%s :- %s",this->nick.c_str(),i->c_str()); - - this->WriteNumeric(RPL_ENDOFMOTD, "%s :End of message of the day.", this->nick.c_str()); -} - -void User::ShowRULES() -{ - if (!ServerInstance->Config->RULES.size()) - { - this->WriteNumeric(ERR_NORULES, "%s :RULES File is missing",this->nick.c_str()); - return; - } - - this->WriteNumeric(RPL_RULESTART, "%s :- %s Server Rules -",this->nick.c_str(),ServerInstance->Config->ServerName.c_str()); - - for (file_cache::iterator i = ServerInstance->Config->RULES.begin(); i != ServerInstance->Config->RULES.end(); i++) - this->WriteNumeric(RPL_RULES, "%s :- %s",this->nick.c_str(),i->c_str()); - - this->WriteNumeric(RPL_RULESEND, "%s :End of RULES command.",this->nick.c_str()); -} - const std::string& FakeUser::GetFullHost() { if (!ServerInstance->Config->HideWhoisServer.empty()) @@ -1673,35 +1706,38 @@ const std::string& FakeUser::GetFullRealHost() ConnectClass::ConnectClass(ConfigTag* tag, char t, const std::string& mask) : config(tag), type(t), fakelag(true), name("unnamed"), registration_timeout(0), host(mask), - pingtime(0), pass(""), hash(""), softsendqmax(0), hardsendqmax(0), recvqmax(0), - penaltythreshold(0), commandrate(0), maxlocal(0), maxglobal(0), maxchans(0), port(0), limit(0) + pingtime(0), softsendqmax(0), hardsendqmax(0), recvqmax(0), + penaltythreshold(0), commandrate(0), maxlocal(0), maxglobal(0), maxconnwarn(true), maxchans(0), limit(0) { } ConnectClass::ConnectClass(ConfigTag* tag, char t, const std::string& mask, const ConnectClass& parent) : config(tag), type(t), fakelag(parent.fakelag), name("unnamed"), registration_timeout(parent.registration_timeout), host(mask), pingtime(parent.pingtime), - pass(parent.pass), hash(parent.hash), softsendqmax(parent.softsendqmax), - hardsendqmax(parent.hardsendqmax), recvqmax(parent.recvqmax), + softsendqmax(parent.softsendqmax), hardsendqmax(parent.hardsendqmax), recvqmax(parent.recvqmax), penaltythreshold(parent.penaltythreshold), commandrate(parent.commandrate), - maxlocal(parent.maxlocal), maxglobal(parent.maxglobal), maxchans(parent.maxchans), - port(parent.port), limit(parent.limit) + maxlocal(parent.maxlocal), maxglobal(parent.maxglobal), maxconnwarn(parent.maxconnwarn), maxchans(parent.maxchans), + limit(parent.limit) { } void ConnectClass::Update(const ConnectClass* src) { + config = src->config; + type = src->type; + fakelag = src->fakelag; name = src->name; registration_timeout = src->registration_timeout; host = src->host; pingtime = src->pingtime; - pass = src->pass; - hash = src->hash; softsendqmax = src->softsendqmax; hardsendqmax = src->hardsendqmax; recvqmax = src->recvqmax; penaltythreshold = src->penaltythreshold; + commandrate = src->commandrate; maxlocal = src->maxlocal; maxglobal = src->maxglobal; + maxconnwarn = src->maxconnwarn; + maxchans = src->maxchans; limit = src->limit; }