X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fusers.cpp;h=92276d07c2d555372f8dd9684d810c6c688fe3ce;hb=20ea635c9fcd0d559ff6fc2863ab581591bc4ef8;hp=89a064b1fdd3ec2699dd0daa700f0061ebe748a9;hpb=69e28c67dddd8b74ee4c321667d286111e09e5da;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/users.cpp b/src/users.cpp index 89a064b1f..92276d07c 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" @@ -37,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)) { @@ -50,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)) { @@ -102,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++; } } @@ -180,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()); @@ -196,10 +222,12 @@ LocalUser::LocalUser(int myfd, irc::sockets::sockaddrs* client, irc::sockets::so bytes_in(0), bytes_out(0), cmds_in(0), cmds_out(0), nping(0), CommandFloodPenalty(0), already_sent(0) { + ident = "unknown"; lastping = 0; eh.SetFd(myfd); memcpy(&client_sa, client, sizeof(irc::sockets::sockaddrs)); memcpy(&server_sa, servaddr, sizeof(irc::sockets::sockaddrs)); + dhost = host = GetIPString(); } User::~User() @@ -306,75 +334,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; @@ -500,25 +498,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; } @@ -539,8 +531,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); @@ -555,6 +545,7 @@ CullResult LocalUser::cull() else ServerInstance->Logs->Log("USERS", DEBUG, "Failed to remove user from vector"); + ClearInvites(); eh.cull(); return User::cull(); } @@ -597,7 +588,7 @@ void User::Oper(OperInfo* info) nick.c_str(), ident.c_str(), host.c_str(), oper->NameStr(), opername.c_str()); this->WriteNumeric(381, "%s :You are now %s %s", nick.c_str(), strchr("aeiouAEIOU", oper->name[0]) ? "an" : "a", oper->NameStr()); - ServerInstance->Logs->Log("OPER", DEFAULT, "%s!%s@%s opered as type: %s", this->nick.c_str(), this->ident.c_str(), this->host.c_str(), oper->NameStr()); + ServerInstance->Logs->Log("OPER", DEFAULT, "%s opered as type: %s", GetFullRealHost().c_str(), oper->NameStr()); ServerInstance->Users->all_opers.push_back(this); // Expand permissions from config for faster lookup @@ -632,25 +623,27 @@ void OperInfo::init() AllowedPrivs.insert(mypriv); } - for (unsigned char* c = (unsigned char*)tag->getString("usermodes").c_str(); *c; ++c) + std::string modes = tag->getString("usermodes"); + for (std::string::const_iterator c = modes.begin(); c != modes.end(); ++c) { if (*c == '*') { this->AllowedUserModes.set(); } - else + else if (*c >= 'A' && *c < 'z') { this->AllowedUserModes[*c - 'A'] = true; } } - for (unsigned char* c = (unsigned char*)tag->getString("chanmodes").c_str(); *c; ++c) + modes = tag->getString("chanmodes"); + for (std::string::const_iterator c = modes.begin(); c != modes.end(); ++c) { if (*c == '*') { this->AllowedChanModes.set(); } - else + else if (*c >= 'A' && *c < 'z') { this->AllowedChanModes[*c - 'A'] = true; } @@ -716,22 +709,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; } @@ -770,6 +766,7 @@ 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 */ + MyClass = NULL; SetClass(); CheckClass(); CheckLines(); @@ -777,11 +774,16 @@ void LocalUser::FullConnect() if (quitting) return; - this->WriteServ("NOTICE Auth :Welcome to \002%s\002!",ServerInstance->Config->Network.c_str()); - this->WriteNumeric(RPL_WELCOME, "%s :Welcome to the %s IRC Network %s!%s@%s",this->nick.c_str(), ServerInstance->Config->Network.c_str(), this->nick.c_str(), this->ident.c_str(), this->host.c_str()); - this->WriteNumeric(RPL_YOURHOSTIS, "%s :Your host is %s, running version InspIRCd-2.0",this->nick.c_str(),ServerInstance->Config->ServerName.c_str()); + if (ServerInstance->Config->WelcomeNotice) + this->WriteServ("NOTICE Auth :Welcome to \002%s\002!",ServerInstance->Config->Network.c_str()); + this->WriteNumeric(RPL_WELCOME, "%s :Welcome to the %s IRC Network %s",this->nick.c_str(), ServerInstance->Config->Network.c_str(), GetFullRealHost().c_str()); + this->WriteNumeric(RPL_YOURHOSTIS, "%s :Your host is %s, running version %s",this->nick.c_str(),ServerInstance->Config->ServerName.c_str(),BRANCH); this->WriteNumeric(RPL_SERVERCREATED, "%s :This server was created %s %s", this->nick.c_str(), __TIME__, __DATE__); - this->WriteNumeric(RPL_SERVERVERSION, "%s %s InspIRCd-2.0 %s %s %s", this->nick.c_str(), ServerInstance->Config->ServerName.c_str(), ServerInstance->Modes->UserModeList().c_str(), ServerInstance->Modes->ChannelModeList().c_str(), ServerInstance->Modes->ParaModeList().c_str()); + + std::string umlist = ServerInstance->Modes->UserModeList(); + std::string cmlist = ServerInstance->Modes->ChannelModeList(); + std::string pmlist = ServerInstance->Modes->ParaModeList(); + this->WriteNumeric(RPL_SERVERVERSION, "%s %s %s %s %s %s", this->nick.c_str(), ServerInstance->Config->ServerName.c_str(), BRANCH, umlist.c_str(), cmlist.c_str(), pmlist.c_str()); ServerInstance->Config->Send005(this); this->WriteNumeric(RPL_YOURUUID, "%s %s :your unique ID", this->nick.c_str(), this->uuid.c_str()); @@ -796,13 +798,16 @@ void LocalUser::FullConnect() std::vector parameters; FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, parameters, this, true, command)); if (!MOD_RESULT) - ServerInstance->CallCommandHandler(command, parameters, this); + ServerInstance->Parser->CallHandler(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); + ServerInstance->Parser->CallHandler(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 @@ -814,10 +819,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]", + this->GetServerPort(), this->MyClass->name.c_str(), GetFullRealHost().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() @@ -861,15 +868,15 @@ 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) { 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()); + ServerInstance->SNO->WriteGlobalSno('a', "Q-Lined nickname %s from %s: %s", + newnick.c_str(), GetFullRealHost().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; @@ -981,10 +988,38 @@ irc::sockets::cidr_mask User::GetCIDRMask() bool User::SetClientIP(const char* sip) { - this->cachedip = ""; + cachedip.clear(); + cached_hostip.clear(); return irc::sockets::aptosa(sip, 0, client_sa); } +void User::SetClientIP(const irc::sockets::sockaddrs& sa) +{ + cachedip.clear(); + cached_hostip.clear(); + memcpy(&client_sa, &sa, sizeof(irc::sockets::sockaddrs)); +} + +bool LocalUser::SetClientIP(const char* sip) +{ + irc::sockets::sockaddrs sa; + if (!irc::sockets::aptosa(sip, 0, sa)) + // Invalid + return false; + + LocalUser::SetClientIP(sa); + return true; +} + +void LocalUser::SetClientIP(const irc::sockets::sockaddrs& sa) +{ + if (sa != client_sa) + { + User::SetClientIP(sa); + FOREACH_MOD(I_OnSetUserIP,OnSetUserIP(this)); + } +} + static std::string wide_newline("\r\n"); void User::Write(const std::string& text) @@ -1008,7 +1043,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); @@ -1381,7 +1416,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; } @@ -1469,7 +1506,8 @@ void User::SendAll(const char* command, const char* text, ...) for (std::vector::const_iterator i = ServerInstance->Users->local_users.begin(); i != ServerInstance->Users->local_users.end(); i++) { - (*i)->Write(fmt); + if ((*i)->registered == REG_ALL) + (*i)->Write(fmt); } } @@ -1522,7 +1560,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()); } @@ -1580,7 +1618,7 @@ void LocalUser::SetClass(const std::string &explicit_name) 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()); @@ -1608,9 +1646,9 @@ void LocalUser::SetClass(const std::string &explicit_name) continue; } - if (!c->config->getString("pass").empty()) + if (regdone && !c->config->getString("password").empty()) { - if (ServerInstance->PassCompare(this, c->config->getString("pass"), password, c->config->getString("hash"))) + if (ServerInstance->PassCompare(this, c->config->getString("password"), password, c->config->getString("hash"))) { ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "Bad password, skipping"); continue; @@ -1676,7 +1714,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) { } @@ -1685,13 +1723,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; @@ -1700,7 +1741,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; }