X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fusers.cpp;h=9c3d645f72c0a64b2ea6491269fedc18a32724db;hb=16c80276ea6cba0d36da6f79a0fe7004b0e6f0ea;hp=c01b5d1b274dcf12c4a118999d69fd4d2250aafe;hpb=d560adec9e578c40f786a0849e3a15f99e738b56;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/users.cpp b/src/users.cpp index c01b5d1b2..9c3d645f7 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)); @@ -337,75 +332,45 @@ const std::string& User::GetFullRealHost() bool LocalUser::IsInvited(const irc::string &channel) { - time_t now = ServerInstance->Time(); - InvitedList::iterator safei; - for (InvitedList::iterator i = invites.begin(); i != invites.end(); ++i) - { - if (channel == i->first) - { - if (i->second != 0 && now > i->second) - { - /* Expired invite, remove it. */ - safei = i; - --i; - invites.erase(safei); - continue; - } - return true; - } - } - return false; + Channel* chan = ServerInstance->FindChan(channel.c_str()); + if (!chan) + return false; + + return (Invitation::Find(chan, this) != NULL); } -InvitedList* LocalUser::GetInviteList() +InviteList& LocalUser::GetInviteList() { - time_t now = ServerInstance->Time(); - /* Weed out expired invites here. */ - InvitedList::iterator safei; - for (InvitedList::iterator i = invites.begin(); i != invites.end(); ++i) - { - if (i->second != 0 && now > i->second) - { - /* Expired invite, remove it. */ - safei = i; - --i; - invites.erase(safei); - } - } - return &invites; + RemoveExpiredInvites(); + return invites; } void LocalUser::InviteTo(const irc::string &channel, time_t invtimeout) { - time_t now = ServerInstance->Time(); - if (invtimeout != 0 && now > invtimeout) return; /* Don't add invites that are expired from the get-go. */ - for (InvitedList::iterator i = invites.begin(); i != invites.end(); ++i) - { - if (channel == i->first) - { - if (i->second != 0 && invtimeout > i->second) - { - i->second = invtimeout; - } - - return; - } - } - invites.push_back(std::make_pair(channel, invtimeout)); + Channel* chan = ServerInstance->FindChan(channel.c_str()); + if (chan) + Invitation::Create(chan, this, invtimeout); } void LocalUser::RemoveInvite(const irc::string &channel) { - for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++) + Channel* chan = ServerInstance->FindChan(channel.c_str()); + if (chan) { - if (channel == i->first) + Invitation* inv = Invitation::Find(chan, this); + if (inv) { - invites.erase(i); - return; - } + inv->cull(); + delete inv; + } } } +void LocalUser::RemoveExpiredInvites() +{ + Invitation::Find(NULL, this); +} + bool User::HasModePermission(unsigned char, ModeType) { return true; @@ -531,25 +496,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; } @@ -570,8 +529,6 @@ CullResult User::cull() ServerInstance->Users->QuitUser(this, "Culled without QuitUser"); PurgeEmptyChannels(); - this->InvalidateCache(); - if (client_sa.sa.sa_family != AF_UNSPEC) ServerInstance->Users->RemoveCloneCounts(this); @@ -586,6 +543,7 @@ CullResult LocalUser::cull() else ServerInstance->Logs->Log("USERS", DEBUG, "Failed to remove user from vector"); + ClearInvites(); eh.cull(); return User::cull(); } @@ -669,7 +627,7 @@ void OperInfo::init() { this->AllowedUserModes.set(); } - else + else if (*c >= 'A' && *c < 'z') { this->AllowedUserModes[*c - 'A'] = true; } @@ -681,7 +639,7 @@ void OperInfo::init() { this->AllowedChanModes.set(); } - else + else if (*c >= 'A' && *c < 'z') { this->AllowedChanModes[*c - 'A'] = true; } @@ -747,22 +705,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; } @@ -801,19 +762,8 @@ 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->config->getString("pass").empty()) - { - if (ServerInstance->PassCompare(this, MyClass->config->getString("pass"), password, MyClass->config->getString("hash"))) - { - ServerInstance->Users->QuitUser(this, "Invalid password"); - return; - } - } + MyClass = NULL; + SetClass(); CheckClass(); CheckLines(); @@ -847,6 +797,9 @@ void LocalUser::FullConnect() 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. @@ -857,10 +810,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(), "", ""); + // reset the flood penalty (which could have been raised due to things like auto +x) + CommandFloodPenalty = 0; } void User::InvalidateCache() @@ -904,7 +859,7 @@ bool User::ChangeNick(const std::string& newnick, bool force) * Also don't check Q:Lines for remote nickchanges, they should have our Q:Lines anyway to enforce themselves. * -- w00t */ - if (IS_LOCAL(this)) + if (IS_LOCAL(this) && !force) { XLine* mq = ServerInstance->XLines->MatchesLine("Q",newnick); if (mq) @@ -1051,7 +1006,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); @@ -1205,7 +1160,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; @@ -1219,7 +1174,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); } @@ -1231,9 +1186,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); } } @@ -1248,7 +1203,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()); @@ -1265,7 +1220,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); } @@ -1276,9 +1231,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); } } @@ -1389,8 +1344,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; @@ -1404,12 +1359,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; } } } @@ -1424,7 +1379,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; } @@ -1434,13 +1391,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) @@ -1565,7 +1522,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()); } @@ -1602,6 +1559,7 @@ 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()); ModResult MOD_RESULT; FIRST_MOD_RESULT(OnSetConnectClass, MOD_RESULT, (this,c)); @@ -1617,8 +1575,12 @@ void LocalUser::SetClass(const std::string &explicit_name) 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()); @@ -1646,6 +1608,15 @@ void LocalUser::SetClass(const std::string &explicit_name) 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, "Bad password, skipping"); + continue; + } + } + /* we stop at the first class that meets ALL critera. */ found = c; break; @@ -1705,7 +1676,7 @@ 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), softsendqmax(0), hardsendqmax(0), recvqmax(0), - penaltythreshold(0), commandrate(0), maxlocal(0), maxglobal(0), maxchans(0), limit(0) + penaltythreshold(0), commandrate(0), maxlocal(0), maxglobal(0), maxconnwarn(true), maxchans(0), limit(0) { } @@ -1714,13 +1685,16 @@ ConnectClass::ConnectClass(ConfigTag* tag, char t, const std::string& mask, cons registration_timeout(parent.registration_timeout), host(mask), pingtime(parent.pingtime), softsendqmax(parent.softsendqmax), hardsendqmax(parent.hardsendqmax), recvqmax(parent.recvqmax), penaltythreshold(parent.penaltythreshold), commandrate(parent.commandrate), - maxlocal(parent.maxlocal), maxglobal(parent.maxglobal), maxchans(parent.maxchans), + 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; @@ -1729,7 +1703,10 @@ void ConnectClass::Update(const ConnectClass* src) 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; }