2012-04-19 20:58:29 +02:00
|
|
|
/*
|
|
|
|
* InspIRCd -- Internet Relay Chat Daemon
|
2007-07-16 17:30:04 +00:00
|
|
|
*
|
2012-04-19 20:58:29 +02:00
|
|
|
* Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
|
|
|
|
* Copyright (C) 2006-2009 Robin Burchell <robin+git@viroteck.net>
|
|
|
|
* Copyright (C) 2006-2007, 2009 Dennis Friis <peavey@inspircd.org>
|
|
|
|
* Copyright (C) 2008 John Brooks <john.brooks@dereferenced.net>
|
|
|
|
* Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
|
|
|
|
* Copyright (C) 2008 Oliver Lupton <oliverlupton@gmail.com>
|
|
|
|
* Copyright (C) 2003-2008 Craig Edwards <craigedwards@brainbox.cc>
|
2007-07-16 17:30:04 +00:00
|
|
|
*
|
2012-04-19 20:58:29 +02:00
|
|
|
* 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.
|
2007-07-16 17:30:04 +00:00
|
|
|
*
|
2012-04-19 20:58:29 +02:00
|
|
|
* 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 <http://www.gnu.org/licenses/>.
|
2007-07-16 17:30:04 +00:00
|
|
|
*/
|
|
|
|
|
2012-04-19 20:58:29 +02:00
|
|
|
|
2007-07-16 17:30:04 +00:00
|
|
|
#include "inspircd.h"
|
|
|
|
#include "xline.h"
|
|
|
|
|
2010-02-12 22:30:27 +00:00
|
|
|
already_sent_t LocalUser::already_sent_id = 0;
|
2007-07-16 17:30:04 +00:00
|
|
|
|
2007-10-15 20:59:05 +00:00
|
|
|
bool User::IsNoticeMaskSet(unsigned char sm)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2008-08-25 15:49:39 +00:00
|
|
|
if (!isalpha(sm))
|
|
|
|
return false;
|
2007-07-16 17:30:04 +00:00
|
|
|
return (snomasks[sm-65]);
|
|
|
|
}
|
|
|
|
|
2007-10-15 20:59:05 +00:00
|
|
|
bool User::IsModeSet(unsigned char m)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2014-02-21 15:11:24 +01:00
|
|
|
ModeHandler* mh = ServerInstance->Modes->FindMode(m, MODETYPE_USER);
|
|
|
|
return (mh && modes[mh->GetId()]);
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2008-08-31 13:00:12 +00:00
|
|
|
const char* User::FormatModes(bool showparameters)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2013-05-16 02:23:45 +02:00
|
|
|
static std::string data;
|
2008-08-31 13:00:12 +00:00
|
|
|
std::string params;
|
2013-05-16 02:23:45 +02:00
|
|
|
data.clear();
|
2008-08-31 13:00:12 +00:00
|
|
|
|
|
|
|
for (unsigned char n = 0; n < 64; n++)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2014-02-21 15:11:24 +01:00
|
|
|
ModeHandler* mh = ServerInstance->Modes->FindMode(n + 65, MODETYPE_USER);
|
|
|
|
if (mh && IsModeSet(mh))
|
2008-08-31 13:00:12 +00:00
|
|
|
{
|
2013-05-16 02:23:45 +02:00
|
|
|
data.push_back(n + 65);
|
2014-02-21 15:11:24 +01:00
|
|
|
if (showparameters && mh->GetNumParams(true))
|
2008-08-31 13:00:12 +00:00
|
|
|
{
|
|
|
|
std::string p = mh->GetUserParameter(this);
|
|
|
|
if (p.length())
|
|
|
|
params.append(" ").append(p);
|
|
|
|
}
|
|
|
|
}
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
2013-05-16 02:23:45 +02:00
|
|
|
data += params;
|
|
|
|
return data.c_str();
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2014-01-05 15:04:01 +01:00
|
|
|
User::User(const std::string& uid, Server* srv, int type)
|
|
|
|
: uuid(uid), server(srv), usertype(type)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2008-02-22 16:40:02 +00:00
|
|
|
age = ServerInstance->Time();
|
2013-04-01 17:05:12 +02:00
|
|
|
signon = 0;
|
2009-10-23 22:47:39 +00:00
|
|
|
registered = 0;
|
2014-01-05 14:17:12 +01:00
|
|
|
quitting = false;
|
2009-10-21 23:45:08 +00:00
|
|
|
client_sa.sa.sa_family = AF_UNSPEC;
|
2007-08-27 13:36:11 +00:00
|
|
|
|
2013-04-12 02:10:06 +01:00
|
|
|
ServerInstance->Logs->Log("USERS", LOG_DEBUG, "New UUID for user: %s", uuid.c_str());
|
2007-08-27 13:54:15 +00:00
|
|
|
|
2014-03-14 13:04:10 +01:00
|
|
|
if (!ServerInstance->Users->uuidlist.insert(std::make_pair(uuid, this)).second)
|
2007-10-15 20:59:05 +00:00
|
|
|
throw CoreException("Duplicate UUID "+std::string(uuid)+" in User constructor");
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2009-11-01 21:53:47 +00:00
|
|
|
LocalUser::LocalUser(int myfd, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* servaddr)
|
2014-01-05 15:04:01 +01:00
|
|
|
: User(ServerInstance->UIDGen.GetUID(), ServerInstance->FakeClient->server, USERTYPE_LOCAL), eh(this),
|
2010-02-12 22:30:27 +00:00
|
|
|
bytes_in(0), bytes_out(0), cmds_in(0), cmds_out(0), nping(0), CommandFloodPenalty(0),
|
|
|
|
already_sent(0)
|
2009-10-21 23:44:48 +00:00
|
|
|
{
|
2013-04-22 05:21:38 +02:00
|
|
|
exempt = quitting_sendq = false;
|
2013-04-01 17:05:12 +02:00
|
|
|
idle_lastmsg = 0;
|
2012-07-09 15:35:12 +02:00
|
|
|
ident = "unknown";
|
2010-02-12 22:30:27 +00:00
|
|
|
lastping = 0;
|
2009-11-06 22:37:36 +00:00
|
|
|
eh.SetFd(myfd);
|
2012-11-21 02:20:23 +01:00
|
|
|
memcpy(&client_sa, client, sizeof(irc::sockets::sockaddrs));
|
2009-11-01 21:53:47 +00:00
|
|
|
memcpy(&server_sa, servaddr, sizeof(irc::sockets::sockaddrs));
|
2012-11-21 02:20:23 +01:00
|
|
|
dhost = host = GetIPString();
|
2009-10-21 23:44:48 +00:00
|
|
|
}
|
|
|
|
|
2007-10-15 20:59:05 +00:00
|
|
|
User::~User()
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2014-03-14 13:04:10 +01:00
|
|
|
if (ServerInstance->FindUUID(uuid))
|
2013-04-12 02:10:06 +01:00
|
|
|
ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "User destructor for %s called without cull", uuid.c_str());
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2008-05-18 23:15:53 +00:00
|
|
|
const std::string& User::MakeHost()
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2008-05-18 23:15:53 +00:00
|
|
|
if (!this->cached_makehost.empty())
|
2007-07-16 17:30:04 +00:00
|
|
|
return this->cached_makehost;
|
|
|
|
|
2013-05-18 18:40:55 +01:00
|
|
|
// XXX: Is there really a need to cache this?
|
|
|
|
this->cached_makehost = ident + "@" + host;
|
2007-07-16 17:30:04 +00:00
|
|
|
return this->cached_makehost;
|
|
|
|
}
|
|
|
|
|
2008-05-18 23:15:53 +00:00
|
|
|
const std::string& User::MakeHostIP()
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2008-05-18 23:15:53 +00:00
|
|
|
if (!this->cached_hostip.empty())
|
2007-07-16 17:30:04 +00:00
|
|
|
return this->cached_hostip;
|
|
|
|
|
2013-05-18 18:40:55 +01:00
|
|
|
// XXX: Is there really a need to cache this?
|
|
|
|
this->cached_hostip = ident + "@" + this->GetIPString();
|
2007-07-16 17:30:04 +00:00
|
|
|
return this->cached_hostip;
|
|
|
|
}
|
|
|
|
|
2009-10-23 22:47:39 +00:00
|
|
|
const std::string& User::GetFullHost()
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2008-05-18 23:15:53 +00:00
|
|
|
if (!this->cached_fullhost.empty())
|
2007-07-16 17:30:04 +00:00
|
|
|
return this->cached_fullhost;
|
|
|
|
|
2013-05-18 18:40:55 +01:00
|
|
|
// XXX: Is there really a need to cache this?
|
|
|
|
this->cached_fullhost = nick + "!" + ident + "@" + dhost;
|
2007-07-16 17:30:04 +00:00
|
|
|
return this->cached_fullhost;
|
|
|
|
}
|
|
|
|
|
2009-10-23 22:47:39 +00:00
|
|
|
const std::string& User::GetFullRealHost()
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2008-05-18 23:15:53 +00:00
|
|
|
if (!this->cached_fullrealhost.empty())
|
2007-07-16 17:30:04 +00:00
|
|
|
return this->cached_fullrealhost;
|
|
|
|
|
2013-05-18 18:40:55 +01:00
|
|
|
// XXX: Is there really a need to cache this?
|
|
|
|
this->cached_fullrealhost = nick + "!" + ident + "@" + host;
|
2007-07-16 17:30:04 +00:00
|
|
|
return this->cached_fullrealhost;
|
|
|
|
}
|
|
|
|
|
2012-06-17 17:53:39 +02:00
|
|
|
InviteList& LocalUser::GetInviteList()
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2012-06-17 17:53:39 +02:00
|
|
|
RemoveExpiredInvites();
|
|
|
|
return invites;
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2013-04-01 18:00:17 +02:00
|
|
|
bool LocalUser::RemoveInvite(Channel* chan)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2013-04-01 18:00:17 +02:00
|
|
|
Invitation* inv = Invitation::Find(chan, this);
|
|
|
|
if (inv)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2013-04-01 18:00:17 +02:00
|
|
|
delete inv;
|
|
|
|
return true;
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
2013-04-01 18:00:17 +02:00
|
|
|
return false;
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2012-06-17 17:53:39 +02:00
|
|
|
void LocalUser::RemoveExpiredInvites()
|
|
|
|
{
|
|
|
|
Invitation::Find(NULL, this);
|
|
|
|
}
|
|
|
|
|
2009-10-21 23:45:32 +00:00
|
|
|
bool User::HasModePermission(unsigned char, ModeType)
|
2008-03-23 20:43:35 +00:00
|
|
|
{
|
2009-10-21 23:45:32 +00:00
|
|
|
return true;
|
|
|
|
}
|
2008-03-23 20:43:35 +00:00
|
|
|
|
2009-10-21 23:45:32 +00:00
|
|
|
bool LocalUser::HasModePermission(unsigned char mode, ModeType type)
|
|
|
|
{
|
2013-04-09 19:12:09 +02:00
|
|
|
if (!this->IsOper())
|
2008-03-23 20:43:35 +00:00
|
|
|
return false;
|
|
|
|
|
2008-09-13 15:47:01 +00:00
|
|
|
if (mode < 'A' || mode > ('A' + 64)) return false;
|
2008-03-23 21:12:36 +00:00
|
|
|
|
2009-10-21 23:46:05 +00:00
|
|
|
return ((type == MODETYPE_USER ? oper->AllowedUserModes : oper->AllowedChanModes))[(mode - 'A')];
|
2009-02-14 21:14:36 +00:00
|
|
|
|
2008-03-23 20:43:35 +00:00
|
|
|
}
|
2009-10-21 23:45:32 +00:00
|
|
|
/*
|
|
|
|
* users on remote servers can completely bypass all permissions based checks.
|
|
|
|
* This prevents desyncs when one server has different type/class tags to another.
|
|
|
|
* That having been said, this does open things up to the possibility of source changes
|
|
|
|
* allowing remote kills, etc - but if they have access to the src, they most likely have
|
|
|
|
* access to the conf - so it's an end to a means either way.
|
|
|
|
*/
|
|
|
|
bool User::HasPermission(const std::string&)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2009-10-21 23:45:32 +00:00
|
|
|
return true;
|
|
|
|
}
|
2007-07-16 17:30:04 +00:00
|
|
|
|
2009-10-21 23:45:32 +00:00
|
|
|
bool LocalUser::HasPermission(const std::string &command)
|
|
|
|
{
|
2007-07-16 17:30:04 +00:00
|
|
|
// are they even an oper at all?
|
2013-04-09 19:12:09 +02:00
|
|
|
if (!this->IsOper())
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2007-10-15 22:33:18 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-10-21 23:46:05 +00:00
|
|
|
if (oper->AllowedOperCommands.find(command) != oper->AllowedOperCommands.end())
|
2007-11-11 15:44:43 +00:00
|
|
|
return true;
|
2009-10-21 23:46:05 +00:00
|
|
|
else if (oper->AllowedOperCommands.find("*") != oper->AllowedOperCommands.end())
|
2007-11-11 15:44:43 +00:00
|
|
|
return true;
|
2007-10-15 22:33:18 +00:00
|
|
|
|
2007-07-16 17:30:04 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-10-18 16:52:48 +00:00
|
|
|
bool User::HasPrivPermission(const std::string &privstr, bool noisy)
|
2008-10-18 16:52:44 +00:00
|
|
|
{
|
2009-10-21 23:45:32 +00:00
|
|
|
return true;
|
|
|
|
}
|
2008-10-18 16:52:48 +00:00
|
|
|
|
2009-10-21 23:45:32 +00:00
|
|
|
bool LocalUser::HasPrivPermission(const std::string &privstr, bool noisy)
|
|
|
|
{
|
2013-04-09 19:12:09 +02:00
|
|
|
if (!this->IsOper())
|
2008-10-18 16:52:48 +00:00
|
|
|
{
|
|
|
|
if (noisy)
|
2013-04-28 12:17:53 +01:00
|
|
|
this->WriteNotice("You are not an oper");
|
2008-10-18 16:52:48 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-10-21 23:46:05 +00:00
|
|
|
if (oper->AllowedPrivs.find(privstr) != oper->AllowedPrivs.end())
|
2008-10-18 16:52:48 +00:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
2009-10-21 23:46:05 +00:00
|
|
|
else if (oper->AllowedPrivs.find("*") != oper->AllowedPrivs.end())
|
2008-10-18 16:52:48 +00:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (noisy)
|
2013-05-16 01:56:06 +02:00
|
|
|
this->WriteNotice("Oper type " + oper->name + " does not have access to priv " + privstr);
|
2013-04-28 12:17:53 +01:00
|
|
|
|
2008-10-18 16:52:48 +00:00
|
|
|
return false;
|
2008-10-18 16:52:44 +00:00
|
|
|
}
|
|
|
|
|
2009-11-06 22:37:36 +00:00
|
|
|
void UserIOHandler::OnDataReady()
|
2009-10-21 23:45:08 +00:00
|
|
|
{
|
2009-11-06 22:37:36 +00:00
|
|
|
if (user->quitting)
|
2009-09-21 13:26:31 +00:00
|
|
|
return;
|
2007-07-16 17:30:04 +00:00
|
|
|
|
2009-11-06 22:37:36 +00:00
|
|
|
if (recvq.length() > user->MyClass->GetRecvqMax() && !user->HasPrivPermission("users/flood/increased-buffers"))
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2009-11-06 22:37:36 +00:00
|
|
|
ServerInstance->Users->QuitUser(user, "RecvQ exceeded");
|
2009-09-21 13:26:31 +00:00
|
|
|
ServerInstance->SNO->WriteToSnoMask('a', "User %s RecvQ of %lu exceeds connect class maximum of %lu",
|
2009-11-06 22:37:36 +00:00
|
|
|
user->nick.c_str(), (unsigned long)recvq.length(), user->MyClass->GetRecvqMax());
|
2013-04-19 17:07:10 +02:00
|
|
|
return;
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
2009-09-26 16:41:07 +00:00
|
|
|
unsigned long sendqmax = ULONG_MAX;
|
2009-11-06 22:37:36 +00:00
|
|
|
if (!user->HasPrivPermission("users/flood/increased-buffers"))
|
|
|
|
sendqmax = user->MyClass->GetSendqSoftMax();
|
2009-11-11 19:52:03 +00:00
|
|
|
unsigned long penaltymax = ULONG_MAX;
|
|
|
|
if (!user->HasPrivPermission("users/flood/no-fakelag"))
|
|
|
|
penaltymax = user->MyClass->GetPenaltyThreshold() * 1000;
|
2008-05-07 21:53:30 +00:00
|
|
|
|
2009-11-11 19:52:03 +00:00
|
|
|
while (user->CommandFloodPenalty < penaltymax && getSendQSize() < sendqmax)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2009-09-21 13:26:31 +00:00
|
|
|
std::string line;
|
2013-05-17 01:34:25 +01:00
|
|
|
line.reserve(ServerInstance->Config->Limits.MaxLine);
|
2009-09-21 13:26:31 +00:00
|
|
|
std::string::size_type qpos = 0;
|
|
|
|
while (qpos < recvq.length())
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2009-09-21 13:26:31 +00:00
|
|
|
char c = recvq[qpos++];
|
|
|
|
switch (c)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2009-09-21 13:26:31 +00:00
|
|
|
case '\0':
|
|
|
|
c = ' ';
|
|
|
|
break;
|
|
|
|
case '\r':
|
|
|
|
continue;
|
|
|
|
case '\n':
|
|
|
|
goto eol_found;
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
2013-05-17 01:35:04 +01:00
|
|
|
if (line.length() < ServerInstance->Config->Limits.MaxLine - 2)
|
2009-09-21 13:26:31 +00:00
|
|
|
line.push_back(c);
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
2009-09-21 13:26:31 +00:00
|
|
|
// if we got here, the recvq ran out before we found a newline
|
|
|
|
return;
|
|
|
|
eol_found:
|
|
|
|
// just found a newline. Terminate the string, and pull it out of recvq
|
|
|
|
recvq = recvq.substr(qpos);
|
2007-07-16 17:30:04 +00:00
|
|
|
|
2009-09-21 13:26:31 +00:00
|
|
|
// TODO should this be moved to when it was inserted in recvq?
|
2014-06-13 15:03:56 +02:00
|
|
|
ServerInstance->stats.Recv += qpos;
|
2009-11-06 22:37:36 +00:00
|
|
|
user->bytes_in += qpos;
|
|
|
|
user->cmds_in++;
|
2009-09-21 13:26:31 +00:00
|
|
|
|
2014-06-13 15:45:55 +02:00
|
|
|
ServerInstance->Parser.ProcessBuffer(line, user);
|
2009-11-06 22:37:36 +00:00
|
|
|
if (user->quitting)
|
2009-10-19 21:10:10 +00:00
|
|
|
return;
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
2009-11-11 19:52:03 +00:00
|
|
|
if (user->CommandFloodPenalty >= penaltymax && !user->MyClass->fakelag)
|
|
|
|
ServerInstance->Users->QuitUser(user, "Excess Flood");
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2009-11-06 22:37:36 +00:00
|
|
|
void UserIOHandler::AddWriteBuf(const std::string &data)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2011-05-23 21:51:08 -04:00
|
|
|
if (user->quitting_sendq)
|
|
|
|
return;
|
2009-11-06 22:37:36 +00:00
|
|
|
if (!user->quitting && getSendQSize() + data.length() > user->MyClass->GetSendqHardMax() &&
|
|
|
|
!user->HasPrivPermission("users/flood/increased-buffers"))
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2011-05-23 21:51:08 -04:00
|
|
|
user->quitting_sendq = true;
|
|
|
|
ServerInstance->GlobalCulls.AddSQItem(user);
|
2007-07-16 17:30:04 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-03-18 10:28:10 +00:00
|
|
|
// We still want to append data to the sendq of a quitting user,
|
|
|
|
// e.g. their ERROR message that says 'closing link'
|
|
|
|
|
2009-09-21 13:26:31 +00:00
|
|
|
WriteData(data);
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2009-11-06 22:37:36 +00:00
|
|
|
void UserIOHandler::OnError(BufferedSocketError)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2009-11-06 22:37:36 +00:00
|
|
|
ServerInstance->Users->QuitUser(user, getError());
|
2009-09-21 13:26:31 +00:00
|
|
|
}
|
2007-08-23 22:06:04 +00:00
|
|
|
|
2009-10-17 18:52:39 +00:00
|
|
|
CullResult User::cull()
|
2009-09-21 13:26:31 +00:00
|
|
|
{
|
|
|
|
if (!quitting)
|
|
|
|
ServerInstance->Users->QuitUser(this, "Culled without QuitUser");
|
2009-09-30 17:12:08 +00:00
|
|
|
|
2009-11-01 21:53:47 +00:00
|
|
|
if (client_sa.sa.sa_family != AF_UNSPEC)
|
|
|
|
ServerInstance->Users->RemoveCloneCounts(this);
|
|
|
|
|
2009-10-17 18:52:39 +00:00
|
|
|
return Extensible::cull();
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2009-10-21 23:45:08 +00:00
|
|
|
CullResult LocalUser::cull()
|
|
|
|
{
|
2014-01-24 13:08:13 +01:00
|
|
|
ServerInstance->Users->local_users.erase(this);
|
2012-06-17 17:53:39 +02:00
|
|
|
ClearInvites();
|
2009-11-06 22:37:36 +00:00
|
|
|
eh.cull();
|
2009-10-21 23:45:08 +00:00
|
|
|
return User::cull();
|
|
|
|
}
|
|
|
|
|
2009-10-23 22:47:39 +00:00
|
|
|
CullResult FakeUser::cull()
|
|
|
|
{
|
|
|
|
// Fake users don't quit, they just get culled.
|
|
|
|
quitting = true;
|
2013-04-19 13:10:16 +02:00
|
|
|
// Fake users are not inserted into UserManager::clientlist, they're only in the uuidlist
|
2014-03-14 13:04:10 +01:00
|
|
|
ServerInstance->Users->uuidlist.erase(uuid);
|
2009-10-23 22:47:39 +00:00
|
|
|
return User::cull();
|
|
|
|
}
|
|
|
|
|
2009-10-21 23:45:44 +00:00
|
|
|
void User::Oper(OperInfo* info)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2013-06-18 19:17:39 +02:00
|
|
|
ModeHandler* opermh = ServerInstance->Modes->FindMode('o', MODETYPE_USER);
|
|
|
|
if (this->IsModeSet(opermh))
|
2008-08-27 19:47:33 +00:00
|
|
|
this->UnOper();
|
2008-08-27 19:23:17 +00:00
|
|
|
|
2013-06-18 19:17:39 +02:00
|
|
|
this->SetMode(opermh, true);
|
2009-10-21 23:45:44 +00:00
|
|
|
this->oper = info;
|
2014-02-05 13:49:16 +00:00
|
|
|
this->WriteCommand("MODE", "+o");
|
2013-06-26 17:01:33 -04:00
|
|
|
FOREACH_MOD(OnOper, (this, info->name));
|
2008-08-27 19:23:17 +00:00
|
|
|
|
2009-10-21 23:45:44 +00:00
|
|
|
std::string opername;
|
|
|
|
if (info->oper_block)
|
|
|
|
opername = info->oper_block->getString("name");
|
2008-08-27 19:23:17 +00:00
|
|
|
|
2009-10-23 19:07:40 +00:00
|
|
|
if (IS_LOCAL(this))
|
|
|
|
{
|
|
|
|
LocalUser* l = IS_LOCAL(this);
|
|
|
|
std::string vhost = oper->getConfig("vhost");
|
|
|
|
if (!vhost.empty())
|
|
|
|
l->ChangeDisplayedHost(vhost.c_str());
|
|
|
|
std::string opClass = oper->getConfig("class");
|
|
|
|
if (!opClass.empty())
|
|
|
|
l->SetClass(opClass);
|
|
|
|
}
|
|
|
|
|
2009-10-21 23:45:44 +00:00
|
|
|
ServerInstance->SNO->WriteToSnoMask('o',"%s (%s@%s) is now an IRC operator of type %s (using oper '%s')",
|
2013-05-16 01:56:06 +02:00
|
|
|
nick.c_str(), ident.c_str(), host.c_str(), oper->name.c_str(), opername.c_str());
|
2013-11-12 06:51:31 -05:00
|
|
|
this->WriteNumeric(RPL_YOUAREOPER, ":You are now %s %s", strchr("aeiouAEIOU", oper->name[0]) ? "an" : "a", oper->name.c_str());
|
2009-10-21 23:45:44 +00:00
|
|
|
|
2013-05-16 01:56:06 +02:00
|
|
|
ServerInstance->Logs->Log("OPER", LOG_DEFAULT, "%s opered as type: %s", GetFullRealHost().c_str(), oper->name.c_str());
|
2008-08-27 19:23:17 +00:00
|
|
|
ServerInstance->Users->all_opers.push_back(this);
|
|
|
|
|
2009-10-21 23:46:05 +00:00
|
|
|
// Expand permissions from config for faster lookup
|
2009-10-21 23:45:32 +00:00
|
|
|
if (IS_LOCAL(this))
|
2009-10-21 23:46:05 +00:00
|
|
|
oper->init();
|
2009-10-21 23:45:32 +00:00
|
|
|
|
2013-06-26 17:01:33 -04:00
|
|
|
FOREACH_MOD(OnPostOper, (this, oper->name, opername));
|
2009-10-21 23:45:32 +00:00
|
|
|
}
|
|
|
|
|
2009-10-21 23:46:05 +00:00
|
|
|
void OperInfo::init()
|
2009-10-21 23:45:32 +00:00
|
|
|
{
|
2009-10-21 23:46:05 +00:00
|
|
|
AllowedOperCommands.clear();
|
|
|
|
AllowedPrivs.clear();
|
2009-10-21 23:45:44 +00:00
|
|
|
AllowedUserModes.reset();
|
|
|
|
AllowedChanModes.reset();
|
2009-10-21 23:46:05 +00:00
|
|
|
AllowedUserModes['o' - 'A'] = true; // Call me paranoid if you want.
|
2009-10-21 23:45:44 +00:00
|
|
|
|
2009-10-21 23:46:05 +00:00
|
|
|
for(std::vector<reference<ConfigTag> >::iterator iter = class_blocks.begin(); iter != class_blocks.end(); ++iter)
|
2009-08-03 21:44:10 +00:00
|
|
|
{
|
2009-10-21 23:45:44 +00:00
|
|
|
ConfigTag* tag = *iter;
|
|
|
|
std::string mycmd, mypriv;
|
|
|
|
/* Process commands */
|
|
|
|
irc::spacesepstream CommandList(tag->getString("commands"));
|
|
|
|
while (CommandList.GetToken(mycmd))
|
2008-08-27 19:23:17 +00:00
|
|
|
{
|
2009-10-21 23:46:05 +00:00
|
|
|
AllowedOperCommands.insert(mycmd);
|
2009-10-21 23:45:44 +00:00
|
|
|
}
|
2009-08-03 21:44:10 +00:00
|
|
|
|
2009-10-21 23:45:44 +00:00
|
|
|
irc::spacesepstream PrivList(tag->getString("privs"));
|
|
|
|
while (PrivList.GetToken(mypriv))
|
|
|
|
{
|
2009-10-21 23:46:05 +00:00
|
|
|
AllowedPrivs.insert(mypriv);
|
2009-10-21 23:45:44 +00:00
|
|
|
}
|
2008-10-18 16:52:48 +00:00
|
|
|
|
2012-09-23 02:51:16 +02:00
|
|
|
std::string modes = tag->getString("usermodes");
|
|
|
|
for (std::string::const_iterator c = modes.begin(); c != modes.end(); ++c)
|
2009-10-21 23:45:44 +00:00
|
|
|
{
|
|
|
|
if (*c == '*')
|
|
|
|
{
|
|
|
|
this->AllowedUserModes.set();
|
|
|
|
}
|
2010-08-03 09:28:56 -04:00
|
|
|
else if (*c >= 'A' && *c < 'z')
|
2009-10-21 23:45:44 +00:00
|
|
|
{
|
|
|
|
this->AllowedUserModes[*c - 'A'] = true;
|
|
|
|
}
|
|
|
|
}
|
2009-08-03 21:44:10 +00:00
|
|
|
|
2012-09-23 02:51:16 +02:00
|
|
|
modes = tag->getString("chanmodes");
|
|
|
|
for (std::string::const_iterator c = modes.begin(); c != modes.end(); ++c)
|
2009-10-21 23:45:44 +00:00
|
|
|
{
|
|
|
|
if (*c == '*')
|
|
|
|
{
|
|
|
|
this->AllowedChanModes.set();
|
|
|
|
}
|
2010-08-03 09:28:56 -04:00
|
|
|
else if (*c >= 'A' && *c < 'z')
|
2009-10-21 23:45:44 +00:00
|
|
|
{
|
|
|
|
this->AllowedChanModes[*c - 'A'] = true;
|
2007-11-11 15:44:43 +00:00
|
|
|
}
|
|
|
|
}
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-15 20:59:05 +00:00
|
|
|
void User::UnOper()
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2013-04-09 19:12:09 +02:00
|
|
|
if (!this->IsOper())
|
2009-10-21 23:45:32 +00:00
|
|
|
return;
|
2008-08-27 21:37:28 +00:00
|
|
|
|
2009-10-21 23:45:32 +00:00
|
|
|
/*
|
|
|
|
* unset their oper type (what IS_OPER checks).
|
|
|
|
* note, order is important - this must come before modes as -o attempts
|
|
|
|
* to call UnOper. -- w00t
|
|
|
|
*/
|
2009-10-21 23:45:44 +00:00
|
|
|
oper = NULL;
|
2009-01-03 17:25:10 +00:00
|
|
|
|
2008-02-26 20:46:21 +00:00
|
|
|
|
2009-10-21 23:45:32 +00:00
|
|
|
/* Remove all oper only modes from the user when the deoper - Bug #466*/
|
|
|
|
std::string moderemove("-");
|
2008-02-26 20:46:21 +00:00
|
|
|
|
2009-10-21 23:45:32 +00:00
|
|
|
for (unsigned char letter = 'A'; letter <= 'z'; letter++)
|
|
|
|
{
|
|
|
|
ModeHandler* mh = ServerInstance->Modes->FindMode(letter, MODETYPE_USER);
|
|
|
|
if (mh && mh->NeedsOper())
|
|
|
|
moderemove += letter;
|
|
|
|
}
|
2009-01-03 17:25:10 +00:00
|
|
|
|
2008-05-04 21:37:36 +00:00
|
|
|
|
2009-10-21 23:45:32 +00:00
|
|
|
std::vector<std::string> parameters;
|
|
|
|
parameters.push_back(this->nick);
|
|
|
|
parameters.push_back(moderemove);
|
2009-01-03 17:25:10 +00:00
|
|
|
|
2013-08-04 19:13:52 +02:00
|
|
|
ServerInstance->Modes->Process(parameters, this);
|
2007-11-11 15:44:43 +00:00
|
|
|
|
2014-03-25 11:03:29 +01:00
|
|
|
// Remove the user from the oper list
|
|
|
|
stdalgo::vector::swaperase(ServerInstance->Users->all_opers, this);
|
2008-03-23 21:36:16 +00:00
|
|
|
|
2013-06-18 19:17:39 +02:00
|
|
|
ModeHandler* opermh = ServerInstance->Modes->FindMode('o', MODETYPE_USER);
|
|
|
|
this->SetMode(opermh, false);
|
2009-10-21 23:45:32 +00:00
|
|
|
}
|
2008-10-18 16:52:48 +00:00
|
|
|
|
2007-07-16 17:30:04 +00:00
|
|
|
/*
|
|
|
|
* Check class restrictions
|
|
|
|
*/
|
2013-07-01 12:31:36 -07:00
|
|
|
void LocalUser::CheckClass(bool clone_count)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2007-10-23 23:25:49 +00:00
|
|
|
ConnectClass* a = this->MyClass;
|
2007-07-16 17:30:04 +00:00
|
|
|
|
2009-10-21 23:45:32 +00:00
|
|
|
if (!a)
|
|
|
|
{
|
|
|
|
ServerInstance->Users->QuitUser(this, "Access denied by configuration");
|
2010-03-06 19:27:57 +00:00
|
|
|
return;
|
2009-10-21 23:45:32 +00:00
|
|
|
}
|
|
|
|
else if (a->type == CC_DENY)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2010-02-15 18:29:19 +00:00
|
|
|
ServerInstance->Users->QuitUser(this, a->config->getString("reason", "Unauthorised connection"));
|
2007-07-16 17:30:04 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-07-01 12:31:36 -07:00
|
|
|
else if (clone_count)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2014-03-17 11:05:09 +01:00
|
|
|
const UserManager::CloneCounts& clonecounts = ServerInstance->Users->GetCloneCounts(this);
|
|
|
|
if ((a->GetMaxLocal()) && (clonecounts.local > a->GetMaxLocal()))
|
2013-07-01 12:31:36 -07:00
|
|
|
{
|
|
|
|
ServerInstance->Users->QuitUser(this, "No more connections allowed from your host via this connect class (local)");
|
|
|
|
if (a->maxconnwarn)
|
|
|
|
ServerInstance->SNO->WriteToSnoMask('a', "WARNING: maximum LOCAL connections (%ld) exceeded for IP %s", a->GetMaxLocal(), this->GetIPString().c_str());
|
|
|
|
return;
|
|
|
|
}
|
2014-03-17 11:05:09 +01:00
|
|
|
else if ((a->GetMaxGlobal()) && (clonecounts.global > a->GetMaxGlobal()))
|
2013-07-01 12:31:36 -07:00
|
|
|
{
|
|
|
|
ServerInstance->Users->QuitUser(this, "No more connections allowed from your host via this connect class (global)");
|
|
|
|
if (a->maxconnwarn)
|
|
|
|
ServerInstance->SNO->WriteToSnoMask('a', "WARNING: maximum GLOBAL connections (%ld) exceeded for IP %s", a->GetMaxGlobal(), this->GetIPString().c_str());
|
|
|
|
return;
|
|
|
|
}
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
2007-08-06 19:55:09 +00:00
|
|
|
|
|
|
|
this->nping = ServerInstance->Time() + a->GetPingTime() + ServerInstance->Config->dns_timeout;
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2013-04-01 17:05:12 +02:00
|
|
|
bool LocalUser::CheckLines(bool doZline)
|
2008-04-12 15:48:01 +00:00
|
|
|
{
|
2008-09-29 08:13:49 +00:00
|
|
|
const char* check[] = { "G" , "K", (doZline) ? "Z" : NULL, NULL };
|
2009-02-14 21:14:36 +00:00
|
|
|
|
2008-04-12 15:48:01 +00:00
|
|
|
if (!this->exempt)
|
|
|
|
{
|
|
|
|
for (int n = 0; check[n]; ++n)
|
|
|
|
{
|
|
|
|
XLine *r = ServerInstance->XLines->MatchesLine(check[n], this);
|
|
|
|
|
|
|
|
if (r)
|
|
|
|
{
|
|
|
|
r->Apply(this);
|
2008-07-12 09:43:58 +00:00
|
|
|
return true;
|
2008-04-12 15:48:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-07-12 09:43:58 +00:00
|
|
|
|
|
|
|
return false;
|
2008-04-12 15:48:01 +00:00
|
|
|
}
|
|
|
|
|
2009-10-21 23:44:58 +00:00
|
|
|
void LocalUser::FullConnect()
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2014-06-13 15:03:56 +02:00
|
|
|
ServerInstance->stats.Connects++;
|
2007-07-16 17:30:04 +00:00
|
|
|
this->idle_lastmsg = ServerInstance->Time();
|
|
|
|
|
|
|
|
/*
|
2007-10-15 20:59:05 +00:00
|
|
|
* You may be thinking "wtf, we checked this in User::AddClient!" - and yes, we did, BUT.
|
2007-07-16 17:30:04 +00:00
|
|
|
* At the time AddClient is called, we don't have a resolved host, by here we probably do - which
|
|
|
|
* may put the user into a totally seperate class with different restrictions! so we *must* check again.
|
|
|
|
* Don't remove this! -- w00t
|
|
|
|
*/
|
2010-03-31 18:18:07 -05:00
|
|
|
MyClass = NULL;
|
2010-02-09 05:54:43 +00:00
|
|
|
SetClass();
|
2010-01-31 03:42:20 +00:00
|
|
|
CheckClass();
|
|
|
|
CheckLines();
|
2007-10-25 15:25:32 +00:00
|
|
|
|
2010-01-31 03:42:20 +00:00
|
|
|
if (quitting)
|
2008-07-12 09:43:58 +00:00
|
|
|
return;
|
2007-07-16 17:30:04 +00:00
|
|
|
|
2013-11-12 06:51:31 -05:00
|
|
|
this->WriteNumeric(RPL_WELCOME, ":Welcome to the %s IRC Network %s", ServerInstance->Config->Network.c_str(), GetFullRealHost().c_str());
|
2014-05-21 01:26:22 +01:00
|
|
|
this->WriteNumeric(RPL_YOURHOSTIS, ":Your host is %s, running version %s", ServerInstance->Config->ServerName.c_str(), INSPIRCD_BRANCH);
|
2013-11-12 06:51:31 -05:00
|
|
|
this->WriteNumeric(RPL_SERVERCREATED, ":This server was created %s %s", __TIME__, __DATE__);
|
2012-09-30 01:10:57 +02:00
|
|
|
|
2013-05-24 18:22:25 +02:00
|
|
|
const std::string& modelist = ServerInstance->Modes->GetModeListFor004Numeric();
|
2014-05-21 01:26:22 +01:00
|
|
|
this->WriteNumeric(RPL_SERVERVERSION, "%s %s %s", ServerInstance->Config->ServerName.c_str(), INSPIRCD_BRANCH, modelist.c_str());
|
2007-07-16 17:30:04 +00:00
|
|
|
|
2013-04-07 22:23:25 +01:00
|
|
|
ServerInstance->ISupport.SendTo(this);
|
2007-08-27 00:12:59 +00:00
|
|
|
|
2007-07-16 17:30:04 +00:00
|
|
|
/* Now registered */
|
2008-02-02 20:55:16 +00:00
|
|
|
if (ServerInstance->Users->unregistered_count)
|
|
|
|
ServerInstance->Users->unregistered_count--;
|
2007-07-16 17:30:04 +00:00
|
|
|
|
2010-01-19 04:43:19 +00:00
|
|
|
/* Trigger MOTD and LUSERS output, give modules a chance too */
|
2009-09-02 00:49:36 +00:00
|
|
|
ModResult MOD_RESULT;
|
2013-04-01 01:01:12 +02:00
|
|
|
std::string command("LUSERS");
|
2008-06-06 15:28:24 +00:00
|
|
|
std::vector<std::string> parameters;
|
2010-01-19 04:43:19 +00:00
|
|
|
FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, parameters, this, true, command));
|
|
|
|
if (!MOD_RESULT)
|
2014-06-13 15:45:55 +02:00
|
|
|
ServerInstance->Parser.CallHandler(command, parameters, this);
|
2010-01-19 04:43:19 +00:00
|
|
|
|
|
|
|
MOD_RESULT = MOD_RES_PASSTHRU;
|
2013-04-01 01:01:12 +02:00
|
|
|
command = "MOTD";
|
2010-01-19 04:43:19 +00:00
|
|
|
FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, parameters, this, true, command));
|
2007-07-16 17:30:04 +00:00
|
|
|
if (!MOD_RESULT)
|
2014-06-13 15:45:55 +02:00
|
|
|
ServerInstance->Parser.CallHandler(command, parameters, this);
|
2007-07-16 17:30:04 +00:00
|
|
|
|
2010-03-19 18:06:39 +00:00
|
|
|
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());
|
|
|
|
|
2007-07-16 17:30:04 +00:00
|
|
|
/*
|
2007-10-16 10:21:11 +00:00
|
|
|
* 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.
|
2007-07-16 17:30:04 +00:00
|
|
|
*/
|
2013-06-26 17:01:33 -04:00
|
|
|
FOREACH_MOD(OnUserConnect, (this));
|
2007-07-16 17:30:04 +00:00
|
|
|
|
|
|
|
this->registered = REG_ALL;
|
|
|
|
|
2013-06-26 17:01:33 -04:00
|
|
|
FOREACH_MOD(OnPostConnect, (this));
|
2007-07-16 17:30:04 +00:00
|
|
|
|
2012-10-21 15:10:44 +02:00
|
|
|
ServerInstance->SNO->WriteToSnoMask('c',"Client connecting on port %d (class %s): %s (%s) [%s]",
|
2013-04-01 01:27:02 +02:00
|
|
|
this->GetServerPort(), this->MyClass->name.c_str(), GetFullRealHost().c_str(), this->GetIPString().c_str(), this->fullname.c_str());
|
2013-04-12 02:10:06 +01:00
|
|
|
ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCache: Adding NEGATIVE hit for " + this->GetIPString());
|
2014-06-13 15:27:40 +02:00
|
|
|
ServerInstance->BanCache.AddHit(this->GetIPString(), "", "");
|
2010-03-23 14:51:43 +00:00
|
|
|
// reset the flood penalty (which could have been raised due to things like auto +x)
|
|
|
|
CommandFloodPenalty = 0;
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2007-10-15 20:59:05 +00:00
|
|
|
void User::InvalidateCache()
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
|
|
|
/* Invalidate cache */
|
2008-05-18 23:15:53 +00:00
|
|
|
cached_fullhost.clear();
|
|
|
|
cached_hostip.clear();
|
|
|
|
cached_makehost.clear();
|
|
|
|
cached_fullrealhost.clear();
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2014-07-03 12:27:24 +02:00
|
|
|
bool User::ChangeNick(const std::string& newnick, time_t newts)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2013-04-21 17:20:28 +02:00
|
|
|
if (quitting)
|
|
|
|
{
|
2013-04-28 00:32:14 +02:00
|
|
|
ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "ERROR: Attempted to change nick of a quitting user: " + this->nick);
|
2013-04-21 17:20:28 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-01-30 18:40:51 +00:00
|
|
|
if (assign(newnick) == assign(nick))
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2014-06-20 16:34:03 +02:00
|
|
|
// case change, don't need to check campers
|
2010-01-30 18:40:51 +00:00
|
|
|
// and, if it's identical including case, we can leave right now
|
2014-03-03 15:07:17 +01:00
|
|
|
// We also don't update the nick TS if it's a case change, either
|
2010-01-30 18:40:51 +00:00
|
|
|
if (newnick == nick)
|
|
|
|
return true;
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
2010-01-30 18:40:51 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* 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. */
|
2014-04-02 12:44:12 +02:00
|
|
|
InUse->WriteFrom(InUse, "NICK %s", InUse->uuid.c_str());
|
2013-11-12 06:51:31 -05:00
|
|
|
InUse->WriteNumeric(ERR_NICKNAMEINUSE, "%s :Nickname overruled.", InUse->nick.c_str());
|
2010-01-30 18:56:39 +00:00
|
|
|
|
2010-01-30 18:40:51 +00:00
|
|
|
InUse->registered &= ~REG_NICK;
|
2014-07-03 12:30:54 +02:00
|
|
|
InUse->ChangeNick(InUse->uuid);
|
2010-01-30 18:40:51 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* No camping, tell the incoming user to stop trying to change nick ;p */
|
2013-11-12 06:51:31 -05:00
|
|
|
this->WriteNumeric(ERR_NICKNAMEINUSE, "%s :Nickname is already in use.", newnick.c_str());
|
2010-01-30 18:56:39 +00:00
|
|
|
return false;
|
2010-01-30 18:40:51 +00:00
|
|
|
}
|
|
|
|
}
|
2014-03-03 15:07:17 +01:00
|
|
|
|
|
|
|
age = newts ? newts : ServerInstance->Time();
|
2010-01-30 18:40:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (this->registered == REG_ALL)
|
|
|
|
this->WriteCommon("NICK %s",newnick.c_str());
|
|
|
|
std::string oldnick = nick;
|
|
|
|
nick = newnick;
|
2010-01-30 18:56:39 +00:00
|
|
|
|
2010-01-30 18:40:51 +00:00
|
|
|
InvalidateCache();
|
2014-03-15 15:29:25 +01:00
|
|
|
ServerInstance->Users->clientlist.erase(oldnick);
|
|
|
|
ServerInstance->Users->clientlist[newnick] = this;
|
2010-01-30 18:56:39 +00:00
|
|
|
|
2010-02-01 01:18:34 +00:00
|
|
|
if (registered == REG_ALL)
|
2013-06-26 17:01:33 -04:00
|
|
|
FOREACH_MOD(OnUserPostNick, (this,oldnick));
|
2010-02-01 01:18:34 +00:00
|
|
|
|
2010-01-30 18:40:51 +00:00
|
|
|
return true;
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2009-10-21 23:45:08 +00:00
|
|
|
int LocalUser::GetServerPort()
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2009-09-01 15:07:36 +00:00
|
|
|
switch (this->server_sa.sa.sa_family)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
|
|
|
case AF_INET6:
|
2009-09-01 15:07:52 +00:00
|
|
|
return htons(this->server_sa.in6.sin6_port);
|
2007-07-16 17:30:04 +00:00
|
|
|
case AF_INET:
|
2009-09-01 15:07:52 +00:00
|
|
|
return htons(this->server_sa.in4.sin_port);
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-04-01 01:27:02 +02:00
|
|
|
const std::string& User::GetIPString()
|
2009-09-01 15:07:52 +00:00
|
|
|
{
|
|
|
|
int port;
|
|
|
|
if (cachedip.empty())
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2009-10-22 21:49:39 +00:00
|
|
|
irc::sockets::satoap(client_sa, cachedip, port);
|
2009-09-01 15:07:52 +00:00
|
|
|
/* IP addresses starting with a : on irc are a Bad Thing (tm) */
|
2013-04-01 01:27:02 +02:00
|
|
|
if (cachedip[0] == ':')
|
2013-08-31 01:17:07 +02:00
|
|
|
cachedip.insert(cachedip.begin(),1,'0');
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
2009-02-14 21:14:36 +00:00
|
|
|
|
2013-04-01 01:27:02 +02:00
|
|
|
return cachedip;
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2009-10-24 20:04:05 +00:00
|
|
|
irc::sockets::cidr_mask User::GetCIDRMask()
|
2009-10-22 21:49:39 +00:00
|
|
|
{
|
|
|
|
int range = 0;
|
|
|
|
switch (client_sa.sa.sa_family)
|
|
|
|
{
|
|
|
|
case AF_INET6:
|
|
|
|
range = ServerInstance->Config->c_ipv6_range;
|
|
|
|
break;
|
|
|
|
case AF_INET:
|
|
|
|
range = ServerInstance->Config->c_ipv4_range;
|
|
|
|
break;
|
|
|
|
}
|
2009-10-24 20:04:05 +00:00
|
|
|
return irc::sockets::cidr_mask(client_sa, range);
|
2009-10-22 21:49:39 +00:00
|
|
|
}
|
|
|
|
|
2013-03-03 23:13:54 +01:00
|
|
|
bool User::SetClientIP(const char* sip, bool recheck_eline)
|
2009-09-01 15:07:36 +00:00
|
|
|
{
|
2012-07-09 15:35:12 +02:00
|
|
|
cachedip.clear();
|
2012-11-21 02:20:23 +01:00
|
|
|
cached_hostip.clear();
|
2012-07-01 21:12:16 +02:00
|
|
|
return irc::sockets::aptosa(sip, 0, client_sa);
|
2009-09-01 15:07:36 +00:00
|
|
|
}
|
|
|
|
|
2013-03-03 23:13:54 +01:00
|
|
|
void User::SetClientIP(const irc::sockets::sockaddrs& sa, bool recheck_eline)
|
2012-07-09 15:35:12 +02:00
|
|
|
{
|
|
|
|
cachedip.clear();
|
2012-11-21 02:20:23 +01:00
|
|
|
cached_hostip.clear();
|
2012-07-09 15:35:12 +02:00
|
|
|
memcpy(&client_sa, &sa, sizeof(irc::sockets::sockaddrs));
|
|
|
|
}
|
|
|
|
|
2013-03-03 23:13:54 +01:00
|
|
|
bool LocalUser::SetClientIP(const char* sip, bool recheck_eline)
|
2012-07-09 15:35:12 +02:00
|
|
|
{
|
|
|
|
irc::sockets::sockaddrs sa;
|
|
|
|
if (!irc::sockets::aptosa(sip, 0, sa))
|
|
|
|
// Invalid
|
|
|
|
return false;
|
|
|
|
|
2013-03-03 23:13:54 +01:00
|
|
|
LocalUser::SetClientIP(sa, recheck_eline);
|
2012-07-09 15:35:12 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-03-03 23:13:54 +01:00
|
|
|
void LocalUser::SetClientIP(const irc::sockets::sockaddrs& sa, bool recheck_eline)
|
2012-07-09 15:35:12 +02:00
|
|
|
{
|
|
|
|
if (sa != client_sa)
|
|
|
|
{
|
|
|
|
User::SetClientIP(sa);
|
2013-03-03 23:13:54 +01:00
|
|
|
if (recheck_eline)
|
|
|
|
this->exempt = (ServerInstance->XLines->MatchesLine("E", this) != NULL);
|
|
|
|
|
2013-06-26 17:01:33 -04:00
|
|
|
FOREACH_MOD(OnSetUserIP, (this));
|
2012-07-09 15:35:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-21 13:26:31 +00:00
|
|
|
static std::string wide_newline("\r\n");
|
|
|
|
|
2009-09-02 00:45:29 +00:00
|
|
|
void User::Write(const std::string& text)
|
2009-10-21 23:45:08 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void User::Write(const char *text, ...)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void LocalUser::Write(const std::string& text)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2014-02-08 23:01:44 +01:00
|
|
|
if (!SocketEngine::BoundsCheckFd(&eh))
|
2007-07-16 17:30:04 +00:00
|
|
|
return;
|
|
|
|
|
2013-05-17 01:35:04 +01:00
|
|
|
if (text.length() > ServerInstance->Config->Limits.MaxLine - 2)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2009-09-21 13:26:31 +00:00
|
|
|
// this should happen rarely or never. Crop the string at 512 and try again.
|
2013-05-17 01:35:04 +01:00
|
|
|
std::string try_again = text.substr(0, ServerInstance->Config->Limits.MaxLine - 2);
|
2009-09-21 13:26:31 +00:00
|
|
|
Write(try_again);
|
|
|
|
return;
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
2009-09-21 13:26:31 +00:00
|
|
|
|
2013-04-12 02:10:06 +01:00
|
|
|
ServerInstance->Logs->Log("USEROUTPUT", LOG_RAWIO, "C[%s] O %s", uuid.c_str(), text.c_str());
|
2009-09-21 13:26:31 +00:00
|
|
|
|
2009-11-06 22:37:36 +00:00
|
|
|
eh.AddWriteBuf(text);
|
|
|
|
eh.AddWriteBuf(wide_newline);
|
2009-09-21 13:26:31 +00:00
|
|
|
|
2014-06-13 15:03:56 +02:00
|
|
|
ServerInstance->stats.Sent += text.length() + 2;
|
2009-09-21 13:26:31 +00:00
|
|
|
this->bytes_out += text.length() + 2;
|
|
|
|
this->cmds_out++;
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Write()
|
|
|
|
*/
|
2009-10-21 23:45:08 +00:00
|
|
|
void LocalUser::Write(const char *text, ...)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2013-05-18 11:35:10 -07:00
|
|
|
std::string textbuffer;
|
|
|
|
VAFORMAT(textbuffer, text, text);
|
|
|
|
this->Write(textbuffer);
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2007-10-15 20:59:05 +00:00
|
|
|
void User::WriteServ(const std::string& text)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2009-10-03 01:52:59 +00:00
|
|
|
this->Write(":%s %s",ServerInstance->Config->ServerName.c_str(),text.c_str());
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** WriteServ()
|
|
|
|
* Same as Write(), except `text' is prefixed with `:server.name '.
|
|
|
|
*/
|
2007-10-15 20:59:05 +00:00
|
|
|
void User::WriteServ(const char* text, ...)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2013-05-18 11:35:10 -07:00
|
|
|
std::string textbuffer;
|
|
|
|
VAFORMAT(textbuffer, text, text);
|
|
|
|
this->WriteServ(textbuffer);
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2014-02-05 13:49:16 +00:00
|
|
|
void User::WriteCommand(const char* command, const std::string& text)
|
2013-04-28 12:17:53 +01:00
|
|
|
{
|
2014-02-05 13:49:16 +00:00
|
|
|
this->WriteServ(command + (this->registered & REG_NICK ? " " + this->nick : " *") + " " + text);
|
2013-04-28 12:17:53 +01:00
|
|
|
}
|
2007-07-16 17:30:04 +00:00
|
|
|
|
2008-03-22 11:45:57 +00:00
|
|
|
void User::WriteNumeric(unsigned int numeric, const char* text, ...)
|
|
|
|
{
|
2013-05-18 11:35:10 -07:00
|
|
|
std::string textbuffer;
|
|
|
|
VAFORMAT(textbuffer, text, text);
|
|
|
|
this->WriteNumeric(numeric, textbuffer);
|
2008-03-22 11:45:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void User::WriteNumeric(unsigned int numeric, const std::string &text)
|
|
|
|
{
|
2009-09-02 00:49:36 +00:00
|
|
|
ModResult MOD_RESULT;
|
2008-03-22 11:45:57 +00:00
|
|
|
|
2009-09-26 14:13:13 +00:00
|
|
|
FIRST_MOD_RESULT(OnNumeric, MOD_RESULT, (this, numeric, text));
|
2008-03-22 11:45:57 +00:00
|
|
|
|
2009-09-02 00:49:36 +00:00
|
|
|
if (MOD_RESULT == MOD_RES_DENY)
|
2008-03-22 11:45:57 +00:00
|
|
|
return;
|
2014-01-23 14:37:09 +01:00
|
|
|
|
2013-11-12 06:51:31 -05:00
|
|
|
const std::string message = InspIRCd::Format(":%s %03u %s %s", ServerInstance->Config->ServerName.c_str(),
|
2014-02-05 13:49:16 +00:00
|
|
|
numeric, this->registered & REG_NICK ? this->nick.c_str() : "*", text.c_str());
|
2013-05-18 17:18:12 +01:00
|
|
|
this->Write(message);
|
2008-03-22 11:45:57 +00:00
|
|
|
}
|
|
|
|
|
2007-10-15 20:59:05 +00:00
|
|
|
void User::WriteFrom(User *user, const std::string &text)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2013-05-06 11:49:50 +01:00
|
|
|
const std::string message = ":" + user->GetFullHost() + " " + text;
|
|
|
|
this->Write(message);
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* write text from an originating user to originating user */
|
|
|
|
|
2007-10-15 20:59:05 +00:00
|
|
|
void User::WriteFrom(User *user, const char* text, ...)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2013-05-18 11:35:10 -07:00
|
|
|
std::string textbuffer;
|
|
|
|
VAFORMAT(textbuffer, text, text);
|
|
|
|
this->WriteFrom(user, textbuffer);
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2007-10-15 20:59:05 +00:00
|
|
|
void User::WriteCommon(const char* text, ...)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2009-10-12 13:20:47 +00:00
|
|
|
if (this->registered != REG_ALL || quitting)
|
2007-07-16 17:30:04 +00:00
|
|
|
return;
|
|
|
|
|
2013-05-18 11:35:10 -07:00
|
|
|
std::string textbuffer;
|
|
|
|
VAFORMAT(textbuffer, text, text);
|
|
|
|
textbuffer = ":" + this->GetFullHost() + " " + textbuffer;
|
|
|
|
this->WriteCommonRaw(textbuffer, true);
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2009-10-05 23:27:46 +00:00
|
|
|
void User::WriteCommonRaw(const std::string &line, bool include_self)
|
|
|
|
{
|
2009-10-12 13:20:47 +00:00
|
|
|
if (this->registered != REG_ALL || quitting)
|
2009-10-05 23:27:46 +00:00
|
|
|
return;
|
2007-07-16 17:30:04 +00:00
|
|
|
|
2010-02-12 22:30:27 +00:00
|
|
|
LocalUser::already_sent_id++;
|
2009-10-05 23:27:46 +00:00
|
|
|
|
2014-01-24 12:58:01 +01:00
|
|
|
IncludeChanList include_c(chans.begin(), chans.end());
|
2009-10-05 23:27:46 +00:00
|
|
|
std::map<User*,bool> exceptions;
|
2008-04-02 17:08:09 +00:00
|
|
|
|
2009-10-05 23:27:46 +00:00
|
|
|
exceptions[this] = include_self;
|
2007-07-16 17:30:04 +00:00
|
|
|
|
2013-06-26 17:01:33 -04:00
|
|
|
FOREACH_MOD(OnBuildNeighborList, (this, include_c, exceptions));
|
2009-10-05 23:27:46 +00:00
|
|
|
|
|
|
|
for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i)
|
2008-02-09 13:06:02 +00:00
|
|
|
{
|
2009-10-25 15:21:45 +00:00
|
|
|
LocalUser* u = IS_LOCAL(i->first);
|
|
|
|
if (u && !u->quitting)
|
2009-10-05 23:27:46 +00:00
|
|
|
{
|
2010-02-12 22:30:27 +00:00
|
|
|
u->already_sent = LocalUser::already_sent_id;
|
2009-10-05 23:27:46 +00:00
|
|
|
if (i->second)
|
|
|
|
u->Write(line);
|
|
|
|
}
|
|
|
|
}
|
2014-01-24 12:58:01 +01:00
|
|
|
for (IncludeChanList::const_iterator v = include_c.begin(); v != include_c.end(); ++v)
|
2009-10-05 23:27:46 +00:00
|
|
|
{
|
2014-01-24 12:58:01 +01:00
|
|
|
Channel* c = (*v)->chan;
|
2009-10-05 23:27:46 +00:00
|
|
|
const UserMembList* ulist = c->GetUsers();
|
2009-09-13 20:30:47 +00:00
|
|
|
for (UserMembList::const_iterator i = ulist->begin(); i != ulist->end(); i++)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2009-10-25 15:21:45 +00:00
|
|
|
LocalUser* u = IS_LOCAL(i->first);
|
2014-01-25 12:15:01 +01:00
|
|
|
if (u && u->already_sent != LocalUser::already_sent_id)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2010-02-12 22:30:27 +00:00
|
|
|
u->already_sent = LocalUser::already_sent_id;
|
2009-10-05 23:27:46 +00:00
|
|
|
u->Write(line);
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-15 20:59:05 +00:00
|
|
|
void User::WriteCommonQuit(const std::string &normal_text, const std::string &oper_text)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
|
|
|
if (this->registered != REG_ALL)
|
|
|
|
return;
|
|
|
|
|
2010-02-12 22:30:27 +00:00
|
|
|
already_sent_t uniq_id = ++LocalUser::already_sent_id;
|
2008-04-02 17:08:09 +00:00
|
|
|
|
2013-05-06 11:49:50 +01:00
|
|
|
const std::string normalMessage = ":" + this->GetFullHost() + " QUIT :" + normal_text;
|
|
|
|
const std::string operMessage = ":" + this->GetFullHost() + " QUIT :" + oper_text;
|
2007-07-16 17:30:04 +00:00
|
|
|
|
2014-01-24 12:58:01 +01:00
|
|
|
IncludeChanList include_c(chans.begin(), chans.end());
|
2009-10-05 23:27:46 +00:00
|
|
|
std::map<User*,bool> exceptions;
|
|
|
|
|
2013-06-26 17:01:33 -04:00
|
|
|
FOREACH_MOD(OnBuildNeighborList, (this, include_c, exceptions));
|
2009-10-05 23:27:46 +00:00
|
|
|
|
|
|
|
for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2009-10-25 15:21:45 +00:00
|
|
|
LocalUser* u = IS_LOCAL(i->first);
|
|
|
|
if (u && !u->quitting)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2010-02-12 22:30:27 +00:00
|
|
|
u->already_sent = uniq_id;
|
2009-10-05 23:27:46 +00:00
|
|
|
if (i->second)
|
2013-05-06 11:49:50 +01:00
|
|
|
u->Write(u->IsOper() ? operMessage : normalMessage);
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
}
|
2014-01-24 12:58:01 +01:00
|
|
|
for (IncludeChanList::const_iterator v = include_c.begin(); v != include_c.end(); ++v)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2014-01-24 12:58:01 +01:00
|
|
|
const UserMembList* ulist = (*v)->chan->GetUsers();
|
2009-09-13 20:30:47 +00:00
|
|
|
for (UserMembList::const_iterator i = ulist->begin(); i != ulist->end(); i++)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2009-10-25 15:21:45 +00:00
|
|
|
LocalUser* u = IS_LOCAL(i->first);
|
2014-01-25 12:15:01 +01:00
|
|
|
if (u && (u->already_sent != uniq_id))
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2010-02-12 22:30:27 +00:00
|
|
|
u->already_sent = uniq_id;
|
2013-05-06 11:49:50 +01:00
|
|
|
u->Write(u->IsOper() ? operMessage : normalMessage);
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-21 23:44:48 +00:00
|
|
|
void LocalUser::SendText(const std::string& line)
|
|
|
|
{
|
|
|
|
Write(line);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RemoteUser::SendText(const std::string& line)
|
|
|
|
{
|
|
|
|
ServerInstance->PI->PushToClient(this, line);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FakeUser::SendText(const std::string& line)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2009-10-20 04:40:27 +00:00
|
|
|
void User::SendText(const char *text, ...)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2013-05-18 11:35:10 -07:00
|
|
|
std::string line;
|
|
|
|
VAFORMAT(line, text, text);
|
|
|
|
SendText(line);
|
2009-10-20 04:40:27 +00:00
|
|
|
}
|
|
|
|
|
2013-05-20 20:15:50 +01:00
|
|
|
void User::SendText(const std::string& linePrefix, std::stringstream& textStream)
|
|
|
|
{
|
|
|
|
std::string line;
|
|
|
|
std::string word;
|
|
|
|
while (textStream >> word)
|
2009-10-20 04:40:27 +00:00
|
|
|
{
|
2013-05-20 20:15:50 +01:00
|
|
|
size_t lineLength = linePrefix.length() + line.length() + word.length() + 3; // "\s\n\r"
|
|
|
|
if (lineLength > ServerInstance->Config->Limits.MaxLine)
|
2009-10-20 04:40:27 +00:00
|
|
|
{
|
2013-05-20 20:15:50 +01:00
|
|
|
SendText(linePrefix + line);
|
|
|
|
line.clear();
|
2009-10-20 04:40:27 +00:00
|
|
|
}
|
2013-05-20 20:15:50 +01:00
|
|
|
line += " " + word;
|
2009-10-20 04:40:27 +00:00
|
|
|
}
|
2013-05-20 20:15:50 +01:00
|
|
|
SendText(linePrefix + line);
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* return 0 or 1 depending if users u and u2 share one or more common channels
|
|
|
|
* (used by QUIT, NICK etc which arent channel specific notices)
|
|
|
|
*
|
|
|
|
* The old algorithm in 1.0 for this was relatively inefficient, iterating over
|
|
|
|
* the first users channels then the second users channels within the outer loop,
|
|
|
|
* therefore it was a maximum of x*y iterations (upon returning 0 and checking
|
|
|
|
* all possible iterations). However this new function instead checks against the
|
2007-10-15 20:59:05 +00:00
|
|
|
* channel's userlist in the inner loop which is a std::map<User*,User*>
|
2007-07-16 17:30:04 +00:00
|
|
|
* and saves us time as we already know what pointer value we are after.
|
|
|
|
* Don't quote me on the maths as i am not a mathematician or computer scientist,
|
|
|
|
* but i believe this algorithm is now x+(log y) maximum iterations instead.
|
|
|
|
*/
|
2007-10-15 20:59:05 +00:00
|
|
|
bool User::SharesChannelWith(User *other)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
|
|
|
/* Outer loop */
|
|
|
|
for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)
|
|
|
|
{
|
|
|
|
/* Eliminate the inner loop (which used to be ~equal in size to the outer loop)
|
|
|
|
* by replacing it with a map::find which *should* be more efficient
|
|
|
|
*/
|
2014-01-24 12:58:01 +01:00
|
|
|
if ((*i)->chan->HasUser(other))
|
2007-07-16 17:30:04 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-08-09 18:20:12 +02:00
|
|
|
bool User::ChangeName(const std::string& gecos)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2008-05-18 23:15:53 +00:00
|
|
|
if (!this->fullname.compare(gecos))
|
2007-07-16 17:30:04 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
if (IS_LOCAL(this))
|
|
|
|
{
|
2009-09-02 00:49:36 +00:00
|
|
|
ModResult MOD_RESULT;
|
2009-10-21 23:45:19 +00:00
|
|
|
FIRST_MOD_RESULT(OnChangeLocalUserGECOS, MOD_RESULT, (IS_LOCAL(this),gecos));
|
2009-09-02 00:49:36 +00:00
|
|
|
if (MOD_RESULT == MOD_RES_DENY)
|
2007-07-16 17:30:04 +00:00
|
|
|
return false;
|
2013-06-26 17:01:33 -04:00
|
|
|
FOREACH_MOD(OnChangeName, (this,gecos));
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
2008-05-25 17:30:43 +00:00
|
|
|
this->fullname.assign(gecos, 0, ServerInstance->Config->Limits.MaxGecos);
|
2007-07-16 17:30:04 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-08-09 18:20:12 +02:00
|
|
|
bool User::ChangeDisplayedHost(const std::string& shost)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2008-05-23 05:15:49 +00:00
|
|
|
if (dhost == shost)
|
2007-07-16 17:30:04 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
if (IS_LOCAL(this))
|
|
|
|
{
|
2009-09-02 00:49:36 +00:00
|
|
|
ModResult MOD_RESULT;
|
2009-10-21 23:45:19 +00:00
|
|
|
FIRST_MOD_RESULT(OnChangeLocalUserHost, MOD_RESULT, (IS_LOCAL(this),shost));
|
2009-09-02 00:49:36 +00:00
|
|
|
if (MOD_RESULT == MOD_RES_DENY)
|
2007-07-16 17:30:04 +00:00
|
|
|
return false;
|
|
|
|
}
|
2008-02-09 13:06:02 +00:00
|
|
|
|
2013-06-26 17:01:33 -04:00
|
|
|
FOREACH_MOD(OnChangeHost, (this,shost));
|
2008-10-25 12:21:14 +00:00
|
|
|
|
2014-03-06 21:43:36 +00:00
|
|
|
this->dhost.assign(shost, 0, ServerInstance->Config->Limits.MaxHost);
|
2007-07-16 17:30:04 +00:00
|
|
|
this->InvalidateCache();
|
|
|
|
|
|
|
|
if (IS_LOCAL(this))
|
2013-11-12 06:51:31 -05:00
|
|
|
this->WriteNumeric(RPL_YOURDISPLAYEDHOST, "%s :is now your displayed host", this->dhost.c_str());
|
2007-07-16 17:30:04 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-08-09 18:20:12 +02:00
|
|
|
bool User::ChangeIdent(const std::string& newident)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2008-10-02 22:27:03 +00:00
|
|
|
if (this->ident == newident)
|
2007-07-16 17:30:04 +00:00
|
|
|
return true;
|
|
|
|
|
2013-06-26 17:01:33 -04:00
|
|
|
FOREACH_MOD(OnChangeIdent, (this,newident));
|
2009-09-02 00:52:12 +00:00
|
|
|
|
2012-12-09 18:06:21 +01:00
|
|
|
this->ident.assign(newident, 0, ServerInstance->Config->Limits.IdentMax);
|
2007-07-16 17:30:04 +00:00
|
|
|
this->InvalidateCache();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-10-23 23:25:49 +00:00
|
|
|
/*
|
|
|
|
* Sets a user's connection class.
|
|
|
|
* If the class name is provided, it will be used. Otherwise, the class will be guessed using host/ip/ident/etc.
|
2007-07-16 17:30:04 +00:00
|
|
|
* NOTE: If the <ALLOW> or <DENY> tag specifies an ip, and this user resolves,
|
|
|
|
* then their ip will be taken as 'priority' anyway, so for example,
|
|
|
|
* <connect allow="127.0.0.1"> will match joe!bloggs@localhost
|
|
|
|
*/
|
2009-10-21 23:45:32 +00:00
|
|
|
void LocalUser::SetClass(const std::string &explicit_name)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2007-10-23 23:31:40 +00:00
|
|
|
ConnectClass *found = NULL;
|
|
|
|
|
2013-04-12 02:10:06 +01:00
|
|
|
ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Setting connect class for UID %s", this->uuid.c_str());
|
2008-05-18 17:25:29 +00:00
|
|
|
|
2007-08-19 19:23:53 +00:00
|
|
|
if (!explicit_name.empty())
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2007-08-19 19:23:53 +00:00
|
|
|
for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2007-10-24 15:48:00 +00:00
|
|
|
ConnectClass* c = *i;
|
|
|
|
|
2009-08-12 18:03:52 +00:00
|
|
|
if (explicit_name == c->name)
|
2007-10-23 23:07:24 +00:00
|
|
|
{
|
2013-04-12 02:10:06 +01:00
|
|
|
ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Explicitly set to %s", explicit_name.c_str());
|
2007-10-24 15:48:00 +00:00
|
|
|
found = c;
|
2007-10-23 23:07:24 +00:00
|
|
|
}
|
2007-08-19 19:23:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
|
|
|
|
{
|
2007-10-24 15:48:00 +00:00
|
|
|
ConnectClass* c = *i;
|
2013-04-12 02:10:06 +01:00
|
|
|
ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Checking %s", c->GetName().c_str());
|
2007-10-24 15:48:00 +00:00
|
|
|
|
2010-02-02 15:02:33 +00:00
|
|
|
ModResult MOD_RESULT;
|
|
|
|
FIRST_MOD_RESULT(OnSetConnectClass, MOD_RESULT, (this,c));
|
|
|
|
if (MOD_RESULT == MOD_RES_DENY)
|
|
|
|
continue;
|
|
|
|
if (MOD_RESULT == MOD_RES_ALLOW)
|
2008-05-18 17:41:04 +00:00
|
|
|
{
|
2013-04-12 02:10:06 +01:00
|
|
|
ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Class forced by module to %s", c->GetName().c_str());
|
2010-02-02 15:02:33 +00:00
|
|
|
found = c;
|
|
|
|
break;
|
2008-05-18 17:41:04 +00:00
|
|
|
}
|
2010-02-02 15:02:33 +00:00
|
|
|
|
|
|
|
if (c->type == CC_NAMED)
|
2010-01-31 03:42:20 +00:00
|
|
|
continue;
|
2008-05-18 17:41:04 +00:00
|
|
|
|
2010-02-09 05:54:43 +00:00
|
|
|
bool regdone = (registered != REG_NONE);
|
|
|
|
if (c->config->getBool("registered", regdone) != regdone)
|
|
|
|
continue;
|
|
|
|
|
2008-05-18 17:16:55 +00:00
|
|
|
/* check if host matches.. */
|
2011-07-17 19:49:03 -04:00
|
|
|
if (!InspIRCd::MatchCIDR(this->GetIPString(), c->GetHost(), NULL) &&
|
2008-08-21 20:56:16 +00:00
|
|
|
!InspIRCd::MatchCIDR(this->host, c->GetHost(), NULL))
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2013-04-12 02:10:06 +01:00
|
|
|
ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "No host match (for %s)", c->GetHost().c_str());
|
2008-05-18 17:16:55 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* deny change if change will take class over the limit check it HERE, not after we found a matching class,
|
|
|
|
* because we should attempt to find another class if this one doesn't match us. -- w00t
|
|
|
|
*/
|
2009-09-30 21:55:21 +00:00
|
|
|
if (c->limit && (c->GetReferenceCount() >= c->limit))
|
2008-05-18 17:16:55 +00:00
|
|
|
{
|
2013-04-12 02:10:06 +01:00
|
|
|
ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "OOPS: Connect class limit (%lu) hit, denying", c->limit);
|
2008-05-18 17:16:55 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if it requires a port ... */
|
2010-02-02 15:02:33 +00:00
|
|
|
int port = c->config->getInt("port");
|
|
|
|
if (port)
|
2008-05-18 17:16:55 +00:00
|
|
|
{
|
2013-04-12 02:10:06 +01:00
|
|
|
ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Requires port (%d)", port);
|
2008-05-18 17:25:29 +00:00
|
|
|
|
2008-05-18 17:16:55 +00:00
|
|
|
/* and our port doesn't match, fail. */
|
2010-02-02 15:02:33 +00:00
|
|
|
if (this->GetServerPort() != port)
|
2008-05-18 17:16:55 +00:00
|
|
|
continue;
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
2008-05-18 17:16:55 +00:00
|
|
|
|
2010-03-31 09:32:05 -05:00
|
|
|
if (regdone && !c->config->getString("password").empty())
|
2010-02-09 05:54:43 +00:00
|
|
|
{
|
2014-01-18 04:53:52 +00:00
|
|
|
if (!ServerInstance->PassCompare(this, c->config->getString("password"), password, c->config->getString("hash")))
|
2010-02-09 05:54:43 +00:00
|
|
|
{
|
2013-04-12 02:10:06 +01:00
|
|
|
ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Bad password, skipping");
|
2010-02-09 05:54:43 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2010-02-09 05:35:19 +00:00
|
|
|
|
2008-05-18 18:23:30 +00:00
|
|
|
/* we stop at the first class that meets ALL critera. */
|
2008-05-18 17:16:55 +00:00
|
|
|
found = c;
|
2008-05-18 18:23:30 +00:00
|
|
|
break;
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
}
|
2007-10-23 23:07:24 +00:00
|
|
|
|
2008-05-18 17:16:55 +00:00
|
|
|
/*
|
|
|
|
* Okay, assuming we found a class that matches.. switch us into that class, keeping refcounts up to date.
|
|
|
|
*/
|
2007-10-23 23:31:40 +00:00
|
|
|
if (found)
|
|
|
|
{
|
2009-09-30 21:55:21 +00:00
|
|
|
MyClass = found;
|
2007-10-23 23:31:40 +00:00
|
|
|
}
|
2007-10-23 23:25:49 +00:00
|
|
|
}
|
|
|
|
|
2007-10-15 20:59:05 +00:00
|
|
|
void User::PurgeEmptyChannels()
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
|
|
|
// firstly decrement the count on each channel
|
2014-01-24 12:58:01 +01:00
|
|
|
for (UCListIter i = this->chans.begin(); i != this->chans.end(); )
|
2007-07-16 17:30:04 +00:00
|
|
|
{
|
2014-01-24 12:58:01 +01:00
|
|
|
Channel* c = (*i)->chan;
|
|
|
|
++i;
|
2009-10-18 02:57:46 +00:00
|
|
|
c->DelUser(this);
|
2007-07-16 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this->UnOper();
|
|
|
|
}
|
|
|
|
|
2009-10-23 22:47:39 +00:00
|
|
|
const std::string& FakeUser::GetFullHost()
|
2009-05-13 17:43:35 +00:00
|
|
|
{
|
2009-10-05 14:06:03 +00:00
|
|
|
if (!ServerInstance->Config->HideWhoisServer.empty())
|
2009-05-13 17:43:35 +00:00
|
|
|
return ServerInstance->Config->HideWhoisServer;
|
2014-01-05 15:04:01 +01:00
|
|
|
return server->GetName();
|
2009-05-13 17:43:35 +00:00
|
|
|
}
|
|
|
|
|
2009-10-23 22:47:39 +00:00
|
|
|
const std::string& FakeUser::GetFullRealHost()
|
2009-05-13 17:43:35 +00:00
|
|
|
{
|
2009-10-03 01:52:59 +00:00
|
|
|
if (!ServerInstance->Config->HideWhoisServer.empty())
|
2009-05-13 17:43:35 +00:00
|
|
|
return ServerInstance->Config->HideWhoisServer;
|
2014-01-05 15:04:01 +01:00
|
|
|
return server->GetName();
|
2009-05-13 17:43:35 +00:00
|
|
|
}
|
|
|
|
|
2009-10-17 02:40:16 +00:00
|
|
|
ConnectClass::ConnectClass(ConfigTag* tag, char t, const std::string& mask)
|
2009-11-11 19:52:03 +00:00
|
|
|
: config(tag), type(t), fakelag(true), name("unnamed"), registration_timeout(0), host(mask),
|
2010-02-02 15:02:33 +00:00
|
|
|
pingtime(0), softsendqmax(0), hardsendqmax(0), recvqmax(0),
|
2014-03-19 20:52:56 +00:00
|
|
|
penaltythreshold(0), commandrate(0), maxlocal(0), maxglobal(0), maxconnwarn(true), maxchans(ServerInstance->Config->MaxChans),
|
2013-07-10 12:46:01 +01:00
|
|
|
limit(0), resolvehostnames(true)
|
2009-08-12 18:03:52 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2009-10-17 02:40:16 +00:00
|
|
|
ConnectClass::ConnectClass(ConfigTag* tag, char t, const std::string& mask, const ConnectClass& parent)
|
2009-11-11 19:52:03 +00:00
|
|
|
: config(tag), type(t), fakelag(parent.fakelag), name("unnamed"),
|
|
|
|
registration_timeout(parent.registration_timeout), host(mask), pingtime(parent.pingtime),
|
2010-02-02 15:02:33 +00:00
|
|
|
softsendqmax(parent.softsendqmax), hardsendqmax(parent.hardsendqmax), recvqmax(parent.recvqmax),
|
2009-11-11 19:52:03 +00:00
|
|
|
penaltythreshold(parent.penaltythreshold), commandrate(parent.commandrate),
|
2012-04-01 21:11:25 +02:00
|
|
|
maxlocal(parent.maxlocal), maxglobal(parent.maxglobal), maxconnwarn(parent.maxconnwarn), maxchans(parent.maxchans),
|
2013-07-10 12:46:01 +01:00
|
|
|
limit(parent.limit), resolvehostnames(parent.resolvehostnames)
|
2009-08-12 18:03:52 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void ConnectClass::Update(const ConnectClass* src)
|
|
|
|
{
|
2010-05-12 19:47:24 -05:00
|
|
|
config = src->config;
|
|
|
|
type = src->type;
|
|
|
|
fakelag = src->fakelag;
|
2009-08-12 18:03:52 +00:00
|
|
|
name = src->name;
|
|
|
|
registration_timeout = src->registration_timeout;
|
|
|
|
host = src->host;
|
|
|
|
pingtime = src->pingtime;
|
2009-09-26 16:41:07 +00:00
|
|
|
softsendqmax = src->softsendqmax;
|
|
|
|
hardsendqmax = src->hardsendqmax;
|
2009-08-12 18:03:52 +00:00
|
|
|
recvqmax = src->recvqmax;
|
2009-10-19 18:32:11 +00:00
|
|
|
penaltythreshold = src->penaltythreshold;
|
2010-05-12 19:47:24 -05:00
|
|
|
commandrate = src->commandrate;
|
2009-08-12 18:03:52 +00:00
|
|
|
maxlocal = src->maxlocal;
|
|
|
|
maxglobal = src->maxglobal;
|
2012-04-01 21:11:25 +02:00
|
|
|
maxconnwarn = src->maxconnwarn;
|
2010-05-12 19:47:24 -05:00
|
|
|
maxchans = src->maxchans;
|
2009-08-12 18:03:52 +00:00
|
|
|
limit = src->limit;
|
2013-07-10 12:46:01 +01:00
|
|
|
resolvehostnames = src->resolvehostnames;
|
2009-08-12 18:03:52 +00:00
|
|
|
}
|